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