jkorous updated this revision to Diff 175069.
jkorous marked 2 inline comments as done.
jkorous added a comment.
Changes based on review.
Repository:
rCTE Clang Tools Extra
https://reviews.llvm.org/D54799
Files:
ClangdLSPServer.cpp
ClangdLSPServer.h
ClangdServer.cpp
ClangdServer.h
Protocol.cpp
Protocol.h
XRefs.cpp
XRefs.h
clangd/cursor-info.test
index/Index.cpp
index/Index.h
Index: clangd/cursor-info.test
===================================================================
--- /dev/null
+++ clangd/cursor-info.test
@@ -0,0 +1,46 @@
+# RUN: clangd -lit-test < %s | FileCheck %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///simple.cpp","languageId":"cpp","version":1,"text":"void foo(); int main() { foo(); }\n"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/symbolInfo","params":{"textDocument":{"uri":"test:///simple.cpp"},"position":{"line":0,"character":27}}}
+# CHECK: "containerName": "",
+# CHECK-NEXT: "id": "CA2EBE44A1D76D2A1547D47BC6D51EBF",
+# CHECK-NEXT: "name": "foo",
+# CHECK-NEXT: "usr": "c:@F@foo#"
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///nested-decl.cpp","languageId":"cpp","version":1,"text":"namespace nnn { struct aaa {}; void foo() { aaa a; }; }"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/symbolInfo","params":{"textDocument":{"uri":"test:///nested-decl.cpp"},"position":{"line":0,"character":46}}}
+# CHECK: "containerName": "nnn::",
+# CHECK-NEXT: "id": "20237FF18EB405D842456DC5D578426D",
+# CHECK-NEXT: "name": "aaa",
+# CHECK-NEXT: "usr": "c:@N@nnn@S@aaa"
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///reference.cpp","languageId":"cpp","version":1,"text":"int value; void foo(int) {} void bar() { foo(value); }"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/symbolInfo","params":{"textDocument":{"uri":"test:///reference.cpp"},"position":{"line":0,"character":48}}}
+# CHECK: "containerName": "",
+# CHECK-NEXT: "id": "844613FB2393C9D40A2AFF25D5D316A1",
+# CHECK-NEXT: "name": "value",
+# CHECK-NEXT: "usr": "c:@value"
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///local.cpp","languageId":"cpp","version":1,"text":"void foo() { int aaa; int bbb = aaa; }"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/symbolInfo","params":{"textDocument":{"uri":"test:///local.cpp"},"position":{"line":0,"character":33}}}
+# CHECK: "containerName": "foo",
+# CHECK-NEXT: "id": "C05589F2664B06F392C2C438568E55E0",
+# CHECK-NEXT: "name": "aaa",
+# CHECK-NEXT: "usr": "c:local.cpp@13@F@foo#@aaa"
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///macro.cpp","languageId":"cpp","version":1,"text":"#define MACRO 5\nint i = MACRO;"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/symbolInfo","params":{"textDocument":{"uri":"test:///macro.cpp"},"position":{"line":1,"character":11}}}
+# CHECK: "containerName": "",
+# CHECK-NEXT: "id": "29EB506CBDF1BA6D1B6EC203FF03B384",
+# CHECK-NEXT: "name": "MACRO",
+# CHECK-NEXT: "usr": "c:macro.cpp@24@macro@MACRO"
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
Index: index/Index.h
===================================================================
--- index/Index.h
+++ index/Index.h
@@ -10,11 +10,11 @@
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_INDEX_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_INDEX_H
+#include "Protocol.h"
#include "clang/Index/IndexSymbol.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
@@ -94,54 +94,6 @@
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const SymbolLocation &);
-// The class identifies a particular C++ symbol (class, function, method, etc).
-//
-// As USRs (Unified Symbol Resolution) could be large, especially for functions
-// with long type arguments, SymbolID is using truncated SHA1(USR) values to
-// guarantee the uniqueness of symbols while using a relatively small amount of
-// memory (vs storing USRs directly).
-//
-// SymbolID can be used as key in the symbol indexes to lookup the symbol.
-class SymbolID {
-public:
- SymbolID() = default;
- explicit SymbolID(llvm::StringRef USR);
-
- bool operator==(const SymbolID &Sym) const {
- return HashValue == Sym.HashValue;
- }
- bool operator<(const SymbolID &Sym) const {
- return HashValue < Sym.HashValue;
- }
-
- // The stored hash is truncated to RawSize bytes.
- // This trades off memory against the number of symbols we can handle.
- // FIXME: can we reduce this further to 8 bytes?
- constexpr static size_t RawSize = 16;
- llvm::StringRef raw() const {
- return StringRef(reinterpret_cast<const char *>(HashValue.data()), RawSize);
- }
- static SymbolID fromRaw(llvm::StringRef);
-
- // Returns a hex encoded string.
- std::string str() const;
- static llvm::Expected<SymbolID> fromStr(llvm::StringRef);
-
-private:
- std::array<uint8_t, RawSize> HashValue;
-};
-
-inline llvm::hash_code hash_value(const SymbolID &ID) {
- // We already have a good hash, just return the first bytes.
- assert(sizeof(size_t) <= SymbolID::RawSize && "size_t longer than SHA1!");
- size_t Result;
- memcpy(&Result, ID.raw().data(), sizeof(size_t));
- return llvm::hash_code(Result);
-}
-
-// Write SymbolID into the given stream. SymbolID is encoded as ID.str().
-llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolID &ID);
-
} // namespace clangd
} // namespace clang
namespace llvm {
Index: index/Index.cpp
===================================================================
--- index/Index.cpp
+++ index/Index.cpp
@@ -12,7 +12,6 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
-#include "llvm/Support/SHA1.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -43,34 +42,6 @@
<< "-" << L.End.line() << ":" << L.End.column() << ")";
}
-SymbolID::SymbolID(StringRef USR) {
- auto Hash = SHA1::hash(arrayRefFromStringRef(USR));
- static_assert(sizeof(Hash) >= RawSize, "RawSize larger than SHA1");
- memcpy(HashValue.data(), Hash.data(), RawSize);
-}
-
-raw_ostream &operator<<(raw_ostream &OS, const SymbolID &ID) {
- return OS << toHex(ID.raw());
-}
-
-SymbolID SymbolID::fromRaw(StringRef Raw) {
- SymbolID ID;
- assert(Raw.size() == RawSize);
- memcpy(ID.HashValue.data(), Raw.data(), RawSize);
- return ID;
-}
-
-std::string SymbolID::str() const { return toHex(raw()); }
-
-Expected<SymbolID> SymbolID::fromStr(StringRef Str) {
- if (Str.size() != RawSize * 2)
- return createStringError(inconvertibleErrorCode(), "Bad ID length");
- for (char C : Str)
- if (!isHexDigit(C))
- return createStringError(inconvertibleErrorCode(), "Bad hex ID");
- return fromRaw(fromHex(Str));
-}
-
raw_ostream &operator<<(raw_ostream &OS, SymbolOrigin O) {
if (O == SymbolOrigin::Unknown)
return OS << "unknown";
Index: XRefs.h
===================================================================
--- XRefs.h
+++ XRefs.h
@@ -38,6 +38,9 @@
std::vector<Location> findReferences(ParsedAST &AST, Position Pos,
const SymbolIndex *Index = nullptr);
+/// Get info about symbol at \p Cursor.
+llvm::Optional<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos);
+
} // namespace clangd
} // namespace clang
Index: XRefs.cpp
===================================================================
--- XRefs.cpp
+++ XRefs.cpp
@@ -92,11 +92,14 @@
const SourceLocation &SearchedLocation;
const ASTContext &AST;
Preprocessor &PP;
+ const bool StopOnFirstDeclFound;
public:
DeclarationAndMacrosFinder(const SourceLocation &SearchedLocation,
- ASTContext &AST, Preprocessor &PP)
- : SearchedLocation(SearchedLocation), AST(AST), PP(PP) {}
+ ASTContext &AST, Preprocessor &PP,
+ bool StopOnFirstDeclFound)
+ : SearchedLocation(SearchedLocation), AST(AST), PP(PP),
+ StopOnFirstDeclFound(StopOnFirstDeclFound) {}
// Get all DeclInfo of the found declarations.
// The results are sorted by "IsReferencedExplicitly" and declaration
@@ -153,6 +156,12 @@
};
bool IsExplicit = !hasImplicitExpr(ASTNode.OrigE);
+
+ if (StopOnFirstDeclFound && IsExplicit) {
+ Decls[D] |= IsExplicit;
+ return false;
+ }
+
// Find and add definition declarations (for GoToDefinition).
// We don't use parameter `D`, as Parameter `D` is the canonical
// declaration, which is the first declaration of a redeclarable
@@ -203,9 +212,10 @@
std::vector<MacroDecl> Macros;
};
-IdentifiedSymbol getSymbolAtPosition(ParsedAST &AST, SourceLocation Pos) {
- auto DeclMacrosFinder = DeclarationAndMacrosFinder(Pos, AST.getASTContext(),
- AST.getPreprocessor());
+IdentifiedSymbol getSymbolAtPosition(ParsedAST &AST, SourceLocation Pos,
+ bool ReturnFirstDeclFound = false) {
+ auto DeclMacrosFinder = DeclarationAndMacrosFinder(
+ Pos, AST.getASTContext(), AST.getPreprocessor(), ReturnFirstDeclFound);
index::IndexingOptions IndexOpts;
IndexOpts.SystemSymbolFilter =
index::IndexingOptions::SystemSymbolFilterKind::All;
@@ -749,5 +759,51 @@
return Results;
}
+llvm::Optional<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos) {
+ const SourceManager &SM = AST.getASTContext().getSourceManager();
+
+ auto Loc = getBeginningOfIdentifier(AST, Pos, SM.getMainFileID());
+ auto Symbols = getSymbolAtPosition(AST, Loc, true);
+
+ SymbolDetails Result;
+
+ if (!Symbols.Decls.empty()) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(Symbols.Decls.front().D)) {
+ std::string QName = printQualifiedName(*ND);
+ std::tie(Result.containerName, Result.name) = splitQualifiedName(QName);
+
+ if (!Result.containerName.empty()) {
+ StringRef ContainerNameRef = Result.containerName;
+ ContainerNameRef.consume_back("::");
+ } else {
+ const auto *DC = ND->getDeclContext();
+ if (DC) {
+ if (const NamedDecl *ParentND = dyn_cast<NamedDecl>(DC)) {
+ Result.containerName = printQualifiedName(*ParentND);
+ }
+ }
+ }
+ }
+ llvm::SmallString<32> USR;
+ if (!index::generateUSRForDecl(Symbols.Decls.front().D, USR)) {
+ Result.USR = USR.str();
+ Result.ID = SymbolID(Result.USR);
+ return Result;
+ }
+ }
+
+ if (!Symbols.Macros.empty()) {
+ Result.name = Symbols.Macros.front().Name;
+ llvm::SmallString<32> USR;
+ if (!index::generateUSRForMacro(Result.name, Loc, SM, USR)) {
+ Result.USR = USR.str();
+ Result.ID = SymbolID(Result.USR);
+ return Result;
+ }
+ }
+
+ return llvm::None;
+}
+
} // namespace clangd
} // namespace clang
Index: Protocol.h
===================================================================
--- Protocol.h
+++ Protocol.h
@@ -673,6 +673,62 @@
llvm::json::Value toJSON(const SymbolInformation &);
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const SymbolInformation &);
+// The class identifies a particular C++ symbol (class, function, method, etc).
+//
+// As USRs (Unified Symbol Resolution) could be large, especially for functions
+// with long type arguments, SymbolID is using truncated SHA1(USR) values to
+// guarantee the uniqueness of symbols while using a relatively small amount of
+// memory (vs storing USRs directly).
+//
+// SymbolID can be used as key in the symbol indexes to lookup the symbol.
+class SymbolID {
+public:
+ SymbolID() = default;
+ explicit SymbolID(llvm::StringRef USR);
+
+ bool operator==(const SymbolID &Sym) const {
+ return HashValue == Sym.HashValue;
+ }
+ bool operator<(const SymbolID &Sym) const {
+ return HashValue < Sym.HashValue;
+ }
+
+ // The stored hash is truncated to RawSize bytes.
+ // This trades off memory against the number of symbols we can handle.
+ // FIXME: can we reduce this further to 8 bytes?
+ constexpr static size_t RawSize = 16;
+ llvm::StringRef raw() const;
+
+ static SymbolID fromRaw(llvm::StringRef);
+
+ // Returns a hex encoded string.
+ std::string str() const;
+ static llvm::Expected<SymbolID> fromStr(llvm::StringRef);
+
+private:
+ std::array<uint8_t, RawSize> HashValue;
+};
+
+llvm::hash_code hash_value(const SymbolID &ID);
+
+// Write SymbolID into the given stream. SymbolID is encoded as ID.str().
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolID &ID);
+
+/// Represents information about identifier.
+/// This is returned from textDocument/symbolInfo, which is a clangd extension.
+struct SymbolDetails {
+ std::string name;
+
+ std::string containerName;
+
+ /// Unified Symbol Resolution identifier
+ std::string USR;
+
+ SymbolID ID;
+};
+llvm::json::Value toJSON(const SymbolDetails &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const SymbolDetails &);
+
/// The parameters of a Workspace Symbol Request.
struct WorkspaceSymbolParams {
/// A non-empty query string
Index: Protocol.cpp
===================================================================
--- Protocol.cpp
+++ Protocol.cpp
@@ -14,11 +14,14 @@
#include "Protocol.h"
#include "Logger.h"
#include "URI.h"
+#include "index/Index.h"
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/SHA1.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -422,6 +425,62 @@
return O;
}
+SymbolID::SymbolID(StringRef USR) {
+ auto Hash = llvm::SHA1::hash(arrayRefFromStringRef(USR));
+ static_assert(sizeof(Hash) >= RawSize, "RawSize larger than SHA1");
+ memcpy(HashValue.data(), Hash.data(), RawSize);
+}
+
+llvm::StringRef SymbolID::raw() const {
+ return StringRef(reinterpret_cast<const char *>(HashValue.data()), RawSize);
+}
+
+SymbolID SymbolID::fromRaw(StringRef Raw) {
+ SymbolID ID;
+ assert(Raw.size() == RawSize);
+ memcpy(ID.HashValue.data(), Raw.data(), RawSize);
+ return ID;
+}
+
+std::string SymbolID::str() const { return toHex(raw()); }
+
+Expected<SymbolID> SymbolID::fromStr(StringRef Str) {
+ if (Str.size() != RawSize * 2)
+ return createStringError(inconvertibleErrorCode(), "Bad ID length");
+ for (char C : Str)
+ if (!isHexDigit(C))
+ return createStringError(inconvertibleErrorCode(), "Bad hex ID");
+ return fromRaw(fromHex(Str));
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolID &ID) {
+ return OS << toHex(ID.raw());
+}
+
+llvm::hash_code hash_value(const SymbolID &ID) {
+ // We already have a good hash, just return the first bytes.
+ assert(sizeof(size_t) <= SymbolID::RawSize && "size_t longer than SHA1!");
+ size_t Result;
+ memcpy(&Result, ID.raw().data(), sizeof(size_t));
+ return llvm::hash_code(Result);
+}
+
+llvm::json::Value toJSON(const SymbolDetails &P) {
+ return json::Object{
+ {"name", P.name},
+ {"containerName", P.containerName},
+ {"usr", P.USR},
+ {"id", P.ID.str()},
+ };
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const SymbolDetails &S) {
+ if (!S.containerName.empty())
+ O << S.containerName << "::";
+ O << S.name << " - " << toJSON(S);
+ return O;
+}
+
bool fromJSON(const json::Value &Params, WorkspaceSymbolParams &R) {
json::ObjectMapper O(Params);
return O && O.map("query", R.query);
Index: ClangdServer.h
===================================================================
--- ClangdServer.h
+++ ClangdServer.h
@@ -201,6 +201,10 @@
/// Called when an event occurs for a watched file in the workspace.
void onFileEvent(const DidChangeWatchedFilesParams &Params);
+ /// Get symbol info for given position.
+ void getSymbolInfo(PathRef File, Position Pos,
+ Callback<llvm::Optional<SymbolDetails>> CB);
+
/// Returns estimated memory usage for each of the currently open files.
/// The order of results is unspecified.
/// Overall memory usage of clangd may be significantly more than reported
Index: ClangdServer.cpp
===================================================================
--- ClangdServer.cpp
+++ ClangdServer.cpp
@@ -517,6 +517,18 @@
WorkScheduler.runWithAST("References", File, Bind(Action, std::move(CB)));
}
+void ClangdServer::getSymbolInfo(PathRef File, Position Pos,
+ Callback<llvm::Optional<SymbolDetails>> CB) {
+ auto Action = [Pos](Callback<llvm::Optional<SymbolDetails>> CB,
+ Expected<InputsAndAST> InpAST) {
+ if (!InpAST)
+ return CB(InpAST.takeError());
+ CB(clangd::getSymbolInfo(InpAST->AST, Pos));
+ };
+
+ WorkScheduler.runWithAST("CursorInfo", File, Bind(Action, std::move(CB)));
+}
+
std::vector<std::pair<Path, std::size_t>>
ClangdServer::getUsedBytesPerFile() const {
return WorkScheduler.getUsedBytesPerFile();
Index: ClangdLSPServer.h
===================================================================
--- ClangdLSPServer.h
+++ ClangdLSPServer.h
@@ -88,6 +88,8 @@
void onHover(const TextDocumentPositionParams &,
Callback<llvm::Optional<Hover>>);
void onChangeConfiguration(const DidChangeConfigurationParams &);
+ void onSymbolInfo(const TextDocumentPositionParams &,
+ Callback<llvm::Optional<SymbolDetails>>);
std::vector<Fix> getFixes(StringRef File, const clangd::Diagnostic &D);
Index: ClangdLSPServer.cpp
===================================================================
--- ClangdLSPServer.cpp
+++ ClangdLSPServer.cpp
@@ -685,6 +685,12 @@
std::move(Reply));
}
+void ClangdLSPServer::onSymbolInfo(const TextDocumentPositionParams &Params,
+ Callback<Optional<SymbolDetails>> Reply) {
+ Server->getSymbolInfo(Params.textDocument.uri.file(), Params.position,
+ std::move(Reply));
+}
+
ClangdLSPServer::ClangdLSPServer(class Transport &Transp,
const clangd::CodeCompleteOptions &CCOpts,
Optional<Path> CompileCommandsDir,
@@ -719,6 +725,7 @@
MsgHandler->bind("textDocument/didChange", &ClangdLSPServer::onDocumentDidChange);
MsgHandler->bind("workspace/didChangeWatchedFiles", &ClangdLSPServer::onFileEvent);
MsgHandler->bind("workspace/didChangeConfiguration", &ClangdLSPServer::onChangeConfiguration);
+ MsgHandler->bind("textDocument/symbolInfo", &ClangdLSPServer::onSymbolInfo);
// clang-format on
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits