1// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -fblocks -w -analyzer-checker=osx.NumberObjectConversion %s -verify
2// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -fblocks -w -analyzer-checker=osx.NumberObjectConversion -analyzer-config osx.NumberObjectConversion:Pedantic=true -DPEDANTIC %s -verify
3// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -fblocks -fobjc-arc -w -analyzer-checker=osx.NumberObjectConversion %s -verify
4// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -fblocks -fobjc-arc -w -analyzer-checker=osx.NumberObjectConversion -analyzer-config osx.NumberObjectConversion:Pedantic=true -DPEDANTIC %s -verify
5
6#include "Inputs/system-header-simulator-objc.h"
7
8void takes_boolean(BOOL);
9void takes_integer(int);
10
11void bad(NSNumber *p) {
12#ifdef PEDANTIC
13  if (p) {} // expected-warning{{Converting a pointer value of type 'NSNumber *' to a primitive boolean value; instead, either compare the pointer to nil or call -boolValue}}
14  if (!p) {} // expected-warning{{Converting a pointer value of type 'NSNumber *' to a primitive boolean value; instead, either compare the pointer to nil or call -boolValue}}
15  (!p) ? 1 : 2; // expected-warning{{Converting a pointer value of type 'NSNumber *' to a primitive boolean value; instead, either compare the pointer to nil or call -boolValue}}
16  if (p == 0) {} // expected-warning{{Comparing a pointer value of type 'NSNumber *' to a scalar integer value; instead, either compare the pointer to nil or compare the result of calling a method on 'NSNumber *' to get the scalar value}}
17#else
18  if (p) {} // no-warning
19  if (!p) {} // no-warning
20  (!p) ? 1 : 2; // no-warning
21  if (p == 0) {} // no-warning
22#endif
23  (BOOL)p; // expected-warning{{Converting a pointer value of type 'NSNumber *' to a primitive BOOL value; did you mean to call -boolValue?}}
24  if (p > 0) {} // expected-warning{{Comparing a pointer value of type 'NSNumber *' to a scalar integer value; did you mean to compare the result of calling a method on 'NSNumber *' to get the scalar value?}}
25  if (p == YES) {} // expected-warning{{Comparing a pointer value of type 'NSNumber *' to a primitive BOOL value; did you mean to compare the result of calling -boolValue?}}
26  if (p == NO) {} // expected-warning{{Comparing a pointer value of type 'NSNumber *' to a primitive BOOL value; did you mean to compare the result of calling -boolValue?}}
27  BOOL x = p; // expected-warning{{Converting a pointer value of type 'NSNumber *' to a primitive BOOL value; did you mean to call -boolValue?}}
28  x = p; // expected-warning{{Converting a pointer value of type 'NSNumber *' to a primitive BOOL value; did you mean to call -boolValue?}}
29  x = (p == YES); // expected-warning{{Comparing a pointer value of type 'NSNumber *' to a primitive BOOL value; did you mean to compare the result of calling -boolValue?}}
30  if (p == 1) {} // expected-warning{{Comparing a pointer value of type 'NSNumber *' to a scalar integer value; did you mean to compare the result of calling a method on 'NSNumber *' to get the scalar value?}}
31  int y = p; // expected-warning{{Converting a pointer value of type 'NSNumber *' to a scalar integer value; did you mean to call a method on 'NSNumber *' to get the scalar value?}}
32  y = p; // expected-warning{{Converting a pointer value of type 'NSNumber *' to a scalar integer value; did you mean to call a method on 'NSNumber *' to get the scalar value?}}
33  takes_boolean(p); // expected-warning{{Converting a pointer value of type 'NSNumber *' to a primitive BOOL value; did you mean to call -boolValue?}}
34  takes_integer(p); // expected-warning{{Converting a pointer value of type 'NSNumber *' to a scalar integer value; did you mean to call a method on 'NSNumber *' to get the scalar value?}}
35  takes_boolean(x); // no-warning
36  takes_integer(y); // no-warning
37}
38
39typedef NSNumber *SugaredNumber;
40void bad_sugared(SugaredNumber p) {
41  p == YES; // expected-warning{{Comparing a pointer value of type 'SugaredNumber' to a primitive BOOL value; did you mean to compare the result of calling -boolValue?}}
42}
43
44@interface I : NSObject {
45@public
46  NSNumber *ivar;
47  NSNumber *prop;
48}
49- (NSNumber *)foo;
50@property(copy) NSNumber *prop;
51@end
52
53@implementation I
54@synthesize prop;
55@end
56
57void bad_ivar(I *i) {
58  i->ivar == YES; // expected-warning{{Comparing a pointer value of type 'NSNumber *' to a primitive BOOL value; did you mean to compare the result of calling -boolValue?}}
59  i->prop == YES; // expected-warning{{Comparing a pointer value of type 'NSNumber *' to a primitive BOOL value; did you mean to compare the result of calling -boolValue?}}
60  [i foo] == YES; // expected-warning{{Comparing a pointer value of type 'NSNumber *' to a primitive BOOL value; did you mean to compare the result of calling -boolValue?}}
61}
62
63void good(NSNumber *p) {
64  if ([p boolValue] == NO) {} // no-warning
65  if ([p boolValue] == YES) {} // no-warning
66  BOOL x = [p boolValue]; // no-warning
67}
68
69void suppression(NSNumber *p) {
70  if (p == NULL) {} // no-warning
71  if (p == nil) {} // no-warning
72}
73
74// Conversion of a pointer to an intptr_t is fine.
75typedef long intptr_t;
76typedef unsigned long uintptr_t;
77typedef long fintptr_t; // Fake, for testing the regex.
78void test_intptr_t(NSNumber *p) {
79  (long)p; // expected-warning{{Converting a pointer value of type 'NSNumber *' to a scalar integer value; did you mean to call a method on 'NSNumber *' to get the scalar value?}}
80  (intptr_t)p; // no-warning
81  (unsigned long)p; // expected-warning{{Converting a pointer value of type 'NSNumber *' to a scalar integer value; did you mean to call a method on 'NSNumber *' to get the scalar value?}}
82  (uintptr_t)p; // no-warning
83  (fintptr_t)p; // expected-warning{{Converting a pointer value of type 'NSNumber *' to a scalar integer value; did you mean to call a method on 'NSNumber *' to get the scalar value?}}
84}
85
86// Test macro suppressions.
87#define FOO 0
88#define BAR 1
89void test_macro(NSNumber *p) {
90  if (p != BAR) {} // expected-warning{{Comparing a pointer value of type 'NSNumber *' to a scalar integer value; did you mean to compare the result of calling a method on 'NSNumber *' to get the scalar value?}}
91#ifdef PEDANTIC
92  if (p != FOO) {} // expected-warning{{Comparing a pointer value of type 'NSNumber *' to a scalar integer value; instead, either compare the pointer to nil or compare the result of calling a method on 'NSNumber *' to get the scalar value}}
93#else
94  if (p != FOO) {} // no-warning
95#endif
96}
97
98#define NULL_INSIDE_MACRO NULL
99void test_NULL_inside_macro(NSNumber *p) {
100#ifdef PEDANTIC
101  if (p == NULL_INSIDE_MACRO) {} // no-warning
102#else
103  if (p == NULL_INSIDE_MACRO) {} // no-warning
104#endif
105}
106
107// Test a different definition of NULL.
108#undef NULL
109#define NULL 0
110void test_non_pointer_NULL(NSNumber *p) {
111  if (p == NULL) {} // no-warning
112}
113