[analyzer] Fix non-determinizm introduced in r172104.

In some cases, we just pick any ivar that needs invalidation and attach
the warning to it. Picking the first from DenseMap of pointer keys was
triggering non-deterministic output.

llvm-svn: 172134
This commit is contained in:
Anna Zaks 2013-01-10 22:44:16 +00:00
parent ecd5f4062f
commit 640123de5e
2 changed files with 31 additions and 19 deletions

View File

@ -175,7 +175,8 @@ class IvarInvalidationChecker :
/// Check if ivar should be tracked and add to TrackedIvars if positive. /// Check if ivar should be tracked and add to TrackedIvars if positive.
/// Returns true if ivar should be tracked. /// Returns true if ivar should be tracked.
static bool trackIvar(const ObjCIvarDecl *Iv, IvarSet &TrackedIvars); static bool trackIvar(const ObjCIvarDecl *Iv, IvarSet &TrackedIvars,
const ObjCIvarDecl **FirstIvarDecl);
/// Given the property declaration, and the list of tracked ivars, finds /// Given the property declaration, and the list of tracked ivars, finds
/// the ivar backing the property when possible. Returns '0' when no such /// the ivar backing the property when possible. Returns '0' when no such
@ -183,7 +184,8 @@ class IvarInvalidationChecker :
static const ObjCIvarDecl *findPropertyBackingIvar( static const ObjCIvarDecl *findPropertyBackingIvar(
const ObjCPropertyDecl *Prop, const ObjCPropertyDecl *Prop,
const ObjCInterfaceDecl *InterfaceD, const ObjCInterfaceDecl *InterfaceD,
IvarSet &TrackedIvars); IvarSet &TrackedIvars,
const ObjCIvarDecl **FirstIvarDecl);
/// Print ivar name or the property if the given ivar backs a property. /// Print ivar name or the property if the given ivar backs a property.
static void printIvar(llvm::raw_svector_ostream &os, static void printIvar(llvm::raw_svector_ostream &os,
@ -251,7 +253,8 @@ void IvarInvalidationChecker::containsInvalidationMethod(
} }
bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv, bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv,
IvarSet &TrackedIvars) { IvarSet &TrackedIvars,
const ObjCIvarDecl **FirstIvarDecl) {
QualType IvQTy = Iv->getType(); QualType IvQTy = Iv->getType();
const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>(); const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>();
if (!IvTy) if (!IvTy)
@ -261,7 +264,10 @@ bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv,
InvalidationInfo Info; InvalidationInfo Info;
containsInvalidationMethod(IvInterf, Info); containsInvalidationMethod(IvInterf, Info);
if (Info.needsInvalidation()) { if (Info.needsInvalidation()) {
TrackedIvars[cast<ObjCIvarDecl>(Iv->getCanonicalDecl())] = Info; const ObjCIvarDecl *I = cast<ObjCIvarDecl>(Iv->getCanonicalDecl());
TrackedIvars[I] = Info;
if (!*FirstIvarDecl)
*FirstIvarDecl = I;
return true; return true;
} }
return false; return false;
@ -270,7 +276,8 @@ bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv,
const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar( const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar(
const ObjCPropertyDecl *Prop, const ObjCPropertyDecl *Prop,
const ObjCInterfaceDecl *InterfaceD, const ObjCInterfaceDecl *InterfaceD,
IvarSet &TrackedIvars) { IvarSet &TrackedIvars,
const ObjCIvarDecl **FirstIvarDecl) {
const ObjCIvarDecl *IvarD = 0; const ObjCIvarDecl *IvarD = 0;
// Lookup for the synthesized case. // Lookup for the synthesized case.
@ -282,7 +289,7 @@ const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar(
return IvarD; return IvarD;
} }
// If the ivar is synthesized we still want to track it. // If the ivar is synthesized we still want to track it.
if (trackIvar(IvarD, TrackedIvars)) if (trackIvar(IvarD, TrackedIvars, FirstIvarDecl))
return IvarD; return IvarD;
} }
@ -330,13 +337,17 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCImplementationDecl *ImplD,
BugReporter &BR) const { BugReporter &BR) const {
// Collect all ivars that need cleanup. // Collect all ivars that need cleanup.
IvarSet Ivars; IvarSet Ivars;
// Record the first Ivar needing invalidation; used in reporting when only
// one ivar is sufficient. Cannot grab the first on the Ivars set to ensure
// deterministic output.
const ObjCIvarDecl *FirstIvarDecl = 0;
const ObjCInterfaceDecl *InterfaceD = ImplD->getClassInterface(); const ObjCInterfaceDecl *InterfaceD = ImplD->getClassInterface();
// Collect ivars declared in this class, its extensions and its implementation // Collect ivars declared in this class, its extensions and its implementation
ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(InterfaceD); ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(InterfaceD);
for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv; for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv;
Iv= Iv->getNextIvar()) Iv= Iv->getNextIvar())
trackIvar(Iv, Ivars); trackIvar(Iv, Ivars, &FirstIvarDecl);
// Construct Property/Property Accessor to Ivar maps to assist checking if an // Construct Property/Property Accessor to Ivar maps to assist checking if an
// ivar which is backing a property has been reset. // ivar which is backing a property has been reset.
@ -352,7 +363,8 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCImplementationDecl *ImplD,
I = PropMap.begin(), E = PropMap.end(); I != E; ++I) { I = PropMap.begin(), E = PropMap.end(); I != E; ++I) {
const ObjCPropertyDecl *PD = I->second; const ObjCPropertyDecl *PD = I->second;
const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars); const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars,
&FirstIvarDecl);
if (!ID) { if (!ID) {
continue; continue;
} }
@ -390,14 +402,14 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCImplementationDecl *ImplD,
llvm::raw_svector_ostream os(sbuf); llvm::raw_svector_ostream os(sbuf);
os << "No invalidation method declared in the @interface for " os << "No invalidation method declared in the @interface for "
<< InterfaceD->getName() << "; "; << InterfaceD->getName() << "; ";
const ObjCIvarDecl *IvarDecl = Ivars.begin()->first; assert(FirstIvarDecl);
printIvar(os, IvarDecl, IvarToPopertyMap); printIvar(os, FirstIvarDecl, IvarToPopertyMap);
os << "needs to be invalidated"; os << "needs to be invalidated";
PathDiagnosticLocation IvarDecLocation = PathDiagnosticLocation IvarDecLocation =
PathDiagnosticLocation::createBegin(IvarDecl, BR.getSourceManager()); PathDiagnosticLocation::createBegin(FirstIvarDecl, BR.getSourceManager());
BR.EmitBasicReport(IvarDecl, "Incomplete invalidation", BR.EmitBasicReport(FirstIvarDecl, "Incomplete invalidation",
categories::CoreFoundationObjectiveC, os.str(), categories::CoreFoundationObjectiveC, os.str(),
IvarDecLocation); IvarDecLocation);
return; return;
@ -455,14 +467,14 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCImplementationDecl *ImplD,
llvm::raw_svector_ostream os(sbuf); llvm::raw_svector_ostream os(sbuf);
os << "No invalidation method defined in the @implementation for " os << "No invalidation method defined in the @implementation for "
<< InterfaceD->getName() << "; "; << InterfaceD->getName() << "; ";
const ObjCIvarDecl *IvarDecl = Ivars.begin()->first; assert(FirstIvarDecl);
printIvar(os, IvarDecl, IvarToPopertyMap); printIvar(os, FirstIvarDecl, IvarToPopertyMap);
os << "needs to be invalidated"; os << "needs to be invalidated";
PathDiagnosticLocation IvarDecLocation = PathDiagnosticLocation IvarDecLocation =
PathDiagnosticLocation::createBegin(IvarDecl, PathDiagnosticLocation::createBegin(FirstIvarDecl,
BR.getSourceManager()); BR.getSourceManager());
BR.EmitBasicReport(IvarDecl, "Incomplete invalidation", BR.EmitBasicReport(FirstIvarDecl, "Incomplete invalidation",
categories::CoreFoundationObjectiveC, os.str(), categories::CoreFoundationObjectiveC, os.str(),
IvarDecLocation); IvarDecLocation);
} }

View File

@ -214,9 +214,9 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1,
@interface MissingInvalidationMethodDecl2 : NSObject { @interface MissingInvalidationMethodDecl2 : NSObject {
@private @private
Foo *_foo1; Foo *_foo1; // expected-warning {{No invalidation method declared in the @interface for MissingInvalidationMethodDecl2; Instance variable _foo1 needs to be invalidated}}
} }
@property (strong) Foo *bar1; // expected-warning {{No invalidation method declared in the @interface for MissingInvalidationMethodDecl2; Property bar1 needs to be invalidated}} @property (strong) Foo *bar1;
@end @end
@implementation MissingInvalidationMethodDecl2 @implementation MissingInvalidationMethodDecl2
@end @end