[clang-tools-extra] r336386 - [clangd] Implementation of textDocument/documentSymbol
Marc-Andre Laperle via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 5 12:35:01 PDT 2018
Author: malaperle
Date: Thu Jul 5 12:35:01 2018
New Revision: 336386
URL: http://llvm.org/viewvc/llvm-project?rev=336386&view=rev
Log:
[clangd] Implementation of textDocument/documentSymbol
Summary:
An AST-based approach is used to retrieve the document symbols rather than an
in-memory index query. The index is not an ideal fit to achieve this because of
the file-centric query being done here whereas the index is suited for
project-wide queries. Document symbols also includes more symbols and need to
keep the order as seen in the file.
Signed-off-by: Marc-Andre Laperle <marc-andre.laperle at ericsson.com>
Subscribers: tomgr, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D47846
Modified:
clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
clang-tools-extra/trunk/clangd/ClangdLSPServer.h
clang-tools-extra/trunk/clangd/ClangdServer.cpp
clang-tools-extra/trunk/clangd/ClangdServer.h
clang-tools-extra/trunk/clangd/FindSymbols.cpp
clang-tools-extra/trunk/clangd/FindSymbols.h
clang-tools-extra/trunk/clangd/Protocol.cpp
clang-tools-extra/trunk/clangd/Protocol.h
clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
clang-tools-extra/trunk/clangd/ProtocolHandlers.h
clang-tools-extra/trunk/clangd/SourceCode.cpp
clang-tools-extra/trunk/clangd/SourceCode.h
clang-tools-extra/trunk/clangd/XRefs.cpp
clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test
clang-tools-extra/trunk/test/clangd/initialize-params.test
clang-tools-extra/trunk/test/clangd/symbols.test
clang-tools-extra/trunk/unittests/clangd/FindSymbolsTests.cpp
clang-tools-extra/trunk/unittests/clangd/SyncAPI.cpp
clang-tools-extra/trunk/unittests/clangd/SyncAPI.h
Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp Thu Jul 5 12:35:01 2018
@@ -112,6 +112,7 @@ void ClangdLSPServer::onInitialize(Initi
{"documentHighlightProvider", true},
{"hoverProvider", true},
{"renameProvider", true},
+ {"documentSymbolProvider", true},
{"workspaceSymbolProvider", true},
{"executeCommandProvider",
json::obj{
@@ -294,6 +295,19 @@ void ClangdLSPServer::onDocumentFormatti
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.
Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.h?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdLSPServer.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdLSPServer.h Thu Jul 5 12:35:01 2018
@@ -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;
Modified: clang-tools-extra/trunk/clangd/ClangdServer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.cpp?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdServer.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdServer.cpp Thu Jul 5 12:35:01 2018
@@ -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();
Modified: clang-tools-extra/trunk/clangd/ClangdServer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.h?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdServer.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdServer.h Thu Jul 5 12:35:01 2018
@@ -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);
Modified: clang-tools-extra/trunk/clangd/FindSymbols.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/FindSymbols.cpp?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/FindSymbols.cpp (original)
+++ clang-tools-extra/trunk/clangd/FindSymbols.cpp Thu Jul 5 12:35:01 2018
@@ -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
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
Modified: clang-tools-extra/trunk/clangd/FindSymbols.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/FindSymbols.h?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/FindSymbols.h (original)
+++ clang-tools-extra/trunk/clangd/FindSymbols.h Thu Jul 5 12:35:01 2018
@@ -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<SymbolInforma
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
Modified: clang-tools-extra/trunk/clangd/Protocol.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.cpp?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.cpp (original)
+++ clang-tools-extra/trunk/clangd/Protocol.cpp Thu Jul 5 12:35:01 2018
@@ -342,6 +342,11 @@ bool fromJSON(const json::Expr &Params,
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))
Modified: clang-tools-extra/trunk/clangd/Protocol.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.h?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.h (original)
+++ clang-tools-extra/trunk/clangd/Protocol.h Thu Jul 5 12:35:01 2018
@@ -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;
Modified: clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp (original)
+++ clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp Thu Jul 5 12:35:01 2018
@@ -66,6 +66,7 @@ void clangd::registerCallbackHandlers(JS
&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",
Modified: clang-tools-extra/trunk/clangd/ProtocolHandlers.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ProtocolHandlers.h?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ProtocolHandlers.h (original)
+++ clang-tools-extra/trunk/clangd/ProtocolHandlers.h Thu Jul 5 12:35:01 2018
@@ -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
Modified: clang-tools-extra/trunk/clangd/SourceCode.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/SourceCode.cpp?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/SourceCode.cpp (original)
+++ clang-tools-extra/trunk/clangd/SourceCode.cpp Thu Jul 5 12:35:01 2018
@@ -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> replacementsToEdit
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
Modified: clang-tools-extra/trunk/clangd/SourceCode.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/SourceCode.h?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/SourceCode.h (original)
+++ clang-tools-extra/trunk/clangd/SourceCode.h Thu Jul 5 12:35:01 2018
@@ -61,6 +61,9 @@ TextEdit replacementToEdit(StringRef Cod
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
Modified: clang-tools-extra/trunk/clangd/XRefs.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/XRefs.cpp?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/XRefs.cpp (original)
+++ clang-tools-extra/trunk/clangd/XRefs.cpp Thu Jul 5 12:35:01 2018
@@ -175,20 +175,6 @@ IdentifiedSymbol getSymbolAtPosition(Par
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();
Modified: clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test (original)
+++ clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test Thu Jul 5 12:35:01 2018
@@ -22,6 +22,7 @@
# CHECK-NEXT: "moreTriggerCharacter": []
# CHECK-NEXT: },
# CHECK-NEXT: "documentRangeFormattingProvider": true,
+# CHECK-NEXT: "documentSymbolProvider": true,
# CHECK-NEXT: "executeCommandProvider": {
# CHECK-NEXT: "commands": [
# CHECK-NEXT: "clangd.applyFix"
Modified: clang-tools-extra/trunk/test/clangd/initialize-params.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/initialize-params.test?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clangd/initialize-params.test (original)
+++ clang-tools-extra/trunk/test/clangd/initialize-params.test Thu Jul 5 12:35:01 2018
@@ -22,6 +22,7 @@
# CHECK-NEXT: "moreTriggerCharacter": []
# CHECK-NEXT: },
# CHECK-NEXT: "documentRangeFormattingProvider": true,
+# CHECK-NEXT: "documentSymbolProvider": true,
# CHECK-NEXT: "executeCommandProvider": {
# CHECK-NEXT: "commands": [
# CHECK-NEXT: "clangd.applyFix"
Modified: clang-tools-extra/trunk/test/clangd/symbols.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/symbols.test?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clangd/symbols.test (original)
+++ clang-tools-extra/trunk/test/clangd/symbols.test Thu Jul 5 12:35:01 2018
@@ -28,6 +28,57 @@
# CHECK-NEXT: ]
# CHECK-NEXT:}
---
+{"jsonrpc":"2.0","id":2,"method":"textDocument/documentSymbol","params":{"textDocument":{"uri":"test:///main.cpp"}}}
+# CHECK: "id": 2,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "containerName": "",
+# CHECK-NEXT: "kind": 12,
+# CHECK-NEXT: "location": {
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": {{.*}},
+# CHECK-NEXT: "line": {{.*}}
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": {{.*}},
+# CHECK-NEXT: "line": {{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "uri": "file://{{.*}}/main.cpp"
+# CHECK-NEXT: },
+# CHECK-NEXT: "name": "foo"
+# CHECK-NEXT: }
+# CHECK-NEXT: {
+# CHECK-NEXT: "containerName": "",
+# CHECK-NEXT: "kind": 12,
+# CHECK-NEXT: "location": {
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": {{.*}},
+# CHECK-NEXT: "line": {{.*}}
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": {{.*}},
+# CHECK-NEXT: "line": {{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "uri": "file://{{.*}}/main.cpp"
+# CHECK-NEXT: },
+# CHECK-NEXT: "name": "main"
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT:}
+---
+{"jsonrpc":"2.0","id":3,"method":"textDocument/documentSymbol","params":{"textDocument":{"uri":"test:///foo.cpp"}}}
+# CHECK: "error": {
+# CHECK-NEXT: "code": -32602,
+# CHECK-NEXT: "message": "trying to get AST for non-added document"
+# CHECK-NEXT: },
+# CHECK-NEXT: "id": 3,
+# CHECK-NEXT: "jsonrpc": "2.0"
+---
{"jsonrpc":"2.0","id":3,"method":"shutdown"}
---
{"jsonrpc":"2.0","method":"exit"}
Modified: clang-tools-extra/trunk/unittests/clangd/FindSymbolsTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/FindSymbolsTests.cpp?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/FindSymbolsTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/clangd/FindSymbolsTests.cpp Thu Jul 5 12:35:01 2018
@@ -22,6 +22,7 @@ namespace {
using ::testing::AllOf;
using ::testing::AnyOf;
using ::testing::ElementsAre;
+using ::testing::ElementsAreArray;
using ::testing::IsEmpty;
using ::testing::UnorderedElementsAre;
@@ -37,6 +38,7 @@ MATCHER_P(QName, Name, "") {
return (arg.containerName + "::" + arg.name) == Name;
}
MATCHER_P(WithKind, Kind, "") { return arg.kind == Kind; }
+MATCHER_P(SymRange, Range, "") { return arg.location.range == Range; }
ClangdServer::Options optsForTests() {
auto ServerOpts = ClangdServer::optsForTest();
@@ -287,5 +289,274 @@ TEST_F(WorkspaceSymbolsTest, WithLimit)
EXPECT_THAT(getSymbols("foo"), ElementsAre(QName("foo")));
}
+namespace {
+class DocumentSymbolsTest : public ::testing::Test {
+public:
+ DocumentSymbolsTest()
+ : Server(CDB, FSProvider, DiagConsumer, optsForTests()) {}
+
+protected:
+ MockFSProvider FSProvider;
+ MockCompilationDatabase CDB;
+ IgnoreDiagnostics DiagConsumer;
+ ClangdServer Server;
+
+ std::vector<SymbolInformation> getSymbols(PathRef File) {
+ EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for preamble";
+ auto SymbolInfos = runDocumentSymbols(Server, File);
+ EXPECT_TRUE(bool(SymbolInfos)) << "documentSymbols returned an error";
+ return *SymbolInfos;
+ }
+
+ void addFile(StringRef FilePath, StringRef Contents) {
+ FSProvider.Files[FilePath] = Contents;
+ Server.addDocument(FilePath, Contents);
+ }
+};
+} // namespace
+
+TEST_F(DocumentSymbolsTest, BasicSymbols) {
+ std::string FilePath = testPath("foo.cpp");
+ Annotations Main(R"(
+ class Foo;
+ class Foo {
+ Foo() {}
+ Foo(int a) {}
+ void $decl[[f]]();
+ friend void f1();
+ friend class Friend;
+ Foo& operator=(const Foo&);
+ ~Foo();
+ class Nested {
+ void f();
+ };
+ };
+ class Friend {
+ };
+
+ void f1();
+ inline void f2() {}
+ static const int KInt = 2;
+ const char* kStr = "123";
+
+ void f1() {}
+
+ namespace foo {
+ // Type alias
+ typedef int int32;
+ using int32_t = int32;
+
+ // Variable
+ int v1;
+
+ // Namespace
+ namespace bar {
+ int v2;
+ }
+ // Namespace alias
+ namespace baz = bar;
+
+ // FIXME: using declaration is not supported as the IndexAction will ignore
+ // implicit declarations (the implicit using shadow declaration) by default,
+ // and there is no way to customize this behavior at the moment.
+ using bar::v2;
+ } // namespace foo
+ )");
+
+ addFile(FilePath, Main.code());
+ EXPECT_THAT(getSymbols(FilePath),
+ ElementsAreArray(
+ {AllOf(QName("Foo"), WithKind(SymbolKind::Class)),
+ AllOf(QName("Foo"), WithKind(SymbolKind::Class)),
+ AllOf(QName("Foo::Foo"), WithKind(SymbolKind::Method)),
+ AllOf(QName("Foo::Foo"), WithKind(SymbolKind::Method)),
+ AllOf(QName("Foo::f"), WithKind(SymbolKind::Method)),
+ AllOf(QName("f1"), WithKind(SymbolKind::Function)),
+ AllOf(QName("Foo::operator="), WithKind(SymbolKind::Method)),
+ AllOf(QName("Foo::~Foo"), WithKind(SymbolKind::Method)),
+ AllOf(QName("Foo::Nested"), WithKind(SymbolKind::Class)),
+ AllOf(QName("Foo::Nested::f"), WithKind(SymbolKind::Method)),
+ AllOf(QName("Friend"), WithKind(SymbolKind::Class)),
+ AllOf(QName("f1"), WithKind(SymbolKind::Function)),
+ AllOf(QName("f2"), WithKind(SymbolKind::Function)),
+ AllOf(QName("KInt"), WithKind(SymbolKind::Variable)),
+ AllOf(QName("kStr"), WithKind(SymbolKind::Variable)),
+ AllOf(QName("f1"), WithKind(SymbolKind::Function)),
+ AllOf(QName("foo"), WithKind(SymbolKind::Namespace)),
+ AllOf(QName("foo::int32"), WithKind(SymbolKind::Class)),
+ AllOf(QName("foo::int32_t"), WithKind(SymbolKind::Class)),
+ AllOf(QName("foo::v1"), WithKind(SymbolKind::Variable)),
+ AllOf(QName("foo::bar"), WithKind(SymbolKind::Namespace)),
+ AllOf(QName("foo::bar::v2"), WithKind(SymbolKind::Variable)),
+ AllOf(QName("foo::baz"), WithKind(SymbolKind::Namespace))}));
+}
+
+TEST_F(DocumentSymbolsTest, DeclarationDefinition) {
+ std::string FilePath = testPath("foo.cpp");
+ Annotations Main(R"(
+ class Foo {
+ void $decl[[f]]();
+ };
+ void Foo::$def[[f]]() {
+ }
+ )");
+
+ addFile(FilePath, Main.code());
+ EXPECT_THAT(getSymbols(FilePath),
+ ElementsAre(AllOf(QName("Foo"), WithKind(SymbolKind::Class)),
+ AllOf(QName("Foo::f"), WithKind(SymbolKind::Method),
+ SymRange(Main.range("decl"))),
+ AllOf(QName("Foo::f"), WithKind(SymbolKind::Method),
+ SymRange(Main.range("def")))));
+}
+
+TEST_F(DocumentSymbolsTest, ExternSymbol) {
+ std::string FilePath = testPath("foo.cpp");
+ addFile(testPath("foo.h"), R"cpp(
+ extern int var = 2;
+ )cpp");
+ addFile(FilePath, R"cpp(
+ #include "foo.h"
+ )cpp");
+
+ EXPECT_THAT(getSymbols(FilePath), IsEmpty());
+}
+
+TEST_F(DocumentSymbolsTest, NoLocals) {
+ std::string FilePath = testPath("foo.cpp");
+ addFile(FilePath,
+ R"cpp(
+ void test(int FirstParam, int SecondParam) {
+ struct LocalClass {};
+ int local_var;
+ })cpp");
+ EXPECT_THAT(getSymbols(FilePath), ElementsAre(QName("test")));
+}
+
+TEST_F(DocumentSymbolsTest, Unnamed) {
+ std::string FilePath = testPath("foo.h");
+ addFile(FilePath,
+ R"cpp(
+ struct {
+ int InUnnamed;
+ } UnnamedStruct;
+ )cpp");
+ EXPECT_THAT(
+ getSymbols(FilePath),
+ ElementsAre(AllOf(QName("UnnamedStruct"), WithKind(SymbolKind::Variable)),
+ AllOf(QName("(anonymous struct)::InUnnamed"),
+ WithKind(SymbolKind::Field))));
+}
+
+TEST_F(DocumentSymbolsTest, InHeaderFile) {
+ addFile("bar.h", R"cpp(
+ int foo() {
+ }
+ )cpp");
+ std::string FilePath = testPath("foo.h");
+ addFile(FilePath, R"cpp(
+ #include "bar.h"
+ int test() {
+ }
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols(FilePath), ElementsAre(QName("test")));
+}
+
+TEST_F(DocumentSymbolsTest, Template) {
+ std::string FilePath = testPath("foo.cpp");
+ addFile(FilePath, R"(
+ // Primary templates and specializations are included but instantiations
+ // are not.
+ template <class T> struct Tmpl {T x = 0;};
+ template <> struct Tmpl<int> {};
+ extern template struct Tmpl<float>;
+ template struct Tmpl<double>;
+ )");
+ EXPECT_THAT(getSymbols(FilePath),
+ ElementsAre(AllOf(QName("Tmpl"), WithKind(SymbolKind::Struct)),
+ AllOf(QName("Tmpl::x"), WithKind(SymbolKind::Field)),
+ AllOf(QName("Tmpl"), WithKind(SymbolKind::Struct))));
+}
+
+TEST_F(DocumentSymbolsTest, Namespaces) {
+ std::string FilePath = testPath("foo.cpp");
+ addFile(FilePath, R"cpp(
+ namespace ans1 {
+ int ai1;
+ namespace ans2 {
+ int ai2;
+ }
+ }
+ namespace {
+ void test() {}
+ }
+
+ namespace na {
+ inline namespace nb {
+ class Foo {};
+ }
+ }
+ namespace na {
+ // This is still inlined.
+ namespace nb {
+ class Bar {};
+ }
+ }
+ )cpp");
+ EXPECT_THAT(
+ getSymbols(FilePath),
+ ElementsAreArray({QName("ans1"), QName("ans1::ai1"), QName("ans1::ans2"),
+ QName("ans1::ans2::ai2"), QName("test"), QName("na"),
+ QName("na::nb"), QName("na::Foo"), QName("na"),
+ QName("na::nb"), QName("na::Bar")}));
+}
+
+TEST_F(DocumentSymbolsTest, Enums) {
+ std::string FilePath = testPath("foo.cpp");
+ addFile(FilePath, R"(
+ enum {
+ Red
+ };
+ enum Color {
+ Green
+ };
+ enum class Color2 {
+ Yellow
+ };
+ namespace ns {
+ enum {
+ Black
+ };
+ }
+ )");
+ EXPECT_THAT(getSymbols(FilePath),
+ ElementsAre(QName("Red"), QName("Color"), QName("Green"),
+ QName("Color2"), QName("Color2::Yellow"), QName("ns"),
+ QName("ns::Black")));
+}
+
+TEST_F(DocumentSymbolsTest, FromMacro) {
+ std::string FilePath = testPath("foo.cpp");
+ Annotations Main(R"(
+ #define FF(name) \
+ class name##_Test {};
+
+ $expansion[[FF]](abc);
+
+ #define FF2() \
+ class $spelling[[Test]] {};
+
+ FF2();
+ )");
+ addFile(FilePath, Main.code());
+ EXPECT_THAT(
+ getSymbols(FilePath),
+ ElementsAre(AllOf(QName("abc_Test"), SymRange(Main.range("expansion"))),
+ AllOf(QName("Test"), SymRange(Main.range("spelling")))));
+}
+
} // namespace clangd
} // namespace clang
Modified: clang-tools-extra/trunk/unittests/clangd/SyncAPI.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/SyncAPI.cpp?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/SyncAPI.cpp (original)
+++ clang-tools-extra/trunk/unittests/clangd/SyncAPI.cpp Thu Jul 5 12:35:01 2018
@@ -117,5 +117,12 @@ runWorkspaceSymbols(ClangdServer &Server
return std::move(*Result);
}
+llvm::Expected<std::vector<SymbolInformation>>
+runDocumentSymbols(ClangdServer &Server, PathRef File) {
+ llvm::Optional<llvm::Expected<std::vector<SymbolInformation>>> Result;
+ Server.documentSymbols(File, capture(Result));
+ return std::move(*Result);
+}
+
} // namespace clangd
} // namespace clang
Modified: clang-tools-extra/trunk/unittests/clangd/SyncAPI.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/SyncAPI.h?rev=336386&r1=336385&r2=336386&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/SyncAPI.h (original)
+++ clang-tools-extra/trunk/unittests/clangd/SyncAPI.h Thu Jul 5 12:35:01 2018
@@ -43,6 +43,9 @@ std::string runDumpAST(ClangdServer &Ser
llvm::Expected<std::vector<SymbolInformation>>
runWorkspaceSymbols(ClangdServer &Server, StringRef Query, int Limit);
+llvm::Expected<std::vector<SymbolInformation>>
+runDocumentSymbols(ClangdServer &Server, PathRef File);
+
} // namespace clangd
} // namespace clang
More information about the cfe-commits
mailing list