summaryrefslogtreecommitdiffstats
path: root/test/SemaObjC/unguarded-availability.m
blob: 39c631097985bd8dce5828b7b2204ecdd7edcaba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
// RUN: %clang_cc1 -triple x86_64-apple-macosx-10.9 -Wunguarded-availability -fblocks -fsyntax-only -verify %s
// RUN: %clang_cc1 -xobjective-c++ -std=c++11 -DOBJCPP -triple x86_64-apple-macosx-10.9 -Wunguarded-availability -fblocks -fsyntax-only -verify %s

#define AVAILABLE_10_0  __attribute__((availability(macos, introduced = 10.0)))
#define AVAILABLE_10_11 __attribute__((availability(macos, introduced = 10.11)))
#define AVAILABLE_10_12 __attribute__((availability(macos, introduced = 10.12)))

typedef int AVAILABLE_10_12 new_int; // expected-note + {{marked partial here}}

int func_10_11() AVAILABLE_10_11; // expected-note 8 {{'func_10_11' has been explicitly marked partial here}}

#ifdef OBJCPP
// expected-note@+2 6 {{marked partial here}}
#endif
int func_10_12() AVAILABLE_10_12; // expected-note 7 {{'func_10_12' has been explicitly marked partial here}}

int func_10_0() AVAILABLE_10_0;

void use_func() {
  func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}

  if (@available(macos 10.11, *))
    func_10_11();
  else
    func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
}

void defn_10_11() AVAILABLE_10_11;

void defn_10_11() {
  func_10_11();
}

void nested_ifs() {
  if (@available(macos 10.12, *)) {
    if (@available(macos 10.10, *)) {
      func_10_12();
    } else {
      func_10_12();
    }
  } else {
    func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{enclose 'func_10_12' in an @available check to silence this warning}}
  }
}

void star_case() {
  if (@available(ios 9, *)) {
    func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
    func_10_0();
  } else
    func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}

  if (@available(macOS 10.11, *)) {
    if (@available(ios 8, *)) {
      func_10_11();
      func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{enclose}}
    } else {
      func_10_11();
      func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{enclose}}
    }
  }
}

typedef int int_10_11 AVAILABLE_10_11; // expected-note {{'int_10_11' has been explicitly marked partial here}}
#ifdef OBJCPP
// expected-note@+2 {{marked partial here}}
#endif
typedef int int_10_12 AVAILABLE_10_12; // expected-note 2 {{'int_10_12' has been explicitly marked partial here}}

void use_typedef() {
  int_10_11 x; // expected-warning{{'int_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'int_10_11' in an @available check to silence this warning}}
}

__attribute__((objc_root_class))
AVAILABLE_10_11 @interface Class_10_11 { // expected-note{{annotate 'Class_10_11' with an availability attribute to silence}}
  int_10_11 foo;
  int_10_12 bar; // expected-warning {{'int_10_12' is only available on macOS 10.12 or newer}}
}
- (void)method1;
- (void)method2;
@end

@implementation Class_10_11
- (void) method1 {
  func_10_11();
  func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{enclose 'func_10_12' in an @available check to silence this warning}}
}

- (void)method2 AVAILABLE_10_12 {
  func_10_12();
}

@end

int protected_scope() {
  if (@available(macos 10.20, *)) { // expected-note 2 {{jump enters controlled statement of if available}}
  label1:
    return 0;
  } else {
  label2:
    goto label1; // expected-error{{cannot jump from this goto statement to its label}}
  }

  goto label2; // expected-error{{cannot jump from this goto statement to its label}}
}

struct S {
  int m1;
  int m2 __attribute__((availability(macos, introduced = 10.12))); // expected-note{{marked partial here}}

  struct Nested {
    int nested_member __attribute__((availability(macos, introduced = 10.12))); // expected-note{{marked partial here}}
  } n;
};

int test_members() {
  struct S s;
  (void)s.m1;
  (void)s.m2; // expected-warning{{'m2' is only available on macOS 10.12 or newer}} expected-note{{@available}}

  (void)s.n.nested_member; // expected-warning{{'nested_member' is only available on macOS 10.12 or newer}} expected-note{{@available}}
}

