[llvm-branch-commits] [cfe-tag] r259905 - [analyzer] checker-277: Pull in nullability fixes and dealloc checker.

Devin Coughlin via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Feb 5 11:17:16 PST 2016


Author: dcoughlin
Date: Fri Feb  5 13:17:16 2016
New Revision: 259905

URL: http://llvm.org/viewvc/llvm-project?rev=259905&view=rev
Log:
[analyzer] checker-277: Pull in nullability fixes and dealloc checker.

Cherry-pick in the following fixes from trunk:

r259288:[analyzer] Make suppression of macro defensive checks work with -analyzer-eagerly-assume.
r259222:[analyzer] Suppress null reports from defensive checks in function-like macros.
r259221:[analyzer] Improve Nullability checker diagnostics
r259118:[analyzer] NullabilityChecker: Remove unused isReturnSelf() function.
r259099:[analyzer] Suppress nullability warnings in copy, mutableCopy, and init families.
r258461:[analyzer] Suppress nullability warning for defensive super initializer idiom.
r258896:[analyzer] ObjCDeallocChecker: Only operate on classes with retained properties.
r258886:[analyzer] Body farm: Look for property ivar in shadowing readwrite property.
r258061:[analyzer] Nullability: Look through implicit casts when suppressing warnings on return.
r257938:[analyzer] Check for return of nil in ObjC methods with nonnull return type.


Added:
    cfe/tags/checker/checker-278/test/Analysis/DeallocMissingRelease.m
      - copied unchanged from r258896, cfe/trunk/test/Analysis/DeallocMissingRelease.m
    cfe/tags/checker/checker-278/test/Analysis/nullability-no-arc.mm
      - copied unchanged from r258061, cfe/trunk/test/Analysis/nullability-no-arc.mm
Modified:
    cfe/tags/checker/checker-278/   (props changed)
    cfe/tags/checker/checker-278/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
    cfe/tags/checker/checker-278/lib/Analysis/BodyFarm.cpp
    cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
    cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
    cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
    cfe/tags/checker/checker-278/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
    cfe/tags/checker/checker-278/lib/StaticAnalyzer/Core/CheckerContext.cpp
    cfe/tags/checker/checker-278/test/Analysis/MissingDealloc.m
    cfe/tags/checker/checker-278/test/Analysis/PR2978.m
    cfe/tags/checker/checker-278/test/Analysis/inlining/false-positive-suppression.c
    cfe/tags/checker/checker-278/test/Analysis/nullability.mm
    cfe/tags/checker/checker-278/test/Analysis/nullability_nullonly.mm
    cfe/tags/checker/checker-278/test/Analysis/properties.m

Propchange: cfe/tags/checker/checker-278/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Feb  5 13:17:16 2016
@@ -1,3 +1,4 @@
 /cfe/branches/type-system-rewrite:134693-134817
+/cfe/trunk:257938,258061,258461,258886,258896,259099,259118,259221-259222,259288
 /cfe/trunk/test:170344
 /cfe/trunk/test/SemaTemplate:126920

Modified: cfe/tags/checker/checker-278/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/tags/checker/checker-278/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h?rev=259905&r1=259904&r2=259905&view=diff
==============================================================================
--- cfe/tags/checker/checker-278/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h (original)
+++ cfe/tags/checker/checker-278/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h Fri Feb  5 13:17:16 2016
@@ -263,6 +263,10 @@ public:
     Eng.getBugReporter().emitReport(std::move(R));
   }
 
+  /// \brief Returns the word that should be used to refer to the declaration
+  /// in the report.
+  StringRef getDeclDescription(const Decl *D);
+
   /// \brief Get the declaration of the called function (path-sensitive).
   const FunctionDecl *getCalleeDecl(const CallExpr *CE) const;
 

Modified: cfe/tags/checker/checker-278/lib/Analysis/BodyFarm.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/tags/checker/checker-278/lib/Analysis/BodyFarm.cpp?rev=259905&r1=259904&r2=259905&view=diff
==============================================================================
--- cfe/tags/checker/checker-278/lib/Analysis/BodyFarm.cpp (original)
+++ cfe/tags/checker/checker-278/lib/Analysis/BodyFarm.cpp Fri Feb  5 13:17:16 2016
@@ -383,10 +383,49 @@ Stmt *BodyFarm::getBody(const FunctionDe
   return Val.getValue();
 }
 
