diff --git a/clang-tools-extra/clangd/Hover.h b/clang-tools-extra/clangd/Hover.h
--- a/clang-tools-extra/clangd/Hover.h
+++ b/clang-tools-extra/clangd/Hover.h
@@ -18,6 +18,14 @@
namespace clang {
namespace clangd {
+struct UsedSymbol {
+ std::string Name;
+ Position Pos;
+};
+inline bool operator<(const UsedSymbol &FstSym, const UsedSymbol &SndSym) {
+ return FstSym.Name < SndSym.Name;
+}
+
/// Contains detailed information about a Symbol. Especially useful when
/// generating hover responses. It can be rendered as a hover panel, or
/// embedding clients can use the structured information to provide their own
@@ -96,6 +104,8 @@
// Set when symbol is inside function call. Contains information extracted
// from the callee definition about the argument this is passed as.
std::optional CalleeArgInfo;
+
+ std::optional> UsedSymbols;
struct PassType {
// How the variable is passed to callee.
enum PassMode { Ref, ConstRef, Value };
diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -13,8 +13,10 @@
#include "Config.h"
#include "FindTarget.h"
#include "ParsedAST.h"
+#include "Protocol.h"
#include "Selection.h"
#include "SourceCode.h"
+#include "clang-include-cleaner/Analysis.h"
#include "index/SymbolCollector.h"
#include "support/Markup.h"
#include "clang/AST/ASTContext.h"
@@ -1084,6 +1086,81 @@
return Candidates.front();
}
+// FIXME(bakalova): Remove after merging https://reviews.llvm.org/D143496
+std::vector
+collectMacroReferences(ParsedAST &AST) {
+ const auto &SM = AST.getSourceManager();
+ // FIXME: !!this is a hacky way to collect macro references.
+ std::vector Macros;
+ auto &PP = AST.getPreprocessor();
+ for (const syntax::Token &Tok :
+ AST.getTokens().spelledTokens(SM.getMainFileID())) {
+ auto Macro = locateMacroAt(Tok, PP);
+ if (!Macro)
+ continue;
+ if (auto DefLoc = Macro->Info->getDefinitionLoc(); DefLoc.isValid())
+ Macros.push_back(
+ {Tok.location(),
+ include_cleaner::Macro{/*Name=*/PP.getIdentifierInfo(Tok.text(SM)),
+ DefLoc},
+ include_cleaner::RefType::Explicit});
+ }
+ return Macros;
+}
+
+void addUsedSymbols(const Inclusion &Inc, ParsedAST &AST,
+ const std::vector &Macros,
+ HoverInfo &HI) {
+ const SourceManager &SM = AST.getSourceManager();
+ std::set UsedSymbols;
+ include_cleaner::walkUsed(
+ AST.getLocalTopLevelDecls(), Macros, AST.getPragmaIncludes(), SM,
+ [&](const include_cleaner::SymbolReference &Ref,
+ llvm::ArrayRef Providers) {
+ if (Ref.RT != include_cleaner::RefType::Explicit ||
+ !Ref.RefLocation.isFileID() ||
+ !SM.isWrittenInMainFile(SM.getSpellingLoc(Ref.RefLocation))
+ ) {
+ return;
+ }
+ std::string Name;
+ switch (Ref.Target.kind()) {
+ case include_cleaner::Symbol::Declaration:
+ Name = cast(Ref.Target.declaration())
+ .getDeclName()
+ .getAsString();
+ break;
+ case include_cleaner::Symbol::Macro:
+ Name = Ref.Target.macro().Name->getName();
+ break;
+ }
+
+ Position Pos = sourceLocToPosition(SM, Ref.RefLocation);
+ for (const include_cleaner::Header &H : Providers) {
+ switch (H.kind()) {
+ case include_cleaner::Header::Physical:
+ if (H.physical()->tryGetRealPathName() == Inc.Resolved) {
+ UsedSymbols.insert({Name, Pos});
+ }
+ break;
+ case include_cleaner::Header::Standard:
+ if (Inc.Written == H.standard().name()) {
+ UsedSymbols.insert({Name, Pos});
+ }
+ break;
+ case include_cleaner::Header::Verbatim:
+ if (Inc.Written == H.verbatim()) {
+ UsedSymbols.insert({Name, Pos});
+ }
+ break;
+ }
+ }
+ });
+
+ if (!UsedSymbols.empty()) {
+ HI.UsedSymbols = std::optional>{std::move(UsedSymbols)};
+ }
+}
} // namespace
std::optional getHover(ParsedAST &AST, Position Pos,
@@ -1103,6 +1180,7 @@
if (TokensTouchingCursor.empty())
return std::nullopt;
+ const auto &Macros = collectMacroReferences(AST);
// Show full header file path if cursor is on include directive.
for (const auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
if (Inc.Resolved.empty() || Inc.HashLine != Pos.line)
@@ -1113,6 +1191,7 @@
HI.Definition =
URIForFile::canonicalize(Inc.Resolved, AST.tuPath()).file().str();
HI.DefinitionLanguage = "";
+ addUsedSymbols(Inc, AST, Macros, HI);
return HI;
}
@@ -1313,6 +1392,25 @@
Output.addCodeBlock(Buffer, DefinitionLanguage);
}
+ if (UsedSymbols) {
+ Output.addRuler();
+ markup::Paragraph &Title = Output.addParagraph();
+ Title.appendText("Provides symbols used in this file:");
+ markup::BulletList &BL = Output.addBulletList();
+
+ for (const auto &Sym : *UsedSymbols) {
+ markup::Document &D = BL.addItem();
+ markup::Paragraph &P = D.addParagraph();
+ P.appendCode(Sym.Name);
+ P.appendSpace();
+ P.appendText("[Ln: ");
+ P.appendText(std::to_string(Sym.Pos.line));
+ P.appendText(", Col: ");
+ P.appendText(std::to_string(Sym.Pos.character));
+ P.appendText("]");
+ }
+ }
+
return Output;
}