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 Korous tryToFindPtrOrigin(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 Korous bool 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