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