Kristof Umann 3b18b050b8 [analyzer] Add a checker option to detect nested dead stores
Enables the users to specify an optional flag which would warn for more dead
stores.
Previously it ignored if the dead store happened e.g. in an if condition.

if ((X = generate())) { // dead store to X
}

This patch introduces the `WarnForDeadNestedAssignments` option to the checker,
which is `false` by default - so this change would not affect any previous
users.
I have updated the code, tests and the docs as well. If I missed something, tell
me.

I also ran the analysis on Clang which generated 14 more reports compared to the
unmodified version. All of them seemed reasonable for me.

Related previous patches:
rGf224820b45c6847b91071da8d7ade59f373b96f3

Reviewers: NoQ, krememek, Szelethus, baloghadamsoftware

Reviewed By: Szelethus

Patch by Balázs Benics!

Differential Revision: https://reviews.llvm.org/D66733

llvm-svn: 370767
2019-09-03 15:22:43 +00:00

120 lines
3.5 KiB
Objective-C

// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-checker=deadcode.DeadStores,osx.cocoa.RetainCount -fblocks -verify -Wno-objc-root-class %s
typedef signed char BOOL;
typedef unsigned int NSUInteger;
typedef struct _NSZone NSZone;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end
@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
@interface NSObject <NSObject> {} @end
extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value; @end
typedef float CGFloat;
typedef struct _NSPoint {} NSRange;
@interface NSValue (NSValueRangeExtensions) + (NSValue *)valueWithRange:(NSRange)range;
- (BOOL)containsObject:(id)anObject;
@end
@class NSURLAuthenticationChallenge;
@interface NSResponder : NSObject <NSCoding> {} @end
@class NSArray, NSDictionary, NSString;
@interface NSObject (NSKeyValueBindingCreation)
+ (void)exposeBinding:(NSString *)binding;
- (NSArray *)exposedBindings;
@end
extern NSString *NSAlignmentBinding;
// This test case was reported as a false positive due to a bug in the
// LiveVariables <-> deadcode.DeadStores interplay. We should not flag a warning
// here. The test case was reported in:
// http://lists.llvm.org/pipermail/cfe-dev/2008-July/002157.html
void DeadStoreTest(NSObject *anObject) {
NSArray *keys;
if ((keys = [anObject exposedBindings]) && // no-warning
([keys containsObject:@"name"] && [keys containsObject:@"icon"])) {}
}
// This test case was a false positive due to how clang models
// pointer types and ObjC object pointer types differently. Here
// we don't warn about a dead store because 'nil' is assigned to
// an object pointer for the sake of defensive programming.
void rdar_7631278(NSObject *x) {
x = ((void*)0);
}
// This test case issuing a bogus warning for the declaration of 'isExec'
// because the compound statement for the @synchronized was being visited
// twice by the LiveVariables analysis.
BOOL baz_rdar8527823();
void foo_rdar8527823();
@interface RDar8527823
- (void) bar_rbar8527823;
@end
@implementation RDar8527823
- (void) bar_rbar8527823
{
@synchronized(self) {
BOOL isExec = baz_rdar8527823(); // no-warning
if (isExec) foo_rdar8527823();
}
}
@end
// Don't flag dead stores to assignments to self within a nested assignment.
@interface Rdar7947686
- (id) init;
@end
@interface Rdar7947686_B : Rdar7947686
- (id) init;
@end
@implementation Rdar7947686_B
- (id) init {
id x = (self = [super init]);
// expected-warning@-1 {{Although the value stored to 'self'}}
return x;
}
@end
// Don't flag dead stores when a variable is captured in a block used
// by a property access.
@interface RDar10591355
@property (assign) int x;
@end
RDar10591355 *rdar10591355_aux();
void rdar10591355() {
RDar10591355 *p = rdar10591355_aux();
^{ (void) p.x; }();
}
@interface Radar11059352_1 {
@private
int *_pathString;
}
@property int *pathString;
@end
@interface Radar11059352 {
@private
Radar11059352_1 *_Path;
}
@end
@implementation Radar11059352
- (int*)usePath {
Radar11059352_1 *xxxxx = _Path; // no warning
int *wp = xxxxx.pathString;
return wp;
}
@end
id test_objc_precise_lifetime_foo();
void test_objc_precise_lifetime() {
__attribute__((objc_precise_lifetime)) id dead = test_objc_precise_lifetime_foo(); // no-warning
dead = 0;
dead = test_objc_precise_lifetime_foo(); // no-warning
dead = 0;
}