diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -1363,7 +1363,7 @@ /// descendants. If not defined, the children have not been resolved. llvm::Optional> children; - /// An optional 'data' filed, which can be used to identify a type hierarchy + /// An optional 'data' field, which can be used to identify a type hierarchy /// item in a resolve request. llvm::Optional data; }; @@ -1385,6 +1385,83 @@ bool fromJSON(const llvm::json::Value &, ResolveTypeHierarchyItemParams &, llvm::json::Path); +enum class SymbolTag { Deprecated = 1 }; +llvm::json::Value toJSON(SymbolTag); + +/// Represents programming constructs like functions or constructors +/// in the context of call hierarchy. +struct CallHierarchyItem { + /// The name of this item. + std::string Name; + + /// The kind of this item. + SymbolKind Kind; + + /// Tags for this item. + std::vector Tags; + + /// More detaill for this item, e.g. the signature of a function. + std::string Detail; + + /// The resource identifier of this item. + URIForFile Uri; + + /// The range enclosing this symbol not including leading / trailing + /// whitespace but everything else, e.g. comments and code. + Range Rng; + + /// The range that should be selected and revealed when this symbol + /// is being picked, e.g. the name of a function. + /// Must be contained by `Rng`. + Range SelectionRange; + + /// An optional 'data' field, which can be used to identify a call + /// hierarchy item in an incomingCalls or outgoingCalls request. + llvm::Optional Data; +}; +llvm::json::Value toJSON(const CallHierarchyItem &); +bool fromJSON(const llvm::json::Value &, CallHierarchyItem &, llvm::json::Path); + +/// Represents an incoming call, e.g. a caller of a method or constructor. +struct CallHierarchyIncomingCall { + /// The item that makes the call. + CallHierarchyItem From; + + /// The range at which the calls appear. + /// This is relative to the caller denoted by `From`. + std::vector FromRanges; +}; +llvm::json::Value toJSON(const CallHierarchyIncomingCall &); + +/// Represents an outgoing call, e.g. calling a getter from a method or +/// a method from a constructor etc. +struct CallHierarchyOutgoingCall { + /// The item that is called. + CallHierarchyItem To; + + /// The range at which this item is called. + /// This is the range relative to the caller, and not `To`. + std::vector FromRanges; +}; +llvm::json::Value toJSON(const CallHierarchyOutgoingCall &); + +/// The parameter of a `textDocument/prepareCallHierarchy` request. +struct CallHierarchyPrepareParams : public TextDocumentPositionParams {}; + +/// The parameter of a `callHierarchy/incomingCalls` request. +struct CallHierarchyIncomingCallsParams { + CallHierarchyItem Item; +}; +bool fromJSON(const llvm::json::Value &, CallHierarchyIncomingCallsParams &, + llvm::json::Path); + +/// The parameter of a `callHierarchy/outgoingCalls` request. +struct CallHierarchyOutgoingCallsParams { + CallHierarchyItem Item; +}; +bool fromJSON(const llvm::json::Value &, CallHierarchyOutgoingCallsParams &, + llvm::json::Path); + struct ReferenceParams : public TextDocumentPositionParams { // For now, no options like context.includeDeclaration are supported. }; diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -1203,6 +1203,54 @@ return fromJSON(Params, Base, P); } +llvm::json::Value toJSON(SymbolTag Tag) { + return llvm::json::Value{static_cast(Tag)}; +} + +llvm::json::Value toJSON(const CallHierarchyItem &I) { + llvm::json::Object Result{ + {"name", I.Name}, {"kind", static_cast(I.Kind)}, + {"tags", I.Tags}, {"detail", I.Detail}, + {"range", I.Rng}, {"selectionRange", I.SelectionRange}, + {"uri", I.Uri}}; + if (I.Data) + Result["data"] = I.Data; + return std::move(Result); +} + +bool fromJSON(const llvm::json::Value &Params, CallHierarchyItem &I, + llvm::json::Path P) { + llvm::json::ObjectMapper O(Params, P); + + // Populate the required fields only. We don't care about the + // optional fields `Tags` and `Detail` for the purpose of + // client --> server communication. + return O && O.map("name", I.Name) && O.map("kind", I.Kind) && + O.map("uri", I.Uri) && O.map("range", I.Rng) && + O.map("selectionRange", I.SelectionRange) && + O.mapOptional("data", I.Data); +} + +llvm::json::Value toJSON(const CallHierarchyIncomingCall &C) { + return llvm::json::Object{{"from", C.From}, {"fromRanges", C.FromRanges}}; +} + +llvm::json::Value toJSON(const CallHierarchyOutgoingCall &C) { + return llvm::json::Object{{"from", C.To}, {"fromRanges", C.FromRanges}}; +} + +bool fromJSON(const llvm::json::Value &Params, + CallHierarchyIncomingCallsParams &C, llvm::json::Path P) { + llvm::json::ObjectMapper O(Params, P); + return O.map("item", C.Item); +} + +bool fromJSON(const llvm::json::Value &Params, + CallHierarchyOutgoingCallsParams &C, llvm::json::Path P) { + llvm::json::ObjectMapper O(Params, P); + return O.map("item", C.Item); +} + static const char *toString(OffsetEncoding OE) { switch (OE) { case OffsetEncoding::UTF8: