clang 20.0.0git
ASTUtils.cpp
Go to the documentation of this file.
1//=======- ASTUtils.cpp ------------------------------------------*- C++ -*-==//
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
9#include "ASTUtils.h"
10#include "PtrTypesSemantics.h"
12#include "clang/AST/Decl.h"
13#include "clang/AST/DeclCXX.h"
14#include "clang/AST/ExprCXX.h"
15#include "clang/AST/ExprObjC.h"
17#include <optional>
18
19namespace clang {
20
23}
24
26 const Expr *E, bool StopAtFirstRefCountedObj,
27 std::function<bool(const clang::Expr *, bool)> callback) {
28 while (E) {
29 if (auto *tempExpr = dyn_cast<MaterializeTemporaryExpr>(E)) {
30 E = tempExpr->getSubExpr();
31 continue;
32 }
33 if (auto *tempExpr = dyn_cast<CXXBindTemporaryExpr>(E)) {
34 E = tempExpr->getSubExpr();
35 continue;
36 }
37 if (auto *tempExpr = dyn_cast<CXXConstructExpr>(E)) {
38 if (auto *C = tempExpr->getConstructor()) {
39 if (auto *Class = C->getParent(); Class && isSafePtr(Class))
40 return callback(E, true);
41 break;
42 }
43 }
44 if (auto *POE = dyn_cast<PseudoObjectExpr>(E)) {
45 if (auto *RF = POE->getResultExpr()) {
46 E = RF;
47 continue;
48 }
49 }
50 if (auto *tempExpr = dyn_cast<ParenExpr>(E)) {
51 E = tempExpr->getSubExpr();
52 continue;
53 }
54 if (auto *Expr = dyn_cast<ConditionalOperator>(E)) {
55 return tryToFindPtrOrigin(Expr->getTrueExpr(), StopAtFirstRefCountedObj,
56 callback) &&
57 tryToFindPtrOrigin(Expr->getFalseExpr(), StopAtFirstRefCountedObj,
58 callback);
59 }
60 if (auto *cast = dyn_cast<CastExpr>(E)) {
61 if (StopAtFirstRefCountedObj) {
62 if (auto *ConversionFunc =
63 dyn_cast_or_null<FunctionDecl>(cast->getConversionFunction())) {
64 if (isCtorOfSafePtr(ConversionFunc))
65 return callback(E, true);
66 }
67 }
68 // FIXME: This can give false "origin" that would lead to false negatives
69 // in checkers. See https://reviews.llvm.org/D37023 for reference.
70 E = cast->getSubExpr();
71 continue;
72 }
73 if (auto *call = dyn_cast<CallExpr>(E)) {
74 if (auto *memberCall = dyn_cast<CXXMemberCallExpr>(call)) {
75 if (auto *decl = memberCall->getMethodDecl()) {
76 std::optional<bool> IsGetterOfRefCt = isGetterOfSafePtr(decl);
77 if (IsGetterOfRefCt && *IsGetterOfRefCt) {
78 E = memberCall->getImplicitObjectArgument();
79 if (StopAtFirstRefCountedObj) {
80 return callback(E, true);
81 }
82 continue;
83 }
84 }
85 }
86
87 if (auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(E)) {
88 if (operatorCall->getNumArgs() == 1) {
89 E = operatorCall->getArg(0);
90 continue;
91 }
92 }
93
94 if (auto *callee = call->getDirectCallee()) {
95 if (isCtorOfRefCounted(callee) || isCtorOfCheckedPtr(callee)) {
96 if (StopAtFirstRefCountedObj)
97 return callback(E, true);
98
99 E = call->getArg(0);
100 continue;
101 }
102
103 if (isSafePtrType(callee->getReturnType()))
104 return callback(E, true);
105
106 if (isSingleton(callee))
107 return callback(E, true);
108
109 if (callee->isInStdNamespace() && safeGetName(callee) == "forward") {
110 E = call->getArg(0);
111 continue;
112 }
113
114 if (isPtrConversion(callee)) {
115 E = call->getArg(0);
116 continue;
117 }
118 }
119 }
120 if (auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E)) {
121 if (auto *Method = ObjCMsgExpr->getMethodDecl()) {
122 if (isSafePtrType(Method->getReturnType()))
123 return callback(E, true);
124 }
125 }
126 if (auto *unaryOp = dyn_cast<UnaryOperator>(E)) {
127 // FIXME: Currently accepts ANY unary operator. Is it OK?
128 E = unaryOp->getSubExpr();
129 continue;
130 }
131
132 break;
133 }
134 // Some other expression.
135 return callback(E, false);
136}
137
138bool isASafeCallArg(const Expr *E) {
139 assert(E);
140 if (auto *Ref = dyn_cast<DeclRefExpr>(E)) {
141 if (auto *D = dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) {
142 if (isa<ParmVarDecl>(D) || D->isLocalVarDecl())
143 return true;
144 }
145 }
147 return true;
148
149 // TODO: checker for method calls on non-refcounted objects
150 return isa<CXXThisExpr>(E);
151}
152
154 if (auto *MCE = dyn_cast<CXXMemberCallExpr>(E)) {
155 if (auto *Callee = MCE->getDirectCallee()) {
156 auto Name = safeGetName(Callee);
157 if (Name == "get" || Name == "ptr") {
158 auto *ThisArg = MCE->getImplicitObjectArgument();
159 E = ThisArg;
160 }
161 }
162 } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) {
163 if (OCE->getOperator() == OO_Star && OCE->getNumArgs() == 1)
164 E = OCE->getArg(0);
165 }
166 auto *ME = dyn_cast<MemberExpr>(E);
167 if (!ME)
168 return false;
169 auto *D = ME->getMemberDecl();
170 if (!D)
171 return false;
172 auto T = D->getType();
173 return isOwnerPtrType(T) && T.isConstQualified();
174}
175
177 : public ConstStmtVisitor<EnsureFunctionVisitor, bool> {
178public:
179 bool VisitStmt(const Stmt *S) {
180 for (const Stmt *Child : S->children()) {
181 if (Child && !Visit(Child))
182 return false;
183 }
184 return true;
185 }
186
187 bool VisitReturnStmt(const ReturnStmt *RS) {
188 if (auto *RV = RS->getRetValue()) {
189 RV = RV->IgnoreParenCasts();
190 if (isa<CXXNullPtrLiteralExpr>(RV))
191 return true;
192 return isConstOwnerPtrMemberExpr(RV);
193 }
194 return false;
195 }
196};
197
199 auto *MCE = dyn_cast<CXXMemberCallExpr>(E);
200 if (!MCE)
201 return false;
202 auto *Callee = MCE->getDirectCallee();
203 if (!Callee)
204 return false;
205 auto *Body = Callee->getBody();
206 if (!Body)
207 return false;
208 auto [CacheIt, IsNew] = Cache.insert(std::make_pair(Callee, false));
209 if (IsNew)
210 CacheIt->second = EnsureFunctionVisitor().Visit(Body);
211 return CacheIt->second;
212}
213
214} // namespace clang
const Decl * D
Expr * E
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:195
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
bool isACallToEnsureFn(const Expr *E) const
Definition: ASTUtils.cpp:198
bool VisitReturnStmt(const ReturnStmt *RS)
Definition: ASTUtils.cpp:187
bool VisitStmt(const Stmt *S)
Definition: ASTUtils.cpp:179
This represents one expression.
Definition: Expr.h:110
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition: Stmt.h:3046
Expr * getRetValue()
Definition: Stmt.h:3077
RetTy Visit(PTR(Stmt) S, ParamTys... P)
Definition: StmtVisitor.h:44
Stmt - This represents one statement.
Definition: Stmt.h:84
The type-property cache.
Definition: Type.cpp:4501
const internal::VariadicAllOfMatcher< Decl > decl
Matches declarations.
The JSON file list parser is used to communicate input to InstallAPI.
bool isCtorOfSafePtr(const clang::FunctionDecl *F)
bool isPtrConversion(const FunctionDecl *F)
bool isCtorOfRefCounted(const clang::FunctionDecl *F)
bool isASafeCallArg(const Expr *E)
For E referring to a ref-countable/-counted pointer/reference we return whether it's a safe call argu...
Definition: ASTUtils.cpp:138
bool isSingleton(const FunctionDecl *F)
bool isRefCounted(const CXXRecordDecl *R)
bool isOwnerPtrType(const clang::QualType T)
bool isSafePtrType(const clang::QualType T)
std::optional< bool > isGetterOfSafePtr(const CXXMethodDecl *M)
const FunctionProtoType * T
bool isSafePtr(clang::CXXRecordDecl *Decl)
Definition: ASTUtils.cpp:21
bool tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj, std::function< bool(const clang::Expr *, bool)> callback)
This function de-facto defines a set of transformations that we consider safe (in heuristical sense).
Definition: ASTUtils.cpp:25
std::string safeGetName(const T *ASTNode)
Definition: ASTUtils.h:81
bool isCtorOfCheckedPtr(const clang::FunctionDecl *F)
bool isCheckedPtr(const std::string &Name)
U cast(CodeGen::Address addr)
Definition: Address.h:325
@ Class
The "class" keyword introduces the elaborated-type-specifier.
bool isConstOwnerPtrMemberExpr(const clang::Expr *E)
Definition: ASTUtils.cpp:153