Index: clang/include/clang/Analysis/AnyCall.h =================================================================== --- /dev/null +++ clang/include/clang/Analysis/AnyCall.h @@ -0,0 +1,174 @@ +//=== 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_ANY_CALL_H +#define LLVM_CLANG_ANALYSIS_ANY_CALL_H + +#include "clang/AST/Decl.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" + +namespace clang { + +/// An instance of this class corresponds to a 'callable' call. +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++ allocation function call (operator `new`), via C++ new-expression + Allocator, + + /// A C++ deallocation function call (operator `delete`), via C++ + /// delete-expression + Deallocator + }; + +private: + /// Call expression, remains null iff the call is an implicit destructor call. + 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; + + AnyCall(const Expr *E, const Decl *D, Kind K) : E(E), D(D), K(K) {} + +public: + AnyCall(const CallExpr *CE) : E(CE) { + D = CE->getCalleeDecl(); + K = (CE->getCallee()->getType()->getAs()) ? Block + : Function; + if (D && ((K == Function && !isa(D)) + || (K == Block && !isa(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) {} + + /// If {@code E} is a generic call (to ObjC method /function/block/etc), + /// return a constructed {@code AnyCall} object. Return None otherwise. + static Optional forExpr(const Expr *E) { + if (const auto *ME = dyn_cast(E)) { + return AnyCall(ME); + } else if (const auto *CE = dyn_cast(E)) { + return AnyCall(CE); + } else if (const auto *CXNE = dyn_cast(E)) { + return AnyCall(CXNE); + } else if (const auto *CXDE = dyn_cast(E)) { + return AnyCall(CXDE); + } else if (const auto *CXCE = dyn_cast(E)) { + return AnyCall(CXCE); + } else { + return None; + } + } + + static AnyCall forDestructorCall(const CXXDestructorDecl *D) { + return AnyCall(/*E=*/nullptr, D, Destructor); + } + + /// \returns formal parameters for direct calls (including virtual calls) + ArrayRef parameters() const { + if (!D) + return None; + + if (const auto *FD = dyn_cast(D)) { + return FD->parameters(); + } else if (const auto *MD = dyn_cast(D)) { + return MD->parameters(); + } else if (const auto *CD = dyn_cast(D)) { + return CD->parameters(); + } else if (const auto *BD = dyn_cast(D)) { + return BD->parameters(); + } else { + return None; + } + } + + using param_const_iterator = ArrayRef::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: + case Block: + return cast(E)->getCallReturnType(Ctx); + case ObjCMethod: + return cast(E)->getCallReturnType(Ctx); + case Destructor: + case Constructor: + case Allocator: + case Deallocator: + return cast(D)->getReturnType(); + } + } + + /// \returns Function identifier if it is a named declaration, + /// {@code nullptr} otherwise. + const IdentifierInfo *getIdentifier() const { + if (const auto *ND = dyn_cast_or_null(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_ANY_CALL_H