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