clang 23.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"
16#include "llvm/ADT/SetVector.h"
17
18using namespace clang;
19using namespace ssaf;
20
21std::string ssaf::describeJSONValue(const llvm::json::Value &V) {
22 return llvm::formatv("{0:2}", V).str();
23}
24
25std::string ssaf::describeJSONValue(const llvm::json::Array &A) {
26 return llvm::formatv("array of size {0}", A.size()).str();
27}
28
29std::string ssaf::describeJSONValue(const llvm::json::Object &O) {
30 return llvm::formatv("an object of {0} key(s)", O.size()).str();
31}
32
33namespace {
34// Traverses the AST and finds contributors.
35class ContributorFinder : public DynamicRecursiveASTVisitor {
36public:
37 llvm::SetVector<const NamedDecl *> Contributors;
38 const SSAFOptions &Opts;
39
40 ContributorFinder(const SSAFOptions &Opts) : Opts(Opts) {
41 ShouldVisitTemplateInstantiations = true;
42 ShouldVisitImplicitCode = false;
43 }
44
45 bool VisitFunctionDecl(FunctionDecl *D) override {
46 Contributors.insert(D);
47 return true;
48 }
49
50 bool VisitRecordDecl(RecordDecl *D) override {
51 Contributors.insert(D);
52 return true;
53 }
54
55 bool VisitVarDecl(VarDecl *D) override {
56 DeclContext *DC = D->getDeclContext();
57
58 // Collects Decl for global variables or static data members:
59 if (DC->isFileContext() || D->isStaticDataMember()) {
60 Contributors.insert(D);
61 return true;
62 }
63
64 // Optionally include block-scope (function-local) variables. Parameters
65 // are intentionally skipped: they are exposed via their parent function's
66 // USR + a parameter-index suffix in getEntityName, so registering them as
67 // independent contributors would be redundant.
68 //
69 // FIXME: clang::index::generateUSRForDecl can produce non-unique or empty
70 // USRs for some local declaration shapes (e.g., locals of certain template
71 // instantiations). The current addEntity path returns std::nullopt when
72 // that happens and downstream extractors skip gracefully, so this is
73 // tolerated for now.
74 if (Opts.IncludeLocalEntities && !D->isImplicit() && !isa<ParmVarDecl>(D) &&
76 Contributors.insert(D);
77 return true;
78 }
79
80 bool VisitLambdaExpr(LambdaExpr *L) override {
81 // TraverseLambdaExpr directly visits the body stmt, skipping the
82 // CXXMethodDecl, which is a contributor that needs to be collected.
83 VisitFunctionDecl(L->getCallOperator());
84 return true;
85 }
86};
87
88/// An AST visitor that skips the root node's strict-descendants that are
89/// callable Decls and record Decls, because those are separate contributors.
90///
91/// Clients need to implement their own "MatchAction", which is a function that
92/// takes a `DynTypedNode`, decides if the node matches and performs any further
93/// callback actions.
94/// ContributorFactFinder takes a reference to a "MatchAction". It does not own
95/// the "MatchAction", which is usually stateful and may own containers.
96class ContributorFactFinder : public DynamicRecursiveASTVisitor {
97 llvm::function_ref<void(const DynTypedNode &)> MatchActionRef;
98 const NamedDecl *RootDecl = nullptr;
99
100 template <typename NodeTy> void match(const NodeTy &Node) {
101 MatchActionRef(DynTypedNode::create(Node));
102 }
103
104public:
105 ContributorFactFinder(
106 llvm::function_ref<void(const DynTypedNode &)> MatchActionRef)
107 : MatchActionRef(MatchActionRef) {
108 ShouldVisitTemplateInstantiations = true;
109 ShouldVisitImplicitCode = false;
110 }
111
112 // The entry point:
113 void findMatches(const NamedDecl *Contributor) {
114 RootDecl = Contributor;
115 TraverseDecl(const_cast<NamedDecl *>(Contributor));
116 }
117
118 bool TraverseDecl(Decl *Node) override {
119 if (!Node)
120 return true;
121 // To skip callables:
122 if (Node != RootDecl &&
124 return true;
125 match(*Node);
127 }
128
129 bool TraverseStmt(Stmt *Node) override {
130 if (!Node)
131 return true;
132 match(*Node);
134 }
135
136 bool TraverseLambdaExpr(LambdaExpr *L) override {
137 // TODO: lambda captures of pointer variables (by copy or by reference)
138 // are currently not tracked. Each capture initializes an implicit closure
139 // field from the captured variable, which constitutes a pointer assignment
140 // edge that should be recorded here.
141 return true; // Skip lambda as it is a callable.
142 }
143};
144} // namespace
145
147 ASTContext &Ctx, const SSAFOptions &Options,
148 llvm::DenseMap<const NamedDecl *, std::vector<const NamedDecl *>>
149 &Contributors) {
150 ContributorFinder Finder{Options};
151 Finder.TraverseAST(Ctx);
152 for (const NamedDecl *C : Finder.Contributors)
153 Contributors[cast<NamedDecl>(C->getCanonicalDecl())].push_back(C);
154}
155
157 const NamedDecl *Contributor,
158 llvm::function_ref<void(const DynTypedNode &)> MatchActionRef) {
159 ContributorFactFinder{MatchActionRef}.findMatches(Contributor);
160}
161
163 const clang::NamedDecl *D) {
164 return makeErrAtNode(Ctx, D, "failed to create entity name for %s",
165 D->getNameAsString().data());
166}
Defines the clang::ASTContext interface.
#define V(N, I)
Defines the clang::Expr interface and subclasses for C++ expressions.
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
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 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)
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)
void findContributors(ASTContext &Ctx, const SSAFOptions &Options, llvm::DenseMap< const NamedDecl *, std::vector< const NamedDecl * > > &Contributors)
Find all contributors in an AST.
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