ilya-biryukov created this revision.
ilya-biryukov added reviewers: ioeric, sammccall, simark.
Herald added subscribers: kadircet, arphaman, jkorous, MaskRay.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D52311

Files:
  clangd/ClangdLSPServer.cpp
  clangd/ClangdServer.cpp
  clangd/ClangdServer.h
  clangd/FindSymbols.cpp
  clangd/FindSymbols.h
  clangd/Protocol.cpp
  clangd/Protocol.h
  clangd/clients/clangd-vscode/package.json
  unittests/clangd/SyncAPI.cpp
  unittests/clangd/SyncAPI.h

Index: unittests/clangd/SyncAPI.h
===================================================================
--- unittests/clangd/SyncAPI.h
+++ unittests/clangd/SyncAPI.h
@@ -47,7 +47,7 @@
 llvm::Expected<std::vector<SymbolInformation>>
 runWorkspaceSymbols(ClangdServer &Server, StringRef Query, int Limit);
 
-llvm::Expected<std::vector<SymbolInformation>>
+llvm::Expected<std::vector<DocumentSymbol>>
 runDocumentSymbols(ClangdServer &Server, PathRef File);
 
 } // namespace clangd
Index: unittests/clangd/SyncAPI.cpp
===================================================================
--- unittests/clangd/SyncAPI.cpp
+++ unittests/clangd/SyncAPI.cpp
@@ -118,7 +118,7 @@
   return std::move(*Result);
 }
 
-llvm::Expected<std::vector<SymbolInformation>>
+llvm::Expected<std::vector<DocumentSymbol>>
 runDocumentSymbols(ClangdServer &Server, PathRef File) {
   llvm::Optional<llvm::Expected<std::vector<SymbolInformation>>> Result;
   Server.documentSymbols(File, capture(Result));
Index: clangd/clients/clangd-vscode/package.json
===================================================================
--- clangd/clients/clangd-vscode/package.json
+++ clangd/clients/clangd-vscode/package.json
@@ -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",
Index: clangd/Protocol.h
===================================================================
--- clangd/Protocol.h
+++ clangd/Protocol.h
@@ -40,6 +40,7 @@
   InvalidRequest = -32600,
   MethodNotFound = -32601,
   InvalidParams = -32602,
+
   InternalError = -32603,
 
   ServerNotInitialized = -32002,
@@ -623,6 +624,38 @@
 
 llvm::json::Value toJSON(const Command &C);
 
+/// 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::json::Value toJSON(const DocumentSymbol &S);
+
 /// Represents information about programming constructs like variables, classes,
 /// interfaces etc.
 struct SymbolInformation {
Index: clangd/Protocol.cpp
===================================================================
--- clangd/Protocol.cpp
+++ clangd/Protocol.cpp
@@ -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"
 
@@ -448,6 +449,16 @@
   return std::move(Cmd);
 }
 
+llvm::json::Value toJSON(const DocumentSymbol &S) {
+  return json::Object{{"name", S.name},
+                      {"detail", S.detail},
+                      {"kind", static_cast<int>(S.kind)},
+                      {"deprecated", S.deprecated},
+                      {"children", json::Array{S.children}},
+                      {"range", S.range},
+                      {"selectionRange", S.selectionRange}};
+}
+
 json::Value toJSON(const WorkspaceEdit &WE) {
   if (!WE.changes)
     return json::Object{};
Index: clangd/FindSymbols.h
===================================================================
--- clangd/FindSymbols.h
+++ clangd/FindSymbols.h
@@ -36,8 +36,7 @@
 
 /// 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
Index: clangd/FindSymbols.cpp
===================================================================
--- clangd/FindSymbols.cpp
+++ clangd/FindSymbols.cpp
@@ -12,12 +12,20 @@
 #include "ClangdUnit.h"
 #include "FuzzyMatch.h"
 #include "Logger.h"
+#include "Protocol.h"
 #include "Quality.h"
 #include "SourceCode.h"
 #include "index/Index.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/Basic/SourceLocation.h"
 #include "clang/Index/IndexDataConsumer.h"
 #include "clang/Index/IndexSymbol.h"
 #include "clang/Index/IndexingAction.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Path.h"
 
@@ -176,104 +184,91 @@
 }
 
 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.
-  llvm::Optional<URIForFile> MainFileUri;
+DocumentSymbol declToSym(ASTContext &Ctx, const NamedDecl &ND,
+                         SourceLocation NameLoc,
+                         const URIForFile &MainFileUri) {
+  auto &SM = Ctx.getSourceManager();
+  SourceLocation EndLoc =
+      Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts());
+  Position Begin = sourceLocToPosition(SM, NameLoc);
+  Position End = sourceLocToPosition(SM, EndLoc);
+  Range R = {Begin, End};
 
-public:
-  DocumentSymbolsConsumer(ASTContext &AST) : AST(AST) {}
-  std::vector<SymbolInformation> takeSymbols() { return std::move(Symbols); }
+  std::string QName = printQualifiedName(ND);
+  StringRef Scope, Name;
+  std::tie(Scope, Name) = splitQualifiedName(QName);
+  Scope.consume_back("::");
 
-  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)
-      return;
-    auto FilePath = getRealPath(F, SM);
-    if (FilePath)
-      MainFileUri = URIForFile(*FilePath);
-  }
+  index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
+  SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind);
 
