From 26902acbbb9f34fe7959ef0305b07d2d713695f4 Mon Sep 17 00:00:00 2001 From: malte_langkabel Date: Fri, 9 Dec 2016 17:00:26 +0100 Subject: [PATCH] src: split CxxAstVisitor into component based indexing system * also: added logging for sqlite exceptions --- src/lib/data/SqliteStorage.cpp | 299 ++-- src/lib/data/SqliteStorage.h | 6 + src/lib_cxx/CMakeLists.txt | 12 + src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp | 1259 +++++------------ src/lib_cxx/data/parser/cxx/CxxAstVisitor.h | 109 +- .../parser/cxx/CxxAstVisitorComponent.cpp | 20 + .../data/parser/cxx/CxxAstVisitorComponent.h | 130 ++ .../cxx/CxxAstVisitorComponentContext.cpp | 200 +++ .../cxx/CxxAstVisitorComponentContext.h | 55 + .../cxx/CxxAstVisitorComponentDeclRefKind.cpp | 178 +++ .../cxx/CxxAstVisitorComponentDeclRefKind.h | 77 + .../cxx/CxxAstVisitorComponentIndexer.cpp | 682 +++++++++ .../cxx/CxxAstVisitorComponentIndexer.h | 77 + .../cxx/CxxAstVisitorComponentTypeRefKind.cpp | 59 + .../cxx/CxxAstVisitorComponentTypeRefKind.h | 35 + .../data/parser/cxx/utilityCxxAstVisitor.cpp | 73 + .../data/parser/cxx/utilityCxxAstVisitor.h | 16 + src/test/CxxParserTestSuite.h | 4 +- 18 files changed, 2170 insertions(+), 1121 deletions(-) create mode 100644 src/lib_cxx/data/parser/cxx/CxxAstVisitorComponent.cpp create mode 100644 src/lib_cxx/data/parser/cxx/CxxAstVisitorComponent.h create mode 100644 src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentContext.cpp create mode 100644 src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentContext.h create mode 100644 src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentDeclRefKind.cpp create mode 100644 src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentDeclRefKind.h create mode 100644 src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentIndexer.cpp create mode 100644 src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentIndexer.h create mode 100644 src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentTypeRefKind.cpp create mode 100644 src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentTypeRefKind.h create mode 100644 src/lib_cxx/data/parser/cxx/utilityCxxAstVisitor.cpp create mode 100644 src/lib_cxx/data/parser/cxx/utilityCxxAstVisitor.h diff --git a/src/lib/data/SqliteStorage.cpp b/src/lib/data/SqliteStorage.cpp index 2d3688fe..1407e478 100644 --- a/src/lib/data/SqliteStorage.cpp +++ b/src/lib/data/SqliteStorage.cpp @@ -17,7 +17,7 @@ SqliteStorage::SqliteStorage(const FilePath& dbFilePath) { m_database.open(m_dbFilePath.str().c_str()); - m_database.execDML("PRAGMA foreign_keys=ON;"); + executeStatement("PRAGMA foreign_keys=ON;"); m_mode = STORAGE_MODE_UNKNOWN; @@ -69,14 +69,14 @@ SqliteStorage::~SqliteStorage() void SqliteStorage::setup() { - m_database.execDML("PRAGMA foreign_keys=ON;"); + executeStatement("PRAGMA foreign_keys=ON;"); setupTables(); m_mode = STORAGE_MODE_UNKNOWN; } void SqliteStorage::clear() { - m_database.execDML("PRAGMA foreign_keys=OFF;"); + executeStatement("PRAGMA foreign_keys=OFF;"); clearTables(); setup(); @@ -106,29 +106,22 @@ void SqliteStorage::setMode(const StorageModeType mode) void SqliteStorage::beginTransaction() { - m_database.execDML("BEGIN TRANSACTION;"); + executeStatement("BEGIN TRANSACTION;"); } void SqliteStorage::commitTransaction() { - m_database.execDML("COMMIT TRANSACTION;"); + executeStatement("COMMIT TRANSACTION;"); } void SqliteStorage::rollbackTransaction() { - m_database.execDML("ROLLBACK TRANSACTION;"); + executeStatement("ROLLBACK TRANSACTION;"); } void SqliteStorage::optimizeMemory() const { - try - { - m_database.execDML("VACUUM;"); - } - catch(CppSQLite3Exception e) - { - LOG_ERROR(e.errorMessage()); - } + executeStatement("VACUUM;"); } FilePath SqliteStorage::getDbFilePath() const @@ -177,25 +170,21 @@ void SqliteStorage::setVersion() Id SqliteStorage::addEdge(int type, Id sourceNodeId, Id targetNodeId) { - m_database.execDML( - "INSERT INTO element(id) VALUES(NULL);" - ); + executeStatement("INSERT INTO element(id) VALUES(NULL);"); Id id = m_database.lastRowId(); - m_database.execDML(( + executeStatement( "INSERT INTO edge(id, type, source_node_id, target_node_id) VALUES(" + std::to_string(id) + ", " + std::to_string(type) + ", " + std::to_string(sourceNodeId) + ", " + std::to_string(targetNodeId) + ");" - ).c_str()); + ); return id; } Id SqliteStorage::addNode(int type, const std::string& serializedName, int definitionType) { - m_database.execDML( - "INSERT INTO element(id) VALUES(NULL);" - ); + executeStatement("INSERT INTO element(id) VALUES(NULL);"); Id id = m_database.lastRowId(); CppSQLite3Statement stmt = m_database.compileStatement(( @@ -204,7 +193,7 @@ Id SqliteStorage::addNode(int type, const std::string& serializedName, int defin ).c_str()); stmt.bind(1, serializedName.c_str()); - stmt.execDML(); + executeStatement(stmt); return id; } @@ -215,10 +204,10 @@ Id SqliteStorage::addFile(const std::string& serializedName, const std::string& std::shared_ptr content = TextAccess::createFromFile(filePath); unsigned int loc = content->getLineCount(); - m_database.execDML(( + executeStatement( "INSERT INTO file(id, path, modification_time, loc) VALUES(" + std::to_string(id) + ", '" + filePath + "', '" + modificationTime + "', " + std::to_string(loc) + ");" - ).c_str()); + ); CppSQLite3Statement stmt = m_database.compileStatement(( "INSERT INTO filecontent(id, content) VALUES(" @@ -226,16 +215,14 @@ Id SqliteStorage::addFile(const std::string& serializedName, const std::string& ).c_str()); stmt.bind(1, content->getText().c_str()); - stmt.execDML(); + executeStatement(stmt); return id; } Id SqliteStorage::addLocalSymbol(const std::string& name) { - m_database.execDML( - "INSERT INTO element(id) VALUES(NULL);" - ); + executeStatement("INSERT INTO element(id) VALUES(NULL);"); Id id = m_database.lastRowId(); CppSQLite3Statement stmt = m_database.compileStatement(( @@ -244,7 +231,7 @@ Id SqliteStorage::addLocalSymbol(const std::string& name) ).c_str()); stmt.bind(1, name.c_str()); - stmt.execDML(); + executeStatement(stmt); return id; } @@ -252,12 +239,12 @@ Id SqliteStorage::addLocalSymbol(const std::string& name) Id SqliteStorage::addSourceLocation( Id fileNodeId, uint startLine, uint startCol, uint endLine, uint endCol, int type) { - m_database.execDML(( + executeStatement( "INSERT INTO source_location(id, file_node_id, start_line, start_column, end_line, end_column, type) " "VALUES(NULL, " + std::to_string(fileNodeId) + ", " + std::to_string(startLine) + ", " + std::to_string(startCol) + ", " + std::to_string(endLine) + ", " + std::to_string(endCol) + ", " + std::to_string(type) + ");" - ).c_str()); + ); return m_database.lastRowId(); } @@ -281,22 +268,22 @@ bool SqliteStorage::addOccurrence(Id elementId, Id sourceLocationId) Id SqliteStorage::addComponentAccess(Id nodeId, int type) { - m_database.execDML(( + executeStatement( "INSERT INTO component_access(id, node_id, type) " "VALUES (NULL, " + std::to_string(nodeId) + ", " + std::to_string(type) + ");" - ).c_str()); + ); return m_database.lastRowId(); } Id SqliteStorage::addCommentLocation(Id fileNodeId, uint startLine, uint startCol, uint endLine, uint endCol) { - m_database.execDML(( + executeStatement( "INSERT INTO comment_location(id, file_node_id, start_line, start_column, end_line, end_column) " "VALUES(NULL, " + std::to_string(fileNodeId) + ", " + std::to_string(startLine) + ", " + std::to_string(startCol) + ", " + std::to_string(endLine) + ", " + std::to_string(endCol) + ");" - ).c_str()); + ); return m_database.lastRowId(); } @@ -307,7 +294,6 @@ Id SqliteStorage::addError(const std::string& message, const FilePath& filePath, // check for duplicate CppSQLite3Statement stmt = m_database.compileStatement(( - //CppSQLite3Query q = m_database.execQuery(( "SELECT * FROM error WHERE " "message == ? AND " "fatal == " + std::to_string(fatal) + " AND " @@ -317,7 +303,7 @@ Id SqliteStorage::addError(const std::string& message, const FilePath& filePath, ).c_str()); stmt.bind(1, sanitizedMessage.c_str()); - CppSQLite3Query q = stmt.execQuery(); + CppSQLite3Query q = executeQuery(stmt); if (!q.eof()) { @@ -333,7 +319,7 @@ Id SqliteStorage::addError(const std::string& message, const FilePath& filePath, ).c_str()); stmt.bind(1, sanitizedMessage.c_str()); - stmt.execDML(); + executeStatement(stmt); return m_database.lastRowId(); } @@ -347,24 +333,24 @@ void SqliteStorage::removeElement(Id id) void SqliteStorage::removeElements(const std::vector& ids) { - m_database.execDML(( + executeStatement( "DELETE FROM element WHERE id IN (" + utility::join(utility::toStrings(ids), ',') + ");" - ).c_str()); + ); } void SqliteStorage::removeElementsWithLocationInFiles(const std::vector& fileIds) { // preparing - m_database.execDML("DROP TABLE IF EXISTS main.element_id_to_clear;"); + executeStatement("DROP TABLE IF EXISTS main.element_id_to_clear;"); - m_database.execDML( + executeStatement( "CREATE TABLE IF NOT EXISTS element_id_to_clear(" "id INTEGER NOT NULL, " "PRIMARY KEY(id));" ); // store ids of all elements located in fileIds into element_id_to_clear - m_database.execDML(( + executeStatement( "INSERT INTO element_id_to_clear " " SELECT occurrence.element_id " " FROM occurrence " @@ -373,85 +359,84 @@ void SqliteStorage::removeElementsWithLocationInFiles(const std::vector& fil " ) " " WHERE source_location.file_node_id IN (" + utility::join(utility::toStrings(fileIds), ',') + ")" " GROUP BY (occurrence.element_id)" - ).c_str()); + ); // delete all edges in element_id_to_clear - m_database.execDML( + executeStatement( "DELETE FROM element WHERE element.id IN (SELECT element_id_to_clear.id FROM element_id_to_clear INNER JOIN edge ON (element_id_to_clear.id = edge.id))" ); // delete all edges originating from element_id_to_clear - m_database.execDML( + executeStatement( "DELETE FROM element WHERE element.id IN (SELECT id FROM edge WHERE source_node_id IN (SELECT id FROM element_id_to_clear))" ); // remove all edges from element_id_to_clear (they have been cleared by now and we can disregard them) - m_database.execDML( + executeStatement( "DELETE FROM element_id_to_clear WHERE id IN (" " SELECT id FROM edge" ")" ); // remove all files from element_id_to_clear (they will be cleared later) - m_database.execDML( + executeStatement( "DELETE FROM element_id_to_clear WHERE id IN (" " SELECT id FROM file" ")" ); // delete source locations from fileIds (this also deletes the respective occurrences) - m_database.execDML(( + executeStatement( "DELETE FROM source_location WHERE file_node_id IN (" + utility::join(utility::toStrings(fileIds), ',') + ");" - ).c_str()); + ); // remove all ids from element_id_to_clear that still have occurrences - m_database.execDML( + executeStatement( "DELETE FROM element_id_to_clear WHERE id IN (" " SELECT element_id_to_clear.id FROM element_id_to_clear INNER JOIN occurrence ON element_id_to_clear.id = occurrence.element_id" ")" ); // remove all ids from element_id_to_clear that still have an edge pointing to them - m_database.execDML( + executeStatement( "DELETE FROM element_id_to_clear WHERE id IN (" " SELECT target_node_id FROM edge" ")" ); // delete all elements that are still listed in element_id_to_clear - m_database.execDML( + executeStatement( "DELETE FROM element WHERE id IN (" " SELECT id FROM element_id_to_clear" ")" ); // cleaning up - m_database.execDML("DROP TABLE IF EXISTS main.element_id_to_clear;"); - + executeStatement("DROP TABLE IF EXISTS main.element_id_to_clear;"); } void SqliteStorage::removeErrorsInFiles(const std::vector& filePaths) { - m_database.execDML(( + executeStatement( "DELETE FROM error WHERE file_path IN ('" + utility::join(utility::toStrings(filePaths), "', '") + "');" - ).c_str()); + ); } bool SqliteStorage::isEdge(Id elementId) const { - int count = m_database.execScalar(("SELECT count(*) FROM edge WHERE id = " + std::to_string(elementId) + ";").c_str()); + int count = executeScalar("SELECT count(*) FROM edge WHERE id = " + std::to_string(elementId) + ";"); return (count > 0); } bool SqliteStorage::isNode(Id elementId) const { - int count = m_database.execScalar(("SELECT count(*) FROM node WHERE id = " + std::to_string(elementId) + ";").c_str()); + int count = executeScalar("SELECT count(*) FROM node WHERE id = " + std::to_string(elementId) + ";"); return (count > 0); } bool SqliteStorage::isFile(Id elementId) const { - int count = m_database.execScalar(("SELECT count(*) FROM file WHERE id = " + std::to_string(elementId) + ";").c_str()); + int count = executeScalar("SELECT count(*) FROM file WHERE id = " + std::to_string(elementId) + ";"); return (count > 0); } @@ -535,7 +520,7 @@ StorageNode SqliteStorage::getNodeBySerializedName(const std::string& serialized ); stmt.bind(1, serializedName.c_str()); - CppSQLite3Query q = stmt.execQuery(); + CppSQLite3Query q = executeQuery(stmt); if (!q.eof()) { @@ -580,19 +565,12 @@ std::vector SqliteStorage::getFilesByPaths(const std::vector SqliteStorage::getFileContentById(Id fileId) const { - try + CppSQLite3Query q = executeQuery( + "SELECT content FROM filecontent WHERE id = '" + std::to_string(fileId) + "';" + ); + if (!q.eof()) { - CppSQLite3Query q = m_database.execQuery(( - "SELECT content FROM filecontent WHERE id = '" + std::to_string(fileId) + "';" - ).c_str()); - if (!q.eof()) - { - return TextAccess::createFromString(q.getStringField(0, "")); - } - } - catch (CppSQLite3Exception& e) - { - LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage()); + return TextAccess::createFromString(q.getStringField(0, "")); } return TextAccess::createFromString(""); @@ -602,12 +580,12 @@ std::shared_ptr SqliteStorage::getFileContentByPath(const std::strin { try { - CppSQLite3Query q = m_database.execQuery(( + CppSQLite3Query q = executeQuery( "SELECT filecontent.content " "FROM filecontent " "INNER JOIN file ON filecontent.id = file.id " "WHERE file.path = '" + filePath + "';" - ).c_str()); + ); if (!q.eof()) { @@ -624,16 +602,16 @@ std::shared_ptr SqliteStorage::getFileContentByPath(const std::strin void SqliteStorage::setNodeType(int type, Id nodeId) { - m_database.execDML(( + executeStatement( "UPDATE node SET type = " + std::to_string(type) + " WHERE id == " + std::to_string(nodeId) + ";" - ).c_str()); + ); } void SqliteStorage::setNodeDefinitionType(int definitionType, Id nodeId) { - m_database.execDML(( + executeStatement( "UPDATE node SET definition_type = " + std::to_string(definitionType) + " WHERE id == " + std::to_string(nodeId) + ";" - ).c_str()); + ); } StorageSourceLocation SqliteStorage::getSourceLocationById(const Id id) const @@ -701,7 +679,7 @@ std::vector> SqliteStorage::getSourceLocati std::vector> SqliteStorage::getAllSourceLocationsAndElementIds(const std::string& query) const { - CppSQLite3Query q = m_database.execQuery(( + CppSQLite3Query q = executeQuery( "SELECT " "source_location.id, " "source_location.file_node_id, " @@ -713,7 +691,7 @@ std::vector> SqliteStorage::getAllSourceLoc "occurrence.element_id " "FROM source_location " "INNER JOIN occurrence ON occurrence.source_location_id = source_location.id " + query + ";" - ).c_str()); + ); std::vector> ret; while (!q.eof()) @@ -748,7 +726,7 @@ std::vector> SqliteStorage::getAllSourceLoc std::vector> SqliteStorage::getAllSourceLocationsAndElementIdsForFileId(Id fileNodeId) const { - CppSQLite3Query q = m_database.execQuery(( + CppSQLite3Query q = executeQuery( "SELECT " "source_location.id, " "source_location.file_node_id, " @@ -758,7 +736,7 @@ std::vector> SqliteStorage::getAllSourceLoc "source_location.end_column, " "source_location.type " "FROM source_location WHERE source_location.file_node_id == " + std::to_string(fileNodeId) + ";" - ).c_str()); + ); std::map locations; std::vector locationIds; @@ -791,12 +769,12 @@ std::vector> SqliteStorage::getAllSourceLoc q.nextRow(); } - CppSQLite3Query q2 = m_database.execQuery(( + CppSQLite3Query q2 = executeQuery( "SELECT " "occurrence.element_id, " "occurrence.source_location_id " "FROM occurrence WHERE occurrence.source_location_id IN (" + utility::join(utility::toStrings(locationIds), ',') + ");" - ).c_str()); + ); std::vector> ret; while (!q2.eof()) @@ -891,43 +869,50 @@ std::vector SqliteStorage::getAllErrors() const int SqliteStorage::getNodeCount() const { - return m_database.execScalar("SELECT COUNT(*) FROM node;"); + return executeScalar("SELECT COUNT(*) FROM node;"); } int SqliteStorage::getEdgeCount() const { - return m_database.execScalar("SELECT COUNT(*) FROM edge;"); + return executeScalar("SELECT COUNT(*) FROM edge;"); } int SqliteStorage::getFileCount() const { - return m_database.execScalar("SELECT COUNT(*) FROM file;"); + return executeScalar("SELECT COUNT(*) FROM file;"); } int SqliteStorage::getFileLOCCount() const { - return m_database.execScalar("SELECT SUM(loc) FROM file;"); + return executeScalar("SELECT SUM(loc) FROM file;"); } int SqliteStorage::getSourceLocationCount() const { - return m_database.execScalar("SELECT COUNT(*) FROM source_location;"); + return executeScalar("SELECT COUNT(*) FROM source_location;"); } void SqliteStorage::clearTables() { - m_database.execDML("DROP TABLE IF EXISTS main.error;"); - m_database.execDML("DROP TABLE IF EXISTS main.comment_location;"); - m_database.execDML("DROP TABLE IF EXISTS main.component_access;"); - m_database.execDML("DROP TABLE IF EXISTS main.occurrence;"); - m_database.execDML("DROP TABLE IF EXISTS main.source_location;"); - m_database.execDML("DROP TABLE IF EXISTS main.local_symbol;"); - m_database.execDML("DROP TABLE IF EXISTS main.filecontent;"); - m_database.execDML("DROP TABLE IF EXISTS main.file;"); - m_database.execDML("DROP TABLE IF EXISTS main.node;"); - m_database.execDML("DROP TABLE IF EXISTS main.edge;"); - m_database.execDML("DROP TABLE IF EXISTS main.element;"); - m_database.execDML("DROP TABLE IF EXISTS main.meta;"); + try + { + m_database.execDML("DROP TABLE IF EXISTS main.error;"); + m_database.execDML("DROP TABLE IF EXISTS main.comment_location;"); + m_database.execDML("DROP TABLE IF EXISTS main.component_access;"); + m_database.execDML("DROP TABLE IF EXISTS main.occurrence;"); + m_database.execDML("DROP TABLE IF EXISTS main.source_location;"); + m_database.execDML("DROP TABLE IF EXISTS main.local_symbol;"); + m_database.execDML("DROP TABLE IF EXISTS main.filecontent;"); + m_database.execDML("DROP TABLE IF EXISTS main.file;"); + m_database.execDML("DROP TABLE IF EXISTS main.node;"); + m_database.execDML("DROP TABLE IF EXISTS main.edge;"); + m_database.execDML("DROP TABLE IF EXISTS main.element;"); + m_database.execDML("DROP TABLE IF EXISTS main.meta;"); + } + catch (CppSQLite3Exception& e) + { + LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage()); + } } void SqliteStorage::setupTables() @@ -1059,11 +1044,75 @@ void SqliteStorage::setupTables() } } +void SqliteStorage::executeStatement(const std::string& statement) const +{ + try + { + m_database.execDML(statement.c_str()); + } + catch(CppSQLite3Exception e) + { + LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage()); + } +} + +void SqliteStorage::executeStatement(CppSQLite3Statement& statement) const +{ + try + { + statement.execDML(); + } + catch(CppSQLite3Exception e) + { + LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage()); + } +} + +int SqliteStorage::executeScalar(const std::string& statement) const +{ + int ret = 0; + try + { + ret = m_database.execScalar(statement.c_str()); + } + catch(CppSQLite3Exception e) + { + LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage()); + } + return ret; +} + +CppSQLite3Query SqliteStorage::executeQuery(const std::string& query) const +{ + try + { + return m_database.execQuery(query.c_str()); + } + catch(CppSQLite3Exception e) + { + LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage()); + } + return CppSQLite3Query(); +} + +CppSQLite3Query SqliteStorage::executeQuery(CppSQLite3Statement& statement) const +{ + try + { + return statement.execQuery(); + } + catch(CppSQLite3Exception e) + { + LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage()); + } + return CppSQLite3Query(); +} + bool SqliteStorage::hasTable(const std::string& tableName) const { - CppSQLite3Query q = m_database.execQuery(( + CppSQLite3Query q = executeQuery( "SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "';" - ).c_str()); + ); if (!q.eof()) { @@ -1077,7 +1126,7 @@ std::string SqliteStorage::getMetaValue(const std::string& key) const { if (hasTable("meta")) { - CppSQLite3Query q = m_database.execQuery(("SELECT value FROM meta WHERE key = '" + key + "';").c_str()); + CppSQLite3Query q = executeQuery("SELECT value FROM meta WHERE key = '" + key + "';"); if (!q.eof()) { @@ -1099,7 +1148,7 @@ void SqliteStorage::insertOrUpdateMetaValue(const std::string& key, const std::s stmt.bind(1, key.c_str()); stmt.bind(2, key.c_str()); stmt.bind(3, value.c_str()); - stmt.execDML(); + executeStatement(stmt); } size_t SqliteStorage::getStorageVersion() const @@ -1139,10 +1188,10 @@ void SqliteStorage::setApplicationVersion() template <> std::vector SqliteStorage::getAll(const std::string& query) const { - CppSQLite3Query q = m_database.execQuery(( + CppSQLite3Query q = executeQuery( "SELECT file.id, node.serialized_name, file.path, file.modification_time FROM file " "INNER JOIN node ON file.id = node.id " + query + ";" - ).c_str()); + ); std::vector files; while (!q.eof()) @@ -1165,9 +1214,9 @@ std::vector SqliteStorage::getAll(const std::string& q template <> std::vector SqliteStorage::getAll(const std::string& query) const { - CppSQLite3Query q = m_database.execQuery(( + CppSQLite3Query q = executeQuery( "SELECT id, type, source_node_id, target_node_id FROM edge " + query + ";" - ).c_str()); + ); std::vector edges; while (!q.eof()) @@ -1190,9 +1239,9 @@ std::vector SqliteStorage::getAll(const std::string& q template <> std::vector SqliteStorage::getAll(const std::string& query) const { - CppSQLite3Query q = m_database.execQuery(( + CppSQLite3Query q = executeQuery( "SELECT id, type, serialized_name, definition_type FROM node " + query + ";" - ).c_str()); + ); std::vector nodes; while (!q.eof()) @@ -1215,9 +1264,9 @@ std::vector SqliteStorage::getAll(const std::string& q template <> std::vector SqliteStorage::getAll(const std::string& query) const { - CppSQLite3Query q = m_database.execQuery(( + CppSQLite3Query q = executeQuery( "SELECT id, name FROM local_symbol " + query + ";" - ).c_str()); + ); std::vector localSymbols; @@ -1239,9 +1288,9 @@ std::vector SqliteStorage::getAll(const template <> std::vector SqliteStorage::getAll(const std::string& query) const { - CppSQLite3Query q = m_database.execQuery(( + CppSQLite3Query q = executeQuery( "SELECT id, file_node_id, start_line, start_column, end_line, end_column, type FROM source_location " + query + ";" - ).c_str()); + ); std::vector sourceLocations; @@ -1268,9 +1317,9 @@ std::vector SqliteStorage::getAll( template <> std::vector SqliteStorage::getAll(const std::string& query) const { - CppSQLite3Query q = m_database.execQuery(( + CppSQLite3Query q = executeQuery( "SELECT element_id, source_location_id FROM occurrence " + query + ";" - ).c_str()); + ); std::vector occurrences; @@ -1292,9 +1341,9 @@ std::vector SqliteStorage::getAll(const st template <> std::vector SqliteStorage::getAll(const std::string& query) const { - CppSQLite3Query q = m_database.execQuery(( + CppSQLite3Query q = executeQuery( "SELECT id, node_id, type FROM component_access " + query + ";" - ).c_str()); + ); std::vector componentAccesses; @@ -1317,9 +1366,9 @@ std::vector SqliteStorage::getAll std::vector SqliteStorage::getAll(const std::string& query) const { - CppSQLite3Query q = m_database.execQuery(( + CppSQLite3Query q = executeQuery( "SELECT id, file_node_id, start_line, start_column, end_line, end_column FROM comment_location " + query + ";" - ).c_str()); + ); std::vector commentLocations; @@ -1347,9 +1396,9 @@ std::vector SqliteStorage::getAll std::vector SqliteStorage::getAll(const std::string& query) const { - CppSQLite3Query q = m_database.execQuery(( + CppSQLite3Query q = executeQuery( "SELECT message, fatal, indexed, file_path, line_number, column_number FROM error " + query + ";" - ).c_str()); + ); std::vector errors; Id id = 1; diff --git a/src/lib/data/SqliteStorage.h b/src/lib/data/SqliteStorage.h index 88d1bbb4..ca190753 100644 --- a/src/lib/data/SqliteStorage.h +++ b/src/lib/data/SqliteStorage.h @@ -142,6 +142,12 @@ private: void clearTables(); void setupTables(); + void executeStatement(const std::string& statement) const; + void executeStatement(CppSQLite3Statement& statement) const; + int executeScalar(const std::string& statement) const; + CppSQLite3Query executeQuery(const std::string& statement) const; + CppSQLite3Query executeQuery(CppSQLite3Statement& statement) const; + bool hasTable(const std::string& tableName) const; std::string getMetaValue(const std::string& key) const; diff --git a/src/lib_cxx/CMakeLists.txt b/src/lib_cxx/CMakeLists.txt index f8f2a1fa..241c5d6d 100644 --- a/src/lib_cxx/CMakeLists.txt +++ b/src/lib_cxx/CMakeLists.txt @@ -34,6 +34,16 @@ add_files( data/parser/cxx/CommentHandler.h data/parser/cxx/CxxAstVisitor.cpp data/parser/cxx/CxxAstVisitor.h + data/parser/cxx/CxxAstVisitorComponent.cpp + data/parser/cxx/CxxAstVisitorComponent.h + data/parser/cxx/CxxAstVisitorComponentContext.cpp + data/parser/cxx/CxxAstVisitorComponentContext.h + data/parser/cxx/CxxAstVisitorComponentDeclRefKind.cpp + data/parser/cxx/CxxAstVisitorComponentDeclRefKind.h + data/parser/cxx/CxxAstVisitorComponentIndexer.cpp + data/parser/cxx/CxxAstVisitorComponentIndexer.h + data/parser/cxx/CxxAstVisitorComponentTypeRefKind.cpp + data/parser/cxx/CxxAstVisitorComponentTypeRefKind.h data/parser/cxx/CxxCompilationDatabaseSingle.cpp data/parser/cxx/CxxCompilationDatabaseSingle.h data/parser/cxx/CxxContext.cpp @@ -46,6 +56,8 @@ add_files( data/parser/cxx/CxxVerboseAstVisitor.h data/parser/cxx/PreprocessorCallbacks.cpp data/parser/cxx/PreprocessorCallbacks.h + data/parser/cxx/utilityCxxAstVisitor.cpp + data/parser/cxx/utilityCxxAstVisitor.h utility/CompilationDatabase.cpp utility/CompilationDatabase.h diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp index be29d1b6..2e5bd599 100644 --- a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp @@ -1,25 +1,25 @@ #include "data/parser/cxx/CxxAstVisitor.h" -#include -#include +#include #include -#include "data/parser/ParseLocation.h" -#include "data/parser/ParserClient.h" -#include "utility/file/FileRegister.h" -#include "utility/ScopedFunctor.h" -#include "utility/ScopedSwitcher.h" - #include "data/parser/cxx/name_resolver/CxxDeclNameResolver.h" #include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h" +#include "data/parser/cxx/CxxAstVisitorComponent.h" +#include "data/parser/cxx/CxxAstVisitorComponentContext.h" +#include "data/parser/cxx/CxxAstVisitorComponentDeclRefKind.h" +#include "data/parser/cxx/CxxAstVisitorComponentTypeRefKind.h" +#include "data/parser/cxx/CxxAstVisitorComponentIndexer.h" +#include "data/parser/cxx/utilityCxxAstVisitor.h" + +#include "data/parser/ParseLocation.h" + CxxAstVisitor::CxxAstVisitor(clang::ASTContext* astContext, clang::Preprocessor* preprocessor, ParserClient* client, FileRegister* fileRegister) : m_astContext(astContext) , m_preprocessor(preprocessor) , m_client(client) , m_fileRegister(fileRegister) - , m_typeRefContext(REFERENCE_TYPE_USAGE) - , m_declRefContext(REFERENCE_USAGE) { m_declNameCache = std::make_shared([](const clang::NamedDecl* decl) -> NameHierarchy { @@ -45,12 +45,55 @@ CxxAstVisitor::CxxAstVisitor(clang::ASTContext* astContext, clang::Preprocessor* } return NameHierarchy("global"); }); + + m_contextComponent = std::make_shared(this); + m_components.push_back(m_contextComponent); + m_typeRefKindComponent = std::make_shared(this); + m_components.push_back(m_typeRefKindComponent); + m_declRefKindComponent = std::make_shared(this); + m_components.push_back(m_declRefKindComponent); + m_indexerComponent = std::make_shared(this, astContext, client, fileRegister); + m_components.push_back(m_indexerComponent); } CxxAstVisitor::~CxxAstVisitor() { } +template <> +std::shared_ptr CxxAstVisitor::getComponent() +{ + return m_contextComponent; +} + +template <> +std::shared_ptr CxxAstVisitor::getComponent() +{ + return m_typeRefKindComponent; +} + +template <> +std::shared_ptr CxxAstVisitor::getComponent() +{ + return m_declRefKindComponent; +} + +template <> +std::shared_ptr CxxAstVisitor::getComponent() +{ + return m_indexerComponent; +} + +std::shared_ptr CxxAstVisitor::getDeclNameCache() +{ + return m_declNameCache; +} + +std::shared_ptr CxxAstVisitor::getTypeNameCache() +{ + return m_typeNameCache; +} + void CxxAstVisitor::indexDecl(clang::Decl* d) { this->TraverseDecl(d); @@ -66,59 +109,84 @@ bool CxxAstVisitor::shouldVisitImplicitCode() const return true; } -bool CxxAstVisitor::TraverseDecl(clang::Decl* d) +bool CxxAstVisitor::checkIgnoresTypeLoc(const clang::TypeLoc& tl) const { - std::shared_ptr removeContextFunctor; - if (d && - clang::isa(d) && - !clang::isa(d) && // no parameter - !(clang::isa(d) && d->getParentFunctionOrMethod() != NULL) && // no local variable - !clang::isa(d) && // no using directive decl - !clang::isa(d) && // no using decl - !clang::isa(d) // no namespace - ){ - clang::NamedDecl* nd = clang::dyn_cast(d); - m_contextStack.push_back(std::make_shared(nd, m_declNameCache)); - removeContextFunctor = std::make_shared([this](){ m_contextStack.pop_back(); }); + if ((!tl.getAs().isNull()) || + (!tl.getAs().isNull()) || + (!tl.getAs().isNull()) || + (!tl.getAs().isNull()) || + (!tl.getAs().isNull()) || + (!tl.getAs().isNull()) || + (!tl.getAs().isNull()) || + (!tl.getAs().isNull()) || + (!tl.getAs().isNull()) + ){ + return false; } - return ( - m_interruptCounter.getCount() == 0 && - base::TraverseDecl(d) - ); + return true; } -bool CxxAstVisitor::TraverseStmt(clang::Stmt* stmt) -{ - return base::TraverseStmt(stmt); -} +#define DEF_TRAVERSE_CUSTOM_TYPE_PTR(__NAME_TYPE__, __PARAM_TYPE__, CODE_BEFORE, CODE_AFTER) \ + bool CxxAstVisitor::Traverse##__NAME_TYPE__(clang::__PARAM_TYPE__* v) \ + { \ + for (auto it = m_components.begin(); it != m_components.end(); it++) \ + { \ + (*it)->beginTraverse##__NAME_TYPE__(v); \ + } \ + bool ret = true; \ + { CODE_BEFORE; } \ + Base::Traverse##__NAME_TYPE__(v); \ + { CODE_AFTER; } \ + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) \ + { \ + (*it)->endTraverse##__NAME_TYPE__(v); \ + } \ + return ret; \ + } -bool CxxAstVisitor::TraverseType(clang::QualType t) -{ - return base::TraverseType(t); -} +#define DEF_TRAVERSE_CUSTOM_TYPE(__NAME_TYPE__, __PARAM_TYPE__, CODE_BEFORE, CODE_AFTER) \ + bool CxxAstVisitor::Traverse##__NAME_TYPE__(clang::__PARAM_TYPE__ v) \ + { \ + for (auto it = m_components.begin(); it != m_components.end(); it++) \ + { \ + (*it)->beginTraverse##__NAME_TYPE__(v); \ + } \ + bool ret = true; \ + { CODE_BEFORE; } \ + Base::Traverse##__NAME_TYPE__(v); \ + { CODE_AFTER; } \ + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) \ + { \ + (*it)->endTraverse##__NAME_TYPE__(v); \ + } \ + return ret; \ + } -// same as base::TraverseQualifiedTypeLoc(..) but we need to make sure to call this.TraverseTypeLoc(..) +#define DEF_TRAVERSE_TYPE_PTR(__TYPE__, CODE_BEFORE, CODE_AFTER) \ + DEF_TRAVERSE_CUSTOM_TYPE_PTR(__TYPE__, __TYPE__, CODE_BEFORE, CODE_AFTER) + +#define DEF_TRAVERSE_TYPE(__TYPE__, CODE_BEFORE, CODE_AFTER) \ + DEF_TRAVERSE_CUSTOM_TYPE(__TYPE__, __TYPE__, CODE_BEFORE, CODE_AFTER) + +DEF_TRAVERSE_TYPE_PTR(Decl, {}, {}) + +DEF_TRAVERSE_TYPE_PTR(Stmt, {}, {}) + +DEF_TRAVERSE_CUSTOM_TYPE(Type, QualType, {}, {}) + +// same as Base::TraverseQualifiedTypeLoc(..) but we need to make sure to call this.TraverseTypeLoc(..) bool CxxAstVisitor::TraverseQualifiedTypeLoc(clang::QualifiedTypeLoc tl) { return TraverseTypeLoc(tl.getUnqualifiedLoc()); } -bool CxxAstVisitor::TraverseTypeLoc(clang::TypeLoc tl) -{ - std::shared_ptr removeContextFunctor; - if (!checkIgnoresTypeLoc(tl)) - { - m_contextStack.push_back(std::make_shared(tl.getTypePtr(), m_typeNameCache)); - removeContextFunctor = std::make_shared([this](){ m_contextStack.pop_back(); }); - } - return base::TraverseTypeLoc(tl); -} +DEF_TRAVERSE_TYPE(TypeLoc, {}, {}) -// same as base::TraverseCXXRecordDecl(..) but we need to integrate the setter for the context info. +// same as Base::TraverseCXXRecordDecl(..) but we need to integrate the setter for the context info. // additionally: skip implicit CXXRecordDecls (this does not skip template specializations). bool CxxAstVisitor::TraverseCXXRecordDecl(clang::CXXRecordDecl *d) { - if (isImplicit(d)) + if (utility::isImplicit(d)) { return true; } @@ -129,10 +197,9 @@ bool CxxAstVisitor::TraverseCXXRecordDecl(clang::CXXRecordDecl *d) if (d->isCompleteDefinition()) { - ScopedSwitcher switcher(m_typeRefContext, REFERENCE_INHERITANCE); for (const auto& base : d->bases()) { - if (!TraverseTypeLoc(base.getTypeSourceInfo()->getTypeLoc())) + if (!traverseCXXBaseSpecifier(base)) { return false; } @@ -143,22 +210,43 @@ bool CxxAstVisitor::TraverseCXXRecordDecl(clang::CXXRecordDecl *d) return true; } -// same as base::TraverseTemplateTypeParmDecl(..) but we need to integrate the setter for the context info. +bool CxxAstVisitor::traverseCXXBaseSpecifier(const clang::CXXBaseSpecifier& d) +{ + for (auto it = m_components.begin(); it != m_components.end(); it++) + { + (*it)->beginTraverseCXXBaseSpecifier(); + } + bool ret = TraverseTypeLoc(d.getTypeSourceInfo()->getTypeLoc()); + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) + { + (*it)->endTraverseCXXBaseSpecifier(); + } + return ret; +} + +// same as Base::TraverseTemplateTypeParmDecl(..) but we need to integrate the setter for the context info. bool CxxAstVisitor::TraverseTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d) { WalkUpFromTemplateTypeParmDecl(d); if (d->hasDefaultArgument() && !d->defaultArgumentWasInherited()) { - ScopedSwitcher switcher(m_typeRefContext, REFERENCE_TEMPLATE_DEFAULT_ARGUMENT); + for (auto it = m_components.begin(); it != m_components.end(); it++) + { + (*it)->beginTraverseTemplateDefaultArgumentLoc(); + } TraverseTypeLoc(d->getDefaultArgumentInfo()->getTypeLoc()); + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) + { + (*it)->endTraverseTemplateDefaultArgumentLoc(); + } } traverseDeclContextHelper(clang::dyn_cast(d)); return true; } -// same as base::TraverseTemplateTemplateParmDecl(..) but we need to integrate the setter for the context info. +// same as Base::TraverseTemplateTemplateParmDecl(..) but we need to integrate the setter for the context info. bool CxxAstVisitor::TraverseTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d) { WalkUpFromTemplateTemplateParmDecl(d); @@ -167,8 +255,15 @@ bool CxxAstVisitor::TraverseTemplateTemplateParmDecl(clang::TemplateTemplateParm if (d->hasDefaultArgument() && !d->defaultArgumentWasInherited()) { - ScopedSwitcher switcher(m_typeRefContext, REFERENCE_TEMPLATE_DEFAULT_ARGUMENT); + for (auto it = m_components.begin(); it != m_components.end(); it++) + { + (*it)->beginTraverseTemplateDefaultArgumentLoc(); + } TraverseTemplateArgumentLoc(d->getDefaultArgument()); + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) + { + (*it)->endTraverseTemplateDefaultArgumentLoc(); + } } clang::TemplateParameterList* TPL = d->getTemplateParameters(); @@ -192,11 +287,23 @@ bool CxxAstVisitor::TraverseNestedNameSpecifierLoc(clang::NestedNameSpecifierLoc bool CxxAstVisitor::TraverseConstructorInitializer(clang::CXXCtorInitializer* init) { + for (auto it = m_components.begin(); it != m_components.end(); it++) + { + (*it)->beginTraverseConstructorInitializer(init); + } + if (!VisitConstructorInitializer(init)) { return false; } - return base::TraverseConstructorInitializer(init); + bool ret = Base::TraverseConstructorInitializer(init); + + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) + { + (*it)->endTraverseConstructorInitializer(init); + } + + return ret; } bool CxxAstVisitor::TraverseCallExpr(clang::CallExpr* s) @@ -217,130 +324,97 @@ bool CxxAstVisitor::TraverseCXXOperatorCallExpr(clang::CXXOperatorCallExpr* s) bool CxxAstVisitor::TraverseCXXConstructExpr(clang::CXXConstructExpr* s) { { - ScopedSwitcher switcher(m_declRefContext, REFERENCE_CALL); + for (auto it = m_components.begin(); it != m_components.end(); it++) + { + (*it)->beginTraverseCallCommonCallee(); + } WalkUpFromCXXConstructExpr(s); + for (auto it = m_components.begin(); it != m_components.end(); it++) + { + (*it)->endTraverseCallCommonCallee(); + } } - for (unsigned int i = 0; i < s->getNumArgs(); ++i) { - clang::Expr *arg = s->getArg(i); - TraverseStmt(arg); + for (unsigned int i = 0; i < s->getNumArgs(); ++i) + { + for (auto it = m_components.begin(); it != m_components.end(); it++) + { + (*it)->beginTraverseCallCommonArgument(); + } + TraverseStmt(s->getArg(i)); + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) + { + (*it)->endTraverseCallCommonArgument(); + } } return true; } -bool CxxAstVisitor::TraverseCXXTemporaryObjectExpr(clang::CXXTemporaryObjectExpr* s) -{ - ScopedSwitcher switcher(m_declRefContext, REFERENCE_CALL); - return base::TraverseCXXTemporaryObjectExpr(s); -} - -bool CxxAstVisitor::TraverseLambdaExpr(clang::LambdaExpr* s) -{ - clang::CXXMethodDecl* methodDecl = s->getCallOperator(); - m_contextStack.push_back(std::make_shared(methodDecl, m_declNameCache)); - std::shared_ptr removeContextFunctor = std::make_shared([this](){ m_contextStack.pop_back(); }); - return base::TraverseLambdaExpr(s); -} - -bool CxxAstVisitor::TraverseFunctionDecl(clang::FunctionDecl* d) -{ - ScopedSwitcher> switcher( - m_templateArgumentContext, std::make_shared(d, m_declNameCache) - ); - return base::TraverseFunctionDecl(d); -} - -bool CxxAstVisitor::TraverseClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl *d) -{ - ScopedSwitcher> switcher( - m_templateArgumentContext, std::make_shared(d, m_declNameCache) - ); - return base::TraverseClassTemplateSpecializationDecl(d); -} - -bool CxxAstVisitor::TraverseClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* d) -{ - ScopedSwitcher> switcher( - m_templateArgumentContext, std::make_shared(d, m_declNameCache) - ); - return base::TraverseClassTemplatePartialSpecializationDecl(d); -} - -bool CxxAstVisitor::TraverseDeclRefExpr(clang::DeclRefExpr* s) -{ - ScopedSwitcher> switcher( - m_templateArgumentContext, std::make_shared(s->getDecl(), m_declNameCache) - ); - return base::TraverseDeclRefExpr(s); -} - -bool CxxAstVisitor::TraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc) -{ - const clang::Type* t = loc.getTypePtr(); - ScopedSwitcher> switcher( - m_templateArgumentContext, std::make_shared(t, m_typeNameCache) - ); - return base::TraverseTemplateSpecializationTypeLoc(loc); -} - -bool CxxAstVisitor::TraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* e) // TODO: do this for unresolved and dependent stuff -{ - std::shared_ptr clear; - ScopedSwitcher> sw(m_templateArgumentContext, clear); - return base::TraverseUnresolvedLookupExpr(e); -} - +DEF_TRAVERSE_TYPE_PTR(CXXTemporaryObjectExpr, {}, {}) +DEF_TRAVERSE_TYPE_PTR(LambdaExpr, {}, {}) +DEF_TRAVERSE_TYPE_PTR(FunctionDecl, {}, {}) +DEF_TRAVERSE_TYPE_PTR(ClassTemplateSpecializationDecl, {}, {}) +DEF_TRAVERSE_TYPE_PTR(ClassTemplatePartialSpecializationDecl, {}, {}) +DEF_TRAVERSE_TYPE_PTR(DeclRefExpr, {}, {}) +DEF_TRAVERSE_TYPE(TemplateSpecializationTypeLoc, {}, {}) +DEF_TRAVERSE_TYPE_PTR(UnresolvedLookupExpr, {}, {}) bool CxxAstVisitor::TraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc) { - std::shared_ptr> switcher; - std::shared_ptr removeContextFunctor; - - if (m_typeRefContext != REFERENCE_TEMPLATE_DEFAULT_ARGUMENT && m_templateArgumentContext) + for (auto it = m_components.begin(); it != m_components.end(); it++) { - switcher = std::make_shared>(m_typeRefContext, REFERENCE_TEMPLATE_ARGUMENT); - - m_contextStack.push_back(m_templateArgumentContext); - removeContextFunctor = std::make_shared([this](){ m_contextStack.pop_back(); }); + (*it)->beginTraverseTemplateArgumentLoc(loc); } - if ( - (loc.getArgument().getKind() == clang::TemplateArgument::Template) && - (shouldVisitReference(loc.getLocation(), getTopmostContextDecl())) - ){ - // TODO: maybe move this to VisitTemplateName - m_client->recordReference( - m_typeRefContext, - m_declNameCache->getValue(loc.getArgument().getAsTemplate().getAsTemplateDecl()), - getContextName(), - getParseLocation(loc.getLocation()) - ); - } + bool ret = Base::TraverseTemplateArgumentLoc(loc); - return base::TraverseTemplateArgumentLoc(loc); + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) + { + (*it)->endTraverseTemplateArgumentLoc(loc); + } + return ret; } bool CxxAstVisitor::TraverseLambdaCapture(clang::LambdaExpr *lambdaExpr, const clang::LambdaCapture *capture) { + for (auto it = m_components.begin(); it != m_components.end(); it++) + { + (*it)->beginTraverseLambdaCapture(lambdaExpr, capture); + } + + bool ret = true; + if (lambdaExpr->isInitCapture(capture)) { - TraverseDecl(capture->getCapturedVar()); + ret = TraverseDecl(capture->getCapturedVar()); } - else if (capture->capturesVariable()) + + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) { - clang::VarDecl* d = capture->getCapturedVar(); - SymbolKind symbolKind = getSymbolKind(d); - if (symbolKind == SYMBOL_LOCAL_VARIABLE || symbolKind == SYMBOL_PARAMETER) - { - if (!d->getNameAsString().empty()) // don't record anonymous parameters - { - ParseLocation declLocation = getParseLocation(d->getLocation()); - std::string name = - declLocation.filePath.fileName() + "<" + - std::to_string(declLocation.startLineNumber) + ":" + - std::to_string(declLocation.startColumnNumber) + ">"; - m_client->onLocalSymbolParsed(name, getParseLocation(capture->getLocation())); - } - } + (*it)->endTraverseLambdaCapture(lambdaExpr, capture); + } + return ret; +} + +bool CxxAstVisitor::TraverseBinComma(clang::BinaryOperator* s) +{ + for (auto it = m_components.begin(); it != m_components.end(); it++) + { + (*it)->beginTraverseBinCommaLhs(); + } + TraverseStmt(s->getLHS()); + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) + { + (*it)->endTraverseBinCommaLhs(); + } + + for (auto it = m_components.begin(); it != m_components.end(); it++) + { + (*it)->beginTraverseBinCommaRhs(); + } + TraverseStmt(s->getRHS()); + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) + { + (*it)->endTraverseBinCommaRhs(); } return true; } @@ -348,702 +422,137 @@ bool CxxAstVisitor::TraverseLambdaCapture(clang::LambdaExpr *lambdaExpr, const c void CxxAstVisitor::traverseDeclContextHelper(clang::DeclContext* d) { if (!d) + { return; + } // Traverse children. for (clang::DeclContext::decl_iterator it = d->decls_begin(), - itEnd = d->decls_end(); it != itEnd; ++it) { + itEnd = d->decls_end(); it != itEnd; ++it) + { // BlockDecls are traversed through BlockExprs. if (!llvm::isa(*it)) + { TraverseDecl(*it); + } } } bool CxxAstVisitor::TraverseCallCommon(clang::CallExpr* s) { + for (auto it = m_components.begin(); it != m_components.end(); it++) { - ScopedSwitcher switcher(m_declRefContext, REFERENCE_CALL); - TraverseStmt(s->getCallee()); + (*it)->beginTraverseCallCommonCallee(); } - for (unsigned int i = 0; i < s->getNumArgs(); ++i) { - clang::Expr *arg = s->getArg(i); - TraverseStmt(arg); - } - return true; -} - -bool CxxAstVisitor::VisitTagDecl(clang::TagDecl* d) -{ - if (shouldVisitDecl(d)) + TraverseStmt(s->getCallee()); + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) { - m_client->recordSymbol( - m_declNameCache->getValue(d), - convertTagKind(d->getTagKind()), - getParseLocation(d->getLocation()), - getParseLocationOfTagDeclBody(d), - convertAccessSpecifier(d->getAccess()), - isImplicit(d) - ); + (*it)->endTraverseCallCommonCallee(); } - return true; -} -bool CxxAstVisitor::VisitClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl* d) -{ - if (shouldVisitDecl(d)) + for (unsigned int i = 0; i < s->getNumArgs(); ++i) { - clang::NamedDecl* specializedFromDecl; - - // todo: use context and childcontext!! - llvm::PointerUnion pu = d->getSpecializedTemplateOrPartial(); - if (pu.is()) + for (auto it = m_components.begin(); it != m_components.end(); it++) { - specializedFromDecl = pu.get(); + (*it)->beginTraverseCallCommonArgument(); } - else if (pu.is()) + TraverseStmt(s->getArg(i)); + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) { - specializedFromDecl = pu.get(); - } - - m_client->recordReference( - REFERENCE_TEMPLATE_SPECIALIZATION_OF, // TODO: call this REFERENCE_TEMPLATE_SPECIALIZATION and reverse the following arguments - m_declNameCache->getValue(specializedFromDecl), - m_declNameCache->getValue(d), - getParseLocation(d->getLocation()) - ); - } - return true; -} - -bool CxxAstVisitor::VisitFunctionDecl(clang::FunctionDecl* d) -{ - if (shouldVisitDecl(d)) - { - m_client->recordSymbol( - m_declNameCache->getValue(d), - clang::isa(d) ? SYMBOL_METHOD : SYMBOL_FUNCTION, - getParseLocation(d->getLocation()), - getParseLocationOfFunctionBody(d), - convertAccessSpecifier(d->getAccess()), - isImplicit(d) - ); - - if (d->isFunctionTemplateSpecialization()) - { - m_client->recordReference( - REFERENCE_TEMPLATE_SPECIALIZATION_OF, // TODO: call this REFERENCE_TEMPLATE_SPECIALIZATION and reverse the following arguments - m_declNameCache->getValue(d->getPrimaryTemplate()->getTemplatedDecl()), // todo: use context and childcontext!! - m_declNameCache->getValue(d), - getParseLocation(d->getLocation()) - ); + (*it)->endTraverseCallCommonArgument(); } } return true; } -bool CxxAstVisitor::VisitCXXMethodDecl(clang::CXXMethodDecl* d) +bool CxxAstVisitor::TraverseAssignCommon(clang::BinaryOperator* s) { - // Decl has been recorded in VisitFunctionDecl - if (shouldVisitDecl(d)) + for (auto it = m_components.begin(); it != m_components.end(); it++) { - for (clang::CXXMethodDecl::method_iterator it = d->begin_overridden_methods(); // iterate in traversal and use RT_Overridden or so.. - it != d->end_overridden_methods(); it++) - { - m_client->recordReference( - REFERENCE_OVERRIDE, - m_declNameCache->getValue(*it), - m_declNameCache->getValue(d), - getParseLocation(d->getLocation()) - ); - } + (*it)->beginTraverseAssignCommonLhs(); + } + TraverseStmt(s->getLHS()); + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) + { + (*it)->endTraverseAssignCommonLhs(); + } - clang::MemberSpecializationInfo* memberSpecializationInfo = d->getMemberSpecializationInfo(); - if (memberSpecializationInfo) - { - clang::NamedDecl* specializedNamedDecl = memberSpecializationInfo->getInstantiatedFrom(); - if (clang::isa(specializedNamedDecl)) - { - m_client->recordReference( - REFERENCE_TEMPLATE_MEMBER_SPECIALIZATION_OF, - m_declNameCache->getValue(specializedNamedDecl), - m_declNameCache->getValue(d), - getParseLocation(d->getLocation()) - ); - } - } + for (auto it = m_components.begin(); it != m_components.end(); it++) + { + (*it)->beginTraverseAssignCommonRhs(); + } + TraverseStmt(s->getRHS()); + for (auto it = m_components.rbegin(); it != m_components.rend(); it++) + { + (*it)->endTraverseAssignCommonRhs(); } return true; } -bool CxxAstVisitor::VisitVarDecl(clang::VarDecl* d) -{ - if (shouldVisitDecl(d)) - { - SymbolKind symbolKind = getSymbolKind(d); - if (symbolKind == SYMBOL_LOCAL_VARIABLE || symbolKind == SYMBOL_PARAMETER) - { - if (!d->getNameAsString().empty()) // don't record anonymous parameters - { - ParseLocation declLocation = getParseLocation(d->getLocation()); - std::string name = - declLocation.filePath.fileName() + "<" + - std::to_string(declLocation.startLineNumber) + ":" + - std::to_string(declLocation.startColumnNumber) + ">"; - m_client->onLocalSymbolParsed(name, getParseLocation(d->getLocation())); - } - } - else - { - m_client->recordSymbol( - m_declNameCache->getValue(d), - symbolKind, - getParseLocation(d->getLocation()), - convertAccessSpecifier(d->getAccess()), - isImplicit(d) - ); - } - } - return true; -} +#undef DEF_TRAVERSE_CUSTOM_TYPE_PTR +#undef DEF_TRAVERSE_CUSTOM_TYPE +#undef DEF_TRAVERSE_TYPE_PTR +#undef DEF_TRAVERSE_TYPE -bool CxxAstVisitor::VisitFieldDecl(clang::FieldDecl* d) -{ - if (shouldVisitDecl(d)) - { - m_client->recordSymbol( - m_declNameCache->getValue(d), - SYMBOL_FIELD, - getParseLocation(d->getLocation()), - convertAccessSpecifier(d->getAccess()), - isImplicit(d) - ); - } - return true; -} - -bool CxxAstVisitor::VisitTypedefDecl(clang::TypedefDecl* d) -{ - if (shouldVisitDecl(d)) - { - m_client->recordSymbol( - m_declNameCache->getValue(d), - SYMBOL_TYPEDEF, - getParseLocation(d->getLocation()), - convertAccessSpecifier(d->getAccess()), - isImplicit(d) - ); - } - return true; -} - -bool CxxAstVisitor::VisitTypeAliasDecl(clang::TypeAliasDecl* d) -{ - if (shouldVisitDecl(d)) - { - m_client->recordSymbol( - m_declNameCache->getValue(d), - SYMBOL_TYPEDEF, - getParseLocation(d->getLocation()), - convertAccessSpecifier(d->getAccess()), - isImplicit(d) - ); - } - return true; -} - -bool CxxAstVisitor::VisitNamespaceDecl(clang::NamespaceDecl* d) -{ - if (shouldVisitDecl(d)) - { - m_client->recordSymbol( - m_declNameCache->getValue(d), - SYMBOL_NAMESPACE, - d->isAnonymousNamespace() ? ParseLocation() : getParseLocation(d->getLocation()), - getParseLocation(d->getSourceRange()), - convertAccessSpecifier(d->getAccess()), - isImplicit(d) - ); - } - return true; -} - -bool CxxAstVisitor::VisitNamespaceAliasDecl(clang::NamespaceAliasDecl* d) -{ - if (shouldVisitDecl(d)) - { - m_client->recordSymbol( - m_declNameCache->getValue(d), - SYMBOL_NAMESPACE, - getParseLocation(d->getLocation()), - convertAccessSpecifier(d->getAccess()), - isImplicit(d) - ); - - m_client->recordReference( - REFERENCE_USAGE, - m_declNameCache->getValue(d->getAliasedNamespace()), - m_declNameCache->getValue(d), - getParseLocation(d->getTargetNameLoc()) - ); - } - return true; -} - -bool CxxAstVisitor::VisitEnumConstantDecl(clang::EnumConstantDecl* d) -{ - if (shouldVisitDecl(d)) - { - m_client->recordSymbol( - m_declNameCache->getValue(d), - SYMBOL_ENUM_CONSTANT, - getParseLocation(d->getLocation()), - ACCESS_NONE, - isImplicit(d) - ); - } - return true; -} - -bool CxxAstVisitor::VisitUsingDirectiveDecl(clang::UsingDirectiveDecl* d) -{ - if (shouldVisitDecl(d)) - { - ParseLocation loc = getParseLocation(d->getLocation()); - m_client->recordReference( - REFERENCE_USAGE, - m_declNameCache->getValue(d->getNominatedNamespaceAsWritten()), - getContextName(NameHierarchy(loc.filePath.fileName())), - loc - ); - } - return true; -} - -bool CxxAstVisitor::VisitUsingDecl(clang::UsingDecl* d) -{ - if (shouldVisitDecl(d)) - { - ParseLocation loc = getParseLocation(d->getLocation()); - m_client->recordReference( - REFERENCE_USAGE, - m_declNameCache->getValue(d), - getContextName(NameHierarchy(loc.filePath.fileName())), - loc - ); - } - return true; -} - -bool CxxAstVisitor::VisitNonTypeTemplateParmDecl(clang::NonTypeTemplateParmDecl* d) -{ - if (shouldVisitDecl(d) && !d->getName().empty()) // We don't create symbols for unnamed template parameters. - { - m_client->recordSymbol( - m_declNameCache->getValue(d), - SYMBOL_TEMPLATE_PARAMETER, - getParseLocation(d->getLocation()), - ACCESS_TEMPLATE_PARAMETER, - isImplicit(d) - ); - } - return true; -} - -bool CxxAstVisitor::VisitTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d) -{ - if (shouldVisitDecl(d) && !d->getName().empty()) // We don't create symbols for unnamed template parameters. - { - m_client->recordSymbol( - m_declNameCache->getValue(d), - SYMBOL_TEMPLATE_PARAMETER, - getParseLocation(d->getLocation()), - ACCESS_TEMPLATE_PARAMETER, - isImplicit(d) - ); - } - return true; -} - -bool CxxAstVisitor::VisitTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d) -{ - if (shouldVisitDecl(d) && !d->getName().empty()) // We don't create symbols for unnamed template parameters. - { - m_client->recordSymbol( - m_declNameCache->getValue(d), - SYMBOL_TEMPLATE_PARAMETER, - getParseLocation(d->getLocation()), - ACCESS_TEMPLATE_PARAMETER, - isImplicit(d) - ); - } - return true; -} - - - -/* -bool CxxAstVisitor::VisitNamedDecl(clang::NamedDecl* d) -{ - if (!shouldVisitDecl(d)) - { - return true; +#define DEF_VISIT_CUSTOM_TYPE_PTR(__NAME_TYPE__, __PARAM_TYPE__) \ + bool CxxAstVisitor::Visit##__NAME_TYPE__(clang::__PARAM_TYPE__* v) \ + { \ + for (auto it = m_components.begin(); it != m_components.end(); it++) \ + { \ + (*it)->visit##__NAME_TYPE__(v); \ + } \ + return true; \ } - - - - //if (clang::UsingDirectiveDecl *ud = llvm::dyn_cast(d)) - //{ - // m_client->recordReference( - // REFERENCE_USAGE, - // m_declNameCache->getValue(ud->getNominatedNamespaceAsWritten()), - // m_con - - // return true; - - - // RecordDeclRef( - // ud->getNominatedNamespaceAsWritten(), - // loc, RT_UsingDirective); - //} - //else if (clang::UsingDecl *usd = llvm::dyn_cast(d)) - //{ - // for (auto it = usd->shadow_begin(), itEnd = usd->shadow_end(); - // it != itEnd; ++it) { - // clang::UsingShadowDecl *shadow = *it; - // RecordDeclRef(shadow->getTargetDecl(), loc, RT_Using); - // } - //} else - - - if (llvm::isa(d)) { - // TODO: use these cases for creating the connection between two undefined template things - // Do nothing. The function will be recorded when it appears as a - // FunctionDecl. - } else if (llvm::isa(d)) { - // Do nothing. The class will be recorded when it appears as a - // RecordDecl. - } else if (llvm::isa(d)) { - // Do nothing. The type alias will be recorded when it appears as a - // TypeAliasDecl. +#define DEF_VISIT_CUSTOM_TYPE(__NAME_TYPE__, __PARAM_TYPE__) \ + bool CxxAstVisitor::Visit##__NAME_TYPE__(clang::__PARAM_TYPE__ v) \ + { \ + for (auto it = m_components.begin(); it != m_components.end(); it++) \ + { \ + (*it)->visit##__NAME_TYPE__(v); \ + } \ + return true; \ } - return true; -} +#define DEF_VISIT_TYPE_PTR(__TYPE__) \ + DEF_VISIT_CUSTOM_TYPE_PTR(__TYPE__, __TYPE__) -*/ +#define DEF_VISIT_TYPE(__TYPE__) \ + DEF_VISIT_CUSTOM_TYPE(__TYPE__, __TYPE__) +DEF_VISIT_TYPE_PTR(CastExpr) +DEF_VISIT_CUSTOM_TYPE_PTR(UnaryAddrOf, UnaryOperator) +DEF_VISIT_CUSTOM_TYPE_PTR(UnaryDeref, UnaryOperator) +DEF_VISIT_TYPE_PTR(DeclStmt) +DEF_VISIT_TYPE_PTR(ReturnStmt) +DEF_VISIT_TYPE_PTR(InitListExpr) +DEF_VISIT_TYPE_PTR(TagDecl) +DEF_VISIT_TYPE_PTR(ClassTemplateSpecializationDecl) +DEF_VISIT_TYPE_PTR(FunctionDecl) +DEF_VISIT_TYPE_PTR(CXXMethodDecl) +DEF_VISIT_TYPE_PTR(VarDecl) +DEF_VISIT_TYPE_PTR(FieldDecl) +DEF_VISIT_TYPE_PTR(TypedefDecl) +DEF_VISIT_TYPE_PTR(TypeAliasDecl) +DEF_VISIT_TYPE_PTR(NamespaceDecl) +DEF_VISIT_TYPE_PTR(NamespaceAliasDecl) +DEF_VISIT_TYPE_PTR(EnumConstantDecl) +DEF_VISIT_TYPE_PTR(UsingDirectiveDecl) +DEF_VISIT_TYPE_PTR(UsingDecl) +DEF_VISIT_TYPE_PTR(NonTypeTemplateParmDecl) +DEF_VISIT_TYPE_PTR(TemplateTypeParmDecl) +DEF_VISIT_TYPE_PTR(TemplateTemplateParmDecl) +DEF_VISIT_TYPE(TypeLoc) +DEF_VISIT_TYPE_PTR(DeclRefExpr) +DEF_VISIT_TYPE_PTR(MemberExpr) +DEF_VISIT_TYPE_PTR(CXXConstructExpr) +DEF_VISIT_TYPE_PTR(LambdaExpr) +DEF_VISIT_CUSTOM_TYPE_PTR(ConstructorInitializer, CXXCtorInitializer) - - - - - -bool CxxAstVisitor::VisitTypeLoc(clang::TypeLoc tl) -{ - if ((shouldVisitReference(tl.getBeginLoc(), getTopmostContextDecl())) && - (!checkIgnoresTypeLoc(tl))) - { - clang::SourceLocation loc; - if (!tl.getAs().isNull()) - { - const clang::DependentNameTypeLoc& dntl = tl.castAs(); - loc = dntl.getNameLoc(); - } - else - { - loc = tl.getBeginLoc(); - } - - m_client->recordReference( - m_typeRefContext, - m_typeNameCache->getValue(tl.getTypePtr()), - getContextName(1), // we skip the last element because it refers to this typeloc. - getParseLocation(loc) - ); - } - return true; -} - -bool CxxAstVisitor::VisitDeclRefExpr(clang::DeclRefExpr* s) -{ - clang::ValueDecl* decl = s->getDecl(); - if (shouldVisitReference(s->getLocation(), getTopmostContextDecl())) - { - if ((clang::isa(decl)) || - (clang::isa(decl) && decl->getParentFunctionOrMethod() != NULL) - ) { - ParseLocation declLocation = getParseLocation(decl->getLocation()); - std::string name = declLocation.filePath.fileName() + "<" + - std::to_string(declLocation.startLineNumber) + ":" + - std::to_string(declLocation.startColumnNumber) + ">"; - - m_client->onLocalSymbolParsed(name, getParseLocation(s->getLocation())); - } - else - { - m_client->recordReference( - consumeDeclRefContextKind(), - m_declNameCache->getValue(s->getDecl()), - getContextName(), - getParseLocation(s->getLocation()) - ); - } - } - - return true; -} - -bool CxxAstVisitor::VisitMemberExpr(clang::MemberExpr* s) -{ - if (shouldVisitReference(s->getMemberLoc(), getTopmostContextDecl())) - { - m_client->recordReference( - consumeDeclRefContextKind(), - m_declNameCache->getValue(s->getMemberDecl()), - getContextName(), - getParseLocation(s->getMemberLoc()) - ); - } - return true; -} - -bool CxxAstVisitor::VisitCXXConstructExpr(clang::CXXConstructExpr* s) -{ - if (shouldVisitReference(s->getLocation(), getTopmostContextDecl())) - { - //if (e->getParenOrBraceRange().isValid()) { - // // XXX: This code is a kludge. Recording calls to constructors is - // // troublesome because there isn't an obvious location to associate the - // // call with. Consider: - // // A::A() : field(1, 2, 3) {} - // // new A(1, 2, 3) - // // struct A { A(B); }; A f() { B b; return b; } - // // Implicit calls to conversion operator methods pose a similar - // // problem. - // // - // // Recording constructor calls is very useful, though, so, as a - // // temporary measure, when there are constructor arguments surrounded - // // by parentheses, associate the call with the right parenthesis. - // // - // // Perhaps the right fix is to associate the call with the line itself - // // or with a larger span which may have other references nested within - // // it. The fix may have implications for the navigator GUI. - // RecordDeclRefExpr( - // e->getConstructor(), - // e->getParenOrBraceRange().getEnd(), - // e, - // CF_Called); - //} - clang::SourceLocation loc; - clang::SourceLocation braceBeginLoc = s->getParenOrBraceRange().getBegin(); - clang::SourceLocation nameBeginLoc = s->getSourceRange().getBegin(); - if (braceBeginLoc.isValid()) - { - if (braceBeginLoc == nameBeginLoc) - { - loc = nameBeginLoc; - } - else - { - loc = braceBeginLoc.getLocWithOffset(-1); - } - } - else - { - loc = s->getSourceRange().getEnd(); - } - loc = clang::Lexer::GetBeginningOfToken(loc, m_astContext->getSourceManager(), m_astContext->getLangOpts()); - - m_client->recordReference( - consumeDeclRefContextKind(), - m_declNameCache->getValue(s->getConstructor()), - getContextName(), - getParseLocation(loc) - ); - } - return true; -} - -bool CxxAstVisitor::VisitLambdaExpr(clang::LambdaExpr* s) -{ - clang::CXXMethodDecl* methodDecl = s->getCallOperator(); - if (shouldVisitDecl(methodDecl)) - { - m_client->recordSymbol( - m_declNameCache->getValue(methodDecl), - SYMBOL_FUNCTION, - getParseLocation(s->getLocStart()), - getParseLocationOfFunctionBody(methodDecl), - ACCESS_NONE, // TODO: introduce AccessLambda - isImplicit(methodDecl) - ); - } - return true; -} - -bool CxxAstVisitor::VisitConstructorInitializer(clang::CXXCtorInitializer* init) -{ - if (shouldVisitReference(init->getMemberLocation(), getTopmostContextDecl())) - { - // record the field usage here because it is not a DeclRefExpr - if (clang::FieldDecl* memberDecl = init->getMember()) - { - m_client->recordReference( - REFERENCE_USAGE, - m_declNameCache->getValue(memberDecl), - getContextName(), - getParseLocation(init->getMemberLocation()) - ); - } - } - return true; -} - -bool CxxAstVisitor::isImplicit(const clang::Decl* d) const -{ - if (!d) - { - return false; - } - - if (d->isImplicit()) - { - if (const clang::RecordDecl* rd = clang::dyn_cast_or_null(d)) - { - if (rd->isLambda()) - { - return isImplicit(clang::dyn_cast_or_null(d->getDeclContext())); - } - } - return true; - } - else if (const clang::ClassTemplateSpecializationDecl* ctsd = clang::dyn_cast_or_null(d)) - { - if (!ctsd->isExplicitSpecialization()) - { - return true; - } - } - else if (const clang::FunctionDecl* fd = clang::dyn_cast_or_null(d)) - { - if (fd->isTemplateInstantiation() && fd->getTemplateSpecializationKind() != clang::TSK_ExplicitSpecialization) // or undefined?? - { - return true; - } - } - - return isImplicit(clang::dyn_cast_or_null(d->getDeclContext())); -} - -bool CxxAstVisitor::shouldVisitDecl(const clang::Decl* decl) -{ - if (decl) - { - clang::SourceLocation loc = decl->getLocation(); - bool declIsImplicit = isImplicit(decl); - if ((declIsImplicit && isLocatedInProjectFile(loc)) || - (!declIsImplicit && isLocatedInUnparsedProjectFile(loc))) - { - return true; - } - } - return false; -} - -bool CxxAstVisitor::shouldVisitReference(const clang::SourceLocation& referenceLocation, const clang::Decl* contextDecl) -{ - bool declIsImplicit = true; // default value is "true" to make sure that everything that should be visited gets visited. - if (contextDecl) - { - declIsImplicit = isImplicit(contextDecl); - } - - if ((declIsImplicit && isLocatedInProjectFile(referenceLocation)) || - (!declIsImplicit && isLocatedInUnparsedProjectFile(referenceLocation))) - { - return true; - } - return false; -} - -bool CxxAstVisitor::isLocatedInUnparsedProjectFile(clang::SourceLocation loc) -{ - clang::SourceManager& sourceManager = m_astContext->getSourceManager(); - clang::SourceLocation spellingLoc = sourceManager.getSpellingLoc(loc); - - clang::FileID fileId; - - if (spellingLoc.isValid()) - { - fileId = sourceManager.getFileID(spellingLoc); - } - if (fileId.isValid()) - { - auto it = m_inUnparsedProjectFileMap.find(fileId); - if (it != m_inUnparsedProjectFileMap.end()) - { - return it->second; - } - - bool ret = false; - if (sourceManager.isWrittenInMainFile(spellingLoc)) - { - ret = true; - } - else - { - const clang::FileEntry* fileEntry = sourceManager.getFileEntryForID(fileId); - if (fileEntry != NULL) - { - std::string fileName = fileEntry->getName(); - FilePath filePath = FilePath(fileName).canonical(); - - if (m_fileRegister->hasIncludeFile(filePath)) - { - ret = !(m_fileRegister->includeFileIsParsed(filePath)); - } - } - } - m_inUnparsedProjectFileMap[fileId] = ret; - return ret; - } - return false; -} - -bool CxxAstVisitor::isLocatedInProjectFile(clang::SourceLocation loc) -{ - clang::SourceManager& sourceManager = m_astContext->getSourceManager(); - clang::SourceLocation spellingLoc = sourceManager.getSpellingLoc(loc); - - clang::FileID fileId; - - if (spellingLoc.isValid()) - { - fileId = sourceManager.getFileID(spellingLoc); - } - - if (!fileId.isInvalid()) - { - auto it = m_inProjectFileMap.find(fileId); - if (it != m_inProjectFileMap.end()) - { - return it->second; - } - - const clang::FileEntry* fileEntry = sourceManager.getFileEntryForID(fileId); - if (fileEntry != NULL) - { - std::string fileName = fileEntry->getName(); - FilePath filePath = FilePath(fileName).canonical(); - bool ret = m_fileRegister->hasFilePath(filePath.str()); - m_inProjectFileMap[fileId] = ret; - return ret; - } - } - - return false; -} +#undef DEF_VISIT_CUSTOM_TYPE_PTR +#undef DEF_VISIT_CUSTOM_TYPE +#undef DEF_VISIT_TYPE_PTR +#undef DEF_VISIT_TYPE ParseLocation CxxAstVisitor::getParseLocationOfTagDeclBody(clang::TagDecl* decl) const { @@ -1121,7 +630,6 @@ ParseLocation CxxAstVisitor::getParseLocation(const clang::SourceLocation& loc) } } - return parseLocation; } @@ -1145,126 +653,3 @@ ParseLocation CxxAstVisitor::getParseLocation(const clang::SourceRange& sourceRa } return parseLocation; } - -AccessKind CxxAstVisitor::convertAccessSpecifier(clang::AccessSpecifier access) const -{ - switch (access) - { - case clang::AS_public: - return ACCESS_PUBLIC; - case clang::AS_protected: - return ACCESS_PROTECTED; - case clang::AS_private: - return ACCESS_PRIVATE; - case clang::AS_none: - return ACCESS_NONE; - } -} - -SymbolKind CxxAstVisitor::convertTagKind(clang::TagTypeKind tagKind) -{ - switch (tagKind) - { - case clang::TTK_Struct: - return SYMBOL_STRUCT; - case clang::TTK_Union: - return SYMBOL_UNION; - case clang::TTK_Class: - return SYMBOL_CLASS; - case clang::TTK_Enum: - return SYMBOL_ENUM; - case clang::TTK_Interface: - return SYMBOL_KIND_MAX; - } -} - -const clang::NamedDecl* CxxAstVisitor::getTopmostContextDecl() const -{ - for (std::vector>::const_reverse_iterator it = m_contextStack.rbegin(); it != m_contextStack.rend(); it ++) - { - const clang::NamedDecl* decl = (*it)->getDecl(); - if (decl) - { - return decl; - } - } - return nullptr; -} - -NameHierarchy CxxAstVisitor::getContextName(const size_t skip) const -{ - if (m_contextStack.size() <= skip) - { - return m_declNameCache->getValue(nullptr); - } - return m_contextStack[m_contextStack.size() - 1 - skip]->getName(); // todo: performance optimize this -} - -NameHierarchy CxxAstVisitor::getContextName(const NameHierarchy& fallback, const size_t skip) const -{ - if (m_contextStack.size() <= skip) - { - return fallback; - } - return m_contextStack[m_contextStack.size() - 1 - skip]->getName(); // todo: performance optimize this -} - -bool CxxAstVisitor::checkIgnoresTypeLoc(const clang::TypeLoc& tl) -{ - if ((!tl.getAs().isNull()) || - (!tl.getAs().isNull()) || - (!tl.getAs().isNull()) || - (!tl.getAs().isNull()) || - (!tl.getAs().isNull()) || - (!tl.getAs().isNull()) || - (!tl.getAs().isNull()) || - (!tl.getAs().isNull()) || - (!tl.getAs().isNull()) - ){ - return false; - } - return true; -} - -ReferenceKind CxxAstVisitor::consumeDeclRefContextKind() -{ - ReferenceKind refKind = REFERENCE_UNDEFINED; - if (m_typeRefContext == REFERENCE_TYPE_USAGE) - { - refKind = m_declRefContext; - m_declRefContext = REFERENCE_USAGE; - } - else - { - refKind = m_typeRefContext; - m_typeRefContext = REFERENCE_TYPE_USAGE; - } - return refKind; -} - -SymbolKind CxxAstVisitor::getSymbolKind(clang::VarDecl* d) -{ - SymbolKind symbolKind = SYMBOL_KIND_MAX; - - if (llvm::isa(d)) - { - symbolKind = SYMBOL_PARAMETER; - } - else if (d->getParentFunctionOrMethod() == NULL) - { - if (d->getAccess() == clang::AS_none) - { - symbolKind = SYMBOL_GLOBAL_VARIABLE; - } - else - { - symbolKind = SYMBOL_FIELD; - } - } - else - { - symbolKind = SYMBOL_LOCAL_VARIABLE; - } - - return symbolKind; -} diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.h b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.h index eb32efc0..7975c072 100644 --- a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.h +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.h @@ -1,16 +1,11 @@ #ifndef CXX_AST_VISITOR_H #define CXX_AST_VISITOR_H -#include -#include +#include -#include "clang/AST/ASTContext.h" #include #include "data/parser/cxx/CxxContext.h" -#include "data/parser/AccessKind.h" -#include "data/parser/ReferenceKind.h" -#include "data/parser/SymbolKind.h" #include "utility/messaging/MessageInterruptTasksCounter.h" #include "utility/Cache.h" @@ -18,6 +13,12 @@ class ParserClient; struct ParseLocation; class FileRegister; +class CxxAstVisitorComponent; +class CxxAstVisitorComponentContext; +class CxxAstVisitorComponentDeclRefKind; +class CxxAstVisitorComponentTypeRefKind; +class CxxAstVisitorComponentIndexer; + // methods are called in this order: // TraverseDecl() // `- TraverseFunctionDecl() @@ -29,29 +30,18 @@ class FileRegister; // | `- VisitFunctionDecl() // `- TraverseChildNodes() -class ScopedContextKindSetter -{ -public: - ScopedContextKindSetter(const ReferenceKind refKind, std::vector* stack) - : m_stack(stack) - { - m_stack->push_back(refKind); - } - - ~ScopedContextKindSetter() - { - m_stack->pop_back(); - } -private: - std::vector* m_stack; -}; - class CxxAstVisitor: public clang::RecursiveASTVisitor { public: CxxAstVisitor(clang::ASTContext* astContext, clang::Preprocessor* preprocessor, ParserClient* client, FileRegister* fileRegister); virtual ~CxxAstVisitor(); + template + std::shared_ptr getComponent(); + + std::shared_ptr getDeclNameCache(); + std::shared_ptr getTypeNameCache(); + // Indexing entry point void indexDecl(clang::Decl *d); @@ -59,6 +49,8 @@ public: virtual bool shouldVisitTemplateInstantiations() const; virtual bool shouldVisitImplicitCode() const; + bool checkIgnoresTypeLoc(const clang::TypeLoc& tl) const; + // Traversal methods. These specify how to traverse the AST and record context info. virtual bool TraverseDecl(clang::Decl *d); virtual bool TraverseQualifiedTypeLoc(clang::QualifiedTypeLoc tl); @@ -66,7 +58,8 @@ public: virtual bool TraverseType(clang::QualType t); virtual bool TraverseStmt(clang::Stmt *stmt); - virtual bool TraverseCXXRecordDecl(clang::CXXRecordDecl *d); + virtual bool TraverseCXXRecordDecl(clang::CXXRecordDecl* d); + bool traverseCXXBaseSpecifier(const clang::CXXBaseSpecifier& d); virtual bool TraverseTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d); virtual bool TraverseTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d); virtual bool TraverseNestedNameSpecifierLoc(clang::NestedNameSpecifierLoc loc); @@ -85,10 +78,27 @@ public: virtual bool TraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* s); virtual bool TraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc); virtual bool TraverseLambdaCapture(clang::LambdaExpr* lambdaExpr, const clang::LambdaCapture* capture); + virtual bool TraverseBinComma(clang::BinaryOperator* s); + +#define OPERATOR(NAME) virtual bool TraverseBin##NAME##Assign(clang::CompoundAssignOperator *s) { return TraverseAssignCommon(s); } + OPERATOR(Mul) OPERATOR(Div) OPERATOR(Rem) OPERATOR(Add) OPERATOR(Sub) + OPERATOR(Shl) OPERATOR(Shr) OPERATOR(And) OPERATOR(Or) OPERATOR(Xor) +#undef OPERATOR + + void traverseDeclContextHelper(clang::DeclContext* d); bool TraverseCallCommon(clang::CallExpr* s); + bool TraverseAssignCommon(clang::BinaryOperator* s); // Visitor methods. These actually record stuff and store it in the database. + virtual bool VisitCastExpr(clang::CastExpr* s); + virtual bool VisitUnaryAddrOf(clang::UnaryOperator* s); + virtual bool VisitUnaryDeref(clang::UnaryOperator* s); + virtual bool VisitDeclStmt(clang::DeclStmt* s); + virtual bool VisitReturnStmt(clang::ReturnStmt* s); + virtual bool VisitInitListExpr(clang::InitListExpr* s); + + virtual bool VisitTagDecl(clang::TagDecl* d); virtual bool VisitClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl* d); virtual bool VisitFunctionDecl(clang::FunctionDecl* d); @@ -114,39 +124,13 @@ public: virtual bool VisitLambdaExpr(clang::LambdaExpr* s); virtual bool VisitConstructorInitializer(clang::CXXCtorInitializer* init); -protected: - // General helpers - bool isImplicit(const clang::Decl* d) const; - bool shouldVisitDecl(const clang::Decl* decl); - bool shouldVisitReference(const clang::SourceLocation& referenceLocation, const clang::Decl* contextDecl); - bool isLocatedInUnparsedProjectFile(clang::SourceLocation loc); - bool isLocatedInProjectFile(clang::SourceLocation loc); - ParseLocation getParseLocationOfTagDeclBody(clang::TagDecl* decl) const; ParseLocation getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const; ParseLocation getParseLocation(const clang::SourceLocation& loc) const; ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const; - AccessKind convertAccessSpecifier(clang::AccessSpecifier access) const; - SymbolKind convertTagKind(clang::TagTypeKind tagKind); private: - ReferenceKind consumeDeclRefContextKind(); - SymbolKind getSymbolKind(clang::VarDecl* d); - - typedef clang::RecursiveASTVisitor base; - - const clang::NamedDecl* getTopmostContextDecl() const; - NameHierarchy getContextName(const size_t skip = 0) const; - NameHierarchy getContextName(const NameHierarchy& fallback, const size_t skip = 0) const; - bool checkIgnoresTypeLoc(const clang::TypeLoc& tl); - - struct FileIdHash - { - size_t operator()(clang::FileID fileID) const - { - return fileID.getHashValue(); - } - }; + typedef clang::RecursiveASTVisitor Base; clang::ASTContext* m_astContext; clang::Preprocessor* m_preprocessor; @@ -155,15 +139,26 @@ private: MessageInterruptTasksCounter m_interruptCounter; - ReferenceKind m_typeRefContext; - ReferenceKind m_declRefContext; - std::vector> m_contextStack; - std::shared_ptr m_templateArgumentContext; + std::vector> m_components; + std::shared_ptr m_contextComponent; + std::shared_ptr m_declRefKindComponent; + std::shared_ptr m_typeRefKindComponent; + std::shared_ptr m_indexerComponent; std::shared_ptr m_declNameCache; std::shared_ptr m_typeNameCache; - std::unordered_map m_inUnparsedProjectFileMap; - std::unordered_map m_inProjectFileMap; }; +template <> +std::shared_ptr CxxAstVisitor::getComponent(); + +template <> +std::shared_ptr CxxAstVisitor::getComponent(); + +template <> +std::shared_ptr CxxAstVisitor::getComponent(); + +template <> +std::shared_ptr CxxAstVisitor::getComponent(); + #endif // CXX_AST_VISITOR_H diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponent.cpp b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponent.cpp new file mode 100644 index 00000000..0bc65a37 --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponent.cpp @@ -0,0 +1,20 @@ +#include "data/parser/cxx/CxxAstVisitorComponent.h" + +CxxAstVisitorComponent::CxxAstVisitorComponent(CxxAstVisitor* astVisitor) + : m_astVisitor(astVisitor) +{ +} + +CxxAstVisitorComponent::~CxxAstVisitorComponent() +{ +} + +CxxAstVisitor* CxxAstVisitorComponent::getAstVisitor() +{ + return m_astVisitor; +} + +const CxxAstVisitor* CxxAstVisitorComponent::getAstVisitor() const +{ + return m_astVisitor; +} diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponent.h b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponent.h new file mode 100644 index 00000000..258795b1 --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponent.h @@ -0,0 +1,130 @@ +#ifndef CXX_AST_VISITOR_COMPONENT_H +#define CXX_AST_VISITOR_COMPONENT_H + +#include "data/parser/cxx/CxxAstVisitor.h" + +// CxxAstVisitorComponent: This is the base class for all ast visitor components. +// Each component can override it's begin-/endTraverse and visit methods in order to provide some functionality. The CxxAstVisitor +// executes all of these methods of registered components while traversing the AST. +class CxxAstVisitorComponent +{ +public: + CxxAstVisitorComponent(CxxAstVisitor* astVisitor); + virtual ~CxxAstVisitorComponent(); + +#define DEF_TRAVERSE_CUSTOM_TYPE_PTR(__NAME_TYPE__, __PARAM_TYPE__) \ + virtual void beginTraverse##__NAME_TYPE__(clang::__PARAM_TYPE__ *v) {} \ + virtual void endTraverse##__NAME_TYPE__(clang::__PARAM_TYPE__ *v) {} + +#define DEF_TRAVERSE_CUSTOM_TYPE(__NAME_TYPE__, __PARAM_TYPE__) \ + virtual void beginTraverse##__NAME_TYPE__(clang::__PARAM_TYPE__ v) {} \ + virtual void endTraverse##__NAME_TYPE__(clang::__PARAM_TYPE__ v) {} + +#define DEF_TRAVERSE_TYPE_PTR(__TYPE__) \ + DEF_TRAVERSE_CUSTOM_TYPE_PTR(__TYPE__, __TYPE__) + +#define DEF_TRAVERSE_TYPE(__TYPE__) \ + DEF_TRAVERSE_CUSTOM_TYPE(__TYPE__, __TYPE__) + +DEF_TRAVERSE_TYPE_PTR(Decl) + +DEF_TRAVERSE_TYPE_PTR(Stmt) + +DEF_TRAVERSE_CUSTOM_TYPE(Type, QualType) + +DEF_TRAVERSE_TYPE(TypeLoc) + +DEF_TRAVERSE_TYPE_PTR(FunctionDecl) + +DEF_TRAVERSE_TYPE_PTR(ClassTemplateSpecializationDecl) + +DEF_TRAVERSE_TYPE_PTR(ClassTemplatePartialSpecializationDecl) + +DEF_TRAVERSE_TYPE(TemplateSpecializationTypeLoc) + +DEF_TRAVERSE_TYPE_PTR(LambdaExpr) + +DEF_TRAVERSE_TYPE_PTR(DeclRefExpr) + +DEF_TRAVERSE_TYPE_PTR(UnresolvedLookupExpr) + + virtual void beginTraverseCallCommonCallee() {} + virtual void endTraverseCallCommonCallee() {} + + virtual void beginTraverseCallCommonArgument() {} + virtual void endTraverseCallCommonArgument() {} + + virtual void beginTraverseBinCommaLhs() {} + virtual void endTraverseBinCommaLhs() {} + + virtual void beginTraverseBinCommaRhs() {} + virtual void endTraverseBinCommaRhs() {} + + virtual void beginTraverseAssignCommonLhs() {} + virtual void endTraverseAssignCommonLhs() {} + + virtual void beginTraverseAssignCommonRhs() {} + virtual void endTraverseAssignCommonRhs() {} + + virtual void beginTraverseCXXBaseSpecifier() {} + virtual void endTraverseCXXBaseSpecifier() {} + + virtual void beginTraverseTemplateDefaultArgumentLoc() {} + virtual void endTraverseTemplateDefaultArgumentLoc() {} + +DEF_TRAVERSE_CUSTOM_TYPE_PTR(ConstructorInitializer, CXXCtorInitializer) + +DEF_TRAVERSE_TYPE_PTR(CXXTemporaryObjectExpr) + + virtual void beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc) {} + virtual void endTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc) {} + + virtual void beginTraverseLambdaCapture(clang::LambdaExpr *lambdaExpr, const clang::LambdaCapture *capture) {} + virtual void endTraverseLambdaCapture(clang::LambdaExpr *lambdaExpr, const clang::LambdaCapture *capture) {} + + virtual void visitTagDecl(clang::TagDecl* d) {} + virtual void visitClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl* d) {} + virtual void visitVarDecl(clang::VarDecl* d) {} + virtual void visitFieldDecl(clang::FieldDecl* d) {} + virtual void visitFunctionDecl(clang::FunctionDecl* d) {} + virtual void visitCXXMethodDecl(clang::CXXMethodDecl* d) {} + virtual void visitEnumConstantDecl(clang::EnumConstantDecl* d) {} + virtual void visitNamespaceDecl(clang::NamespaceDecl* d) {} + virtual void visitNamespaceAliasDecl(clang::NamespaceAliasDecl* d) {} + virtual void visitTypedefDecl(clang::TypedefDecl* d) {} + virtual void visitTypeAliasDecl(clang::TypeAliasDecl* d) {} + virtual void visitUsingDirectiveDecl(clang::UsingDirectiveDecl* d) {} + virtual void visitUsingDecl(clang::UsingDecl* d) {} + virtual void visitNonTypeTemplateParmDecl(clang::NonTypeTemplateParmDecl* d) {} + virtual void visitTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d) {} + virtual void visitTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d) {} + + virtual void visitTypeLoc(clang::TypeLoc tl) {} + + virtual void visitCastExpr(clang::CastExpr* s) {} + virtual void visitUnaryAddrOf(clang::UnaryOperator* s) {} + virtual void visitUnaryDeref(clang::UnaryOperator* s) {} + virtual void visitDeclStmt(clang::DeclStmt* s) {} + virtual void visitReturnStmt(clang::ReturnStmt* s) {} + virtual void visitInitListExpr(clang::InitListExpr* s) {} + virtual void visitDeclRefExpr(clang::DeclRefExpr* s) {} + virtual void visitMemberExpr(clang::MemberExpr* s) {} + virtual void visitCXXConstructExpr(clang::CXXConstructExpr* s) {} + virtual void visitLambdaExpr(clang::LambdaExpr* s) {} + + virtual void visitConstructorInitializer(clang::CXXCtorInitializer* init) {} + +#undef DEF_TRAVERSE_CUSTOM_TYPE_PTR +#undef DEF_TRAVERSE_CUSTOM_TYPE +#undef DEF_TRAVERSE_TYPE_PTR +#undef DEF_TRAVERSE_TYPE + +protected: + CxxAstVisitor* getAstVisitor(); + const CxxAstVisitor* getAstVisitor() const; + +private: + CxxAstVisitor* m_astVisitor; +}; + +#endif // CXX_AST_VISITOR_COMPONENT_H diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentContext.cpp b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentContext.cpp new file mode 100644 index 00000000..b883f785 --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentContext.cpp @@ -0,0 +1,200 @@ +#include "data/parser/cxx/CxxAstVisitorComponentContext.h" + +#include "utility/ScopedFunctor.h" + +CxxAstVisitorComponentContext::CxxAstVisitorComponentContext(CxxAstVisitor* astVisitor) + : CxxAstVisitorComponent(astVisitor) +{ +} + +CxxAstVisitorComponentContext::~CxxAstVisitorComponentContext() +{ +} + +const clang::NamedDecl* CxxAstVisitorComponentContext::getTopmostContextDecl() const +{ + for (std::vector>::const_reverse_iterator it = m_contextStack.rbegin(); it != m_contextStack.rend(); it ++) + { + if (*it) + { + const clang::NamedDecl* decl = (*it)->getDecl(); + if (decl) + { + return decl; + } + } + } + return nullptr; +} + +NameHierarchy CxxAstVisitorComponentContext::getContextName(const size_t skip) +{ + size_t skipped = 0; + + for (auto it = m_contextStack.rbegin(); it != m_contextStack.rend(); it++) + { + if (*it) + { + if (skipped >= skip) + { + return (*it)->getName(); + } + else + { + skipped++; + } + } + } + return getAstVisitor()->getDeclNameCache()->getValue(nullptr); +} + +NameHierarchy CxxAstVisitorComponentContext::getContextName(const NameHierarchy& fallback, const size_t skip) +{ + size_t skipped = 0; + + for (auto it = m_contextStack.rbegin(); it != m_contextStack.rend(); it++) + { + if (*it) + { + if (skipped >= skip) + { + return (*it)->getName(); + } + else + { + skipped++; + } + } + } + return fallback; +} + +void CxxAstVisitorComponentContext::beginTraverseDecl(clang::Decl* d) +{ + std::shared_ptr context; + + if (d && + clang::isa(d) && + !clang::isa(d) && // no parameter + !(clang::isa(d) && d->getParentFunctionOrMethod() != NULL) && // no local variable + !clang::isa(d) && // no using directive decl + !clang::isa(d) && // no using decl + !clang::isa(d) // no namespace + ){ + clang::NamedDecl* nd = clang::dyn_cast(d); + context = std::make_shared(nd, getAstVisitor()->getDeclNameCache()); + } + + m_contextStack.push_back(context); +} + +void CxxAstVisitorComponentContext::endTraverseDecl(clang::Decl* d) +{ + m_contextStack.pop_back(); +} + +void CxxAstVisitorComponentContext::beginTraverseTypeLoc(clang::TypeLoc tl) +{ + std::shared_ptr context; + + if (!getAstVisitor()->checkIgnoresTypeLoc(tl)) + { + context = std::make_shared(tl.getTypePtr(), getAstVisitor()->getTypeNameCache()); + } + + m_contextStack.push_back(context); +} + +void CxxAstVisitorComponentContext::endTraverseTypeLoc(clang::TypeLoc tl) +{ + m_contextStack.pop_back(); +} + +void CxxAstVisitorComponentContext::beginTraverseLambdaExpr(clang::LambdaExpr* s) +{ + clang::CXXMethodDecl* methodDecl = s->getCallOperator(); + m_contextStack.push_back(std::make_shared(methodDecl, getAstVisitor()->getDeclNameCache())); +} + +void CxxAstVisitorComponentContext::endTraverseLambdaExpr(clang::LambdaExpr* s) +{ + m_contextStack.pop_back(); +} + +void CxxAstVisitorComponentContext::beginTraverseFunctionDecl(clang::FunctionDecl* d) +{ + m_templateArgumentContext.push_back(std::make_shared(d, getAstVisitor()->getDeclNameCache())); +} + +void CxxAstVisitorComponentContext::endTraverseFunctionDecl(clang::FunctionDecl* d) +{ + m_templateArgumentContext.pop_back(); +} + +void CxxAstVisitorComponentContext::beginTraverseClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl *d) +{ + m_templateArgumentContext.push_back(std::make_shared(d, getAstVisitor()->getDeclNameCache())); +} + +void CxxAstVisitorComponentContext::endTraverseClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl *d) +{ + m_templateArgumentContext.pop_back(); +} + +void CxxAstVisitorComponentContext::beginTraverseClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* d) +{ + m_templateArgumentContext.push_back(std::make_shared(d, getAstVisitor()->getDeclNameCache())); +} + +void CxxAstVisitorComponentContext::endTraverseClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* d) +{ + m_templateArgumentContext.pop_back(); +} + +void CxxAstVisitorComponentContext::beginTraverseDeclRefExpr(clang::DeclRefExpr* s) +{ + m_templateArgumentContext.push_back(std::make_shared(s->getDecl(), getAstVisitor()->getDeclNameCache())); +} + +void CxxAstVisitorComponentContext::endTraverseDeclRefExpr(clang::DeclRefExpr* s) +{ + m_templateArgumentContext.pop_back(); +} + +void CxxAstVisitorComponentContext::beginTraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc) +{ + m_templateArgumentContext.push_back(std::make_shared(loc.getTypePtr(), getAstVisitor()->getTypeNameCache())); +} + +void CxxAstVisitorComponentContext::endTraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc) +{ + m_templateArgumentContext.pop_back(); +} + +void CxxAstVisitorComponentContext::beginTraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* e) // TODO: do this for unresolved and dependent stuff +{ + std::shared_ptr clear; + m_templateArgumentContext.push_back(clear); +} + +void CxxAstVisitorComponentContext::endTraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* e) +{ + m_templateArgumentContext.pop_back(); +} + +void CxxAstVisitorComponentContext::beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc) +{ + std::shared_ptr context; + + if (!m_templateArgumentContext.empty()) + { + context = m_templateArgumentContext.back(); + } + + m_contextStack.push_back(context); +} + +void CxxAstVisitorComponentContext::endTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc) +{ + m_contextStack.pop_back(); +} diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentContext.h b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentContext.h new file mode 100644 index 00000000..f7100088 --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentContext.h @@ -0,0 +1,55 @@ +#ifndef CXX_AST_VISITOR_COMPONENT_CONTEXT_H +#define CXX_AST_VISITOR_COMPONENT_CONTEXT_H + +#include "data/parser/cxx/CxxAstVisitorComponent.h" +#include "data/parser/cxx/CxxContext.h" + +// This CxxAstVisitorComponent is responsible for recording and providing the decl/type that acts as the context of the currently traversed/visited node. +// Example: void foo() { bar(); } +// For this snippet the declaration of "foo" serves as the context of the call to "bar" +class CxxAstVisitorComponentContext: public CxxAstVisitorComponent +{ +public: + CxxAstVisitorComponentContext(CxxAstVisitor* astVisitor); + virtual ~CxxAstVisitorComponentContext(); + + const clang::NamedDecl* getTopmostContextDecl() const; + NameHierarchy getContextName(const size_t skip = 0); + NameHierarchy getContextName(const NameHierarchy& fallback, const size_t skip = 0); + + virtual void beginTraverseDecl(clang::Decl* d); + virtual void endTraverseDecl(clang::Decl* d); + + virtual void beginTraverseTypeLoc(clang::TypeLoc tl); + virtual void endTraverseTypeLoc(clang::TypeLoc tl); + + virtual void beginTraverseLambdaExpr(clang::LambdaExpr* s); + virtual void endTraverseLambdaExpr(clang::LambdaExpr* s); + + virtual void beginTraverseFunctionDecl(clang::FunctionDecl* d); + virtual void endTraverseFunctionDecl(clang::FunctionDecl* d); + + virtual void beginTraverseClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl *d); + virtual void endTraverseClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl *d); + + virtual void beginTraverseClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* d); + virtual void endTraverseClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* d); + + virtual void beginTraverseDeclRefExpr(clang::DeclRefExpr* s); + virtual void endTraverseDeclRefExpr(clang::DeclRefExpr* s); + + virtual void beginTraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc); + virtual void endTraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc); + + virtual void beginTraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* e); + virtual void endTraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* e); + + virtual void beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc); + virtual void endTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc); + +private: + std::vector> m_contextStack; + std::vector> m_templateArgumentContext; +}; + +#endif // CXX_AST_VISITOR_COMPONENT_CONTEXT_H diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentDeclRefKind.cpp b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentDeclRefKind.cpp new file mode 100644 index 00000000..116ba304 --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentDeclRefKind.cpp @@ -0,0 +1,178 @@ +#include "data/parser/cxx/CxxAstVisitorComponentDeclRefKind.h" + +CxxAstVisitorComponentDeclRefKind::CxxAstVisitorComponentDeclRefKind(CxxAstVisitor* astVisitor) + : CxxAstVisitorComponent(astVisitor) + , m_thisRefKind(REFERENCE_USAGE) + , m_childRefKind(REFERENCE_USAGE) +{ +} + +CxxAstVisitorComponentDeclRefKind::~CxxAstVisitorComponentDeclRefKind() +{ +} + +ReferenceKind CxxAstVisitorComponentDeclRefKind::getReferenceKind() const +{ + return m_thisRefKind; +} + + +void CxxAstVisitorComponentDeclRefKind::beginTraverseDecl(clang::Decl* d) +{ + saveAll(); + m_thisRefKind = REFERENCE_USAGE; + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::endTraverseDecl(clang::Decl* d) +{ + restoreAll(); +} + +void CxxAstVisitorComponentDeclRefKind::beginTraverseStmt(clang::Stmt* s) +{ + saveAll(); + + if (s == nullptr) + { + return; + } + + m_thisRefKind = m_childRefKind; + if (!clang::isa(s)) + { + m_thisRefKind = REFERENCE_USAGE; + } + m_childRefKind = m_thisRefKind; +} + +void CxxAstVisitorComponentDeclRefKind::endTraverseStmt(clang::Stmt* s) +{ + restoreAll(); +} + +void CxxAstVisitorComponentDeclRefKind::beginTraverseType(clang::QualType t) +{ + saveAll(); + m_thisRefKind = REFERENCE_USAGE; + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::endTraverseType(clang::QualType t) +{ + restoreAll(); +} + +void CxxAstVisitorComponentDeclRefKind::beginTraverseTypeLoc(clang::TypeLoc tl) +{ + saveAll(); + m_thisRefKind = REFERENCE_USAGE; + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::endTraverseTypeLoc(clang::TypeLoc tl) +{ + restoreAll(); +} + +void CxxAstVisitorComponentDeclRefKind::beginTraverseCallCommonCallee() +{ + m_thisRefKind = REFERENCE_CALL; + m_childRefKind = REFERENCE_CALL; +} +void CxxAstVisitorComponentDeclRefKind::beginTraverseCallCommonArgument() +{ + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::beginTraverseBinCommaLhs() +{ + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::beginTraverseBinCommaRhs() +{ + m_childRefKind = m_thisRefKind; +} + +void CxxAstVisitorComponentDeclRefKind::beginTraverseAssignCommonLhs() +{ + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::beginTraverseAssignCommonRhs() +{ + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::beginTraverseConstructorInitializer(clang::CXXCtorInitializer* init) +{ + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::beginTraverseCXXTemporaryObjectExpr(clang::CXXTemporaryObjectExpr* s) +{ + m_thisRefKind = REFERENCE_CALL; + m_childRefKind = REFERENCE_CALL; +} + +void CxxAstVisitorComponentDeclRefKind::visitVarDecl(clang::VarDecl* d) +{ + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::visitCastExpr(clang::CastExpr* s) +{ + switch (s->getCastKind()) + { + case clang::CK_ArrayToPointerDecay: + case clang::CK_ToVoid: + case clang::CK_LValueToRValue: + m_childRefKind = REFERENCE_USAGE; + } +} + +void CxxAstVisitorComponentDeclRefKind::visitUnaryAddrOf(clang::UnaryOperator* s) +{ + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::visitUnaryDeref(clang::UnaryOperator* s) +{ + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::visitDeclStmt(clang::DeclStmt* s) +{ + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::visitReturnStmt(clang::ReturnStmt* s) +{ + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::visitInitListExpr(clang::InitListExpr* s) +{ + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::visitMemberExpr(clang::MemberExpr* s) +{ + m_childRefKind = REFERENCE_USAGE; +} + +void CxxAstVisitorComponentDeclRefKind::saveAll() +{ + m_oldThisRefKinds.push_back(m_thisRefKind); + m_oldChildRefKinds.push_back(m_childRefKind); +} + +void CxxAstVisitorComponentDeclRefKind::restoreAll() +{ + m_thisRefKind = m_oldThisRefKinds.back(); + m_oldThisRefKinds.pop_back(); + + m_childRefKind = m_oldChildRefKinds.back(); + m_oldChildRefKinds.pop_back(); +} diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentDeclRefKind.h b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentDeclRefKind.h new file mode 100644 index 00000000..0fa53ddb --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentDeclRefKind.h @@ -0,0 +1,77 @@ +#ifndef CXX_AST_VISITOR_COMPONENT_DECL_REF_KIND_H +#define CXX_AST_VISITOR_COMPONENT_DECL_REF_KIND_H + +#include + +#include "data/parser/cxx/CxxAstVisitor.h" +#include "data/parser/cxx/CxxAstVisitorComponent.h" + +#include "data/parser/ReferenceKind.h" + +// This CxxAstVisitorComponent is responsible for recording and providing the context based ReferenceKind for each reference to a declaration encountered while traversing the AST. +// Example: void foo() { bar(); } +// For this snippet the reference to "bar" is used in the context of a call. +class CxxAstVisitorComponentDeclRefKind: public CxxAstVisitorComponent +{ +public: + CxxAstVisitorComponentDeclRefKind(CxxAstVisitor* astVisitor); + virtual ~CxxAstVisitorComponentDeclRefKind(); + + ReferenceKind getReferenceKind() const; + + virtual void beginTraverseDecl(clang::Decl* d); + virtual void endTraverseDecl(clang::Decl* d); + + virtual void beginTraverseStmt(clang::Stmt* s); + virtual void endTraverseStmt(clang::Stmt* s); + + virtual void beginTraverseType(clang::QualType t); + virtual void endTraverseType(clang::QualType t); + + virtual void beginTraverseTypeLoc(clang::TypeLoc tl); + virtual void endTraverseTypeLoc(clang::TypeLoc tl); + + virtual void beginTraverseCallCommonCallee(); + + virtual void beginTraverseCallCommonArgument(); + + virtual void beginTraverseBinCommaLhs(); + + virtual void beginTraverseBinCommaRhs(); + + virtual void beginTraverseAssignCommonLhs(); + + virtual void beginTraverseAssignCommonRhs(); + + virtual void beginTraverseConstructorInitializer(clang::CXXCtorInitializer* init); + + virtual void beginTraverseCXXTemporaryObjectExpr(clang::CXXTemporaryObjectExpr* s); + + virtual void visitVarDecl(clang::VarDecl* d); + + virtual void visitCastExpr(clang::CastExpr* s); + + virtual void visitUnaryAddrOf(clang::UnaryOperator* s); + + virtual void visitUnaryDeref(clang::UnaryOperator* s); + + virtual void visitDeclStmt(clang::DeclStmt* s); + + virtual void visitReturnStmt(clang::ReturnStmt* s); + + virtual void visitInitListExpr(clang::InitListExpr* s); + + virtual void visitMemberExpr(clang::MemberExpr* s); + +private: + void saveAll(); + void restoreAll(); + + ReferenceKind m_thisRefKind; + ReferenceKind m_childRefKind; + + std::vector m_oldThisRefKinds; + std::vector m_oldChildRefKinds; +}; + +#endif // CXX_AST_VISITOR_COMPONENT_DECL_REF_KIND_H diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentIndexer.cpp b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentIndexer.cpp new file mode 100644 index 00000000..40f45c3e --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentIndexer.cpp @@ -0,0 +1,682 @@ +#include "data/parser/cxx/CxxAstVisitorComponentIndexer.h" + +#include +#include +#include +#include + +#include "data/parser/cxx/CxxAstVisitorComponentContext.h" +#include "data/parser/cxx/CxxAstVisitorComponentDeclRefKind.h" +#include "data/parser/cxx/CxxAstVisitorComponentTypeRefKind.h" + +#include "data/parser/cxx/utilityCxxAstVisitor.h" +#include "data/parser/ParseLocation.h" +#include "data/parser/ParserClient.h" +#include "utility/file/FileRegister.h" + +CxxAstVisitorComponentIndexer::CxxAstVisitorComponentIndexer(CxxAstVisitor* astVisitor, clang::ASTContext* astContext, ParserClient* client, FileRegister* fileRegister) + : CxxAstVisitorComponent(astVisitor) + , m_astContext(astContext) + , m_client(client) + , m_fileRegister(fileRegister) +{ +} + +CxxAstVisitorComponentIndexer::~CxxAstVisitorComponentIndexer() +{ +} + +void CxxAstVisitorComponentIndexer::beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc) +{ + if ( + (loc.getArgument().getKind() == clang::TemplateArgument::Template) && + (shouldVisitReference(loc.getLocation(), getAstVisitor()->getComponent()->getTopmostContextDecl())) + ){ + // TODO: maybe move this to VisitTemplateName + m_client->recordReference( + getAstVisitor()->getComponent()->getReferenceKind(), + getAstVisitor()->getDeclNameCache()->getValue(loc.getArgument().getAsTemplate().getAsTemplateDecl()), + getAstVisitor()->getComponent()->getContextName(), + getParseLocation(loc.getLocation()) + ); + } +} + +void CxxAstVisitorComponentIndexer::beginTraverseLambdaCapture(clang::LambdaExpr *lambdaExpr, const clang::LambdaCapture *capture) +{ + if ((!lambdaExpr->isInitCapture(capture)) && (capture->capturesVariable())) + { + clang::VarDecl* d = capture->getCapturedVar(); + SymbolKind symbolKind = getSymbolKind(d); + if (symbolKind == SYMBOL_LOCAL_VARIABLE || symbolKind == SYMBOL_PARAMETER) + { + if (!d->getNameAsString().empty()) // don't record anonymous parameters + { + ParseLocation declLocation = getParseLocation(d->getLocation()); + std::string name = + declLocation.filePath.fileName() + "<" + + std::to_string(declLocation.startLineNumber) + ":" + + std::to_string(declLocation.startColumnNumber) + ">"; + m_client->onLocalSymbolParsed(name, getParseLocation(capture->getLocation())); + } + } + } +} + +void CxxAstVisitorComponentIndexer::visitTagDecl(clang::TagDecl* d) +{ + if (shouldVisitDecl(d)) + { + m_client->recordSymbol( + getAstVisitor()->getDeclNameCache()->getValue(d), + utility::convertTagKind(d->getTagKind()), + getParseLocation(d->getLocation()), + getParseLocationOfTagDeclBody(d), + utility::convertAccessSpecifier(d->getAccess()), + utility::isImplicit(d) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl* d) +{ + if (shouldVisitDecl(d)) + { + clang::NamedDecl* specializedFromDecl; + + // todo: use context and childcontext!! + llvm::PointerUnion pu = d->getSpecializedTemplateOrPartial(); + if (pu.is()) + { + specializedFromDecl = pu.get(); + } + else if (pu.is()) + { + specializedFromDecl = pu.get(); + } + + m_client->recordReference( + REFERENCE_TEMPLATE_SPECIALIZATION_OF, // TODO: call this REFERENCE_TEMPLATE_SPECIALIZATION and reverse the following arguments + getAstVisitor()->getDeclNameCache()->getValue(specializedFromDecl), + getAstVisitor()->getDeclNameCache()->getValue(d), + getParseLocation(d->getLocation()) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitVarDecl(clang::VarDecl* d) +{ + if (shouldVisitDecl(d)) + { + SymbolKind symbolKind = getSymbolKind(d); + if (symbolKind == SYMBOL_LOCAL_VARIABLE || symbolKind == SYMBOL_PARAMETER) + { + if (!d->getNameAsString().empty()) // don't record anonymous parameters + { + ParseLocation declLocation = getParseLocation(d->getLocation()); + std::string name = + declLocation.filePath.fileName() + "<" + + std::to_string(declLocation.startLineNumber) + ":" + + std::to_string(declLocation.startColumnNumber) + ">"; + m_client->onLocalSymbolParsed(name, getParseLocation(d->getLocation())); + } + } + else + { + m_client->recordSymbol( + getAstVisitor()->getDeclNameCache()->getValue(d), + symbolKind, + getParseLocation(d->getLocation()), + utility::convertAccessSpecifier(d->getAccess()), + utility::isImplicit(d) + ); + } + } +} + +void CxxAstVisitorComponentIndexer::visitFieldDecl(clang::FieldDecl* d) +{ + if (shouldVisitDecl(d)) + { + m_client->recordSymbol( + getAstVisitor()->getDeclNameCache()->getValue(d), + SYMBOL_FIELD, + getParseLocation(d->getLocation()), + utility::convertAccessSpecifier(d->getAccess()), + utility::isImplicit(d) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitFunctionDecl(clang::FunctionDecl* d) +{ + if (shouldVisitDecl(d)) + { + m_client->recordSymbol( + getAstVisitor()->getDeclNameCache()->getValue(d), + clang::isa(d) ? SYMBOL_METHOD : SYMBOL_FUNCTION, + getParseLocation(d->getLocation()), + getParseLocationOfFunctionBody(d), + utility::convertAccessSpecifier(d->getAccess()), + utility::isImplicit(d) + ); + + if (d->isFunctionTemplateSpecialization()) + { + m_client->recordReference( + REFERENCE_TEMPLATE_SPECIALIZATION_OF, // TODO: call this REFERENCE_TEMPLATE_SPECIALIZATION and reverse the following arguments + getAstVisitor()->getDeclNameCache()->getValue(d->getPrimaryTemplate()->getTemplatedDecl()), // todo: use context and childcontext!! + getAstVisitor()->getDeclNameCache()->getValue(d), + getParseLocation(d->getLocation()) + ); + } + } +} + +void CxxAstVisitorComponentIndexer::visitCXXMethodDecl(clang::CXXMethodDecl* d) +{ + // Decl has been recorded in VisitFunctionDecl + if (shouldVisitDecl(d)) + { + for (clang::CXXMethodDecl::method_iterator it = d->begin_overridden_methods(); // TODO: iterate in traversal and use RT_Overridden or so.. + it != d->end_overridden_methods(); it++) + { + m_client->recordReference( + REFERENCE_OVERRIDE, + getAstVisitor()->getDeclNameCache()->getValue(*it), + getAstVisitor()->getDeclNameCache()->getValue(d), + getParseLocation(d->getLocation()) + ); + } + + clang::MemberSpecializationInfo* memberSpecializationInfo = d->getMemberSpecializationInfo(); + if (memberSpecializationInfo) + { + clang::NamedDecl* specializedNamedDecl = memberSpecializationInfo->getInstantiatedFrom(); + if (clang::isa(specializedNamedDecl)) + { + m_client->recordReference( + REFERENCE_TEMPLATE_MEMBER_SPECIALIZATION_OF, + getAstVisitor()->getDeclNameCache()->getValue(specializedNamedDecl), + getAstVisitor()->getDeclNameCache()->getValue(d), + getParseLocation(d->getLocation()) + ); + } + } + } +} + +void CxxAstVisitorComponentIndexer::visitEnumConstantDecl(clang::EnumConstantDecl* d) +{ + if (shouldVisitDecl(d)) + { + m_client->recordSymbol( + getAstVisitor()->getDeclNameCache()->getValue(d), + SYMBOL_ENUM_CONSTANT, + getParseLocation(d->getLocation()), + ACCESS_NONE, + utility::isImplicit(d) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitNamespaceDecl(clang::NamespaceDecl* d) +{ + if (shouldVisitDecl(d)) + { + m_client->recordSymbol( + getAstVisitor()->getDeclNameCache()->getValue(d), + SYMBOL_NAMESPACE, + d->isAnonymousNamespace() ? ParseLocation() : getParseLocation(d->getLocation()), + getParseLocation(d->getSourceRange()), + utility::convertAccessSpecifier(d->getAccess()), + utility::isImplicit(d) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitNamespaceAliasDecl(clang::NamespaceAliasDecl* d) +{ + if (shouldVisitDecl(d)) + { + m_client->recordSymbol( + getAstVisitor()->getDeclNameCache()->getValue(d), + SYMBOL_NAMESPACE, + getParseLocation(d->getLocation()), + utility::convertAccessSpecifier(d->getAccess()), + utility::isImplicit(d) + ); + + m_client->recordReference( + REFERENCE_USAGE, + getAstVisitor()->getDeclNameCache()->getValue(d->getAliasedNamespace()), + getAstVisitor()->getDeclNameCache()->getValue(d), + getParseLocation(d->getTargetNameLoc()) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitTypedefDecl(clang::TypedefDecl* d) +{ + if (shouldVisitDecl(d)) + { + m_client->recordSymbol( + getAstVisitor()->getDeclNameCache()->getValue(d), + SYMBOL_TYPEDEF, + getParseLocation(d->getLocation()), + utility::convertAccessSpecifier(d->getAccess()), + utility::isImplicit(d) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitTypeAliasDecl(clang::TypeAliasDecl* d) +{ + if (shouldVisitDecl(d)) + { + m_client->recordSymbol( + getAstVisitor()->getDeclNameCache()->getValue(d), + SYMBOL_TYPEDEF, + getParseLocation(d->getLocation()), + utility::convertAccessSpecifier(d->getAccess()), + utility::isImplicit(d) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitUsingDirectiveDecl(clang::UsingDirectiveDecl* d) +{ + if (shouldVisitDecl(d)) + { + ParseLocation loc = getParseLocation(d->getLocation()); + m_client->recordReference( + REFERENCE_USAGE, + getAstVisitor()->getDeclNameCache()->getValue(d->getNominatedNamespaceAsWritten()), + getAstVisitor()->getComponent()->getContextName(NameHierarchy(loc.filePath.fileName())), + loc + ); + } +} + +void CxxAstVisitorComponentIndexer::visitUsingDecl(clang::UsingDecl* d) +{ + if (shouldVisitDecl(d)) + { + ParseLocation loc = getParseLocation(d->getLocation()); + m_client->recordReference( + REFERENCE_USAGE, + getAstVisitor()->getDeclNameCache()->getValue(d), + getAstVisitor()->getComponent()->getContextName(NameHierarchy(loc.filePath.fileName())), + loc + ); + } +} + +void CxxAstVisitorComponentIndexer::visitNonTypeTemplateParmDecl(clang::NonTypeTemplateParmDecl* d) +{ + if (shouldVisitDecl(d) && !d->getName().empty()) // We don't create symbols for unnamed template parameters. + { + m_client->recordSymbol( + getAstVisitor()->getDeclNameCache()->getValue(d), + SYMBOL_TEMPLATE_PARAMETER, + getParseLocation(d->getLocation()), + ACCESS_TEMPLATE_PARAMETER, + utility::isImplicit(d) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d) +{ + if (shouldVisitDecl(d) && !d->getName().empty()) // We don't create symbols for unnamed template parameters. + { + m_client->recordSymbol( + getAstVisitor()->getDeclNameCache()->getValue(d), + SYMBOL_TEMPLATE_PARAMETER, + getParseLocation(d->getLocation()), + ACCESS_TEMPLATE_PARAMETER, + utility::isImplicit(d) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d) +{ + if (shouldVisitDecl(d) && !d->getName().empty()) // We don't create symbols for unnamed template parameters. + { + m_client->recordSymbol( + getAstVisitor()->getDeclNameCache()->getValue(d), + SYMBOL_TEMPLATE_PARAMETER, + getParseLocation(d->getLocation()), + ACCESS_TEMPLATE_PARAMETER, + utility::isImplicit(d) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitTypeLoc(clang::TypeLoc tl) +{ + if ((shouldVisitReference(tl.getBeginLoc(), getAstVisitor()->getComponent()->getTopmostContextDecl())) && + (!getAstVisitor()->checkIgnoresTypeLoc(tl))) + { + clang::SourceLocation loc; + if (!tl.getAs().isNull()) + { + const clang::DependentNameTypeLoc& dntl = tl.castAs(); + loc = dntl.getNameLoc(); + } + else + { + loc = tl.getBeginLoc(); + } + + m_client->recordReference( + getAstVisitor()->getComponent()->getReferenceKind(), + getAstVisitor()->getTypeNameCache()->getValue(tl.getTypePtr()), + getAstVisitor()->getComponent()->getContextName(1), // we skip the last element because it refers to this typeloc. + getParseLocation(loc) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitDeclRefExpr(clang::DeclRefExpr* s) +{ + clang::ValueDecl* decl = s->getDecl(); + if (shouldVisitReference(s->getLocation(), getAstVisitor()->getComponent()->getTopmostContextDecl())) + { + if ((clang::isa(decl)) || + (clang::isa(decl) && decl->getParentFunctionOrMethod() != NULL) + ) { + ParseLocation declLocation = getParseLocation(decl->getLocation()); + std::string name = declLocation.filePath.fileName() + "<" + + std::to_string(declLocation.startLineNumber) + ":" + + std::to_string(declLocation.startColumnNumber) + ">"; + + m_client->onLocalSymbolParsed(name, getParseLocation(s->getLocation())); + } + else + { + m_client->recordReference( + consumeDeclRefContextKind(), + getAstVisitor()->getDeclNameCache()->getValue(s->getDecl()), + getAstVisitor()->getComponent()->getContextName(), + getParseLocation(s->getLocation()) + ); + } + } +} + +void CxxAstVisitorComponentIndexer::visitMemberExpr(clang::MemberExpr* s) +{ + if (shouldVisitReference(s->getMemberLoc(), getAstVisitor()->getComponent()->getTopmostContextDecl())) + { + m_client->recordReference( + consumeDeclRefContextKind(), + getAstVisitor()->getDeclNameCache()->getValue(s->getMemberDecl()), + getAstVisitor()->getComponent()->getContextName(), + getParseLocation(s->getMemberLoc()) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitCXXConstructExpr(clang::CXXConstructExpr* s) +{ + if (shouldVisitReference(s->getLocation(), getAstVisitor()->getComponent()->getTopmostContextDecl())) + { + //if (e->getParenOrBraceRange().isValid()) { + // // XXX: This code is a kludge. Recording calls to constructors is + // // troublesome because there isn't an obvious location to associate the + // // call with. Consider: + // // A::A() : field(1, 2, 3) {} + // // new A(1, 2, 3) + // // struct A { A(B); }; A f() { B b; return b; } + // // Implicit calls to conversion operator methods pose a similar + // // problem. + // // + // // Recording constructor calls is very useful, though, so, as a + // // temporary measure, when there are constructor arguments surrounded + // // by parentheses, associate the call with the right parenthesis. + // // + // // Perhaps the right fix is to associate the call with the line itself + // // or with a larger span which may have other references nested within + // // it. The fix may have implications for the navigator GUI. + // RecordDeclRefExpr( + // e->getConstructor(), + // e->getParenOrBraceRange().getEnd(), + // e, + // CF_Called); + //} + clang::SourceLocation loc; + clang::SourceLocation braceBeginLoc = s->getParenOrBraceRange().getBegin(); + clang::SourceLocation nameBeginLoc = s->getSourceRange().getBegin(); + if (braceBeginLoc.isValid()) + { + if (braceBeginLoc == nameBeginLoc) + { + loc = nameBeginLoc; + } + else + { + loc = braceBeginLoc.getLocWithOffset(-1); + } + } + else + { + loc = s->getSourceRange().getEnd(); + } + loc = clang::Lexer::GetBeginningOfToken(loc, m_astContext->getSourceManager(), m_astContext->getLangOpts()); + + m_client->recordReference( + consumeDeclRefContextKind(), + getAstVisitor()->getDeclNameCache()->getValue(s->getConstructor()), + getAstVisitor()->getComponent()->getContextName(), + getParseLocation(loc) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitLambdaExpr(clang::LambdaExpr* s) +{ + clang::CXXMethodDecl* methodDecl = s->getCallOperator(); + if (shouldVisitDecl(methodDecl)) + { + m_client->recordSymbol( + getAstVisitor()->getDeclNameCache()->getValue(methodDecl), + SYMBOL_FUNCTION, + getParseLocation(s->getLocStart()), + getParseLocationOfFunctionBody(methodDecl), + ACCESS_NONE, // TODO: introduce AccessLambda + utility::isImplicit(methodDecl) + ); + } +} + +void CxxAstVisitorComponentIndexer::visitConstructorInitializer(clang::CXXCtorInitializer* init) +{ + if (shouldVisitReference(init->getMemberLocation(), getAstVisitor()->getComponent()->getTopmostContextDecl())) + { + // record the field usage here because it is not a DeclRefExpr + if (clang::FieldDecl* memberDecl = init->getMember()) + { + m_client->recordReference( + REFERENCE_USAGE, + getAstVisitor()->getDeclNameCache()->getValue(memberDecl), + getAstVisitor()->getComponent()->getContextName(), + getParseLocation(init->getMemberLocation()) + ); + } + } +} + +ParseLocation CxxAstVisitorComponentIndexer::getParseLocationOfTagDeclBody(clang::TagDecl* decl) const +{ + return getAstVisitor()->getParseLocationOfTagDeclBody(decl); +} + +ParseLocation CxxAstVisitorComponentIndexer::getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const +{ + return getAstVisitor()->getParseLocationOfFunctionBody(decl); +} + +ParseLocation CxxAstVisitorComponentIndexer::getParseLocation(const clang::SourceLocation& loc) const +{ + return getAstVisitor()->getParseLocation(loc); +} + +ParseLocation CxxAstVisitorComponentIndexer::getParseLocation(const clang::SourceRange& sourceRange) const +{ + return getAstVisitor()->getParseLocation(sourceRange); +} + +ReferenceKind CxxAstVisitorComponentIndexer::consumeDeclRefContextKind() +{ + ReferenceKind refKind = REFERENCE_UNDEFINED; + + std::shared_ptr typeRefKindComponent = getAstVisitor()->getComponent(); + + if (typeRefKindComponent->getReferenceKind() == REFERENCE_TYPE_USAGE) + { + refKind = getAstVisitor()->getComponent()->getReferenceKind(); + } + else + { + refKind = typeRefKindComponent->getReferenceKind(); + } + return refKind; +} + +SymbolKind CxxAstVisitorComponentIndexer::getSymbolKind(clang::VarDecl* d) +{ + SymbolKind symbolKind = SYMBOL_KIND_MAX; + + if (llvm::isa(d)) + { + symbolKind = SYMBOL_PARAMETER; + } + else if (d->getParentFunctionOrMethod() == NULL) + { + if (d->getAccess() == clang::AS_none) + { + symbolKind = SYMBOL_GLOBAL_VARIABLE; + } + else + { + symbolKind = SYMBOL_FIELD; + } + } + else + { + symbolKind = SYMBOL_LOCAL_VARIABLE; + } + + return symbolKind; +} + +bool CxxAstVisitorComponentIndexer::shouldVisitDecl(const clang::Decl* decl) +{ + if (decl) + { + clang::SourceLocation loc = decl->getLocation(); + bool declIsImplicit = utility::isImplicit(decl); + if ((declIsImplicit && isLocatedInProjectFile(loc)) || + (!declIsImplicit && isLocatedInUnparsedProjectFile(loc))) + { + return true; + } + } + return false; +} + +bool CxxAstVisitorComponentIndexer::shouldVisitReference(const clang::SourceLocation& referenceLocation, const clang::Decl* contextDecl) +{ + bool declIsImplicit = true; // default value is "true" to make sure that everything that should be visited gets visited. + if (contextDecl) + { + declIsImplicit = utility::isImplicit(contextDecl); + } + + if ((declIsImplicit && isLocatedInProjectFile(referenceLocation)) || + (!declIsImplicit && isLocatedInUnparsedProjectFile(referenceLocation))) + { + return true; + } + return false; +} + +bool CxxAstVisitorComponentIndexer::isLocatedInUnparsedProjectFile(clang::SourceLocation loc) +{ + clang::SourceManager& sourceManager = m_astContext->getSourceManager(); + clang::SourceLocation spellingLoc = sourceManager.getSpellingLoc(loc); + + clang::FileID fileId; + + if (spellingLoc.isValid()) + { + fileId = sourceManager.getFileID(spellingLoc); + } + if (fileId.isValid()) + { + auto it = m_inUnparsedProjectFileMap.find(fileId); + if (it != m_inUnparsedProjectFileMap.end()) + { + return it->second; + } + + bool ret = false; + if (sourceManager.isWrittenInMainFile(spellingLoc)) + { + ret = true; + } + else + { + const clang::FileEntry* fileEntry = sourceManager.getFileEntryForID(fileId); + if (fileEntry != NULL) + { + std::string fileName = fileEntry->getName(); + FilePath filePath = FilePath(fileName).canonical(); + + if (m_fileRegister->hasIncludeFile(filePath)) + { + ret = !(m_fileRegister->includeFileIsParsed(filePath)); + } + } + } + m_inUnparsedProjectFileMap[fileId] = ret; + return ret; + } + return false; +} + +bool CxxAstVisitorComponentIndexer::isLocatedInProjectFile(clang::SourceLocation loc) +{ + clang::SourceManager& sourceManager = m_astContext->getSourceManager(); + clang::SourceLocation spellingLoc = sourceManager.getSpellingLoc(loc); + + clang::FileID fileId; + + if (spellingLoc.isValid()) + { + fileId = sourceManager.getFileID(spellingLoc); + } + + if (!fileId.isInvalid()) + { + auto it = m_inProjectFileMap.find(fileId); + if (it != m_inProjectFileMap.end()) + { + return it->second; + } + + const clang::FileEntry* fileEntry = sourceManager.getFileEntryForID(fileId); + if (fileEntry != NULL) + { + std::string fileName = fileEntry->getName(); + FilePath filePath = FilePath(fileName).canonical(); + bool ret = m_fileRegister->hasFilePath(filePath.str()); + m_inProjectFileMap[fileId] = ret; + return ret; + } + } + + return false; +} diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentIndexer.h b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentIndexer.h new file mode 100644 index 00000000..49a6f103 --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentIndexer.h @@ -0,0 +1,77 @@ +#ifndef CXX_AST_VISITOR_COMPONENT_INDEXER_H +#define CXX_AST_VISITOR_COMPONENT_INDEXER_H + +#include + +#include "data/parser/cxx/CxxAstVisitor.h" +#include "data/parser/cxx/CxxAstVisitorComponent.h" +#include "data/parser/ReferenceKind.h" +#include "data/parser/SymbolKind.h" + +// This CxxAstVisitorComponent is responsible for recording all symbols and relations throughout the visited AST. +class CxxAstVisitorComponentIndexer: public CxxAstVisitorComponent +{ +public: + CxxAstVisitorComponentIndexer(CxxAstVisitor* astVisitor, clang::ASTContext* astContext, ParserClient* client, FileRegister* fileRegister); + virtual ~CxxAstVisitorComponentIndexer(); + + virtual void beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc); + virtual void beginTraverseLambdaCapture(clang::LambdaExpr *lambdaExpr, const clang::LambdaCapture *capture); + + virtual void visitTagDecl(clang::TagDecl* d); + virtual void visitClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl* d); + virtual void visitVarDecl(clang::VarDecl* d); + virtual void visitFieldDecl(clang::FieldDecl* d); + virtual void visitFunctionDecl(clang::FunctionDecl* d); + virtual void visitCXXMethodDecl(clang::CXXMethodDecl* d); + virtual void visitEnumConstantDecl(clang::EnumConstantDecl* d); + virtual void visitNamespaceDecl(clang::NamespaceDecl* d); + virtual void visitNamespaceAliasDecl(clang::NamespaceAliasDecl* d); + virtual void visitTypedefDecl(clang::TypedefDecl* d); + virtual void visitTypeAliasDecl(clang::TypeAliasDecl* d); + virtual void visitUsingDirectiveDecl(clang::UsingDirectiveDecl* d); + virtual void visitUsingDecl(clang::UsingDecl* d); + virtual void visitNonTypeTemplateParmDecl(clang::NonTypeTemplateParmDecl* d); + virtual void visitTemplateTypeParmDecl(clang::TemplateTypeParmDecl* d); + virtual void visitTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl* d); + + virtual void visitTypeLoc(clang::TypeLoc tl); + + virtual void visitDeclRefExpr(clang::DeclRefExpr* s); + virtual void visitMemberExpr(clang::MemberExpr* s); + virtual void visitCXXConstructExpr(clang::CXXConstructExpr* s); + virtual void visitLambdaExpr(clang::LambdaExpr* s); + + virtual void visitConstructorInitializer(clang::CXXCtorInitializer* init); + +private: + struct FileIdHash + { + size_t operator()(clang::FileID fileID) const + { + return fileID.getHashValue(); + } + }; + + ParseLocation getParseLocationOfTagDeclBody(clang::TagDecl* decl) const; + ParseLocation getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const; + ParseLocation getParseLocation(const clang::SourceLocation& loc) const; + ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const; + + ReferenceKind consumeDeclRefContextKind(); + SymbolKind getSymbolKind(clang::VarDecl* d); + + bool shouldVisitDecl(const clang::Decl* decl); + bool shouldVisitReference(const clang::SourceLocation& referenceLocation, const clang::Decl* contextDecl); + bool isLocatedInUnparsedProjectFile(clang::SourceLocation loc); + bool isLocatedInProjectFile(clang::SourceLocation loc); + + clang::ASTContext* m_astContext; + ParserClient* m_client; + FileRegister* m_fileRegister; + + std::unordered_map m_inUnparsedProjectFileMap; + std::unordered_map m_inProjectFileMap; +}; + +#endif // CXX_AST_VISITOR_COMPONENT_INDEXER_H diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentTypeRefKind.cpp b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentTypeRefKind.cpp new file mode 100644 index 00000000..dde1671e --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentTypeRefKind.cpp @@ -0,0 +1,59 @@ +#include "data/parser/cxx/CxxAstVisitorComponentTypeRefKind.h" + +CxxAstVisitorComponentTypeRefKind::CxxAstVisitorComponentTypeRefKind(CxxAstVisitor* astVisitor) + : CxxAstVisitorComponent(astVisitor) +{ +} + +CxxAstVisitorComponentTypeRefKind::~CxxAstVisitorComponentTypeRefKind() +{ +} + +ReferenceKind CxxAstVisitorComponentTypeRefKind::getReferenceKind() const +{ + for (auto it = m_refKindStack.rbegin(); it != m_refKindStack.rend(); it++) + { + if ((*it) != REFERENCE_UNDEFINED) + { + return (*it); + } + } + return REFERENCE_TYPE_USAGE; +} + +void CxxAstVisitorComponentTypeRefKind::beginTraverseCXXBaseSpecifier() +{ + m_refKindStack.push_back(REFERENCE_INHERITANCE); +} + +void CxxAstVisitorComponentTypeRefKind::endTraverseCXXBaseSpecifier() +{ + m_refKindStack.pop_back(); +} + +void CxxAstVisitorComponentTypeRefKind::beginTraverseTemplateDefaultArgumentLoc() +{ + m_refKindStack.push_back(REFERENCE_TEMPLATE_DEFAULT_ARGUMENT); +} + +void CxxAstVisitorComponentTypeRefKind::endTraverseTemplateDefaultArgumentLoc() +{ + m_refKindStack.pop_back(); +} + +void CxxAstVisitorComponentTypeRefKind::beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc) +{ + if (getReferenceKind() != REFERENCE_TEMPLATE_DEFAULT_ARGUMENT) + { + m_refKindStack.push_back(REFERENCE_TEMPLATE_ARGUMENT); + } + else + { + m_refKindStack.push_back(REFERENCE_UNDEFINED); + } +} + +void CxxAstVisitorComponentTypeRefKind::endTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc) +{ + m_refKindStack.pop_back(); +} diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentTypeRefKind.h b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentTypeRefKind.h new file mode 100644 index 00000000..79299a6a --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentTypeRefKind.h @@ -0,0 +1,35 @@ +#ifndef CXX_AST_VISITOR_COMPONENT_TYPE_REF_KIND_H +#define CXX_AST_VISITOR_COMPONENT_TYPE_REF_KIND_H + +#include + +#include "data/parser/cxx/CxxAstVisitor.h" +#include "data/parser/cxx/CxxAstVisitorComponent.h" + +#include "data/parser/ReferenceKind.h" + +// This CxxAstVisitorComponent is responsible for recording and providing the context based ReferenceKind for each reference to a type encountered while traversing the AST. +// Example: class Foo: public Bar {}; +// For this snippet the type "Bar" is used in the context of an inheritence. +class CxxAstVisitorComponentTypeRefKind: public CxxAstVisitorComponent +{ +public: + CxxAstVisitorComponentTypeRefKind(CxxAstVisitor* astVisitor); + virtual ~CxxAstVisitorComponentTypeRefKind(); + + ReferenceKind getReferenceKind() const; + + virtual void beginTraverseCXXBaseSpecifier(); + virtual void endTraverseCXXBaseSpecifier(); + + virtual void beginTraverseTemplateDefaultArgumentLoc(); + virtual void endTraverseTemplateDefaultArgumentLoc(); + + virtual void beginTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc); + virtual void endTraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc); + +private: + std::vector m_refKindStack; +}; + +#endif // CXX_AST_VISITOR_COMPONENT_TYPE_REF_KIND_H diff --git a/src/lib_cxx/data/parser/cxx/utilityCxxAstVisitor.cpp b/src/lib_cxx/data/parser/cxx/utilityCxxAstVisitor.cpp new file mode 100644 index 00000000..2df9d3f8 --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/utilityCxxAstVisitor.cpp @@ -0,0 +1,73 @@ +#include "data/parser/cxx/utilityCxxAstVisitor.h" + +#include +#include + + +bool utility::isImplicit(const clang::Decl* d) +{ + if (!d) + { + return false; + } + + if (d->isImplicit()) + { + if (const clang::RecordDecl* rd = clang::dyn_cast_or_null(d)) + { + if (rd->isLambda()) + { + return isImplicit(clang::dyn_cast_or_null(d->getDeclContext())); + } + } + return true; + } + else if (const clang::ClassTemplateSpecializationDecl* ctsd = clang::dyn_cast_or_null(d)) + { + if (!ctsd->isExplicitSpecialization()) + { + return true; + } + } + else if (const clang::FunctionDecl* fd = clang::dyn_cast_or_null(d)) + { + if (fd->isTemplateInstantiation() && fd->getTemplateSpecializationKind() != clang::TSK_ExplicitSpecialization) // or undefined?? + { + return true; + } + } + + return isImplicit(clang::dyn_cast_or_null(d->getDeclContext())); +} + +AccessKind utility::convertAccessSpecifier(clang::AccessSpecifier access) +{ + switch (access) + { + case clang::AS_public: + return ACCESS_PUBLIC; + case clang::AS_protected: + return ACCESS_PROTECTED; + case clang::AS_private: + return ACCESS_PRIVATE; + case clang::AS_none: + return ACCESS_NONE; + } +} + +SymbolKind utility::convertTagKind(clang::TagTypeKind tagKind) +{ + switch (tagKind) + { + case clang::TTK_Struct: + return SYMBOL_STRUCT; + case clang::TTK_Union: + return SYMBOL_UNION; + case clang::TTK_Class: + return SYMBOL_CLASS; + case clang::TTK_Enum: + return SYMBOL_ENUM; + case clang::TTK_Interface: + return SYMBOL_KIND_MAX; + } +} diff --git a/src/lib_cxx/data/parser/cxx/utilityCxxAstVisitor.h b/src/lib_cxx/data/parser/cxx/utilityCxxAstVisitor.h new file mode 100644 index 00000000..bcdc9b68 --- /dev/null +++ b/src/lib_cxx/data/parser/cxx/utilityCxxAstVisitor.h @@ -0,0 +1,16 @@ +#ifndef UTILITY_CXX_AST_VISITOR_H +#define UTILITY_CXX_AST_VISITOR_H + +#include + +#include "data/parser/AccessKind.h" +#include "data/parser/SymbolKind.h" + +namespace utility +{ + bool isImplicit(const clang::Decl* d); + AccessKind convertAccessSpecifier(clang::AccessSpecifier access); + SymbolKind convertTagKind(clang::TagTypeKind tagKind); +} + +#endif // UTILITY_CXX_AST_VISITOR_H diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 7b442c36..1701168d 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -3211,7 +3211,7 @@ public: )); } - void test_cxx_parser_finds_template_argument_of_unresolved_lookup_expression_as_type_use() + void test_cxx_parser_finds_template_argument_of_unresolved_lookup_expression() { std::shared_ptr client = parseCode( "template \n" @@ -3227,7 +3227,7 @@ public: ); TS_ASSERT(utility::containsElement( - client->typeUses, "void dispatch() -> dispatch::MessageType <9:4 9:14>" + client->templateArgumentTypes, "void dispatch() -> dispatch::MessageType <9:4 9:14>" )); }