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   AnyCall(const CallExpr *CE) : E(CE) {
70     D = CE->getCalleeDecl();
71     K = (CE->getCallee()->getType()->getAs<BlockPointerType>()) ? Block
72                                                                 : Function;
73     if (D && ((K == Function && !isa<FunctionDecl>(D)) ||
74               (K == Block && !isa<BlockDecl>(D))))
75       D = nullptr;
76   }
77 
78   AnyCall(const ObjCMessageExpr *ME)
79       : E(ME), D(ME->getMethodDecl()), K(ObjCMethod) {}
80 
81   AnyCall(const CXXNewExpr *NE)
82       : E(NE), D(NE->getOperatorNew()), K(Allocator) {}
83 
84   AnyCall(const CXXDeleteExpr *NE)
85       : E(NE), D(NE->getOperatorDelete()), K(Deallocator) {}
86 
87   AnyCall(const CXXConstructExpr *NE)
88       : E(NE), D(NE->getConstructor()), K(Constructor) {}
89 
90   AnyCall(const CXXInheritedCtorInitExpr *CIE)
91       : E(CIE), D(CIE->getConstructor()), K(InheritedConstructor) {}
92 
93   AnyCall(const CXXDestructorDecl *D) : E(nullptr), D(D), K(Destructor) {}
94 
95   AnyCall(const CXXConstructorDecl *D) : E(nullptr), D(D), K(Constructor) {}
96 
97   AnyCall(const ObjCMethodDecl *D) : E(nullptr), D(D), K(ObjCMethod) {}
98 
99   AnyCall(const FunctionDecl *D) : E(nullptr), D(D) {
100     if (isa<CXXConstructorDecl>(D)) {
101       K = Constructor;
102     } else if (isa <CXXDestructorDecl>(D)) {
103       K = Destructor;
104     } else {
105       K = Function;
106     }
107 
108   }
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   static Optional<AnyCall> forExpr(const Expr *E) {
113     if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) {
114       return AnyCall(ME);
115     } else if (const auto *CE = dyn_cast<CallExpr>(E)) {
116       return AnyCall(CE);
117     } else if (const auto *CXNE = dyn_cast<CXXNewExpr>(E)) {
118       return AnyCall(CXNE);
119     } else if (const auto *CXDE = dyn_cast<CXXDeleteExpr>(E)) {
120       return AnyCall(CXDE);
121     } else if (const auto *CXCE = dyn_cast<CXXConstructExpr>(E)) {
122       return AnyCall(CXCE);
123     } else if (const auto *CXCIE = dyn_cast<CXXInheritedCtorInitExpr>(E)) {
124       return AnyCall(CXCIE);
125     } else {
126       return None;
127     }
128   }
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   static Optional<AnyCall> forDecl(const Decl *D) {
134     if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
135       return AnyCall(FD);
136     } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
137       return AnyCall(MD);
138     }
139     return None;
140   }
141 
142   /// \returns formal parameters for direct calls (including virtual calls)
143   ArrayRef<ParmVarDecl *> parameters() const {
144     if (!D)
145       return None;
146 
147     if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
148       return FD->parameters();
149     } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
150       return MD->parameters();
151     } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
152       return BD->parameters();
153     } else {
154       return None;
155     }
156   }
157 
158   using param_const_iterator = ArrayRef<ParmVarDecl *>::const_iterator;
159   param_const_iterator param_begin() const { return parameters().begin(); }
160   param_const_iterator param_end() const { return parameters().end(); }
161   size_t param_size() const { return parameters().size(); }
162   bool param_empty() const { return parameters().empty(); }
163 
164   QualType getReturnType(ASTContext &Ctx) const {
165     switch (K) {
166     case Function:
167       if (E)
168         return cast<CallExpr>(E)->getCallReturnType(Ctx);
169       return cast<FunctionDecl>(D)->getReturnType();
170     case ObjCMethod:
171       if (E)
172         return cast<ObjCMessageExpr>(E)->getCallReturnType(Ctx);
173       return cast<ObjCMethodDecl>(D)->getReturnType();
174     case Block:
175       // FIXME: BlockDecl does not know its return type,
176       // hence the asymmetry with the function and method cases above.
177       return cast<CallExpr>(E)->getCallReturnType(Ctx);
178     case Destructor:
179     case Constructor:
180     case InheritedConstructor:
181     case Allocator:
182     case Deallocator:
183       return cast<FunctionDecl>(D)->getReturnType();
184     }
185     llvm_unreachable("Unknown AnyCall::Kind");
186   }
187 
188   /// \returns Function identifier if it is a named declaration,
189   /// @c nullptr otherwise.
190   const IdentifierInfo *getIdentifier() const {
191     if (const auto *ND = dyn_cast_or_null<NamedDecl>(D))
192       return ND->getIdentifier();
193     return nullptr;
194   }
195 
196   const Decl *getDecl() const {
197     return D;
198   }
199 
200   const Expr *getExpr() const {
201     return E;
202   }
203 
204   Kind getKind() const {
205     return K;
206   }
207 
208   void dump() const {
209     if (E)
210       E->dump();
211     if (D)
212       D->dump();
213   }
214 };
215 
216 }
217 
218 #endif // LLVM_CLANG_ANALYSIS_ANYCALL_H
219