Index: cfe/trunk/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -107,6 +107,9 @@ std::unique_ptr ExtraReleaseBugType; std::unique_ptr MistakenDeallocBugType; + static constexpr const char *MsgDeclared = "Property is declared here"; + static constexpr const char *MsgSynthesized = "Property is synthesized here"; + public: ObjCDeallocChecker(); @@ -128,6 +131,9 @@ void checkEndFunction(CheckerContext &Ctx) const; private: + void addNoteForDecl(std::unique_ptr &BR, StringRef Msg, + const Decl *D) const; + void diagnoseMissingReleases(CheckerContext &C) const; bool diagnoseExtraRelease(SymbolRef ReleasedValue, const ObjCMethodCall &M, @@ -489,6 +495,18 @@ return State; } +/// Add an extra note piece describing a declaration that is important +/// for understanding the bug report. +void ObjCDeallocChecker::addNoteForDecl(std::unique_ptr &BR, + StringRef Msg, + const Decl *D) const { + ASTContext &ACtx = D->getASTContext(); + SourceManager &SM = ACtx.getSourceManager(); + PathDiagnosticLocation Pos = PathDiagnosticLocation::createBegin(D, SM); + if (Pos.isValid() && Pos.asLocation().isValid()) + BR->addNote(Msg, Pos, D->getSourceRange()); +} + /// Report any unreleased instance variables for the current instance being /// dealloced. void ObjCDeallocChecker::diagnoseMissingReleases(CheckerContext &C) const { @@ -586,6 +604,9 @@ std::unique_ptr BR( new BugReport(*MissingReleaseBugType, OS.str(), ErrNode)); + addNoteForDecl(BR, MsgDeclared, PropDecl); + addNoteForDecl(BR, MsgSynthesized, PropImpl); + C.emitReport(std::move(BR)); } @@ -689,11 +710,12 @@ ); const ObjCImplDecl *Container = getContainingObjCImpl(C.getLocationContext()); - OS << "The '" << *PropImpl->getPropertyIvarDecl() - << "' ivar in '" << *Container; + const ObjCIvarDecl *IvarDecl = PropImpl->getPropertyIvarDecl(); + OS << "The '" << *IvarDecl << "' ivar in '" << *Container; + bool ReleasedByCIFilterDealloc = isReleasedByCIFilterDealloc(PropImpl); - if (isReleasedByCIFilterDealloc(PropImpl)) { + if (ReleasedByCIFilterDealloc) { OS << "' will be released by '-[CIFilter dealloc]' but also released here"; } else { OS << "' was synthesized for "; @@ -710,6 +732,10 @@ new BugReport(*ExtraReleaseBugType, OS.str(), ErrNode)); BR->addRange(M.getOriginExpr()->getSourceRange()); + addNoteForDecl(BR, MsgDeclared, PropDecl); + if (!ReleasedByCIFilterDealloc) + addNoteForDecl(BR, MsgSynthesized, PropImpl); + C.emitReport(std::move(BR)); return true; Index: cfe/trunk/test/Analysis/DeallocMissingRelease.m =================================================================== --- cfe/trunk/test/Analysis/DeallocMissingRelease.m +++ cfe/trunk/test/Analysis/DeallocMissingRelease.m @@ -80,6 +80,9 @@ @interface MyPropertyClass1 : NSObject @property (copy) NSObject *ivar; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @end @implementation MyPropertyClass1 @@ -93,6 +96,9 @@ @interface MyPropertyClass2 : NSObject @property (retain) NSObject *ivar; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @end @implementation MyPropertyClass2 @@ -108,10 +114,16 @@ NSObject *_ivar; } @property (retain) NSObject *ivar; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @end @implementation MyPropertyClass3 @synthesize ivar = _ivar; +#if NON_ARC +// expected-note@-2 {{Property is synthesized here}} +#endif - (void)dealloc { #if NON_ARC @@ -125,6 +137,9 @@ void (^_blockPropertyIvar)(void); } @property (copy) void (^blockProperty)(void); +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @property (copy) void (^blockProperty2)(void); @property (copy) void (^blockProperty3)(void); @@ -132,6 +147,9 @@ @implementation MyPropertyClass4 @synthesize blockProperty = _blockPropertyIvar; +#if NON_ARC +// expected-note@-2 {{Property is synthesized here}} +#endif - (void)dealloc { #if NON_ARC @@ -163,10 +181,16 @@ NSObject *_ivar; } @property (retain) NSObject *ivar; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @end @implementation MyPropertyClassWithReturnInDealloc @synthesize ivar = _ivar; +#if NON_ARC +// expected-note@-2 {{Property is synthesized here}} +#endif - (void)dealloc { return; @@ -182,12 +206,18 @@ MyPropertyClassWithReleaseInOtherInstance *_other; } @property (retain) NSObject *ivar; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif -(void)releaseIvars; @end @implementation MyPropertyClassWithReleaseInOtherInstance @synthesize ivar = _ivar; +#if NON_ARC +// expected-note@-2 {{Property is synthesized here}} +#endif -(void)releaseIvars; { #if NON_ARC @@ -208,10 +238,16 @@ NSObject *_ivar; } @property (retain) NSObject *ivar; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @end @implementation MyPropertyClassWithNeitherReturnNorSuperDealloc @synthesize ivar = _ivar; +#if NON_ARC +// expected-note@-2 {{Property is synthesized here}} +#endif - (void)dealloc { } @@ -246,6 +282,9 @@ BOOL _ivar1; } @property (retain) NSObject *ivar2; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @end @implementation ClassWithControlFlowInRelease @@ -287,6 +326,9 @@ @interface ClassWithNildOutIvar : NSObject @property (retain) NSObject *ivar; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @end @implementation ClassWithNildOutIvar @@ -305,6 +347,9 @@ @interface ClassWithUpdatedIvar : NSObject @property (retain) NSObject *ivar; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @end @implementation ClassWithUpdatedIvar @@ -349,6 +394,9 @@ @property (retain) NSObject *propNilledOutInFunction; @property (retain) NSObject *ivarNeverReleased; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif - (void)invalidateInMethod; @end @@ -425,6 +473,9 @@ @interface ClassWhereSelfEscapesViaSynthesizedPropertyAccess : NSObject @property (retain) NSObject *ivar; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @property (retain) NSObject *otherIvar; @end @@ -442,6 +493,9 @@ @interface ClassWhereSelfEscapesViaCallToSystem : NSObject @property (retain) NSObject *ivar1; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @property (retain) NSObject *ivar2; @property (retain) NSObject *ivar3; @property (retain) NSObject *ivar4; @@ -536,6 +590,9 @@ @interface SuperClassOfClassWithInlinedSuperDealloc : NSObject @property (retain) NSObject *propInSuper; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @end @implementation SuperClassOfClassWithInlinedSuperDealloc @@ -548,6 +605,9 @@ @interface ClassWithInlinedSuperDealloc : SuperClassOfClassWithInlinedSuperDealloc @property (retain) NSObject *propInSub; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @end @implementation ClassWithInlinedSuperDealloc @@ -605,6 +665,9 @@ @interface SuperClassOfClassThatEscapesBeforeInliningSuper : NSObject @property (retain) NSObject *propInSuper; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @end @implementation SuperClassOfClassThatEscapesBeforeInliningSuper @@ -794,6 +857,9 @@ @property(retain) NSObject *inputIvar; @property(retain) NSObject *nonInputIvar; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @property(retain) NSObject *inputAutoSynthesizedIvar; @property(retain) NSObject *inputExplicitlySynthesizedToNonPrefixedIvar; @property(retain) NSObject *nonPrefixedPropertyBackedByExplicitlySynthesizedPrefixedIvar; @@ -803,6 +869,9 @@ @implementation ImmediateSubCIFilter @synthesize inputIvar = inputIvar; @synthesize nonInputIvar = nonInputIvar; +#if NON_ARC +// expected-note@-2 {{Property is synthesized here}} +#endif @synthesize inputExplicitlySynthesizedToNonPrefixedIvar = notPrefixedButBackingPrefixedProperty; @synthesize nonPrefixedPropertyBackedByExplicitlySynthesizedPrefixedIvar = inputPrefixedButBackingNonPrefixedProperty; @@ -841,6 +910,9 @@ } @property(retain) NSObject *inputIvar; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @end @implementation OverreleasingCIFilter Index: cfe/trunk/test/Analysis/PR2978.m =================================================================== --- cfe/trunk/test/Analysis/PR2978.m +++ cfe/trunk/test/Analysis/PR2978.m @@ -29,22 +29,22 @@ id _nonPropertyIvar; } @property(retain) id X; -@property(retain) id Y; -@property(assign) id Z; +@property(retain) id Y; // expected-note{{Property is declared here}} +@property(assign) id Z; // expected-note{{Property is declared here}} @property(assign) id K; @property(weak) id L; @property(readonly) id N; @property(retain) id M; @property(weak) id P; -@property(weak) id Q; +@property(weak) id Q; // expected-note{{Property is declared here}} @property(retain) id R; -@property(weak, readonly) id S; +@property(weak, readonly) id S; // expected-note{{Property is declared here}} @property(assign, readonly) id T; // Shadowed in class extension @property(assign) id U; @property(retain) id V; -@property(retain) id W; +@property(retain) id W; // expected-note{{Property is declared here}} -(id) O; -(void) setO: (id) arg; @end @@ -56,16 +56,16 @@ @implementation MyClass @synthesize X = _X; -@synthesize Y = _Y; -@synthesize Z = _Z; +@synthesize Y = _Y; // expected-note{{Property is synthesized here}} +@synthesize Z = _Z; // expected-note{{Property is synthesized here}} @synthesize K = _K; @synthesize L = _L; @synthesize N = _N; @synthesize M = _M; -@synthesize Q = _Q; +@synthesize Q = _Q; // expected-note{{Property is synthesized here}} @synthesize R = _R; @synthesize V = _V; -@synthesize W = _W; +@synthesize W = _W; // expected-note{{Property is synthesized here}} -(id) O{ return 0; } -(void) setO:(id)arg { } Index: cfe/trunk/test/Analysis/properties.m =================================================================== --- cfe/trunk/test/Analysis/properties.m +++ cfe/trunk/test/Analysis/properties.m @@ -134,11 +134,17 @@ NSString *_name; } @property (retain) NSString * name; +#if !__has_feature(objc_arc) +// expected-note@-2 {{Property is declared here}} +#endif @property (assign) id friend; @end @implementation Person @synthesize name = _name; +#if !__has_feature(objc_arc) +// expected-note@-2 {{Property is synthesized here}} +#endif -(void)dealloc { #if !__has_feature(objc_arc)