void test_blocks() {
  (void) ^{
    func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
  };
}

void test_params(int_10_12 x); // expected-warning {{'int_10_12' is only available on macOS 10.12 or newer}} expected-note{{annotate 'test_params' with an availability attribute to silence this warning}}

void test_params2(int_10_12 x) AVAILABLE_10_12; // no warn

void (^topLevelBlockDecl)() = ^ {
  func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
  if (@available(macos 10.12, *))
    func_10_12();
};

AVAILABLE_10_12
__attribute__((objc_root_class))
@interface InterWithProp // expected-note 2 {{marked partial here}}
@property(class) int x;
+ (void) setX: (int)newX AVAILABLE_10_12; // expected-note{{marked partial here}}
@end
void test_property(void) {
  int y = InterWithProp.x; // expected-warning{{'InterWithProp' is only available on macOS 10.12 or newer}} expected-note{{@available}}
  InterWithProp.x = y; // expected-warning{{'InterWithProp' is only available on macOS 10.12 or newer}} expected-note{{@available}} expected-warning{{'setX:' is only available on macOS 10.12 or newer}} expected-note{{@available}}
}

__attribute__((objc_root_class))
@interface Subscriptable
- (id)objectAtIndexedSubscript:(int)sub AVAILABLE_10_12; // expected-note{{marked partial here}}
@end

void test_at(Subscriptable *x) {
  id y = x[42]; // expected-warning{{'objectAtIndexedSubscript:' is only available on macOS 10.12 or newer}} expected-note{{@available}}
}

void uncheckAtAvailable() {
  if (@available(macOS 10.12, *) || 0) // expected-warning {{@available does not guard availability here; use if (@available) instead}}
    func_10_12(); // expected-warning {{'func_10_12' is only available on macOS 10.12 or newer}}
  // expected-note@-1 {{enclose 'func_10_12' in an @available check to silence this warning}}
}

void justAtAvailable() {
  int availability = @available(macOS 10.12, *); // expected-warning {{@available does not guard availability here; use if (@available) instead}}
}

#ifdef OBJCPP

int f(char) AVAILABLE_10_12;
int f(int);

template <class T> int use_f() {
  // FIXME: We should warn here!
  return f(T());
}

int a = use_f<int>();
int b = use_f<char>();

template <class> int use_at_available() {
  if (@available(macos 10.12, *))
    return func_10_12();
  else
    return func_10_12(); // expected-warning {{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{enclose}}
}

int instantiate_template() {
  if (@available(macos 10.12, *)) {
    use_at_available<char>();
  } else {
    use_at_available<float>();
  }
}

template <class>
int with_availability_attr() AVAILABLE_10_11 { // expected-note 2 {{marked partial here}}
  return 0;
}

int instantiate_with_availability_attr() {
  if (@available(macos 10.12, *))
    with_availability_attr<char>();
  else
    with_availability_attr<int>(); // expected-warning {{'with_availability_attr<int>' is only available on macOS 10.11 or newer}} expected-note {{enclose}}
}

int instantiate_availability() {
  if (@available(macOS 10.12, *))
    with_availability_attr<int_10_12>();
  else
    with_availability_attr<int_10_12>(); // expected-warning{{'with_availability_attr<int>' is only available on macOS 10.11 or newer}} expected-warning{{'int_10_12' is only available on macOS 10.12 or newer}} expected-note 2 {{enclose}}
}

auto topLevelLambda = [] () {
  func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
  if (@available(macos 10.12, *))
    func_10_12();
};

void functionInFunction() {
  func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
  struct DontWarnTwice {
    void f() {
      func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
    }
  };
  void([] () {
    func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
  });
  (void)(^ {
    func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
  });
}

#endif

struct InStruct { // expected-note{{annotate 'InStruct' with an availability attribute to silence}}
  new_int mem; // expected-warning{{'new_int' is only available on macOS 10.12 or newer}}

