diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 6b8596efb1b7c579fa9d91f4031aa8d6576e5277..ad4e31db9435eadc90095ea927fcc8237c3bdf49 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -2821,63 +2821,6 @@ static bool wasLoadedFromIvar(SymbolRef Sym) { return false; } -/// Returns the property that claims this instance variable, if any. -static const ObjCPropertyDecl *findPropForIvar(const ObjCIvarDecl *Ivar) { - auto IsPropertyForIvar = [Ivar](const ObjCPropertyDecl *Prop) -> bool { - return Prop->getPropertyIvarDecl() == Ivar; - }; - - const ObjCInterfaceDecl *Interface = Ivar->getContainingInterface(); - auto PropIter = std::find_if(Interface->prop_begin(), Interface->prop_end(), - IsPropertyForIvar); - if (PropIter != Interface->prop_end()) { - return *PropIter; - } - - for (auto Extension : Interface->visible_extensions()) { - PropIter = std::find_if(Extension->prop_begin(), Extension->prop_end(), - IsPropertyForIvar); - if (PropIter != Extension->prop_end()) - return *PropIter; - } - - return nullptr; -} - -namespace { - enum Retaining_t { - NonRetaining, - Retaining - }; -} - -static Optional<Retaining_t> getRetainSemantics(const ObjCPropertyDecl *Prop) { - assert(Prop->getPropertyIvarDecl() && - "should only be used for properties with synthesized implementations"); - - if (!Prop->hasWrittenStorageAttribute()) { - // Don't assume anything about the retain semantics of readonly properties. - if (Prop->isReadOnly()) - return None; - - // Don't assume anything about readwrite properties with manually-supplied - // setters. - const ObjCMethodDecl *Setter = Prop->getSetterMethodDecl(); - bool HasManualSetter = std::any_of(Setter->redecls_begin(), - Setter->redecls_end(), - [](const Decl *SetterRedecl) -> bool { - return cast<ObjCMethodDecl>(SetterRedecl)->hasBody(); - }); - if (HasManualSetter) - return None; - - // If the setter /is/ synthesized, we're already relying on the retain - // semantics of the property. Continue as normal. - } - - return Prop->isRetaining() ? Retaining : NonRetaining; -} - void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE, CheckerContext &C) const { Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>(); @@ -2914,14 +2857,6 @@ void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE, return; } - // Also don't do anything if the ivar is unretained. If so, we know that - // there's no outstanding retain count for the value. - if (Kind == RetEffect::ObjC) - if (const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl())) - if (auto retainSemantics = getRetainSemantics(Prop)) - if (retainSemantics.getValue() == NonRetaining) - return; - // Note that this value has been loaded from an ivar. C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess())); return; @@ -2935,23 +2870,7 @@ void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE, return; } - bool didUpdateState = false; - if (Kind == RetEffect::ObjC) { - // Check if the ivar is known to be unretained. If so, we know that - // there's no outstanding retain count for the value. - if (const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl())) { - if (auto retainSemantics = getRetainSemantics(Prop)) { - if (retainSemantics.getValue() == NonRetaining) { - State = setRefBinding(State, Sym, PlusZero); - didUpdateState = true; - } - } - } - } - - if (!didUpdateState) - State = setRefBinding(State, Sym, PlusZero.withIvarAccess()); - + State = setRefBinding(State, Sym, PlusZero.withIvarAccess()); C.addTransition(State); } diff --git a/test/Analysis/properties.m b/test/Analysis/properties.m index ca6f253d94f416577e22e823b7d92fc5349d252e..c4b8c8c2158065ab0546f429b1f6cea54c32ae6c 100644 --- a/test/Analysis/properties.m +++ b/test/Analysis/properties.m @@ -382,7 +382,7 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) { - (void)testOverreleaseUnownedIvar { [_unownedProp retain]; [_unownedProp release]; - [_unownedProp release]; // expected-warning{{not owned at this point by the caller}} + [_unownedProp release]; // FIXME-warning{{not owned at this point by the caller}} } - (void)testOverreleaseIvarOnly { @@ -409,7 +409,7 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) { - (void)testOverreleaseImplicitSynthIvar { [_implicitSynthProp retain]; [_implicitSynthProp release]; - [_implicitSynthProp release]; // expected-warning{{not owned at this point by the caller}} + [_implicitSynthProp release]; // FIXME-warning{{not owned at this point by the caller}} } - (void)testOverreleaseCF { @@ -486,7 +486,7 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) { - (void)testPropertyAccessThenReleaseUnowned { id unowned = [self.unownedProp retain]; [unowned release]; - [_unownedProp release]; // expected-warning{{not owned}} + [_unownedProp release]; // FIXME-warning{{not owned}} } - (void)testPropertyAccessThenReleaseUnowned2 { @@ -494,7 +494,7 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) { id unowned = [self.unownedProp retain]; [unowned release]; clang_analyzer_eval(unowned == fromIvar); // expected-warning{{TRUE}} - [fromIvar release]; // expected-warning{{not owned}} + [fromIvar release]; // FIXME-warning{{not owned}} } - (void)testPropertyAccessThenReleaseManual { @@ -557,7 +557,7 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) { - (void)testPropertyAccessThenReleaseImplicitSynth { id prop = [self.implicitSynthProp retain]; [prop release]; - [_implicitSynthProp release]; // expected-warning{{not owned}} + [_implicitSynthProp release]; // FIXME-warning{{not owned}} } - (void)testPropertyAccessThenReleaseImplicitSynth2 { @@ -565,7 +565,7 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) { id prop = [self.implicitSynthProp retain]; [prop release]; clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}} - [fromIvar release]; // expected-warning{{not owned}} + [fromIvar release]; // FIXME-warning{{not owned}} } - (id)getUnownedFromProperty { diff --git a/test/Analysis/retain-release-path-notes.m b/test/Analysis/retain-release-path-notes.m index 23935b9d1d3a6f85045e02a99670e1bb89ed3ab9..9232156109e14981819437da20015f191ea4fa27 100644 --- a/test/Analysis/retain-release-path-notes.m +++ b/test/Analysis/retain-release-path-notes.m @@ -282,11 +282,11 @@ void CFAutoreleaseUnownedMixed() { } - (void)testOverreleaseUnownedIvar { - [_unownedProp retain]; // expected-note {{Object loaded from instance variable}} - // expected-note@-1 {{Reference count incremented. The object now has a +1 retain count}} - [_unownedProp release]; // expected-note {{Reference count decremented}} - [_unownedProp release]; // expected-note {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} - // expected-warning@-1 {{not owned at this point by the caller}} + [_unownedProp retain]; // FIXME-note {{Object loaded from instance variable}} + // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}} + [_unownedProp release]; // FIXME-note {{Reference count decremented}} + [_unownedProp release]; // FIXME-note {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} + // FIXME-warning@-1 {{not owned at this point by the caller}} } - (void)testOverreleaseOwnedIvarUse { @@ -6271,300 +6271,6 @@ void CFAutoreleaseUnownedMixed() { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: <key>end</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>4</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>15</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>kind</key><string>event</string> -// CHECK-NEXT: <key>location</key> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>4</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <key>ranges</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>4</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>15</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </array> -// CHECK-NEXT: <key>depth</key><integer>0</integer> -// CHECK-NEXT: <key>extended_message</key> -// CHECK-NEXT: <string>Object loaded from instance variable</string> -// CHECK-NEXT: <key>message</key> -// CHECK-NEXT: <string>Object loaded from instance variable</string> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>kind</key><string>control</string> -// CHECK-NEXT: <key>edges</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>start</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>4</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>15</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: <key>end</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>kind</key><string>event</string> -// CHECK-NEXT: <key>location</key> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <key>ranges</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>23</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>4</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>15</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </array> -// CHECK-NEXT: <key>depth</key><integer>0</integer> -// CHECK-NEXT: <key>extended_message</key> -// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string> -// CHECK-NEXT: <key>message</key> -// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>kind</key><string>control</string> -// CHECK-NEXT: <key>edges</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>start</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>285</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: <key>end</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>287</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>287</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>kind</key><string>event</string> -// CHECK-NEXT: <key>location</key> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>287</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <key>ranges</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>287</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>287</integer> -// CHECK-NEXT: <key>col</key><integer>24</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>287</integer> -// CHECK-NEXT: <key>col</key><integer>4</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>287</integer> -// CHECK-NEXT: <key>col</key><integer>15</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </array> -// CHECK-NEXT: <key>depth</key><integer>0</integer> -// CHECK-NEXT: <key>extended_message</key> -// CHECK-NEXT: <string>Reference count decremented</string> -// CHECK-NEXT: <key>message</key> -// CHECK-NEXT: <string>Reference count decremented</string> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>kind</key><string>control</string> -// CHECK-NEXT: <key>edges</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>start</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>287</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>287</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: <key>end</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>288</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>288</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>kind</key><string>event</string> -// CHECK-NEXT: <key>location</key> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>288</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <key>ranges</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>288</integer> -// CHECK-NEXT: <key>col</key><integer>4</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>288</integer> -// CHECK-NEXT: <key>col</key><integer>15</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </array> -// CHECK-NEXT: <key>depth</key><integer>0</integer> -// CHECK-NEXT: <key>extended_message</key> -// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string> -// CHECK-NEXT: <key>message</key> -// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string> -// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string> -// CHECK-NEXT: <key>type</key><string>Bad release</string> -// CHECK-NEXT: <key>check_name</key><string>osx.cocoa.RetainCount</string> -// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string> -// CHECK-NEXT: <key>issue_context</key><string>testOverreleaseUnownedIvar</string> -// CHECK-NEXT: <key>issue_hash</key><string>4</string> -// CHECK-NEXT: <key>location</key> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>288</integer> -// CHECK-NEXT: <key>col</key><integer>3</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>path</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>kind</key><string>control</string> -// CHECK-NEXT: <key>edges</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>start</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>293</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer>