diff --git a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp index 2cb511cbeaef..6d3dd1e42f02 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp +++ b/clang/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 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D, } } -static bool isAnnotatedToAllowDirectAssignment(const ObjCPropertyDecl *D) { +static bool isAnnotatedToAllowDirectAssignment(const Decl *D) { for (specific_attr_iterator AI = D->specific_attr_begin(), AE = D->specific_attr_end(); AI != AE; ++AI) { @@ -183,10 +191,12 @@ void DirectIvarAssignment::MethodCrawler::VisitBinaryOperator( 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/clang/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m b/clang/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m index 300f9775bfb6..f44978656998 100644 --- a/clang/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m +++ b/clang/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m @@ -23,6 +23,7 @@ typedef signed char BOOL; @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 @@ typedef signed char BOOL; @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 @@ typedef signed char BOOL; _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;