+static const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) {
+  const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
+
+  if (IVar)
+    return IVar;
+
+  // When a readonly property is shadowed in a class extensions with a
+  // a readwrite property, the instance variable belongs to the shadowing
+  // property rather than the shadowed property. If there is no instance
+  // variable on a readonly property, check to see whether the property is
+  // shadowed and if so try to get the instance variable from shadowing
+  // property.
+  if (!Prop->isReadOnly())
+    return nullptr;
+
+  auto *Container = cast<ObjCContainerDecl>(Prop->getDeclContext());
+  const ObjCInterfaceDecl *PrimaryInterface = nullptr;
+  if (auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(Container)) {
+    PrimaryInterface = InterfaceDecl;
+  } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(Container)) {
+    PrimaryInterface = CategoryDecl->getClassInterface();
+  } else if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) {
+    PrimaryInterface = ImplDecl->getClassInterface();
+  } else {
+    return nullptr;
+  }
+
+  // FindPropertyVisibleInPrimaryClass() looks first in class extensions, so it
+  // is guaranteed to find the shadowing property, if it exists, rather than
+  // the shadowed property.
+  auto *ShadowingProp = PrimaryInterface->FindPropertyVisibleInPrimaryClass(
+      Prop->getIdentifier());
+  if (ShadowingProp && ShadowingProp != Prop) {
+    IVar = ShadowingProp->getPropertyIvarDecl();
+  }
+
+  return IVar;
+}
+
 static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
                                       const ObjCPropertyDecl *Prop) {
   // First, find the backing ivar.
-  const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
+  const ObjCIvarDecl *IVar = findBackingIvar(Prop);
   if (!IVar)
     return nullptr;
 

Modified: cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp?rev=259905&r1=259904&r2=259905&view=diff
==============================================================================
--- cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp (original)
+++ cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp Fri Feb  5 13:17:16 2016
@@ -28,7 +28,7 @@
 using namespace clang;
 using namespace ento;
 
-static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID,
+static bool scan_ivar_release(Stmt *S, const ObjCIvarDecl *ID,
                               const ObjCPropertyDecl *PD,
                               Selector Release,
                               IdentifierInfo* SelfII,
@@ -76,42 +76,67 @@ static bool scan_ivar_release(Stmt *S, O
   return false;
 }
 
+static bool isSynthesizedRetainableProperty(const ObjCPropertyImplDecl *I,
+                                            const ObjCIvarDecl **ID,
+                                            const ObjCPropertyDecl **PD) {
+
+  if (I->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
+    return false;
+
+  (*ID) = I->getPropertyIvarDecl();
+  if (!(*ID))
+    return false;
+
+  QualType T = (*ID)->getType();
+  if (!T->isObjCRetainableType())
+    return false;
+
+  (*PD) = I->getPropertyDecl();
+  // Shouldn't be able to synthesize a property that doesn't exist.
+  assert(*PD);
+
+  return true;
+}
+
+static bool synthesizedPropertyRequiresRelease(const ObjCPropertyDecl *PD) {
+  // A synthesized property must be released if and only if the kind of setter
+  // was neither 'assign' or 'weak'.
+  ObjCPropertyDecl::SetterKind SK = PD->getSetterKind();
+  return (SK != ObjCPropertyDecl::Assign && SK != ObjCPropertyDecl::Weak);
+}
+
 static void checkObjCDealloc(const CheckerBase *Checker,
                              const ObjCImplementationDecl *D,
                              const LangOptions &LOpts, BugReporter &BR) {
 
-  assert (LOpts.getGC() != LangOptions::GCOnly);
+  assert(LOpts.getGC() != LangOptions::GCOnly);
+  assert(!LOpts.ObjCAutoRefCount);
 
   ASTContext &Ctx = BR.getContext();
   const ObjCInterfaceDecl *ID = D->getClassInterface();
 
-  // Does the class contain any ivars that are pointers (or id<...>)?
+  // Does the class contain any synthesized properties that are retainable?
   // If not, skip the check entirely.
-  // NOTE: This is motivated by PR 2517:
-  //        http://llvm.org/bugs/show_bug.cgi?id=2517
-
-  bool containsPointerIvar = false;
-
-  for (const auto *Ivar : ID->ivars()) {
-    QualType T = Ivar->getType();
-
-    if (!T->isObjCObjectPointerType() ||
-        Ivar->hasAttr<IBOutletAttr>() || // Skip IBOutlets.
-        Ivar->hasAttr<IBOutletCollectionAttr>()) // Skip IBOutletCollections.
+  bool containsRetainedSynthesizedProperty = false;
+  for (const auto *I : D->property_impls()) {
+    const ObjCIvarDecl *ID = nullptr;
+    const ObjCPropertyDecl *PD = nullptr;
+    if (!isSynthesizedRetainableProperty(I, &ID, &PD))
       continue;
 
-    containsPointerIvar = true;
-    break;
+    if (synthesizedPropertyRequiresRelease(PD)) {
+      containsRetainedSynthesizedProperty = true;
+      break;
+    }
   }
 
-  if (!containsPointerIvar)
+  if (!containsRetainedSynthesizedProperty)
     return;
 
   // Determine if the class subclasses NSObject.
   IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
   IdentifierInfo* SenTestCaseII = &Ctx.Idents.get("SenTestCase");
 
-
   for ( ; ID ; ID = ID->getSuperClass()) {
     IdentifierInfo *II = ID->getIdentifier();
 
@@ -142,9 +167,6 @@ static void checkObjCDealloc(const Check
     }
   }
 
-  PathDiagnosticLocation DLoc =
-    PathDiagnosticLocation::createBegin(D, BR.getSourceManager());
-
   if (!MD) { // No dealloc found.
 
     const char* name = LOpts.getGC() == LangOptions::NonGC
@@ -155,6 +177,9 @@ static void checkObjCDealloc(const Check
     llvm::raw_string_ostream os(buf);
     os << "Objective-C class '" << *D << "' lacks a 'dealloc' instance method";
 
+    PathDiagnosticLocation DLoc =
+        PathDiagnosticLocation::createBegin(D, BR.getSourceManager());
+
     BR.EmitBasicReport(D, Checker, name, categories::CoreFoundationObjectiveC,
                        os.str(), DLoc);
     return;
@@ -170,28 +195,12 @@ static void checkObjCDealloc(const Check
   // Scan for missing and extra releases of ivars used by implementations
   // of synthesized properties
   for (const auto *I : D->property_impls()) {
-    // We can only check the synthesized properties
-    if (I->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
-      continue;
-
-    ObjCIvarDecl *ID = I->getPropertyIvarDecl();
-    if (!ID)
-      continue;
-
-    QualType T = ID->getType();
-    if (!T->isObjCObjectPointerType()) // Skip non-pointer ivars
-      continue;
-
-    const ObjCPropertyDecl *PD = I->getPropertyDecl();
-    if (!PD)
-      continue;
-
-    // ivars cannot be set via read-only properties, so we'll skip them
-    if (PD->isReadOnly())
+    const ObjCIvarDecl *ID = nullptr;
+    const ObjCPropertyDecl *PD = nullptr;
+    if (!isSynthesizedRetainableProperty(I, &ID, &PD))
       continue;
 
-    // ivar must be released if and only if the kind of setter was not 'assign'
-    bool requiresRelease = PD->getSetterKind() != ObjCPropertyDecl::Assign;
+    bool requiresRelease = synthesizedPropertyRequiresRelease(PD);
     if (scan_ivar_release(MD->getBody(), ID, PD, RS, SelfII, Ctx)
        != requiresRelease) {
       const char *name = nullptr;
@@ -203,24 +212,28 @@ static void checkObjCDealloc(const Check
                ? "missing ivar release (leak)"
                : "missing ivar release (Hybrid MM, non-GC)";
 
-        os << "The '" << *ID
-           << "' instance variable was retained by a synthesized property but "
-              "wasn't released in 'dealloc'";
+        os << "The '" << *ID << "' instance variable in '" << *D
+           << "' was retained by a synthesized property "
+              "but was not released in 'dealloc'";
       } else {
         name = LOpts.getGC() == LangOptions::NonGC
                ? "extra ivar release (use-after-release)"
                : "extra ivar release (Hybrid MM, non-GC)";
 
-        os << "The '" << *ID
-           << "' instance variable was not retained by a synthesized property "
+        os << "The '" << *ID << "' instance variable in '" << *D
+           << "' was not retained by a synthesized property "
               "but was released in 'dealloc'";
       }
 
-      PathDiagnosticLocation SDLoc =
-        PathDiagnosticLocation::createBegin(I, BR.getSourceManager());
+      // If @synthesize statement is missing, fall back to @property statement.
+      const Decl *SPDecl = I->getLocation().isValid()
+                               ? static_cast<const Decl *>(I)
+                               : static_cast<const Decl *>(PD);
+      PathDiagnosticLocation SPLoc =
+          PathDiagnosticLocation::createBegin(SPDecl, BR.getSourceManager());
 
       BR.EmitBasicReport(MD, Checker, name,
-                         categories::CoreFoundationObjectiveC, os.str(), SDLoc);
+                         categories::CoreFoundationObjectiveC, os.str(), SPLoc);
     }
   }
 }
@@ -235,7 +248,8 @@ class ObjCDeallocChecker : public Checke
 public:
   void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr,
                     BugReporter &BR) const {
-    if (mgr.getLangOpts().getGC() == LangOptions::GCOnly)
+    if (mgr.getLangOpts().getGC() == LangOptions::GCOnly ||
+        mgr.getLangOpts().ObjCAutoRefCount)
       return;
     checkObjCDealloc(this, cast<ObjCImplementationDecl>(D), mgr.getLangOpts(),
                      BR);

Modified: cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp?rev=259905&r1=259904&r2=259905&view=diff
==============================================================================
--- cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp (original)
+++ cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp Fri Feb  5 13:17:16 2016
@@ -230,7 +230,7 @@ void DereferenceChecker::checkLocation(S
     // dereference.
     if (ExplodedNode *N = C.generateSink(nullState, C.getPredecessor())) {
       ImplicitNullDerefEvent event = {l, isLoad, N, &C.getBugReporter(),
-                                      /*IsDirectDereference=*/false};
+                                      /*IsDirectDereference=*/true};
       dispatchEvent(event);
     }
   }
@@ -272,7 +272,7 @@ void DereferenceChecker::checkBind(SVal
     if (ExplodedNode *N = C.generateSink(StNull, C.getPredecessor())) {
       ImplicitNullDerefEvent event = {V, /*isLoad=*/true, N,
                                       &C.getBugReporter(),
-                                      /*IsDirectDereference=*/false};
+                                      /*IsDirectDereference=*/true};
       dispatchEvent(event);
     }
   }

Modified: cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp?rev=259905&r1=259904&r2=259905&view=diff
==============================================================================
--- cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp (original)
+++ cfe/tags/checker/checker-278/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp Fri Feb  5 13:17:16 2016
@@ -26,13 +26,16 @@
 //===----------------------------------------------------------------------===//
 
 #include "ClangSACheckers.h"
-#include "llvm/Support/Path.h"
+
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Path.h"
+
 using namespace clang;
 using namespace ento;
 
@@ -89,18 +92,6 @@ enum class ErrorKind : int {
   NullablePassedToNonnull
 };
 
-const char *const ErrorMessages[] = {
-    "Null is assigned to a pointer which is expected to have non-null value",
-    "Null passed to a callee that requires a non-null argument",
-    "Null is returned from a function that is expected to return a non-null "
-    "value",
-    "Nullable pointer is assigned to a pointer which is expected to have "
-    "non-null value",
-    "Nullable pointer is returned from a function that is expected to return a "
-    "non-null value",
-    "Nullable pointer is dereferenced",
-    "Nullable pointer is passed to a callee that requires a non-null argument"};
-
 class NullabilityChecker
     : public Checker<check::Bind, check::PreCall, check::PreStmt<ReturnStmt>,
                      check::PostCall, check::PostStmt<ExplicitCastExpr>,
@@ -169,17 +160,19 @@ private:
   ///
   /// When \p SuppressPath is set to true, no more bugs will be reported on this
   /// path by this checker.
-  void reportBugIfPreconditionHolds(ErrorKind Error, ExplodedNode *N,
-                                    const MemRegion *Region, CheckerContext &C,
+  void reportBugIfPreconditionHolds(StringRef Msg, ErrorKind Error,
+                                    ExplodedNode *N, const MemRegion *Region,
+                                    CheckerContext &C,
                                     const Stmt *ValueExpr = nullptr,
                                     bool SuppressPath = false) const;
 
-  void reportBug(ErrorKind Error, ExplodedNode *N, const MemRegion *Region,
-                 BugReporter &BR, const Stmt *ValueExpr = nullptr) const {
+  void reportBug(StringRef Msg, ErrorKind Error, ExplodedNode *N,
+                 const MemRegion *Region, BugReporter &BR,
+                 const Stmt *ValueExpr = nullptr) const {
     if (!BT)
       BT.reset(new BugType(this, "Nullability", "Memory error"));
-    const char *Msg = ErrorMessages[static_cast<int>(Error)];
-    std::unique_ptr<BugReport> R(new BugReport(*BT, Msg, N));
+
+    auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
     if (Region) {
       R->markInteresting(Region);
       R->addVisitor(llvm::make_unique<NullabilityBugVisitor>(Region));
@@ -366,29 +359,25 @@ static bool checkPreconditionViolation(P
   if (!D)
     return false;
 
-  if (const auto *BlockD = dyn_cast<BlockDecl>(D)) {
-    if (checkParamsForPreconditionViolation(BlockD->parameters(), State,
-                                            LocCtxt)) {
-      if (!N->isSink())
-        C.addTransition(State->set<PreconditionViolated>(true), N);
-      return true;
-    }
+  ArrayRef<ParmVarDecl*> Params;
+  if (const auto *BD = dyn_cast<BlockDecl>(D))
+    Params = BD->parameters();
+  else if (const auto *FD = dyn_cast<FunctionDecl>(D))
+    Params = FD->parameters();
+  else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
+    Params = MD->parameters();
+  else
     return false;
-  }
 
-  if (const auto *FuncDecl = dyn_cast<FunctionDecl>(D)) {
-    if (checkParamsForPreconditionViolation(FuncDecl->parameters(), State,
-                                            LocCtxt)) {
-      if (!N->isSink())
-        C.addTransition(State->set<PreconditionViolated>(true), N);
-      return true;
-    }
-    return false;
+  if (checkParamsForPreconditionViolation(Params, State, LocCtxt)) {
+    if (!N->isSink())
+      C.addTransition(State->set<PreconditionViolated>(true), N);
+    return true;
   }
   return false;
 }
 
-void NullabilityChecker::reportBugIfPreconditionHolds(
+void NullabilityChecker::reportBugIfPreconditionHolds(StringRef Msg,
     ErrorKind Error, ExplodedNode *N, const MemRegion *Region,
     CheckerContext &C, const Stmt *ValueExpr, bool SuppressPath) const {
   ProgramStateRef OriginalState = N->getState();
@@ -400,7 +389,7 @@ void NullabilityChecker::reportBugIfPrec
     N = C.addTransition(OriginalState, N);
   }
 
-  reportBug(Error, N, Region, C.getBugReporter(), ValueExpr);
+  reportBug(Msg, Error, N, Region, C.getBugReporter(), ValueExpr);
 }
 
 /// Cleaning up the program state.
@@ -454,12 +443,30 @@ void NullabilityChecker::checkEvent(Impl
     // Do not suppress errors on defensive code paths, because dereferencing
     // a nullable pointer is always an error.
     if (Event.IsDirectDereference)
-      reportBug(ErrorKind::NullableDereferenced, Event.SinkNode, Region, BR);
-    else
-      reportBug(ErrorKind::NullablePassedToNonnull, Event.SinkNode, Region, BR);
+      reportBug("Nullable pointer is dereferenced",
+                ErrorKind::NullableDereferenced, Event.SinkNode, Region, BR);
+    else {
+      reportBug("Nullable pointer is passed to a callee that requires a "
+                "non-null", ErrorKind::NullablePassedToNonnull,
+                Event.SinkNode, Region, BR);
+    }
   }
 }
 
+/// Find the outermost subexpression of E that is not an implicit cast.
+/// This looks through the implicit casts to _Nonnull that ARC adds to
+/// return expressions of ObjC types when the return type of the function or
+/// method is non-null but the express is not.
+static const Expr *lookThroughImplicitCasts(const Expr *E) {
+  assert(E);
+
+  while (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+    E = ICE->getSubExpr();
+  }
+
+  return E;
+}
+
 /// This method check when nullable pointer or null value is returned from a
 /// function that has nonnull return type.
 ///
@@ -484,16 +491,31 @@ void NullabilityChecker::checkPreStmt(co
   if (!RetSVal)
     return;
 
+  bool InSuppressedMethodFamily = false;
+
+  QualType RequiredRetType;
   AnalysisDeclContext *DeclCtxt =
       C.getLocationContext()->getAnalysisDeclContext();
-  const FunctionType *FuncType = DeclCtxt->getDecl()->getFunctionType();
-  if (!FuncType)
+  const Decl *D = DeclCtxt->getDecl();
+  if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+    // HACK: This is a big hammer to avoid warning when there are defensive
+    // nil checks in -init and -copy methods. We should add more sophisticated
+    // logic here to suppress on common defensive idioms but still
+    // warn when there is a likely problem.
+    ObjCMethodFamily Family = MD->getMethodFamily();
+    if (OMF_init == Family || OMF_copy == Family || OMF_mutableCopy == Family)
+      InSuppressedMethodFamily = true;
+
+    RequiredRetType = MD->getReturnType();
+  } else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+    RequiredRetType = FD->getReturnType();
+  } else {
     return;
+  }
 
   NullConstraint Nullness = getNullConstraint(*RetSVal, State);
 
-  Nullability RequiredNullability =
-      getNullabilityAnnotation(FuncType->getReturnType());
+  Nullability RequiredNullability = getNullabilityAnnotation(RequiredRetType);
 
   // If the returned value is null but the type of the expression
   // generating it is nonnull then we will suppress the diagnostic.
@@ -501,17 +523,25 @@ void NullabilityChecker::checkPreStmt(co
   // function with a _Nonnull return type:
   //    return (NSString * _Nonnull)0;
   Nullability RetExprTypeLevelNullability =
-        getNullabilityAnnotation(RetExpr->getType());
+        getNullabilityAnnotation(lookThroughImplicitCasts(RetExpr)->getType());
 
   if (Filter.CheckNullReturnedFromNonnull &&
       Nullness == NullConstraint::IsNull &&
       RetExprTypeLevelNullability != Nullability::Nonnull &&
-      RequiredNullability == Nullability::Nonnull) {
+      RequiredNullability == Nullability::Nonnull &&
+      !InSuppressedMethodFamily) {
     static CheckerProgramPointTag Tag(this, "NullReturnedFromNonnull");
     ExplodedNode *N = C.generateErrorNode(State, &Tag);
     if (!N)
       return;
-    reportBugIfPreconditionHolds(ErrorKind::NilReturnedToNonnull, N, nullptr, C,
+
+    SmallString<256> SBuf;
+    llvm::raw_svector_ostream OS(SBuf);
+    OS << "Null is returned from a " << C.getDeclDescription(D) <<
+          " that is expected to return a non-null value";
+
+    reportBugIfPreconditionHolds(OS.str(),
+                                 ErrorKind::NilReturnedToNonnull, N, nullptr, C,
                                  RetExpr);
     return;
   }
@@ -530,7 +560,14 @@ void NullabilityChecker::checkPreStmt(co
         RequiredNullability == Nullability::Nonnull) {
       static CheckerProgramPointTag Tag(this, "NullableReturnedFromNonnull");
       ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
-      reportBugIfPreconditionHolds(ErrorKind::NullableReturnedToNonnull, N,
+
+      SmallString<256> SBuf;
+      llvm::raw_svector_ostream OS(SBuf);
+      OS << "Nullable pointer is returned from a " << C.getDeclDescription(D) <<
+            " that is expected to return a non-null value";
+
+      reportBugIfPreconditionHolds(OS.str(),
+                                   ErrorKind::NullableReturnedToNonnull, N,
                                    Region, C);
     }
     return;
@@ -579,14 +616,21 @@ void NullabilityChecker::checkPreCall(co
     Nullability ArgExprTypeLevelNullability =
         getNullabilityAnnotation(ArgExpr->getType());
 
+    unsigned ParamIdx = Param->getFunctionScopeIndex() + 1;
+
     if (Filter.CheckNullPassedToNonnull && Nullness == NullConstraint::IsNull &&
         ArgExprTypeLevelNullability != Nullability::Nonnull &&
         RequiredNullability == Nullability::Nonnull) {
       ExplodedNode *N = C.generateErrorNode(State);
       if (!N)
         return;
-      reportBugIfPreconditionHolds(ErrorKind::NilPassedToNonnull, N, nullptr, C,
-                                   ArgExpr);
+      SmallString<256> SBuf;
+      llvm::raw_svector_ostream OS(SBuf);
+      OS << "Null passed to a callee that requires a non-null " << ParamIdx
+         << llvm::getOrdinalSuffix(ParamIdx) << " parameter";
+      reportBugIfPreconditionHolds(OS.str(), ErrorKind::NilPassedToNonnull, N,
+                                   nullptr, C,
+                                   ArgExpr, /*SuppressPath=*/false);
       return;
     }
 
@@ -605,14 +649,20 @@ void NullabilityChecker::checkPreCall(co
       if (Filter.CheckNullablePassedToNonnull &&
           RequiredNullability == Nullability::Nonnull) {
         ExplodedNode *N = C.addTransition(State);
-        reportBugIfPreconditionHolds(ErrorKind::NullablePassedToNonnull, N,
+        SmallString<256> SBuf;
+        llvm::raw_svector_ostream OS(SBuf);
+        OS << "Nullable pointer is passed to a callee that requires a non-null "
+           << ParamIdx << llvm::getOrdinalSuffix(ParamIdx) << " parameter";
+        reportBugIfPreconditionHolds(OS.str(),
+                                     ErrorKind::NullablePassedToNonnull, N,
                                      Region, C, ArgExpr, /*SuppressPath=*/true);
         return;
       }
       if (Filter.CheckNullableDereferenced &&
           Param->getType()->isReferenceType()) {
         ExplodedNode *N = C.addTransition(State);
-        reportBugIfPreconditionHolds(ErrorKind::NullableDereferenced, N, Region,
+        reportBugIfPreconditionHolds("Nullable pointer is dereferenced",
+                                     ErrorKind::NullableDereferenced, N, Region,
                                      C, ArgExpr, /*SuppressPath=*/true);
         return;
       }
@@ -981,7 +1031,9 @@ void NullabilityChecker::checkBind(SVal
     if (!ValueExpr)
       ValueExpr = S;
 
-    reportBugIfPreconditionHolds(ErrorKind::NilAssignedToNonnull, N, nullptr, C,
+    reportBugIfPreconditionHolds("Null is assigned to a pointer which is "
+                                 "expected to have non-null value",
+                                 ErrorKind::NilAssignedToNonnull, N, nullptr, C,
                                  ValueExpr);
     return;
   }
@@ -1003,7 +1055,9 @@ void NullabilityChecker::checkBind(SVal
         LocNullability == Nullability::Nonnull) {
       static CheckerProgramPointTag Tag(this, "NullablePassedToNonnull");
       ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
-      reportBugIfPreconditionHolds(ErrorKind::NullableAssignedToNonnull, N,
+      reportBugIfPreconditionHolds("Nullable pointer is assigned to a pointer "
+                                   "which is expected to have non-null value",
+                                   ErrorKind::NullableAssignedToNonnull, N,
                                    ValueRegion, C);
     }
     return;

Modified: cfe/tags/checker/checker-278/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/tags/checker/checker-278/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp?rev=259905&r1=259904&r2=259905&view=diff
==============================================================================
--- cfe/tags/checker/checker-278/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp (original)
+++ cfe/tags/checker/checker-278/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp Fri Feb  5 13:17:16 2016
@@ -14,6 +14,7 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/CFGStmtMap.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
@@ -828,8 +829,53 @@ SuppressInlineDefensiveChecksVisitor::Vi
     // Check if this is inlined defensive checks.
     const LocationContext *CurLC =Succ->getLocationContext();
     const LocationContext *ReportLC = BR.getErrorNode()->getLocationContext();
-    if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC))
+    if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) {
       BR.markInvalid("Suppress IDC", CurLC);
+      return nullptr;
+    }
+
+    // Treat defensive checks in function-like macros as if they were an inlined
+    // defensive check. If the bug location is not in a macro and the
+    // terminator for the current location is in a macro then suppress the
+    // warning.
+    auto BugPoint = BR.getErrorNode()->getLocation().getAs<StmtPoint>();
+
+    if (!BugPoint)
+      return nullptr;
+
+    SourceLocation BugLoc = BugPoint->getStmt()->getLocStart();
+    if (BugLoc.isMacroID())
+      return nullptr;
+
+    ProgramPoint CurPoint = Succ->getLocation();
+    const Stmt *CurTerminatorStmt = nullptr;
+    if (auto BE = CurPoint.getAs<BlockEdge>()) {
+      CurTerminatorStmt = BE->getSrc()->getTerminator().getStmt();
+    } else if (auto SP = CurPoint.getAs<StmtPoint>()) {
+      const Stmt *CurStmt = SP->getStmt();
+      if (!CurStmt->getLocStart().isMacroID())
+        return nullptr;
+
+      CFGStmtMap *Map = CurLC->getAnalysisDeclContext()->getCFGStmtMap();
+      CurTerminatorStmt = Map->getBlock(CurStmt)->getTerminator();
+    } else {
+      return nullptr;
+    }
+
+    if (!CurTerminatorStmt)
+      return nullptr;
+
+    SourceLocation TerminatorLoc = CurTerminatorStmt->getLocStart();
+    if (TerminatorLoc.isMacroID()) {
+      const SourceManager &SMgr = BRC.getSourceManager();
+      std::pair<FileID, unsigned> TLInfo = SMgr.getDecomposedLoc(TerminatorLoc);
+      SrcMgr::SLocEntry SE = SMgr.getSLocEntry(TLInfo.first);
+      const SrcMgr::ExpansionInfo &EInfo = SE.getExpansion();
+      if (EInfo.isFunctionMacroExpansion()) {
+        BR.markInvalid("Suppress Macro IDC", CurLC);
+        return nullptr;
+      }
+    }
   }
   return nullptr;
 }

Modified: cfe/tags/checker/checker-278/lib/StaticAnalyzer/Core/CheckerContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/tags/checker/checker-278/lib/StaticAnalyzer/Core/CheckerContext.cpp?rev=259905&r1=259904&r2=259905&view=diff
==============================================================================
--- cfe/tags/checker/checker-278/lib/StaticAnalyzer/Core/CheckerContext.cpp (original)
+++ cfe/tags/checker/checker-278/lib/StaticAnalyzer/Core/CheckerContext.cpp Fri Feb  5 13:17:16 2016
@@ -35,6 +35,13 @@ StringRef CheckerContext::getCalleeName(
   return funI->getName();
 }
 
+StringRef CheckerContext::getDeclDescription(const Decl *D) {
+  if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D))
+    return "method";
+  if (isa<BlockDecl>(D))
+    return "anonymous block";
+  return "function";
+}
 
 bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
                                         StringRef Name) {

Modified: cfe/tags/checker/checker-278/test/Analysis/MissingDealloc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/tags/checker/checker-278/test/Analysis/MissingDealloc.m?rev=259905&r1=259904&r2=259905&view=diff
==============================================================================
--- cfe/tags/checker/checker-278/test/Analysis/MissingDealloc.m (original)
+++ cfe/tags/checker/checker-278/test/Analysis/MissingDealloc.m Fri Feb  5 13:17:16 2016
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.Dealloc %s -verify
-// expected-no-diagnostics
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.Dealloc -fblocks %s 2>&1 | FileCheck -check-prefix=CHECK %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.Dealloc -fblocks -triple x86_64-apple-darwin10 -fobjc-arc %s 2>&1 | FileCheck -check-prefix=CHECK-ARC -allow-empty '--implicit-check-not=error:' '--implicit-check-not=warning:' %s
+
 typedef signed char BOOL;
 @protocol NSObject
 - (BOOL)isEqual:(id)object;
@@ -13,23 +14,74 @@ typedef signed char BOOL;
 
 typedef struct objc_selector *SEL;
 
-// <rdar://problem/6380411>: 'myproperty' has kind 'assign' and thus the
-//  assignment through the setter does not perform a release.
+//===------------------------------------------------------------------------===
+// Do not warn about missing -dealloc method.  Not enough context to know
+// whether the ivar is retained or not.
 
- at interface MyObject : NSObject {
-  id _myproperty;  
+ at interface MissingDeallocWithIvar : NSObject {
+  NSObject *_ivar;
 }
- at property(assign) id myproperty;
 @end
 
- at implementation MyObject
- at synthesize myproperty=_myproperty; // no-warning
-- (void)dealloc {
-  self.myproperty = 0;
-  [super dealloc]; 
+ at implementation MissingDeallocWithIvar
+ at end
+
+//===------------------------------------------------------------------------===
+// Do not warn about missing -dealloc method.  These properties are not
+// retained or synthesized.
+
+ at interface MissingDeallocWithIntProperty : NSObject
+ at property (assign) int ivar;
+ at end
+
+ at implementation MissingDeallocWithIntProperty
+ at end
+
+ at interface MissingDeallocWithSELProperty : NSObject
+ at property (assign) SEL ivar;
+ at end
+
+ at implementation MissingDeallocWithSELProperty
+ at end
+
+//===------------------------------------------------------------------------===
+// Warn about missing -dealloc method.
+
+ at interface MissingDeallocWithCopyProperty : NSObject
+ at property (copy) NSObject *ivar;
+ at end
+
+// CHECK: MissingDealloc.m:[[@LINE+1]]:1: warning: Objective-C class 'MissingDeallocWithCopyProperty' lacks a 'dealloc' instance method
+ at implementation MissingDeallocWithCopyProperty
+ at end
+
+ at interface MissingDeallocWithRetainProperty : NSObject
+ at property (retain) NSObject *ivar;
+ at end
+
+// CHECK: MissingDealloc.m:[[@LINE+1]]:1: warning: Objective-C class 'MissingDeallocWithRetainProperty' lacks a 'dealloc' instance method
+ at implementation MissingDeallocWithRetainProperty
+ at end
+
+ at interface MissingDeallocWithIVarAndRetainProperty : NSObject {
+  NSObject *_ivar2;
 }
+ at property (retain) NSObject *ivar1;
+ at end
+
+// CHECK: MissingDealloc.m:[[@LINE+1]]:1: warning: Objective-C class 'MissingDeallocWithIVarAndRetainProperty' lacks a 'dealloc' instance method
+ at implementation MissingDeallocWithIVarAndRetainProperty
 @end
 
+ at interface MissingDeallocWithReadOnlyRetainedProperty : NSObject
+ at property (readonly,retain) NSObject *ivar;
+ at end
+
+// CHECK: MissingDealloc.m:[[@LINE+1]]:1: warning: Objective-C class 'MissingDeallocWithReadOnlyRetainedProperty' lacks a 'dealloc' instance method
+ at implementation MissingDeallocWithReadOnlyRetainedProperty
+ at end
+
+
 //===------------------------------------------------------------------------===
 //  Don't warn about iVars that are selectors.
 
@@ -65,27 +117,6 @@ IBOutlet NSWindow *window;
 @end
 
 //===------------------------------------------------------------------------===
-// <rdar://problem/6380411>
-// Was bogus warning: "The '_myproperty' instance variable was not retained by a
-//  synthesized property but was released in 'dealloc'"
-
- at interface MyObject_rdar6380411 : NSObject {
-    id _myproperty;
-}
- at property(assign) id myproperty;
- at end
-
- at implementation MyObject_rdar6380411
- at synthesize myproperty=_myproperty;
-- (void)dealloc {
-    // Don't claim that myproperty is released since it the property
-    // has the 'assign' attribute.
-    self.myproperty = 0; // no-warning
-    [super dealloc];
-}
- at end
-
-//===------------------------------------------------------------------------===
 // PR 3187: http://llvm.org/bugs/show_bug.cgi?id=3187
 // - Disable the missing -dealloc check for classes that subclass SenTestCase
 
@@ -112,3 +143,4 @@ IBOutlet NSWindow *window;
   // do something which uses resourcepath
 }
 @end
+// CHECK: 4 warnings generated.

Modified: cfe/tags/checker/checker-278/test/Analysis/PR2978.m
URL: http://llvm.org/viewvc/llvm-project/cfe/tags/checker/checker-278/test/Analysis/PR2978.m?rev=259905&r1=259904&r2=259905&view=diff
==============================================================================
--- cfe/tags/checker/checker-278/test/Analysis/PR2978.m (original)
+++ cfe/tags/checker/checker-278/test/Analysis/PR2978.m Fri Feb  5 13:17:16 2016
@@ -14,6 +14,7 @@
   id _Y;
   id _Z;
   id _K;
+  id _L;
   id _N;
   id _M;
   id _V;
@@ -23,6 +24,7 @@
 @property(retain) id Y;
 @property(assign) id Z;
 @property(assign) id K;
+ at property(weak) id L;
 @property(readonly) id N;
 @property(retain) id M;
 @property(retain) id V;
@@ -33,13 +35,14 @@
 
 @implementation MyClass
 @synthesize X = _X;
- at synthesize Y = _Y; // expected-warning{{The '_Y' instance variable was retained by a synthesized property but wasn't released in 'dealloc'}}
- at synthesize Z = _Z; // expected-warning{{The '_Z' instance variable was not retained by a synthesized property but was released in 'dealloc'}}
+ at synthesize Y = _Y; // expected-warning{{The '_Y' instance variable in 'MyClass' was retained by a synthesized property but was not released in 'dealloc'}}
+ at synthesize Z = _Z; // expected-warning{{The '_Z' instance variable in 'MyClass' was not retained by a synthesized property but was released in 'dealloc'}}
 @synthesize K = _K;
- at synthesize N = _N;
+ at synthesize L = _L; // no-warning
+ at synthesize N = _N; // expected-warning{{The '_N' instance variable in 'MyClass' was not retained by a synthesized property but was released in 'dealloc'}}
 @synthesize M = _M;
 @synthesize V = _V;
- at synthesize W = _W; // expected-warning{{The '_W' instance variable was retained by a synthesized property but wasn't released in 'dealloc'}}
+ at synthesize W = _W; // expected-warning{{The '_W' instance variable in 'MyClass' was retained by a synthesized property but was not released in 'dealloc'}}
 
 -(id) O{ return 0; }
 -(void) setO:(id)arg { }

Modified: cfe/tags/checker/checker-278/test/Analysis/inlining/false-positive-suppression.c
URL: http://llvm.org/viewvc/llvm-project/cfe/tags/checker/checker-278/test/Analysis/inlining/false-positive-suppression.c?rev=259905&r1=259904&r2=259905&view=diff
==============================================================================
--- cfe/tags/checker/checker-278/test/Analysis/inlining/false-positive-suppression.c (original)
+++ cfe/tags/checker/checker-278/test/Analysis/inlining/false-positive-suppression.c Fri Feb  5 13:17:16 2016
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -DSUPPRESSED=1 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-eagerly-assume -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-eagerly-assume -analyzer-checker=core -verify -DSUPPRESSED=1 %s
+// RUN: %clang_cc1 -analyze -analyzer-eagerly-assume -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s
 
 int opaquePropertyCheck(void *object);
 int coin();
@@ -93,6 +93,84 @@ int triggerDivZero () {
   return 5/y; // expected-warning {{Division by zero}}
 }
 
+// Treat a function-like macro similarly to an inlined function, so suppress
+// warnings along paths resulting from inlined checks.
+#define MACRO_WITH_CHECK(a) ( ((a) != 0) ? *a : 17)
+void testInlineCheckInMacro(int *p) {
+  int i = MACRO_WITH_CHECK(p);
+  (void)i;
+
+  *p = 1; // no-warning
+}
+
+#define MACRO_WITH_NESTED_CHECK(a) ( { int j = MACRO_WITH_CHECK(a); j; } )
+void testInlineCheckInNestedMacro(int *p) {
+  int i = MACRO_WITH_NESTED_CHECK(p);
+  (void)i;
+
+  *p = 1; // no-warning
+}
+
+// If there is a check in a macro that is not function-like, don't treat
+// it like a function so don't suppress.
+#define NON_FUNCTION_MACRO_WITH_CHECK ( ((p) != 0) ? *p : 17)
+void testNonFunctionMacro(int *p) {
+  int i = NON_FUNCTION_MACRO_WITH_CHECK ;
+  (void)i;
+
+  *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
+}
+
+
+// This macro will dereference its argument if the argument is NULL.
+#define MACRO_WITH_ERROR(a) ( ((a) != 0) ? 0 : *a)
+void testErrorInMacro(int *p) {
+  int i = MACRO_WITH_ERROR(p); // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
+  (void)i;
+}
+
+// Here the check (the "if") is not in a macro, so we should still warn.
+#define MACRO_IN_GUARD(a) (!(a))
+void testMacroUsedAsGuard(int *p) {
+  if (MACRO_IN_GUARD(p))
+    *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
+}
+
+// When a nil case split is introduced in a macro and the macro is in a guard,
+// we still shouldn't warn.
+int isNull(int *p);
+int isEqual(int *p, int *q);
+#define ISNULL(ptr)    ((ptr) == 0 || isNull(ptr))
+#define ISEQUAL(a, b)    ((int *)(a) == (int *)(b) || (ISNULL(a) && ISNULL(b)) || isEqual(a,b))
+#define ISNOTEQUAL(a, b)   (!ISEQUAL(a, b))
+void testNestedDisjunctiveMacro(int *p, int *q) {
+  if (ISNOTEQUAL(p,q)) {
+    *p = 1; // no-warning
+    *q = 1; // no-warning
+  }
+
+  *p = 1; // no-warning
+  *q = 1; // no-warning
+}
+
+void testNestedDisjunctiveMacro2(int *p, int *q) {
+  if (ISEQUAL(p,q)) {
+    return;
+  }
+
+  *p = 1; // no-warning
+  *q = 1; // no-warning
+}
+
+
+// Here the check is entirely in non-macro code even though the code itself
+// is a macro argument.
+#define MACRO_DO_IT(a) (a)
+void testErrorInArgument(int *p) {
+  int i = MACRO_DO_IT((p ? 0 : *p)); // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}c
+  (void)i;
+}
+
 // --------------------------
 // "Suppression suppression"
 // --------------------------

Modified: cfe/tags/checker/checker-278/test/Analysis/nullability.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/tags/checker/checker-278/test/Analysis/nullability.mm?rev=259905&r1=259904&r2=259905&view=diff
==============================================================================
--- cfe/tags/checker/checker-278/test/Analysis/nullability.mm (original)
+++ cfe/tags/checker/checker-278/test/Analysis/nullability.mm Fri Feb  5 13:17:16 2016
@@ -1,15 +1,28 @@
-// RUN: %clang_cc1 -fobjc-arc -analyze -analyzer-checker=core,nullability -verify %s
+// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core,nullability -verify %s
 
 #define nil 0
 #define BOOL int
 
+#define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
+#define NS_ASSUME_NONNULL_END   _Pragma("clang assume_nonnull end")
+
+typedef struct _NSZone NSZone;
+
 @protocol NSObject
 + (id)alloc;
 - (id)init;
 @end
 
+NS_ASSUME_NONNULL_BEGIN
 @protocol NSCopying
+- (id)copyWithZone:(nullable NSZone *)zone;
+
+ at end
+
+ at protocol NSMutableCopying
+- (id)mutableCopyWithZone:(nullable NSZone *)zone;
 @end
+NS_ASSUME_NONNULL_END
 
 __attribute__((objc_root_class))
 @interface
@@ -58,16 +71,16 @@ void testBasicRules() {
   // Make every dereference a different path to avoid sinks after errors.
   switch (getRandom()) {
   case 0: {
-    Dummy &r = *p; // expected-warning {{}}
+    Dummy &r = *p; // expected-warning {{Nullable pointer is dereferenced}}
   } break;
   case 1: {
-    int b = p->val; // expected-warning {{}}
+    int b = p->val; // expected-warning {{Nullable pointer is dereferenced}}
   } break;
   case 2: {
-    int stuff = *ptr; // expected-warning {{}}
+    int stuff = *ptr; // expected-warning {{Nullable pointer is dereferenced}}
   } break;
   case 3:
-    takesNonnull(p); // expected-warning {{}}
+    takesNonnull(p); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
     break;
   case 4: {
     Dummy d;
@@ -89,11 +102,11 @@ void testBasicRules() {
   Dummy *q = 0;
   if (getRandom()) {
     takesNullable(q);
-    takesNonnull(q); // expected-warning {{}}
+    takesNonnull(q); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
   }
   Dummy a;
   Dummy *_Nonnull nonnull = &a;
-  nonnull = q; // expected-warning {{}}
+  nonnull = q; // expected-warning {{Null is assigned to a pointer which is expected to have non-null value}}
   q = &a;
   takesNullable(q);
   takesNonnull(q);
@@ -106,26 +119,26 @@ void testArgumentTracking(Dummy *_Nonnul
   Dummy *p = nullable;
   Dummy *q = nonnull;
   switch(getRandom()) {
-  case 1: nonnull = p; break; // expected-warning {{}}
+  case 1: nonnull = p; break; // expected-warning {{Nullable pointer is assigned to a pointer which is expected to have non-null value}}
   case 2: p = 0; break;
   case 3: q = p; break;
   case 4: testMultiParamChecking(nonnull, nullable, nonnull); break;
   case 5: testMultiParamChecking(nonnull, nonnull, nonnull); break;
-  case 6: testMultiParamChecking(nonnull, nullable, nullable); break; // expected-warning {{}}
-  case 7: testMultiParamChecking(nullable, nullable, nonnull); // expected-warning {{}}
-  case 8: testMultiParamChecking(nullable, nullable, nullable); // expected-warning {{}}
+  case 6: testMultiParamChecking(nonnull, nullable, nullable); break; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 3rd parameter}}
+  case 7: testMultiParamChecking(nullable, nullable, nonnull); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
+  case 8: testMultiParamChecking(nullable, nullable, nullable); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
   case 9: testMultiParamChecking((Dummy *_Nonnull)0, nullable, nonnull); break;
   }
 }
 
 Dummy *_Nonnull testNullableReturn(Dummy *_Nullable a) {
   Dummy *p = a;
-  return p; // expected-warning {{}}
+  return p; // expected-warning {{Nullable pointer is returned from a function that is expected to return a non-null value}}
 }
 
 Dummy *_Nonnull testNullReturn() {
   Dummy *p = 0;
-  return p; // expected-warning {{}}
+  return p; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
 }
 
 void testObjCMessageResultNullability() {
@@ -147,20 +160,20 @@ void testObjCMessageResultNullability()
     break;
   case 3:
     shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
-    [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
+    [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
     break;
   case 4:
     shouldBeNullable = [eraseNullab(getNonnullTestObject()) returnsNullable];
-    [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
+    [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
     break;
   case 5:
     shouldBeNullable =
         [eraseNullab(getUnspecifiedTestObject()) returnsNullable];
-    [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
+    [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
     break;
   case 6:
     shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
-    [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
+    [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
     break;
   case 7: {
     int *shouldBeNonnull = [eraseNullab(getNonnullTestObject()) returnsNonnull];
@@ -189,7 +202,18 @@ Dummy * _Nonnull testDirectCastNilToNonn
 void testIndirectCastNilToNonnullAndPass() {
   Dummy *p = (Dummy * _Nonnull)0;
   // FIXME: Ideally the cast above would suppress this warning.
-  takesNonnull(p);  // expected-warning {{Null passed to a callee that requires a non-null argument}}
+  takesNonnull(p);  // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
+}
+
+void testIndirectNilPassToNonnull() {
+  Dummy *p = 0;
+  takesNonnull(p);  // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
+}
+
+void testConditionalNilPassToNonnull(Dummy *p) {
+  if (!p) {
+    takesNonnull(p);  // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
+  }
 }
 
 Dummy * _Nonnull testIndirectCastNilToNonnullAndReturn() {
@@ -206,7 +230,7 @@ void testInvalidPropagation() {
 
 void onlyReportFirstPreconditionViolationOnPath() {
   Dummy *p = returnsNullable();
-  takesNonnull(p); // expected-warning {{}}
+  takesNonnull(p); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
   takesNonnull(p); // No warning.
   // The first warning was not a sink. The analysis expected to continue.
   int i = 0;
@@ -255,6 +279,14 @@ void inlinedUnspecified(Dummy *p) {
   if (p) return;
 }
 
+void testNilReturnWithBlock(Dummy *p) {
+  p = 0;
+  Dummy *_Nonnull (^myblock)(void) = ^Dummy *_Nonnull(void) {
+    return p; // TODO: We should warn in blocks.
+  };
+  myblock();
+}
+
 Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) {
   switch (getRandom()) {
   case 1: inlinedNullable(p); break;
@@ -279,11 +311,111 @@ Dummy *_Nonnull testDefensiveInlineCheck
   return p;
 }
 
-void testObjCARCImplicitZeroInitialization() {
-  TestObject * _Nonnull implicitlyZeroInitialized; // no-warning
-  implicitlyZeroInitialized = getNonnullTestObject();
+
+ at interface SomeClass : NSObject {
+  int instanceVar;
+}
+ at end
+
+ at implementation SomeClass (MethodReturn)
+- (id)initWithSomething:(int)i {
+  if (self = [super init]) {
+    instanceVar = i;
+  }
+
+  return self;
+}
+
+- (TestObject * _Nonnull)testReturnsNullableInNonnullIndirectly {
+  TestObject *local = getNullableTestObject();
+  return local; // expected-warning {{Nullable pointer is returned from a method that is expected to return a non-null value}}
 }
 
-void testObjCARCExplicitZeroInitialization() {
-  TestObject * _Nonnull explicitlyZeroInitialized = nil; // expected-warning {{Null is assigned to a pointer which is expected to have non-null value}}
+- (TestObject * _Nonnull)testReturnsCastSuppressedNullableInNonnullIndirectly {
+  TestObject *local = getNullableTestObject();
+  return (TestObject * _Nonnull)local; // no-warning
 }
+
+- (TestObject * _Nonnull)testReturnsNullableInNonnullWhenPreconditionViolated:(TestObject * _Nonnull) p {
+  TestObject *local = getNullableTestObject();
+  if (!p) // Pre-condition violated here.
+    return local; // no-warning
+  else
+    return p; // no-warning
+}
+ at end
+
+ at interface ClassWithInitializers : NSObject
+ at end
+
+ at implementation ClassWithInitializers
+- (instancetype _Nonnull)initWithNonnullReturnAndSelfCheckingIdiom {
+  // This defensive check is a common-enough idiom that we filter don't want
+  // to issue a diagnostic for it,
+  if (self = [super init]) {
+  }
+
+  return self; // no-warning
+}
+
+- (instancetype _Nonnull)initWithNonnullReturnAndNilReturnViaLocal {
+  self = [super init];
+  // This leaks, but we're not checking for that here.
+
+  ClassWithInitializers *other = nil;
+  // False negative. Once we have more subtle suppression of defensive checks in
+  // initializers we should warn here.
+  return other;
+}
+ at end
+
+ at interface SubClassWithInitializers : ClassWithInitializers
+ at end
+
+ at implementation SubClassWithInitializers
+// Note: Because this is overridding
+// -[ClassWithInitializers initWithNonnullReturnAndSelfCheckingIdiom],
+// the return type of this method becomes implicitly id _Nonnull.
+- (id)initWithNonnullReturnAndSelfCheckingIdiom {
+  if (self = [super initWithNonnullReturnAndSelfCheckingIdiom]) {
+  }
+
+  return self; // no-warning
+}
+
+- (id _Nonnull)initWithNonnullReturnAndSelfCheckingIdiomV2; {
+  // Another common return-checking idiom
+  self = [super initWithNonnullReturnAndSelfCheckingIdiom];
+  if (!self) {
+    return nil; // no-warning
+  }
+
+  return self;
+}
+ at end
+
+ at interface ClassWithCopyWithZone : NSObject<NSCopying,NSMutableCopying> {
+  id i;
+}
+
+ at end
+
+ at implementation ClassWithCopyWithZone
+-(id)copyWithZone:(NSZone *)zone {
+  ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
+  if (!newInstance)
+    return nil;
+
+  newInstance->i = i;
+  return newInstance;
+}
+
+-(id)mutableCopyWithZone:(NSZone *)zone {
+  ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
+  if (newInstance) {
+    newInstance->i = i;
+  }
+
+  return newInstance;
+}
+ at end

Modified: cfe/tags/checker/checker-278/test/Analysis/nullability_nullonly.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/tags/checker/checker-278/test/Analysis/nullability_nullonly.mm?rev=259905&r1=259904&r2=259905&view=diff
==============================================================================
--- cfe/tags/checker/checker-278/test/Analysis/nullability_nullonly.mm (original)
+++ cfe/tags/checker/checker-278/test/Analysis/nullability_nullonly.mm Fri Feb  5 13:17:16 2016
@@ -1,4 +1,20 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -verify %s
+// RUN: %clang_cc1 -analyze -fobjc-arc -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -verify %s
+
+#define nil 0
+#define BOOL int
+
+ at protocol NSObject
++ (id)alloc;
+- (id)init;
+ at end
+
+ at protocol NSCopying
+ at end
+
+__attribute__((objc_root_class))
+ at interface
+NSObject<NSObject>
+ at end
 
 int getRandom();
 
@@ -15,18 +31,18 @@ void testBasicRules() {
   Dummy *q = 0;
   if (getRandom()) {
     takesNullable(q);
-    takesNonnull(q); // expected-warning {{}}
+    takesNonnull(q); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
   }
 }
 
 Dummy *_Nonnull testNullReturn() {
   Dummy *p = 0;
-  return p; // expected-warning {{}}
+  return p; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
 }
 
 void onlyReportFirstPreconditionViolationOnPath() {
   Dummy *p = 0;
-  takesNonnull(p); // expected-warning {{}}
+  takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
   takesNonnull(p); // No warning.
   // Passing null to nonnull is a sink. Stop the analysis.
   int i = 0;
@@ -85,3 +101,61 @@ Dummy *_Nonnull testDefensiveInlineCheck
     takesNonnull(p);
   return p;
 }
+
+ at interface TestObject : NSObject
+ at end
+
+TestObject *_Nonnull getNonnullTestObject();
+
+void testObjCARCImplicitZeroInitialization() {
+  TestObject * _Nonnull implicitlyZeroInitialized; // no-warning
+  implicitlyZeroInitialized = getNonnullTestObject();
+}
+
+void testObjCARCExplicitZeroInitialization() {
+  TestObject * _Nonnull explicitlyZeroInitialized = nil; // expected-warning {{Null is assigned to a pointer which is expected to have non-null value}}
+}
+
+// Under ARC, returned expressions of ObjC objects types are are implicitly
+// cast to _Nonnull when the functions return type is _Nonnull, so make
+// sure this doesn't implicit cast doesn't suppress a legitimate warning.
+TestObject * _Nonnull returnsNilObjCInstanceIndirectly() {
+  TestObject *local = 0;
+  return local; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
+}
+
+TestObject * _Nonnull returnsNilObjCInstanceIndirectlyWithSupressingCast() {
+  TestObject *local = 0;
+  return (TestObject * _Nonnull)local; // no-warning
+}
+
+TestObject * _Nonnull returnsNilObjCInstanceDirectly() {
+  return nil; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
+}
+
+TestObject * _Nonnull returnsNilObjCInstanceDirectlyWithSuppressingCast() {
+  return (TestObject * _Nonnull)nil; // no-warning
+}
+
+ at interface SomeClass : NSObject
+ at end
+
+ at implementation SomeClass (MethodReturn)
+- (SomeClass * _Nonnull)testReturnsNilInNonnull {
+  SomeClass *local = nil;
+  return local; // expected-warning {{Null is returned from a method that is expected to return a non-null value}}
+}
+
+- (SomeClass * _Nonnull)testReturnsCastSuppressedNilInNonnull {
+  SomeClass *local = nil;
+  return (SomeClass * _Nonnull)local; // no-warning
+}
+
+- (SomeClass * _Nonnull)testReturnsNilInNonnullWhenPreconditionViolated:(SomeClass * _Nonnull) p {
+  SomeClass *local = nil;
+  if (!p) // Pre-condition violated here.
+    return local; // no-warning
+  else
+    return p; // no-warning
+}
+ at end

Modified: cfe/tags/checker/checker-278/test/Analysis/properties.m
URL: http://llvm.org/viewvc/llvm-project/cfe/tags/checker/checker-278/test/Analysis/properties.m?rev=259905&r1=259904&r2=259905&view=diff
==============================================================================
--- cfe/tags/checker/checker-278/test/Analysis/properties.m (original)
+++ cfe/tags/checker/checker-278/test/Analysis/properties.m Fri Feb  5 13:17:16 2016
@@ -211,6 +211,33 @@ void testConsistencyAssign(Person *p) {
   clang_analyzer_eval(p.friend == origFriend); // expected-warning{{UNKNOWN}}
 }
 
+ at interface ClassWithShadowedReadWriteProperty {
+  int _f;
+}
+ at property (readonly) int someProp;
+ at end
+
+ at interface ClassWithShadowedReadWriteProperty ()
+ at property (readwrite) int someProp;
+ at end
+
+ at implementation ClassWithShadowedReadWriteProperty
+- (void)testSynthesisForShadowedReadWriteProperties; {
+  clang_analyzer_eval(self.someProp == self.someProp); // expected-warning{{TRUE}}
+
+  _f = 1;
+
+  // Read of shadowed property should not invalidate receiver.
+  (void)self.someProp;
+  clang_analyzer_eval(_f == 1); // expected-warning{{TRUE}}
+
+  _f = 2;
+  // Call to getter of shadowed property should not invalidate receiver.
+  (void)[self someProp];
+  clang_analyzer_eval(_f == 2); // expected-warning{{TRUE}}
+}
+ at end
+
 #if !__has_feature(objc_arc)
 void testOverrelease(Person *p, int coin) {
   switch (coin) {




More information about the llvm-branch-commits mailing list