diff --git a/src/libs/clangsupport/clangsupport_global.h b/src/libs/clangsupport/clangsupport_global.h index 57ce18e195c..7b63feb381a 100644 --- a/src/libs/clangsupport/clangsupport_global.h +++ b/src/libs/clangsupport/clangsupport_global.h @@ -201,15 +201,14 @@ struct HighlightingTypes { MixinHighlightingTypes mixinHighlightingTypes; }; -enum class SourceLocationKind : uchar -{ - None = 0, +enum class SourceLocationKind : uchar { + Definition = 1, Declaration, DeclarationReference, - Definition, MacroDefinition = 128, + MacroUndefinition, MacroUsage, - MacroUndefinition + None = 255, }; enum class SymbolKind : uchar diff --git a/src/libs/clangsupport/refactoringdatabaseinitializer.h b/src/libs/clangsupport/refactoringdatabaseinitializer.h index 6042264a5da..426485a1fd9 100644 --- a/src/libs/clangsupport/refactoringdatabaseinitializer.h +++ b/src/libs/clangsupport/refactoringdatabaseinitializer.h @@ -82,13 +82,15 @@ public: Sqlite::Table table; table.setUseIfNotExists(true); table.setName("locations"); - table.addColumn("symbolId", Sqlite::ColumnType::Integer); + const Sqlite::Column &symbolIdColumn = table.addColumn("symbolId", + Sqlite::ColumnType::Integer); const Sqlite::Column &lineColumn = table.addColumn("line", Sqlite::ColumnType::Integer); const Sqlite::Column &columnColumn = table.addColumn("column", Sqlite::ColumnType::Integer); const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer); const Sqlite::Column &locationKindColumn = table.addColumn("locationKind", Sqlite::ColumnType::Integer); table.addUniqueIndex({sourceIdColumn, lineColumn, columnColumn}); table.addIndex({sourceIdColumn, locationKindColumn}); + table.addIndex({symbolIdColumn}); table.initialize(database); } diff --git a/src/plugins/clangrefactoring/querysqlitestatementfactory.h b/src/plugins/clangrefactoring/querysqlitestatementfactory.h index 14fc27149d2..65d82895792 100644 --- a/src/plugins/clangrefactoring/querysqlitestatementfactory.h +++ b/src/plugins/clangrefactoring/querysqlitestatementfactory.h @@ -47,7 +47,20 @@ public: ReadStatement selectSourceUsagesForSymbolLocation{ "SELECT directoryPath || '/' || sourceName, line, column " "FROM locations NATURAL JOIN sources NATURAL JOIN directories " - "WHERE symbolId = (SELECT symbolId FROM locations WHERE sourceId=? AND line=? AND column=?)", + "WHERE symbolId = (SELECT symbolId FROM locations WHERE sourceId=? AND line=? AND " + "column=?)", + database}; + ReadStatement selectSourceUsagesOrderedForSymbolLocation{ + "SELECT directoryPath || '/' || sourceName, line, column " + "FROM locations NATURAL JOIN sources NATURAL JOIN directories " + "WHERE symbolId = (SELECT symbolId FROM locations WHERE sourceId=? AND line=? AND " + "column=?) ORDER BY locationKind LIMIT 2", + database}; + ReadStatement selectSourceUsagesByLocationKindForSymbolLocation{ + "SELECT directoryPath || '/' || sourceName, line, column " + "FROM locations NATURAL JOIN sources NATURAL JOIN directories " + "WHERE symbolId = (SELECT symbolId FROM locations WHERE sourceId=? AND line=? AND " + "column=?) AND locationKind = ?", database}; ReadStatement selectSymbolsForKindAndStartsWith{ "SELECT symbolId, symbolName, signature FROM symbols WHERE symbolKind = ? AND symbolName LIKE ?", diff --git a/src/plugins/clangrefactoring/refactoringengine.cpp b/src/plugins/clangrefactoring/refactoringengine.cpp index cc9121331dd..6b5546cc88c 100644 --- a/src/plugins/clangrefactoring/refactoringengine.cpp +++ b/src/plugins/clangrefactoring/refactoringengine.cpp @@ -68,7 +68,8 @@ void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &, CppTools::Usages RefactoringEngine::locationsAt(const CppTools::CursorInEditor &data) const { - CppTools::Usages usages; + if (data.cursor().isNull()) + return {}; QTextCursor cursor = Utils::Text::wordStartCursor(data.cursor()); Utils::OptionalLineColumn lineColumn = Utils::Text::convertPosition(cursor.document(), @@ -78,10 +79,30 @@ CppTools::Usages RefactoringEngine::locationsAt(const CppTools::CursorInEditor & const QByteArray filePath = data.filePath().toString().toUtf8(); const ClangBackEnd::FilePathId filePathId = m_filePathCache.filePathId(ClangBackEnd::FilePathView(filePath)); - usages = m_symbolQuery.sourceUsagesAt(filePathId, lineColumn->line, lineColumn->column); + return m_symbolQuery.sourceUsagesAt(filePathId, lineColumn->line, lineColumn->column); } - return usages; + return {}; +} + +CppTools::Usages RefactoringEngine::declarationAt(const CppTools::CursorInEditor &data) const +{ + if (data.cursor().isNull()) + return {}; + + QTextCursor cursor = Utils::Text::wordStartCursor(data.cursor()); + Utils::OptionalLineColumn lineColumn = Utils::Text::convertPosition(cursor.document(), + cursor.position()); + + if (lineColumn) { + const QByteArray filePath = data.filePath().toString().toUtf8(); + const ClangBackEnd::FilePathId filePathId = m_filePathCache.filePathId( + ClangBackEnd::FilePathView(filePath)); + + return m_symbolQuery.declarationsAt(filePathId, lineColumn->line, lineColumn->column); + } + + return {}; } void RefactoringEngine::globalRename(const CppTools::CursorInEditor &data, @@ -104,16 +125,13 @@ void RefactoringEngine::globalFollowSymbol(const CppTools::CursorInEditor &data, CppTools::SymbolFinder *, bool) const { - // TODO: replace that with specific followSymbol query - const CppTools::Usages usages = locationsAt(data); + const CppTools::Usages usages = declarationAt(data); CppTools::Usage usage = Utils::findOrDefault(usages, [&data](const CppTools::Usage &usage) { - // We've already searched in the current file, skip it. - if (usage.path == data.filePath().toString()) - return false; - return true; + return usage.path != data.filePath().toString(); + }); - processLinkCallback(Link(usage.path, usage.line, usage.column)); + processLinkCallback(Link(usage.path, usage.line, usage.column - 1)); } bool RefactoringEngine::isRefactoringEngineAvailable() const diff --git a/src/plugins/clangrefactoring/refactoringengine.h b/src/plugins/clangrefactoring/refactoringengine.h index 739b5453109..4dfef3ba0c2 100644 --- a/src/plugins/clangrefactoring/refactoringengine.h +++ b/src/plugins/clangrefactoring/refactoringengine.h @@ -74,6 +74,7 @@ public: private: CppTools::Usages locationsAt(const CppTools::CursorInEditor &data) const; + CppTools::Usages declarationAt(const CppTools::CursorInEditor &data) const; ClangBackEnd::RefactoringServerInterface &m_server; ClangBackEnd::RefactoringClientInterface &m_client; diff --git a/src/plugins/clangrefactoring/symbolquery.h b/src/plugins/clangrefactoring/symbolquery.h index b5a46ab7e60..2468369c828 100644 --- a/src/plugins/clangrefactoring/symbolquery.h +++ b/src/plugins/clangrefactoring/symbolquery.h @@ -75,6 +75,36 @@ public: utf8Column); } + CppTools::Usages sourceUsagesAtByLocationKind(ClangBackEnd::FilePathId filePathId, + int line, + int utf8Column, + ClangBackEnd::SourceLocationKind kind) const override + { + ReadStatement &locationsStatement = m_statementFactory.selectSourceUsagesByLocationKindForSymbolLocation; + + const std::size_t reserveSize = 128; + + return locationsStatement.template values(reserveSize, + filePathId.filePathId, + line, + utf8Column, + int(kind)); + } + + CppTools::Usages declarationsAt(ClangBackEnd::FilePathId filePathId, + int line, + int utf8Column) const override + { + ReadStatement &locationsStatement = m_statementFactory.selectSourceUsagesOrderedForSymbolLocation; + + const std::size_t reserveSize = 128; + + return locationsStatement.template values(reserveSize, + filePathId.filePathId, + line, + utf8Column); + } + Symbols symbolsWithOneSymbolKinds(ClangBackEnd::SymbolKind symbolKind, Utils::SmallStringView searchTerm) const { diff --git a/src/plugins/clangrefactoring/symbolqueryinterface.h b/src/plugins/clangrefactoring/symbolqueryinterface.h index 568d26568fe..6ea6c97304c 100644 --- a/src/plugins/clangrefactoring/symbolqueryinterface.h +++ b/src/plugins/clangrefactoring/symbolqueryinterface.h @@ -46,10 +46,17 @@ public: virtual CppTools::Usages sourceUsagesAt(ClangBackEnd::FilePathId filePathId, int line, int utf8Column) const = 0; + virtual CppTools::Usages sourceUsagesAtByLocationKind(ClangBackEnd::FilePathId filePathId, + int line, + int utf8Column, + ClangBackEnd::SourceLocationKind) const = 0; virtual Symbols symbols(const ClangBackEnd::SymbolKinds &symbolKinds, Utils::SmallStringView searchTerm) const = 0; virtual Utils::optional locationForSymbolId(SymbolId symbolId, ClangBackEnd::SourceLocationKind kind) const = 0; + virtual CppTools::Usages declarationsAt(ClangBackEnd::FilePathId filePathId, + int line, + int utf8Column) const = 0; protected: ~SymbolQueryInterface() = default; diff --git a/src/tools/clangrefactoringbackend/source/indexdataconsumer.cpp b/src/tools/clangrefactoringbackend/source/indexdataconsumer.cpp index 00ad465bcc2..9e8da8cdbff 100644 --- a/src/tools/clangrefactoringbackend/source/indexdataconsumer.cpp +++ b/src/tools/clangrefactoringbackend/source/indexdataconsumer.cpp @@ -52,12 +52,12 @@ Utils::SmallString symbolName(const clang::NamedDecl *declaration) SourceLocationKind sourceLocationKind(clang::index::SymbolRoleSet roles) { - if (hasSymbolRole(clang::index::SymbolRole::Reference, roles)) - return SourceLocationKind::DeclarationReference; + if (hasSymbolRole(clang::index::SymbolRole::Definition, roles)) + return SourceLocationKind::Definition; else if (hasSymbolRole(clang::index::SymbolRole::Declaration, roles)) return SourceLocationKind::Declaration; - else if (hasSymbolRole(clang::index::SymbolRole::Definition, roles)) - return SourceLocationKind::Definition; + else if (hasSymbolRole(clang::index::SymbolRole::Reference, roles)) + return SourceLocationKind::DeclarationReference; return SourceLocationKind::None; } diff --git a/tests/unit/unittest/data/symbolscollector/class.cpp b/tests/unit/unittest/data/symbolscollector/class.cpp new file mode 100644 index 00000000000..5f393c44cd0 --- /dev/null +++ b/tests/unit/unittest/data/symbolscollector/class.cpp @@ -0,0 +1,14 @@ +class Class +{ + Class(); + Class(int); + + void foo(); + + void bar() {} +}; + +void Class::foo() +{ + bar(); +} diff --git a/tests/unit/unittest/filepathcache-test.cpp b/tests/unit/unittest/filepathcache-test.cpp index 95557961161..4b43d3924c5 100644 --- a/tests/unit/unittest/filepathcache-test.cpp +++ b/tests/unit/unittest/filepathcache-test.cpp @@ -453,11 +453,11 @@ TEST_F(FilePathCache, GetFileIdInAfterPopulateIfEmpty) TEST_F(FilePathCache, DontPopulateIfNotEmpty) { cacheNotFilled.filePathId("/path/to/file.cpp"); + + EXPECT_CALL(mockStorageFilled, fetchAllDirectories()).Times(0); + EXPECT_CALL(mockStorageFilled, fetchAllSources()).Times(0); + cacheNotFilled.populateIfEmpty(); - - auto id = cacheNotFilled.filePathId("/path2/to/file.cpp"); - - ASSERT_FALSE(id.isValid()); } TEST_F(FilePathCache, GetDirectoryIdAfterPopulateIfEmpty) diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 141a926d9e4..385e7e8ab9a 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -37,6 +37,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -46,6 +49,8 @@ #include #include #include +#include +#include #include #include #include @@ -58,11 +63,7 @@ #include #include #include -#include -#include -#include -#include -#include +#include namespace { ClangBackEnd::FilePathCaching *filePathCache = nullptr; @@ -178,6 +179,12 @@ std::ostream &operator<<(std::ostream &out, const LineColumn &lineColumn) return out << "(" << lineColumn.line << ", " << lineColumn.column << ")"; } +std::ostream &operator<<(std::ostream &out, const Link &link) +{ + return out << "(" << link.targetFileName << ", " << link.targetLine << ", " << link.targetColumn + << ", " << link.linkTextStart << ", " << link.linkTextEnd << ")"; +} + const char * toText(Utils::Language language) { using Utils::Language; diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index 624288ee98d..948b2e911c7 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -81,11 +81,13 @@ std::ostream &operator<<(std::ostream &out, const HeaderPath &headerPath); namespace Utils { class LineColumn; class SmallStringView; +class Link; std::ostream &operator<<(std::ostream &out, const LineColumn &lineColumn); std::ostream &operator<<(std::ostream &out, const Utils::Language &language); std::ostream &operator<<(std::ostream &out, const Utils::LanguageVersion &languageVersion); std::ostream &operator<<(std::ostream &out, const Utils::LanguageExtension &languageExtension); +std::ostream &operator<<(std::ostream &out, const Link &link); template std::ostream &operator<<(std::ostream &out, const Utils::optional &optional) diff --git a/tests/unit/unittest/mocksqlitereadstatement.cpp b/tests/unit/unittest/mocksqlitereadstatement.cpp index 0a63f3c284e..1a27eea50f0 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.cpp +++ b/tests/unit/unittest/mocksqlitereadstatement.cpp @@ -46,6 +46,16 @@ MockSqliteReadStatement::values( return valuesReturnSourceUsages(reserveSize, sourceId, line, column); } +template<> +CppTools::Usages MockSqliteReadStatement::values(std::size_t reserveSize, + const int &sourceId, + const int &line, + const int &column, + const int &locationKind) +{ + return valuesReturnSourceUsages(reserveSize, sourceId, line, column, locationKind); +} + template <> Symbols MockSqliteReadStatement::values( diff --git a/tests/unit/unittest/mocksqlitereadstatement.h b/tests/unit/unittest/mocksqlitereadstatement.h index 0048fd62760..04e1f8effca 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.h +++ b/tests/unit/unittest/mocksqlitereadstatement.h @@ -78,8 +78,9 @@ public: MOCK_METHOD4(valuesReturnSourceLocations, SourceLocations(std::size_t, int, int, int)); - MOCK_METHOD4(valuesReturnSourceUsages, - CppTools::Usages(std::size_t, int, int, int)); + MOCK_METHOD4(valuesReturnSourceUsages, CppTools::Usages(std::size_t, int, int, int)); + + MOCK_METHOD5(valuesReturnSourceUsages, CppTools::Usages(std::size_t, int, int, int, int)); MOCK_METHOD1(valuesReturnStdVectorDirectory, std::vector(std::size_t)); @@ -191,6 +192,13 @@ MockSqliteReadStatement::values( const int &line, const int &column); +template<> +CppTools::Usages MockSqliteReadStatement::values(std::size_t reserveSize, + const int &sourceId, + const int &line, + const int &column, + const int &locationKind); + template <> Symbols MockSqliteReadStatement::values( diff --git a/tests/unit/unittest/mocksymbolquery.h b/tests/unit/unittest/mocksymbolquery.h index 0b3f4d59843..f8333ed7aa0 100644 --- a/tests/unit/unittest/mocksymbolquery.h +++ b/tests/unit/unittest/mocksymbolquery.h @@ -40,4 +40,11 @@ public: ClangRefactoring::Symbols(const ClangBackEnd::SymbolKinds &symbolKinds, Utils::SmallStringView searchTerm)); MOCK_CONST_METHOD2(locationForSymbolId, Utils::optional(ClangRefactoring::SymbolId symbolId, ClangBackEnd::SourceLocationKind kind)); + MOCK_CONST_METHOD4(sourceUsagesAtByLocationKind, + CppTools::Usages(ClangBackEnd::FilePathId filePathId, + int line, + int utf8Column, + ClangBackEnd::SourceLocationKind)); + MOCK_CONST_METHOD3(declarationsAt, + CppTools::Usages(ClangBackEnd::FilePathId filePathId, int line, int utf8Column)); }; diff --git a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp index 3af0fc8cfec..7af00158dfb 100644 --- a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp +++ b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp @@ -60,7 +60,9 @@ TEST_F(RefactoringDatabaseInitializer, AddLocationsTable) EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER, locationKind INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_locations_sourceId_line_column ON locations(sourceId, line, column)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId_locationKind ON locations(sourceId, locationKind)"))); - + EXPECT_CALL(mockDatabase, + execute(Eq( + "CREATE INDEX IF NOT EXISTS index_locations_symbolId ON locations(symbolId)"))); initializer.createLocationsTable(); } @@ -220,6 +222,9 @@ TEST_F(RefactoringDatabaseInitializer, CreateInTheContructor) EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId_locationKind ON " "locations(sourceId, locationKind)"))); + EXPECT_CALL(mockDatabase, + execute(Eq( + "CREATE INDEX IF NOT EXISTS index_locations_symbolId ON locations(symbolId)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, " "directoryId INTEGER, sourceName TEXT)"))); diff --git a/tests/unit/unittest/refactoringengine-test.cpp b/tests/unit/unittest/refactoringengine-test.cpp index 280a2409429..0648cca8e00 100644 --- a/tests/unit/unittest/refactoringengine-test.cpp +++ b/tests/unit/unittest/refactoringengine-test.cpp @@ -65,13 +65,15 @@ protected: commandLine = Utils::SmallStringVector( optionsBuilder.build(projectFile.kind, CppTools::UsePrecompiledHeaders::No)); commandLine.push_back(qStringFilePath); + ON_CALL(mockFilePathCaching, filePathId(Eq(clangBackEndFilePath))).WillByDefault(Return(12)); + cursor.setPosition(11); } protected: NiceMock mockFilePathCaching; MockRefactoringServer mockRefactoringServer; MockRefactoringClient mockRefactoringClient; - MockSymbolQuery mockSymbolQuery; + NiceMock mockSymbolQuery; ClangRefactoring::RefactoringEngine engine{mockRefactoringServer, mockRefactoringClient, mockFilePathCaching, @@ -85,27 +87,96 @@ protected: SmallStringVector commandLine; ProjectExplorer::Project project; CppTools::ProjectPart::Ptr projectPart; + CppTools::Usages usages{{"/path1", 1, 3}, {"/path2", 4, 5}}; CppTools::ProjectFile projectFile{qStringFilePath, CppTools::ProjectFile::CXXSource}; }; -TEST_F(RefactoringEngine, ExpectSourceUsagesAtInFindUsages) +TEST_F(RefactoringEngine, FindUsages) { - cursor.setPosition(11); + ON_CALL(mockSymbolQuery, sourceUsagesAt(Eq(12), 2, 5)).WillByDefault(Return(usages)); + NiceMock> mockCallback; - EXPECT_CALL(mockSymbolQuery, sourceUsagesAt(_, 2, 5)); + EXPECT_CALL(mockCallback, Call(usages)); - engine.findUsages(CppTools::CursorInEditor{cursor, filePath}, - [](const CppTools::Usages &) {}); + engine.findUsages(CppTools::CursorInEditor{cursor, filePath}, mockCallback.AsStdFunction()); } -TEST_F(RefactoringEngine, ExpectSourceUsagesAtInGlobalRename) +TEST_F(RefactoringEngine, CallFindUsages) { - cursor.setPosition(11); + EXPECT_CALL(mockSymbolQuery, sourceUsagesAt(Eq(12), 2, 5)); - EXPECT_CALL(mockSymbolQuery, sourceUsagesAt(_, 2, 5)); + engine.findUsages(CppTools::CursorInEditor{cursor, filePath}, [](const CppTools::Usages &) {}); +} + +TEST_F(RefactoringEngine, FindUsagesWithInvalidCursor) +{ + EXPECT_CALL(mockSymbolQuery, sourceUsagesAt(_, _, _)).Times(0); + + engine.findUsages(CppTools::CursorInEditor{{}, filePath}, [](const CppTools::Usages &) {}); +} + +TEST_F(RefactoringEngine, CallSourceUsagesInInGlobalRename) +{ + EXPECT_CALL(mockSymbolQuery, sourceUsagesAt(Eq(12), 2, 5)); engine.globalRename(CppTools::CursorInEditor{cursor, filePath}, - [](const CppTools::Usages &) {}, QString()); + [](const CppTools::Usages &) {}, + {}); +} + +TEST_F(RefactoringEngine, CallSourceUsagesInInGlobalRenameWithInvalidCursor) +{ + EXPECT_CALL(mockSymbolQuery, sourceUsagesAt(_, _, _)).Times(0); + + engine.globalRename(CppTools::CursorInEditor{{}, filePath}, [](const CppTools::Usages &) {}, {}); +} + +TEST_F(RefactoringEngine, CallDeclarationsAtInInGlobalFollowSymbol) +{ + + EXPECT_CALL(mockSymbolQuery, declarationsAt(Eq(12), 2, 5)); + + engine.globalFollowSymbol( + CppTools::CursorInEditor{cursor, filePath}, [](const Utils::Link &) {}, {}, {}, {}, {}); +} + +TEST_F(RefactoringEngine, CallDeclarationsAtInInGlobalFollowSymbolWithInvalidCursor) +{ + EXPECT_CALL(mockSymbolQuery, declarationsAt(_, _, _)).Times(0); + + engine.globalFollowSymbol( + CppTools::CursorInEditor{{}, filePath}, [](const Utils::Link &) {}, {}, {}, {}, {}); +} + +TEST_F(RefactoringEngine, InGlobalFollowSymbol) +{ + using Utils::Link; + NiceMock> mockCallback; + ON_CALL(mockSymbolQuery, declarationsAt(Eq(12), 2, 5)).WillByDefault(Return(usages)); + + EXPECT_CALL(mockCallback, + Call(AllOf(Field(&Link::targetFileName, Eq("/path1")), + Field(&Link::targetLine, Eq(1)), + Field(&Link::targetColumn, Eq(2))))); + + engine.globalFollowSymbol( + CppTools::CursorInEditor{cursor, filePath}, mockCallback.AsStdFunction(), {}, {}, {}, {}); +} + +TEST_F(RefactoringEngine, InGlobalFollowSymbolSkipCurrentFile) +{ + using Utils::Link; + NiceMock> mockCallback; + CppTools::Usages usages{{clangBackEndFilePath, 1, 3}, {"/path2", 4, 5}}; + ON_CALL(mockSymbolQuery, declarationsAt(Eq(12), 2, 5)).WillByDefault(Return(usages)); + + EXPECT_CALL(mockCallback, + Call(AllOf(Field(&Link::targetFileName, Eq("/path2")), + Field(&Link::targetLine, Eq(4)), + Field(&Link::targetColumn, Eq(4))))); + + engine.globalFollowSymbol( + CppTools::CursorInEditor{cursor, filePath}, mockCallback.AsStdFunction(), {}, {}, {}, {}); } TEST_F(RefactoringEngine, EngineIsNotUsableForUnusableServer) diff --git a/tests/unit/unittest/symbolquery-test.cpp b/tests/unit/unittest/symbolquery-test.cpp index a2aeb41d086..8a7fad42721 100644 --- a/tests/unit/unittest/symbolquery-test.cpp +++ b/tests/unit/unittest/symbolquery-test.cpp @@ -61,12 +61,11 @@ protected: MockSqliteReadStatement &selectSymbolsForKindAndStartsWith2 = mockStatementFactory.selectSymbolsForKindAndStartsWith2; MockSqliteReadStatement &selectSymbolsForKindAndStartsWith3 = mockStatementFactory.selectSymbolsForKindAndStartsWith3; MockSqliteReadStatement &selectLocationOfSymbol = mockStatementFactory.selectLocationOfSymbol; - SourceLocations locations{{1, 1, 1}, - {1, 2, 3}, - {2, 1, 1}, - {2, 3, 1}, - {4, 1, 1}, - {4, 1, 3}}; + MockSqliteReadStatement &selectSourceUsagesOrderedForSymbolLocation = mockStatementFactory + .selectSourceUsagesOrderedForSymbolLocation; + MockSqliteReadStatement &selectSourceUsagesByLocationKindForSymbolLocation + = mockStatementFactory.selectSourceUsagesByLocationKindForSymbolLocation; + SourceLocations locations{{1, 1, 1}, {1, 2, 3}, {2, 1, 1}, {2, 3, 1}, {4, 1, 1}, {4, 1, 3}}; MockQuery query{mockStatementFactory}; }; @@ -78,8 +77,9 @@ protected: database.execute("INSERT INTO sources VALUES (1, 1, \"filename.h\")"); database.execute("INSERT INTO sources VALUES (2, 1, \"filename.cpp\")"); database.execute("INSERT INTO directories VALUES (1, \"/path/to\")"); - database.execute("INSERT INTO locations VALUES (1, 2, 3, 1, 1)"); - database.execute("INSERT INTO locations VALUES (1, 4, 6, 2, 3)"); + database.execute("INSERT INTO locations VALUES (1, 2, 3, 1, 2)"); + database.execute("INSERT INTO locations VALUES (1, 4, 6, 2, 1)"); + database.execute("INSERT INTO locations VALUES (1, 20, 36, 2, 3)"); database.execute("INSERT INTO symbols VALUES (1, \"functionusr\", \"Function\", 3, \"void function(int)\")"); database.execute("INSERT INTO symbols VALUES (2, \"classusr\", \"Class\", 2, \"class Class final\")"); database.execute("INSERT INTO symbols VALUES (3, \"enumusr\", \"Enum\", 1, \"enum Enum : char\")"); @@ -105,7 +105,8 @@ TEST_F(SymbolQuerySlowTest, LocationsAt) ASSERT_THAT(locations, UnorderedElementsAre(SourceLocation(1, 2, 3), - SourceLocation(2, 4, 6))); + SourceLocation(2, 4, 6), + SourceLocation(2, 20, 36))); } TEST_F(SymbolQuery, SourceUsagesAtCallsValues) @@ -121,7 +122,8 @@ TEST_F(SymbolQuerySlowTest, SourceUsagesAt) ASSERT_THAT(usages, UnorderedElementsAre(CppTools::Usage("/path/to/filename.h", 2, 3), - CppTools::Usage("/path/to/filename.cpp", 4, 6))); + CppTools::Usage("/path/to/filename.cpp", 4, 6), + CppTools::Usage("/path/to/filename.cpp", 20, 36))); } TEST_F(SymbolQuery, SymbolsCallsValuesWithOneKindParameter) @@ -193,4 +195,39 @@ TEST_F(SymbolQuerySlowTest, LocationForSymbolId) ASSERT_THAT(location.value(), Eq(SourceLocation(2, {4, 6}))); } +TEST_F(SymbolQuery, SourceUsagesAtByLocationKindCallsValues) +{ + EXPECT_CALL(selectSourceUsagesByLocationKindForSymbolLocation, + valuesReturnSourceUsages( + _, 42, 14, 7, static_cast(ClangBackEnd::SourceLocationKind::Definition))); + + query.sourceUsagesAtByLocationKind(42, 14, 7, ClangBackEnd::SourceLocationKind::Definition); } + +TEST_F(SymbolQuerySlowTest, SourceUsagesAtByLocationKind) +{ + auto usages = query.sourceUsagesAtByLocationKind(2, + 4, + 6, + ClangBackEnd::SourceLocationKind::Definition); + + ASSERT_THAT(usages, ElementsAre(CppTools::Usage("/path/to/filename.cpp", 4, 6))); +} + +TEST_F(SymbolQuery, DeclarationsAtCallsValues) +{ + EXPECT_CALL(selectSourceUsagesOrderedForSymbolLocation, valuesReturnSourceUsages(_, 42, 14, 7)); + + query.declarationsAt(42, 14, 7); +} + +TEST_F(SymbolQuerySlowTest, DeclarationsAt) +{ + auto usages = query.declarationsAt(2, 4, 6); + + ASSERT_THAT(usages, + ElementsAre(CppTools::Usage("/path/to/filename.cpp", 4, 6), + CppTools::Usage("/path/to/filename.h", 2, 3))); +} + +} // namespace diff --git a/tests/unit/unittest/symbolscollector-test.cpp b/tests/unit/unittest/symbolscollector-test.cpp index 675a4af6d47..47190307375 100644 --- a/tests/unit/unittest/symbolscollector-test.cpp +++ b/tests/unit/unittest/symbolscollector-test.cpp @@ -648,4 +648,44 @@ TEST_F(SymbolsCollector, ClearInputFilesAfterCollectingSymbols) ASSERT_TRUE(collector.isClean()); } + +TEST_F(SymbolsCollector, ClassDeclarations) +{ + collector.setFile(filePathId(TESTDATA_DIR "/symbolscollector/class.cpp"), {"cc"}); + + collector.collectSymbols(); + + ASSERT_THAT( + collector.sourceLocations(), + AllOf(Contains(IsSourceLocationEntry(symbolId("Class"), + filePathId(TESTDATA_DIR "/symbolscollector/class.cpp"), + 1, + 7, + SourceLocationKind::Definition)), + Contains(IsSourceLocationEntry(symbolId("bar"), + filePathId(TESTDATA_DIR "/symbolscollector/class.cpp"), + 8, + 8, + SourceLocationKind::Definition)), + Contains(IsSourceLocationEntry(symbolId("foo"), + filePathId(TESTDATA_DIR "/symbolscollector/class.cpp"), + 11, + 13, + SourceLocationKind::Definition)), + Contains(IsSourceLocationEntry(symbolId("foo"), + filePathId(TESTDATA_DIR "/symbolscollector/class.cpp"), + 6, + 8, + SourceLocationKind::Declaration)), + Contains(IsSourceLocationEntry(symbolId("Class"), + filePathId(TESTDATA_DIR "/symbolscollector/class.cpp"), + 11, + 6, + SourceLocationKind::DeclarationReference)), + Contains(IsSourceLocationEntry(symbolId("bar"), + filePathId(TESTDATA_DIR "/symbolscollector/class.cpp"), + 13, + 5, + SourceLocationKind::DeclarationReference)))); +} } // namespace