14 #include "clang/AST/Decl.h" 15 #include "clang/AST/DeclCXX.h" 16 #include "clang/AST/Type.h" 17 #include "clang/ASTMatchers/ASTMatchFinder.h" 18 #include "clang/ASTMatchers/ASTMatchers.h" 19 #include "clang/Tooling/Tooling.h" 20 #include "llvm/ADT/Optional.h" 21 #include "llvm/Support/FileSystem.h" 26 namespace find_all_symbols {
30 if (
const auto *ED = dyn_cast<EnumDecl>(Node.getDeclContext()))
31 return ED->isScoped();
36 AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, VarDecl,
38 if (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
39 bool IsPartialSpecialization =
40 llvm::isa<VarTemplatePartialSpecializationDecl>(Node) ||
41 llvm::isa<ClassTemplatePartialSpecializationDecl>(Node);
42 return !IsPartialSpecialization;
47 std::vector<SymbolInfo::Context> GetContexts(
const NamedDecl *ND) {
48 std::vector<SymbolInfo::Context> Contexts;
49 for (
const auto *Context = ND->getDeclContext(); Context;
50 Context = Context->getParent()) {
51 if (llvm::isa<TranslationUnitDecl>(Context) ||
52 llvm::isa<LinkageSpecDecl>(Context))
55 assert(llvm::isa<NamedDecl>(Context) &&
56 "Expect Context to be a NamedDecl");
57 if (
const auto *NSD = dyn_cast<NamespaceDecl>(Context)) {
58 if (!NSD->isInlineNamespace())
60 NSD->getName().str());
61 }
else if (
const auto *ED = dyn_cast<EnumDecl>(Context)) {
65 const auto *RD = cast<RecordDecl>(Context);
73 llvm::Optional<SymbolInfo>
74 CreateSymbolInfo(
const NamedDecl *ND,
const SourceManager &SM,
75 const HeaderMapCollector *Collector) {
77 if (llvm::isa<VarDecl>(ND)) {
79 }
else if (llvm::isa<FunctionDecl>(ND)) {
81 }
else if (llvm::isa<TypedefNameDecl>(ND)) {
83 }
else if (llvm::isa<EnumConstantDecl>(ND)) {
85 }
else if (llvm::isa<EnumDecl>(ND)) {
88 if (ND->getName().empty())
91 assert(llvm::isa<RecordDecl>(ND) &&
92 "Matched decl must be one of VarDecl, " 93 "FunctionDecl, TypedefNameDecl, EnumConstantDecl, " 94 "EnumDecl and RecordDecl!");
96 if (ND->getName().empty())
101 SourceLocation
Loc = SM.getExpansionLoc(ND->getLocation());
102 if (!Loc.isValid()) {
103 llvm::errs() <<
"Declaration " << ND->getNameAsString() <<
"(" 104 << ND->getDeclKindName()
105 <<
") has invalid declaration location.";
110 if (FilePath.empty())
return llvm::None;
112 return SymbolInfo(ND->getNameAsString(), Type, FilePath, GetContexts(ND));
117 void FindAllSymbols::registerMatchers(MatchFinder *MatchFinder) {
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(hasDeclaration(Types.bind(
"use"))))),
223 MatchFinder->addMatcher(
224 typeLoc(isExpansionInMainFile(),
225 loc(typedefType(hasDeclaration(Typedefs.bind(
"use"))))),
230 MatchFinder->addMatcher(
231 typeLoc(isExpansionInMainFile(),
232 loc(templateSpecializationType(hasDeclaration(
233 classTemplateSpecializationDecl(hasSpecializedTemplate(
234 classTemplateDecl(has(CXXRecords.bind(
"use"))))))))),
238 void FindAllSymbols::run(
const MatchFinder::MatchResult &
Result) {
240 if (Result.Context->getDiagnostics().hasErrorOccurred()) {
246 if ((ND = Result.Nodes.getNodeAs<NamedDecl>(
"use")))
248 else if ((ND = Result.Nodes.getNodeAs<NamedDecl>(
"decl")))
251 assert(
false &&
"Must match a NamedDecl!");
253 const SourceManager *SM = Result.SourceManager;
254 if (
auto Symbol = CreateSymbolInfo(ND, *SM, Collector)) {
255 Filename = SM->getFileEntryForID(SM->getMainFileID())->getName();
256 FileSymbols[*Symbol] += Signals;
260 void FindAllSymbols::onEndOfTranslationUnit() {
262 Reporter->reportSymbols(
Filename, FileSymbols);
SourceLocation Loc
'#' location in the include directive
AST_MATCHER(BinaryOperator, isAssignmentOperator)
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.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//