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