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