[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
// need to be invalidated in the regular invalidation methods.
bool AtImplementationContainsAtLeastOnePartialInvalidationMethod = false;
for (MethodSet::iterator
I = PartialInfo.InvalidationMethods.begin(),
E = PartialInfo.InvalidationMethods.end(); I != E; ++I) {
@ -446,6 +447,8 @@ visit(const ObjCImplementationDecl *ImplD) const {
const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(),
InterfD->isInstanceMethod());
if (D && D->hasBody()) {
AtImplementationContainsAtLeastOnePartialInvalidationMethod = true;
bool CalledAnotherInvalidationMethod = false;
// The MethodCrowler is going to remove the invalidated ivars.
MethodCrawler(Ivars,
@ -471,7 +474,7 @@ visit(const ObjCImplementationDecl *ImplD) const {
containsInvalidationMethod(InterfaceD, Info, /*LookForPartial*/ false);
// Report an error in case none of the invalidation methods are declared.
if (!Info.needsInvalidation()) {
if (!Info.needsInvalidation() && !PartialInfo.needsInvalidation()) {
if (Filter.check_MissingInvalidationMethod)
reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
/*MissingDeclaration*/ true);
@ -520,9 +523,19 @@ visit(const ObjCImplementationDecl *ImplD) const {
}
// Report an error in case none of the invalidation methods are implemented.
if (!AtImplementationContainsAtLeastOneInvalidationMethod)
if (!AtImplementationContainsAtLeastOneInvalidationMethod) {
if (AtImplementationContainsAtLeastOnePartialInvalidationMethod) {
// 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::
@ -557,6 +570,7 @@ reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
llvm::raw_svector_ostream os(sbuf);
printIvar(os, IvarD, IvarToPopertyMap);
os << "needs to be invalidated or set to nil";
if (MethodD) {
PathDiagnosticLocation MethodDecLocation =
PathDiagnosticLocation::createEnd(MethodD->getBody(),
BR.getSourceManager(),
@ -564,6 +578,13 @@ reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
BR.EmitBasicReport(MethodD, "Incomplete invalidation",
categories::CoreFoundationObjectiveC, os.str(),
MethodDecLocation);
} else {
BR.EmitBasicReport(IvarD, "Incomplete invalidation",
categories::CoreFoundationObjectiveC, os.str(),
PathDiagnosticLocation::createBegin(IvarD,
BR.getSourceManager()));
}
}
void IvarInvalidationCheckerImpl::MethodCrawler::markInvalidated(

View File

@ -322,6 +322,47 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1,
#endif
@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.
@interface PartialCallsFull : SomeInvalidationImplementingObject {
SomeInvalidationImplementingObject *Ivar1;