From 7a2704800943fbb69207e125d28186278712af36 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Fri, 28 Sep 2012 22:21:35 +0000 Subject: [PATCH] -Warc-repeated-use-of-weak: check ivars and variables as well. Like properties, loading from a weak ivar twice in the same function can give you inconsistent results if the object is deallocated between the two loads. It is safer to assign to a strong local variable and use that. Second half of . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164855 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 14 ++- include/clang/Sema/ScopeInfo.h | 23 +++- lib/Sema/AnalysisBasedWarnings.cpp | 33 ++++- lib/Sema/Sema.cpp | 137 ++++++++++++--------- lib/Sema/SemaChecking.cpp | 12 +- lib/Sema/SemaExpr.cpp | 28 ++++- lib/Sema/SemaExprMember.cpp | 21 +++- lib/Sema/SemaPseudoObject.cpp | 3 +- test/SemaObjC/arc-repeated-weak.mm | 83 ++++++++++--- 9 files changed, 253 insertions(+), 101 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index fa492164ab..c0afb10ef9 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -710,14 +710,16 @@ def warn_receiver_is_weak : Warning < "unpredictably null in ARC mode">, InGroup>, DefaultIgnore; def warn_arc_repeated_use_of_weak : Warning < - "weak property is accessed multiple times in this " - "%select{function|method|block|lambda}0 but may be unpredictably set to nil; " - "assign to a strong variable to keep the object alive">, + "weak %select{variable|property|implicit property|instance variable}0 %1 is " + "accessed multiple times in this %select{function|method|block|lambda}2 " + "but may be unpredictably set to nil; assign to a strong variable to keep " + "the object alive">, InGroup, DefaultIgnore; def warn_arc_possible_repeated_use_of_weak : Warning < - "weak property may be accessed multiple times in this " - "%select{function|method|block|lambda}0 but may be unpredictably set to nil; " - "assign to a strong variable to keep the object alive">, + "weak %select{variable|property|implicit property|instance variable}0 %1 may " + "be accessed multiple times in this %select{function|method|block|lambda}2 " + "and may be unpredictably set to nil; assign to a strong variable to keep " + "the object alive">, InGroup, DefaultIgnore; def note_arc_weak_also_accessed_here : Note< "also accessed here">; diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h index e4a663c059..c43da966a4 100644 --- a/include/clang/Sema/ScopeInfo.h +++ b/include/clang/Sema/ScopeInfo.h @@ -30,6 +30,8 @@ class ReturnStmt; class Scope; class SwitchStmt; class VarDecl; +class DeclRefExpr; +class ObjCIvarRefExpr; class ObjCPropertyRefExpr; namespace sema { @@ -132,6 +134,8 @@ public: /// [self foo].prop | 0 (unknown) | prop (ObjCPropertyDecl) /// self.prop1.prop2 | prop1 (ObjCPropertyDecl) | prop2 (ObjCPropertyDecl) /// MyClass.prop | MyClass (ObjCInterfaceDecl) | -prop (ObjCMethodDecl) + /// weakVar | 0 (known) | weakVar (VarDecl) + /// self->weakIvar | self (VarDecl) | weakIvar (ObjCIvarDecl) /// /// Objects are identified with only two Decls to make it reasonably fast to /// compare them. @@ -151,6 +155,9 @@ public: /// case of "implicit" properties (regular methods accessed via dot syntax). const NamedDecl *Property; + /// Used to find the proper base profile for a given base expression. + static BaseInfoTy getBaseInfo(const Expr *BaseE); + // For use in DenseMap. friend struct llvm::DenseMapInfo; inline WeakObjectProfileTy(); @@ -158,6 +165,8 @@ public: public: WeakObjectProfileTy(const ObjCPropertyRefExpr *RE); + WeakObjectProfileTy(const DeclRefExpr *RE); + WeakObjectProfileTy(const ObjCIvarRefExpr *RE); const NamedDecl *getProperty() const { return Property; } @@ -219,10 +228,11 @@ private: WeakObjectUseMap WeakObjectUses; public: - /// Record that a weak property was accessed. + /// Record that a weak object was accessed. /// /// Part of the implementation of -Wrepeated-use-of-weak. - void recordUseOfWeak(const ObjCPropertyRefExpr *PropE); + template + inline void recordUseOfWeak(const ExprT *E, bool IsRead = true); /// Record that a given expression is a "safe" access of a weak object (e.g. /// assigning it to a strong variable.) @@ -518,8 +528,15 @@ FunctionScopeInfo::WeakObjectProfileTy::getSentinel() { return Result; } +template +void FunctionScopeInfo::recordUseOfWeak(const ExprT *E, bool IsRead) { + assert(E); + WeakUseVector &Uses = WeakObjectUses[WeakObjectProfileTy(E)]; + Uses.push_back(WeakUseTy(E, IsRead)); } -} + +} // end namespace sema +} // end namespace clang namespace llvm { template <> diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 86e9dc2d64..bc25c0a554 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -957,19 +957,42 @@ static void diagnoseRepeatedUseOfWeak(Sema &S, const WeakObjectProfileTy &Key = I->second->first; const WeakUseVector &Uses = I->second->second; - // For complicated expressions like self.foo.bar, it's hard to keep track - // of whether 'self.foo' is the same between two cases. We can only be - // 100% sure of a repeated use if the "base" part of the key is a variable, - // rather than, say, another property. + // For complicated expressions like 'a.b.c' and 'x.b.c', WeakObjectProfileTy + // may not contain enough information to determine that these are different + // properties. We can only be 100% sure of a repeated use in certain cases, + // and we adjust the diagnostic kind accordingly so that the less certain + // case can be turned off if it is too noisy. unsigned DiagKind; if (Key.isExactProfile()) DiagKind = diag::warn_arc_repeated_use_of_weak; else DiagKind = diag::warn_arc_possible_repeated_use_of_weak; + // Classify the weak object being accessed for better warning text. + // This enum should stay in sync with the cases in + // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak. + enum { + Variable, + Property, + ImplicitProperty, + Ivar + } ObjectKind; + + const NamedDecl *D = Key.getProperty(); + if (isa(D)) + ObjectKind = Variable; + else if (isa(D)) + ObjectKind = Property; + else if (isa(D)) + ObjectKind = ImplicitProperty; + else if (isa(D)) + ObjectKind = Ivar; + else + llvm_unreachable("Unexpected weak object kind!"); + // Show the first time the object was read. S.Diag(FirstRead->getLocStart(), DiagKind) - << FunctionKind + << ObjectKind << D << FunctionKind << FirstRead->getSourceRange(); // Print all the other accesses as notes. diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 84cdb2b6f0..8555562d0d 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -82,65 +82,77 @@ static bool isSelfExpr(const Expr *E) { return M->getSelfDecl() == Param; } +FunctionScopeInfo::WeakObjectProfileTy::BaseInfoTy +FunctionScopeInfo::WeakObjectProfileTy::getBaseInfo(const Expr *E) { + E = E->IgnoreParenCasts(); + + const NamedDecl *D = 0; + bool IsExact = false; + + switch (E->getStmtClass()) { + case Stmt::DeclRefExprClass: + D = cast(E)->getDecl(); + IsExact = isa(D); + break; + case Stmt::MemberExprClass: { + const MemberExpr *ME = cast(E); + D = ME->getMemberDecl(); + IsExact = isa(ME->getBase()->IgnoreParenImpCasts()); + break; + } + case Stmt::ObjCIvarRefExprClass: { + const ObjCIvarRefExpr *IE = cast(E); + D = IE->getDecl(); + IsExact = isSelfExpr(IE->getBase()); + break; + } + case Stmt::PseudoObjectExprClass: { + const PseudoObjectExpr *POE = cast(E); + const ObjCPropertyRefExpr *BaseProp = + dyn_cast(POE->getSyntacticForm()); + if (BaseProp) { + D = getBestPropertyDecl(BaseProp); + + const Expr *DoubleBase = BaseProp->getBase(); + if (const OpaqueValueExpr *OVE = dyn_cast(DoubleBase)) + DoubleBase = OVE->getSourceExpr(); + + IsExact = isSelfExpr(DoubleBase); + } + break; + } + default: + break; + } + + return BaseInfoTy(D, IsExact); +} + + FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy( const ObjCPropertyRefExpr *PropE) - : Base(0, false), Property(getBestPropertyDecl(PropE)) { + : Base(0, true), Property(getBestPropertyDecl(PropE)) { if (PropE->isObjectReceiver()) { const OpaqueValueExpr *OVE = cast(PropE->getBase()); - const Expr *E = OVE->getSourceExpr()->IgnoreParenCasts(); - - switch (E->getStmtClass()) { - case Stmt::DeclRefExprClass: - Base.setPointer(cast(E)->getDecl()); - Base.setInt(isa(Base.getPointer())); - break; - case Stmt::MemberExprClass: { - const MemberExpr *ME = cast(E); - Base.setPointer(ME->getMemberDecl()); - Base.setInt(isa(ME->getBase()->IgnoreParenImpCasts())); - break; - } - case Stmt::ObjCIvarRefExprClass: { - const ObjCIvarRefExpr *IE = cast(E); - Base.setPointer(IE->getDecl()); - if (isSelfExpr(IE->getBase())) - Base.setInt(true); - break; - } - case Stmt::PseudoObjectExprClass: { - const PseudoObjectExpr *POE = cast(E); - const ObjCPropertyRefExpr *BaseProp = - dyn_cast(POE->getSyntacticForm()); - if (BaseProp) { - Base.setPointer(getBestPropertyDecl(BaseProp)); - - const Expr *DoubleBase = BaseProp->getBase(); - if (const OpaqueValueExpr *OVE = dyn_cast(DoubleBase)) - DoubleBase = OVE->getSourceExpr(); - - if (isSelfExpr(DoubleBase)) - Base.setInt(true); - } - break; - } - default: - break; - } + const Expr *E = OVE->getSourceExpr(); + Base = getBaseInfo(E); } else if (PropE->isClassReceiver()) { Base.setPointer(PropE->getClassReceiver()); - Base.setInt(true); } else { assert(PropE->isSuperReceiver()); - Base.setInt(true); } } -void FunctionScopeInfo::recordUseOfWeak(const ObjCPropertyRefExpr *RefExpr) { - assert(RefExpr); - WeakUseVector &Uses = - WeakObjectUses[FunctionScopeInfo::WeakObjectProfileTy(RefExpr)]; - Uses.push_back(WeakUseTy(RefExpr, RefExpr->isMessagingGetter())); +FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy( + const DeclRefExpr *DRE) + : Base(0, true), Property(DRE->getDecl()) { + assert(isa(Property)); +} + +FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy( + const ObjCIvarRefExpr *IvarE) + : Base(getBaseInfo(IvarE->getBase())), Property(IvarE->getDecl()) { } void FunctionScopeInfo::markSafeWeakUse(const Expr *E) { @@ -164,22 +176,27 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) { return; } - if (const ObjCPropertyRefExpr *RefExpr = dyn_cast(E)) { - // Has this property been seen as a weak property? - FunctionScopeInfo::WeakObjectUseMap::iterator Uses = - WeakObjectUses.find(FunctionScopeInfo::WeakObjectProfileTy(RefExpr)); - if (Uses == WeakObjectUses.end()) - return; + // Has this weak object been seen before? + FunctionScopeInfo::WeakObjectUseMap::iterator Uses; + if (const ObjCPropertyRefExpr *RefExpr = dyn_cast(E)) + Uses = WeakObjectUses.find(FunctionScopeInfo::WeakObjectProfileTy(RefExpr)); + else if (const ObjCIvarRefExpr *IvarE = dyn_cast(E)) + Uses = WeakObjectUses.find(FunctionScopeInfo::WeakObjectProfileTy(IvarE)); + else if (const DeclRefExpr *DRE = dyn_cast(E)) + Uses = WeakObjectUses.find(FunctionScopeInfo::WeakObjectProfileTy(DRE)); + else + return; - // Has there been a read from the property using this Expr? - FunctionScopeInfo::WeakUseVector::reverse_iterator ThisUse = - std::find(Uses->second.rbegin(), Uses->second.rend(), WeakUseTy(E, true)); - if (ThisUse == Uses->second.rend()) - return; + if (Uses == WeakObjectUses.end()) + return; - ThisUse->markSafe(); + // Has there been a read from the object using this Expr? + FunctionScopeInfo::WeakUseVector::reverse_iterator ThisUse = + std::find(Uses->second.rbegin(), Uses->second.rend(), WeakUseTy(E, true)); + if (ThisUse == Uses->second.rend()) return; - } + + ThisUse->markSafe(); } BlockScopeInfo::~BlockScopeInfo() { } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 7951a71e4e..ebb6cd1065 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -5639,9 +5639,19 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, if (LHSType.isNull()) LHSType = LHS->getType(); + + Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime(); + + if (LT == Qualifiers::OCL_Weak) { + DiagnosticsEngine::Level Level = + Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, Loc); + if (Level != DiagnosticsEngine::Ignored) + getCurFunction()->markSafeWeakUse(LHS); + } + if (checkUnsafeAssigns(Loc, LHSType, RHS)) return; - Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime(); + // FIXME. Check for other life times. if (LT != Qualifiers::OCL_None) return; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 597e4d6f77..0570dd38c7 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1425,6 +1425,15 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, MarkDeclRefReferenced(E); + if (getLangOpts().ObjCARCWeak && isa(D) && + Ty.getObjCLifetime() == Qualifiers::OCL_Weak) { + DiagnosticsEngine::Level Level = + Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, + E->getLocStart()); + if (Level != DiagnosticsEngine::Ignored) + getCurFunction()->recordUseOfWeak(E); + } + // Just in case we're building an illegal pointer-to-member. FieldDecl *FD = dyn_cast(D); if (FD && FD->isBitField()) @@ -1986,9 +1995,22 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, ObjCMethodFamily MF = CurMethod->getMethodFamily(); if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize) Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName(); - return Owned(new (Context) - ObjCIvarRefExpr(IV, IV->getType(), Loc, - SelfExpr.take(), true, true)); + + ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(), + Loc, + SelfExpr.take(), + true, true); + + if (getLangOpts().ObjCAutoRefCount) { + if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { + DiagnosticsEngine::Level Level = + Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, Loc); + if (Level != DiagnosticsEngine::Ignored) + getCurFunction()->recordUseOfWeak(Result); + } + } + + return Owned(Result); } } else if (CurMethod->isInstanceMethod()) { // We should warn if a local variable hides an ivar. diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index ec787d67a3..ff580697e6 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -13,6 +13,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -1272,9 +1273,23 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, if (warn) Diag(MemberLoc, diag::warn_direct_ivar_access) << IV->getDeclName(); } - return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), - MemberLoc, BaseExpr.take(), - IsArrow)); + + ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(), + MemberLoc, + BaseExpr.take(), + IsArrow); + + if (getLangOpts().ObjCAutoRefCount) { + if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { + DiagnosticsEngine::Level Level = + Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, + MemberLoc); + if (Level != DiagnosticsEngine::Ignored) + getCurFunction()->recordUseOfWeak(Result); + } + } + + return Owned(Result); } // Objective-C property access. diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index b07a59b81c..501fa113ce 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -845,7 +845,8 @@ ExprResult ObjCPropertyOpBuilder::complete(Expr *SyntacticForm) { S.Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, SyntacticForm->getLocStart()); if (Level != DiagnosticsEngine::Ignored) - S.getCurFunction()->recordUseOfWeak(SyntacticRefExpr); + S.getCurFunction()->recordUseOfWeak(SyntacticRefExpr, + SyntacticRefExpr->isMessagingGetter()); } return PseudoOpBuilder::complete(SyntacticForm); diff --git a/test/SemaObjC/arc-repeated-weak.mm b/test/SemaObjC/arc-repeated-weak.mm index 728ffcb951..90ba75f6ef 100644 --- a/test/SemaObjC/arc-repeated-weak.mm +++ b/test/SemaObjC/arc-repeated-weak.mm @@ -3,6 +3,7 @@ @interface Test { @public Test *ivar; + __weak id weakIvar; } @property(weak) Test *weakProp; @property(strong) Test *strongProp; @@ -18,7 +19,7 @@ extern bool condition(); #define nil ((id)0) void sanity(Test *a) { - use(a.weakProp); // expected-warning{{weak property is accessed multiple times in this function but may be unpredictably set to nil; assign to a strong variable to keep the object alive}} + use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function but may be unpredictably set to nil; assign to a strong variable to keep the object alive}} use(a.weakProp); // expected-note{{also accessed here}} use(a.strongProp); @@ -38,11 +39,22 @@ void assignsOnly(Test *a) { id next = get(); if (next) a.weakProp = next; // no-warning + + a->weakIvar = get(); // no-warning + next = get(); + if (next) + a->weakIvar = next; // no-warning + + extern __weak id x; + x = get(); // no-warning + next = get(); + if (next) + x = next; // no-warning } void assignThenRead(Test *a) { a.weakProp = get(); // expected-note{{also accessed here}} - use(a.weakProp); // expected-warning{{weak property is accessed multiple times}} + use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} } void twoVariables(Test *a, Test *b) { @@ -51,22 +63,22 @@ void twoVariables(Test *a, Test *b) { } void doubleLevelAccess(Test *a) { - use(a.strongProp.weakProp); // expected-warning{{weak property may be accessed multiple times in this function but may be unpredictably set to nil; assign to a strong variable to keep the object alive}} + use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times in this function and may be unpredictably set to nil; assign to a strong variable to keep the object alive}} use(a.strongProp.weakProp); // expected-note{{also accessed here}} } void doubleLevelAccessIvar(Test *a) { - use(a.strongProp.weakProp); // expected-warning{{weak property may be accessed multiple times}} + use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}} use(a.strongProp.weakProp); // expected-note{{also accessed here}} } void implicitProperties(Test *a) { - use(a.implicitProp); // expected-warning{{weak property is accessed multiple times}} + use(a.implicitProp); // expected-warning{{weak implicit property 'implicitProp' is accessed multiple times}} use(a.implicitProp); // expected-note{{also accessed here}} } void classProperties() { - use(Test.weakProp); // expected-warning{{weak property is accessed multiple times}} + use(Test.weakProp); // expected-warning{{weak implicit property 'weakProp' is accessed multiple times}} use(Test.weakProp); // expected-note{{also accessed here}} } @@ -76,16 +88,38 @@ void classPropertiesAreDifferent(Test *a) { use(a.strongProp.weakProp); // no-warning } +void ivars(Test *a) { + use(a->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}} + use(a->weakIvar); // expected-note{{also accessed here}} +} + +void globals() { + extern __weak id a; + use(a); // expected-warning{{weak variable 'a' is accessed multiple times}} + use(a); // expected-note{{also accessed here}} +} + void assignToStrongWrongInit(Test *a) { id val = a.weakProp; // expected-note{{also accessed here}} - use(a.weakProp); // expected-warning{{weak property is accessed multiple times}} + use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} } void assignToStrongWrong(Test *a) { id val; val = a.weakProp; // expected-note{{also accessed here}} - use(a.weakProp); // expected-warning{{weak property is accessed multiple times}} + use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} +} + +void assignToIvarWrong(Test *a) { + a->weakIvar = get(); // expected-note{{also accessed here}} + use(a->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}} +} + +void assignToGlobalWrong() { + extern __weak id a; + a = get(); // expected-note{{also accessed here}} + use(a); // expected-warning{{weak variable 'a' is accessed multiple times}} } void assignToStrongOK(Test *a) { @@ -108,7 +142,7 @@ void testBlock(Test *a) { use(a.weakProp); // no-warning use(^{ - use(a.weakProp); // expected-warning{{weak property is accessed multiple times in this block}} + use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this block}} use(a.weakProp); // expected-note{{also accessed here}} }); } @@ -119,16 +153,24 @@ void testBlock(Test *a) { @implementation Test (Methods) - (void)sanity { - use(self.weakProp); // expected-warning{{weak property is accessed multiple times in this method but may be unpredictably set to nil; assign to a strong variable to keep the object alive}} + use(self.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this method but may be unpredictably set to nil; assign to a strong variable to keep the object alive}} use(self.weakProp); // expected-note{{also accessed here}} } +- (void)ivars { + use(weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times in this method but may be unpredictably set to nil; assign to a strong variable to keep the object alive}} + use(weakIvar); // expected-note{{also accessed here}} +} + - (void)doubleLevelAccessForSelf { - use(self.strongProp.weakProp); // expected-warning{{weak property is accessed multiple times}} + use(self.strongProp.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} use(self.strongProp.weakProp); // expected-note{{also accessed here}} - use(self->ivar.weakProp); // expected-warning{{weak property is accessed multiple times}} + use(self->ivar.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} use(self->ivar.weakProp); // expected-note{{also accessed here}} + + use(self->ivar->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}} + use(self->ivar->weakIvar); // expected-note{{also accessed here}} } - (void)distinctFromOther:(Test *)other { @@ -137,6 +179,9 @@ void testBlock(Test *a) { use(self->ivar.weakProp); // no-warning use(other->ivar.weakProp); // no-warning + + use(self.strongProp->weakIvar); // no-warning + use(other.strongProp->weakIvar); // no-warning } @end @@ -146,7 +191,7 @@ class Wrapper { public: void fields() { - use(a.weakProp); // expected-warning{{weak property is accessed multiple times in this function but may be unpredictably set to nil; assign to a strong variable to keep the object alive}} + use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function but may be unpredictably set to nil; assign to a strong variable to keep the object alive}} use(a.weakProp); // expected-note{{also accessed here}} } @@ -157,7 +202,7 @@ public: } static void doubleLevelAccessField(const Wrapper &x, const Wrapper &y) { - use(x.a.weakProp); // expected-warning{{weak property may be accessed multiple times}} + use(x.a.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}} use(y.a.weakProp); // expected-note{{also accessed here}} } }; @@ -170,7 +215,7 @@ public: // Most of these would require flow-sensitive analysis to silence correctly. void assignAfterRead(Test *a) { - if (!a.weakProp) // expected-warning{{weak property is accessed multiple times}} + if (!a.weakProp) // expected-warning{{weak property 'weakProp' is accessed multiple times}} a.weakProp = get(); // expected-note{{also accessed here}} } @@ -178,25 +223,25 @@ void assignNil(Test *a) { if (condition()) a.weakProp = nil; // expected-note{{also accessed here}} - use(a.weakProp); // expected-warning{{weak property is accessed multiple times}} + use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} } void branch(Test *a) { if (condition()) - use(a.weakProp); // expected-warning{{weak property is accessed multiple times}} + use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} else use(a.weakProp); // expected-note{{also accessed here}} } void doubleLevelAccess(Test *a, Test *b) { - use(a.strongProp.weakProp); // expected-warning{{weak property may be accessed multiple times}} + use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}} use(b.strongProp.weakProp); // expected-note{{also accessed here}} use(a.weakProp.weakProp); // no-warning } void doubleLevelAccessIvar(Test *a, Test *b) { - use(a->ivar.weakProp); // expected-warning{{weak property may be accessed multiple times}} + use(a->ivar.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}} use(b->ivar.weakProp); // expected-note{{also accessed here}} use(a.strongProp.weakProp); // no-warning -- 2.40.0