[analyzer] IvarInvalidation: correctly handle cases where only partial invalidators exist

- If only partial invalidators exist and there are no full invalidators in @implementation, report every ivar that has
not been invalidated. (Previously, we reported the first Ivar in the list, which could actually have been invalidated
by a partial invalidator. The code assumed you cannot have only partial invalidators.)

- Do not report missing invalidation method declaration if a partial invalidation method declaration exists.

llvm-svn: 180170
This commit is contained in:
Anna Zaks 2013-04-24 02:49:16 +00:00
parent b205227092
commit 7712f38978
2 changed files with 75 additions and 13 deletions

View File

@ -437,6 +437,7 @@ visit(const ObjCImplementationDecl *ImplD) const {
// Remove ivars invalidated by the partial invalidation methods. They do not // Remove ivars invalidated by the partial invalidation methods. They do not
// need to be invalidated in the regular invalidation methods. // need to be invalidated in the regular invalidation methods.
bool AtImplementationContainsAtLeastOnePartialInvalidationMethod = false;
for (MethodSet::iterator for (MethodSet::iterator
I = PartialInfo.InvalidationMethods.begin(), I = PartialInfo.InvalidationMethods.begin(),
E = PartialInfo.InvalidationMethods.end(); I != E; ++I) { E = PartialInfo.InvalidationMethods.end(); I != E; ++I) {
@ -446,6 +447,8 @@ visit(const ObjCImplementationDecl *ImplD) const {
const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(), const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(),
InterfD->isInstanceMethod()); InterfD->isInstanceMethod());
if (D && D->hasBody()) { if (D && D->hasBody()) {
AtImplementationContainsAtLeastOnePartialInvalidationMethod = true;
bool CalledAnotherInvalidationMethod = false; bool CalledAnotherInvalidationMethod = false;
// The MethodCrowler is going to remove the invalidated ivars. // The MethodCrowler is going to remove the invalidated ivars.
MethodCrawler(Ivars, MethodCrawler(Ivars,
@ -471,7 +474,7 @@ visit(const ObjCImplementationDecl *ImplD) const {
containsInvalidationMethod(InterfaceD, Info, /*LookForPartial*/ false); containsInvalidationMethod(InterfaceD, Info, /*LookForPartial*/ false);
// Report an error in case none of the invalidation methods are declared. // Report an error in case none of the invalidation methods are declared.
if (!Info.needsInvalidation()) { if (!Info.needsInvalidation() && !PartialInfo.needsInvalidation()) {
if (Filter.check_MissingInvalidationMethod) if (Filter.check_MissingInvalidationMethod)
reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD, reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
/*MissingDeclaration*/ true); /*MissingDeclaration*/ true);
@ -520,9 +523,19 @@ visit(const ObjCImplementationDecl *ImplD) const {
} }
// Report an error in case none of the invalidation methods are implemented. // Report an error in case none of the invalidation methods are implemented.
if (!AtImplementationContainsAtLeastOneInvalidationMethod) if (!AtImplementationContainsAtLeastOneInvalidationMethod) {
reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD, if (AtImplementationContainsAtLeastOnePartialInvalidationMethod) {
/*MissingDeclaration*/ false); // Warn on the ivars that were not invalidated by the prrtial
// invalidation methods.
for (IvarSet::const_iterator
I = Ivars.begin(), E = Ivars.end(); I != E; ++I)
reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, 0);
} else {
// Otherwise, no invalidation methods were implemented.
reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
/*MissingDeclaration*/ false);
}
}
} }
void IvarInvalidationCheckerImpl:: void IvarInvalidationCheckerImpl::
@ -551,19 +564,27 @@ reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
void IvarInvalidationCheckerImpl:: void IvarInvalidationCheckerImpl::
reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD, reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
const IvarToPropMapTy &IvarToPopertyMap, const IvarToPropMapTy &IvarToPopertyMap,
const ObjCMethodDecl *MethodD) const { const ObjCMethodDecl *MethodD) const {
SmallString<128> sbuf; SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf); llvm::raw_svector_ostream os(sbuf);
printIvar(os, IvarD, IvarToPopertyMap); printIvar(os, IvarD, IvarToPopertyMap);
os << "needs to be invalidated or set to nil"; os << "needs to be invalidated or set to nil";
PathDiagnosticLocation MethodDecLocation = if (MethodD) {
PathDiagnosticLocation::createEnd(MethodD->getBody(), PathDiagnosticLocation MethodDecLocation =
BR.getSourceManager(), PathDiagnosticLocation::createEnd(MethodD->getBody(),
Mgr.getAnalysisDeclContext(MethodD)); BR.getSourceManager(),
BR.EmitBasicReport(MethodD, "Incomplete invalidation", Mgr.getAnalysisDeclContext(MethodD));
categories::CoreFoundationObjectiveC, os.str(), BR.EmitBasicReport(MethodD, "Incomplete invalidation",
MethodDecLocation); categories::CoreFoundationObjectiveC, os.str(),
MethodDecLocation);
} else {
BR.EmitBasicReport(IvarD, "Incomplete invalidation",
categories::CoreFoundationObjectiveC, os.str(),
PathDiagnosticLocation::createBegin(IvarD,
BR.getSourceManager()));
}
} }
void IvarInvalidationCheckerImpl::MethodCrawler::markInvalidated( void IvarInvalidationCheckerImpl::MethodCrawler::markInvalidated(

View File

@ -322,6 +322,47 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1,
#endif #endif
@end @end
@interface SomeNotInvalidatedInPartial : SomeInvalidationImplementingObject {
SomeInvalidationImplementingObject *Ivar1;
SomeInvalidationImplementingObject *Ivar2;
#if RUN_IVAR_INVALIDATION
// expected-warning@-2 {{Instance variable Ivar2 needs to be invalidated or set to nil}}
#endif
}
-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial")));
-(void)partialInvalidatorCallsPartial __attribute__((annotate("objc_instance_variable_invalidator_partial")));
@end
@implementation SomeNotInvalidatedInPartial {
SomeInvalidationImplementingObject *Ivar3;
#if RUN_IVAR_INVALIDATION
// expected-warning@-2 {{Instance variable Ivar3 needs to be invalidated or set to nil}}
#endif
}
-(void)partialInvalidator {
Ivar1 = 0;
}
-(void)partialInvalidatorCallsPartial {
[self partialInvalidator];
}
@end
@interface OnlyPartialDeclsBase : NSObject
-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial")));
@end
@implementation OnlyPartialDeclsBase
-(void)partialInvalidator {}
@end
@interface OnlyPartialDecls : OnlyPartialDeclsBase {
SomeInvalidationImplementingObject *Ivar1;
#if RUN_IVAR_INVALIDATION
// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for OnlyPartialDecls}}
#endif
}
@end
@implementation OnlyPartialDecls
@end
// False negative. // False negative.
@interface PartialCallsFull : SomeInvalidationImplementingObject { @interface PartialCallsFull : SomeInvalidationImplementingObject {
SomeInvalidationImplementingObject *Ivar1; SomeInvalidationImplementingObject *Ivar1;