Skip to content

Commit

Permalink
[analyzer] Add extra notes to ObjCDeallocChecker
Browse files Browse the repository at this point in the history
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

llvm-svn: 283093
  • Loading branch information
haoNoQ committed Oct 3, 2016
1 parent 9dceb11 commit 918602d
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 12 deletions.
32 changes: 29 additions & 3 deletions clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
Expand Up @@ -107,6 +107,9 @@ class ObjCDeallocChecker
std::unique_ptr<BugType> ExtraReleaseBugType;
std::unique_ptr<BugType> MistakenDeallocBugType;

static constexpr const char *MsgDeclared = "Property is declared here";
static constexpr const char *MsgSynthesized = "Property is synthesized here";

public:
ObjCDeallocChecker();

Expand All @@ -128,6 +131,9 @@ class ObjCDeallocChecker
void checkEndFunction(CheckerContext &Ctx) const;

private:
void addNoteForDecl(std::unique_ptr<BugReport> &BR, StringRef Msg,
const Decl *D) const;

void diagnoseMissingReleases(CheckerContext &C) const;

bool diagnoseExtraRelease(SymbolRef ReleasedValue, const ObjCMethodCall &M,
Expand Down Expand Up @@ -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<BugReport> &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 {
Expand Down Expand Up @@ -586,6 +604,9 @@ void ObjCDeallocChecker::diagnoseMissingReleases(CheckerContext &C) const {
std::unique_ptr<BugReport> BR(
new BugReport(*MissingReleaseBugType, OS.str(), ErrNode));

addNoteForDecl(BR, MsgDeclared, PropDecl);
addNoteForDecl(BR, MsgSynthesized, PropImpl);

C.emitReport(std::move(BR));
}

Expand Down Expand Up @@ -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 ";
Expand All @@ -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;
Expand Down
72 changes: 72 additions & 0 deletions clang/test/Analysis/DeallocMissingRelease.m
Expand Up @@ -80,6 +80,9 @@ - (void)setIvar:(NSObject *)ivar

@interface MyPropertyClass1 : NSObject
@property (copy) NSObject *ivar;
#if NON_ARC
// expected-note@-2 {{Property is declared here}}
#endif
@end

@implementation MyPropertyClass1
Expand All @@ -93,6 +96,9 @@ - (void)dealloc

@interface MyPropertyClass2 : NSObject
@property (retain) NSObject *ivar;
#if NON_ARC
// expected-note@-2 {{Property is declared here}}
#endif
@end

@implementation MyPropertyClass2
Expand All @@ -108,10 +114,16 @@ @interface MyPropertyClass3 : NSObject {
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
Expand All @@ -125,13 +137,19 @@ @interface MyPropertyClass4 : NSObject {
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);

@end

@implementation MyPropertyClass4
@synthesize blockProperty = _blockPropertyIvar;
#if NON_ARC
// expected-note@-2 {{Property is synthesized here}}
#endif
- (void)dealloc
{
#if NON_ARC
Expand Down Expand Up @@ -163,10 +181,16 @@ @interface MyPropertyClassWithReturnInDealloc : NSObject {
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;
Expand All @@ -182,12 +206,18 @@ @interface MyPropertyClassWithReleaseInOtherInstance : NSObject {
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
Expand All @@ -208,10 +238,16 @@ @interface MyPropertyClassWithNeitherReturnNorSuperDealloc : NSObject {
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
{
}
Expand Down Expand Up @@ -246,6 +282,9 @@ @interface ClassWithControlFlowInRelease : NSObject {
BOOL _ivar1;
}
@property (retain) NSObject *ivar2;
#if NON_ARC
// expected-note@-2 {{Property is declared here}}
#endif
@end

@implementation ClassWithControlFlowInRelease
Expand Down Expand Up @@ -287,6 +326,9 @@ - (void)dealloc; {

@interface ClassWithNildOutIvar : NSObject
@property (retain) NSObject *ivar;
#if NON_ARC
// expected-note@-2 {{Property is declared here}}
#endif
@end

@implementation ClassWithNildOutIvar
Expand All @@ -305,6 +347,9 @@ - (void)dealloc; {

@interface ClassWithUpdatedIvar : NSObject
@property (retain) NSObject *ivar;
#if NON_ARC
// expected-note@-2 {{Property is declared here}}
#endif
@end

@implementation ClassWithUpdatedIvar
Expand Down Expand Up @@ -349,6 +394,9 @@ @interface ClassWithDeallocHelpers : NSObject
@property (retain) NSObject *propNilledOutInFunction;

@property (retain) NSObject *ivarNeverReleased;
#if NON_ARC
// expected-note@-2 {{Property is declared here}}
#endif
- (void)invalidateInMethod;
@end

Expand Down Expand Up @@ -425,6 +473,9 @@ - (void)dealloc; {

@interface ClassWhereSelfEscapesViaSynthesizedPropertyAccess : NSObject
@property (retain) NSObject *ivar;
#if NON_ARC
// expected-note@-2 {{Property is declared here}}
#endif
@property (retain) NSObject *otherIvar;
@end

Expand All @@ -442,6 +493,9 @@ - (void)dealloc; {

@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;
Expand Down Expand Up @@ -536,6 +590,9 @@ - (void)dealloc; {

@interface SuperClassOfClassWithInlinedSuperDealloc : NSObject
@property (retain) NSObject *propInSuper;
#if NON_ARC
// expected-note@-2 {{Property is declared here}}
#endif
@end

@implementation SuperClassOfClassWithInlinedSuperDealloc
Expand All @@ -548,6 +605,9 @@ - (void)dealloc {

@interface ClassWithInlinedSuperDealloc : SuperClassOfClassWithInlinedSuperDealloc
@property (retain) NSObject *propInSub;
#if NON_ARC
// expected-note@-2 {{Property is declared here}}
#endif
@end

@implementation ClassWithInlinedSuperDealloc
Expand Down Expand Up @@ -605,6 +665,9 @@ - (void)dealloc {

@interface SuperClassOfClassThatEscapesBeforeInliningSuper : NSObject
@property (retain) NSObject *propInSuper;
#if NON_ARC
// expected-note@-2 {{Property is declared here}}
#endif
@end

@implementation SuperClassOfClassThatEscapesBeforeInliningSuper
Expand Down Expand Up @@ -794,6 +857,9 @@ @interface ImmediateSubCIFilter : CIFilter {

@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;
Expand All @@ -803,6 +869,9 @@ @interface ImmediateSubCIFilter : CIFilter {
@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;

Expand Down Expand Up @@ -841,6 +910,9 @@ @interface OverreleasingCIFilter : CIFilter {
}

@property(retain) NSObject *inputIvar;
#if NON_ARC
// expected-note@-2 {{Property is declared here}}
#endif
@end

@implementation OverreleasingCIFilter
Expand Down
18 changes: 9 additions & 9 deletions clang/test/Analysis/PR2978.m
Expand Up @@ -29,22 +29,22 @@ @interface MyClass : NSObject {
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
Expand All @@ -56,16 +56,16 @@ @interface MyClass ()

@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 { }
Expand Down
6 changes: 6 additions & 0 deletions clang/test/Analysis/properties.m
Expand Up @@ -134,11 +134,17 @@ @interface Person : NSObject {
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)
Expand Down

0 comments on commit 918602d

Please sign in to comment.