13#include "clang/AST/Decl.h"
14#include "clang/AST/DeclCXX.h"
15#include "clang/AST/Type.h"
16#include "clang/ASTMatchers/ASTMatchFinder.h"
17#include "clang/ASTMatchers/ASTMatchers.h"
18#include "clang/Tooling/Tooling.h"
19#include "llvm/Support/FileSystem.h"
25namespace find_all_symbols {
29 if (
const auto *ED = dyn_cast<EnumDecl>(
Node.getDeclContext()))
30 return ED->isScoped();
35 AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, VarDecl,
37 if (
Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
38 bool IsPartialSpecialization =
39 llvm::isa<VarTemplatePartialSpecializationDecl>(Node) ||
40 llvm::isa<ClassTemplatePartialSpecializationDecl>(Node);
41 return !IsPartialSpecialization;
46std::vector<SymbolInfo::Context> GetContexts(
const NamedDecl *ND) {
47 std::vector<SymbolInfo::Context> Contexts;
48 for (
const auto *Context = ND->getDeclContext(); Context;
49 Context = Context->getParent()) {
50 if (llvm::isa<TranslationUnitDecl>(Context) ||
51 llvm::isa<LinkageSpecDecl>(Context))
54 assert(llvm::isa<NamedDecl>(Context) &&
55 "Expect Context to be a NamedDecl");
56 if (
const auto *NSD = dyn_cast<NamespaceDecl>(Context)) {
57 if (!NSD->isInlineNamespace())
59 NSD->getName().str());
60 }
else if (
const auto *ED = dyn_cast<EnumDecl>(Context)) {
64 const auto *RD = cast<RecordDecl>(Context);
72std::optional<SymbolInfo>
73CreateSymbolInfo(
const NamedDecl *ND,
const SourceManager &SM,
74 const HeaderMapCollector *Collector) {
76 if (llvm::isa<VarDecl>(ND)) {
78 }
else if (llvm::isa<FunctionDecl>(ND)) {
80 }
else if (llvm::isa<TypedefNameDecl>(ND)) {
82 }
else if (llvm::isa<EnumConstantDecl>(ND)) {
84 }
else if (llvm::isa<EnumDecl>(ND)) {
87 if (ND->getName().empty())
90 assert(llvm::isa<RecordDecl>(ND) &&
91 "Matched decl must be one of VarDecl, "
92 "FunctionDecl, TypedefNameDecl, EnumConstantDecl, "
93 "EnumDecl and RecordDecl!");
95 if (ND->getName().empty())
100 SourceLocation
Loc = SM.getExpansionLoc(ND->getLocation());
101 if (!
Loc.isValid()) {
102 llvm::errs() <<
"Declaration " << ND->getDeclName() <<
"("
103 << ND->getDeclKindName()
104 <<
") has invalid declaration location.";
109 if (FilePath.empty())
112 return SymbolInfo(ND->getNameAsString(),
Type, FilePath, GetContexts(ND));
119 auto IsInSpecialization = hasAncestor(
120 decl(anyOf(cxxRecordDecl(isExplicitTemplateSpecialization()),
121 functionDecl(isExplicitTemplateSpecialization()))));
127 allOf(unless(isImplicit()), unless(isExpansionInMainFile()));
129 auto HasNSOrTUCtxMatcher =
130 hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
138 allOf(HasNSOrTUCtxMatcher, unless(IsInSpecialization),
139 unless(ast_matchers::isTemplateInstantiation()),
140 unless(isInstantiated()), unless(isFullySpecialized()));
143 auto ExternCMatcher = hasDeclContext(linkageSpecDecl());
156 auto Vars = varDecl(CommonFilter, anyOf(ExternCMatcher, CCMatcher),
157 unless(parmVarDecl()));
160 auto CRecords = recordDecl(CommonFilter, ExternCMatcher, isDefinition());
162 auto CXXRecords = cxxRecordDecl(CommonFilter, CCMatcher, isDefinition());
168 auto Functions = functionDecl(CommonFilter, unless(hasParent(friendDecl())),
169 anyOf(ExternCMatcher, CCMatcher));
183 typedefNameDecl(CommonFilter, anyOf(HasNSOrTUCtxMatcher,
184 hasDeclContext(linkageSpecDecl())));
187 auto Enums = enumDecl(CommonFilter, isDefinition(),
188 anyOf(HasNSOrTUCtxMatcher, ExternCMatcher));
193 auto EnumConstants = enumConstantDecl(
194 CommonFilter, unless(isInScopedEnum()),
195 anyOf(hasDeclContext(enumDecl(HasNSOrTUCtxMatcher)), ExternCMatcher));
198 auto Types = namedDecl(anyOf(CRecords, CXXRecords, Enums));
199 auto Decls = namedDecl(anyOf(CRecords, CXXRecords, Enums, Typedefs, Vars,
200 EnumConstants, Functions));
203 MatchFinder->addMatcher(Decls.bind(
"decl"),
this);
207 MatchFinder->addMatcher(
208 declRefExpr(isExpansionInMainFile(), to(Decls.bind(
"use"))),
this);
210 MatchFinder->addMatcher(
211 declRefExpr(isExpansionInMainFile(),
212 to(functionDecl(hasParent(
213 functionTemplateDecl(has(Functions.bind(
"use"))))))),
217 MatchFinder->addMatcher(
218 typeLoc(isExpansionInMainFile(),
219 loc(qualType(allOf(unless(elaboratedType()),
220 hasDeclaration(Types.bind(
"use")))))),
224 MatchFinder->addMatcher(
225 typeLoc(isExpansionInMainFile(),
226 loc(typedefType(hasDeclaration(Typedefs.bind(
"use"))))),
231 MatchFinder->addMatcher(
232 typeLoc(isExpansionInMainFile(),
233 loc(templateSpecializationType(hasDeclaration(
234 classTemplateSpecializationDecl(hasSpecializedTemplate(
235 classTemplateDecl(has(CXXRecords.bind(
"use"))))))))),
241 if (Result.Context->getDiagnostics().hasErrorOccurred()) {
247 if ((ND = Result.Nodes.getNodeAs<NamedDecl>(
"use")))
249 else if ((ND = Result.Nodes.getNodeAs<NamedDecl>(
"decl")))
252 assert(
false &&
"Must match a NamedDecl!");
254 const SourceManager *SM = Result.SourceManager;
255 if (
auto Symbol = CreateSymbolInfo(ND, *SM, Collector)) {
257 std::string(SM->getFileEntryRefForID(SM->getMainFileID())->getName());
258 FileSymbols[*Symbol] += Signals;
263 if (Filename !=
"") {
::clang::DynTypedNode Node
void registerMatchers(ast_matchers::MatchFinder *MatchFinder)
void run(const ast_matchers::MatchFinder::MatchResult &result) override
void onEndOfTranslationUnit() override
Describes a named symbol from a header.
SymbolKind
The SymbolInfo Type.
virtual void reportSymbols(llvm::StringRef FileName, const SymbolInfo::SignalMap &Symbols)=0
AST_MATCHER(Expr, isMacroID)
AST_POLYMORPHIC_MATCHER(isInAbseilFile, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc, NestedNameSpecifierLoc))
Matches AST nodes that were found within Abseil files.
std::string getIncludePath(const SourceManager &SM, SourceLocation Loc, const HeaderMapCollector *Collector)
This calculates the include path for Loc.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//