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_ANY_CALL_H 14#define LLVM_CLANG_ANALYSIS_ANY_CALL_H 15 16#include "clang/AST/Decl.h" 17#include "clang/AST/ExprCXX.h" 18#include "clang/AST/ExprObjC.h" 19 20namespace 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. 25class AnyCall { 26public: 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++ allocation function call (operator `new`), via C++ new-expression 45 Allocator, 46 47 /// A C++ deallocation function call (operator `delete`), via C++ 48 /// delete-expression 49 Deallocator 50 }; 51 52private: 53 /// Either expression or declaration (but not both at the same time) 54 /// can be null. 55 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; 59 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; 63 Kind K; 64 65public: 66 AnyCall(const CallExpr *CE) : E(CE) { 67 D = CE->getCalleeDecl(); 68 K = (CE->getCallee()->getType()->getAs<BlockPointerType>()) ? Block 69 : Function; 70 if (D && ((K == Function && !isa<FunctionDecl>(D)) || 71 (K == Block && !isa<BlockDecl>(D)))) 72 D = nullptr; 73 } 74 75 AnyCall(const ObjCMessageExpr *ME) 76 : E(ME), D(ME->getMethodDecl()), K(ObjCMethod) {} 77 78 AnyCall(const CXXNewExpr *NE) 79 : E(NE), D(NE->getOperatorNew()), K(Allocator) {} 80 81 AnyCall(const CXXDeleteExpr *NE) 82 : E(NE), D(NE->getOperatorDelete()), K(Deallocator) {} 83 84 AnyCall(const CXXConstructExpr *NE) 85 : E(NE), D(NE->getConstructor()), K(Constructor) {} 86 87 AnyCall(const CXXDestructorDecl *D) : E(nullptr), D(D), K(Destructor) {} 88 89 AnyCall(const CXXConstructorDecl *D) : E(nullptr), D(D), K(Constructor) {} 90 91 AnyCall(const ObjCMethodDecl *D) : E(nullptr), D(D), K(ObjCMethod) {} 92 93 AnyCall(const FunctionDecl *D) : E(nullptr), D(D) { 94 if (isa<CXXConstructorDecl>(D)) { 95 K = Constructor; 96 } else if (isa <CXXDestructorDecl>(D)) { 97 K = Destructor; 98 } else { 99 K = Function; 100 } 101 102 } 103 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)) { 108 return AnyCall(ME); 109 } else if (const auto *CE = dyn_cast<CallExpr>(E)) { 110 return AnyCall(CE); 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); 117 } else { 118 return None; 119 } 120 } 121 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)) { 127 return AnyCall(FD); 128 } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { 129 return AnyCall(MD); 130 } 131 return None; 132 } 133 134 /// \returns formal parameters for direct calls (including virtual calls) 135 ArrayRef<ParmVarDecl *> parameters() const { 136 if (!D) 137 return None; 138 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(); 145 } else { 146 return None; 147 } 148 } 149 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(); } 155 156 QualType getReturnType(ASTContext &Ctx) const { 157 switch (K) { 158 case Function: 159 if (E) 160 return cast<CallExpr>(E)->getCallReturnType(Ctx); 161 return cast<FunctionDecl>(D)->getReturnType(); 162 case ObjCMethod: 163 if (E) 164 return cast<ObjCMessageExpr>(E)->getCallReturnType(Ctx); 165 return cast<ObjCMethodDecl>(D)->getReturnType(); 166 case Block: 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); 170 case Destructor: 171 case Constructor: 172 case Allocator: 173 case Deallocator: 174 return cast<FunctionDecl>(D)->getReturnType(); 175 } 176 llvm_unreachable("Unknown AnyCall::Kind"); 177 } 178 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(); 184 return nullptr; 185 } 186 187 const Decl *getDecl() const { 188 return D; 189 } 190 191 const Expr *getExpr() const { 192 return E; 193 } 194 195 Kind getKind() const { 196 return K; 197 } 198 199 void dump() const { 200 if (E) 201 E->dump(); 202 if (D) 203 D->dump(); 204 } 205}; 206 207} 208 209#endif // LLVM_CLANG_ANALYSIS_ANY_CALL_H 210