// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s // Nullability of const string-like globals, testing // NonnullGlobalConstantsChecker. void clang_analyzer_eval(bool); @class NSString; typedef const struct __CFString *CFStringRef; typedef const struct __CFBoolean *CFBooleanRef; #define CF_BRIDGED_TYPE(T) __attribute__((objc_bridge(T))) typedef const struct CF_BRIDGED_TYPE(NSNull) __CFNull *CFNullRef; extern const CFNullRef kCFNull; // Global NSString* is non-null. extern NSString *const StringConstGlobal; void stringConstGlobal() { clang_analyzer_eval(StringConstGlobal); // expected-warning{{TRUE}} } // The logic does not apply to local variables though. extern NSString *stringGetter(); void stringConstLocal() { NSString *const local = stringGetter(); clang_analyzer_eval(local); // expected-warning{{UNKNOWN}} } // Global const CFStringRef's are also assumed to be non-null. extern const CFStringRef CFStringConstGlobal; void cfStringCheckGlobal() { clang_analyzer_eval(CFStringConstGlobal); // expected-warning{{TRUE}} } // But only "const" ones. extern CFStringRef CFStringNonConstGlobal; void cfStringCheckMutableGlobal() { clang_analyzer_eval(CFStringNonConstGlobal); // expected-warning{{UNKNOWN}} } // char* const is also assumed to be non-null. extern const char *const ConstCharStarConst; void constCharStarCheckGlobal() { clang_analyzer_eval(ConstCharStarConst); // expected-warning{{TRUE}} } // Pointer value can be mutable. extern char *const CharStarConst; void charStarCheckGlobal() { clang_analyzer_eval(CharStarConst); // expected-warning{{TRUE}} } // But the pointer itself should be immutable. extern char *CharStar; void charStartCheckMutableGlobal() { clang_analyzer_eval(CharStar); // expected-warning{{UNKNOWN}} } // Type definitions should also work across typedefs, for pointers: typedef char *const str; extern str globalStr; void charStarCheckTypedef() { clang_analyzer_eval(globalStr); // expected-warning{{TRUE}} } // And for types. typedef NSString *const NStr; extern NStr globalNSString; void NSStringCheckTypedef() { clang_analyzer_eval(globalNSString); // expected-warning{{TRUE}} } // Note that constness could be either inside // the var declaration, or in a typedef. typedef NSString *NStr2; extern const NStr2 globalNSString2; void NSStringCheckConstTypedef() { clang_analyzer_eval(globalNSString2); // expected-warning{{TRUE}} } // Nested typedefs should work as well. typedef const CFStringRef str1; typedef str1 str2; extern str2 globalStr2; void testNestedTypedefs() { clang_analyzer_eval(globalStr2); // expected-warning{{TRUE}} } // And for NSString *. typedef NSString *const nstr1; typedef nstr1 nstr2; extern nstr2 nglobalStr2; void testNestedTypedefsForNSString() { clang_analyzer_eval(nglobalStr2); // expected-warning{{TRUE}} } // And for CFBooleanRefs. extern const CFBooleanRef kBool; void testNonnullBool() { clang_analyzer_eval(kBool); // expected-warning{{TRUE}} } // And again, only for const one. extern CFBooleanRef kBoolMutable; void testNonnullNonconstBool() { clang_analyzer_eval(kBoolMutable); // expected-warning{{UNKNOWN}} } // If it's annotated as nonnull, it doesn't even need to be const. extern CFStringRef _Nonnull str3; void testNonnullNonconstCFString() { clang_analyzer_eval(str3); // expected-warning{{TRUE}} } // This one's nonnull for two reasons. extern const CFStringRef _Nonnull str4; void testNonnullNonnullCFString() { clang_analyzer_eval(str4); // expected-warning{{TRUE}} } void test_kCFNull() { clang_analyzer_eval(kCFNull); // expected-warning{{TRUE}} }