1// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
2
3// Nullability of const string-like globals, testing
4// NonnullGlobalConstantsChecker.
5
6void clang_analyzer_eval(bool);
7
8@class NSString;
9typedef const struct __CFString *CFStringRef;
10typedef const struct __CFBoolean *CFBooleanRef;
11
12#define CF_BRIDGED_TYPE(T) __attribute__((objc_bridge(T)))
13typedef const struct CF_BRIDGED_TYPE(NSNull) __CFNull *CFNullRef;
14extern const CFNullRef kCFNull;
15
16// Global NSString* is non-null.
17extern NSString *const StringConstGlobal;
18void stringConstGlobal() {
19  clang_analyzer_eval(StringConstGlobal); // expected-warning{{TRUE}}
20}
21
22// The logic does not apply to local variables though.
23extern NSString *stringGetter();
24void stringConstLocal() {
25  NSString *const local = stringGetter();
26  clang_analyzer_eval(local); // expected-warning{{UNKNOWN}}
27}
28
29// Global const CFStringRef's are also assumed to be non-null.
30extern const CFStringRef CFStringConstGlobal;
31void cfStringCheckGlobal() {
32  clang_analyzer_eval(CFStringConstGlobal); // expected-warning{{TRUE}}
33}
34
35// But only "const" ones.
36extern CFStringRef CFStringNonConstGlobal;
37void cfStringCheckMutableGlobal() {
38  clang_analyzer_eval(CFStringNonConstGlobal); // expected-warning{{UNKNOWN}}
39}
40
41// char* const is also assumed to be non-null.
42extern const char *const ConstCharStarConst;
43void constCharStarCheckGlobal() {
44  clang_analyzer_eval(ConstCharStarConst); // expected-warning{{TRUE}}
45}
46
47// Pointer value can be mutable.
48extern char *const CharStarConst;
49void charStarCheckGlobal() {
50  clang_analyzer_eval(CharStarConst); // expected-warning{{TRUE}}
51}
52
53// But the pointer itself should be immutable.
54extern char *CharStar;
55void charStartCheckMutableGlobal() {
56  clang_analyzer_eval(CharStar); // expected-warning{{UNKNOWN}}
57}
58
59// Type definitions should also work across typedefs, for pointers:
60typedef char *const str;
61extern str globalStr;
62void charStarCheckTypedef() {
63  clang_analyzer_eval(globalStr); // expected-warning{{TRUE}}
64}
65
66// And for types.
67typedef NSString *const NStr;
68extern NStr globalNSString;
69void NSStringCheckTypedef() {
70  clang_analyzer_eval(globalNSString); // expected-warning{{TRUE}}
71}
72
73// Note that constness could be either inside
74// the var declaration, or in a typedef.
75typedef NSString *NStr2;
76extern const NStr2 globalNSString2;
77void NSStringCheckConstTypedef() {
78  clang_analyzer_eval(globalNSString2); // expected-warning{{TRUE}}
79}
80
81// Nested typedefs should work as well.
82typedef const CFStringRef str1;
83typedef str1 str2;
84extern str2 globalStr2;
85void testNestedTypedefs() {
86  clang_analyzer_eval(globalStr2); // expected-warning{{TRUE}}
87}
88
89// And for NSString *.
90typedef NSString *const nstr1;
91typedef nstr1 nstr2;
92extern nstr2 nglobalStr2;
93void testNestedTypedefsForNSString() {
94  clang_analyzer_eval(nglobalStr2); // expected-warning{{TRUE}}
95}
96
97// And for CFBooleanRefs.
98extern const CFBooleanRef kBool;
99void testNonnullBool() {
100  clang_analyzer_eval(kBool); // expected-warning{{TRUE}}
101}
102
103// And again, only for const one.
104extern CFBooleanRef kBoolMutable;
105void testNonnullNonconstBool() {
106  clang_analyzer_eval(kBoolMutable); // expected-warning{{UNKNOWN}}
107}
108
109// If it's annotated as nonnull, it doesn't even need to be const.
110extern CFStringRef _Nonnull str3;
111void testNonnullNonconstCFString() {
112  clang_analyzer_eval(str3); // expected-warning{{TRUE}}
113}
114
115// This one's nonnull for two reasons.
116extern const CFStringRef _Nonnull str4;
117void testNonnullNonnullCFString() {
118  clang_analyzer_eval(str4); // expected-warning{{TRUE}}
119}
120
121void test_kCFNull() {
122  clang_analyzer_eval(kCFNull); // expected-warning{{TRUE}}
123}
124