xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 //=======- ASTUtils.cpp ------------------------------------------*- C++ -*-==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "ASTUtils.h"
10 #include "PtrTypesSemantics.h"
11 #include "clang/AST/CXXInheritance.h"
12 #include "clang/AST/Decl.h"
13 #include "clang/AST/DeclCXX.h"
14 #include "clang/AST/ExprCXX.h"
15 #include <optional>
16 
17 namespace clang {
18 
19 bool tryToFindPtrOrigin(
20     const Expr *E, bool StopAtFirstRefCountedObj,
21     std::function<bool(const clang::Expr *, bool)> callback) {
22   while (E) {
23     if (auto *tempExpr = dyn_cast<MaterializeTemporaryExpr>(E)) {
24       E = tempExpr->getSubExpr();
25       continue;
26     }
27     if (auto *tempExpr = dyn_cast<CXXBindTemporaryExpr>(E)) {
28       E = tempExpr->getSubExpr();
29       continue;
30     }
31     if (auto *tempExpr = dyn_cast<CXXTemporaryObjectExpr>(E)) {
32       if (auto *C = tempExpr->getConstructor()) {
33         if (auto *Class = C->getParent(); Class && isRefCounted(Class))
34           return callback(E, true);
35         break;
36       }
37     }
38     if (auto *tempExpr = dyn_cast<ParenExpr>(E)) {
39       E = tempExpr->getSubExpr();
40       continue;
41     }
42     if (auto *Expr = dyn_cast<ConditionalOperator>(E)) {
43       return tryToFindPtrOrigin(Expr->getTrueExpr(), StopAtFirstRefCountedObj,
44                                 callback) &&
45              tryToFindPtrOrigin(Expr->getFalseExpr(), StopAtFirstRefCountedObj,
46                                 callback);
47     }
48     if (auto *cast = dyn_cast<CastExpr>(E)) {
49       if (StopAtFirstRefCountedObj) {
50         if (auto *ConversionFunc =
51                 dyn_cast_or_null<FunctionDecl>(cast->getConversionFunction())) {
52           if (isCtorOfRefCounted(ConversionFunc))
53             return callback(E, true);
54         }
55       }
56       // FIXME: This can give false "origin" that would lead to false negatives
57       // in checkers. See https://reviews.llvm.org/D37023 for reference.
58       E = cast->getSubExpr();
59       continue;
60     }
61     if (auto *call = dyn_cast<CallExpr>(E)) {
62       if (auto *memberCall = dyn_cast<CXXMemberCallExpr>(call)) {
63         if (auto *decl = memberCall->getMethodDecl()) {
64           std::optional<bool> IsGetterOfRefCt = isGetterOfRefCounted(decl);
65           if (IsGetterOfRefCt && *IsGetterOfRefCt) {
66             E = memberCall->getImplicitObjectArgument();
67             if (StopAtFirstRefCountedObj) {
68               return callback(E, true);
69             }
70             continue;
71           }
72         }
73       }
74 
75       if (auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(E)) {
76         if (operatorCall->getNumArgs() == 1) {
77           E = operatorCall->getArg(0);
78           continue;
79         }
80       }
81 
82       if (auto *callee = call->getDirectCallee()) {
83         if (isCtorOfRefCounted(callee)) {
84           if (StopAtFirstRefCountedObj)
85             return callback(E, true);
86 
87           E = call->getArg(0);
88           continue;
89         }
90 
91         if (isReturnValueRefCounted(callee))
92           return callback(E, true);
93 
94         if (isSingleton(callee))
95           return callback(E, true);
96 
97         if (isPtrConversion(callee)) {
98           E = call->getArg(0);
99           continue;
100         }
101       }
102     }
103     if (auto *unaryOp = dyn_cast<UnaryOperator>(E)) {
104       // FIXME: Currently accepts ANY unary operator. Is it OK?
105       E = unaryOp->getSubExpr();
106       continue;
107     }
108 
109     break;
110   }
111   // Some other expression.
112   return callback(E, false);
113 }
114 
115 bool isASafeCallArg(const Expr *E) {
116   assert(E);
117   if (auto *Ref = dyn_cast<DeclRefExpr>(E)) {
118     if (auto *D = dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) {
119       if (isa<ParmVarDecl>(D) || D->isLocalVarDecl())
120         return true;
121     }
122   }
123 
124   // TODO: checker for method calls on non-refcounted objects
125   return isa<CXXThisExpr>(E);
126 }
127 
128 } // namespace clang
129