[clang-tools-extra] r347498 - [clangd] Add support for hierarchical documentSymbol

Mikael Holmén via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 26 04:22:43 PST 2018



On 11/26/18 12:41 PM, Ilya Biryukov wrote:
> Sorry about that, should be fixed in r347539.
> 

Yep, thanks!

/Mikael

> On Mon, Nov 26, 2018 at 8:10 AM Mikael Holmén 
> <mikael.holmen at ericsson.com <mailto:mikael.holmen at ericsson.com>> wrote:
> 
>     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 <http://arg.name> == Name;
>      >     return (arg.containerName + "::" + arg.name
>     <http://arg.name>) == Name;
>      >   }
>      > +MATCHER_P(WithName, N, "") { return arg.name <http://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 at lists.llvm.org <mailto:cfe-commits at lists.llvm.org>
>      > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>      >
> 
> 
> 
> -- 
> Regards,
> Ilya Biryukov



More information about the cfe-commits mailing list