  struct { new_int mem; } anon; // expected-warning{{'new_int' is only available on macOS 10.12 or newer}} expected-note{{annotate anonymous struct with an availability attribute to silence}}
};

#ifdef OBJCPP
static constexpr int AVAILABLE_10_12 SomeConstexprValue = 2; // expected-note{{marked partial here}}
typedef enum { // expected-note{{annotate anonymous enum with an availability attribute}}
  SomeValue = SomeConstexprValue // expected-warning{{'SomeConstexprValue' is only available on macOS 10.12 or newer}} 
} SomeEnum;
#endif

@interface InInterface
-(new_int)meth; // expected-warning{{'new_int' is only available on macOS 10.12 or newer}} expected-note{{annotate 'meth' with an availability attribute}}
@end

@interface Proper // expected-note{{annotate 'Proper' with an availability attribute}}
@property (class) new_int x; // expected-warning{{'new_int' is only available}}
@end

void with_local_struct() {
  struct local { // expected-note{{annotate 'local' with an availability attribute}}
    new_int x; // expected-warning{{'new_int' is only available}}
  };
}

// rdar://33156429:
// Avoid the warning on protocol requirements.

AVAILABLE_10_12
@protocol NewProtocol // expected-note {{'NewProtocol' has been explicitly marked partial here}}
@end

@protocol ProtocolWithNewProtocolRequirement <NewProtocol> // expected-note {{annotate 'ProtocolWithNewProtocolRequirement' with an availability attribute to silence}}

@property(copy) id<NewProtocol> prop; // expected-warning {{'NewProtocol' is only available on macOS 10.12 or newer}}

@end

@interface BaseClass
@end

@interface ClassWithNewProtocolRequirement : BaseClass <NewProtocol>

@end

@interface BaseClass (CategoryWithNewProtocolRequirement) <NewProtocol>

@end

typedef enum {
  AK_Dodo __attribute__((availability(macos, deprecated=10.3))), // expected-note 3 {{marked deprecated here}}
  AK_Cat __attribute__((availability(macos, introduced=10.4))),
  AK_CyborgCat __attribute__((availability(macos, introduced=10.12))), // expected-note {{marked partial here}}
} Animals;

void switchAnimals(Animals a) {
  switch (a) {
  case AK_Dodo: break; // expected-warning{{'AK_Dodo' is deprecated}}
  case AK_Cat: break;
  case AK_Cat|AK_CyborgCat: break; // expected-warning{{case value not in enum}}
  case AK_CyborgCat: break; // no warn
  }

  switch (a) {
  case AK_Dodo...AK_CyborgCat: // expected-warning {{'AK_Dodo' is depr}}
    break;
  }

  (void)AK_Dodo; // expected-warning{{'AK_Dodo' is deprecated}}
  (void)AK_Cat; // no warning
  (void)AK_CyborgCat; // expected-warning{{'AK_CyborgCat' is only available on macOS 10.12 or newer}} expected-note {{@available}}
}


// test static initializers has the same availability as the deployment target and it cannot be overwritten.
@interface HasStaticInitializer : BaseClass
+ (void)load AVAILABLE_10_11; // expected-warning{{ignoring availability attribute on '+load' method}}
@end

@implementation HasStaticInitializer
+ (void)load {
  func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
}
@end

// test availability from interface is ignored when checking the unguarded availability in +load method.
AVAILABLE_10_11
@interface HasStaticInitializer1 : BaseClass
+ (void)load;
+ (void)load: (int)x; // no warning.
@end

@implementation HasStaticInitializer1
+ (void)load {
  func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
}
+ (void)load: (int)x {
  func_10_11(); // no warning.
}
@end

__attribute__((constructor))
void is_constructor();

AVAILABLE_10_11 // expected-warning{{ignoring availability attribute with constructor attribute}}
void is_constructor() {
  func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
}

AVAILABLE_10_11 // expected-warning{{ignoring availability attribute with destructor attribute}}
__attribute__((destructor))
void is_destructor() {
  func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
}