/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Analysis/AnyCall.h
Line | Count | Source (jump to first uncovered line) |
1 | | //=== AnyCall.h - Abstraction over different callables --------*- 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 | | // A utility class for performing generic operations over different callables. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | // |
13 | | #ifndef LLVM_CLANG_ANALYSIS_ANYCALL_H |
14 | | #define LLVM_CLANG_ANALYSIS_ANYCALL_H |
15 | | |
16 | | #include "clang/AST/Decl.h" |
17 | | #include "clang/AST/ExprCXX.h" |
18 | | #include "clang/AST/ExprObjC.h" |
19 | | |
20 | | namespace clang { |
21 | | |
22 | | /// An instance of this class corresponds to a call. |
23 | | /// It might be a syntactically-concrete call, done as a part of evaluating an |
24 | | /// expression, or it may be an abstract callee with no associated expression. |
25 | | class AnyCall { |
26 | | public: |
27 | | enum Kind { |
28 | | /// A function, function pointer, or a C++ method call |
29 | | Function, |
30 | | |
31 | | /// A call to an Objective-C method |
32 | | ObjCMethod, |
33 | | |
34 | | /// A call to an Objective-C block |
35 | | Block, |
36 | | |
37 | | /// An implicit C++ destructor call (called implicitly |
38 | | /// or by operator 'delete') |
39 | | Destructor, |
40 | | |
41 | | /// An implicit or explicit C++ constructor call |
42 | | Constructor, |
43 | | |
44 | | /// A C++ inherited constructor produced by a "using T::T" directive |
45 | | InheritedConstructor, |
46 | | |
47 | | /// A C++ allocation function call (operator `new`), via C++ new-expression |
48 | | Allocator, |
49 | | |
50 | | /// A C++ deallocation function call (operator `delete`), via C++ |
51 | | /// delete-expression |
52 | | Deallocator |
53 | | }; |
54 | | |
55 | | private: |
56 | | /// Either expression or declaration (but not both at the same time) |
57 | | /// can be null. |
58 | | |
59 | | /// Call expression, is null when is not known (then declaration is non-null), |
60 | | /// or for implicit destructor calls (when no expression exists.) |
61 | | const Expr *E = nullptr; |
62 | | |
63 | | /// Corresponds to a statically known declaration of the called function, |
64 | | /// or null if it is not known (e.g. for a function pointer). |
65 | | const Decl *D = nullptr; |
66 | | Kind K; |
67 | | |
68 | | public: |
69 | 1.94k | AnyCall(const CallExpr *CE) : E(CE) { |
70 | 1.94k | D = CE->getCalleeDecl(); |
71 | 1.94k | K = (CE->getCallee()->getType()->getAs<BlockPointerType>()) ? Block38 |
72 | 1.94k | : Function1.90k ; |
73 | 1.94k | if (D && ((K == Function && !isa<FunctionDecl>(D)1.90k ) || |
74 | 1.94k | (1.87k K == Block1.87k && !isa<BlockDecl>(D)38 ))) |
75 | 92 | D = nullptr; |
76 | 1.94k | } |
77 | | |
78 | | AnyCall(const ObjCMessageExpr *ME) |
79 | 2.31k | : E(ME), D(ME->getMethodDecl()), K(ObjCMethod) {} |
80 | | |
81 | | AnyCall(const CXXNewExpr *NE) |
82 | 24 | : E(NE), D(NE->getOperatorNew()), K(Allocator) {} |
83 | | |
84 | | AnyCall(const CXXDeleteExpr *NE) |
85 | 1 | : E(NE), D(NE->getOperatorDelete()), K(Deallocator) {} |
86 | | |
87 | | AnyCall(const CXXConstructExpr *NE) |
88 | 126 | : E(NE), D(NE->getConstructor()), K(Constructor) {} |
89 | | |
90 | | AnyCall(const CXXInheritedCtorInitExpr *CIE) |
91 | 1 | : E(CIE), D(CIE->getConstructor()), K(InheritedConstructor) {} |
92 | | |
93 | 13 | AnyCall(const CXXDestructorDecl *D) : E(nullptr), D(D), K(Destructor) {} |
94 | | |
95 | 0 | AnyCall(const CXXConstructorDecl *D) : E(nullptr), D(D), K(Constructor) {} |
96 | | |
97 | 1.52k | AnyCall(const ObjCMethodDecl *D) : E(nullptr), D(D), K(ObjCMethod) {} |
98 | | |
99 | 14.6k | AnyCall(const FunctionDecl *D) : E(nullptr), D(D) { |
100 | 14.6k | if (isa<CXXConstructorDecl>(D)) { |
101 | 961 | K = Constructor; |
102 | 13.7k | } else if (isa <CXXDestructorDecl>(D)) { |
103 | 57 | K = Destructor; |
104 | 13.6k | } else { |
105 | 13.6k | K = Function; |
106 | 13.6k | } |
107 | | |
108 | 14.6k | } |
109 | | |
110 | | /// If @c E is a generic call (to ObjC method /function/block/etc), |
111 | | /// return a constructed @c AnyCall object. Return None otherwise. |
112 | 4.41k | static Optional<AnyCall> forExpr(const Expr *E) { |
113 | 4.41k | if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) { |
114 | 2.31k | return AnyCall(ME); |
115 | 2.31k | } else if (const auto *2.09k CE2.09k = dyn_cast<CallExpr>(E)) { |
116 | 1.94k | return AnyCall(CE); |
117 | 1.94k | } else if (const auto *152 CXNE152 = dyn_cast<CXXNewExpr>(E)) { |
118 | 24 | return AnyCall(CXNE); |
119 | 128 | } else if (const auto *CXDE = dyn_cast<CXXDeleteExpr>(E)) { |
120 | 1 | return AnyCall(CXDE); |
121 | 127 | } else if (const auto *CXCE = dyn_cast<CXXConstructExpr>(E)) { |
122 | 126 | return AnyCall(CXCE); |
123 | 126 | } else if (const auto *1 CXCIE1 = dyn_cast<CXXInheritedCtorInitExpr>(E)) { |
124 | 1 | return AnyCall(CXCIE); |
125 | 1 | } else { |
126 | 0 | return None; |
127 | 0 | } |
128 | 4.41k | } |
129 | | |
130 | | /// If @c D is a callable (Objective-C method or a function), return |
131 | | /// a constructed @c AnyCall object. Return None otherwise. |
132 | | // FIXME: block support. |
133 | 16.0k | static Optional<AnyCall> forDecl(const Decl *D) { |
134 | 16.0k | if (const auto *FD = dyn_cast<FunctionDecl>(D)) { |
135 | 14.5k | return AnyCall(FD); |
136 | 14.5k | } else if (const auto *1.55k MD1.55k = dyn_cast<ObjCMethodDecl>(D)) { |
137 | 1.28k | return AnyCall(MD); |
138 | 1.28k | } |
139 | 271 | return None; |
140 | 16.0k | } |
141 | | |
142 | | /// \returns formal parameters for direct calls (including virtual calls) |
143 | 55.6k | ArrayRef<ParmVarDecl *> parameters() const { |
144 | 55.6k | if (!D) |
145 | 152 | return None; |
146 | | |
147 | 55.4k | if (const auto *FD = dyn_cast<FunctionDecl>(D)) { |
148 | 46.6k | return FD->parameters(); |
149 | 46.6k | } else if (const auto *8.88k MD8.88k = dyn_cast<ObjCMethodDecl>(D)) { |
150 | 8.88k | return MD->parameters(); |
151 | 8.88k | } else if (const auto *0 BD0 = dyn_cast<BlockDecl>(D)) { |
152 | 0 | return BD->parameters(); |
153 | 0 | } else { |
154 | 0 | return None; |
155 | 0 | } |
156 | 55.4k | } |
157 | | |
158 | | using param_const_iterator = ArrayRef<ParmVarDecl *>::const_iterator; |
159 | 6.21k | param_const_iterator param_begin() const { return parameters().begin(); } |
160 | 6.21k | param_const_iterator param_end() const { return parameters().end(); } |
161 | 15.0k | size_t param_size() const { return parameters().size(); } |
162 | 0 | bool param_empty() const { return parameters().empty(); } |
163 | | |
164 | 709 | QualType getReturnType(ASTContext &Ctx) const { |
165 | 709 | switch (K) { |
166 | 641 | case Function: |
167 | 641 | if (E) |
168 | 0 | return cast<CallExpr>(E)->getCallReturnType(Ctx); |
169 | 641 | return cast<FunctionDecl>(D)->getReturnType(); |
170 | 62 | case ObjCMethod: |
171 | 62 | if (E) |
172 | 0 | return cast<ObjCMessageExpr>(E)->getCallReturnType(Ctx); |
173 | 62 | return cast<ObjCMethodDecl>(D)->getReturnType(); |
174 | 0 | case Block: |
175 | | // FIXME: BlockDecl does not know its return type, |
176 | | // hence the asymmetry with the function and method cases above. |
177 | 0 | return cast<CallExpr>(E)->getCallReturnType(Ctx); |
178 | 3 | case Destructor: |
179 | 6 | case Constructor: |
180 | 6 | case InheritedConstructor: |
181 | 6 | case Allocator: |
182 | 6 | case Deallocator: |
183 | 6 | return cast<FunctionDecl>(D)->getReturnType(); |
184 | 709 | } |
185 | 0 | llvm_unreachable("Unknown AnyCall::Kind"); |
186 | 0 | } |
187 | | |
188 | | /// \returns Function identifier if it is a named declaration, |
189 | | /// @c nullptr otherwise. |
190 | 84 | const IdentifierInfo *getIdentifier() const { |
191 | 84 | if (const auto *ND = dyn_cast_or_null<NamedDecl>(D)) |
192 | 84 | return ND->getIdentifier(); |
193 | 0 | return nullptr; |
194 | 84 | } |
195 | | |
196 | 17.5k | const Decl *getDecl() const { |
197 | 17.5k | return D; |
198 | 17.5k | } |
199 | | |
200 | 2.98k | const Expr *getExpr() const { |
201 | 2.98k | return E; |
202 | 2.98k | } |
203 | | |
204 | 6.26k | Kind getKind() const { |
205 | 6.26k | return K; |
206 | 6.26k | } |
207 | | |
208 | 0 | void dump() const { |
209 | 0 | if (E) |
210 | 0 | E->dump(); |
211 | 0 | if (D) |
212 | 0 | D->dump(); |
213 | 0 | } |
214 | | }; |
215 | | |
216 | | } |
217 | | |
218 | | #endif // LLVM_CLANG_ANALYSIS_ANYCALL_H |