indev
This commit is contained in:
@@ -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()) + "\".");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user