Index: clang/include/clang/Analysis/GenericCall.h =================================================================== --- /dev/null +++ clang/include/clang/Analysis/GenericCall.h @@ -0,0 +1,139 @@ +//=== GenericCall.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_GENERIC_CALL_H +#define LLVM_CLANG_ANALYSIS_GENERIC_CALL_H + +#include "clang/AST/Decl.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" + +namespace clang { + +class GenericCall { +public: + enum CallKind { + Function, + ObjCMethod, + Block, + Destructor, + Constructor, + Allocator, + Deallocator + }; + +private: + const Expr *E = nullptr; + const Decl *D = nullptr; + CallKind K; + +public: + + /// Construct a generic call. + /// \param E Call expression, if exists (e.g. does not exist for destructors) + /// \param InputDecl Declaration of the called function: can be left empty + /// iff {@code E} is not empty. + GenericCall(const Expr *E, + const Decl *InputDecl = nullptr) : E(E) { + if (!E) { + assert(InputDecl); + D = InputDecl; + K = Destructor; + } else if (const auto *ME = dyn_cast(E)) { + D = ME->getMethodDecl(); + K = ObjCMethod; + } else if (const auto *CE = dyn_cast(E)) { + const Decl *CD = CE->getCalleeDecl(); + if (CD && isa(CD)) { + D = CD; + K = Function; + } else if (CD && isa(CD)) { + D = CD; + K = Block; + } else { + D = nullptr; + K = Function; + } + } else if (const auto *CXNE = dyn_cast(E)) { + D = CXNE->getOperatorNew(); + K = Allocator; + } else if (const auto *CXDE = dyn_cast(E)) { + D = CXDE->getOperatorDelete(); + K = Deallocator; + } else if (const auto *CXCE = dyn_cast(E)) { + D = CXCE->getConstructor(); + K = Constructor; + } else { + llvm_unreachable("Unexpected type"); + } + } + + 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() const { + return E->getType(); + } + + const IdentifierInfo *getIdentifier() const { + if (const auto *FD = dyn_cast(D)) { + return FD->getIdentifier(); + } else if (const auto *MD = dyn_cast(D)) { + return MD->getIdentifier(); + } else { + return nullptr; + } + } + + const Decl *getDecl() const { + return D; + } + + const Expr *getExpr() const { + return E; + } + + CallKind getKind() const { + return K; + } + + void dump() const { + if (E) + E->dump(); + if (D) + D->dump(); + } +}; + +} + +#endif // LLVM_CLANG_ANALYSIS_GENERIC_CALL_H