[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:
Ilya Biryukov 2017-12-12 12:27:47 +00:00
parent b0783cccb7
commit 0e6a51f4f3
13 changed files with 315 additions and 46 deletions

View File

@ -57,6 +57,7 @@ void ClangdLSPServer::onInitialize(Ctx C, InitializeParams &Params) {
{"triggerCharacters", {"(", ","}}, {"triggerCharacters", {"(", ","}},
}}, }},
{"definitionProvider", true}, {"definitionProvider", true},
{"documentHighlightProvider", true},
{"renameProvider", true}, {"renameProvider", true},
{"executeCommandProvider", {"executeCommandProvider",
json::obj{ json::obj{
@ -235,6 +236,22 @@ void ClangdLSPServer::onSwitchSourceHeader(Ctx C,
C.reply(Result ? URI::fromFile(*Result).uri : ""); 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, ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, unsigned AsyncThreadsCount,
bool StorePreamblesInMemory, bool StorePreamblesInMemory,
const clangd::CodeCompleteOptions &CCOpts, const clangd::CodeCompleteOptions &CCOpts,

View File

@ -69,6 +69,7 @@ private:
void onSignatureHelp(Ctx C, TextDocumentPositionParams &Params) override; void onSignatureHelp(Ctx C, TextDocumentPositionParams &Params) override;
void onGoToDefinition(Ctx C, TextDocumentPositionParams &Params) override; void onGoToDefinition(Ctx C, TextDocumentPositionParams &Params) override;
void onSwitchSourceHeader(Ctx C, TextDocumentIdentifier &Params) override; void onSwitchSourceHeader(Ctx C, TextDocumentIdentifier &Params) override;
void onDocumentHighlight(Ctx C, TextDocumentPositionParams &Params) override;
void onFileEvent(Ctx C, DidChangeWatchedFilesParams &Params) override; void onFileEvent(Ctx C, DidChangeWatchedFilesParams &Params) override;
void onCommand(Ctx C, ExecuteCommandParams &Params) override; void onCommand(Ctx C, ExecuteCommandParams &Params) override;
void onRename(Ctx C, RenameParams &Parames) override; void onRename(Ctx C, RenameParams &Parames) override;

View File

@ -509,6 +509,39 @@ llvm::Optional<Path> ClangdServer::switchSourceHeader(PathRef Path) {
return llvm::None; 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( std::future<void> ClangdServer::scheduleReparseAndDiags(
PathRef File, VersionedDraft Contents, std::shared_ptr<CppFile> Resources, PathRef File, VersionedDraft Contents, std::shared_ptr<CppFile> Resources,
Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS) { Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS) {

View File

@ -210,8 +210,7 @@ public:
ClangdServer(GlobalCompilationDatabase &CDB, ClangdServer(GlobalCompilationDatabase &CDB,
DiagnosticsConsumer &DiagConsumer, DiagnosticsConsumer &DiagConsumer,
FileSystemProvider &FSProvider, unsigned AsyncThreadsCount, FileSystemProvider &FSProvider, unsigned AsyncThreadsCount,
bool StorePreamblesInMemory, bool StorePreamblesInMemory, clangd::Logger &Logger,
clangd::Logger &Logger,
llvm::Optional<StringRef> ResourceDir = llvm::None); llvm::Optional<StringRef> ResourceDir = llvm::None);
/// Set the root path of the workspace. /// Set the root path of the workspace.
@ -286,6 +285,10 @@ public:
/// given a header file and vice versa. /// given a header file and vice versa.
llvm::Optional<Path> switchSourceHeader(PathRef Path); 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. /// Run formatting for \p Rng inside \p File.
std::vector<tooling::Replacement> formatRange(PathRef File, Range Rng); std::vector<tooling::Replacement> formatRange(PathRef File, Range Rng);
/// Run formatting for the whole \p File. /// Run formatting for the whole \p File.

View File

@ -222,26 +222,34 @@ SourceLocation getMacroArgExpandedLocation(const SourceManager &Mgr,
} }
/// Finds declarations locations that a given source location refers to. /// Finds declarations locations that a given source location refers to.
class DeclarationLocationsFinder : public index::IndexDataConsumer { class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
std::vector<Location> DeclarationLocations; std::vector<const Decl *> Decls;
std::vector<const MacroInfo *> MacroInfos;
const SourceLocation &SearchedLocation; const SourceLocation &SearchedLocation;
const ASTContext &AST; const ASTContext &AST;
Preprocessor &PP; Preprocessor &PP;
public: public:
DeclarationLocationsFinder(raw_ostream &OS, DeclarationAndMacrosFinder(raw_ostream &OS,
const SourceLocation &SearchedLocation, const SourceLocation &SearchedLocation,
ASTContext &AST, Preprocessor &PP) ASTContext &AST, Preprocessor &PP)
: SearchedLocation(SearchedLocation), AST(AST), PP(PP) {} : SearchedLocation(SearchedLocation), AST(AST), PP(PP) {}
std::vector<Location> takeLocations() { std::vector<const Decl *> takeDecls() {
// Don't keep the same location multiple times. // Don't keep the same declaration multiple times.
// This can happen when nodes in the AST are visited twice. // This can happen when nodes in the AST are visited twice.
std::sort(DeclarationLocations.begin(), DeclarationLocations.end()); std::sort(Decls.begin(), Decls.end());
auto last = auto Last = std::unique(Decls.begin(), Decls.end());
std::unique(DeclarationLocations.begin(), DeclarationLocations.end()); Decls.erase(Last, Decls.end());
DeclarationLocations.erase(last, DeclarationLocations.end()); return std::move(Decls);
return std::move(DeclarationLocations); }
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 bool
@ -249,9 +257,8 @@ public:
ArrayRef<index::SymbolRelation> Relations, FileID FID, ArrayRef<index::SymbolRelation> Relations, FileID FID,
unsigned Offset, unsigned Offset,
index::IndexDataConsumer::ASTNodeInfo ASTNode) override { index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
if (isSearchedLocation(FID, Offset)) { if (isSearchedLocation(FID, Offset))
addDeclarationLocation(D->getSourceRange()); Decls.push_back(D);
}
return true; return true;
} }
@ -262,31 +269,6 @@ private:
SourceMgr.getFileID(SearchedLocation) == FID; 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 { void finish() override {
// Also handle possible macro at the searched location. // Also handle possible macro at the searched location.
Token Result; Token Result;
@ -309,16 +291,111 @@ private:
PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation); PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation);
MacroInfo *MacroInf = MacroDef.getMacroInfo(); MacroInfo *MacroInf = MacroDef.getMacroInfo();
if (MacroInf) { if (MacroInf) {
addDeclarationLocation(SourceRange(MacroInf->getDefinitionLoc(), MacroInfos.push_back(MacroInf);
MacroInf->getDefinitionEndLoc()));
} }
} }
} }
} }
}; };
/// 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 } // 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, std::vector<Location> clangd::findDefinitions(ParsedAST &AST, Position Pos,
clangd::Logger &Logger) { clangd::Logger &Logger) {
const SourceManager &SourceMgr = AST.getASTContext().getSourceManager(); 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); SourceLocation SourceLocationBeg = getBeginningOfIdentifier(AST, Pos, FE);
auto DeclLocationsFinder = std::make_shared<DeclarationLocationsFinder>( auto DeclMacrosFinder = std::make_shared<DeclarationAndMacrosFinder>(
llvm::errs(), SourceLocationBeg, AST.getASTContext(), llvm::errs(), SourceLocationBeg, AST.getASTContext(),
AST.getPreprocessor()); AST.getPreprocessor());
index::IndexingOptions IndexOpts; index::IndexingOptions IndexOpts;
@ -337,9 +414,60 @@ std::vector<Location> clangd::findDefinitions(ParsedAST &AST, Position Pos,
IndexOpts.IndexFunctionLocals = true; IndexOpts.IndexFunctionLocals = true;
indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(), 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() { void ParsedAST::ensurePreambleDeclsDeserialized() {

View File

@ -256,7 +256,6 @@ private:
clangd::Logger &Logger; clangd::Logger &Logger;
}; };
/// Get the beginning SourceLocation at a specified \p Pos. /// Get the beginning SourceLocation at a specified \p Pos.
SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos, SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos,
const FileEntry *FE); const FileEntry *FE);
@ -265,6 +264,9 @@ SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos,
std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos, std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
clangd::Logger &Logger); clangd::Logger &Logger);
std::vector<DocumentHighlight>
findDocumentHighlights(ParsedAST &AST, Position Pos, clangd::Logger &Logger);
/// For testing/debugging purposes. Note that this method deserializes all /// For testing/debugging purposes. Note that this method deserializes all
/// unserialized Decls, so use with care. /// unserialized Decls, so use with care.
void dumpAST(ParsedAST &AST, llvm::raw_ostream &OS); void dumpAST(ParsedAST &AST, llvm::raw_ostream &OS);

