Nebiroth updated this revision to Diff 124833.
Nebiroth added a comment.
Herald added a subscriber: klimek.
Invalid FileEntries now return llvm:ErrorOr
Repository:
rCTE Clang Tools Extra
https://reviews.llvm.org/D35894
Files:
clangd/ClangdLSPServer.cpp
clangd/ClangdLSPServer.h
clangd/ClangdServer.cpp
clangd/ClangdServer.h
clangd/ClangdUnit.cpp
clangd/ClangdUnit.h
clangd/Protocol.cpp
clangd/Protocol.h
clangd/ProtocolHandlers.cpp
clangd/ProtocolHandlers.h
test/clangd/hover.test
test/clangd/initialize-params-invalid.test
test/clangd/initialize-params.test
Index: test/clangd/initialize-params.test
===================================================================
--- test/clangd/initialize-params.test
+++ test/clangd/initialize-params.test
@@ -30,6 +30,7 @@
# CHECK-NEXT: "clangd.applyFix"
# CHECK-NEXT: ]
# CHECK-NEXT: },
+# CHECK-NEXT: "hoverProvider": true,
# CHECK-NEXT: "renameProvider": true,
# CHECK-NEXT: "signatureHelpProvider": {
# CHECK-NEXT: "triggerCharacters": [
Index: test/clangd/initialize-params-invalid.test
===================================================================
--- test/clangd/initialize-params-invalid.test
+++ test/clangd/initialize-params-invalid.test
@@ -30,6 +30,7 @@
# CHECK-NEXT: "clangd.applyFix"
# CHECK-NEXT: ]
# CHECK-NEXT: },
+# CHECK-NEXT: "hoverProvider": true,
# CHECK-NEXT: "renameProvider": true,
# CHECK-NEXT: "signatureHelpProvider": {
# CHECK-NEXT: "triggerCharacters": [
Index: test/clangd/hover.test
===================================================================
--- /dev/null
+++ test/clangd/hover.test
@@ -0,0 +1,56 @@
+# RUN: clangd -run-synchronously < %s | FileCheck %s
+# It is absolutely vital that this file has CRLF line endings.
+#
+Content-Length: 125
+
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+
+Content-Length: 611
+
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"#define MACRO 1\nnamespace ns1 {\nint test = 5;\nstruct MyClass {\nint xasd;\nvoid anotherOperation() {\n}\nstatic int foo(MyClass*) {\nreturn 0;\n}\n\n};}\n//comments test\ntemplate<class T>\nT templateTest(T foo) {\nreturn foo;}\ntemplate<classT>\nclass classTemplateTest {\npublic: T test;};\nint main() {\nint a;\na;\nint b = ns1::test;\nns1::MyClass* Params;\nParams->anotherOperation();\nMACRO;\nint temp = 5;\ntemplateTest(temp);classTemplateTest<int> test;}\n"}}}
+
+Content-Length: 144
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":0,"character":12}}}
+# CHECK: {"id":1,"jsonrpc":"2.0","result":{"contents":[{"language":"C++","value":"#define MACRO 1"}],"range":{"end":{"character":15,"line":0},"start":{"character":8,"line":0}}}}
+
+Content-Length: 144
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":21,"character":1}}}
+# CHECK: {"id":1,"jsonrpc":"2.0","result":{"contents":[{"language":"C++","value":"int a"}],"range":{"end":{"character":5,"line":20},"start":{"character":0,"line":20}}}}
+
+Content-Length: 145
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":22,"character":15}}}
+# CHECK: {"id":1,"jsonrpc":"2.0","result":{"contents":[{"language":"C++","value":"In ns1"},{"language":"C++","value":"int test = 5"}],"range":{"end":{"character":12,"line":2},"start":{"character":0,"line":2}}}}
+
+Content-Length: 145
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":23,"character":10}}}
+# CHECK: {"id":1,"jsonrpc":"2.0","result":{"contents":[{"language":"C++","value":"In ns1"},{"language":"C++","value":"struct MyClass {"}],"range":{"end":{"character":16,"line":3},"start":{"character":0,"line":3}}}}
+
+Content-Length: 145
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":24,"character":13}}}
+# CHECK: {"id":1,"jsonrpc":"2.0","result":{"contents":[{"language":"C++","value":"In ns1::MyClass"},{"language":"C++","value":"void anotherOperation() {"}],"range":{"end":{"character":25,"line":5},"start":{"character":0,"line":5}}}}
+
+Content-Length: 144
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":25,"character":1}}}
+# CHECK: {"id":1,"jsonrpc":"2.0","result":{"contents":[{"language":"C++","value":"#define MACRO 1"}],"range":{"end":{"character":15,"line":0},"start":{"character":8,"line":0}}}}
+
+Content-Length: 144
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":26,"character":8}}}
+# CHECK: {"id":1,"jsonrpc":"2.0","result":{"contents":[{"language":"C++","value":"int temp = 5"}],"range":{"end":{"character":12,"line":26},"start":{"character":0,"line":26}}}}
+
+Content-Length: 144
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":27,"character":1}}}
+# CHECK: {"id":1,"jsonrpc":"2.0","result":{"contents":[{"language":"C++","value":"//comments test\ntemplate<class T>\nT templateTest(T foo) {"}],"range":{"end":{"character":23,"line":14},"start":{"character":0,"line":12}}}}
+
+Content-Length: 44
+
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+
+
Index: clangd/ProtocolHandlers.h
===================================================================
--- clangd/ProtocolHandlers.h
+++ clangd/ProtocolHandlers.h
@@ -54,6 +54,7 @@
virtual void onFileEvent(Ctx C, DidChangeWatchedFilesParams &Params) = 0;
virtual void onCommand(Ctx C, ExecuteCommandParams &Params) = 0;
virtual void onRename(Ctx C, RenameParams &Parames) = 0;
+ virtual void onCodeHover(Ctx C, TextDocumentPositionParams &Params) = 0;
};
void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, JSONOutput &Out,
Index: clangd/ProtocolHandlers.cpp
===================================================================
--- clangd/ProtocolHandlers.cpp
+++ clangd/ProtocolHandlers.cpp
@@ -72,6 +72,7 @@
Register("textDocument/switchSourceHeader",
&ProtocolCallbacks::onSwitchSourceHeader);
Register("textDocument/rename", &ProtocolCallbacks::onRename);
+ Register("textDocument/hover", &ProtocolCallbacks::onCodeHover);
Register("workspace/didChangeWatchedFiles", &ProtocolCallbacks::onFileEvent);
Register("workspace/executeCommand", &ProtocolCallbacks::onCommand);
}
Index: clangd/Protocol.h
===================================================================
--- clangd/Protocol.h
+++ clangd/Protocol.h
@@ -23,7 +23,7 @@
#include "JSONExpr.h"
#include "llvm/ADT/Optional.h"
-#include <string>
+#include "llvm/Support/YAMLParser.h"
#include <vector>
namespace clang {
@@ -431,6 +431,49 @@
parse(const json::Expr &Params);
};
+struct MarkedString {
+
+ /// MarkedString can be used to render human readable text. It is either a
+ /// markdown string
+ /// or a code-block that provides a language and a code snippet. The language
+ /// identifier
+ /// is sematically equal to the optional language identifier in fenced code
+ /// blocks in GitHub
+ /// issues. See
+ /// https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
+ ///
+ /// The pair of a language and a value is an equivalent to markdown:
+ /// ```
+ /// ${language}
+ /// ${value}
+ /// ```
+ ///
+ /// Note that markdown strings will be sanitized - that means html will be
+ /// escaped.
+
+ std::string markdownString;
+ std::string language;
+ std::string codeBlockValue;
+
+ static json::Expr unparse(const MarkedString &MS);
+};
+
+struct Hover {
+
+ /**
+ * The hover's content
+ */
+ std::vector<MarkedString> contents;
+
+ /**
+ * An optional range is a range inside a text document
+ * that is used to visualize a hover, e.g. by changing the background color.
+ */
+ llvm::Optional<Range> range;
+
+ static json::Expr unparse(const Hover &H);
+};
+
/// The kind of a completion entry.
enum class CompletionItemKind {
Missing = 0,
Index: clangd/Protocol.cpp
===================================================================
--- clangd/Protocol.cpp
+++ clangd/Protocol.cpp
@@ -487,6 +487,28 @@
return R;
}
+json::Expr Hover::unparse(const Hover &H) {
+ if (H.range.hasValue()) {
+ return json::obj{
+ {"contents", json::ary(H.contents)},
+ {"range", H.range.getValue()},
+ };
+ } else {
+ // Default Hover values
+ Hover H;
+ return json::obj{
+ {"contents", json::ary(H.contents)},
+ };
+ }
+}
+
+json::Expr MarkedString::unparse(const MarkedString &MS) {
+ return json::obj{
+ {"language", MS.language},
+ {"value", MS.codeBlockValue},
+ };
+}
+
json::Expr CompletionItem::unparse(const CompletionItem &CI) {
assert(!CI.label.empty() && "completion item label is required");
json::obj Result{{"label", CI.label}};
Index: clangd/ClangdUnit.h
===================================================================
--- clangd/ClangdUnit.h
+++ clangd/ClangdUnit.h
@@ -315,6 +315,8 @@
std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
clangd::Logger &Logger);
+Hover getHover(ParsedAST &AST, Position Pos, clangd::Logger &Logger);
+
/// For testing/debugging purposes. Note that this method deserializes all
/// unserialized Decls, so use with care.
void dumpAST(ParsedAST &AST, llvm::raw_ostream &OS);
Index: clangd/ClangdUnit.cpp
===================================================================
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -27,6 +27,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/Errc.h"
#include "llvm/Support/Format.h"
#include <algorithm>
@@ -209,6 +210,7 @@
// EndSourceFile), but that won't happen if DisableFree is set to true.
// Since createInvocationFromCommandLine sets it to true, we have to override
// it.
+ CI->LangOpts->CommentOpts.ParseAllComments = true;
CI->getFrontendOpts().DisableFree = false;
return CI;
}
@@ -933,37 +935,46 @@
return Mgr.getMacroArgExpandedLocation(InputLoc);
}
-/// Finds declarations locations that a given source location refers to.
-class DeclarationLocationsFinder : public index::IndexDataConsumer {
- std::vector<Location> DeclarationLocations;
+/// Finds declarations and macros that a given source location refers to.
+class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
+ std::vector<const Decl *> Decls;
+ std::vector<const MacroInfo *> MacroInfos;
const SourceLocation &SearchedLocation;
const ASTContext &AST;
Preprocessor &PP;
public:
- DeclarationLocationsFinder(raw_ostream &OS,
+ DeclarationAndMacrosFinder(raw_ostream &OS,
const SourceLocation &SearchedLocation,
ASTContext &AST, Preprocessor &PP)
: SearchedLocation(SearchedLocation), AST(AST), PP(PP) {}
- std::vector<Location> takeLocations() {
+ std::vector<const Decl *> takeDecls() {
// Don't keep the same location multiple times.
// This can happen when nodes in the AST are visited twice.
- std::sort(DeclarationLocations.begin(), DeclarationLocations.end());
- auto last =
- std::unique(DeclarationLocations.begin(), DeclarationLocations.end());
- DeclarationLocations.erase(last, DeclarationLocations.end());
- return std::move(DeclarationLocations);
+ std::sort(Decls.begin(), Decls.end());
+ auto Last = std::unique(Decls.begin(), Decls.end());
+ Decls.erase(Last, Decls.end());
+ return Decls;
+ }
+
+ std::vector<const MacroInfo *> takeMacroInfos() {
+ // Don't keep the same Macro info multiple times.
+ // This can happen when nodes in the AST are visited twice.
+ std::sort(MacroInfos.begin(), MacroInfos.end());
+ auto Last = std::unique(MacroInfos.begin(), MacroInfos.end());
+ MacroInfos.erase(Last, MacroInfos.end());
+ return MacroInfos;
}
bool
handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
ArrayRef<index::SymbolRelation> Relations, FileID FID,
unsigned Offset,
index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
- if (isSearchedLocation(FID, Offset)) {
- addDeclarationLocation(D->getSourceRange());
- }
+
+ if (isSearchedLocation(FID, Offset))
+ Decls.push_back(D);
return true;
}
@@ -974,31 +985,6 @@
SourceMgr.getFileID(SearchedLocation) == FID;
}
- void addDeclarationLocation(const SourceRange &ValSourceRange) {
- const SourceManager &SourceMgr = AST.getSourceManager();
- const LangOptions &LangOpts = AST.getLangOpts();
- SourceLocation LocStart = ValSourceRange.getBegin();
- SourceLocation LocEnd = Lexer::getLocForEndOfToken(ValSourceRange.getEnd(),
- 0, SourceMgr, LangOpts);
- Position Begin;
- Begin.line = SourceMgr.getSpellingLineNumber(LocStart) - 1;
- Begin.character = SourceMgr.getSpellingColumnNumber(LocStart) - 1;
- Position End;
- End.line = SourceMgr.getSpellingLineNumber(LocEnd) - 1;
- End.character = SourceMgr.getSpellingColumnNumber(LocEnd) - 1;
- Range R = {Begin, End};
- Location L;
- if (const FileEntry *F =
- SourceMgr.getFileEntryForID(SourceMgr.getFileID(LocStart))) {
- StringRef FilePath = F->tryGetRealPathName();
- if (FilePath.empty())
- FilePath = F->getName();
- L.uri = URI::fromFile(FilePath);
- L.range = R;
- DeclarationLocations.push_back(L);
- }
- }
-
void finish() override {
// Also handle possible macro at the searched location.
Token Result;
@@ -1021,16 +1007,99 @@
PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation);
MacroInfo *MacroInf = MacroDef.getMacroInfo();
if (MacroInf) {
- addDeclarationLocation(SourceRange(MacroInf->getDefinitionLoc(),
- MacroInf->getDefinitionEndLoc()));
+ MacroInfos.push_back(MacroInf);
}
}
}
}
};
+/// Obtains scope for in which a NamedDecl is contained
+std::string getScope(const NamedDecl *ND, const LangOptions &LangOpts) {
+ // Get the full qualified name, the non-qualified name and then diff
+ // them. If there's something left, use that as the scope in the hover,
+ // trimming the extra "::"
+ std::string Res;
+ PrintingPolicy WithScopePP(LangOpts);
+ std::string WithScopeBuf;
+ llvm::raw_string_ostream WithScopeOS(WithScopeBuf);
+ ND->printQualifiedName(WithScopeOS, WithScopePP);
+
+ std::string ResWithScope = WithScopeOS.str();
+ if (!ResWithScope.empty()) {
+ // Get non-qualified name
+ std::string PrintedNameBuf;
+ llvm::raw_string_ostream PrintedNameOS(PrintedNameBuf);
+ ND->printName(PrintedNameOS);
+ auto Last = ResWithScope.rfind(PrintedNameOS.str());
+ if (Last != std::string::npos) {
+ Res = ResWithScope.substr(0, Last);
+ if (Res.length() > 2 &&
+ Res.substr(Res.length() - 2, Res.length()) == "::")
+ Res = Res.substr(0, Res.length() - 2);
+ }
+ }
+ return Res;
+}
+
+/// Returns the file buffer data that the given SourceRange points to.
+StringRef getBufferDataFromSourceRange(ParsedAST &AST, Location L) {
+ StringRef Ref;
+
+ const FileEntry *FE =
+ AST.getASTContext().getSourceManager().getFileManager().getFile(
+ L.uri.file);
+ if (!FE) {
+ llvm::ErrorOr<StringRef> InvalidFileError = "invalid file!";
+ return InvalidFileError.get();
+ } else {
+ FileID FID = AST.getASTContext().getSourceManager().translateFile(FE);
+ Ref = AST.getASTContext().getSourceManager().getBufferData(FID);
+ unsigned Start = AST.getASTContext().getSourceManager().getFileOffset(
+ AST.getASTContext().getSourceManager().translateFileLineCol(
+ FE, L.range.start.line + 1, L.range.start.character + 1));
+ unsigned End = AST.getASTContext().getSourceManager().getFileOffset(
+ AST.getASTContext().getSourceManager().translateFileLineCol(
+ FE, L.range.end.line + 1, L.range.end.character + 1));
+ Ref = Ref.slice(Start, End);
+ return Ref;
+ }
+}
+
} // namespace
+Location getDeclarationLocation(ParsedAST &AST,
+ const SourceRange &ValSourceRange) {
+ const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
+ const LangOptions &LangOpts = AST.getASTContext().getLangOpts();
+ SourceLocation LocStart = ValSourceRange.getBegin();
+ SourceLocation LocEnd = Lexer::getLocForEndOfToken(ValSourceRange.getEnd(), 0,
+ SourceMgr, LangOpts);
+ Position Begin;
+ Begin.line = SourceMgr.getSpellingLineNumber(LocStart) - 1;
+ Begin.character = SourceMgr.getSpellingColumnNumber(LocStart) - 1;
+ Position End;
+ End.line = SourceMgr.getSpellingLineNumber(LocEnd) - 1;
+ End.character = SourceMgr.getSpellingColumnNumber(LocEnd) - 1;
+ Range R = {Begin, End};
+ Location L;
+
+ const FileEntry *F =
+ SourceMgr.getFileEntryForID(SourceMgr.getFileID(LocStart));
+ if (!F) {
+ llvm::ErrorOr<StringRef> InvalidFileError = "invalid file!";
+ llvm::errs() << InvalidFileError.get();
+ return L;
+ } else {
+ StringRef FilePath = F->tryGetRealPathName();
+ if (FilePath.empty())
+ FilePath = F->getName();
+ L.uri = URI::fromFile(FilePath);
+ L.range = R;
+ }
+ return L;
+}
+
std::vector<Location> clangd::findDefinitions(ParsedAST &AST, Position Pos,
clangd::Logger &Logger) {
const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
@@ -1040,18 +1109,152 @@
SourceLocation SourceLocationBeg = getBeginningOfIdentifier(AST, Pos, FE);
- auto DeclLocationsFinder = std::make_shared<DeclarationLocationsFinder>(
+ auto DeclMacrosFinder = std::make_shared<DeclarationAndMacrosFinder>(
+ llvm::errs(), SourceLocationBeg, AST.getASTContext(),
+ AST.getPreprocessor());
+ index::IndexingOptions IndexOpts;
+ IndexOpts.SystemSymbolFilter =
+ index::IndexingOptions::SystemSymbolFilterKind::All;
+ IndexOpts.IndexFunctionLocals = true;
+
+ indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
+ DeclMacrosFinder, IndexOpts);
+
+ std::vector<const Decl *> Decls = DeclMacrosFinder->takeDecls();
+ std::vector<const MacroInfo *> MacroInfos =
+ DeclMacrosFinder->takeMacroInfos();
+ std::vector<Location> Result;
+
+ for (auto Item : Decls) {
+ Location L = getDeclarationLocation(AST, Item->getSourceRange());
+ Result.push_back(L);
+ }
+
+ for (auto Item : MacroInfos) {
+ SourceRange SR(Item->getDefinitionLoc(), Item->getDefinitionEndLoc());
+ Location L = getDeclarationLocation(AST, SR);
+ Result.push_back(L);
+ }
+
+ return Result;
+}
+
+Hover clangd::getHover(ParsedAST &AST, Position Pos, clangd::Logger &Logger) {
+
+ // Default Hover values
+ Hover H;
+ StringRef HoverText;
+
+ const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
+ const LangOptions &LangOpts = AST.getASTContext().getLangOpts();
+ const FileEntry *FE = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
+ if (!FE)
+ return H;
+
+ SourceLocation SourceLocationBeg = getBeginningOfIdentifier(AST, Pos, FE);
+
+ auto DeclMacrosFinder = std::make_shared<DeclarationAndMacrosFinder>(
llvm::errs(), SourceLocationBeg, AST.getASTContext(),
AST.getPreprocessor());
index::IndexingOptions IndexOpts;
IndexOpts.SystemSymbolFilter =
index::IndexingOptions::SystemSymbolFilterKind::All;
IndexOpts.IndexFunctionLocals = true;
indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
- DeclLocationsFinder, IndexOpts);
+ DeclMacrosFinder, IndexOpts);
+
+ std::vector<const Decl *> DeclVector = DeclMacrosFinder->takeDecls();
+
+ if (!DeclVector.empty()) {
+ const Decl *LocationDecl = DeclVector[0];
+
+ if (LocationDecl) {
+ SourceRange SR = LocationDecl->getSourceRange();
+ SourceLocation NewLocation;
+
+ if (LocationDecl->getDescribedTemplate()) {
+ RawComment *RC = AST.getASTContext().getRawCommentForDeclNoCache(
+ LocationDecl->getDescribedTemplate());
+ if (RC) {
+ NewLocation = RC->getLocStart();
+ } else {
+ NewLocation =
+ LocationDecl->getDescribedTemplate()->getSourceRange().getBegin();
+ }
+ } else {
+ RawComment *RC =
+ AST.getASTContext().getRawCommentForDeclNoCache(LocationDecl);
+ if (RC) {
+ NewLocation = RC->getLocStart();
+ SR =
+ SourceRange(NewLocation, LocationDecl->getSourceRange().getEnd());
+ }
+ }
+ SourceLocation BeginLocation;
+ (NewLocation.isValid()) ? (BeginLocation = NewLocation)
+ : (BeginLocation = SR.getBegin());
+
+ if (auto FuncDecl = dyn_cast<FunctionDecl>(LocationDecl)) {
+ SR =
+ SourceRange(BeginLocation, LocationDecl->getSourceRange().getEnd());
+ if (FuncDecl->isThisDeclarationADefinition() && FuncDecl->getBody())
+ SR = SourceRange(BeginLocation, FuncDecl->getBody()->getLocStart());
+ } else if (auto TagDeclaration = dyn_cast<TagDecl>(LocationDecl)) {
+ if (TagDeclaration->isThisDeclarationADefinition())
+ SR = SourceRange(BeginLocation,
+ TagDeclaration->getBraceRange().getBegin());
+
+ } else if (auto NameDecl = dyn_cast<NamespaceDecl>(LocationDecl)) {
+ SourceLocation BeforeLBraceLoc = Lexer::getLocForEndOfToken(
+ LocationDecl->getLocation(), 0, SourceMgr, LangOpts);
+ if (BeforeLBraceLoc.isValid())
+ SR = SourceRange(NameDecl->getLocStart(), BeforeLBraceLoc);
+
+ } else if (dyn_cast<TypedefDecl>(LocationDecl)) {
+ SR = LocationDecl->getSourceRange();
+ // for everything else in ValueDecl, so lvalues of variables, function
+ // designations and enum constants
+ } else if (dyn_cast<ValueDecl>(LocationDecl)) {
+ SR = LocationDecl->getSourceRange();
+ }
+
+ if (SR.isValid()) {
+ Location L = getDeclarationLocation(AST, SR);
+ H.range = L.range;
+ HoverText = getBufferDataFromSourceRange(AST, L);
+ }
+
+ if (const NamedDecl *NamedD = dyn_cast<NamedDecl>(LocationDecl)) {
+ std::string Res = ::getScope(NamedD, AST.getASTContext().getLangOpts());
+ if (!Res.empty()) {
+ MarkedString Info = {"", "C++", "In " + Res};
+ H.contents.push_back(Info);
+ }
+ }
+ }
+ MarkedString MS = {"", "C++", HoverText};
+ H.contents.push_back(MS);
+ return H;
+ }
+
+ if (!DeclMacrosFinder->takeMacroInfos().empty()) {
+ const MacroInfo *MacroInf = DeclMacrosFinder->takeMacroInfos()[0];
+ if (MacroInf) {
+ SourceRange SR = SourceRange(MacroInf->getDefinitionLoc(),
+ MacroInf->getDefinitionEndLoc());
+ if (SR.isValid()) {
+ Location L = getDeclarationLocation(AST, SR);
+ H.range = L.range;
+ HoverText = getBufferDataFromSourceRange(AST, L);
+ }
+ }
+ MarkedString MS = {"", "C++", "#define " + HoverText.str()};
+ H.contents.push_back(MS);
+ return H;
+ }
- return DeclLocationsFinder->takeLocations();
+ return H;
}
void ParsedAST::ensurePreambleDeclsDeserialized() {
@@ -1299,8 +1502,7 @@
CppFilePreambleCallbacks SerializedDeclsCollector;
auto BuiltPreamble = PrecompiledPreamble::Build(
*CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine, VFS, PCHs,
- /*StoreInMemory=*/That->StorePreamblesInMemory,
- SerializedDeclsCollector);
+ /*StoreInMemory=*/true, SerializedDeclsCollector);
if (BuiltPreamble) {
return std::make_shared<PreambleData>(
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -284,6 +284,8 @@
/// given a header file and vice versa.
llvm::Optional<Path> switchSourceHeader(PathRef Path);
+ llvm::Expected<Tagged<Hover>> findHover(PathRef File, Position Pos);
+
/// Run formatting for \p Rng inside \p File.
std::vector<tooling::Replacement> formatRange(PathRef File, Range Rng);
/// Run formatting for the whole \p File.
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -507,6 +507,23 @@
return llvm::None;
}
+llvm::Expected<Tagged<Hover>> ClangdServer::findHover(PathRef File,
+ Position Pos) {
+ Hover FinalHover;
+ auto TaggedFS = FSProvider.getTaggedFileSystem(File);
+
+ std::shared_ptr<CppFile> Resources = Units.getFile(File);
+ assert(Resources && "Calling findHover on non-added file");
+ Resources->getAST().get()->runUnderLock(
+ [Pos, &FinalHover, this](ParsedAST *AST) {
+ if (!AST)
+ return;
+ FinalHover = clangd::getHover(*AST, Pos, Logger);
+ });
+
+ return make_tagged(std::move(FinalHover), TaggedFS.Tag);
+}
+
std::future<void> ClangdServer::scheduleReparseAndDiags(
PathRef File, VersionedDraft Contents, std::shared_ptr<CppFile> Resources,
Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS) {
Index: clangd/ClangdLSPServer.h
===================================================================
--- clangd/ClangdLSPServer.h
+++ clangd/ClangdLSPServer.h
@@ -72,6 +72,7 @@
void onFileEvent(Ctx C, DidChangeWatchedFilesParams &Params) override;
void onCommand(Ctx C, ExecuteCommandParams &Params) override;
void onRename(Ctx C, RenameParams &Parames) override;
+ void onCodeHover(Ctx C, TextDocumentPositionParams &Params) override;
std::vector<clang::tooling::Replacement>
getFixIts(StringRef File, const clangd::Diagnostic &D);
Index: clangd/ClangdLSPServer.cpp
===================================================================
--- clangd/ClangdLSPServer.cpp
+++ clangd/ClangdLSPServer.cpp
@@ -57,6 +57,7 @@
{"triggerCharacters", {"(", ","}},
}},
{"definitionProvider", true},
+ {"hoverProvider", true},
{"renameProvider", true},
{"executeCommandProvider",
json::obj{
@@ -224,6 +225,7 @@
if (!Items)
return C.replyError(ErrorCode::InvalidParams,
llvm::toString(Items.takeError()));
+
C.reply(json::ary(Items->Value));
}
@@ -234,6 +236,20 @@
C.reply(Result ? URI::fromFile(*Result).uri : "");
}
+void ClangdLSPServer::onCodeHover(Ctx C, TextDocumentPositionParams &Params) {
+
+ auto H = Server.findHover(
+ Params.textDocument.uri.file,
+ Position{Params.position.line, Params.position.character});
+
+ if (!H) {
+ C.replyError(ErrorCode::InternalError, llvm::toString(H.takeError()));
+ return;
+ }
+
+ C.reply(Hover::unparse(H->Value));
+}
+
ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, unsigned AsyncThreadsCount,
bool StorePreamblesInMemory,
const clangd::CodeCompleteOptions &CCOpts,
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits