summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/unittests/clangd
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/unittests/clangd')
-rw-r--r--clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp59
-rw-r--r--clang-tools-extra/unittests/clangd/FileIndexTests.cpp2
-rw-r--r--clang-tools-extra/unittests/clangd/IndexTests.cpp40
-rw-r--r--clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp24
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
OpenPOWER on IntegriCloud