Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 41 additions & 23 deletions clang-tools-extra/clangd/ClangdLSPServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,8 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params,
SupportsHierarchicalDocumentSymbol =
Params.capabilities.HierarchicalDocumentSymbol;
SupportsReferenceContainer = Params.capabilities.ReferenceContainer;
SupportsReferenceTags = Params.capabilities.ReferenceTagsSupport;
SupportsReferenceItems = Params.capabilities.ReferenceItemsSupport;
SupportFileStatus = Params.initializationOptions.FileStatus;
SupportsDocumentChanges = Params.capabilities.DocumentChanges;
SupportsChangeAnnotation = Params.capabilities.ChangeAnnotation;
Expand Down Expand Up @@ -1389,7 +1391,8 @@ void ClangdLSPServer::onPrepareCallHierarchy(
void ClangdLSPServer::onCallHierarchyIncomingCalls(
const CallHierarchyIncomingCallsParams &Params,
Callback<std::vector<CallHierarchyIncomingCall>> Reply) {
Server->incomingCalls(Params.item, std::move(Reply));
Server->incomingCalls(Params.item.uri.file(), Params.item,
SupportsReferenceTags, std::move(Reply));
}

void ClangdLSPServer::onClangdInlayHints(const InlayHintsParams &Params,
Expand Down Expand Up @@ -1434,7 +1437,8 @@ void ClangdLSPServer::onInlayHint(const InlayHintsParams &Params,
void ClangdLSPServer::onCallHierarchyOutgoingCalls(
const CallHierarchyOutgoingCallsParams &Params,
Callback<std::vector<CallHierarchyOutgoingCall>> Reply) {
Server->outgoingCalls(Params.item, std::move(Reply));
Server->outgoingCalls(Params.item.uri.file(), Params.item,
SupportsReferenceTags, std::move(Reply));
}

void ClangdLSPServer::applyConfiguration(
Expand Down Expand Up @@ -1479,27 +1483,41 @@ void ClangdLSPServer::onChangeConfiguration(
applyConfiguration(Params.settings);
}

void ClangdLSPServer::onReference(
const ReferenceParams &Params,
Callback<std::vector<ReferenceLocation>> Reply) {
Server->findReferences(Params.textDocument.uri.file(), Params.position,
Opts.ReferencesLimit, SupportsReferenceContainer,
[Reply = std::move(Reply),
IncludeDecl(Params.context.includeDeclaration)](
llvm::Expected<ReferencesResult> Refs) mutable {
if (!Refs)
return Reply(Refs.takeError());
// Filter out declarations if the client asked.
std::vector<ReferenceLocation> Result;
Result.reserve(Refs->References.size());
for (auto &Ref : Refs->References) {
bool IsDecl =
Ref.Attributes & ReferencesResult::Declaration;
if (IncludeDecl || !IsDecl)
Result.push_back(std::move(Ref.Loc));
}
return Reply(std::move(Result));
});
void ClangdLSPServer::onReference(const ReferenceParams &Params,
Callback<llvm::json::Value> Reply) {
Server->findReferences(
Params.textDocument.uri.file(), Params.position, Opts.ReferencesLimit,
SupportsReferenceContainer,
/*ComputeReferenceTags=*/SupportsReferenceItems,
[Reply = std::move(Reply), IncludeDecl(Params.context.includeDeclaration),
ReturnReferenceItems(SupportsReferenceItems)](
llvm::Expected<ReferencesResult> Refs) mutable {
if (!Refs)
return Reply(Refs.takeError());
// Filter out declarations if the client asked.
if (ReturnReferenceItems) {
std::vector<Reference> Result;
Result.reserve(Refs->References.size());
for (auto &Ref : Refs->References) {
bool IsDecl = Ref.Attributes & ReferencesResult::Declaration;
if (!(IncludeDecl || !IsDecl))
continue;
Reference Item;
Item.location = std::move(Ref.Loc);
Item.referenceTags = std::move(Ref.ReferenceTags);
Result.push_back(std::move(Item));
}
return Reply(std::move(Result));
}
std::vector<ReferenceLocation> Result;
Result.reserve(Refs->References.size());
for (auto &Ref : Refs->References) {
bool IsDecl = Ref.Attributes & ReferencesResult::Declaration;
if (IncludeDecl || !IsDecl)
Result.push_back(std::move(Ref.Loc));
}
return Reply(std::move(Result));
});
}

void ClangdLSPServer::onGoToType(const TextDocumentPositionParams &Params,
Expand Down
7 changes: 6 additions & 1 deletion clang-tools-extra/clangd/ClangdLSPServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class ClangdLSPServer : private ClangdServer::Callbacks,
Callback<std::vector<Location>>);
void onGoToImplementation(const TextDocumentPositionParams &,
Callback<std::vector<Location>>);
void onReference(const ReferenceParams &, Callback<std::vector<ReferenceLocation>>);
void onReference(const ReferenceParams &, Callback<llvm::json::Value>);
void onSwitchSourceHeader(const TextDocumentIdentifier &,
Callback<std::optional<URIForFile>>);
void onDocumentHighlight(const TextDocumentPositionParams &,
Expand Down Expand Up @@ -299,6 +299,11 @@ class ClangdLSPServer : private ClangdServer::Callbacks,
bool SupportFileStatus = false;
/// Whether the client supports attaching a container string to references.
bool SupportsReferenceContainer = false;
/// Whether the client supports reference tags on hierarchy/reference items.
bool SupportsReferenceTags = false;
/// Whether the client supports and prefers LSP 3.18 Reference[] results
/// for textDocument/references.
bool SupportsReferenceItems = false;
/// Which kind of markup should we use in textDocument/hover responses.
MarkupKind HoverContentFormat = MarkupKind::PlainText;
/// Whether the client supports offsets for parameter info labels.
Expand Down
46 changes: 33 additions & 13 deletions clang-tools-extra/clangd/ClangdServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -912,12 +912,15 @@ void ClangdServer::prepareCallHierarchy(
}

void ClangdServer::incomingCalls(
const CallHierarchyItem &Item,
PathRef File, const CallHierarchyItem &Item, bool ComputeReferenceTags,
Callback<std::vector<CallHierarchyIncomingCall>> CB) {
WorkScheduler->run("Incoming Calls", "",
[CB = std::move(CB), Item, this]() mutable {
CB(clangd::incomingCalls(Item, Index));
});
auto Action = [Item, ComputeReferenceTags, CB = std::move(CB),
this](llvm::Expected<InputsAndAST> InpAST) mutable {
if (!InpAST)
return CB(InpAST.takeError());
CB(clangd::incomingCalls(Item, Index, InpAST->AST, ComputeReferenceTags));
};
WorkScheduler->runWithAST("Incoming Calls", File, std::move(Action));
}

void ClangdServer::inlayHints(PathRef File, std::optional<Range> RestrictRange,
Expand All @@ -932,12 +935,27 @@ void ClangdServer::inlayHints(PathRef File, std::optional<Range> RestrictRange,
}

void ClangdServer::outgoingCalls(
const CallHierarchyItem &Item,
PathRef File, const CallHierarchyItem &Item, bool ComputeReferenceTags,
Callback<std::vector<CallHierarchyOutgoingCall>> CB) {
WorkScheduler->run("Outgoing Calls", "",
[CB = std::move(CB), Item, this]() mutable {
CB(clangd::outgoingCalls(Item, Index));
});
if (!ComputeReferenceTags) {
// Fast path: reference tags are not requested, so no AST is needed.
// Dispatch as an index-only task to avoid unnecessary parse latency.
WorkScheduler->run(
"Outgoing Calls", "", [Item, CB = std::move(CB), this]() mutable {
CB(clangd::outgoingCalls(Item, Index,
/*AST=*/nullptr,
/*ComputeReferenceTags=*/false));
});
return;
}
auto Action = [Item, CB = std::move(CB),
this](llvm::Expected<InputsAndAST> InpAST) mutable {
if (!InpAST)
return CB(InpAST.takeError());
CB(clangd::outgoingCalls(Item, Index, &InpAST->AST,
/*ComputeReferenceTags=*/true));
};
WorkScheduler->runWithAST("Outgoing Calls", File, std::move(Action));
}

void ClangdServer::onFileEvent(const DidChangeWatchedFilesParams &Params) {
Expand Down Expand Up @@ -1008,13 +1026,15 @@ void ClangdServer::findImplementations(
}

void ClangdServer::findReferences(PathRef File, Position Pos, uint32_t Limit,
bool AddContainer,
bool AddContainer, bool ComputeReferenceTags,
Callback<ReferencesResult> CB) {
auto Action = [Pos, Limit, AddContainer, CB = std::move(CB),
auto Action = [Pos, Limit, AddContainer, ComputeReferenceTags,
CB = std::move(CB),
this](llvm::Expected<InputsAndAST> InpAST) mutable {
if (!InpAST)
return CB(InpAST.takeError());
CB(clangd::findReferences(InpAST->AST, Pos, Limit, Index, AddContainer));
CB(clangd::findReferences(InpAST->AST, Pos, Limit, Index, AddContainer,
ComputeReferenceTags));
};

WorkScheduler->runWithAST("References", File, std::move(Action));
Expand Down
9 changes: 6 additions & 3 deletions clang-tools-extra/clangd/ClangdServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,11 +302,13 @@ class ClangdServer {
Callback<std::vector<CallHierarchyItem>> CB);

/// Resolve incoming calls for a given call hierarchy item.
void incomingCalls(const CallHierarchyItem &Item,
void incomingCalls(PathRef File, const CallHierarchyItem &Item,
bool ComputeReferenceTags,
Callback<std::vector<CallHierarchyIncomingCall>>);

/// Resolve outgoing calls for a given call hierarchy item.
void outgoingCalls(const CallHierarchyItem &Item,
void outgoingCalls(PathRef File, const CallHierarchyItem &Item,
bool ComputeReferenceTags,
Callback<std::vector<CallHierarchyOutgoingCall>>);

/// Resolve inlay hints for a given document.
Expand Down Expand Up @@ -334,7 +336,8 @@ class ClangdServer {

/// Retrieve locations for symbol references.
void findReferences(PathRef File, Position Pos, uint32_t Limit,
bool AddContainer, Callback<ReferencesResult> CB);
bool AddContainer, bool ComputeReferenceTags,
Callback<ReferencesResult> CB);

/// Run formatting for the \p File with content \p Code.
/// If \p Rng is non-empty, formats only those regions.
Expand Down
25 changes: 23 additions & 2 deletions clang-tools-extra/clangd/Protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,13 @@ llvm::json::Value toJSON(const ReferenceLocation &P) {
return Result;
}

llvm::json::Value toJSON(const Reference &R) {
llvm::json::Object Result{{"location", R.location}};
if (!R.referenceTags.empty())
Result["referenceTags"] = R.referenceTags;
return Result;
}

llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
const ReferenceLocation &L) {
return OS << L.range << '@' << L.uri << " (container: " << L.containerName
Expand Down Expand Up @@ -209,7 +216,7 @@ bool fromJSON(const llvm::json::Value &Params, ChangeAnnotation &R,
O.map("needsConfirmation", R.needsConfirmation) &&
O.mapOptional("description", R.description);
}
llvm::json::Value toJSON(const ChangeAnnotation & CA) {
llvm::json::Value toJSON(const ChangeAnnotation &CA) {
llvm::json::Object Result{{"label", CA.label}};
if (CA.needsConfirmation)
Result["needsConfirmation"] = *CA.needsConfirmation;
Expand Down Expand Up @@ -398,9 +405,16 @@ bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R,
if (auto RelatedInfo = Diagnostics->getBoolean("relatedInformation"))
R.DiagnosticRelatedInformation = *RelatedInfo;
}
if (auto *References = TextDocument->getObject("references"))
if (auto *References = TextDocument->getObject("references")) {
if (auto ContainerSupport = References->getBoolean("container"))
R.ReferenceContainer = *ContainerSupport;
if (auto ItemsSupport = References->getBoolean("referenceItemsSupport"))
R.ReferenceItemsSupport = *ItemsSupport;
}
if (auto *CallHierarchy = TextDocument->getObject("callHierarchy")) {
if (auto TagsSupport = CallHierarchy->getBoolean("referenceTagsSupport"))
R.ReferenceTagsSupport = *TagsSupport;
}
if (auto *Completion = TextDocument->getObject("completion")) {
if (auto *Item = Completion->getObject("completionItem")) {
if (auto SnippetSupport = Item->getBoolean("snippetSupport"))
Expand Down Expand Up @@ -1488,6 +1502,10 @@ llvm::json::Value toJSON(SymbolTag Tag) {
return llvm::json::Value(static_cast<int>(Tag));
}

llvm::json::Value toJSON(ReferenceTag Tag) {
return llvm::json::Value(static_cast<int>(Tag));
}

llvm::json::Value toJSON(const CallHierarchyItem &I) {
llvm::json::Object Result{{"name", I.name},
{"kind", static_cast<int>(I.kind)},
Expand All @@ -1500,6 +1518,9 @@ llvm::json::Value toJSON(const CallHierarchyItem &I) {
Result["detail"] = I.detail;
if (!I.data.empty())
Result["data"] = I.data;
if (!I.referenceTags.empty())
Result["referenceTags"] = I.referenceTags;

return std::move(Result);
}

Expand Down
37 changes: 37 additions & 0 deletions clang-tools-extra/clangd/Protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
namespace clang {
namespace clangd {

enum class ReferenceTag;

enum class ErrorCode {
// Defined by JSON RPC.
ParseError = -32700,
Expand Down Expand Up @@ -238,6 +240,16 @@ struct ReferenceLocation : Location {
llvm::json::Value toJSON(const ReferenceLocation &);
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ReferenceLocation &);

/// LSP 3.18 reference item used by textDocument/references when supported.
struct Reference {
/// The location of this reference.
Location location;

/// Optional, one or more tags describing this reference.
std::vector<ReferenceTag> referenceTags;
};
llvm::json::Value toJSON(const Reference &);

using ChangeAnnotationIdentifier = std::string;
// A combination of a LSP standard TextEdit and AnnotatedTextEdit.
struct TextEdit {
Expand Down Expand Up @@ -405,6 +417,13 @@ enum class SymbolKind {
Operator = 25,
TypeParameter = 26
};

/// Tags describing the reference kind.
enum class ReferenceTag {
Read = 1,
Write = 2,
};

bool fromJSON(const llvm::json::Value &, SymbolKind &, llvm::json::Path);
constexpr auto SymbolKindMin = static_cast<size_t>(SymbolKind::File);
constexpr auto SymbolKindMax = static_cast<size_t>(SymbolKind::TypeParameter);
Expand Down Expand Up @@ -568,6 +587,21 @@ struct ClientCapabilities {
/// notification. This is a clangd extension.
/// textDocument.inactiveRegionsCapabilities.inactiveRegions
bool InactiveRegions = false;

/// Determines whether the client supports reference tags on call hierarchy
/// items. If the value is missing, the server assumes that the client does
/// not support reference tags.
/// textDocument.callHierarchy.referenceTagsSupport
/// @since 3.18.0
bool ReferenceTagsSupport = false;

/// Determines whether the client supports and prefers Reference items instead
/// of Location items. If this value is missing, the server assumes that the
/// client accepts Location items as defined in earlier versions of the
/// protocol.
/// textDocument.references.referenceItemsSupport
/// @since 3.18.0
bool ReferenceItemsSupport = false;
};
bool fromJSON(const llvm::json::Value &, ClientCapabilities &,
llvm::json::Path);
Expand Down Expand Up @@ -1622,6 +1656,9 @@ struct CallHierarchyItem {
/// Tags for this item.
std::vector<SymbolTag> tags;

/// The tags describing reference kinds of this item.
std::vector<ReferenceTag> referenceTags;

/// More detaill for this item, e.g. the signature of a function.
std::string detail;

Expand Down
Loading