diff options
Diffstat (limited to 'clang-tools-extra/unittests/clangd')
4 files changed, 112 insertions, 13 deletions
diff --git a/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp b/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp index 284149a5e05..80e5f91430e 100644 --- a/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp +++ b/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp @@ -55,10 +55,16 @@ MATCHER_P(SigHelpLabeled, Label, "") { return arg.label == Label; } MATCHER_P(Kind, K, "") { return arg.Kind == K; } MATCHER_P(Doc, D, "") { return arg.Documentation == D; } MATCHER_P(ReturnType, D, "") { return arg.ReturnType == D; } +MATCHER_P(HasInclude, IncludeHeader, "") { + return !arg.Includes.empty() && arg.Includes[0].Header == IncludeHeader; +} MATCHER_P(InsertInclude, IncludeHeader, "") { - return arg.Header == IncludeHeader && bool(arg.HeaderInsertion); + return !arg.Includes.empty() && arg.Includes[0].Header == IncludeHeader && + bool(arg.Includes[0].Insertion); +} +MATCHER(InsertInclude, "") { + return !arg.Includes.empty() && bool(arg.Includes[0].Insertion); } -MATCHER(InsertInclude, "") { return bool(arg.HeaderInsertion); } MATCHER_P(SnippetSuffix, Text, "") { return arg.SnippetSuffix == Text; } MATCHER_P(Origin, OriginSet, "") { return arg.Origin == OriginSet; } @@ -568,7 +574,7 @@ TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) { auto BarURI = URI::createFile(BarHeader).toString(); Symbol Sym = cls("ns::X"); Sym.CanonicalDeclaration.FileURI = BarURI; - Sym.IncludeHeader = BarURI; + Sym.IncludeHeaders.emplace_back(BarURI, 1); // Shoten include path based on search dirctory and insert. auto Results = completions(Server, R"cpp( @@ -600,8 +606,8 @@ TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) { auto BarURI = URI::createFile(BarHeader).toString(); SymX.CanonicalDeclaration.FileURI = BarURI; SymY.CanonicalDeclaration.FileURI = BarURI; - SymX.IncludeHeader = "<bar>"; - SymY.IncludeHeader = "<bar>"; + SymX.IncludeHeaders.emplace_back("<bar>", 1); + SymY.IncludeHeaders.emplace_back("<bar>", 1); // Shoten include path based on search dirctory and insert. auto Results = completions(Server, R"cpp( @@ -1178,7 +1184,7 @@ TEST(CompletionTest, OverloadBundling) { // Differences in header-to-insert suppress bundling. std::string DeclFile = URI::createFile(testPath("foo")).toString(); NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile; - NoArgsGFunc.IncludeHeader = "<foo>"; + NoArgsGFunc.IncludeHeaders.emplace_back("<foo>", 1); EXPECT_THAT( completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions, UnorderedElementsAre(AllOf(Named("GFuncC"), InsertInclude("<foo>")), @@ -1345,7 +1351,9 @@ TEST(CompletionTest, Render) { C.RequiredQualifier = "Foo::"; C.Scope = "ns::Foo::"; C.Documentation = "This is x()."; - C.Header = "\"foo.h\""; + C.Includes.emplace_back(); + auto &Include = C.Includes.back(); + Include.Header = "\"foo.h\""; C.Kind = CompletionItemKind::Method; C.Score.Total = 1.0; C.Origin = SymbolOrigin::AST | SymbolOrigin::Static; @@ -1370,7 +1378,7 @@ TEST(CompletionTest, Render) { EXPECT_EQ(R.insertText, "Foo::x(${0:bool})"); EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); - C.HeaderInsertion.emplace(); + Include.Insertion.emplace(); R = C.render(Opts); EXPECT_EQ(R.label, "^Foo::x(bool) const"); EXPECT_THAT(R.additionalTextEdits, Not(IsEmpty())); @@ -1826,6 +1834,41 @@ TEST(CompletionTest, EnableSpeculativeIndexRequest) { ASSERT_EQ(Reqs3.size(), 2u); } +TEST(CompletionTest, InsertTheMostPopularHeader) { + std::string DeclFile = URI::createFile(testPath("foo")).toString(); + Symbol sym = func("Func"); + sym.CanonicalDeclaration.FileURI = DeclFile; + sym.IncludeHeaders.emplace_back("\"foo.h\"", 2); + sym.IncludeHeaders.emplace_back("\"bar.h\"", 1000); + + auto Results = completions("Fun^", {sym}).Completions; + assert(!Results.empty()); + EXPECT_THAT(Results[0], AllOf(Named("Func"), InsertInclude("\"bar.h\""))); + EXPECT_EQ(Results[0].Includes.size(), 2u); +} + +TEST(CompletionTest, NoInsertIncludeIfOnePresent) { + MockFSProvider FS; + MockCompilationDatabase CDB; + + std::string FooHeader = testPath("foo.h"); + FS.Files[FooHeader] = ""; + + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + + std::string DeclFile = URI::createFile(testPath("foo")).toString(); + Symbol sym = func("Func"); + sym.CanonicalDeclaration.FileURI = DeclFile; + sym.IncludeHeaders.emplace_back("\"foo.h\"", 2); + sym.IncludeHeaders.emplace_back("\"bar.h\"", 1000); + + EXPECT_THAT( + completions(Server, "#include \"foo.h\"\nFun^", {sym}).Completions, + UnorderedElementsAre( + AllOf(Named("Func"), HasInclude("\"foo.h\""), Not(InsertInclude())))); +} + } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/unittests/clangd/FileIndexTests.cpp b/clang-tools-extra/unittests/clangd/FileIndexTests.cpp index 727240d7498..d18f1809644 100644 --- a/clang-tools-extra/unittests/clangd/FileIndexTests.cpp +++ b/clang-tools-extra/unittests/clangd/FileIndexTests.cpp @@ -223,7 +223,7 @@ TEST(FileIndexTest, NoIncludeCollected) { Req.Query = ""; bool SeenSymbol = false; M.fuzzyFind(Req, [&](const Symbol &Sym) { - EXPECT_TRUE(Sym.IncludeHeader.empty()); + EXPECT_TRUE(Sym.IncludeHeaders.empty()); SeenSymbol = true; }); EXPECT_TRUE(SeenSymbol); diff --git a/clang-tools-extra/unittests/clangd/IndexTests.cpp b/clang-tools-extra/unittests/clangd/IndexTests.cpp index 1ac71034065..7fd39e60e7d 100644 --- a/clang-tools-extra/unittests/clangd/IndexTests.cpp +++ b/clang-tools-extra/unittests/clangd/IndexTests.cpp @@ -306,6 +306,46 @@ TEST(MergeIndexTest, FindOccurrences) { FileURI("unittest:///test2.cc")))); } +MATCHER_P2(IncludeHeaderWithRef, IncludeHeader, References, "") { + return (arg.IncludeHeader == IncludeHeader) && (arg.References == References); +} + +TEST(MergeTest, MergeIncludesOnDifferentDefinitions) { + Symbol L, R; + L.Name = "left"; + R.Name = "right"; + L.ID = R.ID = SymbolID("hello"); + L.IncludeHeaders.emplace_back("common", 1); + R.IncludeHeaders.emplace_back("common", 1); + R.IncludeHeaders.emplace_back("new", 1); + + // Both have no definition. + Symbol M = mergeSymbol(L, R); + EXPECT_THAT(M.IncludeHeaders, + UnorderedElementsAre(IncludeHeaderWithRef("common", 2u), + IncludeHeaderWithRef("new", 1u))); + + // Only merge references of the same includes but do not merge new #includes. + L.Definition.FileURI = "file:/left.h"; + M = mergeSymbol(L, R); + EXPECT_THAT(M.IncludeHeaders, + UnorderedElementsAre(IncludeHeaderWithRef("common", 2u))); + + // Definitions are the same. + R.Definition.FileURI = "file:/right.h"; + M = mergeSymbol(L, R); + EXPECT_THAT(M.IncludeHeaders, + UnorderedElementsAre(IncludeHeaderWithRef("common", 2u), + IncludeHeaderWithRef("new", 1u))); + + // Definitions are different. + R.Definition.FileURI = "file:/right.h"; + M = mergeSymbol(L, R); + EXPECT_THAT(M.IncludeHeaders, + UnorderedElementsAre(IncludeHeaderWithRef("common", 2u), + IncludeHeaderWithRef("new", 1u))); +} + } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp b/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp index 5769a266874..b9efa5ba407 100644 --- a/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp +++ b/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp @@ -54,7 +54,13 @@ MATCHER_P(Snippet, S, "") { MATCHER_P(QName, Name, "") { return (arg.Scope + arg.Name).str() == Name; } MATCHER_P(DeclURI, P, "") { return arg.CanonicalDeclaration.FileURI == P; } MATCHER_P(DefURI, P, "") { return arg.Definition.FileURI == P; } -MATCHER_P(IncludeHeader, P, "") { return arg.IncludeHeader == P; } +MATCHER_P(IncludeHeader, P, "") { + return (arg.IncludeHeaders.size() == 1) && + (arg.IncludeHeaders.begin()->IncludeHeader == P); +} +MATCHER_P2(IncludeHeaderWithRef, IncludeHeader, References, "") { + return (arg.IncludeHeader == IncludeHeader) && (arg.References == References); +} MATCHER_P(DeclRange, Pos, "") { return std::tie(arg.CanonicalDeclaration.Start.Line, arg.CanonicalDeclaration.Start.Column, @@ -760,6 +766,11 @@ CanonicalDeclaration: IsIndexedForCodeCompletion: true Documentation: 'Foo doc' ReturnType: 'int' +IncludeHeaders: + - Header: 'include1' + References: 7 + - Header: 'include2' + References: 3 ... )"; const std::string YAML2 = R"( @@ -791,6 +802,10 @@ CompletionSnippetSuffix: '-snippet' Doc("Foo doc"), ReturnType("int"), DeclURI("file:///path/foo.h"), ForCodeCompletion(true)))); + auto &Sym1 = *Symbols1.begin(); + EXPECT_THAT(Sym1.IncludeHeaders, + UnorderedElementsAre(IncludeHeaderWithRef("include1", 7u), + IncludeHeaderWithRef("include2", 3u))); auto Symbols2 = symbolsFromYAML(YAML2); EXPECT_THAT(Symbols2, UnorderedElementsAre(AllOf( QName("clang::Foo2"), Labeled("Foo2-sig"), @@ -812,9 +827,10 @@ CompletionSnippetSuffix: '-snippet' TEST_F(SymbolCollectorTest, IncludeHeaderSameAsFileURI) { CollectorOpts.CollectIncludePath = true; runSymbolCollector("class Foo {};", /*Main=*/""); - EXPECT_THAT(Symbols, - UnorderedElementsAre(AllOf(QName("Foo"), DeclURI(TestHeaderURI), - IncludeHeader(TestHeaderURI)))); + EXPECT_THAT(Symbols, UnorderedElementsAre( + AllOf(QName("Foo"), DeclURI(TestHeaderURI)))); + EXPECT_THAT(Symbols.begin()->IncludeHeaders, + UnorderedElementsAre(IncludeHeaderWithRef(TestHeaderURI, 1u))); } #ifndef _WIN32 |