View File

@ -359,5 +359,12 @@ bool fromJSON(const json::Expr &Params, RenameParams &R) {
O.map("position", R.position) && O.map("newName", R.newName); 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 clangd
} // namespace clang } // namespace clang

View File

@ -557,6 +557,36 @@ struct RenameParams {
}; };
bool fromJSON(const json::Expr &, 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 clangd
} // namespace clang } // namespace clang

View File

@ -72,4 +72,6 @@ void clangd::registerCallbackHandlers(JSONRPCDispatcher &Dispatcher,
Register("textDocument/rename", &ProtocolCallbacks::onRename); Register("textDocument/rename", &ProtocolCallbacks::onRename);
Register("workspace/didChangeWatchedFiles", &ProtocolCallbacks::onFileEvent); Register("workspace/didChangeWatchedFiles", &ProtocolCallbacks::onFileEvent);
Register("workspace/executeCommand", &ProtocolCallbacks::onCommand); Register("workspace/executeCommand", &ProtocolCallbacks::onCommand);
Register("textDocument/documentHighlight",
&ProtocolCallbacks::onDocumentHighlight);
} }

View File

@ -54,6 +54,8 @@ public:
virtual void onFileEvent(Ctx C, DidChangeWatchedFilesParams &Params) = 0; virtual void onFileEvent(Ctx C, DidChangeWatchedFilesParams &Params) = 0;
virtual void onCommand(Ctx C, ExecuteCommandParams &Params) = 0; virtual void onCommand(Ctx C, ExecuteCommandParams &Params) = 0;
virtual void onRename(Ctx C, RenameParams &Parames) = 0; virtual void onRename(Ctx C, RenameParams &Parames) = 0;
virtual void onDocumentHighlight(Ctx C,
TextDocumentPositionParams &Params) = 0;
}; };
void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, JSONOutput &Out, void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, JSONOutput &Out,

