1 //=== AnyCall.h - Abstraction over different callables --------*- C++ -*--//
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
7 //===----------------------------------------------------------------------===//
9 // A utility class for performing generic operations over different callables.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_CLANG_ANALYSIS_ANY_CALL_H
14 #define LLVM_CLANG_ANALYSIS_ANY_CALL_H
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/ExprCXX.h"
18 #include "clang/AST/ExprObjC.h"
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.
28 /// A function, function pointer, or a C++ method call
31 /// A call to an Objective-C method
34 /// A call to an Objective-C block
37 /// An implicit C++ destructor call (called implicitly
38 /// or by operator 'delete')
41 /// An implicit or explicit C++ constructor call
44 /// A C++ allocation function call (operator `new`), via C++ new-expression
47 /// A C++ deallocation function call (operator `delete`), via C++
53 /// Either expression or declaration (but not both at the same time)
56 /// Call expression, is null when is not known (then declaration is non-null),
57 /// or for implicit destructor calls (when no expression exists.)
58 const Expr *E = nullptr;
60 /// Corresponds to a statically known declaration of the called function,
61 /// or null if it is not known (e.g. for a function pointer).
62 const Decl *D = nullptr;
66 AnyCall(const CallExpr *CE) : E(CE) {
67 D = CE->getCalleeDecl();
68 K = (CE->getCallee()->getType()->getAs<BlockPointerType>()) ? Block
70 if (D && ((K == Function && !isa<FunctionDecl>(D)) ||
71 (K == Block && !isa<BlockDecl>(D))))
75 AnyCall(const ObjCMessageExpr *ME)
76 : E(ME), D(ME->getMethodDecl()), K(ObjCMethod) {}
78 AnyCall(const CXXNewExpr *NE)
79 : E(NE), D(NE->getOperatorNew()), K(Allocator) {}
81 AnyCall(const CXXDeleteExpr *NE)
82 : E(NE), D(NE->getOperatorDelete()), K(Deallocator) {}
84 AnyCall(const CXXConstructExpr *NE)
85 : E(NE), D(NE->getConstructor()), K(Constructor) {}
87 AnyCall(const CXXDestructorDecl *D) : E(nullptr), D(D), K(Destructor) {}
89 AnyCall(const CXXConstructorDecl *D) : E(nullptr), D(D), K(Constructor) {}
91 AnyCall(const ObjCMethodDecl *D) : E(nullptr), D(D), K(ObjCMethod) {}
93 AnyCall(const FunctionDecl *D) : E(nullptr), D(D) {
94 if (isa<CXXConstructorDecl>(D)) {
96 } else if (isa <CXXDestructorDecl>(D)) {
104 /// If {@code E} is a generic call (to ObjC method /function/block/etc),
105 /// return a constructed {@code AnyCall} object. Return None otherwise.
106 static Optional<AnyCall> forExpr(const Expr *E) {
107 if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) {
109 } else if (const auto *CE = dyn_cast<CallExpr>(E)) {
111 } else if (const auto *CXNE = dyn_cast<CXXNewExpr>(E)) {
112 return AnyCall(CXNE);
113 } else if (const auto *CXDE = dyn_cast<CXXDeleteExpr>(E)) {
114 return AnyCall(CXDE);
115 } else if (const auto *CXCE = dyn_cast<CXXConstructExpr>(E)) {
116 return AnyCall(CXCE);
122 /// If {@code D} is a callable (Objective-C method or a function), return
123 /// a constructed {@code AnyCall} object. Return None otherwise.
124 // FIXME: block support.
125 static Optional<AnyCall> forDecl(const Decl *D) {
126 if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
128 } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
134 /// \returns formal parameters for direct calls (including virtual calls)
135 ArrayRef<ParmVarDecl *> parameters() const {
139 if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
140 return FD->parameters();
141 } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
142 return MD->parameters();
143 } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
144 return BD->parameters();
150 using param_const_iterator = ArrayRef<ParmVarDecl *>::const_iterator;
151 param_const_iterator param_begin() const { return parameters().begin(); }
152 param_const_iterator param_end() const { return parameters().end(); }
153 size_t param_size() const { return parameters().size(); }
154 bool param_empty() const { return parameters().empty(); }
156 QualType getReturnType(ASTContext &Ctx) const {
160 return cast<CallExpr>(E)->getCallReturnType(Ctx);
161 return cast<FunctionDecl>(D)->getReturnType();
164 return cast<ObjCMessageExpr>(E)->getCallReturnType(Ctx);
165 return cast<ObjCMethodDecl>(D)->getReturnType();
167 // FIXME: BlockDecl does not know its return type,
168 // hence the asymmetry with the function and method cases above.
169 return cast<CallExpr>(E)->getCallReturnType(Ctx);
174 return cast<FunctionDecl>(D)->getReturnType();
176 llvm_unreachable("Unknown AnyCall::Kind");
179 /// \returns Function identifier if it is a named declaration,
180 /// {@code nullptr} otherwise.
181 const IdentifierInfo *getIdentifier() const {
182 if (const auto *ND = dyn_cast_or_null<NamedDecl>(D))
183 return ND->getIdentifier();
187 const Decl *getDecl() const {
191 const Expr *getExpr() const {
195 Kind getKind() const {
209 #endif // LLVM_CLANG_ANALYSIS_ANY_CALL_H