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 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: AnyCall(const CallExpr * CE)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 AnyCall(const ObjCMessageExpr * ME)78 AnyCall(const ObjCMessageExpr *ME) 79 : E(ME), D(ME->getMethodDecl()), K(ObjCMethod) {} 80 AnyCall(const CXXNewExpr * NE)81 AnyCall(const CXXNewExpr *NE) 82 : E(NE), D(NE->getOperatorNew()), K(Allocator) {} 83 AnyCall(const CXXDeleteExpr * NE)84 AnyCall(const CXXDeleteExpr *NE) 85 : E(NE), D(NE->getOperatorDelete()), K(Deallocator) {} 86 AnyCall(const CXXConstructExpr * NE)87 AnyCall(const CXXConstructExpr *NE) 88 : E(NE), D(NE->getConstructor()), K(Constructor) {} 89 AnyCall(const CXXInheritedCtorInitExpr * CIE)90 AnyCall(const CXXInheritedCtorInitExpr *CIE) 91 : E(CIE), D(CIE->getConstructor()), K(InheritedConstructor) {} 92 AnyCall(const CXXDestructorDecl * D)93 AnyCall(const CXXDestructorDecl *D) : E(nullptr), D(D), K(Destructor) {} 94 AnyCall(const CXXConstructorDecl * D)95 AnyCall(const CXXConstructorDecl *D) : E(nullptr), D(D), K(Constructor) {} 96 AnyCall(const ObjCMethodDecl * D)97 AnyCall(const ObjCMethodDecl *D) : E(nullptr), D(D), K(ObjCMethod) {} 98 AnyCall(const FunctionDecl * D)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 {@code E} is a generic call (to ObjC method /function/block/etc), 111 /// return a constructed {@code AnyCall} object. Return None otherwise. forExpr(const Expr * E)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 {@code D} is a callable (Objective-C method or a function), return 131 /// a constructed {@code AnyCall} object. Return None otherwise. 132 // FIXME: block support. forDecl(const Decl * D)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) parameters()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; param_begin()159 param_const_iterator param_begin() const { return parameters().begin(); } param_end()160 param_const_iterator param_end() const { return parameters().end(); } param_size()161 size_t param_size() const { return parameters().size(); } param_empty()162 bool param_empty() const { return parameters().empty(); } 163 getReturnType(ASTContext & Ctx)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 /// {@code nullptr} otherwise. getIdentifier()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 getDecl()196 const Decl *getDecl() const { 197 return D; 198 } 199 getExpr()200 const Expr *getExpr() const { 201 return E; 202 } 203 getKind()204 Kind getKind() const { 205 return K; 206 } 207 dump()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_ANY_CALL_H 219