View File

@ -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"}

View File

@ -20,6 +20,7 @@ Content-Length: 142
# CHECK-NEXT: }, # CHECK-NEXT: },
# CHECK-NEXT: "definitionProvider": true, # CHECK-NEXT: "definitionProvider": true,
# CHECK-NEXT: "documentFormattingProvider": true, # CHECK-NEXT: "documentFormattingProvider": true,
# CHECK-NEXT: "documentHighlightProvider": true,
# CHECK-NEXT: "documentOnTypeFormattingProvider": { # CHECK-NEXT: "documentOnTypeFormattingProvider": {
# CHECK-NEXT: "firstTriggerCharacter": "}", # CHECK-NEXT: "firstTriggerCharacter": "}",
# CHECK-NEXT: "moreTriggerCharacter": [] # CHECK-NEXT: "moreTriggerCharacter": []

View File

@ -20,6 +20,7 @@ Content-Length: 143
# CHECK-NEXT: }, # CHECK-NEXT: },
# CHECK-NEXT: "definitionProvider": true, # CHECK-NEXT: "definitionProvider": true,
# CHECK-NEXT: "documentFormattingProvider": true, # CHECK-NEXT: "documentFormattingProvider": true,
# CHECK-NEXT: "documentHighlightProvider": true,
# CHECK-NEXT: "documentOnTypeFormattingProvider": { # CHECK-NEXT: "documentOnTypeFormattingProvider": {
# CHECK-NEXT: "firstTriggerCharacter": "}", # CHECK-NEXT: "firstTriggerCharacter": "}",
# CHECK-NEXT: "moreTriggerCharacter": [] # CHECK-NEXT: "moreTriggerCharacter": []