forked from OSchip/llvm-project
[clangd] Document highlights for clangd
Summary: Implementation of Document Highlights Request as described in LSP. Contributed by William Enright (nebiroth). Reviewers: malaperle, krasimir, bkramer, ilya-biryukov Reviewed By: malaperle Subscribers: mgrang, sammccall, klimek, ioeric, rwols, cfe-commits, arphaman, ilya-biryukov Differential Revision: https://reviews.llvm.org/D38425 llvm-svn: 320474
This commit is contained in:
parent
b0783cccb7
commit
0e6a51f4f3
|
@ -57,6 +57,7 @@ void ClangdLSPServer::onInitialize(Ctx C, InitializeParams &Params) {
|
|||
{"triggerCharacters", {"(", ","}},
|
||||
}},
|
||||
{"definitionProvider", true},
|
||||
{"documentHighlightProvider", true},
|
||||
{"renameProvider", true},
|
||||
{"executeCommandProvider",
|
||||
json::obj{
|
||||
|
@ -235,6 +236,22 @@ void ClangdLSPServer::onSwitchSourceHeader(Ctx C,
|
|||
C.reply(Result ? URI::fromFile(*Result).uri : "");
|
||||
}
|
||||
|
||||
void ClangdLSPServer::onDocumentHighlight(Ctx C,
|
||||
TextDocumentPositionParams &Params) {
|
||||
|
||||
auto Highlights = Server.findDocumentHighlights(
|
||||
Params.textDocument.uri.file,
|
||||
Position{Params.position.line, Params.position.character});
|
||||
|
||||
if (!Highlights) {
|
||||
C.replyError(ErrorCode::InternalError,
|
||||
llvm::toString(Highlights.takeError()));
|
||||
return;
|
||||
}
|
||||
|
||||
C.reply(json::ary(Highlights->Value));
|
||||
}
|
||||
|
||||
ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, unsigned AsyncThreadsCount,
|
||||
bool StorePreamblesInMemory,
|
||||
const clangd::CodeCompleteOptions &CCOpts,
|
||||
|
|
|
@ -69,6 +69,7 @@ private:
|
|||
void onSignatureHelp(Ctx C, TextDocumentPositionParams &Params) override;
|
||||
void onGoToDefinition(Ctx C, TextDocumentPositionParams &Params) override;
|
||||
void onSwitchSourceHeader(Ctx C, TextDocumentIdentifier &Params) override;
|
||||
void onDocumentHighlight(Ctx C, TextDocumentPositionParams &Params) override;
|
||||
void onFileEvent(Ctx C, DidChangeWatchedFilesParams &Params) override;
|
||||
void onCommand(Ctx C, ExecuteCommandParams &Params) override;
|
||||
void onRename(Ctx C, RenameParams &Parames) override;
|
||||
|
|
|
@ -509,6 +509,39 @@ llvm::Optional<Path> ClangdServer::switchSourceHeader(PathRef Path) {
|
|||
return llvm::None;
|
||||
}
|
||||
|
||||
llvm::Expected<Tagged<std::vector<DocumentHighlight>>>
|
||||
ClangdServer::findDocumentHighlights(PathRef File, Position Pos) {
|
||||
auto FileContents = DraftMgr.getDraft(File);
|
||||
if (!FileContents.Draft)
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
"findDocumentHighlights called on non-added file",
|
||||
llvm::errc::invalid_argument);
|
||||
|
||||
auto TaggedFS = FSProvider.getTaggedFileSystem(File);
|
||||
|
||||
std::shared_ptr<CppFile> Resources = Units.getFile(File);
|
||||
if (!Resources)
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
"findDocumentHighlights called on non-added file",
|
||||
llvm::errc::invalid_argument);
|
||||
|
||||
std::vector<DocumentHighlight> Result;
|
||||
llvm::Optional<llvm::Error> Err;
|
||||
Resources->getAST().get()->runUnderLock([Pos, &Result, &Err,
|
||||
this](ParsedAST *AST) {
|
||||
if (!AST) {
|
||||
Err = llvm::make_error<llvm::StringError>("Invalid AST",
|
||||
llvm::errc::invalid_argument);
|
||||
return;
|
||||
}
|
||||
Result = clangd::findDocumentHighlights(*AST, Pos, Logger);
|
||||
});
|
||||
|
||||
if (Err)
|
||||
return std::move(*Err);
|
||||
return make_tagged(Result, TaggedFS.Tag);
|
||||
}
|
||||
|
||||
std::future<void> ClangdServer::scheduleReparseAndDiags(
|
||||
PathRef File, VersionedDraft Contents, std::shared_ptr<CppFile> Resources,
|
||||
Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS) {
|
||||
|
|
|
@ -210,8 +210,7 @@ public:
|
|||
ClangdServer(GlobalCompilationDatabase &CDB,
|
||||
DiagnosticsConsumer &DiagConsumer,
|
||||
FileSystemProvider &FSProvider, unsigned AsyncThreadsCount,
|
||||
bool StorePreamblesInMemory,
|
||||
clangd::Logger &Logger,
|
||||
bool StorePreamblesInMemory, clangd::Logger &Logger,
|
||||
llvm::Optional<StringRef> ResourceDir = llvm::None);
|
||||
|
||||
/// Set the root path of the workspace.
|
||||
|
@ -286,6 +285,10 @@ public:
|
|||
/// given a header file and vice versa.
|
||||
llvm::Optional<Path> switchSourceHeader(PathRef Path);
|
||||
|
||||
/// Get document highlights for a given position.
|
||||
llvm::Expected<Tagged<std::vector<DocumentHighlight>>>
|
||||
findDocumentHighlights(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.
|
||||
|
|
|
@ -222,26 +222,34 @@ SourceLocation getMacroArgExpandedLocation(const SourceManager &Mgr,
|
|||
}
|
||||
|
||||
/// Finds declarations locations that a given source location refers to.
|
||||
class DeclarationLocationsFinder : public index::IndexDataConsumer {
|
||||
std::vector<Location> DeclarationLocations;
|
||||
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() {
|
||||
// Don't keep the same location multiple times.
|
||||
std::vector<const Decl *> takeDecls() {
|
||||
// Don't keep the same declaration 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 std::move(Decls);
|
||||
}
|
||||
|
||||
std::vector<const MacroInfo *> takeMacroInfos() {
|
||||
// Don't keep the same Macro info multiple times.
|
||||
std::sort(MacroInfos.begin(), MacroInfos.end());
|
||||
auto Last = std::unique(MacroInfos.begin(), MacroInfos.end());
|
||||
MacroInfos.erase(Last, MacroInfos.end());
|
||||
return std::move(MacroInfos);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -249,9 +257,8 @@ public:
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -262,31 +269,6 @@ private:
|
|||
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;
|
||||
|
@ -309,16 +291,111 @@ private:
|
|||
PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation);
|
||||
MacroInfo *MacroInf = MacroDef.getMacroInfo();
|
||||
if (MacroInf) {
|
||||
addDeclarationLocation(SourceRange(MacroInf->getDefinitionLoc(),
|
||||
MacroInf->getDefinitionEndLoc()));
|
||||
MacroInfos.push_back(MacroInf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Finds document highlights that a given list of declarations refers to.
|
||||
class DocumentHighlightsFinder : public index::IndexDataConsumer {
|
||||
std::vector<const Decl *> &Decls;
|
||||
std::vector<DocumentHighlight> DocumentHighlights;
|
||||
const ASTContext &AST;
|
||||
|
||||
public:
|
||||
DocumentHighlightsFinder(raw_ostream &OS, ASTContext &AST, Preprocessor &PP,
|
||||
std::vector<const Decl *> &Decls)
|
||||
: Decls(Decls), AST(AST) {}
|
||||
std::vector<DocumentHighlight> takeHighlights() {
|
||||
// Don't keep the same highlight multiple times.
|
||||
// This can happen when nodes in the AST are visited twice.
|
||||
std::sort(DocumentHighlights.begin(), DocumentHighlights.end());
|
||||
auto Last =
|
||||
std::unique(DocumentHighlights.begin(), DocumentHighlights.end());
|
||||
DocumentHighlights.erase(Last, DocumentHighlights.end());
|
||||
return std::move(DocumentHighlights);
|
||||
}
|
||||
|
||||
bool
|
||||
handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
|
||||
ArrayRef<index::SymbolRelation> Relations, FileID FID,
|
||||
unsigned Offset,
|
||||
index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
|
||||
const SourceManager &SourceMgr = AST.getSourceManager();
|
||||
if (SourceMgr.getMainFileID() != FID ||
|
||||
std::find(Decls.begin(), Decls.end(), D) == Decls.end()) {
|
||||
return true;
|
||||
}
|
||||
SourceLocation Begin, End;
|
||||
const LangOptions &LangOpts = AST.getLangOpts();
|
||||
SourceLocation StartOfFileLoc = SourceMgr.getLocForStartOfFile(FID);
|
||||
SourceLocation HightlightStartLoc = StartOfFileLoc.getLocWithOffset(Offset);
|
||||
End =
|
||||
Lexer::getLocForEndOfToken(HightlightStartLoc, 0, SourceMgr, LangOpts);
|
||||
SourceRange SR(HightlightStartLoc, End);
|
||||
|
||||
DocumentHighlightKind Kind = DocumentHighlightKind::Text;
|
||||
if (static_cast<index::SymbolRoleSet>(index::SymbolRole::Write) & Roles)
|
||||
Kind = DocumentHighlightKind::Write;
|
||||
else if (static_cast<index::SymbolRoleSet>(index::SymbolRole::Read) & Roles)
|
||||
Kind = DocumentHighlightKind::Read;
|
||||
|
||||
DocumentHighlights.push_back(getDocumentHighlight(SR, Kind));
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
DocumentHighlight getDocumentHighlight(SourceRange SR,
|
||||
DocumentHighlightKind Kind) {
|
||||
const SourceManager &SourceMgr = AST.getSourceManager();
|
||||
SourceLocation LocStart = SR.getBegin();
|
||||
Position Begin;
|
||||
Begin.line = SourceMgr.getSpellingLineNumber(LocStart) - 1;
|
||||
Begin.character = SourceMgr.getSpellingColumnNumber(LocStart) - 1;
|
||||
Position End;
|
||||
End.line = SourceMgr.getSpellingLineNumber(SR.getEnd()) - 1;
|
||||
End.character = SourceMgr.getSpellingColumnNumber(SR.getEnd()) - 1;
|
||||
Range R = {Begin, End};
|
||||
DocumentHighlight DH;
|
||||
DH.range = R;
|
||||
DH.kind = Kind;
|
||||
return DH;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
llvm::Optional<Location>
|
||||
getDeclarationLocation(ParsedAST &AST, const SourceRange &ValSourceRange) {
|
||||
const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
|
||||
const LangOptions &LangOpts = AST.getASTContext().getLangOpts();
|
||||
SourceLocation LocStart = ValSourceRange.getBegin();
|
||||
|
||||
const FileEntry *F =
|
||||
SourceMgr.getFileEntryForID(SourceMgr.getFileID(LocStart));
|
||||
if (!F)
|
||||
return llvm::None;
|
||||
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;
|
||||
|
||||
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();
|
||||
|
@ -328,7 +405,7 @@ std::vector<Location> clangd::findDefinitions(ParsedAST &AST, Position Pos,
|
|||
|
||||
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;
|
||||
|
@ -337,9 +414,60 @@ std::vector<Location> clangd::findDefinitions(ParsedAST &AST, Position Pos,
|
|||
IndexOpts.IndexFunctionLocals = true;
|
||||
|
||||
indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
|
||||
DeclLocationsFinder, IndexOpts);
|
||||
DeclMacrosFinder, IndexOpts);
|
||||
|
||||
return DeclLocationsFinder->takeLocations();
|
||||
std::vector<const Decl *> Decls = DeclMacrosFinder->takeDecls();
|
||||
std::vector<const MacroInfo *> MacroInfos =
|
||||
DeclMacrosFinder->takeMacroInfos();
|
||||
std::vector<Location> Result;
|
||||
|
||||
for (auto Item : Decls) {
|
||||
auto L = getDeclarationLocation(AST, Item->getSourceRange());
|
||||
if (L)
|
||||
Result.push_back(*L);
|
||||
}
|
||||
|
||||
for (auto Item : MacroInfos) {
|
||||
SourceRange SR(Item->getDefinitionLoc(), Item->getDefinitionEndLoc());
|
||||
auto L = getDeclarationLocation(AST, SR);
|
||||
if (L)
|
||||
Result.push_back(*L);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::vector<DocumentHighlight>
|
||||
clangd::findDocumentHighlights(ParsedAST &AST, Position Pos,
|
||||
clangd::Logger &Logger) {
|
||||
const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
|
||||
const FileEntry *FE = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
|
||||
if (!FE)
|
||||
return {};
|
||||
|
||||
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;
|
||||
|
||||
// Macro occurences are not currently handled.
|
||||
indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
|
||||
DeclMacrosFinder, IndexOpts);
|
||||
|
||||
std::vector<const Decl *> SelectedDecls = DeclMacrosFinder->takeDecls();
|
||||
|
||||
auto DocHighlightsFinder = std::make_shared<DocumentHighlightsFinder>(
|
||||
llvm::errs(), AST.getASTContext(), AST.getPreprocessor(), SelectedDecls);
|
||||
|
||||
indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
|
||||
DocHighlightsFinder, IndexOpts);
|
||||
|
||||
return DocHighlightsFinder->takeHighlights();
|
||||
}
|
||||
|
||||
void ParsedAST::ensurePreambleDeclsDeserialized() {
|
||||
|
|
|
@ -256,7 +256,6 @@ private:
|
|||
clangd::Logger &Logger;
|
||||
};
|
||||
|
||||
|
||||
/// Get the beginning SourceLocation at a specified \p Pos.
|
||||
SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos,
|
||||
const FileEntry *FE);
|
||||
|
@ -265,6 +264,9 @@ SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos,
|
|||
std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
|
||||
clangd::Logger &Logger);
|
||||
|
||||
std::vector<DocumentHighlight>
|
||||
findDocumentHighlights(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);
|
||||
|
|
|
@ -359,5 +359,12 @@ bool fromJSON(const json::Expr &Params, RenameParams &R) {
|
|||
O.map("position", R.position) && O.map("newName", R.newName);
|
||||
}
|
||||
|
||||
json::Expr toJSON(const DocumentHighlight &DH) {
|
||||
return json::obj{
|
||||
{"range", toJSON(DH.range)},
|
||||
{"kind", static_cast<int>(DH.kind)},
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace clangd
|
||||
} // namespace clang
|
||||
|
|
|
@ -557,6 +557,36 @@ struct RenameParams {
|
|||
};
|
||||
bool fromJSON(const json::Expr &, RenameParams &);
|
||||
|
||||
enum class DocumentHighlightKind { Text = 1, Read = 2, Write = 3 };
|
||||
|
||||
/// A document highlight is a range inside a text document which deserves
|
||||
/// special attention. Usually a document highlight is visualized by changing
|
||||
/// the background color of its range.
|
||||
|
||||
struct DocumentHighlight {
|
||||
|
||||
/// The range this highlight applies to.
|
||||
|
||||
Range range;
|
||||
|
||||
/// The highlight kind, default is DocumentHighlightKind.Text.
|
||||
|
||||
DocumentHighlightKind kind = DocumentHighlightKind::Text;
|
||||
|
||||
friend bool operator<(const DocumentHighlight &LHS,
|
||||
const DocumentHighlight &RHS) {
|
||||
int LHSKind = static_cast<int>(LHS.kind);
|
||||
int RHSKind = static_cast<int>(RHS.kind);
|
||||
return std::tie(LHS.range, LHSKind) < std::tie(RHS.range, RHSKind);
|
||||
}
|
||||
|
||||
friend bool operator==(const DocumentHighlight &LHS,
|
||||
const DocumentHighlight &RHS) {
|
||||
return LHS.kind == RHS.kind && LHS.range == RHS.range;
|
||||
}
|
||||
};
|
||||
json::Expr toJSON(const DocumentHighlight &DH);
|
||||
|
||||
} // namespace clangd
|
||||
} // namespace clang
|
||||
|
||||
|
|
|
@ -72,4 +72,6 @@ void clangd::registerCallbackHandlers(JSONRPCDispatcher &Dispatcher,
|
|||
Register("textDocument/rename", &ProtocolCallbacks::onRename);
|
||||
Register("workspace/didChangeWatchedFiles", &ProtocolCallbacks::onFileEvent);
|
||||
Register("workspace/executeCommand", &ProtocolCallbacks::onCommand);
|
||||
Register("textDocument/documentHighlight",
|
||||
&ProtocolCallbacks::onDocumentHighlight);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,8 @@ public:
|
|||
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 onDocumentHighlight(Ctx C,
|
||||
TextDocumentPositionParams &Params) = 0;
|
||||
};
|
||||
|
||||
void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, JSONOutput &Out,
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
# 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: 479
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"#define MACRO 1\nnamespace ns1 {\nstruct MyClass {\nint xasd;\nvoid anotherOperation() {\n}\nstatic int foo(MyClass*) {\nreturn 0;\n}\n\n};\nstruct Foo {\nint xasd;\n};\n}\nint main() {\nint bonjour;\nbonjour = 2;\nint test1 = bonjour;\nns1::Foo bar = { xasd : 1};\nbar.xasd = 3;\nns1::MyClass* Params;\nParams->anotherOperation();\n}\n"}}}
|
||||
|
||||
Content-Length: 156
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/documentHighlight","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":17,"character":2}}}
|
||||
# Verify local variable
|
||||
# CHECK: {"id":1,"jsonrpc":"2.0","result":[{"kind":1,"range":{"end":{"character":11,"line":16},"start":{"character":4,"line":16}}},{"kind":3,"range":{"end":{"character":7,"line":17},"start":{"character":0,"line":17}}},{"kind":2,"range":{"end":{"character":19,"line":18},"start":{"character":12,"line":18}}}]}
|
||||
|
||||
Content-Length: 157
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/documentHighlight","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":18,"character":17}}}
|
||||
# Verify struct highlight
|
||||
# CHECK: {"id":1,"jsonrpc":"2.0","result":[{"kind":1,"range":{"end":{"character":11,"line":16},"start":{"character":4,"line":16}}},{"kind":3,"range":{"end":{"character":7,"line":17},"start":{"character":0,"line":17}}},{"kind":2,"range":{"end":{"character":19,"line":18},"start":{"character":12,"line":18}}}]}
|
||||
|
||||
Content-Length: 157
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/documentHighlight","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":21,"character":10}}}
|
||||
# Verify method highlight
|
||||
# CHECK: {"id":1,"jsonrpc":"2.0","result":[{"kind":1,"range":{"end":{"character":14,"line":2},"start":{"character":7,"line":2}}},{"kind":1,"range":{"end":{"character":22,"line":6},"start":{"character":15,"line":6}}},{"kind":1,"range":{"end":{"character":12,"line":21},"start":{"character":5,"line":21}}}]}
|
||||
|
||||
Content-Length: 157
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/documentHighlight","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":18,"character":14}}}
|
||||
# Verify Read-access of a symbol (kind = 2)
|
||||
# CHECK: {"id":1,"jsonrpc":"2.0","result":[{"kind":1,"range":{"end":{"character":11,"line":16},"start":{"character":4,"line":16}}},{"kind":3,"range":{"end":{"character":7,"line":17},"start":{"character":0,"line":17}}},{"kind":2,"range":{"end":{"character":19,"line":18},"start":{"character":12,"line":18}}}]}
|
||||
|
||||
Content-Length: 48
|
||||
|
||||
{"jsonrpc":"2.0","id":10000,"method":"shutdown"}
|
||||
|
||||
Content-Length: 33
|
||||
|
||||
{"jsonrpc":"2.0":"method":"exit"}
|
|
@ -20,6 +20,7 @@ Content-Length: 142
|
|||
# CHECK-NEXT: },
|
||||
# CHECK-NEXT: "definitionProvider": true,
|
||||
# CHECK-NEXT: "documentFormattingProvider": true,
|
||||
# CHECK-NEXT: "documentHighlightProvider": true,
|
||||
# CHECK-NEXT: "documentOnTypeFormattingProvider": {
|
||||
# CHECK-NEXT: "firstTriggerCharacter": "}",
|
||||
# CHECK-NEXT: "moreTriggerCharacter": []
|
||||
|
|
|
@ -20,6 +20,7 @@ Content-Length: 143
|
|||
# CHECK-NEXT: },
|
||||
# CHECK-NEXT: "definitionProvider": true,
|
||||
# CHECK-NEXT: "documentFormattingProvider": true,
|
||||
# CHECK-NEXT: "documentHighlightProvider": true,
|
||||
# CHECK-NEXT: "documentOnTypeFormattingProvider": {
|
||||
# CHECK-NEXT: "firstTriggerCharacter": "}",
|
||||
# CHECK-NEXT: "moreTriggerCharacter": []
|
||||
|
|
Loading…
Reference in New Issue