Author: sammccall Date: Thu Jan 18 01:27:56 2018 New Revision: 322824 URL: http://llvm.org/viewvc/llvm-project?rev=322824&view=rev Log: [clangd] CodeCompleteTests cleanup: naming, ordering, helpers. NFC
Modified: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp Modified: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp?rev=322824&r1=322823&r2=322824&view=diff ============================================================================== --- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp (original) +++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp Thu Jan 18 01:27:56 2018 @@ -97,8 +97,25 @@ Matcher<const std::vector<CompletionItem } MATCHER(IsDocumented, "") { return !arg.documentation.empty(); } +std::unique_ptr<SymbolIndex> memIndex(std::vector<Symbol> Symbols) { + SymbolSlab::Builder Slab; + for (const auto &Sym : Symbols) + Slab.insert(Sym); + return MemIndex::build(std::move(Slab).build()); +} + +// Builds a server and runs code completion. +// If IndexSymbols is non-empty, an index will be built and passed to opts. CompletionList completions(StringRef Text, + std::vector<Symbol> IndexSymbols = {}, clangd::CodeCompleteOptions Opts = {}) { + std::unique_ptr<SymbolIndex> OverrideIndex; + if (!IndexSymbols.empty()) { + assert(!Opts.Index && "both Index and IndexSymbols given!"); + OverrideIndex = memIndex(std::move(IndexSymbols)); + Opts.Index = OverrideIndex.get(); + } + MockFSProvider FS; MockCompilationDatabase CDB; IgnoreDiagnostics DiagConsumer; @@ -116,6 +133,27 @@ CompletionList completions(StringRef Tex return CompletionList; } +// Helpers to produce fake index symbols for memIndex() or completions(). +Symbol sym(StringRef QName, index::SymbolKind Kind) { + Symbol Sym; + Sym.ID = SymbolID(QName); + size_t Pos = QName.rfind("::"); + if (Pos == llvm::StringRef::npos) { + Sym.Name = QName; + Sym.Scope = ""; + } else { + Sym.Name = QName.substr(Pos + 2); + Sym.Scope = QName.substr(0, Pos); + } + Sym.CompletionPlainInsertText = Sym.Name; + Sym.CompletionLabel = Sym.Name; + Sym.SymInfo.Kind = Kind; + return Sym; +} +Symbol func(StringRef Name) { return sym(Name, index::SymbolKind::Function); } +Symbol cls(StringRef Name) { return sym(Name, index::SymbolKind::Class); } +Symbol var(StringRef Name) { return sym(Name, index::SymbolKind::Variable); } + TEST(CompletionTest, Limit) { clangd::CodeCompleteOptions Opts; Opts.Limit = 2; @@ -127,7 +165,7 @@ struct ClassWithMembers { } int main() { ClassWithMembers().^ } )cpp", - Opts); + /*IndexSymbols=*/{}, Opts); EXPECT_TRUE(Results.isIncomplete); EXPECT_THAT(Results.items, ElementsAre(Named("AAA"), Named("BBB"))); @@ -188,7 +226,7 @@ void TestAfterDotCompletion(clangd::Code ClassWithMembers().^ } )cpp", - Opts); + /*IndexSymbols=*/{}, Opts); // Class members. The only items that must be present in after-dot // completion. @@ -233,7 +271,7 @@ void TestGlobalScopeCompletion(clangd::C ^ } )cpp", - Opts); + /*IndexSymbols=*/{}, Opts); // Class members. Should never be present in global completions. EXPECT_THAT(Results.items, @@ -355,7 +393,7 @@ TEST(CompletionTest, Snippets) { f.^ } )cpp", - Opts); + /*IndexSymbols=*/{}, Opts); EXPECT_THAT(Results.items, HasSubsequence(Snippet("a"), Snippet("f(${1:int i}, ${2:const float f})"))); @@ -375,9 +413,6 @@ TEST(CompletionTest, Kinds) { EXPECT_THAT(Results.items, Has("Struct", CompletionItemKind::Class)); EXPECT_THAT(Results.items, Has("MACRO", CompletionItemKind::Text)); - clangd::CodeCompleteOptions Opts; - Opts.EnableSnippets = true; // Needed for code patterns. - Results = completions("nam^"); EXPECT_THAT(Results.items, Has("namespace", CompletionItemKind::Snippet)); } @@ -406,184 +441,67 @@ TEST(CompletionTest, FuzzyRanking) { EXPECT_THAT(Items, ElementsAre(Named("BigBang"), Named("Babble"))); } -SignatureHelp signatures(StringRef Text) { - MockFSProvider FS; - MockCompilationDatabase CDB; - IgnoreDiagnostics DiagConsumer; - ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(), - /*StorePreamblesInMemory=*/true); - auto File = getVirtualTestFilePath("foo.cpp"); - Annotations Test(Text); - Server.addDocument(Context::empty(), File, Test.code()); - auto R = Server.signatureHelp(Context::empty(), File, Test.point()); - assert(R); - return R.get().Value; -} - -MATCHER_P(ParamsAre, P, "") { - if (P.size() != arg.parameters.size()) - return false; - for (unsigned I = 0; I < P.size(); ++I) - if (P[I] != arg.parameters[I].label) - return false; - return true; -} - -Matcher<SignatureInformation> Sig(std::string Label, - std::vector<std::string> Params) { - return AllOf(Labeled(Label), ParamsAre(Params)); -} - -TEST(SignatureHelpTest, Overloads) { - auto Results = signatures(R"cpp( - void foo(int x, int y); - void foo(int x, float y); - void foo(float x, int y); - void foo(float x, float y); - void bar(int x, int y = 0); - int main() { foo(^); } - )cpp"); - EXPECT_THAT(Results.signatures, - UnorderedElementsAre( - Sig("foo(float x, float y) -> void", {"float x", "float y"}), - Sig("foo(float x, int y) -> void", {"float x", "int y"}), - Sig("foo(int x, float y) -> void", {"int x", "float y"}), - Sig("foo(int x, int y) -> void", {"int x", "int y"}))); - // We always prefer the first signature. - EXPECT_EQ(0, Results.activeSignature); - EXPECT_EQ(0, Results.activeParameter); -} - -TEST(SignatureHelpTest, DefaultArgs) { - auto Results = signatures(R"cpp( - void bar(int x, int y = 0); - void bar(float x = 0, int y = 42); - int main() { bar(^ - )cpp"); - EXPECT_THAT(Results.signatures, - UnorderedElementsAre( - Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}), - Sig("bar(float x = 0, int y = 42) -> void", - {"float x = 0", "int y = 42"}))); - EXPECT_EQ(0, Results.activeSignature); - EXPECT_EQ(0, Results.activeParameter); -} - -TEST(SignatureHelpTest, ActiveArg) { - auto Results = signatures(R"cpp( - int baz(int a, int b, int c); - int main() { baz(baz(1,2,3), ^); } - )cpp"); - EXPECT_THAT(Results.signatures, - ElementsAre(Sig("baz(int a, int b, int c) -> int", - {"int a", "int b", "int c"}))); - EXPECT_EQ(0, Results.activeSignature); - EXPECT_EQ(1, Results.activeParameter); -} - -std::unique_ptr<SymbolIndex> simpleIndexFromSymbols( - std::vector<std::pair<std::string, index::SymbolKind>> Symbols) { - SymbolSlab::Builder Slab; - for (const auto &Pair : Symbols) { - Symbol Sym; - Sym.ID = SymbolID(Pair.first); - llvm::StringRef QName = Pair.first; - size_t Pos = QName.rfind("::"); - if (Pos == llvm::StringRef::npos) { - Sym.Name = QName; - Sym.Scope = ""; - } else { - Sym.Name = QName.substr(Pos + 2); - Sym.Scope = QName.substr(0, Pos); - } - Sym.CompletionPlainInsertText = Sym.Name; - Sym.SymInfo.Kind = Pair.second; - Slab.insert(Sym); - } - return MemIndex::build(std::move(Slab).build()); -} - TEST(CompletionTest, NoIndex) { - clangd::CodeCompleteOptions Opts; - Opts.Index = nullptr; - auto Results = completions(R"cpp( namespace ns { class Local {}; } void f() { ns::^ } - )cpp", - Opts); + )cpp"); EXPECT_THAT(Results.items, Has("Local")); } TEST(CompletionTest, StaticAndDynamicIndex) { clangd::CodeCompleteOptions Opts; - auto StaticIdx = - simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}}); - auto DynamicIdx = - simpleIndexFromSymbols({{"ns::foo", index::SymbolKind::Function}}); + auto StaticIdx = memIndex({cls("ns::XYZ")}); + auto DynamicIdx = memIndex({func("ns::foo")}); auto Merge = mergeIndex(DynamicIdx.get(), StaticIdx.get()); Opts.Index = Merge.get(); - auto Results = completions(R"cpp( - void f() { ::ns::^ } - )cpp", - Opts); + auto Results = completions( + R"cpp( + void f() { ::ns::^ } + )cpp", + /*IndexSymbols=*/{}, Opts); EXPECT_THAT(Results.items, Contains(Labeled("[I]XYZ"))); EXPECT_THAT(Results.items, Contains(Labeled("[I]foo"))); } -TEST(CompletionTest, SimpleIndexBased) { - clangd::CodeCompleteOptions Opts; - auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}, - {"nx::XYZ", index::SymbolKind::Class}, - {"ns::foo", index::SymbolKind::Function}}); - Opts.Index = I.get(); - - auto Results = completions(R"cpp( - namespace ns { int local; } - void f() { ns::^ } - )cpp", - Opts); - EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class)); - EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function)); - EXPECT_THAT(Results.items, Has("local")); +TEST(CompletionTest, IndexScope) { + auto Results = completions( + R"cpp( + namespace ns { int local; } + void f() { ns::^ } + )cpp", + {cls("ns::XYZ"), cls("nx::XYZ"), func("ns::foo")}); + EXPECT_THAT(Results.items, + UnorderedElementsAre(Named("XYZ"), Named("foo"), Named("local"))); } TEST(CompletionTest, IndexBasedWithFilter) { - clangd::CodeCompleteOptions Opts; - auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}, - {"ns::foo", index::SymbolKind::Function}}); - Opts.Index = I.get(); - - auto Results = completions(R"cpp( - void f() { ns::x^ } - )cpp", - Opts); - EXPECT_THAT(Results.items, Contains(AllOf(Named("XYZ"), Filter("XYZ")))); - EXPECT_THAT(Results.items, Not(Has("foo"))); + auto Results = completions( + R"cpp( + void f() { ns::x^ } + )cpp", + {cls("ns::XYZ"), func("ns::foo")}); + EXPECT_THAT(Results.items, + UnorderedElementsAre(AllOf(Named("XYZ"), Filter("XYZ")))); } -TEST(CompletionTest, GlobalQualified) { - clangd::CodeCompleteOptions Opts; - auto I = simpleIndexFromSymbols({{"XYZ", index::SymbolKind::Class}}); - Opts.Index = I.get(); - - auto Results = completions(R"cpp( - void f() { ::^ } - )cpp", - Opts); - EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class)); +TEST(CompletionTest, IndexGlobalQualified) { + auto Results = completions( + R"cpp( + void f() { ::^ } + )cpp", + {cls("XYZ")}); + EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class), + Has("f", CompletionItemKind::Function))); } -TEST(CompletionTest, FullyQualifiedScope) { - clangd::CodeCompleteOptions Opts; - auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}}); - Opts.Index = I.get(); - - auto Results = completions(R"cpp( - void f() { ::ns::^ } - )cpp", - Opts); +TEST(CompletionTest, IndexFullyQualifiedScope) { + auto Results = completions( + R"cpp( + void f() { ::ns::^ } + )cpp", + {cls("ns::XYZ")}); EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class)); } @@ -612,7 +530,7 @@ TEST(CompletionTest, IndexSuppressesPrea EXPECT_THAT(WithoutIndex.items, UnorderedElementsAre(Named("local"), Named("preamble"))); - auto I = simpleIndexFromSymbols({{"ns::index", index::SymbolKind::Variable}}); + auto I = memIndex({var("ns::index")}); Opts.Index = I.get(); auto WithIndex = Server.codeComplete(Context::empty(), File, Test.point(), Opts) @@ -622,7 +540,7 @@ TEST(CompletionTest, IndexSuppressesPrea UnorderedElementsAre(Named("local"), Named("index"))); } -TEST(CompletionTest, ASTIndexMultiFile) { +TEST(CompletionTest, DynamicIndexMultiFile) { MockFSProvider FS; MockCompilationDatabase CDB; IgnoreDiagnostics DiagConsumer; @@ -660,6 +578,81 @@ TEST(CompletionTest, ASTIndexMultiFile) Doc("Doooc"), Detail("void")))); } +SignatureHelp signatures(StringRef Text) { + MockFSProvider FS; + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(), + /*StorePreamblesInMemory=*/true); + auto File = getVirtualTestFilePath("foo.cpp"); + Annotations Test(Text); + Server.addDocument(Context::empty(), File, Test.code()); + auto R = Server.signatureHelp(Context::empty(), File, Test.point()); + assert(R); + return R.get().Value; +} + +MATCHER_P(ParamsAre, P, "") { + if (P.size() != arg.parameters.size()) + return false; + for (unsigned I = 0; I < P.size(); ++I) + if (P[I] != arg.parameters[I].label) + return false; + return true; +} + +Matcher<SignatureInformation> Sig(std::string Label, + std::vector<std::string> Params) { + return AllOf(Labeled(Label), ParamsAre(Params)); +} + +TEST(SignatureHelpTest, Overloads) { + auto Results = signatures(R"cpp( + void foo(int x, int y); + void foo(int x, float y); + void foo(float x, int y); + void foo(float x, float y); + void bar(int x, int y = 0); + int main() { foo(^); } + )cpp"); + EXPECT_THAT(Results.signatures, + UnorderedElementsAre( + Sig("foo(float x, float y) -> void", {"float x", "float y"}), + Sig("foo(float x, int y) -> void", {"float x", "int y"}), + Sig("foo(int x, float y) -> void", {"int x", "float y"}), + Sig("foo(int x, int y) -> void", {"int x", "int y"}))); + // We always prefer the first signature. + EXPECT_EQ(0, Results.activeSignature); + EXPECT_EQ(0, Results.activeParameter); +} + +TEST(SignatureHelpTest, DefaultArgs) { + auto Results = signatures(R"cpp( + void bar(int x, int y = 0); + void bar(float x = 0, int y = 42); + int main() { bar(^ + )cpp"); + EXPECT_THAT(Results.signatures, + UnorderedElementsAre( + Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}), + Sig("bar(float x = 0, int y = 42) -> void", + {"float x = 0", "int y = 42"}))); + EXPECT_EQ(0, Results.activeSignature); + EXPECT_EQ(0, Results.activeParameter); +} + +TEST(SignatureHelpTest, ActiveArg) { + auto Results = signatures(R"cpp( + int baz(int a, int b, int c); + int main() { baz(baz(1,2,3), ^); } + )cpp"); + EXPECT_THAT(Results.signatures, + ElementsAre(Sig("baz(int a, int b, int c) -> int", + {"int a", "int b", "int c"}))); + EXPECT_EQ(0, Results.activeSignature); + EXPECT_EQ(1, Results.activeParameter); +} + } // namespace } // namespace clangd } // namespace clang _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits