Hi Ilya, This patch doesn't compile for me with clang 3.6.0. I get:
../tools/clang/tools/extra/clangd/Protocol.cpp:474:10: error: no viable conversion from 'json::Object' to 'llvm::json::Value' return Result; ^~~~~~ ../include/llvm/Support/JSON.h:291:3: note: candidate constructor not viable: no known conversion from 'json::Object' to 'const llvm::json::Value &' for 1st argument Value(const Value &M) { copyFrom(M); } ^ ../include/llvm/Support/JSON.h:292:3: note: candidate constructor not viable: no known conversion from 'json::Object' to 'llvm::json::Value &&' for 1st argument Value(Value &&M) { moveFrom(std::move(M)); } ^ ../include/llvm/Support/JSON.h:293:3: note: candidate constructor not viable: no known conversion from 'json::Object' to 'std::initializer_list<Value>' for 1st argument Value(std::initializer_list<Value> Elements); ^ ../include/llvm/Support/JSON.h:294:3: note: candidate constructor not viable: no known conversion from 'json::Object' to 'json::Array &&' for 1st argument Value(json::Array &&Elements) : Type(T_Array) { ^ ../include/llvm/Support/JSON.h:299:3: note: candidate constructor not viable: no known conversion from 'json::Object' to 'json::Object &&' for 1st argument Value(json::Object &&Properties) : Type(T_Object) { ^ ../include/llvm/Support/JSON.h:305:3: note: candidate constructor not viable: no known conversion from 'json::Object' to 'std::string' (aka 'basic_string<char>') for 1st argument Value(std::string V) : Type(T_String) { ^ ../include/llvm/Support/JSON.h:312:3: note: candidate constructor not viable: no known conversion from 'json::Object' to 'const llvm::SmallVectorImpl<char> &' for 1st argument Value(const llvm::SmallVectorImpl<char> &V) ^ ../include/llvm/Support/JSON.h:314:3: note: candidate constructor not viable: no known conversion from 'json::Object' to 'const llvm::formatv_object_base &' for 1st argument Value(const llvm::formatv_object_base &V) : Value(V.str()){}; ^ ../include/llvm/Support/JSON.h:316:3: note: candidate constructor not viable: no known conversion from 'json::Object' to 'llvm::StringRef' for 1st argument Value(StringRef V) : Type(T_StringRef) { ^ ../include/llvm/Support/JSON.h:323:3: note: candidate constructor not viable: no known conversion from 'json::Object' to 'const char *' for 1st argument Value(const char *V) : Value(StringRef(V)) {} ^ ../include/llvm/Support/JSON.h:324:3: note: candidate constructor not viable: no known conversion from 'json::Object' to 'std::nullptr_t' (aka 'nullptr_t') for 1st argument Value(std::nullptr_t) : Type(T_Null) {} ^ ../include/llvm/Support/JSON.h:298:3: note: candidate template ignored: could not match 'vector<type-parameter-0-0, allocator<type-parameter-0-0> >' against 'llvm::json::Object' Value(const std::vector<Elt> &C) : Value(json::Array(C)) {} ^ ../include/llvm/Support/JSON.h:303:3: note: candidate template ignored: could not match 'map<std::basic_string<char>, type-parameter-0-0, std::less<std::basic_string<char> >, allocator<pair<const std::basic_string<char>, type-parameter-0-0> > >' against 'llvm::json::Object' Value(const std::map<std::string, Elt> &C) : Value(json::Object(C)) {} ^ ../include/llvm/Support/JSON.h:329:42: note: candidate template ignored: disabled by 'enable_if' [with T = llvm::json::Object] typename = typename std::enable_if<std::is_same<T, bool>::value>::type, ^ ../include/llvm/Support/JSON.h:337:42: note: candidate template ignored: disabled by 'enable_if' [with T = llvm::json::Object] typename = typename std::enable_if<std::is_integral<T>::value>::type, ^ ../include/llvm/Support/JSON.h:345:41: note: candidate template ignored: disabled by 'enable_if' [with T = llvm::json::Object] typename std::enable_if<std::is_floating_point<T>::value>::type, ^ ../include/llvm/Support/JSON.h:355:3: note: candidate template ignored: substitution failure [with T = llvm::json::Object]: no matching function for call to 'toJSON' Value(const T &V) : Value(toJSON(V)) {} ^ 1 error generated. ninja: build stopped: subcommand failed. system(/proj/flexasic/app/ninja/1.8.2/SLED11-64/bin/ninja -j1 -C build-all all) failed: child exited with value 1 A couple of the build bots fail the same way, see e.g: http://lab.llvm.org:8011/builders/clang-cmake-armv7-quick/builds/5512/steps/build%20stage%201/logs/stdio ------------- This patch also causes a couple of new warnings: ../tools/clang/tools/extra/clangd/AST.cpp:98:13: error: unused variable 'NS' [-Werror,-Wunused-variable] if (auto *NS = llvm::dyn_cast<NamespaceDecl>(&ND)) ^ ../tools/clang/tools/extra/clangd/AST.cpp:102:13: error: unused variable 'En' [-Werror,-Wunused-variable] if (auto *En = llvm::dyn_cast<EnumDecl>(&ND)) ^ 2 errors generated. /Mikael On 11/23/18 4:21 PM, Ilya Biryukov via cfe-commits wrote: > Author: ibiryukov > Date: Fri Nov 23 07:21:19 2018 > New Revision: 347498 > > URL: http://llvm.org/viewvc/llvm-project?rev=347498&view=rev > Log: > [clangd] Add support for hierarchical documentSymbol > > Reviewers: ioeric, sammccall, simark > > Reviewed By: sammccall > > Subscribers: MaskRay, jkorous, arphaman, kadircet, cfe-commits > > Differential Revision: https://reviews.llvm.org/D52311 > > Modified: > clang-tools-extra/trunk/clangd/AST.cpp > clang-tools-extra/trunk/clangd/AST.h > clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp > clang-tools-extra/trunk/clangd/ClangdLSPServer.h > clang-tools-extra/trunk/clangd/ClangdServer.cpp > clang-tools-extra/trunk/clangd/ClangdServer.h > clang-tools-extra/trunk/clangd/FindSymbols.cpp > clang-tools-extra/trunk/clangd/FindSymbols.h > clang-tools-extra/trunk/clangd/Protocol.cpp > clang-tools-extra/trunk/clangd/Protocol.h > clang-tools-extra/trunk/clangd/clients/clangd-vscode/package.json > clang-tools-extra/trunk/unittests/clangd/FindSymbolsTests.cpp > clang-tools-extra/trunk/unittests/clangd/SyncAPI.cpp > clang-tools-extra/trunk/unittests/clangd/SyncAPI.h > > Modified: clang-tools-extra/trunk/clangd/AST.cpp > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/AST.cpp?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/AST.cpp (original) > +++ clang-tools-extra/trunk/clangd/AST.cpp Fri Nov 23 07:21:19 2018 > @@ -11,9 +11,12 @@ > > #include "clang/AST/ASTContext.h" > #include "clang/AST/Decl.h" > +#include "clang/AST/DeclTemplate.h" > #include "clang/Basic/SourceLocation.h" > #include "clang/Basic/SourceManager.h" > #include "clang/Index/USRGeneration.h" > +#include "llvm/Support/Casting.h" > +#include "llvm/Support/ScopedPrinter.h" > > using namespace llvm; > namespace clang { > @@ -61,6 +64,46 @@ std::string printQualifiedName(const Nam > return QName; > } > > +static const TemplateArgumentList * > +getTemplateSpecializationArgs(const NamedDecl &ND) { > + if (auto *Func = llvm::dyn_cast<FunctionDecl>(&ND)) > + return Func->getTemplateSpecializationArgs(); > + if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) > + return &Cls->getTemplateInstantiationArgs(); > + if (auto *Var = llvm::dyn_cast<VarTemplateSpecializationDecl>(&ND)) > + return &Var->getTemplateInstantiationArgs(); > + return nullptr; > +} > + > +std::string printName(const ASTContext &Ctx, const NamedDecl &ND) { > + std::string Name; > + llvm::raw_string_ostream Out(Name); > + PrintingPolicy PP(Ctx.getLangOpts()); > + // Handle 'using namespace'. They all have the same name - > <using-directive>. > + if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) { > + Out << "using namespace "; > + if (auto *Qual = UD->getQualifier()) > + Qual->print(Out, PP); > + UD->getNominatedNamespaceAsWritten()->printName(Out); > + return Out.str(); > + } > + ND.getDeclName().print(Out, PP); > + if (!Out.str().empty()) { > + // FIXME(ibiryukov): do not show args not explicitly written by the user. > + if (auto *ArgList = getTemplateSpecializationArgs(ND)) > + printTemplateArgumentList(Out, ArgList->asArray(), PP); > + return Out.str(); > + } > + // The name was empty, so present an anonymous entity. > + if (auto *NS = llvm::dyn_cast<NamespaceDecl>(&ND)) > + return "(anonymous namespace)"; > + if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND)) > + return ("(anonymous " + Cls->getKindName() + ")").str(); > + if (auto *En = llvm::dyn_cast<EnumDecl>(&ND)) > + return "(anonymous enum)"; > + return "(anonymous)"; > +} > + > std::string printNamespaceScope(const DeclContext &DC) { > for (const auto *Ctx = &DC; Ctx != nullptr; Ctx = Ctx->getParent()) > if (const auto *NS = dyn_cast<NamespaceDecl>(Ctx)) > > Modified: clang-tools-extra/trunk/clangd/AST.h > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/AST.h?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/AST.h (original) > +++ clang-tools-extra/trunk/clangd/AST.h Fri Nov 23 07:21:19 2018 > @@ -42,6 +42,11 @@ std::string printQualifiedName(const Nam > /// Returns the first enclosing namespace scope starting from \p DC. > std::string printNamespaceScope(const DeclContext &DC); > > +/// Prints unqualified name of the decl for the purpose of displaying it to > the > +/// user. Anonymous decls return names of the form "(anonymous {kind})", e.g. > +/// "(anonymous struct)" or "(anonymous namespace)". > +std::string printName(const ASTContext &Ctx, const NamedDecl &ND); > + > /// Gets the symbol ID for a declaration, if possible. > llvm::Optional<SymbolID> getSymbolID(const Decl *D); > > > Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp (original) > +++ clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp Fri Nov 23 07:21:19 > 2018 > @@ -23,6 +23,14 @@ namespace clang { > namespace clangd { > namespace { > > +void adjustSymbolKinds(llvm::MutableArrayRef<DocumentSymbol> Syms, > + SymbolKindBitset Kinds) { > + for (auto &S : Syms) { > + S.kind = adjustKindToCapability(S.kind, Kinds); > + adjustSymbolKinds(S.children, Kinds); > + } > +} > + > SymbolKindBitset defaultSymbolKinds() { > SymbolKindBitset Defaults; > for (size_t I = SymbolKindMin; I <= > static_cast<size_t>(SymbolKind::Array); > @@ -284,6 +292,8 @@ void ClangdLSPServer::onInitialize(const > if (Params.capabilities.CompletionItemKinds) > SupportedCompletionItemKinds |= > *Params.capabilities.CompletionItemKinds; > SupportsCodeAction = Params.capabilities.CodeActionStructure; > + SupportsHierarchicalDocumentSymbol = > + Params.capabilities.HierarchicalDocumentSymbol; > > Reply(json::Object{ > {{"capabilities", > @@ -501,19 +511,48 @@ void ClangdLSPServer::onDocumentFormatti > Reply(ReplacementsOrError.takeError()); > } > > -void ClangdLSPServer::onDocumentSymbol( > - const DocumentSymbolParams &Params, > - Callback<std::vector<SymbolInformation>> Reply) { > +/// The functions constructs a flattened view of the DocumentSymbol > hierarchy. > +/// Used by the clients that do not support the hierarchical view. > +static std::vector<SymbolInformation> > +flattenSymbolHierarchy(llvm::ArrayRef<DocumentSymbol> Symbols, > + const URIForFile &FileURI) { > + > + std::vector<SymbolInformation> Results; > + std::function<void(const DocumentSymbol &, StringRef)> Process = > + [&](const DocumentSymbol &S, Optional<StringRef> ParentName) { > + SymbolInformation SI; > + SI.containerName = ParentName ? "" : *ParentName; > + SI.name = S.name; > + SI.kind = S.kind; > + SI.location.range = S.range; > + SI.location.uri = FileURI; > + > + Results.push_back(std::move(SI)); > + std::string FullName = > + !ParentName ? S.name : (ParentName->str() + "::" + S.name); > + for (auto &C : S.children) > + Process(C, /*ParentName=*/FullName); > + }; > + for (auto &S : Symbols) > + Process(S, /*ParentName=*/""); > + return Results; > +} > + > +void ClangdLSPServer::onDocumentSymbol(const DocumentSymbolParams &Params, > + Callback<json::Value> Reply) { > + URIForFile FileURI = Params.textDocument.uri; > Server->documentSymbols( > Params.textDocument.uri.file(), > Bind( > - [this](decltype(Reply) Reply, > - Expected<std::vector<SymbolInformation>> Items) { > + [this, FileURI](decltype(Reply) Reply, > + Expected<std::vector<DocumentSymbol>> Items) { > if (!Items) > return Reply(Items.takeError()); > - for (auto &Sym : *Items) > - Sym.kind = adjustKindToCapability(Sym.kind, > SupportedSymbolKinds); > - Reply(std::move(*Items)); > + adjustSymbolKinds(*Items, SupportedSymbolKinds); > + if (SupportsHierarchicalDocumentSymbol) > + return Reply(std::move(*Items)); > + else > + return Reply(flattenSymbolHierarchy(*Items, FileURI)); > }, > std::move(Reply))); > } > > Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.h > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.h?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/ClangdLSPServer.h (original) > +++ clang-tools-extra/trunk/clangd/ClangdLSPServer.h Fri Nov 23 07:21:19 2018 > @@ -66,8 +66,11 @@ private: > Callback<std::vector<TextEdit>>); > void onDocumentFormatting(const DocumentFormattingParams &, > Callback<std::vector<TextEdit>>); > + // The results are serialized 'vector<DocumentSymbol>' if > + // SupportsHierarchicalDocumentSymbol is true and > 'vector<SymbolInformation>' > + // otherwise. > void onDocumentSymbol(const DocumentSymbolParams &, > - Callback<std::vector<SymbolInformation>>); > + Callback<llvm::json::Value>); > void onCodeAction(const CodeActionParams &, Callback<llvm::json::Value>); > void onCompletion(const TextDocumentPositionParams &, > Callback<CompletionList>); > @@ -128,6 +131,8 @@ private: > CompletionItemKindBitset SupportedCompletionItemKinds; > // Whether the client supports CodeAction response objects. > bool SupportsCodeAction = false; > + /// From capabilities of textDocument/documentSymbol. > + bool SupportsHierarchicalDocumentSymbol = false; > > // Store of the current versions of the open documents. > DraftStore DraftMgr; > > Modified: clang-tools-extra/trunk/clangd/ClangdServer.cpp > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.cpp?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/ClangdServer.cpp (original) > +++ clang-tools-extra/trunk/clangd/ClangdServer.cpp Fri Nov 23 07:21:19 2018 > @@ -470,10 +470,10 @@ void ClangdServer::workspaceSymbols( > std::move(CB))); > } > > -void ClangdServer::documentSymbols( > - StringRef File, Callback<std::vector<SymbolInformation>> CB) { > - auto Action = [](Callback<std::vector<SymbolInformation>> CB, > - Expected<InputsAndAST> InpAST) { > +void ClangdServer::documentSymbols(StringRef File, > + Callback<std::vector<DocumentSymbol>> CB) > { > + auto Action = [](Callback<std::vector<DocumentSymbol>> CB, > + llvm::Expected<InputsAndAST> InpAST) { > if (!InpAST) > return CB(InpAST.takeError()); > CB(clangd::getDocumentSymbols(InpAST->AST)); > > Modified: clang-tools-extra/trunk/clangd/ClangdServer.h > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.h?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/ClangdServer.h (original) > +++ clang-tools-extra/trunk/clangd/ClangdServer.h Fri Nov 23 07:21:19 2018 > @@ -167,7 +167,7 @@ public: > > /// Retrieve the symbols within the specified file. > void documentSymbols(StringRef File, > - Callback<std::vector<SymbolInformation>> CB); > + Callback<std::vector<DocumentSymbol>> CB); > > /// Retrieve locations for symbol references. > void findReferences(PathRef File, Position Pos, > > Modified: clang-tools-extra/trunk/clangd/FindSymbols.cpp > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/FindSymbols.cpp?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/FindSymbols.cpp (original) > +++ clang-tools-extra/trunk/clangd/FindSymbols.cpp Fri Nov 23 07:21:19 2018 > @@ -15,11 +15,13 @@ > #include "Quality.h" > #include "SourceCode.h" > #include "index/Index.h" > +#include "clang/AST/DeclTemplate.h" > #include "clang/Index/IndexDataConsumer.h" > #include "clang/Index/IndexSymbol.h" > #include "clang/Index/IndexingAction.h" > #include "llvm/Support/FormatVariadic.h" > #include "llvm/Support/Path.h" > +#include "llvm/Support/ScopedPrinter.h" > > #define DEBUG_TYPE "FindSymbols" > > @@ -178,104 +180,146 @@ getWorkspaceSymbols(StringRef Query, int > } > > namespace { > -/// Finds document symbols in the main file of the AST. > -class DocumentSymbolsConsumer : public index::IndexDataConsumer { > - ASTContext &AST; > - std::vector<SymbolInformation> Symbols; > - // We are always list document for the same file, so cache the value. > - Optional<URIForFile> MainFileUri; > +llvm::Optional<DocumentSymbol> declToSym(ASTContext &Ctx, const NamedDecl > &ND) { > + auto &SM = Ctx.getSourceManager(); > > + SourceLocation NameLoc = findNameLoc(&ND); > + // getFileLoc is a good choice for us, but we also need to make sure > + // sourceLocToPosition won't switch files, so we call getSpellingLoc on > top of > + // that to make sure it does not switch files. > + // FIXME: sourceLocToPosition should not switch files! > + SourceLocation BeginLoc = > SM.getSpellingLoc(SM.getFileLoc(ND.getBeginLoc())); > + SourceLocation EndLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getEndLoc())); > + if (NameLoc.isInvalid() || BeginLoc.isInvalid() || EndLoc.isInvalid()) > + return llvm::None; > + > + if (!SM.isWrittenInMainFile(NameLoc) || !SM.isWrittenInMainFile(BeginLoc) > || > + !SM.isWrittenInMainFile(EndLoc)) > + return llvm::None; > + > + Position NameBegin = sourceLocToPosition(SM, NameLoc); > + Position NameEnd = sourceLocToPosition( > + SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts())); > + > + index::SymbolInfo SymInfo = index::getSymbolInfo(&ND); > + // FIXME: this is not classifying constructors, destructors and operators > + // correctly (they're all "methods"). > + SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind); > + > + DocumentSymbol SI; > + SI.name = printName(Ctx, ND); > + SI.kind = SK; > + SI.deprecated = ND.isDeprecated(); > + SI.range = > + Range{sourceLocToPosition(SM, BeginLoc), sourceLocToPosition(SM, > EndLoc)}; > + SI.selectionRange = Range{NameBegin, NameEnd}; > + if (!SI.range.contains(SI.selectionRange)) { > + // 'selectionRange' must be contained in 'range', so in cases where clang > + // reports unrelated ranges we need to reconcile somehow. > + SI.range = SI.selectionRange; > + } > + return SI; > +} > + > +/// A helper class to build an outline for the parse AST. It traverse the AST > +/// directly instead of using RecursiveASTVisitor (RAV) for three main > reasons: > +/// - there is no way to keep RAV from traversing subtrees we're not > +/// interested in. E.g. not traversing function locals or implicit > template > +/// instantiations. > +/// - it's easier to combine results of recursive passes, e.g. > +/// - visiting decls is actually simple, so we don't hit the complicated > +/// cases that RAV mostly helps with (types and expressions, etc.) > +class DocumentOutline { > public: > - DocumentSymbolsConsumer(ASTContext &AST) : AST(AST) {} > - std::vector<SymbolInformation> takeSymbols() { return std::move(Symbols); } > + DocumentOutline(ParsedAST &AST) : AST(AST) {} > + > + /// Builds the document outline for the generated AST. > + std::vector<DocumentSymbol> build() { > + std::vector<DocumentSymbol> Results; > + for (auto &TopLevel : AST.getLocalTopLevelDecls()) > + traverseDecl(TopLevel, Results); > + return Results; > + } > > - void initialize(ASTContext &Ctx) override { > - // Compute the absolute path of the main file which we will use for all > - // results. > - const SourceManager &SM = AST.getSourceManager(); > - const FileEntry *F = SM.getFileEntryForID(SM.getMainFileID()); > - if (!F) > +private: > + enum class VisitKind { No, OnlyDecl, DeclAndChildren }; > + > + void traverseDecl(Decl *D, std::vector<DocumentSymbol> &Results) { > + if (auto *Templ = llvm::dyn_cast<TemplateDecl>(D)) > + D = Templ->getTemplatedDecl(); > + auto *ND = llvm::dyn_cast<NamedDecl>(D); > + if (!ND) > + return; > + VisitKind Visit = shouldVisit(ND); > + if (Visit == VisitKind::No) > return; > - auto FilePath = getRealPath(F, SM); > - if (FilePath) > - MainFileUri = URIForFile(*FilePath); > + llvm::Optional<DocumentSymbol> Sym = declToSym(AST.getASTContext(), *ND); > + if (!Sym) > + return; > + if (Visit == VisitKind::DeclAndChildren) > + traverseChildren(D, Sym->children); > + Results.push_back(std::move(*Sym)); > } > > - bool shouldIncludeSymbol(const NamedDecl *ND) { > - if (!ND || ND->isImplicit()) > - return false; > - // Skip anonymous declarations, e.g (anonymous enum/class/struct). > - if (ND->getDeclName().isEmpty()) > - return false; > - return true; > + void traverseChildren(Decl *D, std::vector<DocumentSymbol> &Results) { > + auto *Scope = llvm::dyn_cast<DeclContext>(D); > + if (!Scope) > + return; > + for (auto *C : Scope->decls()) > + traverseDecl(C, Results); > } > > - bool > - handleDeclOccurence(const Decl *, index::SymbolRoleSet Roles, > - ArrayRef<index::SymbolRelation> Relations, > - SourceLocation Loc, > - index::IndexDataConsumer::ASTNodeInfo ASTNode) > override { > - assert(ASTNode.OrigD); > - // No point in continuing the index consumer if we could not get the > - // absolute path of the main file. > - if (!MainFileUri) > - return false; > - // We only want declarations and definitions, i.e. no references. > - if (!(Roles & static_cast<unsigned>(index::SymbolRole::Declaration) || > - Roles & static_cast<unsigned>(index::SymbolRole::Definition))) > - return true; > - SourceLocation NameLoc = findNameLoc(ASTNode.OrigD); > - const SourceManager &SourceMgr = AST.getSourceManager(); > - // We should be only be looking at "local" decls in the main file. > - if (!SourceMgr.isWrittenInMainFile(NameLoc)) { > - // Even thought we are visiting only local (non-preamble) decls, > - // we can get here when in the presence of "extern" decls. > - return true; > + VisitKind shouldVisit(NamedDecl *D) { > + if (D->isImplicit()) > + return VisitKind::No; > + > + if (auto Func = llvm::dyn_cast<FunctionDecl>(D)) { > + // Some functions are implicit template instantiations, those should be > + // ignored. > + if (auto *Info = Func->getTemplateSpecializationInfo()) { > + if (!Info->isExplicitInstantiationOrSpecialization()) > + return VisitKind::No; > + } > + // Only visit the function itself, do not visit the children (i.e. > + // function parameters, etc.) > + return VisitKind::OnlyDecl; > } > - const NamedDecl *ND = dyn_cast<NamedDecl>(ASTNode.OrigD); > - if (!shouldIncludeSymbol(ND)) > - return true; > - > - SourceLocation EndLoc = > - Lexer::getLocForEndOfToken(NameLoc, 0, SourceMgr, AST.getLangOpts()); > - Position Begin = sourceLocToPosition(SourceMgr, NameLoc); > - Position End = sourceLocToPosition(SourceMgr, EndLoc); > - Range R = {Begin, End}; > - Location L; > - L.uri = *MainFileUri; > - L.range = R; > - > - std::string QName = printQualifiedName(*ND); > - StringRef Scope, Name; > - std::tie(Scope, Name) = splitQualifiedName(QName); > - Scope.consume_back("::"); > - > - index::SymbolInfo SymInfo = index::getSymbolInfo(ND); > - SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind); > - > - SymbolInformation SI; > - SI.name = Name; > - SI.kind = SK; > - SI.location = L; > - SI.containerName = Scope; > - Symbols.push_back(std::move(SI)); > - return true; > + // Handle template instantiations. We have three cases to consider: > + // - explicit instantiations, e.g. 'template class std::vector<int>;' > + // Visit the decl itself (it's present in the code), but not the > + // children. > + // - implicit instantiations, i.e. not written by the user. > + // Do not visit at all, they are not present in the code. > + // - explicit specialization, e.g. 'template <> class vector<bool> {};' > + // Visit both the decl and its children, both are written in the > code. > + if (auto *TemplSpec = > llvm::dyn_cast<ClassTemplateSpecializationDecl>(D)) { > + if (TemplSpec->isExplicitInstantiationOrSpecialization()) > + return TemplSpec->isExplicitSpecialization() > + ? VisitKind::DeclAndChildren > + : VisitKind::OnlyDecl; > + return VisitKind::No; > + } > + if (auto *TemplSpec = llvm::dyn_cast<VarTemplateSpecializationDecl>(D)) { > + if (TemplSpec->isExplicitInstantiationOrSpecialization()) > + return TemplSpec->isExplicitSpecialization() > + ? VisitKind::DeclAndChildren > + : VisitKind::OnlyDecl; > + return VisitKind::No; > + } > + // For all other cases, visit both the children and the decl. > + return VisitKind::DeclAndChildren; > } > -}; > -} // namespace > > -Expected<std::vector<SymbolInformation>> getDocumentSymbols(ParsedAST &AST) { > - DocumentSymbolsConsumer DocumentSymbolsCons(AST.getASTContext()); > + ParsedAST &AST; > +}; > > - index::IndexingOptions IndexOpts; > - IndexOpts.SystemSymbolFilter = > - index::IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly; > - IndexOpts.IndexFunctionLocals = false; > - indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(), > - AST.getLocalTopLevelDecls(), DocumentSymbolsCons, > - IndexOpts); > +std::vector<DocumentSymbol> collectDocSymbols(ParsedAST &AST) { > + return DocumentOutline(AST).build(); > +} > +} // namespace > > - return DocumentSymbolsCons.takeSymbols(); > +llvm::Expected<std::vector<DocumentSymbol>> getDocumentSymbols(ParsedAST > &AST) { > + return collectDocSymbols(AST); > } > > } // namespace clangd > > Modified: clang-tools-extra/trunk/clangd/FindSymbols.h > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/FindSymbols.h?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/FindSymbols.h (original) > +++ clang-tools-extra/trunk/clangd/FindSymbols.h Fri Nov 23 07:21:19 2018 > @@ -36,8 +36,7 @@ getWorkspaceSymbols(llvm::StringRef Quer > > /// Retrieves the symbols contained in the "main file" section of an AST in > the > /// same order that they appear. > -llvm::Expected<std::vector<SymbolInformation>> > -getDocumentSymbols(ParsedAST &AST); > +llvm::Expected<std::vector<DocumentSymbol>> getDocumentSymbols(ParsedAST > &AST); > > } // namespace clangd > } // namespace clang > > Modified: clang-tools-extra/trunk/clangd/Protocol.cpp > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.cpp?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/Protocol.cpp (original) > +++ clang-tools-extra/trunk/clangd/Protocol.cpp Fri Nov 23 07:21:19 2018 > @@ -18,6 +18,7 @@ > #include "llvm/ADT/SmallString.h" > #include "llvm/Support/Format.h" > #include "llvm/Support/FormatVariadic.h" > +#include "llvm/Support/JSON.h" > #include "llvm/Support/Path.h" > #include "llvm/Support/raw_ostream.h" > > @@ -222,6 +223,11 @@ bool fromJSON(const json::Value &Params, > if (CodeAction->getObject("codeActionLiteralSupport")) > R.CodeActionStructure = true; > } > + if (auto *DocumentSymbol = TextDocument->getObject("documentSymbol")) { > + if (auto HierarchicalSupport = > + > DocumentSymbol->getBoolean("hierarchicalDocumentSymbolSupport")) > + R.HierarchicalDocumentSymbol = *HierarchicalSupport; > + } > } > if (auto *Workspace = O->getObject("workspace")) { > if (auto *Symbol = Workspace->getObject("symbol")) { > @@ -449,6 +455,25 @@ json::Value toJSON(const CodeAction &CA) > return std::move(CodeAction); > } > > +llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const DocumentSymbol &S) > { > + return O << S.name << " - " << toJSON(S); > +} > + > +llvm::json::Value toJSON(const DocumentSymbol &S) { > + json::Object Result{{"name", S.name}, > + {"kind", static_cast<int>(S.kind)}, > + {"range", S.range}, > + {"selectionRange", S.selectionRange}}; > + > + if (!S.detail.empty()) > + Result["detail"] = S.detail; > + if (!S.children.empty()) > + Result["children"] = S.children; > + if (S.deprecated) > + Result["deprecated"] = true; > + return Result; > +} > + > json::Value toJSON(const WorkspaceEdit &WE) { > if (!WE.changes) > return json::Object{}; > > Modified: clang-tools-extra/trunk/clangd/Protocol.h > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.h?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/Protocol.h (original) > +++ clang-tools-extra/trunk/clangd/Protocol.h Fri Nov 23 07:21:19 2018 > @@ -150,6 +150,9 @@ struct Range { > } > > bool contains(Position Pos) const { return start <= Pos && Pos < end; } > + bool contains(Range Rng) const { > + return start <= Rng.start && Rng.end <= end; > + } > }; > bool fromJSON(const llvm::json::Value &, Range &); > llvm::json::Value toJSON(const Range &); > @@ -331,6 +334,9 @@ struct ClientCapabilities { > /// textDocument.completion.completionItem.snippetSupport > bool CompletionSnippets = false; > > + /// Client supports hierarchical document symbols. > + bool HierarchicalDocumentSymbol = false; > + > /// The supported set of CompletionItemKinds for textDocument/completion. > /// textDocument.completion.completionItemKind.valueSet > llvm::Optional<CompletionItemKindBitset> CompletionItemKinds; > @@ -655,6 +661,39 @@ struct CodeAction { > }; > llvm::json::Value toJSON(const CodeAction &); > > +/// Represents programming constructs like variables, classes, interfaces > etc. > +/// that appear in a document. Document symbols can be hierarchical and they > +/// have two ranges: one that encloses its definition and one that points to > its > +/// most interesting range, e.g. the range of an identifier. > +struct DocumentSymbol { > + /// The name of this symbol. > + std::string name; > + > + /// More detail for this symbol, e.g the signature of a function. > + std::string detail; > + > + /// The kind of this symbol. > + SymbolKind kind; > + > + /// Indicates if this symbol is deprecated. > + bool deprecated; > + > + /// The range enclosing this symbol not including leading/trailing > whitespace > + /// but everything else like comments. This information is typically used > to > + /// determine if the clients cursor is inside the symbol to reveal in the > + /// symbol in the UI. > + Range range; > + > + /// The range that should be selected and revealed when this symbol is > being > + /// picked, e.g the name of a function. Must be contained by the `range`. > + Range selectionRange; > + > + /// Children of this symbol, e.g. properties of a class. > + std::vector<DocumentSymbol> children; > +}; > +llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const DocumentSymbol &S); > +llvm::json::Value toJSON(const DocumentSymbol &S); > + > /// Represents information about programming constructs like variables, > classes, > /// interfaces etc. > struct SymbolInformation { > > Modified: clang-tools-extra/trunk/clangd/clients/clangd-vscode/package.json > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/clients/clangd-vscode/package.json?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/clangd/clients/clangd-vscode/package.json > (original) > +++ clang-tools-extra/trunk/clangd/clients/clangd-vscode/package.json Fri Nov > 23 07:21:19 2018 > @@ -6,7 +6,7 @@ > "publisher": "llvm-vs-code-extensions", > "homepage": "https://clang.llvm.org/extra/clangd.html", > "engines": { > - "vscode": "^1.18.0" > + "vscode": "^1.27.0" > }, > "categories": [ > "Programming Languages", > @@ -32,8 +32,8 @@ > "test": "node ./node_modules/vscode/bin/test" > }, > "dependencies": { > - "vscode-languageclient": "^4.0.0", > - "vscode-languageserver": "^4.0.0" > + "vscode-languageclient": "^5.1.0", > + "vscode-languageserver": "^5.1.0" > }, > "devDependencies": { > "typescript": "^2.0.3", > > Modified: clang-tools-extra/trunk/unittests/clangd/FindSymbolsTests.cpp > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/FindSymbolsTests.cpp?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/unittests/clangd/FindSymbolsTests.cpp (original) > +++ clang-tools-extra/trunk/unittests/clangd/FindSymbolsTests.cpp Fri Nov 23 > 07:21:19 2018 > @@ -14,6 +14,8 @@ > #include "gmock/gmock.h" > #include "gtest/gtest.h" > > +using namespace llvm; > + > namespace clang { > namespace clangd { > > @@ -23,6 +25,7 @@ using ::testing::AllOf; > using ::testing::AnyOf; > using ::testing::ElementsAre; > using ::testing::ElementsAreArray; > +using ::testing::Field; > using ::testing::IsEmpty; > using ::testing::UnorderedElementsAre; > > @@ -37,9 +40,17 @@ MATCHER_P(QName, Name, "") { > return arg.name == Name; > return (arg.containerName + "::" + arg.name) == Name; > } > +MATCHER_P(WithName, N, "") { return arg.name == N; } > MATCHER_P(WithKind, Kind, "") { return arg.kind == Kind; } > MATCHER_P(SymRange, Range, "") { return arg.location.range == Range; } > > +// GMock helpers for matching DocumentSymbol. > +MATCHER_P(SymNameRange, Range, "") { return arg.selectionRange == Range; } > +template <class... ChildMatchers> > +testing::Matcher<DocumentSymbol> Children(ChildMatchers... ChildrenM) { > + return Field(&DocumentSymbol::children, ElementsAre(ChildrenM...)); > +} > + > ClangdServer::Options optsForTests() { > auto ServerOpts = ClangdServer::optsForTest(); > ServerOpts.WorkspaceRoot = testRoot(); > @@ -300,7 +311,7 @@ protected: > IgnoreDiagnostics DiagConsumer; > ClangdServer Server; > > - std::vector<SymbolInformation> getSymbols(PathRef File) { > + std::vector<DocumentSymbol> getSymbols(PathRef File) { > EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for preamble"; > auto SymbolInfos = runDocumentSymbols(Server, File); > EXPECT_TRUE(bool(SymbolInfos)) << "documentSymbols returned an error"; > @@ -363,31 +374,46 @@ TEST_F(DocumentSymbolsTest, BasicSymbols > )"); > > addFile(FilePath, Main.code()); > - EXPECT_THAT(getSymbols(FilePath), > - ElementsAreArray( > - {AllOf(QName("Foo"), WithKind(SymbolKind::Class)), > - AllOf(QName("Foo"), WithKind(SymbolKind::Class)), > - AllOf(QName("Foo::Foo"), WithKind(SymbolKind::Method)), > - AllOf(QName("Foo::Foo"), WithKind(SymbolKind::Method)), > - AllOf(QName("Foo::f"), WithKind(SymbolKind::Method)), > - AllOf(QName("f1"), WithKind(SymbolKind::Function)), > - AllOf(QName("Foo::operator="), > WithKind(SymbolKind::Method)), > - AllOf(QName("Foo::~Foo"), WithKind(SymbolKind::Method)), > - AllOf(QName("Foo::Nested"), WithKind(SymbolKind::Class)), > - AllOf(QName("Foo::Nested::f"), > WithKind(SymbolKind::Method)), > - AllOf(QName("Friend"), WithKind(SymbolKind::Class)), > - AllOf(QName("f1"), WithKind(SymbolKind::Function)), > - AllOf(QName("f2"), WithKind(SymbolKind::Function)), > - AllOf(QName("KInt"), WithKind(SymbolKind::Variable)), > - AllOf(QName("kStr"), WithKind(SymbolKind::Variable)), > - AllOf(QName("f1"), WithKind(SymbolKind::Function)), > - AllOf(QName("foo"), WithKind(SymbolKind::Namespace)), > - AllOf(QName("foo::int32"), WithKind(SymbolKind::Class)), > - AllOf(QName("foo::int32_t"), WithKind(SymbolKind::Class)), > - AllOf(QName("foo::v1"), WithKind(SymbolKind::Variable)), > - AllOf(QName("foo::bar"), WithKind(SymbolKind::Namespace)), > - AllOf(QName("foo::bar::v2"), > WithKind(SymbolKind::Variable)), > - AllOf(QName("foo::baz"), > WithKind(SymbolKind::Namespace))})); > + EXPECT_THAT( > + getSymbols(FilePath), > + ElementsAreArray( > + {AllOf(WithName("Foo"), WithKind(SymbolKind::Class), Children()), > + AllOf(WithName("Foo"), WithKind(SymbolKind::Class), > + Children(AllOf(WithName("Foo"), > WithKind(SymbolKind::Method), > + Children()), > + AllOf(WithName("Foo"), > WithKind(SymbolKind::Method), > + Children()), > + AllOf(WithName("f"), WithKind(SymbolKind::Method), > + Children()), > + AllOf(WithName("operator="), > + WithKind(SymbolKind::Method), Children()), > + AllOf(WithName("~Foo"), > WithKind(SymbolKind::Method), > + Children()), > + AllOf(WithName("Nested"), > WithKind(SymbolKind::Class), > + Children(AllOf(WithName("f"), > + WithKind(SymbolKind::Method), > + Children()))))), > + AllOf(WithName("Friend"), WithKind(SymbolKind::Class), > Children()), > + AllOf(WithName("f1"), WithKind(SymbolKind::Function), Children()), > + AllOf(WithName("f2"), WithKind(SymbolKind::Function), Children()), > + AllOf(WithName("KInt"), WithKind(SymbolKind::Variable), > Children()), > + AllOf(WithName("kStr"), WithKind(SymbolKind::Variable), > Children()), > + AllOf(WithName("f1"), WithKind(SymbolKind::Function), Children()), > + AllOf(WithName("foo"), WithKind(SymbolKind::Namespace), > + Children( > + AllOf(WithName("int32"), WithKind(SymbolKind::Class), > + Children()), > + AllOf(WithName("int32_t"), WithKind(SymbolKind::Class), > + Children()), > + AllOf(WithName("v1"), WithKind(SymbolKind::Variable), > + Children()), > + AllOf(WithName("bar"), WithKind(SymbolKind::Namespace), > + Children(AllOf(WithName("v2"), > + WithKind(SymbolKind::Variable), > + Children()))), > + AllOf(WithName("baz"), WithKind(SymbolKind::Namespace), > + Children()), > + AllOf(WithName("v2"), > WithKind(SymbolKind::Variable))))})); > } > > TEST_F(DocumentSymbolsTest, DeclarationDefinition) { > @@ -402,11 +428,12 @@ TEST_F(DocumentSymbolsTest, DeclarationD > > addFile(FilePath, Main.code()); > EXPECT_THAT(getSymbols(FilePath), > - ElementsAre(AllOf(QName("Foo"), WithKind(SymbolKind::Class)), > - AllOf(QName("Foo::f"), > WithKind(SymbolKind::Method), > - SymRange(Main.range("decl"))), > - AllOf(QName("Foo::f"), > WithKind(SymbolKind::Method), > - SymRange(Main.range("def"))))); > + ElementsAre(AllOf(WithName("Foo"), WithKind(SymbolKind::Class), > + Children(AllOf( > + WithName("f"), > WithKind(SymbolKind::Method), > + SymNameRange(Main.range("decl"))))), > + AllOf(WithName("f"), WithKind(SymbolKind::Method), > + SymNameRange(Main.range("def"))))); > } > > TEST_F(DocumentSymbolsTest, ExternSymbol) { > @@ -429,7 +456,7 @@ TEST_F(DocumentSymbolsTest, NoLocals) { > struct LocalClass {}; > int local_var; > })cpp"); > - EXPECT_THAT(getSymbols(FilePath), ElementsAre(QName("test"))); > + EXPECT_THAT(getSymbols(FilePath), ElementsAre(WithName("test"))); > } > > TEST_F(DocumentSymbolsTest, Unnamed) { > @@ -442,9 +469,12 @@ TEST_F(DocumentSymbolsTest, Unnamed) { > )cpp"); > EXPECT_THAT( > getSymbols(FilePath), > - ElementsAre(AllOf(QName("UnnamedStruct"), > WithKind(SymbolKind::Variable)), > - AllOf(QName("(anonymous struct)::InUnnamed"), > - WithKind(SymbolKind::Field)))); > + ElementsAre( > + AllOf(WithName("(anonymous struct)"), WithKind(SymbolKind::Struct), > + Children(AllOf(WithName("InUnnamed"), > + WithKind(SymbolKind::Field), Children()))), > + AllOf(WithName("UnnamedStruct"), WithKind(SymbolKind::Variable), > + Children()))); > } > > TEST_F(DocumentSymbolsTest, InHeaderFile) { > @@ -461,23 +491,46 @@ TEST_F(DocumentSymbolsTest, InHeaderFile > addFile("foo.cpp", R"cpp( > #include "foo.h" > )cpp"); > - EXPECT_THAT(getSymbols(FilePath), ElementsAre(QName("test"))); > + EXPECT_THAT(getSymbols(FilePath), ElementsAre(WithName("test"))); > } > > TEST_F(DocumentSymbolsTest, Template) { > std::string FilePath = testPath("foo.cpp"); > addFile(FilePath, R"( > - // Primary templates and specializations are included but instantiations > - // are not. > template <class T> struct Tmpl {T x = 0;}; > - template <> struct Tmpl<int> {}; > + template <> struct Tmpl<int> { > + int y = 0; > + }; > extern template struct Tmpl<float>; > template struct Tmpl<double>; > + > + template <class T, class U, class Z = float> > + int funcTmpl(U a); > + template <> > + int funcTmpl<int>(double a); > + > + template <class T, class U = double> > + int varTmpl = T(); > + template <> > + double varTmpl<int> = 10.0; > )"); > - EXPECT_THAT(getSymbols(FilePath), > - ElementsAre(AllOf(QName("Tmpl"), WithKind(SymbolKind::Struct)), > - AllOf(QName("Tmpl::x"), > WithKind(SymbolKind::Field)), > - AllOf(QName("Tmpl"), > WithKind(SymbolKind::Struct)))); > + EXPECT_THAT( > + getSymbols(FilePath), > + ElementsAre( > + AllOf(WithName("Tmpl"), WithKind(SymbolKind::Struct), > + Children(AllOf(WithName("x"), WithKind(SymbolKind::Field)))), > + AllOf(WithName("Tmpl<int>"), WithKind(SymbolKind::Struct), > + Children(WithName("y"))), > + AllOf(WithName("Tmpl<float>"), WithKind(SymbolKind::Struct), > + Children()), > + AllOf(WithName("Tmpl<double>"), WithKind(SymbolKind::Struct), > + Children()), > + AllOf(WithName("funcTmpl"), Children()), > + // FIXME(ibiryukov): template args should be <int> to match the > code. > + AllOf(WithName("funcTmpl<int, double, float>"), Children()), > + AllOf(WithName("varTmpl"), Children()), > + // FIXME(ibiryukov): template args should be <int> to match the > code. > + AllOf(WithName("varTmpl<int, double>"), Children()))); > } > > TEST_F(DocumentSymbolsTest, Namespaces) { > @@ -507,10 +560,15 @@ TEST_F(DocumentSymbolsTest, Namespaces) > )cpp"); > EXPECT_THAT( > getSymbols(FilePath), > - ElementsAreArray({QName("ans1"), QName("ans1::ai1"), > QName("ans1::ans2"), > - QName("ans1::ans2::ai2"), QName("test"), QName("na"), > - QName("na::nb"), QName("na::Foo"), QName("na"), > - QName("na::nb"), QName("na::Bar")})); > + ElementsAreArray<testing::Matcher<DocumentSymbol>>( > + {AllOf(WithName("ans1"), > + Children(AllOf(WithName("ai1"), Children()), > + AllOf(WithName("ans2"), > Children(WithName("ai2"))))), > + AllOf(WithName("(anonymous namespace)"), > Children(WithName("test"))), > + AllOf(WithName("na"), > + Children(AllOf(WithName("nb"), Children(WithName("Foo"))))), > + AllOf(WithName("na"), > + Children(AllOf(WithName("nb"), > Children(WithName("Bar")))))})); > } > > TEST_F(DocumentSymbolsTest, Enums) { > @@ -531,10 +589,14 @@ TEST_F(DocumentSymbolsTest, Enums) { > }; > } > )"); > - EXPECT_THAT(getSymbols(FilePath), > - ElementsAre(QName("Red"), QName("Color"), QName("Green"), > - QName("Color2"), QName("Color2::Yellow"), > QName("ns"), > - QName("ns::Black"))); > + EXPECT_THAT( > + getSymbols(FilePath), > + ElementsAre( > + AllOf(WithName("(anonymous enum)"), Children(WithName("Red"))), > + AllOf(WithName("Color"), Children(WithName("Green"))), > + AllOf(WithName("Color2"), Children(WithName("Yellow"))), > + AllOf(WithName("ns"), Children(AllOf(WithName("(anonymous enum)"), > + > Children(WithName("Black"))))))); > } > > TEST_F(DocumentSymbolsTest, FromMacro) { > @@ -553,8 +615,43 @@ TEST_F(DocumentSymbolsTest, FromMacro) { > addFile(FilePath, Main.code()); > EXPECT_THAT( > getSymbols(FilePath), > - ElementsAre(AllOf(QName("abc_Test"), > SymRange(Main.range("expansion"))), > - AllOf(QName("Test"), SymRange(Main.range("spelling"))))); > + ElementsAre( > + AllOf(WithName("abc_Test"), SymNameRange(Main.range("expansion"))), > + AllOf(WithName("Test"), SymNameRange(Main.range("spelling"))))); > +} > + > +TEST_F(DocumentSymbolsTest, FuncTemplates) { > + std::string FilePath = testPath("foo.cpp"); > + Annotations Source(R"cpp( > + template <class T> > + T foo() {} > + > + auto x = foo<int>(); > + auto y = foo<double>() > + )cpp"); > + addFile(FilePath, Source.code()); > + // Make sure we only see the template declaration, not instantiations. > + EXPECT_THAT(getSymbols(FilePath), > + ElementsAre(WithName("foo"), WithName("x"), WithName("y"))); > +} > + > +TEST_F(DocumentSymbolsTest, UsingDirectives) { > + std::string FilePath = testPath("foo.cpp"); > + Annotations Source(R"cpp( > + namespace ns { > + int foo; > + } > + > + namespace ns_alias = ns; > + > + using namespace ::ns; // check we don't loose qualifiers. > + using namespace ns_alias; // and namespace aliases. > + )cpp"); > + addFile(FilePath, Source.code()); > + EXPECT_THAT(getSymbols(FilePath), > + ElementsAre(WithName("ns"), WithName("ns_alias"), > + WithName("using namespace ::ns"), > + WithName("using namespace ns_alias"))); > } > > } // namespace clangd > > Modified: clang-tools-extra/trunk/unittests/clangd/SyncAPI.cpp > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/SyncAPI.cpp?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/unittests/clangd/SyncAPI.cpp (original) > +++ clang-tools-extra/trunk/unittests/clangd/SyncAPI.cpp Fri Nov 23 07:21:19 > 2018 > @@ -120,9 +120,9 @@ runWorkspaceSymbols(ClangdServer &Server > return std::move(*Result); > } > > -Expected<std::vector<SymbolInformation>> > -runDocumentSymbols(ClangdServer &Server, PathRef File) { > - Optional<Expected<std::vector<SymbolInformation>>> Result; > +Expected<std::vector<DocumentSymbol>> runDocumentSymbols(ClangdServer > &Server, > + PathRef File) { > + Optional<Expected<std::vector<DocumentSymbol>>> Result; > Server.documentSymbols(File, capture(Result)); > return std::move(*Result); > } > > Modified: clang-tools-extra/trunk/unittests/clangd/SyncAPI.h > URL: > http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/SyncAPI.h?rev=347498&r1=347497&r2=347498&view=diff > ============================================================================== > --- clang-tools-extra/trunk/unittests/clangd/SyncAPI.h (original) > +++ clang-tools-extra/trunk/unittests/clangd/SyncAPI.h Fri Nov 23 07:21:19 > 2018 > @@ -47,8 +47,8 @@ std::string runDumpAST(ClangdServer &Ser > llvm::Expected<std::vector<SymbolInformation>> > runWorkspaceSymbols(ClangdServer &Server, StringRef Query, int Limit); > > -llvm::Expected<std::vector<SymbolInformation>> > -runDocumentSymbols(ClangdServer &Server, PathRef File); > +Expected<std::vector<DocumentSymbol>> runDocumentSymbols(ClangdServer > &Server, > + PathRef File); > > SymbolSlab runFuzzyFind(const SymbolIndex &Index, StringRef Query); > SymbolSlab runFuzzyFind(const SymbolIndex &Index, const FuzzyFindRequest > &Req); > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits > _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits