This commit is contained in:
mlangkabel
2018-11-30 16:16:31 +01:00
parent e105ac88ca
commit ea3abfc026
38 changed files with 187291 additions and 1 deletions
+607
View File
@@ -0,0 +1,607 @@
#include "DatabaseStorage.h"
#include <vector>
#include "SourcetrailException.h"
#include "NodeKind.h"
#include "utility.h"
#include "version.h"
namespace sourcetrail
{
// --- Public Interface ---
int DatabaseStorage::getSupportedDatabaseVersion()
{
return DATABASE_VERSION;
}
std::shared_ptr<DatabaseStorage> DatabaseStorage::openDatabase(const std::string& dbFilePath)
{
std::shared_ptr<DatabaseStorage> storage = std::shared_ptr<DatabaseStorage>(new DatabaseStorage());
storage->m_database.open(dbFilePath.c_str());
storage->executeStatement("PRAGMA foreign_keys=ON;");
return storage;
}
DatabaseStorage::~DatabaseStorage()
{
m_database.close();
}
void DatabaseStorage::setupTables()
{
executeStatement("PRAGMA foreign_keys=ON;");
if (!isCompatible())
{
throw SourcetrailException("Unable to setup database tables because database is not compatible.");
}
executeStatement(
"CREATE TABLE IF NOT EXISTS meta("
" id INTEGER, "
" key TEXT, "
" value TEXT, "
" PRIMARY KEY(id)"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS element("
" id INTEGER, "
" PRIMARY KEY(id)"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS edge("
" id INTEGER NOT NULL, "
" type INTEGER NOT NULL, "
" source_node_id INTEGER NOT NULL, "
" target_node_id INTEGER NOT NULL, "
" PRIMARY KEY(id), "
" FOREIGN KEY(id) REFERENCES element(id) ON DELETE CASCADE, "
" FOREIGN KEY(source_node_id) REFERENCES node(id) ON DELETE CASCADE, "
" FOREIGN KEY(target_node_id) REFERENCES node(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS node("
" id INTEGER NOT NULL, "
" type INTEGER NOT NULL, "
" serialized_name TEXT, "
" PRIMARY KEY(id), "
" FOREIGN KEY(id) REFERENCES element(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS symbol("
" id INTEGER NOT NULL, "
" definition_kind INTEGER NOT NULL, "
" PRIMARY KEY(id), "
" FOREIGN KEY(id) REFERENCES node(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS file("
" id INTEGER NOT NULL, "
" path TEXT, "
" modification_time TEXT, "
" indexed INTEGER, "
" complete INTEGER, "
" line_count INTEGER, "
" PRIMARY KEY(id), "
" FOREIGN KEY(id) REFERENCES node(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS filecontent("
" id INTERGER, "
" content TEXT, "
" FOREIGN KEY(id) REFERENCES file(id)"
" ON DELETE CASCADE "
" ON UPDATE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS local_symbol("
" id INTEGER NOT NULL, "
" name TEXT, "
" PRIMARY KEY(id), "
" FOREIGN KEY(id) REFERENCES element(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS source_location("
" id INTEGER NOT NULL, "
" file_node_id INTEGER, "
" start_line INTEGER, "
" start_column INTEGER, "
" end_line INTEGER, "
" end_column INTEGER, "
" type INTEGER, "
" PRIMARY KEY(id), "
" FOREIGN KEY(file_node_id) REFERENCES node(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS occurrence("
" element_id INTEGER NOT NULL, "
" source_location_id INTEGER NOT NULL, "
" PRIMARY KEY(element_id, source_location_id), "
" FOREIGN KEY(element_id) REFERENCES element(id) ON DELETE CASCADE, "
" FOREIGN KEY(source_location_id) REFERENCES source_location(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS component_access("
" node_id INTEGER NOT NULL, "
" type INTEGER NOT NULL, "
" PRIMARY KEY(node_id), "
" FOREIGN KEY(node_id) REFERENCES node(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS error("
" id INTEGER NOT NULL, "
" message TEXT, "
" fatal INTEGER NOT NULL, "
" indexed INTEGER NOT NULL, "
" translation_unit TEXT, "
" PRIMARY KEY(id), "
" FOREIGN KEY(id) REFERENCES element(id) ON DELETE CASCADE"
");"
);
insertOrUpdateMetaValue("storage_version", std::to_string(getSupportedDatabaseVersion()));
}
void DatabaseStorage::clearTables()
{
executeStatement("PRAGMA foreign_keys=OFF;");
const std::vector<std::string> tableNames = {
"meta",
"error"
"component_access",
"occurrence",
"source_location",
"local_symbol",
"filecontent",
"file",
"symbol",
"node",
"edge",
"element"
};
for (const std::string& tableName : tableNames)
{
executeStatement("DROP TABLE IF EXISTS main." + tableName + ";");
}
setupTables();
}
bool DatabaseStorage::isEmpty() const
{
const std::string tableName = "meta";
CppSQLite3Query q = executeQuery(
"SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "';"
);
if (!q.eof())
{
return q.getStringField(0, "") == tableName;
}
return true;
}
bool DatabaseStorage::isCompatible() const
{
if (isEmpty())
{
return true;
}
return getLoadedDatabaseVersion() == getSupportedDatabaseVersion();
}
int DatabaseStorage::getLoadedDatabaseVersion() const
{
if (isEmpty())
{
throw SourcetrailException("Unable to determine version of an empty database.");
}
CppSQLite3Query q = executeQuery("SELECT value FROM meta WHERE key = 'storage_version';");
if (!q.eof())
{
return std::stoi(q.getStringField(0, "0"));
}
return 0;
}
void DatabaseStorage::beginTransaction()
{
executeStatement("BEGIN TRANSACTION;");
}
void DatabaseStorage::commitTransaction()
{
executeStatement("COMMIT TRANSACTION;");
}
void DatabaseStorage::rollbackTransaction()
{
executeStatement("ROLLBACK TRANSACTION;");
}
void DatabaseStorage::optimizeDatabaseMemory()
{
executeStatement("VACUUM;");
}
int DatabaseStorage::addNode(const std::string& serializedNameHierarchy)
{
int id = 0;
{
CppSQLite3Statement stmt = m_database.compileStatement(
"SELECT id FROM node WHERE serialized_name == ? LIMIT 1;"
);
stmt.bind(1, serializedNameHierarchy.c_str());
CppSQLite3Query q = executeQuery(stmt);
if (!q.eof())
{
id = q.getIntField(0, 0);
}
}
if (id == 0)
{
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT INTO element(id) VALUES(NULL);"
);
executeStatement(stmt);
id = m_database.lastRowId();
}
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT INTO node(id, type, serialized_name) VALUES(?, ?, ?);"
);
stmt.bind(1, id);
stmt.bind(2, nodeKindToInt(NODE_UNKNOWN));
stmt.bind(3, serializedNameHierarchy.c_str());
executeStatement(stmt);
}
}
return id;
}
void DatabaseStorage::addSymbol(int nodeId, int definitionKind)
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT OR IGNORE INTO symbol(id, definition_kind) VALUES(?, ?);"
);
stmt.bind(1, nodeId);
stmt.bind(2, definitionKind);
executeStatement(stmt);
}
void DatabaseStorage::addFile(int nodeId, const std::string& filePath)
{
std::string modificationTime = utility::getDateTimeString(0);
const bool indexed = true;
const bool complete = true;
std::string content = "";
if (utility::getFileExists(filePath))
{
modificationTime = utility::getDateTimeString(utility::getFileModificationTime(filePath));
content = utility::getFileContent(filePath);
}
const int lineCount = utility::getLineCount(content);
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT OR IGNORE INTO file(id, path, modification_time, indexed, complete, line_count) VALUES(?, ?, ?, ?, ?, ?);"
);
stmt.bind(1, nodeId);
stmt.bind(2, filePath.c_str());
stmt.bind(3, modificationTime.c_str());
stmt.bind(4, indexed);
stmt.bind(5, complete);
stmt.bind(6, lineCount);
executeStatement(stmt);
}
if (!content.empty())
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT INTO filecontent(id, content) VALUES(?, ?);"
);
stmt.bind(1, nodeId);
stmt.bind(2, content.c_str());
executeStatement(stmt);
}
}
int DatabaseStorage::addEdge(int sourceNodeId, int targetNodeId, int edgeKind)
{
int id = 0;
{
CppSQLite3Statement stmt = m_database.compileStatement(
"SELECT id FROM edge WHERE source_node_id == ? AND target_node_id == ? AND type == ? LIMIT 1;"
);
stmt.bind(1, sourceNodeId);
stmt.bind(2, targetNodeId);
stmt.bind(3, edgeKind);
CppSQLite3Query q = executeQuery(stmt);
if (!q.eof())
{
id = q.getIntField(0, 0);
}
}
if (id == 0)
{
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT INTO element(id) VALUES(NULL);"
);
executeStatement(stmt);
id = m_database.lastRowId();
}
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT INTO edge(id, type, source_node_id, target_node_id) VALUES(?, ?, ?, ?);"
);
stmt.bind(1, id);
stmt.bind(2, edgeKind);
stmt.bind(3, sourceNodeId);
stmt.bind(4, targetNodeId);
executeStatement(stmt);
}
}
return id;
}
int DatabaseStorage::addLocalSymbol(const std::string& name)
{
int id = 0;
{
CppSQLite3Statement stmt = m_database.compileStatement(
"SELECT id FROM local_symbol WHERE name == ? LIMIT 1;"
);
stmt.bind(1, name.c_str());
CppSQLite3Query q = executeQuery(stmt);
if (!q.eof())
{
id = q.getIntField(0, 0);
}
}
if (id == 0)
{
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT INTO element(id) VALUES(NULL);"
);
executeStatement(stmt);
id = m_database.lastRowId();
}
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT INTO local_symbol(id, name) VALUES(?, ?);"
);
stmt.bind(1, id);
stmt.bind(2, name.c_str());
executeStatement(stmt);
}
}
return id;
}
int DatabaseStorage::addSourceLocation(
int fileId,
int startLineNumber,
int startColumnNumber,
int endLineNumber,
int endColumnNumber,
int locationKind)
{
int id = 0;
{
CppSQLite3Statement stmt = m_database.compileStatement(
"SELECT id FROM source_location WHERE "
"file_node_id = ? AND "
"start_line = ? AND "
"start_column = ? AND "
"end_line = ? AND "
"end_column = ? AND "
"type = ? "
"LIMIT 1;"
);
stmt.bind(1, fileId);
stmt.bind(2, startLineNumber);
stmt.bind(3, startColumnNumber);
stmt.bind(4, endLineNumber);
stmt.bind(5, endColumnNumber);
stmt.bind(6, locationKind);
CppSQLite3Query q = executeQuery(stmt);
if (!q.eof())
{
id = q.getIntField(0, 0);
}
}
if (id == 0)
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT INTO source_location(id, file_node_id, start_line, start_column, end_line, end_column, type) VALUES(NULL, ?, ?, ?, ?, ?, ?);"
);
stmt.bind(1, fileId);
stmt.bind(2, startLineNumber);
stmt.bind(3, startColumnNumber);
stmt.bind(4, endLineNumber);
stmt.bind(5, endColumnNumber);
stmt.bind(6, locationKind);
executeStatement(stmt);
id = m_database.lastRowId();
}
return id;
}
void DatabaseStorage::addOccurrence(int elementId, int sourceLocationId)
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT OR IGNORE INTO occurrence(element_id, source_location_id) VALUES(?, ?);"
);
stmt.bind(1, elementId);
stmt.bind(2, sourceLocationId);
executeStatement(stmt);
}
int DatabaseStorage::addError(
const std::string& message,
bool fatal)
{
int id = 0;
{
CppSQLite3Statement stmt = m_database.compileStatement(
"SELECT id FROM error WHERE "
"message = ? AND "
"fatal == ? "
"LIMIT 1;"
);
stmt.bind(1, message.c_str());
stmt.bind(2, fatal);
CppSQLite3Query q = executeQuery(stmt);
if (!q.eof() && q.numFields() > 0)
{
id = q.getIntField(0, -1);
}
}
if (id == 0)
{
{
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT INTO element(id) VALUES(NULL);"
);
executeStatement(stmt);
id = m_database.lastRowId();
}
CppSQLite3Statement stmt = m_database.compileStatement(
"INSERT INTO error(id, message, fatal, indexed, translation_unit) "
"VALUES(?, ?, ?, ?, ?);"
);
stmt.bind(1, id);
stmt.bind(2, message.c_str());
stmt.bind(3, fatal);
stmt.bind(4, true);
stmt.bind(5, "");
executeStatement(stmt);
id = m_database.lastRowId();
}
return id;
}
void DatabaseStorage::setNodeType(int nodeId, int nodeType)
{
CppSQLite3Statement stmt = m_database.compileStatement(
"UPDATE node SET type = ? WHERE id == ?;"
);
stmt.bind(1, nodeType);
stmt.bind(2, nodeId);
executeStatement(stmt);
}
// --- Private Interface ---
void DatabaseStorage::insertOrUpdateMetaValue(const std::string& key, const std::string& value)
{
CppSQLite3Statement stmt = m_database.compileStatement(std::string(
"INSERT OR REPLACE INTO meta(id, key, value) VALUES("
"(SELECT id FROM meta WHERE key = ?), ?, ?"
");"
).c_str());
stmt.bind(1, key.c_str());
stmt.bind(2, key.c_str());
stmt.bind(3, value.c_str());
executeStatement(stmt);
}
void DatabaseStorage::executeStatement(const std::string& statement) const
{
try
{
m_database.execDML(statement.c_str());
}
catch (CppSQLite3Exception e)
{
throw SourcetrailException("Failed to execute statement \"" + statement + "\" with message \"" + e.errorMessage() + "\".");
}
}
void DatabaseStorage::executeStatement(CppSQLite3Statement& statement) const
{
try
{
statement.execDML();
}
catch (CppSQLite3Exception e)
{
throw SourcetrailException("Failed to execute statement with message \"" + std::string(e.errorMessage()) + "\".");
}
}
CppSQLite3Query DatabaseStorage::executeQuery(const std::string& query) const
{
try
{
return m_database.execQuery(query.c_str());
}
catch (CppSQLite3Exception e)
{
throw SourcetrailException("Failed to execute query \"" + query + "\" with message \"" + e.errorMessage() + "\".");
}
}
CppSQLite3Query DatabaseStorage::executeQuery(CppSQLite3Statement& statement) const
{
try
{
return statement.execQuery();
}
catch (CppSQLite3Exception e)
{
throw SourcetrailException("Failed to execute query with message \"" + std::string(e.errorMessage()) + "\".");
}
}
}
+19
View File
@@ -0,0 +1,19 @@
#include "DefinitionKind.h"
namespace sourcetrail
{
int definitionKindToInt(DefinitionKind v)
{
return v;
}
DefinitionKind intToDefinitionKind(int v)
{
if (v == definitionKindToInt(DEFINITION_IMPLICIT))
return DEFINITION_IMPLICIT;
if (v == definitionKindToInt(DEFINITION_EXPLICIT))
return DEFINITION_EXPLICIT;
return DEFINITION_EXPLICIT;
}
}
+50
View File
@@ -0,0 +1,50 @@
#include "EdgeKind.h"
#include "ReferenceKind.h"
namespace sourcetrail
{
int edgeKindToInt(EdgeKind edgeKind)
{
return edgeKind;
}
EdgeKind intToEdgeKind(int i)
{
switch (i)
{
case EDGE_MEMBER:
return EDGE_MEMBER;
case EDGE_TYPE_USAGE:
return EDGE_TYPE_USAGE;
case EDGE_USAGE:
return EDGE_USAGE;
case EDGE_CALL:
return EDGE_CALL;
case EDGE_INHERITANCE:
return EDGE_INHERITANCE;
case EDGE_OVERRIDE:
return EDGE_OVERRIDE;
case EDGE_TEMPLATE_ARGUMENT:
return EDGE_TEMPLATE_ARGUMENT;
case EDGE_TYPE_ARGUMENT:
return EDGE_TYPE_ARGUMENT;
case EDGE_TEMPLATE_DEFAULT_ARGUMENT:
return EDGE_TEMPLATE_DEFAULT_ARGUMENT;
case EDGE_TEMPLATE_SPECIALIZATION:
return EDGE_TEMPLATE_SPECIALIZATION;
case EDGE_TEMPLATE_MEMBER_SPECIALIZATION:
return EDGE_TEMPLATE_MEMBER_SPECIALIZATION;
case EDGE_INCLUDE:
return EDGE_INCLUDE;
case EDGE_IMPORT:
return EDGE_IMPORT;
case EDGE_AGGREGATION:
return EDGE_AGGREGATION;
case EDGE_MACRO_USAGE:
return EDGE_MACRO_USAGE;
}
return EDGE_UNKNOWN;
}
}
+37
View File
@@ -0,0 +1,37 @@
#include "LocationKind.h"
#include "SourcetrailException.h"
namespace sourcetrail
{
LocationKind intToLocationKind(int i)
{
switch (i)
{
case LOCATION_TOKEN:
return LOCATION_TOKEN;
case LOCATION_SCOPE:
return LOCATION_SCOPE;
case LOCATION_QUALIFIER:
return LOCATION_QUALIFIER;
case LOCATION_LOCAL_SYMBOL:
return LOCATION_LOCAL_SYMBOL;
case LOCATION_SIGNATURE:
return LOCATION_SIGNATURE;
case LOCATION_COMMENT:
return LOCATION_COMMENT;
case LOCATION_ERROR:
return LOCATION_ERROR;
case LOCATION_FULLTEXT_SEARCH:
return LOCATION_FULLTEXT_SEARCH;
case LOCATION_SCREEN_SEARCH:
return LOCATION_SCREEN_SEARCH;
}
throw SourcetrailException("Unable to convert integer \"" + std::to_string(i) + "\" to location kind.");
}
int locationKindToInt(LocationKind locationKind)
{
return locationKind;
}
}
+84
View File
@@ -0,0 +1,84 @@
#include "NameHierarchy.h"
#include "json/json.hpp"
namespace sourcetrail
{
std::string serializeNameHierarchyToJson(const NameHierarchy& nameHierarchy)
{
typedef nlohmann::json json;
nlohmann::json j;
j["name_delimiter"] = nameHierarchy.nameDelimiter;
for (const NameElement& nameElement : nameHierarchy.nameElements)
{
j["name_elements"].push_back(
{
{ "prefix", nameElement.prefix } ,
{ "name", nameElement.name } ,
{ "postfix", nameElement.postfix }
});
}
return j.dump(4);
}
NameHierarchy deserializeNameHierarchyFromJson(const std::string& serializedNameHierarchy)
{
typedef nlohmann::json json;
NameHierarchy nameHierarchy;
try
{
json j = nlohmann::json::parse(serializedNameHierarchy);
{
json jDelimiter = j["name_delimiter"];
if (jDelimiter.is_string())
{
nameHierarchy.nameDelimiter = jDelimiter.get<std::string>();
}
}
{
json jNameElements = j["name_elements"];
if (jNameElements.is_array())
{
for (json::iterator it = jNameElements.begin(); it != jNameElements.end(); ++it)
{
NameElement nameElement;
{
json jPrefix = it.value()["prefix"];
if (jPrefix.is_string())
{
nameElement.prefix = jPrefix.get<std::string>();
}
}
{
json jName = it.value()["name"];
if (jName.is_string())
{
nameElement.name = jName.get<std::string>();
}
}
{
json jPostfix = it.value()["postfix"];
if (jPostfix.is_string())
{
nameElement.postfix = jPostfix.get<std::string>();
}
}
nameHierarchy.nameElements.push_back(nameElement);
}
}
}
}
catch (...)
{
// do nothing
}
return nameHierarchy;
}
}
+35
View File
@@ -0,0 +1,35 @@
#include "NodeKind.h"
namespace sourcetrail
{
int nodeKindToInt(NodeKind v)
{
return v;
}
NodeKind intToNodeKind(int v)
{
if (v == nodeKindToInt(NODE_UNKNOWN)) { return NODE_UNKNOWN; }
if (v == nodeKindToInt(NODE_TYPE)) { return NODE_TYPE; }
if (v == nodeKindToInt(NODE_BUILTIN_TYPE)) { return NODE_BUILTIN_TYPE; }
if (v == nodeKindToInt(NODE_NAMESPACE)) { return NODE_NAMESPACE; }
if (v == nodeKindToInt(NODE_PACKAGE)) { return NODE_PACKAGE; }
if (v == nodeKindToInt(NODE_STRUCT)) { return NODE_STRUCT; }
if (v == nodeKindToInt(NODE_CLASS)) { return NODE_CLASS; }
if (v == nodeKindToInt(NODE_INTERFACE)) { return NODE_INTERFACE; }
if (v == nodeKindToInt(NODE_ANNOTATION)) { return NODE_ANNOTATION; }
if (v == nodeKindToInt(NODE_GLOBAL_VARIABLE)) { return NODE_GLOBAL_VARIABLE; }
if (v == nodeKindToInt(NODE_FIELD)) { return NODE_FIELD; }
if (v == nodeKindToInt(NODE_FUNCTION)) { return NODE_FUNCTION; }
if (v == nodeKindToInt(NODE_METHOD)) { return NODE_METHOD; }
if (v == nodeKindToInt(NODE_ENUM)) { return NODE_ENUM; }
if (v == nodeKindToInt(NODE_ENUM_CONSTANT)) { return NODE_ENUM_CONSTANT; }
if (v == nodeKindToInt(NODE_TYPEDEF)) { return NODE_TYPEDEF; }
if (v == nodeKindToInt(NODE_TEMPLATE_PARAMETER)) { return NODE_TEMPLATE_PARAMETER; }
if (v == nodeKindToInt(NODE_TYPE_PARAMETER)) { return NODE_TYPE_PARAMETER; }
if (v == nodeKindToInt(NODE_FILE)) { return NODE_FILE; }
if (v == nodeKindToInt(NODE_MACRO)) { return NODE_MACRO; }
if (v == nodeKindToInt(NODE_UNION)) { return NODE_UNION; }
return NODE_UNKNOWN;
}
}
+42
View File
@@ -0,0 +1,42 @@
#include "ReferenceKind.h"
#include "EdgeKind.h"
namespace sourcetrail
{
EdgeKind referenceKindToEdgeKind(ReferenceKind v)
{
switch (v)
{
case REFERENCE_TYPE_USAGE:
return EDGE_TYPE_USAGE;
case REFERENCE_USAGE:
return EDGE_USAGE;
case REFERENCE_CALL:
return EDGE_CALL;
case REFERENCE_INHERITANCE:
return EDGE_INHERITANCE;
case REFERENCE_OVERRIDE:
return EDGE_OVERRIDE;
case REFERENCE_TEMPLATE_ARGUMENT:
return EDGE_TEMPLATE_ARGUMENT;
case REFERENCE_TYPE_ARGUMENT:
return EDGE_TYPE_ARGUMENT;
case REFERENCE_TEMPLATE_DEFAULT_ARGUMENT:
return EDGE_TEMPLATE_DEFAULT_ARGUMENT;
case REFERENCE_TEMPLATE_SPECIALIZATION:
return EDGE_TEMPLATE_SPECIALIZATION;
case REFERENCE_TEMPLATE_MEMBER_SPECIALIZATION:
return EDGE_TEMPLATE_MEMBER_SPECIALIZATION;
case REFERENCE_INCLUDE:
return EDGE_INCLUDE;
case REFERENCE_IMPORT:
return EDGE_IMPORT;
case REFERENCE_MACRO_USAGE:
return EDGE_MACRO_USAGE;
case REFERENCE_ANNOTATION_USAGE:
return EDGE_ANNOTATION_USAGE;
}
return EDGE_UNKNOWN;
}
}
+722
View File
@@ -0,0 +1,722 @@
#include "SourcetrailDBWriter.h"
#include <fstream>
#include <vector>
#include "sqlite/CppSQLite3.h"
#include "DatabaseStorage.h"
#include "DefinitionKind.h"
#include "EdgeKind.h"
#include "LocationKind.h"
#include "NameHierarchy.h"
#include "NodeKind.h"
#include "ReferenceKind.h"
#include "SourceRange.h"
#include "SourcetrailException.h"
#include "SymbolKind.h"
#include "version.h"
namespace sourcetrail
{
// --- Public Interface ---
SourcetrailDBWriter::SourcetrailDBWriter()
: m_lastError("")
{
}
std::string SourcetrailDBWriter::getVersionString() const
{
return VERSION_STRING;
}
int SourcetrailDBWriter::getSupportedDatabaseVersion() const
{
return DatabaseStorage::getSupportedDatabaseVersion();
}
const std::string& SourcetrailDBWriter::getLastError() const
{
return m_lastError;
}
void SourcetrailDBWriter::clearLastError()
{
m_lastError.clear();
}
bool SourcetrailDBWriter::openProject(const std::string& projectDirectory, const std::string& projectName)
{
m_projectDirectory = projectDirectory;
m_projectName = projectName;
try
{
openDatabase();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
try
{
setupDatabaseTables();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
{
bool projectFileExists = false;
{
std::ifstream f(getProjectFilePath().c_str());
projectFileExists = f.good();
f.close();
}
if (!projectFileExists)
{
try
{
createOrResetProjectFile();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
}
return true;
}
bool SourcetrailDBWriter::closeProject()
{
try
{
closeDatabase();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::clearProject()
{
try
{
clearDatabaseTables();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
try
{
createOrResetProjectFile();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::isEmpty() const
{
if (!m_storage)
{
m_lastError = "Unable to check if database is empty, because no database is currently open.";
return true;
}
try
{
return m_storage->isEmpty();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return true;
}
}
bool SourcetrailDBWriter::isCompatible() const
{
if (!m_storage)
{
m_lastError = "Unable to check if database is compatible, because no database is currently open.";
return false;
}
try
{
return m_storage->isCompatible();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
int SourcetrailDBWriter::getLoadedDatabaseVersion() const
{
if (!m_storage)
{
m_lastError = "Unable to fetch database version, because no database is currently open.";
return false;
}
try
{
return m_storage->getLoadedDatabaseVersion();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return 0;
}
}
bool SourcetrailDBWriter::beginTransaction()
{
if (!m_storage)
{
m_lastError = "Unable to begin transaction, because no database is currently open.";
return false;
}
try
{
m_storage->beginTransaction();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::commitTransaction()
{
if (!m_storage)
{
m_lastError = "Unable to commit transaction, because no database is currently open.";
return false;
}
try
{
m_storage->commitTransaction();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::rollbackTransaction()
{
if (!m_storage)
{
m_lastError = "Unable to rollback transaction, because no database is currently open.";
return false;
}
try
{
m_storage->rollbackTransaction();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::optimizeDatabaseMemory()
{
if (!m_storage)
{
m_lastError = "Unable to optimize database memory, because no database is currently open.";
return false;
}
try
{
m_storage->optimizeDatabaseMemory();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
int SourcetrailDBWriter::recordSymbol(const NameHierarchy& nameHierarchy)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol, because no database is currently open.";
return false;
}
try
{
return addNodeHierarchy(nameHierarchy);
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return 0;
}
}
bool SourcetrailDBWriter::recordSymbolDefinitionKind(int symbolId, DefinitionKind definitionKind)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol kind, because no database is currently open.";
return false;
}
try
{
m_storage->addSymbol(symbolId, definitionKindToInt(definitionKind));
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::recordSymbolKind(int symbolId, SymbolKind symbolKind)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol kind, because no database is currently open.";
return false;
}
try
{
m_storage->setNodeType(symbolId, nodeKindToInt(symbolKindToNodeKind(symbolKind)));
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::recordSymbolLocation(int symbolId, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol location, because no database is currently open.";
return false;
}
try
{
addSourceLocation(symbolId, location, LOCATION_TOKEN);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
bool SourcetrailDBWriter::recordSymbolScopeLocation(int symbolId, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol scope location, because no database is currently open.";
return false;
}
try
{
addSourceLocation(symbolId, location, LOCATION_SCOPE);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
bool SourcetrailDBWriter::recordSymbolSignatureLocation(int symbolId, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol signature location, because no database is currently open.";
return false;
}
try
{
addSourceLocation(symbolId, location, LOCATION_SIGNATURE);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
int SourcetrailDBWriter::recordReference(int contextSymbolId, int referencedSymbolId, ReferenceKind referenceKind)
{
if (!m_storage)
{
m_lastError = "Unable to record reference, because no database is currently open.";
return false;
}
try
{
return addEdge(contextSymbolId, referencedSymbolId, referenceKindToEdgeKind(referenceKind));
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return 0;
}
}
bool SourcetrailDBWriter::recordReferenceLocation(int referenceId, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol signature location, because no database is currently open.";
return false;
}
try
{
addSourceLocation(referenceId, location, LOCATION_TOKEN);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
int SourcetrailDBWriter::recordFile(const std::string& filePath)
{
if (!m_storage)
{
m_lastError = "Unable to record file, because no database is currently open.";
return false;
}
try
{
return addFile(filePath);
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return 0;
}
}
int SourcetrailDBWriter::recordLocalSymbol(const std::string& name)
{
if (!m_storage)
{
m_lastError = "Unable to record local symbol, because no database is currently open.";
return false;
}
try
{
return m_storage->addLocalSymbol(name);
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return 0;
}
}
bool SourcetrailDBWriter::recordLocalSymbolLocation(int localSymbolId, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record local symbol location, because no database is currently open.";
return false;
}
try
{
addSourceLocation(localSymbolId, location, LOCATION_LOCAL_SYMBOL);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
bool SourcetrailDBWriter::recordCommentLocation(const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record comment location, because no database is currently open.";
return false;
}
try
{
const int fileId = addFile(location.filePath);
const int sourceLocationId = m_storage->addSourceLocation(
fileId,
location.startLine,
location.startColumn,
location.endLine,
location.endColumn,
LOCATION_COMMENT
);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
bool SourcetrailDBWriter::recordError(const std::string& message, bool fatal, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record error, because no database is currently open.";
return false;
}
try
{
const int errorId = m_storage->addError(message, fatal);
addSourceLocation(errorId, location, LOCATION_ERROR);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
// --- Private Interface ---
std::string SourcetrailDBWriter::serializeNameHierarchy(const NameHierarchy& nameHierarchy)
{
static std::string META_DELIMITER = "\tm";
static std::string NAME_DELIMITER = "\tn";
static std::string PARTS_DELIMITER = "\ts";
static std::string SIGNATURE_DELIMITER = "\tp";
std::string serialized = nameHierarchy.nameDelimiter + META_DELIMITER;
for (size_t i = 0; i < nameHierarchy.nameElements.size(); i++)
{
if (i != 0)
{
serialized += NAME_DELIMITER;
}
const NameElement& nameElement = nameHierarchy.nameElements[i];
serialized += nameElement.name + PARTS_DELIMITER + nameElement.prefix + SIGNATURE_DELIMITER + nameElement.postfix;
}
return serialized;
}
std::string SourcetrailDBWriter::getProjectFilePath() const
{
return m_projectDirectory + "/" + m_projectName + ".srctrlprj";
}
std::string SourcetrailDBWriter::getDatabaseFilePath() const
{
return m_projectDirectory + "/" + m_projectName + ".srctrldb";
}
void SourcetrailDBWriter::openDatabase()
{
if (m_storage)
{
closeDatabase();
}
try
{
m_storage = DatabaseStorage::openDatabase(getDatabaseFilePath());
}
catch (CppSQLite3Exception e)
{
m_storage.reset();
throw e;
}
}
void SourcetrailDBWriter::closeDatabase()
{
if (!m_storage)
{
throw SourcetrailException("Unable to close database, because no database is currently open.");
}
m_storage.reset();
}
void SourcetrailDBWriter::setupDatabaseTables()
{
if (!m_storage)
{
throw SourcetrailException("Unable to setup database tables, because no database is currently open.");
}
m_storage->setupTables();
}
void SourcetrailDBWriter::clearDatabaseTables()
{
if (!m_storage)
{
throw SourcetrailException("Unable to setup database tables, because no database is currently open.");
}
m_storage->clearTables();
}
void SourcetrailDBWriter::createOrResetProjectFile()
{
try
{
std::ofstream fileStream;
fileStream.open(getProjectFilePath(), std::ios::out);
fileStream << std::string(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <version>0</version>\n"
"</config>\n"
);
fileStream.close();
}
catch (...)
{
throw SourcetrailException("Exception occurred while creating project file.");
}
}
int SourcetrailDBWriter::addNodeHierarchy(const NameHierarchy& nameHierarchy)
{
if (nameHierarchy.nameElements.size() == 0)
{
throw SourcetrailException("Unable to add nodes for an empty name hierarchy.");
}
int parentNodeId = 0;
NameHierarchy currentNameHierarchy;
currentNameHierarchy.nameDelimiter = nameHierarchy.nameDelimiter;
for (size_t i = 0; i < nameHierarchy.nameElements.size(); i++)
{
currentNameHierarchy.nameElements.push_back(nameHierarchy.nameElements[i]);
int nodeId = m_storage->addNode(serializeNameHierarchy(currentNameHierarchy));
if (parentNodeId != 0)
{
addEdge(parentNodeId, nodeId, EDGE_MEMBER);
}
parentNodeId = nodeId;
}
return parentNodeId;
}
int SourcetrailDBWriter::addFile(const std::string& filePath)
{
NameElement nameElement;
nameElement.name = filePath;
NameHierarchy nameHierarchy;
nameHierarchy.nameDelimiter = "/";
nameHierarchy.nameElements.push_back(nameElement);
const int nodeId = addNodeHierarchy(nameHierarchy);
m_storage->setNodeType(nodeId, nodeKindToInt(NODE_FILE));
m_storage->addFile(nodeId, filePath);
return nodeId;
}
int SourcetrailDBWriter::addEdge(int sourceId, int targetId, EdgeKind edgeKind)
{
if (!m_storage)
{
throw SourcetrailException("Unable to add edge, because no database is currently open.");
}
if (!sourceId)
{
throw SourcetrailException("Unable to add edge, because source id is invalid.");
}
if (!targetId)
{
throw SourcetrailException("Unable to add edge, because target id is invalid.");
}
return m_storage->addEdge(sourceId, targetId, edgeKindToInt(edgeKind));
}
void SourcetrailDBWriter::addSourceLocation(int elementId, const SourceRange& location, LocationKind kind)
{
const int fileId = addFile(location.filePath);
const int sourceLocationId = m_storage->addSourceLocation(
fileId,
location.startLine,
location.startColumn,
location.endLine,
location.endColumn,
locationKindToInt(kind)
);
m_storage->addOccurrence(
elementId,
sourceLocationId
);
}
}
+52
View File
@@ -0,0 +1,52 @@
#include "SymbolKind.h"
#include "NodeKind.h"
namespace sourcetrail
{
NodeKind symbolKindToNodeKind(SymbolKind v)
{
switch (v)
{
case SYMBOL_TYPE:
return NODE_TYPE;
case SYMBOL_BUILTIN_TYPE:
return NODE_BUILTIN_TYPE;
case SYMBOL_NAMESPACE:
return NODE_NAMESPACE;
case SYMBOL_PACKAGE:
return NODE_PACKAGE;
case SYMBOL_STRUCT:
return NODE_STRUCT;
case SYMBOL_CLASS:
return NODE_CLASS;
case SYMBOL_INTERFACE:
return NODE_INTERFACE;
case SYMBOL_ANNOTATION:
return NODE_ANNOTATION;
case SYMBOL_GLOBAL_VARIABLE:
return NODE_GLOBAL_VARIABLE;
case SYMBOL_FIELD:
return NODE_FIELD;
case SYMBOL_FUNCTION:
return NODE_FUNCTION;
case SYMBOL_METHOD:
return NODE_METHOD;
case SYMBOL_ENUM:
return NODE_ENUM;
case SYMBOL_ENUM_CONSTANT:
return NODE_ENUM_CONSTANT;
case SYMBOL_TYPEDEF:
return NODE_TYPEDEF;
case SYMBOL_TEMPLATE_PARAMETER:
return NODE_TEMPLATE_PARAMETER;
case SYMBOL_TYPE_PARAMETER:
return NODE_TYPE_PARAMETER;
case SYMBOL_MACRO:
return NODE_MACRO;
case SYMBOL_UNION:
return NODE_UNION;
}
return NODE_UNKNOWN;
}
}
+63
View File
@@ -0,0 +1,63 @@
#include "utility.h"
#include <fstream>
#include <filesystem>
#include "SourcetrailException.h"
namespace sourcetrail
{
namespace utility
{
bool getFileExists(const std::string& filePath)
{
std::ifstream file(filePath);
return file.good();
}
std::string getFileContent(const std::string& filePath)
{
std::string content;
std::ifstream file;
file.open(filePath);
if (file.fail())
{
throw SourcetrailException("Could not open file " + filePath);
}
for (std::string line; std::getline(file, line); )
{
content += line + "\n";
}
file.close();
return content;
}
time_t getFileModificationTime(const std::string& filePath)
{
std::experimental::filesystem::path p(filePath);
auto ftime = std::experimental::filesystem::last_write_time(p);
// assuming system_clock for this demo
// note: not true on MSVC; C++20 will allow portable output
return decltype(ftime)::clock::to_time_t(ftime);
}
std::string getDateTimeString(const time_t& time)
{
std::tm* ptm = std::localtime(&time);
char buffer[32];
std::strftime(buffer, 32, "%Y-%m-%d %H:%M:%S", ptm);
return buffer;
}
int getLineCount(const std::string s)
{
return std::count(s.begin(), s.end(), '\n');
}
}
}