NoQ created this revision. NoQ added reviewers: vsavchenko, george.karpenkov, rjmccall. Herald added a subscriber: martong. NoQ requested review of this revision.
AnyCall is an interface provided by libAnalysis to polymorphically handle various call-like entities (function calls, Obj-C message expressions, block calls, constructor/destructor invocations, new/delete invocations, etc.) which aren't necessarily related in the AST class hierarchy. This patch updates it to allow obtaining arguments of any call-like expression. It also adds a couple of accessor functions in the AST in order to make this possible. The `CXXDeleteExpr`'s `getArgumentAddress()` looks a bit weird out of context but we do seem to have a precedent (`VarDecl::getInitAddress()`). Repository: rC Clang https://reviews.llvm.org/D101788 Files: clang/include/clang/AST/ExprCXX.h clang/include/clang/Analysis/AnyCall.h Index: clang/include/clang/Analysis/AnyCall.h =================================================================== --- clang/include/clang/Analysis/AnyCall.h +++ clang/include/clang/Analysis/AnyCall.h @@ -109,7 +109,7 @@ /// If @c E is a generic call (to ObjC method /function/block/etc), /// return a constructed @c AnyCall object. Return None otherwise. - static Optional<AnyCall> forExpr(const Expr *E) { + static Optional<AnyCall> forExpr(const Stmt *E) { if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) { return AnyCall(ME); } else if (const auto *CE = dyn_cast<CallExpr>(E)) { @@ -161,6 +161,35 @@ size_t param_size() const { return parameters().size(); } bool param_empty() const { return parameters().empty(); } + ArrayRef<const Expr *> arguments() const { + if (!E) + return None; + + if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) { + return {ME->getArgs(), ME->getNumArgs()}; + } else if (const auto *CE = dyn_cast<CallExpr>(E)) { + return {CE->getArgs(), CE->getNumArgs()}; + } else if (const auto *CXNE = dyn_cast<CXXNewExpr>(E)) { + return {CXNE->getPlacementArgs(), CXNE->getNumPlacementArgs()}; + } else if (const auto *CXDE = dyn_cast<CXXDeleteExpr>(E)) { + // The only argument is the object being deleted. + return {reinterpret_cast<Expr *const *>(CXDE->getArgumentAddress()), 1U}; + } else if (const auto *CXCE = dyn_cast<CXXConstructExpr>(E)) { + return {CXCE->getArgs(), CXCE->getNumArgs()}; + } else if (const auto *CXCIE = dyn_cast<CXXInheritedCtorInitExpr>(E)) { + // No argument expressions are synthesized in this case. + return None; + } else { + return None; + } + } + + using arg_const_iterator = ArrayRef<const Expr *>::const_iterator; + arg_const_iterator arg_begin() const { return arguments().begin(); } + arg_const_iterator arg_end() const { return arguments().end(); } + size_t arg_size() const { return arguments().size(); } + bool arg_empty() const { return arguments().empty(); } + QualType getReturnType(ASTContext &Ctx) const { switch (K) { case Function: Index: clang/include/clang/AST/ExprCXX.h =================================================================== --- clang/include/clang/AST/ExprCXX.h +++ clang/include/clang/AST/ExprCXX.h @@ -2281,6 +2281,11 @@ placementNewArgsOffset()); } + Expr *const *getPlacementArgs() const { + return reinterpret_cast<Expr *const *>(getTrailingObjects<Stmt *>() + + placementNewArgsOffset()); + } + Expr *getPlacementArg(unsigned I) { assert((I < getNumPlacementArgs()) && "Index out of range!"); return getPlacementArgs()[I]; @@ -2439,6 +2444,9 @@ Expr *getArgument() { return cast<Expr>(Argument); } const Expr *getArgument() const { return cast<Expr>(Argument); } + /// Retrieve the address of the argument expression. + Stmt *const *getArgumentAddress() const { return &Argument; } + /// Retrieve the type being destroyed. /// /// If the type being destroyed is a dependent type which may or may not
Index: clang/include/clang/Analysis/AnyCall.h =================================================================== --- clang/include/clang/Analysis/AnyCall.h +++ clang/include/clang/Analysis/AnyCall.h @@ -109,7 +109,7 @@ /// If @c E is a generic call (to ObjC method /function/block/etc), /// return a constructed @c AnyCall object. Return None otherwise. - static Optional<AnyCall> forExpr(const Expr *E) { + static Optional<AnyCall> forExpr(const Stmt *E) { if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) { return AnyCall(ME); } else if (const auto *CE = dyn_cast<CallExpr>(E)) { @@ -161,6 +161,35 @@ size_t param_size() const { return parameters().size(); } bool param_empty() const { return parameters().empty(); } + ArrayRef<const Expr *> arguments() const { + if (!E) + return None; + + if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) { + return {ME->getArgs(), ME->getNumArgs()}; + } else if (const auto *CE = dyn_cast<CallExpr>(E)) { + return {CE->getArgs(), CE->getNumArgs()}; + } else if (const auto *CXNE = dyn_cast<CXXNewExpr>(E)) { + return {CXNE->getPlacementArgs(), CXNE->getNumPlacementArgs()}; + } else if (const auto *CXDE = dyn_cast<CXXDeleteExpr>(E)) { + // The only argument is the object being deleted. + return {reinterpret_cast<Expr *const *>(CXDE->getArgumentAddress()), 1U}; + } else if (const auto *CXCE = dyn_cast<CXXConstructExpr>(E)) { + return {CXCE->getArgs(), CXCE->getNumArgs()}; + } else if (const auto *CXCIE = dyn_cast<CXXInheritedCtorInitExpr>(E)) { + // No argument expressions are synthesized in this case. + return None; + } else { + return None; + } + } + + using arg_const_iterator = ArrayRef<const Expr *>::const_iterator; + arg_const_iterator arg_begin() const { return arguments().begin(); } + arg_const_iterator arg_end() const { return arguments().end(); } + size_t arg_size() const { return arguments().size(); } + bool arg_empty() const { return arguments().empty(); } + QualType getReturnType(ASTContext &Ctx) const { switch (K) { case Function: Index: clang/include/clang/AST/ExprCXX.h =================================================================== --- clang/include/clang/AST/ExprCXX.h +++ clang/include/clang/AST/ExprCXX.h @@ -2281,6 +2281,11 @@ placementNewArgsOffset()); } + Expr *const *getPlacementArgs() const { + return reinterpret_cast<Expr *const *>(getTrailingObjects<Stmt *>() + + placementNewArgsOffset()); + } + Expr *getPlacementArg(unsigned I) { assert((I < getNumPlacementArgs()) && "Index out of range!"); return getPlacementArgs()[I]; @@ -2439,6 +2444,9 @@ Expr *getArgument() { return cast<Expr>(Argument); } const Expr *getArgument() const { return cast<Expr>(Argument); } + /// Retrieve the address of the argument expression. + Stmt *const *getArgumentAddress() const { return &Argument; } + /// Retrieve the type being destroyed. /// /// If the type being destroyed is a dependent type which may or may not
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits