[clangd] Add TemplateArgumentList into Symbol
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
This commit is contained in:
parent
a80a52283c
commit
79063de95c
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue