1228753Smm//=======- ASTUtils.cpp ------------------------------------------*- C++ -*-==//
2228753Smm//
3228753Smm// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4228753Smm// See https://llvm.org/LICENSE.txt for license information.
5228753Smm// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6228753Smm//
7228753Smm//===----------------------------------------------------------------------===//
8228753Smm
9228753Smm#include "ASTUtils.h"
10228753Smm#include "PtrTypesSemantics.h"
11228753Smm#include "clang/AST/CXXInheritance.h"
12228753Smm#include "clang/AST/Decl.h"
13228753Smm#include "clang/AST/DeclCXX.h"
14228753Smm#include "clang/AST/ExprCXX.h"
15228753Smm
16228753Smmusing llvm::Optional;
17228753Smmnamespace clang {
18228753Smm
19228753Smmstd::pair<const Expr *, bool>
20228753SmmtryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
21228753Smm  while (E) {
22228753Smm    if (auto *cast = dyn_cast<CastExpr>(E)) {
23228753Smm      if (StopAtFirstRefCountedObj) {
24228753Smm        if (auto *ConversionFunc =
25228753Smm                dyn_cast_or_null<FunctionDecl>(cast->getConversionFunction())) {
26228763Smm          if (isCtorOfRefCounted(ConversionFunc))
27228753Smm            return {E, true};
28228753Smm        }
29228753Smm      }
30228753Smm      // FIXME: This can give false "origin" that would lead to false negatives
31228753Smm      // in checkers. See https://reviews.llvm.org/D37023 for reference.
32228753Smm      E = cast->getSubExpr();
33228753Smm      continue;
34228753Smm    }
35228753Smm    if (auto *call = dyn_cast<CallExpr>(E)) {
36228753Smm      if (auto *memberCall = dyn_cast<CXXMemberCallExpr>(call)) {
37228753Smm        Optional<bool> IsGetterOfRefCt =
38228753Smm            isGetterOfRefCounted(memberCall->getMethodDecl());
39228753Smm        if (IsGetterOfRefCt && *IsGetterOfRefCt) {
40228753Smm          E = memberCall->getImplicitObjectArgument();
41228753Smm          if (StopAtFirstRefCountedObj) {
42228753Smm            return {E, true};
43228753Smm          }
44228753Smm          continue;
45228753Smm        }
46228753Smm      }
47228753Smm
48228753Smm      if (auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(E)) {
49228753Smm        if (operatorCall->getNumArgs() == 1) {
50228753Smm          E = operatorCall->getArg(0);
51228753Smm          continue;
52228753Smm        }
53228753Smm      }
54228753Smm
55228753Smm      if (auto *callee = call->getDirectCallee()) {
56228753Smm        if (isCtorOfRefCounted(callee)) {
57228753Smm          if (StopAtFirstRefCountedObj)
58228753Smm            return {E, true};
59228753Smm
60228753Smm          E = call->getArg(0);
61228753Smm          continue;
62228753Smm        }
63228753Smm
64228753Smm        if (isPtrConversion(callee)) {
65228753Smm          E = call->getArg(0);
66228753Smm          continue;
67228753Smm        }
68228753Smm      }
69228753Smm    }
70228753Smm    if (auto *unaryOp = dyn_cast<UnaryOperator>(E)) {
71228753Smm      // FIXME: Currently accepts ANY unary operator. Is it OK?
72228753Smm      E = unaryOp->getSubExpr();
73228753Smm      continue;
74228753Smm    }
75228753Smm
76228753Smm    break;
77228753Smm  }
78228753Smm  // Some other expression.
79228753Smm  return {E, false};
80228753Smm}
81228753Smm
82228753Smmbool isASafeCallArg(const Expr *E) {
83228753Smm  assert(E);
84228753Smm  if (auto *Ref = dyn_cast<DeclRefExpr>(E)) {
85228753Smm    if (auto *D = dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) {
86228753Smm      if (isa<ParmVarDecl>(D) || D->isLocalVarDecl())
87228753Smm        return true;
88228753Smm    }
89228753Smm  }
90228753Smm
91228753Smm  // TODO: checker for method calls on non-refcounted objects
92228753Smm  return isa<CXXThisExpr>(E);
93228753Smm}
94228753Smm
95228753Smm} // namespace clang
96228753Smm