[analyzer] DirectIvarAssignment: allow suppression annotation on Ivars.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172766 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
index 2cb511c..6d3dd1e 100644
--- a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
+++ b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
@@ -7,9 +7,17 @@
 //
 //===----------------------------------------------------------------------===//
 //
-//  Check that Objective C properties follow the following rules:
-//    - The property should be set with the setter, not though a direct
-//      assignment.
+//  Check that Objective C properties are set with the setter, not though a
+//      direct assignment.
+//
+//  Two versions of a checker exist: one that checks all methods and the other
+//      that only checks the methods annotated with
+//      __attribute__((annotate("objc_no_direct_instance_variable_assignment")))
+//
+//  The checker does not warn about assignments to Ivars, annotated with
+//       __attribute__((objc_allow_direct_instance_variable_assignment"))). This
+//      annotation serves as a false positive suppression mechanism for the
+//      checker. The annotation is allowed on properties and Ivars.
 //
 //===----------------------------------------------------------------------===//
 
@@ -155,7 +163,7 @@
   }
 }
 
-static bool isAnnotatedToAllowDirectAssignment(const ObjCPropertyDecl *D) {
+static bool isAnnotatedToAllowDirectAssignment(const Decl *D) {
   for (specific_attr_iterator<AnnotateAttr>
        AI = D->specific_attr_begin<AnnotateAttr>(),
        AE = D->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) {
@@ -183,10 +191,12 @@
 
     if (I != IvarToPropMap.end()) {
       const ObjCPropertyDecl *PD = I->second;
-      // Skip warnings on Ivars that correspond to properties, annotated with
+      // Skip warnings on Ivars, annotated with
       // objc_allow_direct_instance_variable_assignment. This annotation serves
-      // as a false positive suppression mechanism for the checker.
-      if (isAnnotatedToAllowDirectAssignment(PD))
+      // as a false positive suppression mechanism for the checker. The
+      // annotation is allowed on properties and ivars.
+      if (isAnnotatedToAllowDirectAssignment(PD) ||
+          isAnnotatedToAllowDirectAssignment(D))
         return;
 
       ObjCMethodDecl *GetterMethod =
diff --git a/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m b/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m
index 300f977..f449786 100644
--- a/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m
+++ b/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m
@@ -23,6 +23,7 @@
 @interface TestProperty : AnnotatedClass {
   MyClass *_Z;
   id _nonSynth;
+  MyClass* _NotA __attribute__((annotate("objc_allow_direct_instance_variable_assignment")));
 }
 
   @property (assign, nonatomic) MyClass* A; // explicitely synthesized, not implemented, non-default ivar name
@@ -33,7 +34,8 @@
 
   @property (assign, nonatomic) MyClass* Z; // non synthesized ivar, implemented setter
   @property (readonly) id nonSynth;  // non synthesized, explicitly implemented to return ivar with expected name
-
+  
+  @property (assign) MyClass* NotA;  // warnings should be suppressed, backing ivar is annotated
   @property (assign) MyClass* NotX __attribute__((annotate("objc_allow_direct_instance_variable_assignment")));  // warnings should be suppressed
 
   @end
@@ -48,6 +50,7 @@
     _Z = In; // expected-warning {{Direct assignment to an instance variable backing a property; use the setter instead}}
     _nonSynth = 0; // expected-warning {{Direct assignment to an instance variable backing a property; use the setter instead}}
     _NotX = 0; // no-warning
+    _NotA = 0; // no-warning
   }
   - (void) someMethodNotAnnaotated: (MyClass*)In {
     (__A) = In;