clang 24.0.0git
SSAFAnalysesCommon.cpp
Go to the documentation of this file.
1//===- SSAFAnalysesCommon.cpp ---------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
11#include "clang/AST/Decl.h"
12#include "clang/AST/DeclObjC.h"
14#include "clang/AST/ExprCXX.h"
17#include "llvm/ADT/SetVector.h"
18
19using namespace clang;
20using namespace ssaf;
21
22std::string ssaf::describeJSONValue(const llvm::json::Value &V) {
23 return llvm::formatv("{0:2}", V).str();
24}
25
26std::string ssaf::describeJSONValue(const llvm::json::Array &A) {
27 return llvm::formatv("array of size {0}", A.size()).str();
28}
29
30std::string ssaf::describeJSONValue(const llvm::json::Object &O) {
31 return llvm::formatv("an object of {0} key(s)", O.size()).str();
32}
33
34namespace {
35// Traverses the AST and finds contributors.
36class ContributorFinder : public DynamicRecursiveASTVisitor {
37public:
38 llvm::SetVector<const NamedDecl *> Contributors;
39 const SSAFOptions &Opts;
40
41 ContributorFinder(ASTContext &Ctx, const SSAFOptions &Opts,
42 bool ExtractFromSystemHeaders)
43 : Opts(Opts), Ctx(Ctx),
44 ExtractFromSystemHeaders(ExtractFromSystemHeaders) {
45 ShouldVisitTemplateInstantiations = true;
46 ShouldVisitImplicitCode = false;
47 }
48
49 bool VisitFunctionDecl(FunctionDecl *D) override {
50 if (!skipForSystemHeader(D))
51 Contributors.insert(D);
52 return true;
53 }
54
55 bool VisitRecordDecl(RecordDecl *D) override {
56 if (skipForSystemHeader(D))
57 return true;
58 Contributors.insert(D);
59 return true;
60 }
61
62 bool VisitVarDecl(VarDecl *D) override {
63 if (skipForSystemHeader(D))
64 return true;
65 DeclContext *DC = D->getDeclContext();
66
67 // Collects Decl for global variables or static data members:
68 if (DC->isFileContext() || D->isStaticDataMember()) {
69 Contributors.insert(D);
70 return true;
71 }
72
73 // Optionally include block-scope (function-local) variables. Parameters
74 // are intentionally skipped: they are exposed via their parent function's
75 // USR + a parameter-index suffix in getEntityName, so registering them as
76 // independent contributors would be redundant.
77 //
78 // FIXME: clang::index::generateUSRForDecl can produce non-unique or empty
79 // USRs for some local declaration shapes (e.g., locals of certain template
80 // instantiations). The current addEntity path returns std::nullopt when
81 // that happens and downstream extractors skip gracefully, so this is
82 // tolerated for now.
83 if (Opts.IncludeLocalEntities && !D->isImplicit() && !isa<ParmVarDecl>(D) &&
85 Contributors.insert(D);
86 return true;
87 }
88
89 bool VisitLambdaExpr(LambdaExpr *L) override {
90 return VisitFunctionDecl(L->getCallOperator());
91 }
92
93private:
94 bool skipForSystemHeader(const Decl *D) const {
95 if (ExtractFromSystemHeaders)
96 return false;
97 SourceLocation Loc = D->getLocation();
98 return Loc.isValid() && Ctx.getSourceManager().isInSystemHeader(Loc);
99 }
100
101 ASTContext &Ctx;
102 bool ExtractFromSystemHeaders;
103};
104
105/// An AST visitor that skips the root node's strict-descendants that are
106/// callable Decls and record Decls, because those are separate contributors.
107///
108/// Clients need to implement their own "MatchAction", which is a function that
109/// takes a `DynTypedNode`, decides if the node matches and performs any further
110/// callback actions.
111/// ContributorFactFinder takes a reference to a "MatchAction". It does not own
112/// the "MatchAction", which is usually stateful and may own containers.
113class ContributorFactFinder : public DynamicRecursiveASTVisitor {
114 llvm::function_ref<void(const DynTypedNode &)> MatchActionRef;
115 const NamedDecl *RootDecl = nullptr;
116
117 template <typename NodeTy> void match(const NodeTy &Node) {
118 MatchActionRef(DynTypedNode::create(Node));
119 }
120
121public:
122 ContributorFactFinder(
123 llvm::function_ref<void(const DynTypedNode &)> MatchActionRef)
124 : MatchActionRef(MatchActionRef) {
125 ShouldVisitTemplateInstantiations = true;
126 ShouldVisitImplicitCode = false;
127 }
128
129 // The entry point:
130 void findMatches(const NamedDecl *Contributor) {
131 RootDecl = Contributor;
132 TraverseDecl(const_cast<NamedDecl *>(Contributor));
133 }
134
135 bool TraverseDecl(Decl *Node) override {
136 if (!Node)
137 return true;
138 // To skip callables:
139 if (Node != RootDecl &&
141 return true;
142 match(*Node);
144 }
145
146 bool TraverseStmt(Stmt *Node) override {
147 if (!Node)
148 return true;
149 match(*Node);
151 }
152
153 bool TraverseLambdaExpr(LambdaExpr *L) override {
154 // TODO: lambda captures of pointer variables (by copy or by reference)
155 // are currently not tracked. Each capture initializes an implicit closure
156 // field from the captured variable, which constitutes a pointer assignment
157 // edge that should be recorded here.
158 return true; // Skip lambda as it is a callable.
159 }
160};
161} // namespace
162
164 ASTContext &Ctx, const SSAFOptions &Options,
165 llvm::DenseMap<const NamedDecl *, std::vector<const NamedDecl *>>
166 &Contributors,
167 bool ExtractFromSystemHeaders) {
168 ContributorFinder Finder{Ctx, Options, ExtractFromSystemHeaders};
169 Finder.TraverseAST(Ctx);
170 for (const NamedDecl *C : Finder.Contributors)
171 Contributors[cast<NamedDecl>(C->getCanonicalDecl())].push_back(C);
172}
173
175 const NamedDecl *Contributor,
176 llvm::function_ref<void(const DynTypedNode &)> MatchActionRef) {
177 ContributorFactFinder{MatchActionRef}.findMatches(Contributor);
178}
179
181 const clang::NamedDecl *D) {
182 return makeErrAtNode(Ctx, D, "failed to create entity name for %s",
183 D->getNameAsString().data());
184}
Defines the clang::ASTContext interface.
#define V(N, I)
Defines the clang::Expr interface and subclasses for C++ expressions.
Defines the SourceManager interface.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
bool isFileContext() const
Definition DeclBase.h:2197
bool isFunctionOrMethod() const
Definition DeclBase.h:2178
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition DeclBase.h:601
SourceLocation getLocation() const
Definition DeclBase.h:447
DeclContext * getDeclContext()
Definition DeclBase.h:456
A dynamically typed AST node container.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
virtual bool TraverseStmt(MaybeConst< Stmt > *S)
Represents a function declaration or definition.
Definition Decl.h:2029
CXXMethodDecl * getCallOperator() const
Retrieve the function call operator associated with this lambda expression.
Definition ExprCXX.cpp:1411
This represents a decl that may have a name.
Definition Decl.h:274
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
Definition Decl.h:317
bool isValid() const
Return true if this is a valid SourceLocation object.
bool isStaticDataMember() const
Determines whether this is a static data member.
Definition Decl.h:1306
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
llvm::Error makeErrAtNode(clang::ASTContext &Ctx, const NodeTy *N, llvm::StringRef Fmt, const Ts &...Args)
void findContributors(ASTContext &Ctx, const SSAFOptions &Options, llvm::DenseMap< const NamedDecl *, std::vector< const NamedDecl * > > &Contributors, bool ExtractFromSystemHeaders=true)
Find all contributors in an AST.
llvm::Error makeEntityNameErr(clang::ASTContext &Ctx, const clang::NamedDecl *D)
void findMatchesIn(const NamedDecl *Contributor, llvm::function_ref< void(const DynTypedNode &)> MatchActionRef)
Perform "MatchAction" on each Stmt and Decl belonging to the Contributor.
std::string describeJSONValue(const llvm::json::Value &V)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
Definition Address.h:327