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