diff options
Diffstat (limited to 'clang-tools-extra/clangd')
| -rw-r--r-- | clang-tools-extra/clangd/ClangdLSPServer.cpp | 14 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/ClangdLSPServer.h | 1 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/ClangdServer.cpp | 12 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/ClangdServer.h | 4 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/FindSymbols.cpp | 109 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/FindSymbols.h | 6 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/Protocol.cpp | 5 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/Protocol.h | 6 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/ProtocolHandlers.cpp | 1 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/ProtocolHandlers.h | 1 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/SourceCode.cpp | 18 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/SourceCode.h | 3 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/XRefs.cpp | 14 |
13 files changed, 178 insertions, 16 deletions
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index 77a0bb1c01d..385768a14b0 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -112,6 +112,7 @@ void ClangdLSPServer::onInitialize(InitializeParams &Params) { {"documentHighlightProvider", true}, {"hoverProvider", true}, {"renameProvider", true}, + {"documentSymbolProvider", true}, {"workspaceSymbolProvider", true}, {"executeCommandProvider", json::obj{ @@ -294,6 +295,19 @@ void ClangdLSPServer::onDocumentFormatting(DocumentFormattingParams &Params) { llvm::toString(ReplacementsOrError.takeError())); } +void ClangdLSPServer::onDocumentSymbol(DocumentSymbolParams &Params) { + Server.documentSymbols( + Params.textDocument.uri.file(), + [this](llvm::Expected<std::vector<SymbolInformation>> Items) { + if (!Items) + return replyError(ErrorCode::InvalidParams, + llvm::toString(Items.takeError())); + for (auto &Sym : *Items) + Sym.kind = adjustKindToCapability(Sym.kind, SupportedSymbolKinds); + reply(json::ary(*Items)); + }); +} + void ClangdLSPServer::onCodeAction(CodeActionParams &Params) { // We provide a code action for each diagnostic at the requested location // which has FixIts available. diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h index 0a3e6fc0a52..e3b67709ef5 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.h +++ b/clang-tools-extra/clangd/ClangdLSPServer.h @@ -62,6 +62,7 @@ private: void onDocumentRangeFormatting(DocumentRangeFormattingParams &Params) override; void onDocumentFormatting(DocumentFormattingParams &Params) override; + void onDocumentSymbol(DocumentSymbolParams &Params) override; void onCodeAction(CodeActionParams &Params) override; void onCompletion(TextDocumentPositionParams &Params) override; void onSignatureHelp(TextDocumentPositionParams &Params) override; diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index cc61673186f..bc6a9fb16b8 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -456,6 +456,18 @@ void ClangdServer::workspaceSymbols( RootPath ? *RootPath : "")); } +void ClangdServer::documentSymbols( + StringRef File, Callback<std::vector<SymbolInformation>> CB) { + auto Action = [](Callback<std::vector<SymbolInformation>> CB, + llvm::Expected<InputsAndAST> InpAST) { + if (!InpAST) + return CB(InpAST.takeError()); + CB(clangd::getDocumentSymbols(InpAST->AST)); + }; + WorkScheduler.runWithAST("documentSymbols", File, + Bind(Action, std::move(CB))); +} + std::vector<std::pair<Path, std::size_t>> ClangdServer::getUsedBytesPerFile() const { return WorkScheduler.getUsedBytesPerFile(); diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h index 5d14f09e23f..36dcd1cc3f9 100644 --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -167,6 +167,10 @@ public: void workspaceSymbols(StringRef Query, int Limit, Callback<std::vector<SymbolInformation>> CB); + /// Retrieve the symbols within the specified file. + void documentSymbols(StringRef File, + Callback<std::vector<SymbolInformation>> CB); + /// Run formatting for \p Rng inside \p File with content \p Code. llvm::Expected<tooling::Replacements> formatRange(StringRef Code, PathRef File, Range Rng); diff --git a/clang-tools-extra/clangd/FindSymbols.cpp b/clang-tools-extra/clangd/FindSymbols.cpp index 66608dde4af..d4f9c037daf 100644 --- a/clang-tools-extra/clangd/FindSymbols.cpp +++ b/clang-tools-extra/clangd/FindSymbols.cpp @@ -8,12 +8,16 @@ //===----------------------------------------------------------------------===// #include "FindSymbols.h" -#include "Logger.h" +#include "AST.h" +#include "ClangdUnit.h" #include "FuzzyMatch.h" -#include "SourceCode.h" +#include "Logger.h" #include "Quality.h" +#include "SourceCode.h" #include "index/Index.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" @@ -172,5 +176,106 @@ getWorkspaceSymbols(StringRef Query, int Limit, const SymbolIndex *const Index, return Result; } +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; + +public: + DocumentSymbolsConsumer(ASTContext &AST) : AST(AST) {} + std::vector<SymbolInformation> takeSymbols() { return std::move(Symbols); } + + 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 = getAbsoluteFilePath(F, SM); + if (FilePath) + MainFileUri = URIForFile(*FilePath); + } + + 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; + } + + 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 presense of "extern" decls. + return true; + } + 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; + } +}; +} // 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); + + return DocumentSymbolsCons.takeSymbols(); +} + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/FindSymbols.h b/clang-tools-extra/clangd/FindSymbols.h index 49c20f3809b..863578b2c64 100644 --- a/clang-tools-extra/clangd/FindSymbols.h +++ b/clang-tools-extra/clangd/FindSymbols.h @@ -17,6 +17,7 @@ #include "llvm/ADT/StringRef.h" namespace clang { +class ParsedAST; namespace clangd { class SymbolIndex; @@ -33,6 +34,11 @@ llvm::Expected<std::vector<SymbolInformation>> getWorkspaceSymbols(llvm::StringRef Query, int Limit, const SymbolIndex *const Index, llvm::StringRef HintPath); +/// 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); + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp index b3290e15054..64f6bd60c02 100644 --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -342,6 +342,11 @@ bool fromJSON(const json::Expr &Params, DocumentFormattingParams &R) { O.map("options", R.options); } +bool fromJSON(const json::Expr &Params, DocumentSymbolParams &R) { + json::ObjectMapper O(Params); + return O && O.map("textDocument", R.textDocument); +} + bool fromJSON(const json::Expr &Params, Diagnostic &R) { json::ObjectMapper O(Params); if (!O || !O.map("range", R.range) || !O.map("message", R.message)) diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index bbafdf171fc..999b8432b76 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -479,6 +479,12 @@ struct DocumentFormattingParams { }; bool fromJSON(const json::Expr &, DocumentFormattingParams &); +struct DocumentSymbolParams { + // The text document to find symbols in. + TextDocumentIdentifier textDocument; +}; +bool fromJSON(const json::Expr &, DocumentSymbolParams &); + struct Diagnostic { /// The range at which the message applies. Range range; diff --git a/clang-tools-extra/clangd/ProtocolHandlers.cpp b/clang-tools-extra/clangd/ProtocolHandlers.cpp index 0432714a5a8..479bf527039 100644 --- a/clang-tools-extra/clangd/ProtocolHandlers.cpp +++ b/clang-tools-extra/clangd/ProtocolHandlers.cpp @@ -66,6 +66,7 @@ void clangd::registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, &ProtocolCallbacks::onSwitchSourceHeader); Register("textDocument/rename", &ProtocolCallbacks::onRename); Register("textDocument/hover", &ProtocolCallbacks::onHover); + Register("textDocument/documentSymbol", &ProtocolCallbacks::onDocumentSymbol); Register("workspace/didChangeWatchedFiles", &ProtocolCallbacks::onFileEvent); Register("workspace/executeCommand", &ProtocolCallbacks::onCommand); Register("textDocument/documentHighlight", diff --git a/clang-tools-extra/clangd/ProtocolHandlers.h b/clang-tools-extra/clangd/ProtocolHandlers.h index dd181494043..63fd99dcac6 100644 --- a/clang-tools-extra/clangd/ProtocolHandlers.h +++ b/clang-tools-extra/clangd/ProtocolHandlers.h @@ -38,6 +38,7 @@ public: virtual void onDocumentDidChange(DidChangeTextDocumentParams &Params) = 0; virtual void onDocumentDidClose(DidCloseTextDocumentParams &Params) = 0; virtual void onDocumentFormatting(DocumentFormattingParams &Params) = 0; + virtual void onDocumentSymbol(DocumentSymbolParams &Params) = 0; virtual void onDocumentOnTypeFormatting(DocumentOnTypeFormattingParams &Params) = 0; virtual void diff --git a/clang-tools-extra/clangd/SourceCode.cpp b/clang-tools-extra/clangd/SourceCode.cpp index 50a7f4e6bc5..b7402893eb6 100644 --- a/clang-tools-extra/clangd/SourceCode.cpp +++ b/clang-tools-extra/clangd/SourceCode.cpp @@ -8,9 +8,13 @@ //===----------------------------------------------------------------------===// #include "SourceCode.h" +#include "Logger.h" +#include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" +#include "clang/Lex/Lexer.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" +#include "llvm/Support/Path.h" namespace clang { namespace clangd { @@ -181,5 +185,19 @@ std::vector<TextEdit> replacementsToEdits(StringRef Code, return Edits; } +llvm::Optional<std::string> +getAbsoluteFilePath(const FileEntry *F, const SourceManager &SourceMgr) { + SmallString<64> FilePath = F->tryGetRealPathName(); + if (FilePath.empty()) + FilePath = F->getName(); + if (!llvm::sys::path::is_absolute(FilePath)) { + if (!SourceMgr.getFileManager().makeAbsolutePath(FilePath)) { + log("Could not turn relative path to absolute: " + FilePath); + return llvm::None; + } + } + return FilePath.str().str(); +} + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/SourceCode.h b/clang-tools-extra/clangd/SourceCode.h index a61d411fe13..b67fe6ecfde 100644 --- a/clang-tools-extra/clangd/SourceCode.h +++ b/clang-tools-extra/clangd/SourceCode.h @@ -61,6 +61,9 @@ TextEdit replacementToEdit(StringRef Code, const tooling::Replacement &R); std::vector<TextEdit> replacementsToEdits(StringRef Code, const tooling::Replacements &Repls); +/// Get the absolute file path of a given file entry. +llvm::Optional<std::string> getAbsoluteFilePath(const FileEntry *F, + const SourceManager &SourceMgr); } // namespace clangd } // namespace clang #endif diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index 6cc661a20bc..8b65883eecb 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -175,20 +175,6 @@ IdentifiedSymbol getSymbolAtPosition(ParsedAST &AST, SourceLocation Pos) { return {DeclMacrosFinder.takeDecls(), DeclMacrosFinder.takeMacroInfos()}; } -llvm::Optional<std::string> -getAbsoluteFilePath(const FileEntry *F, const SourceManager &SourceMgr) { - SmallString<64> FilePath = F->tryGetRealPathName(); - if (FilePath.empty()) - FilePath = F->getName(); - if (!llvm::sys::path::is_absolute(FilePath)) { - if (!SourceMgr.getFileManager().makeAbsolutePath(FilePath)) { - log("Could not turn relative path to absolute: " + FilePath); - return llvm::None; - } - } - return FilePath.str().str(); -} - llvm::Optional<Location> makeLocation(ParsedAST &AST, const SourceRange &ValSourceRange) { const SourceManager &SourceMgr = AST.getASTContext().getSourceManager(); |

