From: Anna Zaks Date: Wed, 24 Apr 2013 02:49:16 +0000 (+0000) Subject: [analyzer] IvarInvalidation: correctly handle cases where only partial invalidators... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=caadc413a88e864e058a3bea832f42debd8ddef2;p=clang [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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180170 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp index 5ed28e955d..cc940be7b1 100644 --- a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp @@ -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) - reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD, - /*MissingDeclaration*/ false); + 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:: @@ -551,19 +564,27 @@ reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl, void IvarInvalidationCheckerImpl:: reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD, - const IvarToPropMapTy &IvarToPopertyMap, - const ObjCMethodDecl *MethodD) const { + const IvarToPropMapTy &IvarToPopertyMap, + const ObjCMethodDecl *MethodD) const { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); printIvar(os, IvarD, IvarToPopertyMap); os << "needs to be invalidated or set to nil"; - PathDiagnosticLocation MethodDecLocation = - PathDiagnosticLocation::createEnd(MethodD->getBody(), - BR.getSourceManager(), - Mgr.getAnalysisDeclContext(MethodD)); - BR.EmitBasicReport(MethodD, "Incomplete invalidation", - categories::CoreFoundationObjectiveC, os.str(), - MethodDecLocation); + if (MethodD) { + PathDiagnosticLocation MethodDecLocation = + PathDiagnosticLocation::createEnd(MethodD->getBody(), + BR.getSourceManager(), + Mgr.getAnalysisDeclContext(MethodD)); + 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( diff --git a/test/Analysis/objc_invalidation.m b/test/Analysis/objc_invalidation.m index a6f5ec3f84..6919feaccf 100644 --- a/test/Analysis/objc_invalidation.m +++ b/test/Analysis/objc_invalidation.m @@ -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;