Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:25

0001 //=== AnyCall.h - Abstraction over different callables --------*- C++ -*--//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // A utility class for performing generic operations over different callables.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 //
0013 #ifndef LLVM_CLANG_ANALYSIS_ANYCALL_H
0014 #define LLVM_CLANG_ANALYSIS_ANYCALL_H
0015 
0016 #include "clang/AST/Decl.h"
0017 #include "clang/AST/ExprCXX.h"
0018 #include "clang/AST/ExprObjC.h"
0019 #include <optional>
0020 
0021 namespace clang {
0022 
0023 /// An instance of this class corresponds to a call.
0024 /// It might be a syntactically-concrete call, done as a part of evaluating an
0025 /// expression, or it may be an abstract callee with no associated expression.
0026 class AnyCall {
0027 public:
0028   enum Kind {
0029     /// A function, function pointer, or a C++ method call
0030     Function,
0031 
0032     /// A call to an Objective-C method
0033     ObjCMethod,
0034 
0035     /// A call to an Objective-C block
0036     Block,
0037 
0038     /// An implicit C++ destructor call (called implicitly
0039     /// or by operator 'delete')
0040     Destructor,
0041 
0042     /// An implicit or explicit C++ constructor call
0043     Constructor,
0044 
0045     /// A C++ inherited constructor produced by a "using T::T" directive
0046     InheritedConstructor,
0047 
0048     /// A C++ allocation function call (operator `new`), via C++ new-expression
0049     Allocator,
0050 
0051     /// A C++ deallocation function call (operator `delete`), via C++
0052     /// delete-expression
0053     Deallocator
0054   };
0055 
0056 private:
0057   /// Either expression or declaration (but not both at the same time)
0058   /// can be null.
0059 
0060   /// Call expression, is null when is not known (then declaration is non-null),
0061   /// or for implicit destructor calls (when no expression exists.)
0062   const Expr *E = nullptr;
0063 
0064   /// Corresponds to a statically known declaration of the called function,
0065   /// or null if it is not known (e.g. for a function pointer).
0066   const Decl *D = nullptr;
0067   Kind K;
0068 
0069 public:
0070   AnyCall(const CallExpr *CE) : E(CE) {
0071     D = CE->getCalleeDecl();
0072     K = (CE->getCallee()->getType()->getAs<BlockPointerType>()) ? Block
0073                                                                 : Function;
0074     if (D && ((K == Function && !isa<FunctionDecl>(D)) ||
0075               (K == Block && !isa<BlockDecl>(D))))
0076       D = nullptr;
0077   }
0078 
0079   AnyCall(const ObjCMessageExpr *ME)
0080       : E(ME), D(ME->getMethodDecl()), K(ObjCMethod) {}
0081 
0082   AnyCall(const CXXNewExpr *NE)
0083       : E(NE), D(NE->getOperatorNew()), K(Allocator) {}
0084 
0085   AnyCall(const CXXDeleteExpr *NE)
0086       : E(NE), D(NE->getOperatorDelete()), K(Deallocator) {}
0087 
0088   AnyCall(const CXXConstructExpr *NE)
0089       : E(NE), D(NE->getConstructor()), K(Constructor) {}
0090 
0091   AnyCall(const CXXInheritedCtorInitExpr *CIE)
0092       : E(CIE), D(CIE->getConstructor()), K(InheritedConstructor) {}
0093 
0094   AnyCall(const CXXDestructorDecl *D) : E(nullptr), D(D), K(Destructor) {}
0095 
0096   AnyCall(const CXXConstructorDecl *D) : E(nullptr), D(D), K(Constructor) {}
0097 
0098   AnyCall(const ObjCMethodDecl *D) : E(nullptr), D(D), K(ObjCMethod) {}
0099 
0100   AnyCall(const FunctionDecl *D) : E(nullptr), D(D) {
0101     if (isa<CXXConstructorDecl>(D)) {
0102       K = Constructor;
0103     } else if (isa <CXXDestructorDecl>(D)) {
0104       K = Destructor;
0105     } else {
0106       K = Function;
0107     }
0108 
0109   }
0110 
0111   /// If @c E is a generic call (to ObjC method /function/block/etc),
0112   /// return a constructed @c AnyCall object. Return std::nullopt otherwise.
0113   static std::optional<AnyCall> forExpr(const Expr *E) {
0114     if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) {
0115       return AnyCall(ME);
0116     } else if (const auto *CE = dyn_cast<CallExpr>(E)) {
0117       return AnyCall(CE);
0118     } else if (const auto *CXNE = dyn_cast<CXXNewExpr>(E)) {
0119       return AnyCall(CXNE);
0120     } else if (const auto *CXDE = dyn_cast<CXXDeleteExpr>(E)) {
0121       return AnyCall(CXDE);
0122     } else if (const auto *CXCE = dyn_cast<CXXConstructExpr>(E)) {
0123       return AnyCall(CXCE);
0124     } else if (const auto *CXCIE = dyn_cast<CXXInheritedCtorInitExpr>(E)) {
0125       return AnyCall(CXCIE);
0126     } else {
0127       return std::nullopt;
0128     }
0129   }
0130 
0131   /// If @c D is a callable (Objective-C method or a function), return
0132   /// a constructed @c AnyCall object. Return std::nullopt otherwise.
0133   // FIXME: block support.
0134   static std::optional<AnyCall> forDecl(const Decl *D) {
0135     if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
0136       return AnyCall(FD);
0137     } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
0138       return AnyCall(MD);
0139     }
0140     return std::nullopt;
0141   }
0142 
0143   /// \returns formal parameters for direct calls (including virtual calls)
0144   ArrayRef<ParmVarDecl *> parameters() const {
0145     if (!D)
0146       return {};
0147 
0148     if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
0149       return FD->parameters();
0150     } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
0151       return MD->parameters();
0152     } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
0153       return BD->parameters();
0154     } else {
0155       return {};
0156     }
0157   }
0158 
0159   using param_const_iterator = ArrayRef<ParmVarDecl *>::const_iterator;
0160   param_const_iterator param_begin() const { return parameters().begin(); }
0161   param_const_iterator param_end() const { return parameters().end(); }
0162   size_t param_size() const { return parameters().size(); }
0163   bool param_empty() const { return parameters().empty(); }
0164 
0165   QualType getReturnType(ASTContext &Ctx) const {
0166     switch (K) {
0167     case Function:
0168       if (E)
0169         return cast<CallExpr>(E)->getCallReturnType(Ctx);
0170       return cast<FunctionDecl>(D)->getReturnType();
0171     case ObjCMethod:
0172       if (E)
0173         return cast<ObjCMessageExpr>(E)->getCallReturnType(Ctx);
0174       return cast<ObjCMethodDecl>(D)->getReturnType();
0175     case Block:
0176       // FIXME: BlockDecl does not know its return type,
0177       // hence the asymmetry with the function and method cases above.
0178       return cast<CallExpr>(E)->getCallReturnType(Ctx);
0179     case Destructor:
0180     case Constructor:
0181     case InheritedConstructor:
0182     case Allocator:
0183     case Deallocator:
0184       return cast<FunctionDecl>(D)->getReturnType();
0185     }
0186     llvm_unreachable("Unknown AnyCall::Kind");
0187   }
0188 
0189   /// \returns Function identifier if it is a named declaration,
0190   /// @c nullptr otherwise.
0191   const IdentifierInfo *getIdentifier() const {
0192     if (const auto *ND = dyn_cast_or_null<NamedDecl>(D))
0193       return ND->getIdentifier();
0194     return nullptr;
0195   }
0196 
0197   const Decl *getDecl() const {
0198     return D;
0199   }
0200 
0201   const Expr *getExpr() const {
0202     return E;
0203   }
0204 
0205   Kind getKind() const {
0206     return K;
0207   }
0208 
0209   void dump() const {
0210     if (E)
0211       E->dump();
0212     if (D)
0213       D->dump();
0214   }
0215 };
0216 
0217 }
0218 
0219 #endif // LLVM_CLANG_ANALYSIS_ANYCALL_H