-  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;
-  }
+  DocumentSymbol SI;
+  SI.name = Name;
+  SI.kind = SK;
+  SI.deprecated = ND.isDeprecated();
+  // FIXME(ibiryukov): set the range properly.
+  SI.range = R;
+  SI.selectionRange = R;
+  return SI;
+}
 
-  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;
+std::vector<DocumentSymbol> collectDocSymbols(ASTContext &Ctx,
+                                              const DeclContext &Scope,
+                                              const URIForFile &MainFileUri) {
+  std::vector<DocumentSymbol> Symbols;
+  auto &SM = Ctx.getSourceManager();
+  for (const Decl *D : Scope.decls()) {
+    if (D->isImplicit())
+      continue;
+    if (!SM.isWrittenInMainFile(D->getLocation()))
+      continue;
+    // Add symbol to a list.
+    DocumentSymbol *S = nullptr;
+    if (const NamedDecl *ND = llvm::dyn_cast<NamedDecl>(D)) {
+      Symbols.push_back(declToSym(Ctx, *ND, findNameLoc(ND), MainFileUri));
+      S = &Symbols.back();
+    }
+    // Add childrens if decl is also a DeclContext.
+    // FIXME(ibiryukov): filtering only functions is probably not enough.
+    if (llvm::isa<FunctionDecl>(D))
+      continue; // don't add function locals.
+    // FIXME(ibiryukov): do we even need to handle "DeclContext, but not
+    //                   NamedDecl" case? Can this happen?
+    if (const DeclContext *ChildScope = llvm::dyn_cast<DeclContext>(D)) {
+      auto ChildSymbols = collectDocSymbols(Ctx, *ChildScope, MainFileUri);
+      if (S)
+        S->children = std::move(ChildSymbols);
+      else
+        Symbols.insert(Symbols.end(), ChildSymbols.begin(), ChildSymbols.end());
     }
-    const NamedDecl *ND = llvm::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;
   }
-};
+  return Symbols;
+}
 } // namespace
 
-llvm::Expected<std::vector<SymbolInformation>>
-getDocumentSymbols(ParsedAST &AST) {
-  DocumentSymbolsConsumer DocumentSymbolsCons(AST.getASTContext());
-
-  index::IndexingOptions IndexOpts;
-  IndexOpts.SystemSymbolFilter =
-      index::IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly;
-  IndexOpts.IndexFunctionLocals = false;
-  indexTopLevelDecls(AST.getASTContext(), AST.getLocalTopLevelDecls(),
-                     DocumentSymbolsCons, IndexOpts);
+llvm::Expected<std::vector<DocumentSymbol>> getDocumentSymbols(ParsedAST &AST) {
+  // Compute the absolute path of the main file which we will use for all
+  // results.
+  const SourceManager &SM = AST.getASTContext().getSourceManager();
+  const FileEntry *F = SM.getFileEntryForID(SM.getMainFileID());
+  if (!F)
+    return llvm::createStringError(
+        llvm::errc::invalid_argument,
+        "Could not retrieve FileEntry for main file.");
+  auto FilePath = getRealPath(F, SM);
+  // No point in continuing the index consumer if we could not get the
+  // absolute path of the main file.
+  if (!FilePath)
+    return llvm::createStringError(
+        llvm::errc::invalid_argument,
+        "Could not retrieve absolute path of the main file.");
+  URIForFile MainFileUri = URIForFile(*FilePath);
 
-  return DocumentSymbolsCons.takeSymbols();
+  // Collect all local symbols in the AST, along with start locations of their
+  // names.
+  ASTContext &Ctx = AST.getASTContext();
+  // Convert into the hierarchical tree of symbols.
+  return collectDocSymbols(Ctx, *Ctx.getTranslationUnitDecl(), MainFileUri);
 }
 
 } // namespace clangd
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -165,7 +165,7 @@
 
   /// 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,
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -544,9 +544,9 @@
                                  RootPath ? *RootPath : ""));
 }
 
-void ClangdServer::documentSymbols(
-    StringRef File, Callback<std::vector<SymbolInformation>> CB) {
-  auto Action = [](Callback<std::vector<SymbolInformation>> CB,
+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());
Index: clangd/ClangdLSPServer.cpp
===================================================================
--- clangd/ClangdLSPServer.cpp
+++ clangd/ClangdLSPServer.cpp
@@ -306,7 +306,7 @@
 void ClangdLSPServer::onDocumentSymbol(DocumentSymbolParams &Params) {
   Server.documentSymbols(
       Params.textDocument.uri.file(),
-      [this](llvm::Expected<std::vector<SymbolInformation>> Items) {
+      [this](llvm::Expected<std::vector<DocumentSymbol>> Items) {
         if (!Items)
           return replyError(ErrorCode::InvalidParams,
                             llvm::toString(Items.takeError()));
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to