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
|
// 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(
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue