summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clangd')
-rw-r--r--clang-tools-extra/clangd/ClangdLSPServer.cpp14
-rw-r--r--clang-tools-extra/clangd/ClangdLSPServer.h1
-rw-r--r--clang-tools-extra/clangd/ClangdServer.cpp12
-rw-r--r--clang-tools-extra/clangd/ClangdServer.h4
-rw-r--r--clang-tools-extra/clangd/FindSymbols.cpp109
-rw-r--r--clang-tools-extra/clangd/FindSymbols.h6
-rw-r--r--clang-tools-extra/clangd/Protocol.cpp5
-rw-r--r--clang-tools-extra/clangd/Protocol.h6
-rw-r--r--clang-tools-extra/clangd/ProtocolHandlers.cpp1
-rw-r--r--clang-tools-extra/clangd/ProtocolHandlers.h1
-rw-r--r--clang-tools-extra/clangd/SourceCode.cpp18
-rw-r--r--clang-tools-extra/clangd/SourceCode.h3
-rw-r--r--clang-tools-extra/clangd/XRefs.cpp14
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();
OpenPOWER on IntegriCloud