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/ADT/Optional.h" 20 #include "llvm/Support/FileSystem.h" 25 namespace 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;
46 std::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);
72 llvm::Optional<SymbolInfo>
73 CreateSymbolInfo(
const NamedDecl *ND,
const SourceManager &SM,
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->getNameAsString() <<
"(" 103 << ND->getDeclKindName()
104 <<
") has invalid declaration location.";
109 if (FilePath.empty())
return llvm::None;
111 return SymbolInfo(ND->getNameAsString(),
Type, FilePath, GetContexts(ND));
116 void FindAllSymbols::registerMatchers(MatchFinder *MatchFinder) {
118 auto IsInSpecialization = hasAncestor(
126 allOf(unless(isImplicit()), unless(isExpansionInMainFile()));
128 auto HasNSOrTUCtxMatcher =
129 hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
137 allOf(HasNSOrTUCtxMatcher, unless(IsInSpecialization),
138 unless(ast_matchers::isTemplateInstantiation()),
139 unless(isInstantiated()), unless(isFullySpecialized()));
142 auto ExternCMatcher = hasDeclContext(linkageSpecDecl());
155 auto Vars = varDecl(CommonFilter, anyOf(ExternCMatcher, CCMatcher),
156 unless(parmVarDecl()));
159 auto CRecords = recordDecl(CommonFilter, ExternCMatcher, isDefinition());
161 auto CXXRecords = cxxRecordDecl(CommonFilter, CCMatcher, isDefinition());
167 auto Functions = functionDecl(CommonFilter, unless(hasParent(friendDecl())),
168 anyOf(ExternCMatcher, CCMatcher));
182 typedefNameDecl(CommonFilter, anyOf(HasNSOrTUCtxMatcher,
183 hasDeclContext(linkageSpecDecl())));
186 auto Enums = enumDecl(CommonFilter, isDefinition(),
187 anyOf(HasNSOrTUCtxMatcher, ExternCMatcher));
192 auto EnumConstants = enumConstantDecl(
193 CommonFilter, unless(isInScopedEnum()),
194 anyOf(hasDeclContext(enumDecl(HasNSOrTUCtxMatcher)), ExternCMatcher));
197 auto Types = namedDecl(anyOf(CRecords, CXXRecords, Enums));
198 auto Decls = namedDecl(anyOf(CRecords, CXXRecords, Enums, Typedefs, Vars,
199 EnumConstants, Functions));
202 MatchFinder->addMatcher(
Decls.bind(
"decl"),
this);
206 MatchFinder->addMatcher(
207 declRefExpr(isExpansionInMainFile(), to(
Decls.bind(
"use"))),
this);
209 MatchFinder->addMatcher(
210 declRefExpr(isExpansionInMainFile(),
211 to(functionDecl(hasParent(
212 functionTemplateDecl(has(Functions.bind(
"use"))))))),
216 MatchFinder->addMatcher(
217 typeLoc(isExpansionInMainFile(),
218 loc(qualType(hasDeclaration(Types.bind(
"use"))))),
222 MatchFinder->addMatcher(
223 typeLoc(isExpansionInMainFile(),
224 loc(typedefType(hasDeclaration(Typedefs.bind(
"use"))))),
229 MatchFinder->addMatcher(
230 typeLoc(isExpansionInMainFile(),
231 loc(templateSpecializationType(hasDeclaration(
232 classTemplateSpecializationDecl(hasSpecializedTemplate(
233 classTemplateDecl(has(CXXRecords.bind(
"use"))))))))),
237 void FindAllSymbols::run(
const MatchFinder::MatchResult &Result) {
239 if (Result.Context->getDiagnostics().hasErrorOccurred()) {
245 if ((ND = Result.Nodes.getNodeAs<NamedDecl>(
"use")))
247 else if ((ND = Result.Nodes.getNodeAs<NamedDecl>(
"decl")))
250 assert(
false &&
"Must match a NamedDecl!");
252 const SourceManager *SM = Result.SourceManager;
253 if (
auto Symbol = CreateSymbolInfo(ND, *SM, Collector)) {
254 Filename = SM->getFileEntryForID(SM->getMainFileID())->getName();
255 FileSymbols[*Symbol] += Signals;
259 void FindAllSymbols::onEndOfTranslationUnit() {
261 Reporter->reportSymbols(
Filename, FileSymbols);
SourceLocation Loc
'#' location in the include directive
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.
std::string Filename
Filename as a string.
clang::find_all_symbols::SymbolInfo SymbolInfo
SymbolKind
The SymbolInfo Type.
std::shared_ptr< SymbolCollector > Collector
bool isExplicitTemplateSpecialization(const NamedDecl *D)
Indicates if D is an explicit template specialization, e.g.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::SmallDenseMap< const NamedDecl *, RelSet > Decls