Skip to content

Commit

Permalink
[clangd] Add TemplateArgumentList into Symbol
Browse files Browse the repository at this point in the history
Summary:
Part of re-landing rC356541 with D59599. Changes the way we store
template arguments, previous patch was storing them inside Name field of Symbol.
Which was violating the assumption:
```Symbol::Scope+Symbol::Name == clang::clangd::printQualifiedName```
which was made in multiple places inside codebase. This patch instead moves
those arguments into their own field. Currently the field is meant to be
human-readable, can be made structured if need be.

Reviewers: ioeric, ilya-biryukov, gribozavr

Subscribers: MaskRay, jkorous, arphaman, jdoerfert, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D59640

llvm-svn: 358273
  • Loading branch information
kadircet committed Apr 12, 2019
1 parent a80a522 commit 79063de
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 1 deletion.
2 changes: 2 additions & 0 deletions clang-tools-extra/clangd/index/Serialization.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down
5 changes: 5 additions & 0 deletions clang-tools-extra/clangd/index/Symbol.h
Expand Up @@ -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).
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion clang-tools-extra/clangd/index/SymbolCollector.cpp
Expand Up @@ -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))
Expand Down
2 changes: 2 additions & 0 deletions clang-tools-extra/clangd/index/YAMLSerialization.cpp
Expand Up @@ -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);
Expand Down
68 changes: 68 additions & 0 deletions clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 79063de

Please sign in to comment.