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" |
11 | #include "clang/AST/CXXInheritance.h" |
12 | #include "clang/AST/Decl.h" |
13 | #include "clang/AST/DeclCXX.h" |
14 | #include "clang/AST/ExprCXX.h" |
15 | #include <optional> |
16 | |
17 | namespace clang { |
18 | |
19 | bool tryToFindPtrOrigin( |
20 | const Expr *E, bool StopAtFirstRefCountedObj, |
21 | std::function<bool(const clang::Expr *, bool)> callback) { |
22 | while (E) { |
23 | if (auto *tempExpr = dyn_cast<MaterializeTemporaryExpr>(Val: E)) { |
24 | E = tempExpr->getSubExpr(); |
25 | continue; |
26 | } |
27 | if (auto *tempExpr = dyn_cast<CXXBindTemporaryExpr>(Val: E)) { |
28 | E = tempExpr->getSubExpr(); |
29 | continue; |
30 | } |
31 | if (auto *tempExpr = dyn_cast<CXXTemporaryObjectExpr>(Val: E)) { |
32 | if (auto *C = tempExpr->getConstructor()) { |
33 | if (auto *Class = C->getParent(); Class && isRefCounted(Class)) |
34 | return callback(E, true); |
35 | break; |
36 | } |
37 | } |
38 | if (auto *tempExpr = dyn_cast<ParenExpr>(Val: E)) { |
39 | E = tempExpr->getSubExpr(); |
40 | continue; |
41 | } |
42 | if (auto *Expr = dyn_cast<ConditionalOperator>(Val: E)) { |
43 | return tryToFindPtrOrigin(E: Expr->getTrueExpr(), StopAtFirstRefCountedObj, |
44 | callback) && |
45 | tryToFindPtrOrigin(E: Expr->getFalseExpr(), StopAtFirstRefCountedObj, |
46 | callback); |
47 | } |
48 | if (auto *cast = dyn_cast<CastExpr>(Val: E)) { |
49 | if (StopAtFirstRefCountedObj) { |
50 | if (auto *ConversionFunc = |
51 | dyn_cast_or_null<FunctionDecl>(Val: cast->getConversionFunction())) { |
52 | if (isCtorOfRefCounted(F: ConversionFunc)) |
53 | return callback(E, true); |
54 | } |
55 | } |
56 | // FIXME: This can give false "origin" that would lead to false negatives |
57 | // in checkers. See https://reviews.llvm.org/D37023 for reference. |
58 | E = cast->getSubExpr(); |
59 | continue; |
60 | } |
61 | if (auto *call = dyn_cast<CallExpr>(Val: E)) { |
62 | if (auto *memberCall = dyn_cast<CXXMemberCallExpr>(Val: call)) { |
63 | if (auto *decl = memberCall->getMethodDecl()) { |
64 | std::optional<bool> IsGetterOfRefCt = isGetterOfRefCounted(Method: decl); |
65 | if (IsGetterOfRefCt && *IsGetterOfRefCt) { |
66 | E = memberCall->getImplicitObjectArgument(); |
67 | if (StopAtFirstRefCountedObj) { |
68 | return callback(E, true); |
69 | } |
70 | continue; |
71 | } |
72 | } |
73 | } |
74 | |
75 | if (auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(Val: E)) { |
76 | if (operatorCall->getNumArgs() == 1) { |
77 | E = operatorCall->getArg(Arg: 0); |
78 | continue; |
79 | } |
80 | } |
81 | |
82 | if (auto *callee = call->getDirectCallee()) { |
83 | if (isCtorOfRefCounted(F: callee)) { |
84 | if (StopAtFirstRefCountedObj) |
85 | return callback(E, true); |
86 | |
87 | E = call->getArg(Arg: 0); |
88 | continue; |
89 | } |
90 | |
91 | if (isReturnValueRefCounted(F: callee)) |
92 | return callback(E, true); |
93 | |
94 | if (isSingleton(F: callee)) |
95 | return callback(E, true); |
96 | |
97 | if (isPtrConversion(F: callee)) { |
98 | E = call->getArg(Arg: 0); |
99 | continue; |
100 | } |
101 | } |
102 | } |
103 | if (auto *unaryOp = dyn_cast<UnaryOperator>(Val: E)) { |
104 | // FIXME: Currently accepts ANY unary operator. Is it OK? |
105 | E = unaryOp->getSubExpr(); |
106 | continue; |
107 | } |
108 | |
109 | break; |
110 | } |
111 | // Some other expression. |
112 | return callback(E, false); |
113 | } |
114 | |
115 | bool isASafeCallArg(const Expr *E) { |
116 | assert(E); |
117 | if (auto *Ref = dyn_cast<DeclRefExpr>(Val: E)) { |
118 | if (auto *D = dyn_cast_or_null<VarDecl>(Val: Ref->getFoundDecl())) { |
119 | if (isa<ParmVarDecl>(Val: D) || D->isLocalVarDecl()) |
120 | return true; |
121 | } |
122 | } |
123 | |
124 | // TODO: checker for method calls on non-refcounted objects |
125 | return isa<CXXThisExpr>(Val: E); |
126 | } |
127 | |
128 | } // namespace clang |
129 | |