xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
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)20ec727ea7Spatrick tryToFindPtrOrigin(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)81ec727ea7Spatrick bool 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