[cfe-commits] r164868 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp test/Analysis/objc_invalidation.m
Anna Zaks
ganna at apple.com
Fri Sep 28 17:20:38 PDT 2012
Author: zaks
Date: Fri Sep 28 19:20:38 2012
New Revision: 164868
URL: http://llvm.org/viewvc/llvm-project?rev=164868&view=rev
Log:
[analyzer] Re-implement IvarInvalidationChecker so that it verifies that
the validation occurred.
The original implementation was pessimistic - we assumed that ivars
which escape are invalidated. This version is optimistic, it assumes
that the ivars will always be explicitly invalidated: either set to nil
or sent an invalidation message.
Modified:
cfe/trunk/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
cfe/trunk/test/Analysis/objc_invalidation.m
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp?rev=164868&r1=164867&r2=164868&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp Fri Sep 28 19:20:38 2012
@@ -1,4 +1,4 @@
-//=- IvarInvalidationChecker.cpp - -*- C++ ----*-==//
+//=- IvarInvalidationChecker.cpp - -*- C++ -------------------------------*-==//
//
// The LLVM Compiler Infrastructure
//
@@ -13,10 +13,12 @@
// __attribute__((annotate("objc_instance_variable_invalidator")));
// all the "ivalidatable" instance variables of this class should be
// invalidated. We call an instance variable ivalidatable if it is an object of
-// a class which contains an invalidation method.
-//
-// Note, this checker currently only checks if an ivar was accessed by the
-// method, we do not currently support any deeper invalidation checking.
+// a class which contains an invalidation method. There could be multiple
+// methods annotated with such annotations per class, either one can be used
+// to invalidate the ivar. An ivar or property are considered to be
+// invalidated if they are being assigned 'nil' or an invalidation method has
+// been called on them. An invalidation method should either invalidate all
+// the ivars or call another invalidation method (on self).
//
//===----------------------------------------------------------------------===//
@@ -36,7 +38,7 @@
class IvarInvalidationChecker :
public Checker<check::ASTDecl<ObjCMethodDecl> > {
- typedef llvm::DenseMap<const ObjCIvarDecl*, bool> IvarSet;
+ typedef llvm::DenseSet<const ObjCMethodDecl*> MethodSet;
typedef llvm::DenseMap<const ObjCMethodDecl*,
const ObjCIvarDecl*> MethToIvarMapTy;
typedef llvm::DenseMap<const ObjCPropertyDecl*,
@@ -44,46 +46,130 @@
typedef llvm::DenseMap<const ObjCIvarDecl*,
const ObjCPropertyDecl*> IvarToPropMapTy;
+
+ struct IvarInfo {
+ /// Has the ivar been invalidated?
+ bool IsInvalidated;
+
+ /// The methods which can be used to invalidate the ivar.
+ MethodSet InvalidationMethods;
+
+ IvarInfo() : IsInvalidated(false) {}
+ void addInvalidationMethod(const ObjCMethodDecl *MD) {
+ InvalidationMethods.insert(MD);
+ }
+
+ bool needsInvalidation() const {
+ return !InvalidationMethods.empty();
+ }
+
+ void markInvalidated() {
+ IsInvalidated = true;
+ }
+
+ bool markInvalidated(const ObjCMethodDecl *MD) {
+ if (IsInvalidated)
+ return true;
+ for (MethodSet::iterator I = InvalidationMethods.begin(),
+ E = InvalidationMethods.end(); I != E; ++I) {
+ if (*I == MD) {
+ IsInvalidated = true;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool isInvalidated() const {
+ return IsInvalidated;
+ }
+ };
+
+ typedef llvm::DenseMap<const ObjCIvarDecl*, IvarInfo> IvarSet;
+
/// Statement visitor, which walks the method body and flags the ivars
/// referenced in it (either directly or via property).
class MethodCrawler : public ConstStmtVisitor<MethodCrawler> {
+ const ObjCMethodDecl *EnclosingMethod;
/// The set of Ivars which need to be invalidated.
IvarSet &IVars;
- /// Property setter/getter to ivar mapping.
- MethToIvarMapTy &PropertyAccessorToIvarMap;
+ /// Flag is set as the result of a message send to another
+ /// invalidation method.
+ bool &CalledAnotherInvalidationMethod;
+
+ /// Property setter to ivar mapping.
+ const MethToIvarMapTy &PropertySetterToIvarMap;
+
+ /// Property getter to ivar mapping.
+ const MethToIvarMapTy &PropertyGetterToIvarMap;
+
+ /// Property to ivar mapping.
+ const PropToIvarMapTy &PropertyToIvarMap;
+
+ /// The invalidation method being currently processed.
+ const ObjCMethodDecl *InvalidationMethod;
+
+ /// Peel off parents, casts, OpaqueValueExpr, and PseudoObjectExpr.
+ const Expr *peel(const Expr *E) const;
- // Property to ivar mapping.
- PropToIvarMapTy &PropertyToIvarMap;
+ /// Does this expression represent zero: '0'?
+ bool isZero(const Expr *E) const;
+
+ /// Mark the given ivar as invalidated.
+ void markInvalidated(const ObjCIvarDecl *Iv);
+
+ /// Checks if IvarRef refers to the tracked IVar, if yes, marks it as
+ /// invalidated.
+ void checkObjCIvarRefExpr(const ObjCIvarRefExpr *IvarRef);
+
+ /// Checks if ObjCPropertyRefExpr refers to the tracked IVar, if yes, marks
+ /// it as invalidated.
+ void checkObjCPropertyRefExpr(const ObjCPropertyRefExpr *PA);
+
+ /// Checks if ObjCMessageExpr refers to (is a getter for) the tracked IVar,
+ /// if yes, marks it as invalidated.
+ void checkObjCMessageExpr(const ObjCMessageExpr *ME);
+
+ /// Checks if the Expr refers to an ivar, if yes, marks it as invalidated.
+ void check(const Expr *E);
public:
- MethodCrawler(const ObjCInterfaceDecl *InID,
+ MethodCrawler(const ObjCMethodDecl *InMeth,
IvarSet &InIVars,
- MethToIvarMapTy &InPropertyAccessorToIvarMap,
- PropToIvarMapTy &InPropertyToIvarMap)
- : IVars(InIVars),
- PropertyAccessorToIvarMap(InPropertyAccessorToIvarMap),
- PropertyToIvarMap(InPropertyToIvarMap) {}
+ bool &InCalledAnotherInvalidationMethod,
+ const MethToIvarMapTy &InPropertySetterToIvarMap,
+ const MethToIvarMapTy &InPropertyGetterToIvarMap,
+ const PropToIvarMapTy &InPropertyToIvarMap)
+ : EnclosingMethod(InMeth),
+ IVars(InIVars),
+ CalledAnotherInvalidationMethod(InCalledAnotherInvalidationMethod),
+ PropertySetterToIvarMap(InPropertySetterToIvarMap),
+ PropertyGetterToIvarMap(InPropertyGetterToIvarMap),
+ PropertyToIvarMap(InPropertyToIvarMap),
+ InvalidationMethod(0) {}
void VisitStmt(const Stmt *S) { VisitChildren(S); }
- void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *IvarRef);
+ void VisitBinaryOperator(const BinaryOperator *BO);
void VisitObjCMessageExpr(const ObjCMessageExpr *ME);
- void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *PA);
-
void VisitChildren(const Stmt *S) {
- for (Stmt::const_child_range I = S->children(); I; ++I)
+ for (Stmt::const_child_range I = S->children(); I; ++I) {
if (*I)
this->Visit(*I);
+ if (CalledAnotherInvalidationMethod)
+ return;
+ }
}
};
/// Check if the any of the methods inside the interface are annotated with
- /// the invalidation annotation.
- static bool containsInvalidationMethod(const ObjCContainerDecl *D);
+ /// the invalidation annotation, update the IvarInfo accordingly.
+ static void containsInvalidationMethod(const ObjCContainerDecl *D,
+ IvarInfo &Out);
/// Check if ivar should be tracked and add to TrackedIvars if positive.
/// Returns true if ivar should be tracked.
@@ -104,7 +190,7 @@
// TODO: We are currently ignoring the ivars coming from class extensions.
};
-bool isInvalidationMethod(const ObjCMethodDecl *M) {
+static bool isInvalidationMethod(const ObjCMethodDecl *M) {
for (specific_attr_iterator<AnnotateAttr>
AI = M->specific_attr_begin<AnnotateAttr>(),
AE = M->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) {
@@ -115,13 +201,13 @@
return false;
}
-bool IvarInvalidationChecker::containsInvalidationMethod (
- const ObjCContainerDecl *D) {
+void IvarInvalidationChecker::containsInvalidationMethod(
+ const ObjCContainerDecl *D, IvarInfo &OutInfo) {
// TODO: Cache the results.
if (!D)
- return false;
+ return;
// Check all methods.
for (ObjCContainerDecl::method_iterator
@@ -129,7 +215,8 @@
E = D->meth_end(); I != E; ++I) {
const ObjCMethodDecl *MDI = *I;
if (isInvalidationMethod(MDI))
- return true;
+ OutInfo.addInvalidationMethod(
+ cast<ObjCMethodDecl>(MDI->getCanonicalDecl()));
}
// If interface, check all parent protocols and super.
@@ -139,10 +226,10 @@
for (ObjCInterfaceDecl::protocol_iterator
I = InterfaceD->protocol_begin(),
E = InterfaceD->protocol_end(); I != E; ++I) {
- if (containsInvalidationMethod(*I))
- return true;
+ containsInvalidationMethod(*I, OutInfo);
}
- return containsInvalidationMethod(InterfaceD->getSuperClass());
+ containsInvalidationMethod(InterfaceD->getSuperClass(), OutInfo);
+ return;
}
// If protocol, check all parent protocols.
@@ -150,10 +237,9 @@
for (ObjCInterfaceDecl::protocol_iterator
I = ProtD->protocol_begin(),
E = ProtD->protocol_end(); I != E; ++I) {
- if (containsInvalidationMethod(*I))
- return true;
+ containsInvalidationMethod(*I, OutInfo);
}
- return false;
+ return;
}
llvm_unreachable("One of the casts above should have succeeded.");
@@ -166,8 +252,11 @@
if (!IvTy)
return false;
const ObjCInterfaceDecl *IvInterf = IvTy->getInterfaceDecl();
- if (containsInvalidationMethod(IvInterf)) {
- TrackedIvars[cast<ObjCIvarDecl>(Iv->getCanonicalDecl())] = false;
+
+ IvarInfo Info;
+ containsInvalidationMethod(IvInterf, Info);
+ if (Info.needsInvalidation()) {
+ TrackedIvars[cast<ObjCIvarDecl>(Iv->getCanonicalDecl())] = Info;
return true;
}
return false;
@@ -234,7 +323,8 @@
// Construct Property/Property Accessor to Ivar maps to assist checking if an
// ivar which is backing a property has been reset.
- MethToIvarMapTy PropAccessorToIvarMap;
+ MethToIvarMapTy PropSetterToIvarMap;
+ MethToIvarMapTy PropGetterToIvarMap;
PropToIvarMapTy PropertyToIvarMap;
IvarToPropMapTy IvarToPopertyMap;
for (ObjCInterfaceDecl::prop_iterator
@@ -256,25 +346,31 @@
const ObjCMethodDecl *SetterD = PD->getSetterMethodDecl();
if (SetterD) {
SetterD = cast<ObjCMethodDecl>(SetterD->getCanonicalDecl());
- PropAccessorToIvarMap[SetterD] = ID;
+ PropSetterToIvarMap[SetterD] = ID;
}
const ObjCMethodDecl *GetterD = PD->getGetterMethodDecl();
if (GetterD) {
GetterD = cast<ObjCMethodDecl>(GetterD->getCanonicalDecl());
- PropAccessorToIvarMap[GetterD] = ID;
+ PropGetterToIvarMap[GetterD] = ID;
}
}
- // Check which ivars have been accessed by the method.
- // We assume that if ivar was at least accessed, it was not forgotten.
- MethodCrawler(InterfaceD, Ivars,
- PropAccessorToIvarMap, PropertyToIvarMap).VisitStmt(D->getBody());
+ // Check which ivars have been invalidated in the method body.
+ bool CalledAnotherInvalidationMethod = false;
+ MethodCrawler(D, Ivars,
+ CalledAnotherInvalidationMethod,
+ PropSetterToIvarMap,
+ PropGetterToIvarMap,
+ PropertyToIvarMap).VisitStmt(D->getBody());
+
+ if (CalledAnotherInvalidationMethod)
+ return;
// Warn on the ivars that were not accessed by the method.
for (IvarSet::const_iterator I = Ivars.begin(), E = Ivars.end(); I != E; ++I){
- if (I->second == false) {
+ if (!I->second.isInvalidated()) {
const ObjCIvarDecl *IvarDecl = I->first;
PathDiagnosticLocation IvarDecLocation =
@@ -303,38 +399,56 @@
}
}
-/// Handle the case when an ivar is directly accessed.
-void IvarInvalidationChecker::MethodCrawler::VisitObjCIvarRefExpr(
- const ObjCIvarRefExpr *IvarRef) {
- const Decl *D = IvarRef->getDecl();
- if (D)
- IVars[cast<ObjCIvarDecl>(D->getCanonicalDecl())] = true;
- VisitStmt(IvarRef);
+void IvarInvalidationChecker::MethodCrawler::markInvalidated(
+ const ObjCIvarDecl *Iv) {
+ IvarSet::iterator I = IVars.find(Iv);
+ if (I != IVars.end()) {
+ // If InvalidationMethod is present, we are processing the message send and
+ // should ensure we are invalidating with the appropriate method,
+ // otherwise, we are processing setting to 'nil'.
+ if (InvalidationMethod)
+ I->second.markInvalidated(InvalidationMethod);
+ else
+ I->second.markInvalidated();
+ }
}
+const Expr *IvarInvalidationChecker::MethodCrawler::peel(const Expr *E) const {
+ E = E->IgnoreParenCasts();
+ if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
+ E = POE->getSyntacticForm()->IgnoreParenCasts();
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
+ E = OVE->getSourceExpr()->IgnoreParenCasts();
+ return E;
+}
-/// Handle the case when the property backing ivar is set via a direct call
-/// to the setter.
-void IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr(
+void IvarInvalidationChecker::MethodCrawler::checkObjCIvarRefExpr(
+ const ObjCIvarRefExpr *IvarRef) {
+ if (const Decl *D = IvarRef->getDecl())
+ markInvalidated(cast<ObjCIvarDecl>(D->getCanonicalDecl()));
+}
+
+void IvarInvalidationChecker::MethodCrawler::checkObjCMessageExpr(
const ObjCMessageExpr *ME) {
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (MD) {
MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl());
- IVars[PropertyAccessorToIvarMap[MD]] = true;
+ MethToIvarMapTy::const_iterator IvI = PropertyGetterToIvarMap.find(MD);
+ if (IvI != PropertyGetterToIvarMap.end())
+ markInvalidated(IvI->second);
}
- VisitStmt(ME);
}
-/// Handle the case when the property backing ivar is set via the dot syntax.
-void IvarInvalidationChecker::MethodCrawler::VisitObjCPropertyRefExpr(
+void IvarInvalidationChecker::MethodCrawler::checkObjCPropertyRefExpr(
const ObjCPropertyRefExpr *PA) {
if (PA->isExplicitProperty()) {
const ObjCPropertyDecl *PD = PA->getExplicitProperty();
if (PD) {
PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl());
- IVars[PropertyToIvarMap[PD]] = true;
- VisitStmt(PA);
+ PropToIvarMapTy::const_iterator IvI = PropertyToIvarMap.find(PD);
+ if (IvI != PropertyToIvarMap.end())
+ markInvalidated(IvI->second);
return;
}
}
@@ -343,12 +457,95 @@
const ObjCMethodDecl *MD = PA->getImplicitPropertySetter();
if (MD) {
MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl());
- IVars[PropertyAccessorToIvarMap[MD]] = true;
- VisitStmt(PA);
+ MethToIvarMapTy::const_iterator IvI =PropertyGetterToIvarMap.find(MD);
+ if (IvI != PropertyGetterToIvarMap.end())
+ markInvalidated(IvI->second);
return;
}
}
- VisitStmt(PA);
+}
+
+bool IvarInvalidationChecker::MethodCrawler::isZero(const Expr *E) const {
+ E = peel(E);
+ if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E))
+ return IL->getValue() == 0;
+
+ if (const CastExpr *ICE = dyn_cast<CastExpr>(E))
+ return ICE->getCastKind() == CK_NullToPointer;
+
+ return false;
+}
+
+void IvarInvalidationChecker::MethodCrawler::check(const Expr *E) {
+ E = peel(E);
+
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
+ E = OVE->getSourceExpr();
+
+ if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
+ checkObjCIvarRefExpr(IvarRef);
+ return;
+ }
+
+ if (const ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ checkObjCPropertyRefExpr(PropRef);
+ return;
+ }
+
+ if (const ObjCMessageExpr *MsgExpr = dyn_cast<ObjCMessageExpr>(E)) {
+ checkObjCMessageExpr(MsgExpr);
+ return;
+ }
+}
+
+void IvarInvalidationChecker::MethodCrawler::VisitBinaryOperator(
+ const BinaryOperator *BO) {
+ if (!BO->isAssignmentOp())
+ return;
+
+ // Do we assign zero?
+ if (!isZero(BO->getRHS()))
+ return;
+
+ // Check the variable we are assigning to.
+ check(BO->getLHS());
+
+ VisitStmt(BO);
+}
+
+void IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr(
+ const ObjCMessageExpr *ME) {
+ const ObjCMethodDecl *MD = ME->getMethodDecl();
+ const Expr *Receiver = ME->getInstanceReceiver();
+
+ // Stop if we are calling '[self invalidate]'.
+ if (Receiver && isInvalidationMethod(MD))
+ if (const DeclRefExpr *RD =
+ dyn_cast<DeclRefExpr>(Receiver->IgnoreParenCasts())) {
+ if (RD->getDecl() == EnclosingMethod->getSelfDecl()) {
+ CalledAnotherInvalidationMethod = true;
+ return;
+ }
+ }
+
+ // Check if we call a setter and set the property to 'nil'.
+ if (MD && (ME->getNumArgs() == 1) && isZero(ME->getArg(0))) {
+ MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl());
+ MethToIvarMapTy::const_iterator IvI = PropertySetterToIvarMap.find(MD);
+ if (IvI != PropertySetterToIvarMap.end()) {
+ markInvalidated(IvI->second);
+ return;
+ }
+ }
+
+ // Check if we call the 'invalidation' routine on the ivar.
+ if (Receiver) {
+ InvalidationMethod = MD;
+ check(Receiver->IgnoreParenCasts());
+ InvalidationMethod = 0;
+ }
+
+ VisitStmt(ME);
}
}
Modified: cfe/trunk/test/Analysis/objc_invalidation.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/objc_invalidation.m?rev=164868&r1=164867&r2=164868&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/objc_invalidation.m (original)
+++ cfe/trunk/test/Analysis/objc_invalidation.m Fri Sep 28 19:20:38 2012
@@ -10,7 +10,11 @@
-(id)copy;
- (Class)class;
-(id)retain;
+-(id)description;
@end
+ at class NSString;
+
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
@protocol Invalidation1 <NSObject>
- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator")));
@@ -22,6 +26,7 @@
@protocol Invalidation3 <NSObject>
- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator")));
+- (void) invalidate2 __attribute__((annotate("objc_instance_variable_invalidator")));
@end
@interface Invalidation2Class <Invalidation2>
@@ -31,7 +36,7 @@
@end
@interface SomeInvalidationImplementingObject: NSObject <Invalidation3, Invalidation2> {
- SomeInvalidationImplementingObject *ObjA;
+ SomeInvalidationImplementingObject *ObjA; // invalidation in the parent
}
@end
@@ -39,21 +44,28 @@
- (void)invalidate{
ObjA = 0;
}
+- (void)invalidate2 {
+ [self invalidate];
+}
@end
@interface SomeSubclassInvalidatableObject : SomeInvalidationImplementingObject {
- SomeInvalidationImplementingObject *Obj1;
- SomeInvalidationImplementingObject *Obj2;
- SomeInvalidationImplementingObject *Obj3;
- SomeInvalidationImplementingObject *_Prop1;
- SomeInvalidationImplementingObject *_Prop4;
- SomeInvalidationImplementingObject *_propIvar;
- Invalidation1Class *MultipleProtocols;
- Invalidation2Class *MultInheritance;
- SomeInvalidationImplementingObject *_Prop5; // invalidate via getter method
+ SomeInvalidationImplementingObject *Ivar1; // regular ivar
+ SomeInvalidationImplementingObject *Ivar2; // regular ivar, sending invalidate message
+ SomeInvalidationImplementingObject *_Ivar3; // no property, call -description
+ SomeInvalidationImplementingObject *_Ivar4; // no property, provide as argument to NSLog()
+
+ SomeInvalidationImplementingObject *_Prop1; // partially implemented property, set to 0 with dot syntax
+ SomeInvalidationImplementingObject *_Prop2; // fully implemented prop, set to 0 with dot syntax
+ SomeInvalidationImplementingObject *_propIvar; // property with custom named ivar, set to 0 via setter
+ Invalidation1Class *MultipleProtocols; // regular ivar belonging to a different class
+ Invalidation2Class *MultInheritance; // regular ivar belonging to a different class
+ SomeInvalidationImplementingObject *_Prop3; // property, invalidate via sending a message to a getter method
+ SomeInvalidationImplementingObject *_Prop4; // property with @synthesize, invalidate via property
+ SomeInvalidationImplementingObject *_Prop5; // property with @synthesize, invalidate via getter method
- // No warnings on these.
- NSObject *NObj1;
+ // No warnings on these as they are not invalidatable.
+ NSObject *NIvar1;
NSObject *NObj2;
NSObject *_NProp1;
NSObject *_NpropIvar;
@@ -63,10 +75,12 @@
@property (nonatomic, assign) SomeInvalidationImplementingObject* Prop1;
@property (assign) SomeInvalidationImplementingObject* Prop2;
@property (assign) SomeInvalidationImplementingObject* Prop3;
- at property (assign) SomeInvalidationImplementingObject* Prop4;
- at property (assign) SomeInvalidationImplementingObject* Prop5;
- at property (assign) SomeInvalidationImplementingObject *SynthIvarProp;
+ at property (assign) SomeInvalidationImplementingObject *Prop5;
+ at property (assign) SomeInvalidationImplementingObject *Prop4;
+ at property (assign) SomeInvalidationImplementingObject* Prop6; // automatically synthesized prop
+ at property (assign) SomeInvalidationImplementingObject* Prop7; // automatically synthesized prop
+ at property (assign) SomeInvalidationImplementingObject *SynthIvarProp;
@property (assign) NSObject* NProp0;
@property (nonatomic, assign) NSObject* NProp1;
@@ -81,18 +95,21 @@
@implementation SomeSubclassInvalidatableObject
- at synthesize Prop2 = _propIvar;
- at synthesize Prop3;
+ at synthesize Prop7 = _propIvar;
+ at synthesize Prop3 = _Prop3;
+ at synthesize Prop5 = _Prop5;
+ at synthesize Prop4 = _Prop4;
+
- (void) setProp1: (SomeInvalidationImplementingObject*) InObj {
_Prop1 = InObj;
}
-- (void) setProp4: (SomeInvalidationImplementingObject*) InObj {
- _Prop4 = InObj;
+- (void) setProp2: (SomeInvalidationImplementingObject*) InObj {
+ _Prop2 = InObj;
}
-- (SomeInvalidationImplementingObject*) Prop4 {
- return _Prop4;
+- (SomeInvalidationImplementingObject*) Prop2 {
+ return _Prop2;
}
@synthesize NProp2 = _NpropIvar;
@@ -102,17 +119,24 @@
}
- (void) invalidate {
- [Obj3 invalidate];
+ [Ivar2 invalidate];
self.Prop0 = 0;
self.Prop1 = 0;
[self setProp2:0];
[self setProp3:0];
- self.Prop4 = 0;
- [[self Prop5] invalidate];
+ [[self Prop5] invalidate2];
+ [self.Prop4 invalidate];
+ self.Prop6 = 0;
+ [[self Prop7] invalidate];
+
+ [_Ivar3 description];
+ NSLog(@"%@", _Ivar4);
[super invalidate];
-}// expected-warning {{Instance variable Obj1 needs to be invalidated}}
- // expected-warning at -1 {{Instance variable Obj2 needs to be invalidated}}
+}
+// expected-warning at -1 {{Instance variable Ivar1 needs to be invalidated}}
// expected-warning at -2 {{Instance variable MultipleProtocols needs to be invalidated}}
// expected-warning at -3 {{Instance variable MultInheritance needs to be invalidated}}
// expected-warning at -4 {{Property SynthIvarProp needs to be invalidated}}
+ // expected-warning at -5 {{Instance variable _Ivar3 needs to be invalidated}}
+ // expected-warning at -6 {{Instance variable _Ivar4 needs to be invalidated}}
@end
More information about the cfe-commits
mailing list