[clang][NFC] simplify the unset check in `ParseLabeledStatement` (#117430)
[llvm-project.git] / clang / test / Analysis / localization-aggressive.m
blob4da35b5b3304058b41968759feb853a01e435805
1 // RUN: %clang_cc1 -fblocks -x objective-c-header -emit-pch -o %t.pch %S/Inputs/localization-pch.h
3 // RUN: %clang_analyze_cc1 -fblocks \
4 // RUN:   -analyzer-config optin.osx.cocoa.localizability.NonLocalizedStringChecker:AggressiveReport=true \
5 // RUN:   -analyzer-checker=optin.osx.cocoa.localizability.NonLocalizedStringChecker \
6 // RUN:   -analyzer-checker=optin.osx.cocoa.localizability.EmptyLocalizationContextChecker \
7 // RUN:   -include-pch %t.pch -verify  %s
9 // These declarations were reduced using Delta-Debugging from Foundation.h
10 // on Mac OS X.
12 #define nil ((id)0)
13 #define NSLocalizedString(key, comment)                                        \
14   [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]
15 #define NSLocalizedStringFromTable(key, tbl, comment)                          \
16   [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:(tbl)]
17 #define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment)          \
18   [bundle localizedStringForKey:(key) value:@"" table:(tbl)]
19 #define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment)      \
20   [bundle localizedStringForKey:(key) value:(val) table:(tbl)]
21 #define CGFLOAT_TYPE double
22 typedef CGFLOAT_TYPE CGFloat;
23 struct CGPoint {
24   CGFloat x;
25   CGFloat y;
27 typedef struct CGPoint CGPoint;
28 @interface NSObject
29 + (id)alloc;
30 - (id)init;
31 @end
32 @class NSDictionary;
33 @interface NSString : NSObject
34 - (void)drawAtPoint:(CGPoint)point withAttributes:(NSDictionary *)attrs;
35 + (instancetype)localizedStringWithFormat:(NSString *)format, ...;
36 @end
37 @interface NSBundle : NSObject
38 + (NSBundle *)mainBundle;
39 - (NSString *)localizedStringForKey:(NSString *)key
40                               value:(NSString *)value
41                               table:(NSString *)tableName;
42 @end
43 @protocol UIAccessibility 
44 - (void)accessibilitySetIdentification:(NSString *)ident;
45 - (void)setAccessibilityLabel:(NSString *)label;
46 @end
47 @interface UILabel : NSObject <UIAccessibility>
48 @property(nullable, nonatomic, copy) NSString *text;
49 @end
50 @interface TestObject : NSObject
51 @property(strong) NSString *text;
52 @end
53 @interface NSView : NSObject
54 @property (strong) NSString *toolTip;
55 @end
56 @interface NSViewSubclass : NSView
57 @end
59 @interface LocalizationTestSuite : NSObject
60 NSString *ForceLocalized(NSString *str)
61     __attribute__((annotate("returns_localized_nsstring")));
62 CGPoint CGPointMake(CGFloat x, CGFloat y);
63 int random(void);
64 // This next one is a made up API
65 NSString *CFNumberFormatterCreateStringWithNumber(float x);
66 + (NSString *)forceLocalized:(NSString *)str
67     __attribute__((annotate("returns_localized_nsstring")));
68 + (NSString *)takesLocalizedString:
69     (NSString *)__attribute__((annotate("takes_localized_nsstring")))str;
70 @end
72 NSString *
73 takesLocalizedString(NSString *str
74                      __attribute__((annotate("takes_localized_nsstring")))) {
75   return str;
78 // Test cases begin here
79 @implementation LocalizationTestSuite
81 // A C-Funtion that returns a localized string because it has the
82 // "returns_localized_nsstring" annotation
83 NSString *ForceLocalized(NSString *str) { return str; }
84 // An ObjC method that returns a localized string because it has the
85 // "returns_localized_nsstring" annotation
86 + (NSString *)forceLocalized:(NSString *)str {
87   return str;
90 + (NSString *) takesLocalizedString:(NSString *)str { return str; }
92 // An ObjC method that returns a localized string
93 + (NSString *)unLocalizedStringMethod {
94   return @"UnlocalizedString";
97 - (void)testLocalizationErrorDetectedOnPathway {
98   UILabel *testLabel = [[UILabel alloc] init];
99   NSString *bar = NSLocalizedString(@"Hello", @"Comment");
101   if (random()) {
102     bar = @"Unlocalized string";
103   }
105   [testLabel setText:bar]; // expected-warning {{User-facing text should use localized string macro}}
108 - (void)testLocalizationErrorDetectedOnNSString {
109   NSString *bar = NSLocalizedString(@"Hello", @"Comment");
111   if (random()) {
112     bar = @"Unlocalized string";
113   }
115   [bar drawAtPoint:CGPointMake(0, 0) withAttributes:nil]; // expected-warning {{User-facing text should use localized string macro}}
118 - (void)testNoLocalizationErrorDetectedFromCFunction {
119   UILabel *testLabel = [[UILabel alloc] init];
120   NSString *bar = CFNumberFormatterCreateStringWithNumber(1);
122   [testLabel setText:bar]; // no-warning
125 - (void)testAnnotationAddsLocalizedStateForCFunction {
126   UILabel *testLabel = [[UILabel alloc] init];
127   NSString *bar = NSLocalizedString(@"Hello", @"Comment");
129   if (random()) {
130     bar = @"Unlocalized string";
131   }
133   [testLabel setText:ForceLocalized(bar)]; // no-warning
136 - (void)testAnnotationAddsLocalizedStateForObjCMethod {
137   UILabel *testLabel = [[UILabel alloc] init];
138   NSString *bar = NSLocalizedString(@"Hello", @"Comment");
140   if (random()) {
141     bar = @"Unlocalized string";
142   }
144   [testLabel setText:[LocalizationTestSuite forceLocalized:bar]]; // no-warning
147 // An empty string literal @"" should not raise an error
148 - (void)testEmptyStringLiteralHasLocalizedState {
149   UILabel *testLabel = [[UILabel alloc] init];
150   NSString *bar = @"";
152   [testLabel setText:bar]; // no-warning
155 // An empty string literal @"" inline should not raise an error
156 - (void)testInlineEmptyStringLiteralHasLocalizedState {
157   UILabel *testLabel = [[UILabel alloc] init];
158   [testLabel setText:@""]; // no-warning
161 // An string literal @"Hello" inline should raise an error
162 - (void)testInlineStringLiteralHasLocalizedState {
163   UILabel *testLabel = [[UILabel alloc] init];
164   [testLabel setText:@"Hello"]; // expected-warning {{User-facing text should use localized string macro}}
167 // A nil string should not raise an error
168 - (void)testNilStringIsNotMarkedAsUnlocalized {
169   UILabel *testLabel = [[UILabel alloc] init];
170   [testLabel setText:nil]; // no-warning
173 // A method that takes in a localized string and returns a string
174 // most likely that string is localized.
175 - (void)testLocalizedStringArgument {
176   UILabel *testLabel = [[UILabel alloc] init];
177   NSString *localizedString = NSLocalizedString(@"Hello", @"Comment");
179   NSString *combinedString =
180       [NSString localizedStringWithFormat:@"%@", localizedString];
182   [testLabel setText:combinedString]; // no-warning
185 // A String passed in as a an parameter should not be considered
186 // unlocalized
187 - (void)testLocalizedStringAsArgument:(NSString *)argumentString {
188   UILabel *testLabel = [[UILabel alloc] init];
190   [testLabel setText:argumentString]; // no-warning
193 // The warning is expected to be seen in localizedStringAsArgument: body
194 - (void)testLocalizedStringAsArgumentOtherMethod:(NSString *)argumentString {
195   [self localizedStringAsArgument:@"UnlocalizedString"];
198 // A String passed into another method that calls a method that
199 // requires a localized string should give an error
200 - (void)localizedStringAsArgument:(NSString *)argumentString {
201   UILabel *testLabel = [[UILabel alloc] init];
203   [testLabel setText:argumentString]; // expected-warning {{User-facing text should use localized string macro}}
206 // [LocalizationTestSuite unLocalizedStringMethod] returns an unlocalized string
207 // so we expect an error. Unfrtunately, it probably doesn't make a difference
208 // what [LocalizationTestSuite unLocalizedStringMethod] returns since all
209 // string values returned are marked as Unlocalized in aggressive reporting.
210 - (void)testUnLocalizedStringMethod {
211   UILabel *testLabel = [[UILabel alloc] init];
212   NSString *bar = NSLocalizedString(@"Hello", @"Comment");
214   [testLabel setText:[LocalizationTestSuite unLocalizedStringMethod]]; // expected-warning {{User-facing text should use localized string macro}}
217 // This is the reverse situation: accessibilitySetIdentification: doesn't care
218 // about localization so we don't expect a warning
219 - (void)testMethodNotInRequiresLocalizedStringMethods {
220   UILabel *testLabel = [[UILabel alloc] init];
222   [testLabel accessibilitySetIdentification:@"UnlocalizedString"]; // no-warning
225 // An NSView subclass should raise a warning for methods in NSView that 
226 // require localized strings 
227 - (void)testRequiresLocalizationMethodFromSuperclass {
228   NSViewSubclass *s = [[NSViewSubclass alloc] init];
229   NSString *bar = @"UnlocalizedString";
231   [s setToolTip:bar]; // expected-warning {{User-facing text should use localized string macro}}
234 - (void)testRequiresLocalizationMethodFromProtocol {
235   UILabel *testLabel = [[UILabel alloc] init];
237   [testLabel setAccessibilityLabel:@"UnlocalizedString"]; // expected-warning {{User-facing text should use localized string macro}}
240 // EmptyLocalizationContextChecker tests
241 #define HOM(s) YOLOC(s)
242 #define YOLOC(x) NSLocalizedString(x, nil)
244 - (void)testNilLocalizationContext {
245   NSString *string = NSLocalizedString(@"LocalizedString", nil); // expected-warning {{Localized string macro should include a non-empty comment for translators}}
246   NSString *string2 = NSLocalizedString(@"LocalizedString", nil); // expected-warning {{Localized string macro should include a non-empty comment for translators}}
247   NSString *string3 = NSLocalizedString(@"LocalizedString", nil); // expected-warning {{Localized string macro should include a non-empty comment for translators}}
250 - (void)testEmptyLocalizationContext {
251   NSString *string = NSLocalizedString(@"LocalizedString", @""); // expected-warning {{Localized string macro should include a non-empty comment for translators}}
252   NSString *string2 = NSLocalizedString(@"LocalizedString", @" "); // expected-warning {{Localized string macro should include a non-empty comment for translators}}
253   NSString *string3 = NSLocalizedString(@"LocalizedString", @"   "); // expected-warning {{Localized string macro should include a non-empty comment for translators}}
256 - (void)testNSLocalizedStringVariants {
257   NSString *string = NSLocalizedStringFromTable(@"LocalizedString", nil, @""); // expected-warning {{Localized string macro should include a non-empty comment for translators}}
258   NSString *string2 = NSLocalizedStringFromTableInBundle(@"LocalizedString", nil, [[NSBundle alloc] init],@""); // expected-warning {{Localized string macro should include a non-empty comment for translators}}
259   NSString *string3 = NSLocalizedStringWithDefaultValue(@"LocalizedString", nil, [[NSBundle alloc] init], nil,@""); // expected-warning {{Localized string macro should include a non-empty comment for translators}}
262 - (void)testMacroExpansionNilString {
263   NSString *string = YOLOC(@"Hello"); // expected-warning {{Localized string macro should include a non-empty comment for translators}}
264   NSString *string2 = HOM(@"Hello");  // expected-warning {{Localized string macro should include a non-empty comment for translators}}
265   NSString *string3 = NSLocalizedString((0 ? @"Critical" : @"Current"),nil); // expected-warning {{Localized string macro should include a non-empty comment for translators}}
268 - (void)testMacroExpansionDefinedInPCH {
269   NSString *string = MyLocalizedStringInPCH(@"Hello"); // expected-warning {{Localized string macro should include a non-empty comment for translators}}
272 #define KCLocalizedString(x,comment) NSLocalizedString(x, comment)
273 #define POSSIBLE_FALSE_POSITIVE(s,other) KCLocalizedString(s,@"Comment")
275 - (void)testNoWarningForNilCommentPassedIntoOtherMacro {
276   NSString *string = KCLocalizedString(@"Hello",@""); // no-warning
277   NSString *string2 = KCLocalizedString(@"Hello",nil); // no-warning
278   NSString *string3 = KCLocalizedString(@"Hello",@"Comment"); // no-warning
281 - (void)testPossibleFalsePositiveSituationAbove {
282   NSString *string = POSSIBLE_FALSE_POSITIVE(@"Hello", nil); // no-warning
283   NSString *string2 = POSSIBLE_FALSE_POSITIVE(@"Hello", @"Hello"); // no-warning
286 - (void)testTakesLocalizedString {
287   NSString *localized = NSLocalizedString(@"Hello", @"World");
288   NSString *alsoLocalized = [LocalizationTestSuite takesLocalizedString:localized]; // no-warning
289   NSString *stillLocalized = [LocalizationTestSuite takesLocalizedString:alsoLocalized]; // no-warning
290   takesLocalizedString(stillLocalized); // no-warning
292   [LocalizationTestSuite takesLocalizedString:@"not localized"]; // expected-warning {{User-facing text should use localized string macro}}
293   takesLocalizedString(@"not localized"); // expected-warning {{User-facing text should use localized string macro}}
295 @end
297 @interface SynthesizedAccessors : NSObject
298 @property (assign) NSObject *obj;
299 @end
301 @implementation SynthesizedAccessors
302 // no-crash
303 @end