123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //=== AnyCall.h - Abstraction over different callables --------*- C++ -*--//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // A utility class for performing generic operations over different callables.
- //
- //===----------------------------------------------------------------------===//
- //
- #ifndef LLVM_CLANG_ANALYSIS_ANYCALL_H
- #define LLVM_CLANG_ANALYSIS_ANYCALL_H
- #include "clang/AST/Decl.h"
- #include "clang/AST/ExprCXX.h"
- #include "clang/AST/ExprObjC.h"
- #include <optional>
- namespace clang {
- /// An instance of this class corresponds to a call.
- /// It might be a syntactically-concrete call, done as a part of evaluating an
- /// expression, or it may be an abstract callee with no associated expression.
- class AnyCall {
- public:
- enum Kind {
- /// A function, function pointer, or a C++ method call
- Function,
- /// A call to an Objective-C method
- ObjCMethod,
- /// A call to an Objective-C block
- Block,
- /// An implicit C++ destructor call (called implicitly
- /// or by operator 'delete')
- Destructor,
- /// An implicit or explicit C++ constructor call
- Constructor,
- /// A C++ inherited constructor produced by a "using T::T" directive
- InheritedConstructor,
- /// A C++ allocation function call (operator `new`), via C++ new-expression
- Allocator,
- /// A C++ deallocation function call (operator `delete`), via C++
- /// delete-expression
- Deallocator
- };
- private:
- /// Either expression or declaration (but not both at the same time)
- /// can be null.
- /// Call expression, is null when is not known (then declaration is non-null),
- /// or for implicit destructor calls (when no expression exists.)
- const Expr *E = nullptr;
- /// Corresponds to a statically known declaration of the called function,
- /// or null if it is not known (e.g. for a function pointer).
- const Decl *D = nullptr;
- Kind K;
- public:
- AnyCall(const CallExpr *CE) : E(CE) {
- D = CE->getCalleeDecl();
- K = (CE->getCallee()->getType()->getAs<BlockPointerType>()) ? Block
- : Function;
- if (D && ((K == Function && !isa<FunctionDecl>(D)) ||
- (K == Block && !isa<BlockDecl>(D))))
- D = nullptr;
- }
- AnyCall(const ObjCMessageExpr *ME)
- : E(ME), D(ME->getMethodDecl()), K(ObjCMethod) {}
- AnyCall(const CXXNewExpr *NE)
- : E(NE), D(NE->getOperatorNew()), K(Allocator) {}
- AnyCall(const CXXDeleteExpr *NE)
- : E(NE), D(NE->getOperatorDelete()), K(Deallocator) {}
- AnyCall(const CXXConstructExpr *NE)
- : E(NE), D(NE->getConstructor()), K(Constructor) {}
- AnyCall(const CXXInheritedCtorInitExpr *CIE)
- : E(CIE), D(CIE->getConstructor()), K(InheritedConstructor) {}
- AnyCall(const CXXDestructorDecl *D) : E(nullptr), D(D), K(Destructor) {}
- AnyCall(const CXXConstructorDecl *D) : E(nullptr), D(D), K(Constructor) {}
- AnyCall(const ObjCMethodDecl *D) : E(nullptr), D(D), K(ObjCMethod) {}
- AnyCall(const FunctionDecl *D) : E(nullptr), D(D) {
- if (isa<CXXConstructorDecl>(D)) {
- K = Constructor;
- } else if (isa <CXXDestructorDecl>(D)) {
- K = Destructor;
- } else {
- K = Function;
- }
- }
- /// If @c E is a generic call (to ObjC method /function/block/etc),
- /// return a constructed @c AnyCall object. Return std::nullopt otherwise.
- static std::optional<AnyCall> forExpr(const Expr *E) {
- if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) {
- return AnyCall(ME);
- } else if (const auto *CE = dyn_cast<CallExpr>(E)) {
- return AnyCall(CE);
- } else if (const auto *CXNE = dyn_cast<CXXNewExpr>(E)) {
- return AnyCall(CXNE);
- } else if (const auto *CXDE = dyn_cast<CXXDeleteExpr>(E)) {
- return AnyCall(CXDE);
- } else if (const auto *CXCE = dyn_cast<CXXConstructExpr>(E)) {
- return AnyCall(CXCE);
- } else if (const auto *CXCIE = dyn_cast<CXXInheritedCtorInitExpr>(E)) {
- return AnyCall(CXCIE);
- } else {
- return std::nullopt;
- }
- }
- /// If @c D is a callable (Objective-C method or a function), return
- /// a constructed @c AnyCall object. Return std::nullopt otherwise.
- // FIXME: block support.
- static std::optional<AnyCall> forDecl(const Decl *D) {
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- return AnyCall(FD);
- } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
- return AnyCall(MD);
- }
- return std::nullopt;
- }
- /// \returns formal parameters for direct calls (including virtual calls)
- ArrayRef<ParmVarDecl *> parameters() const {
- if (!D)
- return std::nullopt;
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- return FD->parameters();
- } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
- return MD->parameters();
- } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
- return BD->parameters();
- } else {
- return std::nullopt;
- }
- }
- using param_const_iterator = ArrayRef<ParmVarDecl *>::const_iterator;
- param_const_iterator param_begin() const { return parameters().begin(); }
- param_const_iterator param_end() const { return parameters().end(); }
- size_t param_size() const { return parameters().size(); }
- bool param_empty() const { return parameters().empty(); }
- QualType getReturnType(ASTContext &Ctx) const {
- switch (K) {
- case Function:
- if (E)
- return cast<CallExpr>(E)->getCallReturnType(Ctx);
- return cast<FunctionDecl>(D)->getReturnType();
- case ObjCMethod:
- if (E)
- return cast<ObjCMessageExpr>(E)->getCallReturnType(Ctx);
- return cast<ObjCMethodDecl>(D)->getReturnType();
- case Block:
- // FIXME: BlockDecl does not know its return type,
- // hence the asymmetry with the function and method cases above.
- return cast<CallExpr>(E)->getCallReturnType(Ctx);
- case Destructor:
- case Constructor:
- case InheritedConstructor:
- case Allocator:
- case Deallocator:
- return cast<FunctionDecl>(D)->getReturnType();
- }
- llvm_unreachable("Unknown AnyCall::Kind");
- }
- /// \returns Function identifier if it is a named declaration,
- /// @c nullptr otherwise.
- const IdentifierInfo *getIdentifier() const {
- if (const auto *ND = dyn_cast_or_null<NamedDecl>(D))
- return ND->getIdentifier();
- return nullptr;
- }
- const Decl *getDecl() const {
- return D;
- }
- const Expr *getExpr() const {
- return E;
- }
- Kind getKind() const {
- return K;
- }
- void dump() const {
- if (E)
- E->dump();
- if (D)
- D->dump();
- }
- };
- }
- #endif // LLVM_CLANG_ANALYSIS_ANYCALL_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|