Index: clang/include/clang/Analysis/AnyCall.h =================================================================== --- clang/include/clang/Analysis/AnyCall.h +++ clang/include/clang/Analysis/AnyCall.h @@ -19,7 +19,8 @@ namespace clang { -/// An instance of this class corresponds to a 'callable' call. +/// An instance of this class corresponds to a 'callable' call, such as a +/// function, Objective-C method, block, etc. class AnyCall { public: enum Kind { @@ -48,7 +49,11 @@ }; private: - /// Call expression, remains null iff the call is an implicit destructor call. + /// 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, @@ -56,8 +61,6 @@ 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(); @@ -80,6 +83,14 @@ AnyCall(const CXXConstructExpr *NE) : E(NE), D(NE->getConstructor()), K(Constructor) {} + 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), K(Function) {} + /// 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) { @@ -98,8 +109,20 @@ } } - static AnyCall forDestructorCall(const CXXDestructorDecl *D) { - return AnyCall(/*E=*/nullptr, D, Destructor); + /// If {@code D} is a callable (Objective-C method or a function), return + /// a constructed {@code AnyCall} object. Return None otherwise. + // FIXME: block support. + static Optional forDecl(const Decl *D) { + if (const auto *CD = dyn_cast(D)) { + return AnyCall(CD); + } else if (const auto *DD = dyn_cast(D)) { + return AnyCall(DD); + } else if (const auto *FD = dyn_cast(D)) { + return AnyCall(FD); + } else if (const auto *MD = dyn_cast(D)) { + return AnyCall(MD); + } + return None; } /// \returns formal parameters for direct calls (including virtual calls) @@ -111,8 +134,6 @@ 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 { @@ -129,10 +150,17 @@ QualType getReturnType(ASTContext &Ctx) const { switch (K) { case Function: + if (E) + return cast(E)->getCallReturnType(Ctx); + return cast(D)->getReturnType(); + case ObjCMethod: + if (E) + return cast(E)->getCallReturnType(Ctx); + return cast(D)->getReturnType(); case Block: + // FIXME: BlockDecl does not know it's return type, + // hence the assymetry here. return cast(E)->getCallReturnType(Ctx); - case ObjCMethod: - return cast(E)->getCallReturnType(Ctx); case Destructor: case Constructor: case Allocator: