10b57cec5SDimitry Andric //=== AnyCall.h - Abstraction over different callables --------*- C++ -*--// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // A utility class for performing generic operations over different callables. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric // 1304eeddc0SDimitry Andric #ifndef LLVM_CLANG_ANALYSIS_ANYCALL_H 1404eeddc0SDimitry Andric #define LLVM_CLANG_ANALYSIS_ANYCALL_H 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #include "clang/AST/Decl.h" 170b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h" 180b57cec5SDimitry Andric #include "clang/AST/ExprObjC.h" 19bdd1243dSDimitry Andric #include <optional> 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric namespace clang { 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric /// An instance of this class corresponds to a call. 240b57cec5SDimitry Andric /// It might be a syntactically-concrete call, done as a part of evaluating an 250b57cec5SDimitry Andric /// expression, or it may be an abstract callee with no associated expression. 260b57cec5SDimitry Andric class AnyCall { 270b57cec5SDimitry Andric public: 280b57cec5SDimitry Andric enum Kind { 290b57cec5SDimitry Andric /// A function, function pointer, or a C++ method call 300b57cec5SDimitry Andric Function, 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric /// A call to an Objective-C method 330b57cec5SDimitry Andric ObjCMethod, 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric /// A call to an Objective-C block 360b57cec5SDimitry Andric Block, 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric /// An implicit C++ destructor call (called implicitly 390b57cec5SDimitry Andric /// or by operator 'delete') 400b57cec5SDimitry Andric Destructor, 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric /// An implicit or explicit C++ constructor call 430b57cec5SDimitry Andric Constructor, 440b57cec5SDimitry Andric 455ffd83dbSDimitry Andric /// A C++ inherited constructor produced by a "using T::T" directive 465ffd83dbSDimitry Andric InheritedConstructor, 475ffd83dbSDimitry Andric 480b57cec5SDimitry Andric /// A C++ allocation function call (operator `new`), via C++ new-expression 490b57cec5SDimitry Andric Allocator, 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric /// A C++ deallocation function call (operator `delete`), via C++ 520b57cec5SDimitry Andric /// delete-expression 530b57cec5SDimitry Andric Deallocator 540b57cec5SDimitry Andric }; 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric private: 570b57cec5SDimitry Andric /// Either expression or declaration (but not both at the same time) 580b57cec5SDimitry Andric /// can be null. 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric /// Call expression, is null when is not known (then declaration is non-null), 610b57cec5SDimitry Andric /// or for implicit destructor calls (when no expression exists.) 620b57cec5SDimitry Andric const Expr *E = nullptr; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric /// Corresponds to a statically known declaration of the called function, 650b57cec5SDimitry Andric /// or null if it is not known (e.g. for a function pointer). 660b57cec5SDimitry Andric const Decl *D = nullptr; 670b57cec5SDimitry Andric Kind K; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric public: AnyCall(const CallExpr * CE)700b57cec5SDimitry Andric AnyCall(const CallExpr *CE) : E(CE) { 710b57cec5SDimitry Andric D = CE->getCalleeDecl(); 720b57cec5SDimitry Andric K = (CE->getCallee()->getType()->getAs<BlockPointerType>()) ? Block 730b57cec5SDimitry Andric : Function; 740b57cec5SDimitry Andric if (D && ((K == Function && !isa<FunctionDecl>(D)) || 750b57cec5SDimitry Andric (K == Block && !isa<BlockDecl>(D)))) 760b57cec5SDimitry Andric D = nullptr; 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric AnyCall(const ObjCMessageExpr * ME)790b57cec5SDimitry Andric AnyCall(const ObjCMessageExpr *ME) 800b57cec5SDimitry Andric : E(ME), D(ME->getMethodDecl()), K(ObjCMethod) {} 810b57cec5SDimitry Andric AnyCall(const CXXNewExpr * NE)820b57cec5SDimitry Andric AnyCall(const CXXNewExpr *NE) 830b57cec5SDimitry Andric : E(NE), D(NE->getOperatorNew()), K(Allocator) {} 840b57cec5SDimitry Andric AnyCall(const CXXDeleteExpr * NE)850b57cec5SDimitry Andric AnyCall(const CXXDeleteExpr *NE) 860b57cec5SDimitry Andric : E(NE), D(NE->getOperatorDelete()), K(Deallocator) {} 870b57cec5SDimitry Andric AnyCall(const CXXConstructExpr * NE)880b57cec5SDimitry Andric AnyCall(const CXXConstructExpr *NE) 890b57cec5SDimitry Andric : E(NE), D(NE->getConstructor()), K(Constructor) {} 900b57cec5SDimitry Andric AnyCall(const CXXInheritedCtorInitExpr * CIE)915ffd83dbSDimitry Andric AnyCall(const CXXInheritedCtorInitExpr *CIE) 925ffd83dbSDimitry Andric : E(CIE), D(CIE->getConstructor()), K(InheritedConstructor) {} 935ffd83dbSDimitry Andric AnyCall(const CXXDestructorDecl * D)940b57cec5SDimitry Andric AnyCall(const CXXDestructorDecl *D) : E(nullptr), D(D), K(Destructor) {} 950b57cec5SDimitry Andric AnyCall(const CXXConstructorDecl * D)960b57cec5SDimitry Andric AnyCall(const CXXConstructorDecl *D) : E(nullptr), D(D), K(Constructor) {} 970b57cec5SDimitry Andric AnyCall(const ObjCMethodDecl * D)980b57cec5SDimitry Andric AnyCall(const ObjCMethodDecl *D) : E(nullptr), D(D), K(ObjCMethod) {} 990b57cec5SDimitry Andric AnyCall(const FunctionDecl * D)1000b57cec5SDimitry Andric AnyCall(const FunctionDecl *D) : E(nullptr), D(D) { 1010b57cec5SDimitry Andric if (isa<CXXConstructorDecl>(D)) { 1020b57cec5SDimitry Andric K = Constructor; 1030b57cec5SDimitry Andric } else if (isa <CXXDestructorDecl>(D)) { 1040b57cec5SDimitry Andric K = Destructor; 1050b57cec5SDimitry Andric } else { 1060b57cec5SDimitry Andric K = Function; 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric 111fe6060f1SDimitry Andric /// If @c E is a generic call (to ObjC method /function/block/etc), 112bdd1243dSDimitry Andric /// return a constructed @c AnyCall object. Return std::nullopt otherwise. forExpr(const Expr * E)113bdd1243dSDimitry Andric static std::optional<AnyCall> forExpr(const Expr *E) { 1140b57cec5SDimitry Andric if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) { 1150b57cec5SDimitry Andric return AnyCall(ME); 1160b57cec5SDimitry Andric } else if (const auto *CE = dyn_cast<CallExpr>(E)) { 1170b57cec5SDimitry Andric return AnyCall(CE); 1180b57cec5SDimitry Andric } else if (const auto *CXNE = dyn_cast<CXXNewExpr>(E)) { 1190b57cec5SDimitry Andric return AnyCall(CXNE); 1200b57cec5SDimitry Andric } else if (const auto *CXDE = dyn_cast<CXXDeleteExpr>(E)) { 1210b57cec5SDimitry Andric return AnyCall(CXDE); 1220b57cec5SDimitry Andric } else if (const auto *CXCE = dyn_cast<CXXConstructExpr>(E)) { 1230b57cec5SDimitry Andric return AnyCall(CXCE); 1245ffd83dbSDimitry Andric } else if (const auto *CXCIE = dyn_cast<CXXInheritedCtorInitExpr>(E)) { 1255ffd83dbSDimitry Andric return AnyCall(CXCIE); 1260b57cec5SDimitry Andric } else { 127bdd1243dSDimitry Andric return std::nullopt; 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 131fe6060f1SDimitry Andric /// If @c D is a callable (Objective-C method or a function), return 132bdd1243dSDimitry Andric /// a constructed @c AnyCall object. Return std::nullopt otherwise. 1330b57cec5SDimitry Andric // FIXME: block support. forDecl(const Decl * D)134bdd1243dSDimitry Andric static std::optional<AnyCall> forDecl(const Decl *D) { 1350b57cec5SDimitry Andric if (const auto *FD = dyn_cast<FunctionDecl>(D)) { 1360b57cec5SDimitry Andric return AnyCall(FD); 1370b57cec5SDimitry Andric } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { 1380b57cec5SDimitry Andric return AnyCall(MD); 1390b57cec5SDimitry Andric } 140bdd1243dSDimitry Andric return std::nullopt; 1410b57cec5SDimitry Andric } 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric /// \returns formal parameters for direct calls (including virtual calls) parameters()1440b57cec5SDimitry Andric ArrayRef<ParmVarDecl *> parameters() const { 1450b57cec5SDimitry Andric if (!D) 146bdd1243dSDimitry Andric return std::nullopt; 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric if (const auto *FD = dyn_cast<FunctionDecl>(D)) { 1490b57cec5SDimitry Andric return FD->parameters(); 1500b57cec5SDimitry Andric } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { 1510b57cec5SDimitry Andric return MD->parameters(); 1520b57cec5SDimitry Andric } else if (const auto *BD = dyn_cast<BlockDecl>(D)) { 1530b57cec5SDimitry Andric return BD->parameters(); 1540b57cec5SDimitry Andric } else { 155bdd1243dSDimitry Andric return std::nullopt; 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric using param_const_iterator = ArrayRef<ParmVarDecl *>::const_iterator; param_begin()1600b57cec5SDimitry Andric param_const_iterator param_begin() const { return parameters().begin(); } param_end()1610b57cec5SDimitry Andric param_const_iterator param_end() const { return parameters().end(); } param_size()1620b57cec5SDimitry Andric size_t param_size() const { return parameters().size(); } param_empty()1630b57cec5SDimitry Andric bool param_empty() const { return parameters().empty(); } 1640b57cec5SDimitry Andric getReturnType(ASTContext & Ctx)1650b57cec5SDimitry Andric QualType getReturnType(ASTContext &Ctx) const { 1660b57cec5SDimitry Andric switch (K) { 1670b57cec5SDimitry Andric case Function: 1680b57cec5SDimitry Andric if (E) 1690b57cec5SDimitry Andric return cast<CallExpr>(E)->getCallReturnType(Ctx); 1700b57cec5SDimitry Andric return cast<FunctionDecl>(D)->getReturnType(); 1710b57cec5SDimitry Andric case ObjCMethod: 1720b57cec5SDimitry Andric if (E) 1730b57cec5SDimitry Andric return cast<ObjCMessageExpr>(E)->getCallReturnType(Ctx); 1740b57cec5SDimitry Andric return cast<ObjCMethodDecl>(D)->getReturnType(); 1750b57cec5SDimitry Andric case Block: 1760b57cec5SDimitry Andric // FIXME: BlockDecl does not know its return type, 1770b57cec5SDimitry Andric // hence the asymmetry with the function and method cases above. 1780b57cec5SDimitry Andric return cast<CallExpr>(E)->getCallReturnType(Ctx); 1790b57cec5SDimitry Andric case Destructor: 1800b57cec5SDimitry Andric case Constructor: 1815ffd83dbSDimitry Andric case InheritedConstructor: 1820b57cec5SDimitry Andric case Allocator: 1830b57cec5SDimitry Andric case Deallocator: 1840b57cec5SDimitry Andric return cast<FunctionDecl>(D)->getReturnType(); 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric llvm_unreachable("Unknown AnyCall::Kind"); 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric /// \returns Function identifier if it is a named declaration, 190fe6060f1SDimitry Andric /// @c nullptr otherwise. getIdentifier()1910b57cec5SDimitry Andric const IdentifierInfo *getIdentifier() const { 1920b57cec5SDimitry Andric if (const auto *ND = dyn_cast_or_null<NamedDecl>(D)) 1930b57cec5SDimitry Andric return ND->getIdentifier(); 1940b57cec5SDimitry Andric return nullptr; 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric getDecl()1970b57cec5SDimitry Andric const Decl *getDecl() const { 1980b57cec5SDimitry Andric return D; 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric getExpr()2010b57cec5SDimitry Andric const Expr *getExpr() const { 2020b57cec5SDimitry Andric return E; 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric getKind()2050b57cec5SDimitry Andric Kind getKind() const { 2060b57cec5SDimitry Andric return K; 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric dump()2090b57cec5SDimitry Andric void dump() const { 2100b57cec5SDimitry Andric if (E) 2110b57cec5SDimitry Andric E->dump(); 2120b57cec5SDimitry Andric if (D) 2130b57cec5SDimitry Andric D->dump(); 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric }; 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric 21904eeddc0SDimitry Andric #endif // LLVM_CLANG_ANALYSIS_ANYCALL_H 220