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