From: Artem Dergachev Date: Mon, 3 Oct 2016 08:03:51 +0000 (+0000) Subject: [analyzer] Add extra notes to ObjCDeallocChecker X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=23eb5dbf9c59b3422a9484c752e07f588402223a;p=clang [analyzer] Add extra notes to ObjCDeallocChecker The report is now highlighting instance variables and properties referenced by the warning message with the help of the extra notes feature recently introduced in r283092. Differential Revision: https://reviews.llvm.org/D24915 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@283093 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index ffb0adc8d6..8fd36b8286 100644 --- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -107,6 +107,9 @@ class ObjCDeallocChecker 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 @@ public: 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 @@ ProgramStateRef ObjCDeallocChecker::checkPointerEscape( 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 @@ void ObjCDeallocChecker::diagnoseMissingReleases(CheckerContext &C) const { 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 @@ bool ObjCDeallocChecker::diagnoseExtraRelease(SymbolRef ReleasedValue, ); 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 @@ bool ObjCDeallocChecker::diagnoseExtraRelease(SymbolRef ReleasedValue, 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; diff --git a/test/Analysis/DeallocMissingRelease.m b/test/Analysis/DeallocMissingRelease.m index 009e801518..224f44c1d1 100644 --- a/test/Analysis/DeallocMissingRelease.m +++ b/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 @@ void NilOutPropertyHelper(ClassWithDeallocHelpers *o) { @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 @@ void NilOutPropertyHelper(ClassWithDeallocHelpers *o) { @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 @@ void ReleaseMe(id arg); @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 @@ void ReleaseMe(id arg); @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 @@ void ReleaseMe(id arg); @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 @@ __attribute__((objc_root_class)) @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 @@ __attribute__((objc_root_class)) @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 @@ __attribute__((objc_root_class)) } @property(retain) NSObject *inputIvar; +#if NON_ARC +// expected-note@-2 {{Property is declared here}} +#endif @end @implementation OverreleasingCIFilter diff --git a/test/Analysis/PR2978.m b/test/Analysis/PR2978.m index b609da5aac..379fe6c047 100644 --- a/test/Analysis/PR2978.m +++ b/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 { } diff --git a/test/Analysis/properties.m b/test/Analysis/properties.m index b1305341e5..55ea2c10be 100644 --- a/test/Analysis/properties.m +++ b/test/Analysis/properties.m @@ -134,11 +134,17 @@ NSNumber* numberFromMyNumberProperty(MyNumber* aMyNumber) 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)