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