summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang-tools-extra/clangd/index/Serialization.cpp2
-rw-r--r--clang-tools-extra/clangd/index/Symbol.h5
-rw-r--r--clang-tools-extra/clangd/index/SymbolCollector.cpp4
-rw-r--r--clang-tools-extra/clangd/index/YAMLSerialization.cpp2
-rw-r--r--clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp68
5 files changed, 80 insertions, 1 deletions
diff --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp
index c7c23c27eb5..e3f9c3b1e16 100644
--- a/clang-tools-extra/clangd/index/Serialization.cpp
+++ b/clang-tools-extra/clangd/index/Serialization.cpp
@@ -282,6 +282,7 @@ void writeSymbol(const Symbol &Sym, const StringTableOut &Strings,
OS.write(static_cast<uint8_t>(Sym.SymInfo.Lang));
writeVar(Strings.index(Sym.Name), OS);
writeVar(Strings.index(Sym.Scope), OS);
+ writeVar(Strings.index(Sym.TemplateSpecializationArgs), OS);
writeLocation(Sym.Definition, Strings, OS);
writeLocation(Sym.CanonicalDeclaration, Strings, OS);
writeVar(Sym.References, OS);
@@ -309,6 +310,7 @@ Symbol readSymbol(Reader &Data, llvm::ArrayRef<llvm::StringRef> Strings) {
Sym.SymInfo.Lang = static_cast<index::SymbolLanguage>(Data.consume8());
Sym.Name = Data.consumeString(Strings);
Sym.Scope = Data.consumeString(Strings);
+ Sym.TemplateSpecializationArgs = Data.consumeString(Strings);
Sym.Definition = readLocation(Data, Strings);
Sym.CanonicalDeclaration = readLocation(Data, Strings);
Sym.References = Data.consumeVar();
diff --git a/clang-tools-extra/clangd/index/Symbol.h b/clang-tools-extra/clangd/index/Symbol.h
index ae4f6bc668a..c79c0dc8dce 100644
--- a/clang-tools-extra/clangd/index/Symbol.h
+++ b/clang-tools-extra/clangd/index/Symbol.h
@@ -63,6 +63,10 @@ struct Symbol {
/// candidate list. For example, "(X x, Y y) const" is a function signature.
/// Only set when the symbol is indexed for completion.
llvm::StringRef Signature;
+ /// Argument list in human-readable format, will be displayed to help
+ /// disambiguate between different specializations of a template. Empty for
+ /// non-specializations. Example: "<int, bool, 3>"
+ llvm::StringRef TemplateSpecializationArgs;
/// What to insert when completing this symbol, after the symbol name.
/// This is in LSP snippet syntax (e.g. "({$0})" for a no-args function).
/// (When snippets are disabled, the symbol name alone is used).
@@ -143,6 +147,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Symbol::SymbolFlag);
template <typename Callback> void visitStrings(Symbol &S, const Callback &CB) {
CB(S.Name);
CB(S.Scope);
+ CB(S.TemplateSpecializationArgs);
CB(S.Signature);
CB(S.CompletionSnippetSuffix);
CB(S.Documentation);
diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp
index b4ef6bf134d..a37ccd22f99 100644
--- a/clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -524,9 +524,11 @@ const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND, SymbolID ID,
Symbol S;
S.ID = std::move(ID);
std::string QName = printQualifiedName(ND);
- std::tie(S.Scope, S.Name) = splitQualifiedName(QName);
// FIXME: this returns foo:bar: for objective-C methods, we prefer only foo:
// for consistency with CodeCompletionString and a clean name/signature split.
+ std::tie(S.Scope, S.Name) = splitQualifiedName(QName);
+ std::string TemplateSpecializationArgs = printTemplateSpecializationArgs(ND);
+ S.TemplateSpecializationArgs = TemplateSpecializationArgs;
// We collect main-file symbols, but do not use them for code completion.
if (!IsMainFileOnly && isIndexedForCodeCompletion(ND, Ctx))
diff --git a/clang-tools-extra/clangd/index/YAMLSerialization.cpp b/clang-tools-extra/clangd/index/YAMLSerialization.cpp
index 84d6cd99831..6bf0cb789ca 100644
--- a/clang-tools-extra/clangd/index/YAMLSerialization.cpp
+++ b/clang-tools-extra/clangd/index/YAMLSerialization.cpp
@@ -193,6 +193,8 @@ template <> struct MappingTraits<Symbol> {
IO.mapOptional("Origin", NSymbolOrigin->Origin);
IO.mapOptional("Flags", NSymbolFlag->Flag);
IO.mapOptional("Signature", Sym.Signature);
+ IO.mapOptional("TemplateSpecializationArgs",
+ Sym.TemplateSpecializationArgs);
IO.mapOptional("CompletionSnippetSuffix", Sym.CompletionSnippetSuffix);
IO.mapOptional("Documentation", Sym.Documentation);
IO.mapOptional("ReturnType", Sym.ReturnType);
diff --git a/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp b/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp
index ee6ebc724e4..5b9e55353ca 100644
--- a/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp
+++ b/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp
@@ -51,6 +51,9 @@ MATCHER_P(Snippet, S, "") {
return (arg.Name + arg.CompletionSnippetSuffix).str() == S;
}
MATCHER_P(QName, Name, "") { return (arg.Scope + arg.Name).str() == Name; }
+MATCHER_P(TemplateArgs, TemplArgs, "") {
+ return arg.TemplateSpecializationArgs == TemplArgs;
+}
MATCHER_P(DeclURI, P, "") {
return StringRef(arg.CanonicalDeclaration.FileURI) == P;
}
@@ -412,6 +415,71 @@ TEST_F(SymbolCollectorTest, Template) {
ForCodeCompletion(false))));
}
+TEST_F(SymbolCollectorTest, TemplateArgs) {
+ Annotations Header(R"(
+ template <class X> class $barclasstemp[[Bar]] {};
+ template <class T, class U, template<typename> class Z, int Q>
+ struct [[Tmpl]] { T $xdecl[[x]] = 0; };
+
+ // template-template, non-type and type full spec
+ template <> struct $specdecl[[Tmpl]]<int, bool, Bar, 3> {};
+
+ // template-template, non-type and type partial spec
+ template <class U, int T> struct $partspecdecl[[Tmpl]]<bool, U, Bar, T> {};
+ // instantiation
+ extern template struct Tmpl<float, bool, Bar, 8>;
+ // instantiation
+ template struct Tmpl<double, bool, Bar, 2>;
+
+ template <typename ...> class $fooclasstemp[[Foo]] {};
+ // parameter-packs full spec
+ template<> class $parampack[[Foo]]<Bar<int>, int, double> {};
+ // parameter-packs partial spec
+ template<class T> class $parampackpartial[[Foo]]<T, T> {};
+
+ template <int ...> class $bazclasstemp[[Baz]] {};
+ // non-type parameter-packs full spec
+ template<> class $parampacknontype[[Baz]]<3, 5, 8> {};
+ // non-type parameter-packs partial spec
+ template<int T> class $parampacknontypepartial[[Baz]]<T, T> {};
+
+ template <template <class> class ...> class $fozclasstemp[[Foz]] {};
+ // template-template parameter-packs full spec
+ template<> class $parampacktempltempl[[Foz]]<Bar, Bar> {};
+ // template-template parameter-packs partial spec
+ template<template <class> class T>
+ class $parampacktempltemplpartial[[Foz]]<T, T> {};
+ )");
+ runSymbolCollector(Header.code(), /*Main=*/"");
+ EXPECT_THAT(
+ Symbols,
+ AllOf(
+ Contains(AllOf(QName("Tmpl"), TemplateArgs("<int, bool, Bar, 3>"),
+ DeclRange(Header.range("specdecl")),
+ ForCodeCompletion(false))),
+ Contains(AllOf(QName("Tmpl"), TemplateArgs("<bool, U, Bar, T>"),
+ DeclRange(Header.range("partspecdecl")),
+ ForCodeCompletion(false))),
+ Contains(AllOf(QName("Foo"), TemplateArgs("<Bar<int>, int, double>"),
+ DeclRange(Header.range("parampack")),
+ ForCodeCompletion(false))),
+ Contains(AllOf(QName("Foo"), TemplateArgs("<T, T>"),
+ DeclRange(Header.range("parampackpartial")),
+ ForCodeCompletion(false))),
+ Contains(AllOf(QName("Baz"), TemplateArgs("<3, 5, 8>"),
+ DeclRange(Header.range("parampacknontype")),
+ ForCodeCompletion(false))),
+ Contains(AllOf(QName("Baz"), TemplateArgs("<T, T>"),
+ DeclRange(Header.range("parampacknontypepartial")),
+ ForCodeCompletion(false))),
+ Contains(AllOf(QName("Foz"), TemplateArgs("<Bar, Bar>"),
+ DeclRange(Header.range("parampacktempltempl")),
+ ForCodeCompletion(false))),
+ Contains(AllOf(QName("Foz"), TemplateArgs("<T, T>"),
+ DeclRange(Header.range("parampacktempltemplpartial")),
+ ForCodeCompletion(false)))));
+}
+
TEST_F(SymbolCollectorTest, ObjCSymbols) {
const std::string Header = R"(
@interface Person
OpenPOWER on IntegriCloud