kadircet updated this revision to Diff 198457.
kadircet marked 2 inline comments as done.
kadircet added a comment.
I will start adding test cases(and most likely change the way I populate the
struct at some places) if everyone is happy with current representation for
`HoverInfo`.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D61497/new/
https://reviews.llvm.org/D61497
Files:
clang-tools-extra/clangd/ClangdLSPServer.cpp
clang-tools-extra/clangd/ClangdServer.cpp
clang-tools-extra/clangd/ClangdServer.h
clang-tools-extra/clangd/XRefs.cpp
clang-tools-extra/clangd/XRefs.h
clang-tools-extra/clangd/unittests/XRefsTests.cpp
Index: clang-tools-extra/clangd/unittests/XRefsTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -1185,7 +1185,9 @@
auto AST = TU.build();
if (auto H = getHover(AST, T.point())) {
EXPECT_NE("", Test.ExpectedHover) << Test.Input;
- EXPECT_EQ(H->contents.value, Test.ExpectedHover.str()) << Test.Input;
+ EXPECT_EQ(H->render().contents.value, Test.ExpectedHover.str())
+ << Test.Input << '\n'
+ << H;
} else
EXPECT_EQ("", Test.ExpectedHover.str()) << Test.Input;
}
Index: clang-tools-extra/clangd/XRefs.h
===================================================================
--- clang-tools-extra/clangd/XRefs.h
+++ clang-tools-extra/clangd/XRefs.h
@@ -16,7 +16,10 @@
#include "ClangdUnit.h"
#include "Protocol.h"
#include "index/Index.h"
+#include "index/SymbolLocation.h"
+#include "clang/Index/IndexSymbol.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/Support/raw_ostream.h"
#include <vector>
namespace clang {
@@ -46,8 +49,40 @@
std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
Position Pos);
+struct HoverInfo {
+ using Type = std::string;
+ struct Param {
+ // For template template params it holds the whole template decl, e.g,
+ // "template<typename> class".
+ // For type-template params will contain "typename" or "class".
+ Type T;
+ std::string Name;
+ std::string Default;
+ };
+
+ LocatedSymbol Sym;
+ /// Fully qualiffied name for the scope containing the Sym.
+ std::string Scope;
+ std::string ParentScope;
+ SymbolKind Kind;
+ std::string Documentation;
+ /// Line containing the definition of the symbol.
+ std::string Definition;
+
+ /// T and ReturnType are mutually exclusive.
+ llvm::Optional<Type> T;
+ llvm::Optional<Type> ReturnType;
+ llvm::Optional<std::vector<Param>> Parameters;
+ llvm::Optional<std::vector<Param>> TemplateParameters;
+
+ /// Lower to LSP struct.
+ Hover render() const;
+};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const HoverInfo::Param &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const HoverInfo &);
+
/// Get the hover information when hovering at \p Pos.
-llvm::Optional<Hover> getHover(ParsedAST &AST, Position Pos);
+llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos);
/// Returns reference locations of the symbol at a specified \p Pos.
/// \p Limit limits the number of results returned (0 means no limit).
Index: clang-tools-extra/clangd/XRefs.cpp
===================================================================
--- clang-tools-extra/clangd/XRefs.cpp
+++ clang-tools-extra/clangd/XRefs.cpp
@@ -7,21 +7,32 @@
//===----------------------------------------------------------------------===//
#include "XRefs.h"
#include "AST.h"
+#include "CodeCompletionStrings.h"
#include "FindSymbols.h"
#include "Logger.h"
+#include "Protocol.h"
#include "SourceCode.h"
#include "URI.h"
#include "index/Merge.h"
#include "index/SymbolCollector.h"
#include "index/SymbolLocation.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Type.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Index/IndexDataConsumer.h"
#include "clang/Index/IndexSymbol.h"
#include "clang/Index/IndexingAction.h"
#include "clang/Index/USRGeneration.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
namespace clang {
namespace clangd {
@@ -241,17 +252,17 @@
return {DeclMacrosFinder.getFoundDecls(), DeclMacrosFinder.takeMacroInfos()};
}
-Range getTokenRange(ParsedAST &AST, SourceLocation TokLoc) {
- const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
- SourceLocation LocEnd = Lexer::getLocForEndOfToken(
- TokLoc, 0, SourceMgr, AST.getASTContext().getLangOpts());
+Range getTokenRange(ASTContext &AST, SourceLocation TokLoc) {
+ const SourceManager &SourceMgr = AST.getSourceManager();
+ SourceLocation LocEnd =
+ Lexer::getLocForEndOfToken(TokLoc, 0, SourceMgr, AST.getLangOpts());
return {sourceLocToPosition(SourceMgr, TokLoc),
sourceLocToPosition(SourceMgr, LocEnd)};
}
-llvm::Optional<Location> makeLocation(ParsedAST &AST, SourceLocation TokLoc,
+llvm::Optional<Location> makeLocation(ASTContext &AST, SourceLocation TokLoc,
llvm::StringRef TUPath) {
- const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
+ const SourceManager &SourceMgr = AST.getSourceManager();
const FileEntry *F = SourceMgr.getFileEntryForID(SourceMgr.getFileID(TokLoc));
if (!F)
return None;
@@ -299,8 +310,8 @@
// As a consequence, there's no need to look them up in the index either.
std::vector<LocatedSymbol> Result;
for (auto M : Symbols.Macros) {
- if (auto Loc =
- makeLocation(AST, M.Info->getDefinitionLoc(), *MainFilePath)) {
+ if (auto Loc = makeLocation(AST.getASTContext(), M.Info->getDefinitionLoc(),
+ *MainFilePath)) {
LocatedSymbol Macro;
Macro.Name = M.Name;
Macro.PreferredDeclaration = *Loc;
@@ -320,7 +331,7 @@
// Emit all symbol locations (declaration or definition) from AST.
for (const Decl *D : Symbols.Decls) {
- auto Loc = makeLocation(AST, findNameLoc(D), *MainFilePath);
+ auto Loc = makeLocation(AST.getASTContext(), findNameLoc(D), *MainFilePath);
if (!Loc)
continue;
@@ -453,7 +464,7 @@
std::vector<DocumentHighlight> Result;
for (const auto &Ref : References) {
DocumentHighlight DH;
- DH.range = getTokenRange(AST, Ref.Loc);
+ DH.range = getTokenRange(AST.getASTContext(), Ref.Loc);
if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
DH.kind = DocumentHighlightKind::Write;
else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
@@ -525,54 +536,208 @@
return None;
}
-/// Generate a \p Hover object given the declaration \p D.
-static Hover getHoverContents(const Decl *D) {
- Hover H;
- llvm::Optional<std::string> NamedScope = getScopeName(D);
+static QualType getDeclType(const Decl *D) {
+ if (const TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(D))
+ return TDD->getUnderlyingType();
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ return VD->getType();
+ if (const TagDecl *TD = dyn_cast<TagDecl>(D))
+ return TD->getTypeForDecl()->getCanonicalTypeInternal();
+ return QualType();
+}
- // Generate the "Declared in" section.
- if (NamedScope) {
- assert(!NamedScope->empty());
+static llvm::Optional<Location> getDeclLoc(const SourceLocation &SL,
+ ASTContext &AST) {
+ if (SL.isInvalid())
+ return llvm::None;
+ const auto &SM = AST.getSourceManager();
+ auto MainFilePath =
+ getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
+ if (!MainFilePath) {
+ elog("Couldn't get main file path for: {0}", SL.printToString(SM));
+ return llvm::None;
+ }
+ return makeLocation(AST, SL, *MainFilePath);
+}
- H.contents.value += "Declared in ";
- H.contents.value += *NamedScope;
- H.contents.value += "\n\n";
+static std::string getDefinitionLine(const Decl *D) {
+ std::string Definition;
+ {
+ llvm::raw_string_ostream OS(Definition);
+ PrintingPolicy Policy =
+ printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
+ D->print(OS, Policy);
}
+ return Definition;
+}
- // We want to include the template in the Hover.
- if (TemplateDecl *TD = D->getDescribedTemplate())
- D = TD;
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const std::vector<HoverInfo::Param> &Params) {
+ for (size_t I = 0, E = Params.size(); I != E; ++I) {
+ if (I)
+ OS << ", ";
+ OS << Params.at(I);
+ }
+ return OS;
+}
- std::string DeclText;
- llvm::raw_string_ostream OS(DeclText);
+static std::vector<HoverInfo::Param>
+fetchTemplateParameters(const TemplateParameterList *Params,
+ const PrintingPolicy &PP) {
+ assert(Params);
+ std::vector<HoverInfo::Param> TempParameters;
+
+ for (const Decl *Param : *Params) {
+ HoverInfo::Param P;
+ if (const auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+ P.T = TTP->wasDeclaredWithTypename() ? "typename" : "class";
+ if (TTP->isParameterPack())
+ P.T += "...";
+
+ llvm::raw_string_ostream Out(P.Name);
+ Out << *TTP;
+ if (TTP->hasDefaultArgument())
+ P.Default = TTP->getDefaultArgument().getAsString(PP);
+ } else if (const auto NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (IdentifierInfo *II = NTTP->getIdentifier())
+ P.Name = II->getName().str();
+
+ llvm::raw_string_ostream Out(P.T);
+ NTTP->getType().print(Out, PP);
+ if (NTTP->isParameterPack())
+ Out << "...";
+
+ if (NTTP->hasDefaultArgument()) {
+ llvm::raw_string_ostream Out(P.Default);
+ NTTP->getDefaultArgument()->printPretty(Out, nullptr, PP);
+ }
+ } else if (const auto TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
+ llvm::raw_string_ostream OS(P.T);
+ OS << "template <"
+ << fetchTemplateParameters(
+ TTPD->getDescribedTemplate()->getTemplateParameters(), PP)
+ << "> class"; // FIXME: TemplateTemplateParameter doesn't store the
+ // info on whether this param was a "typename" or
+ // "class".
+ if (TTPD->hasDefaultArgument()) {
+ llvm::raw_string_ostream Out(P.Default);
+ TTPD->getDefaultArgument().getArgument().print(PP, Out);
+ }
+ } else {
+ std::string ParamSerial;
+ llvm::raw_string_ostream Out(ParamSerial);
+ Param->print(Out, PP);
+ Out.flush();
+ vlog("Unhandled template param: {0}", ParamSerial);
+ continue;
+ }
+ TempParameters.push_back(std::move(P));
+ }
+
+ return TempParameters;
+}
+
+/// Generate a \p Hover object given the declaration \p D.
+static HoverInfo getHoverContents(const Decl *D) {
+ HoverInfo HI;
PrintingPolicy Policy =
printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
+ if (const NamedDecl *ND = llvm::dyn_cast<NamedDecl>(D)) {
+ HI.Documentation = getDeclComment(ND->getASTContext(), *ND);
+ HI.Sym.Name = printName(D->getASTContext(), *ND);
+ HI.Scope = printQualifiedName(*ND);
+ }
- D->print(OS, Policy);
+ if (llvm::Optional<std::string> NamedScope = getScopeName(D)) {
+ assert(!NamedScope->empty());
+ HI.ParentScope = std::move(*NamedScope);
+ }
+ HI.Kind = indexSymbolKindToSymbolKind(index::getSymbolInfo(D).Kind);
- OS.flush();
+ if (const TemplateDecl *TD = D->getDescribedTemplate()) {
+ HI.TemplateParameters =
+ fetchTemplateParameters(TD->getTemplateParameters(), Policy);
+ D = TD;
+ } else if (const FunctionDecl *FD = D->getAsFunction()) {
+ if (const auto FTD = FD->getDescribedTemplate()) {
+ HI.TemplateParameters =
+ fetchTemplateParameters(FTD->getTemplateParameters(), Policy);
+ D = FTD;
+ }
+ }
- H.contents.value += DeclText;
- return H;
+ if (const FunctionDecl *FD = D->getAsFunction()) {
+ HI.ReturnType.emplace();
+ llvm::raw_string_ostream OS(*HI.ReturnType);
+ FD->getReturnType().print(OS, Policy);
+
+ HI.Parameters.emplace();
+ for (const ParmVarDecl *PVD : FD->parameters()) {
+ HI.Parameters->emplace_back();
+ auto &P = HI.Parameters->back();
+ P.T = PVD->getNameAsString();
+ if (PVD->hasDefaultArg()) {
+ llvm::raw_string_ostream Out(P.Default);
+ PVD->getDefaultArg()->printPretty(Out, nullptr, Policy);
+ }
+ }
+ if (FD->isVariadic()) {
+ HI.Parameters->emplace_back();
+ HI.Parameters->back().T = "...";
+ }
+ } else {
+ auto QT = getDeclType(D);
+ if (!QT.isNull()) {
+ HI.T.emplace();
+ llvm::raw_string_ostream OS(*HI.T);
+ QT.print(OS, std::move(Policy));
+ }
+ }
+
+ if (auto DefLoc = getDeclLoc(findNameLoc(D), D->getASTContext())) {
+ HI.Sym.PreferredDeclaration = *DefLoc;
+ if (getDefinition(D) == D)
+ HI.Sym.Definition = *DefLoc;
+ }
+ HI.Definition = getDefinitionLine(D);
+ return HI;
}
/// Generate a \p Hover object given the type \p T.
-static Hover getHoverContents(QualType T, ASTContext &ASTCtx) {
- Hover H;
- std::string TypeText;
- llvm::raw_string_ostream OS(TypeText);
- PrintingPolicy Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
- T.print(OS, Policy);
- OS.flush();
- H.contents.value += TypeText;
- return H;
+static HoverInfo getHoverContents(QualType T, ASTContext &ASTCtx) {
+ HoverInfo HI;
+ {
+ HI.T.emplace();
+ llvm::raw_string_ostream OS(*HI.T);
+ PrintingPolicy Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
+ T.print(OS, Policy);
+ }
+ HI.Sym.Name = *HI.T;
+ if (const TagDecl *TD = T.getTypePtr()->getAsTagDecl()) {
+ if (auto ScopedName = getScopeName(TD))
+ HI.ParentScope = std::move(*ScopedName);
+ HI.Scope = printQualifiedName(*TD);
+ HI.Kind = indexSymbolKindToSymbolKind(index::getSymbolInfo(TD).Kind);
+ // FIXME: Populate documentation
+ if (auto DefLoc = getDeclLoc(findNameLoc(TD), TD->getASTContext())) {
+ HI.Sym.PreferredDeclaration = *DefLoc;
+ if (getDefinition(TD) == TD)
+ HI.Sym.Definition = *DefLoc;
+ }
+ HI.Definition = getDefinitionLine(TD);
+ }
+ return HI;
}
/// Generate a \p Hover object given the macro \p MacroDecl.
-static Hover getHoverContents(MacroDecl Decl, ParsedAST &AST) {
+static HoverInfo getHoverContents(MacroDecl Decl, ParsedAST &AST) {
+ HoverInfo HI;
SourceManager &SM = AST.getASTContext().getSourceManager();
- std::string Definition = Decl.Name;
+ HI.Sym.Name = Decl.Name;
+ HI.Kind = indexSymbolKindToSymbolKind(
+ index::getSymbolInfoForMacro(*Decl.Info).Kind);
+ // FIXME: Populate documentation
// Try to get the full definition, not just the name
SourceLocation StartLoc = Decl.Info->getDefinitionLoc();
@@ -586,14 +751,15 @@
unsigned StartOffset = SM.getFileOffset(StartLoc);
unsigned EndOffset = SM.getFileOffset(EndLoc);
if (EndOffset <= Buffer.size() && StartOffset < EndOffset)
- Definition = Buffer.substr(StartOffset, EndOffset - StartOffset).str();
+ HI.Definition =
+ Buffer.substr(StartOffset, EndOffset - StartOffset).str();
}
}
-
- Hover H;
- H.contents.kind = MarkupKind::PlainText;
- H.contents.value = "#define " + Definition;
- return H;
+ if (auto DefLoc = getDeclLoc(StartLoc, AST.getASTContext())) {
+ HI.Sym.PreferredDeclaration = *DefLoc;
+ HI.Sym.Definition = *DefLoc;
+ }
+ return HI;
}
namespace {
@@ -708,7 +874,7 @@
return V.getDeducedType();
}
-llvm::Optional<Hover> getHover(ParsedAST &AST, Position Pos) {
+llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos) {
const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
SourceLocation SourceLocationBeg =
getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
@@ -748,7 +914,7 @@
auto MainFileRefs = findRefs(Symbols.Decls, AST);
for (const auto &Ref : MainFileRefs) {
Location Result;
- Result.range = getTokenRange(AST, Ref.Loc);
+ Result.range = getTokenRange(AST.getASTContext(), Ref.Loc);
Result.uri = URIForFile::canonicalize(*MainFilePath, *MainFilePath);
Results.push_back(std::move(Result));
}
@@ -991,5 +1157,70 @@
return Result;
}
+Hover HoverInfo::render() const {
+ Hover H;
+ H.range = Sym.PreferredDeclaration.range;
+ H.contents.kind = MarkupKind::PlainText;
+ std::vector<std::string> Output;
+
+ if (!Scope.empty())
+ H.contents.value = llvm::formatv("Declared in {0}\n\n", Scope);
+
+ if (Kind == SymbolKind::String) {
+ // We use SymbolKind::String for macro kinds
+ Output.push_back("#define");
+ if (!Definition.empty())
+ Output.push_back(Definition);
+ else
+ Output.push_back(Sym.Name);
+ } else if (T || ReturnType) {
+ // Non-macros
+ if (TemplateParameters) {
+ Output.emplace_back();
+ llvm::raw_string_ostream OS(Output.back());
+ OS << "template <" << *TemplateParameters << '>';
+ }
+ if (T)
+ Output.push_back(*T);
+ else if (ReturnType)
+ Output.push_back(*ReturnType);
+
+ if (!Sym.Name.empty())
+ if (!T || !llvm::StringRef(*T).endswith(Sym.Name))
+ Output.push_back(Sym.Name);
+
+ if (Parameters) {
+ // We don't want space before parameters.
+ llvm::raw_string_ostream OS(Output.back());
+ OS << '(' << *Parameters << ')';
+ }
+ } else {
+ // Symbols without types, like namespaces.
+ Output.push_back(Definition);
+ }
+ H.contents.value += llvm::join(Output, " ");
+ return H;
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const HoverInfo::Param &P) {
+ OS << P.T << ' ' << P.Name;
+ if (!P.Default.empty())
+ OS << " = " << P.Default;
+ return OS;
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const HoverInfo &HI) {
+ OS << HI.Definition << '\n';
+ OS << HI.Documentation << '\n';
+ OS << HI.Parameters << '\n';
+ OS << HI.ReturnType << '\n';
+ OS << HI.Scope << '\n';
+ OS << HI.Sym << '\n';
+ OS << HI.T << '\n';
+ OS << HI.TemplateParameters << '\n';
+ return OS;
+}
+
} // namespace clangd
} // namespace clang
Index: clang-tools-extra/clangd/ClangdServer.h
===================================================================
--- clang-tools-extra/clangd/ClangdServer.h
+++ clang-tools-extra/clangd/ClangdServer.h
@@ -180,7 +180,7 @@
/// Get code hover for a given position.
void findHover(PathRef File, Position Pos,
- Callback<llvm::Optional<Hover>> CB);
+ Callback<llvm::Optional<HoverInfo>> CB);
/// Get information about type hierarchy for a given position.
void typeHierarchy(PathRef File, Position Pos, int Resolve,
Index: clang-tools-extra/clangd/ClangdServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdServer.cpp
+++ clang-tools-extra/clangd/ClangdServer.cpp
@@ -523,8 +523,8 @@
}
void ClangdServer::findHover(PathRef File, Position Pos,
- Callback<llvm::Optional<Hover>> CB) {
- auto Action = [Pos](Callback<llvm::Optional<Hover>> CB,
+ Callback<llvm::Optional<HoverInfo>> CB) {
+ auto Action = [Pos](Callback<llvm::Optional<HoverInfo>> CB,
llvm::Expected<InputsAndAST> InpAST) {
if (!InpAST)
return CB(InpAST.takeError());
Index: clang-tools-extra/clangd/ClangdLSPServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -839,7 +839,17 @@
void ClangdLSPServer::onHover(const TextDocumentPositionParams &Params,
Callback<llvm::Optional<Hover>> Reply) {
Server->findHover(Params.textDocument.uri.file(), Params.position,
- std::move(Reply));
+ Bind(
+ [](decltype(Reply) Reply,
+ llvm::Expected<llvm::Optional<HoverInfo>> HIorErr) {
+ if (!HIorErr)
+ return Reply(HIorErr.takeError());
+ const auto &HI = HIorErr.get();
+ if (!HI)
+ return Reply(llvm::None);
+ return Reply(HI->render());
+ },
+ std::move(Reply)));
}
void ClangdLSPServer::onTypeHierarchy(
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits