forked from OSchip/llvm-project
[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:
parent
b205227092
commit
7712f38978
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue