]> granicus.if.org Git - clang/commitdiff
Extend AnyCall to handle callable declarations without the call expressions
authorGeorge Karpenkov <ekarpenkov@apple.com>
Tue, 29 Jan 2019 19:29:19 +0000 (19:29 +0000)
committerGeorge Karpenkov <ekarpenkov@apple.com>
Tue, 29 Jan 2019 19:29:19 +0000 (19:29 +0000)
That weakens inner invariants, but allows the class to be more generic,
allowing usage in situations where the call expression is not known (or
should not matter).

Differential Revision: https://reviews.llvm.org/D57344

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@352531 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/AnyCall.h
lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp

index f3442df6a25f32bf76690d780a68c99093178169..a9098adcbfa22da5faaf77a42f1a910845139631 100644 (file)
@@ -19,7 +19,9 @@
 
 namespace clang {
 
-/// An instance of this class corresponds to a 'callable' call.
+/// 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 {
@@ -48,7 +50,11 @@ public:
   };
 
 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 +62,6 @@ private:
   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 +84,23 @@ public:
   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) {
+    if (isa<CXXConstructorDecl>(D)) {
+      K = Constructor;
+    } else if (isa <CXXDestructorDecl>(D)) {
+      K = Destructor;
+    } else {
+      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<AnyCall> forExpr(const Expr *E) {
@@ -98,8 +119,16 @@ public:
     }
   }
 
-  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<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 None;
   }
 
   /// \returns formal parameters for direct calls (including virtual calls)
@@ -111,8 +140,6 @@ public:
       return FD->parameters();
     } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
       return MD->parameters();
-    } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
-      return CD->parameters();
     } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
       return BD->parameters();
     } else {
@@ -129,10 +156,17 @@ public:
   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 ObjCMethod:
-      return cast<ObjCMessageExpr>(E)->getCallReturnType(Ctx);
     case Destructor:
     case Constructor:
     case Allocator:
index c3d191429e4a259ac4987cdea3efdf43e6617d96..1ab4106b857a6291b9c3ea0ff908e1b1cc7e4527 100644 (file)
@@ -347,7 +347,7 @@ const static RetainSummary *getSummary(RetainSummaryManager &Summaries,
   const Expr *CE = Call.getOriginExpr();
   AnyCall C =
       CE ? *AnyCall::forExpr(CE)
-         : AnyCall::forDestructorCall(cast<CXXDestructorDecl>(Call.getDecl()));
+         : AnyCall(cast<CXXDestructorDecl>(Call.getDecl()));
   return Summaries.getSummary(C, Call.hasNonZeroCallbackArg(),
                               isReceiverUnconsumedSelf(Call), ReceiverType);
 }