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: AnyCall(const CallExpr * CE)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 AnyCall(const ObjCMessageExpr * ME)79 AnyCall(const ObjCMessageExpr *ME) 80 : E(ME), D(ME->getMethodDecl()), K(ObjCMethod) {} 81 AnyCall(const CXXNewExpr * NE)82 AnyCall(const CXXNewExpr *NE) 83 : E(NE), D(NE->getOperatorNew()), K(Allocator) {} 84 AnyCall(const CXXDeleteExpr * NE)85 AnyCall(const CXXDeleteExpr *NE) 86 : E(NE), D(NE->getOperatorDelete()), K(Deallocator) {} 87 AnyCall(const CXXConstructExpr * NE)88 AnyCall(const CXXConstructExpr *NE) 89 : E(NE), D(NE->getConstructor()), K(Constructor) {} 90 AnyCall(const CXXInheritedCtorInitExpr * CIE)91 AnyCall(const CXXInheritedCtorInitExpr *CIE) 92 : E(CIE), D(CIE->getConstructor()), K(InheritedConstructor) {} 93 AnyCall(const CXXDestructorDecl * D)94 AnyCall(const CXXDestructorDecl *D) : E(nullptr), D(D), K(Destructor) {} 95 AnyCall(const CXXConstructorDecl * D)96 AnyCall(const CXXConstructorDecl *D) : E(nullptr), D(D), K(Constructor) {} 97 AnyCall(const ObjCMethodDecl * D)98 AnyCall(const ObjCMethodDecl *D) : E(nullptr), D(D), K(ObjCMethod) {} 99 AnyCall(const FunctionDecl * D)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. forExpr(const Expr * E)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. forDecl(const Decl * D)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) parameters()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; param_begin()160 param_const_iterator param_begin() const { return parameters().begin(); } param_end()161 param_const_iterator param_end() const { return parameters().end(); } param_size()162 size_t param_size() const { return parameters().size(); } param_empty()163 bool param_empty() const { return parameters().empty(); } 164 getReturnType(ASTContext & Ctx)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. getIdentifier()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 getDecl()197 const Decl *getDecl() const { 198 return D; 199 } 200 getExpr()201 const Expr *getExpr() const { 202 return E; 203 } 204 getKind()205 Kind getKind() const { 206 return K; 207 } 208 dump()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