1a7eb3692SJan Korous //=======- ASTUtils.cpp ------------------------------------------*- C++ -*-==// 2a7eb3692SJan Korous // 3a7eb3692SJan Korous // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7eb3692SJan Korous // See https://llvm.org/LICENSE.txt for license information. 5a7eb3692SJan Korous // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7eb3692SJan Korous // 7a7eb3692SJan Korous //===----------------------------------------------------------------------===// 8a7eb3692SJan Korous 9a7eb3692SJan Korous #include "ASTUtils.h" 10a7eb3692SJan Korous #include "PtrTypesSemantics.h" 11a7eb3692SJan Korous #include "clang/AST/CXXInheritance.h" 12a7eb3692SJan Korous #include "clang/AST/Decl.h" 13a7eb3692SJan Korous #include "clang/AST/DeclCXX.h" 14a7eb3692SJan Korous #include "clang/AST/ExprCXX.h" 15a7eb3692SJan Korous 16a7eb3692SJan Korous using llvm::Optional; 17a7eb3692SJan Korous namespace clang { 18a7eb3692SJan Korous 19a7eb3692SJan Korous std::pair<const Expr *, bool> tryToFindPtrOrigin(const Expr * E,bool StopAtFirstRefCountedObj)20a7eb3692SJan KoroustryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) { 21a7eb3692SJan Korous while (E) { 22a7eb3692SJan Korous if (auto *cast = dyn_cast<CastExpr>(E)) { 23a7eb3692SJan Korous if (StopAtFirstRefCountedObj) { 24a7eb3692SJan Korous if (auto *ConversionFunc = 25a7eb3692SJan Korous dyn_cast_or_null<FunctionDecl>(cast->getConversionFunction())) { 26a7eb3692SJan Korous if (isCtorOfRefCounted(ConversionFunc)) 27a7eb3692SJan Korous return {E, true}; 28a7eb3692SJan Korous } 29a7eb3692SJan Korous } 30a7eb3692SJan Korous // FIXME: This can give false "origin" that would lead to false negatives 31a7eb3692SJan Korous // in checkers. See https://reviews.llvm.org/D37023 for reference. 32a7eb3692SJan Korous E = cast->getSubExpr(); 33a7eb3692SJan Korous continue; 34a7eb3692SJan Korous } 35a7eb3692SJan Korous if (auto *call = dyn_cast<CallExpr>(E)) { 36a7eb3692SJan Korous if (auto *memberCall = dyn_cast<CXXMemberCallExpr>(call)) { 37*47e68514SJan Korous Optional<bool> IsGetterOfRefCt = 38*47e68514SJan Korous isGetterOfRefCounted(memberCall->getMethodDecl()); 39*47e68514SJan Korous if (IsGetterOfRefCt && *IsGetterOfRefCt) { 40a7eb3692SJan Korous E = memberCall->getImplicitObjectArgument(); 41a7eb3692SJan Korous if (StopAtFirstRefCountedObj) { 42a7eb3692SJan Korous return {E, true}; 43a7eb3692SJan Korous } 44a7eb3692SJan Korous continue; 45a7eb3692SJan Korous } 46a7eb3692SJan Korous } 47a7eb3692SJan Korous 48a7eb3692SJan Korous if (auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(E)) { 49a7eb3692SJan Korous if (operatorCall->getNumArgs() == 1) { 50a7eb3692SJan Korous E = operatorCall->getArg(0); 51a7eb3692SJan Korous continue; 52a7eb3692SJan Korous } 53a7eb3692SJan Korous } 54a7eb3692SJan Korous 55a7eb3692SJan Korous if (auto *callee = call->getDirectCallee()) { 56a7eb3692SJan Korous if (isCtorOfRefCounted(callee)) { 57a7eb3692SJan Korous if (StopAtFirstRefCountedObj) 58a7eb3692SJan Korous return {E, true}; 59a7eb3692SJan Korous 60a7eb3692SJan Korous E = call->getArg(0); 61a7eb3692SJan Korous continue; 62a7eb3692SJan Korous } 63a7eb3692SJan Korous 64a7eb3692SJan Korous if (isPtrConversion(callee)) { 65a7eb3692SJan Korous E = call->getArg(0); 66a7eb3692SJan Korous continue; 67a7eb3692SJan Korous } 68a7eb3692SJan Korous } 69a7eb3692SJan Korous } 70a7eb3692SJan Korous if (auto *unaryOp = dyn_cast<UnaryOperator>(E)) { 71a7eb3692SJan Korous // FIXME: Currently accepts ANY unary operator. Is it OK? 72a7eb3692SJan Korous E = unaryOp->getSubExpr(); 73a7eb3692SJan Korous continue; 74a7eb3692SJan Korous } 75a7eb3692SJan Korous 76a7eb3692SJan Korous break; 77a7eb3692SJan Korous } 78a7eb3692SJan Korous // Some other expression. 79a7eb3692SJan Korous return {E, false}; 80a7eb3692SJan Korous } 81a7eb3692SJan Korous isASafeCallArg(const Expr * E)82a7eb3692SJan Korousbool isASafeCallArg(const Expr *E) { 83a7eb3692SJan Korous assert(E); 84a7eb3692SJan Korous if (auto *Ref = dyn_cast<DeclRefExpr>(E)) { 85a7eb3692SJan Korous if (auto *D = dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) { 86a7eb3692SJan Korous if (isa<ParmVarDecl>(D) || D->isLocalVarDecl()) 87a7eb3692SJan Korous return true; 88a7eb3692SJan Korous } 89a7eb3692SJan Korous } 90a7eb3692SJan Korous 91a7eb3692SJan Korous // TODO: checker for method calls on non-refcounted objects 92a7eb3692SJan Korous return isa<CXXThisExpr>(E); 93a7eb3692SJan Korous } 94a7eb3692SJan Korous 95a7eb3692SJan Korous } // namespace clang 96