Viewing file: AnyCall.h (6.65 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
//=== 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
|