Coverage Report

Created: 2020-02-15 09:57

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Sema/SemaAvailability.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- SemaAvailability.cpp - Availability attribute handling -----------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
//  This file processes the availability attribute.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/AST/Attr.h"
14
#include "clang/AST/Decl.h"
15
#include "clang/AST/RecursiveASTVisitor.h"
16
#include "clang/Basic/DiagnosticSema.h"
17
#include "clang/Lex/Preprocessor.h"
18
#include "clang/Sema/DelayedDiagnostic.h"
19
#include "clang/Sema/ScopeInfo.h"
20
#include "clang/Sema/Sema.h"
21
22
using namespace clang;
23
using namespace sema;
24
25
static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
26
537k
                                                  const Decl *D) {
27
537k
  // Check each AvailabilityAttr to find the one for this platform.
28
595k
  for (const auto *A : D->attrs()) {
29
595k
    if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
30
525k
      // FIXME: this is copied from CheckAvailability. We should try to
31
525k
      // de-duplicate.
32
525k
33
525k
      // Check if this is an App Extension "platform", and if so chop off
34
525k
      // the suffix for matching with the actual platform.
35
525k
      StringRef ActualPlatform = Avail->getPlatform()->getName();
36
525k
      StringRef RealizedPlatform = ActualPlatform;
37
525k
      if (Context.getLangOpts().AppExt) {
38
48
        size_t suffix = RealizedPlatform.rfind("_app_extension");
39
48
        if (suffix != StringRef::npos)
40
32
          RealizedPlatform = RealizedPlatform.slice(0, suffix);
41
48
      }
42
525k
43
525k
      StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
44
525k
45
525k
      // Match the platform name.
46
525k
      if (RealizedPlatform == TargetPlatform)
47
525k
        return Avail;
48
525k
    }
49
595k
  }
50
537k
  
return nullptr12.2k
;
51
537k
}
52
53
/// The diagnostic we should emit for \c D, and the declaration that
54
/// originated it, or \c AR_Available.
55
///
56
/// \param D The declaration to check.
57
/// \param Message If non-null, this will be populated with the message from
58
/// the availability attribute that is selected.
59
/// \param ClassReceiver If we're checking the the method of a class message
60
/// send, the class. Otherwise nullptr.
61
static std::pair<AvailabilityResult, const NamedDecl *>
62
ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,
63
                                 std::string *Message,
64
49.4M
                                 ObjCInterfaceDecl *ClassReceiver) {
65
49.4M
  AvailabilityResult Result = D->getAvailability(Message);
66
49.4M
67
49.4M
  // For typedefs, if the typedef declaration appears available look
68
49.4M
  // to the underlying type to see if it is more restrictive.
69
50.8M
  while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
70
22.4M
    if (Result == AR_Available) {
71
22.1M
      if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) {
72
1.44M
        D = TT->getDecl();
73
1.44M
        Result = D->getAvailability(Message);
74
1.44M
        continue;
75
1.44M
      }
76
21.0M
    }
77
21.0M
    break;
78
21.0M
  }
79
49.4M
80
49.4M
  // Forward class declarations get their attributes from their definition.
81
49.4M
  if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
82
1.54M
    if (IDecl->getDefinition()) {
83
1.40M
      D = IDecl->getDefinition();
84
1.40M
      Result = D->getAvailability(Message);
85
1.40M
    }
86
1.54M
  }
87
49.4M
88
49.4M
  if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
89
484k
    if (Result == AR_Available) {
90
483k
      const DeclContext *DC = ECD->getDeclContext();
91
483k
      if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
92
483k
        Result = TheEnumDecl->getAvailability(Message);
93
483k
        D = TheEnumDecl;
94
483k
      }
95
483k
    }
96
49.4M
97
49.4M
  // For +new, infer availability from -init.
98
49.4M
  if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
99
23.2k
    if (S.NSAPIObj && ClassReceiver) {
100
7.47k
      ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod(
101
7.47k
          S.NSAPIObj->getInitSelector());
102
7.47k
      if (Init && 
Result == AR_Available5.52k
&&
MD->isClassMethod()5.45k
&&
103
7.47k
          
MD->getSelector() == S.NSAPIObj->getNewSelector()5.40k
&&
104
7.47k
          
MD->definedInNSObject(S.getASTContext())230
) {
105
222
        Result = Init->getAvailability(Message);
106
222
        D = Init;
107
222
      }
108
7.47k
    }
109
23.2k
  }
110
49.4M
111
49.4M
  return {Result, D};
112
49.4M
}
113
114
115
/// whether we should emit a diagnostic for \c K and \c DeclVersion in
116
/// the context of \c Ctx. For example, we should emit an unavailable diagnostic
117
/// in a deprecated context, but not the other way around.
118
static bool
119
ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K,
120
                                    VersionTuple DeclVersion, Decl *Ctx,
121
442k
                                    const NamedDecl *OffendingDecl) {
122
442k
  assert(K != AR_Available && "Expected an unavailable declaration here!");
123
442k
124
442k
  // Checks if we should emit the availability diagnostic in the context of C.
125
712k
  auto CheckContext = [&](const Decl *C) {
126
712k
    if (K == AR_NotYetIntroduced) {
127
537
      if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C))
128
40
        if (AA->getIntroduced() >= DeclVersion)
129
26
          return true;
130
711k
    } else if (K == AR_Deprecated) {
131
677k
      if (C->isDeprecated())
132
365k
        return true;
133
34.1k
    } else if (K == AR_Unavailable) {
134
34.1k
      // It is perfectly fine to refer to an 'unavailable' Objective-C method
135
34.1k
      // when it is referenced from within the @implementation itself. In this
136
34.1k
      // context, we interpret unavailable as a form of access control.
137
34.1k
      if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) {
138
501
        if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) {
139
71
          if (MD->getClassInterface() == Impl->getClassInterface())
140
8
            return true;
141
346k
        }
142
501
      }
143
34.1k
    }
144
346k
145
346k
    if (C->isUnavailable())
146
29.6k
      return true;
147
317k
    return false;
148
317k
  };
149
442k
150
712k
  do {
151
712k
    if (CheckContext(Ctx))
152
395k
      return false;
153
316k
154
316k
    // An implementation implicitly has the availability of the interface.
155
316k
    // Unless it is "+load" method.
156
316k
    if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx))
157
3.73k
      if (MethodD->isClassMethod() &&
158
3.73k
          
MethodD->getSelector().getAsString() == "load"1.17k
)
159
4
        return true;
160
316k
161
316k
    if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) {
162
167
      if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface())
163
167
        if (CheckContext(Interface))
164
19
          return false;
165
316k
    }
166
316k
    // A category implicitly has the availability of the interface.
167
316k
    else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx))
168
15
      if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface())
169
7
        if (CheckContext(Interface))
170
4
          return false;
171
316k
  } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext())));
172
442k
173
442k
  
return true47.4k
;
174
442k
}
175
176
static bool
177
shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
178
                                    const VersionTuple &DeploymentVersion,
179
215
                                    const VersionTuple &DeclVersion) {
180
215
  const auto &Triple = Context.getTargetInfo().getTriple();
181
215
  VersionTuple ForceAvailabilityFromVersion;
182
215
  switch (Triple.getOS()) {
183
38
  case llvm::Triple::IOS:
184
38
  case llvm::Triple::TvOS:
185
38
    ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11);
186
38
    break;
187
38
  case llvm::Triple::WatchOS:
188
7
    ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4);
189
7
    break;
190
169
  case llvm::Triple::Darwin:
191
169
  case llvm::Triple::MacOSX:
192
169
    ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
193
169
    break;
194
169
  default:
195
1
    // New targets should always warn about availability.
196
1
    return Triple.getVendor() == llvm::Triple::Apple;
197
214
  }
198
214
  return DeploymentVersion >= ForceAvailabilityFromVersion ||
199
214
         
DeclVersion >= ForceAvailabilityFromVersion185
;
200
214
}
201
202
52
static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) {
203
119
  for (Decl *Ctx = OrigCtx; Ctx;
204
94
       
Ctx = cast_or_null<Decl>(Ctx->getDeclContext())67
) {
205
94
    if (isa<TagDecl>(Ctx) || 
isa<FunctionDecl>(Ctx)86
||
isa<ObjCMethodDecl>(Ctx)79
)
206
18
      return cast<NamedDecl>(Ctx);
207
76
    if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
208
9
      if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
209
1
        return Imp->getClassInterface();
210
8
      return CD;
211
8
    }
212
76
  }
213
52
214
52
  
return dyn_cast<NamedDecl>(OrigCtx)25
;
215
52
}
216
217
namespace {
218
219
struct AttributeInsertion {
220
  StringRef Prefix;
221
  SourceLocation Loc;
222
  StringRef Suffix;
223
224
1
  static AttributeInsertion createInsertionAfter(const NamedDecl *D) {
225
1
    return {" ", D->getEndLoc(), ""};
226
1
  }
227
1
  static AttributeInsertion createInsertionAfter(SourceLocation Loc) {
228
1
    return {" ", Loc, ""};
229
1
  }
230
2
  static AttributeInsertion createInsertionBefore(const NamedDecl *D) {
231
2
    return {"", D->getBeginLoc(), "\n"};
232
2
  }
233
};
234
235
} // end anonymous namespace
236
237
/// Tries to parse a string as ObjC method name.
238
///
239
/// \param Name The string to parse. Expected to originate from availability
240
/// attribute argument.
241
/// \param SlotNames The vector that will be populated with slot names. In case
242
/// of unsuccessful parsing can contain invalid data.
243
/// \returns A number of method parameters if parsing was successful, None
244
/// otherwise.
245
static Optional<unsigned>
246
tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames,
247
47
                       const LangOptions &LangOpts) {
248
47
  // Accept replacements starting with - or + as valid ObjC method names.
249
47
  if (!Name.empty() && (Name.front() == '-' || 
Name.front() == '+'40
))
250
10
    Name = Name.drop_front(1);
251
47
  if (Name.empty())
252
2
    return None;
253
45
  Name.split(SlotNames, ':');
254
45
  unsigned NumParams;
255
45
  if (Name.back() == ':') {
256
36
    // Remove an empty string at the end that doesn't represent any slot.
257
36
    SlotNames.pop_back();
258
36
    NumParams = SlotNames.size();
259
36
  } else {
260
9
    if (SlotNames.size() != 1)
261
2
      // Not a valid method name, just a colon-separated string.
262
2
      return None;
263
7
    NumParams = 0;
264
7
  }
265
45
  // Verify all slot names are valid.
266
45
  bool AllowDollar = LangOpts.DollarIdents;
267
80
  for (StringRef S : SlotNames) {
268
80
    if (S.empty())
269
3
      continue;
270
77
    if (!isValidIdentifier(S, AllowDollar))
271
6
      return None;
272
77
  }
273
43
  
return NumParams37
;
274
43
}
275
276
/// Returns a source location in which it's appropriate to insert a new
277
/// attribute for the given declaration \D.
278
static Optional<AttributeInsertion>
279
createAttributeInsertion(const NamedDecl *D, const SourceManager &SM,
280
4
                         const LangOptions &LangOpts) {
281
4
  if (isa<ObjCPropertyDecl>(D))
282
0
    return AttributeInsertion::createInsertionAfter(D);
283
4
  if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
284
1
    if (MD->hasBody())
285
0
      return None;
286
1
    return AttributeInsertion::createInsertionAfter(D);
287
1
  }
288
3
  if (const auto *TD = dyn_cast<TagDecl>(D)) {
289
1
    SourceLocation Loc =
290
1
        Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts);
291
1
    if (Loc.isInvalid())
292
0
      return None;
293
1
    // Insert after the 'struct'/whatever keyword.
294
1
    return AttributeInsertion::createInsertionAfter(Loc);
295
1
  }
296
2
  return AttributeInsertion::createInsertionBefore(D);
297
2
}
298
299
/// Actually emit an availability diagnostic for a reference to an unavailable
300
/// decl.
301
///
302
/// \param Ctx The context that the reference occurred in
303
/// \param ReferringDecl The exact declaration that was referenced.
304
/// \param OffendingDecl A related decl to \c ReferringDecl that has an
305
/// availability attribute corresponding to \c K attached to it. Note that this
306
/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
307
/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
308
/// and OffendingDecl is the EnumDecl.
309
static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
310
                                      Decl *Ctx, const NamedDecl *ReferringDecl,
311
                                      const NamedDecl *OffendingDecl,
312
                                      StringRef Message,
313
                                      ArrayRef<SourceLocation> Locs,
314
                                      const ObjCInterfaceDecl *UnknownObjCClass,
315
                                      const ObjCPropertyDecl *ObjCProperty,
316
442k
                                      bool ObjCPropertyAccess) {
317
442k
  // Diagnostics for deprecated or unavailable.
318
442k
  unsigned diag, diag_message, diag_fwdclass_message;
319
442k
  unsigned diag_available_here = diag::note_availability_specified_here;
320
442k
  SourceLocation NoteLocation = OffendingDecl->getLocation();
321
442k
322
442k
  // Matches 'diag::note_property_attribute' options.
323
442k
  unsigned property_note_select;
324
442k
325
442k
  // Matches diag::note_availability_specified_here.
326
442k
  unsigned available_here_select_kind;
327
442k
328
442k
  VersionTuple DeclVersion;
329
442k
  if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl))
330
437k
    DeclVersion = AA->getIntroduced();
331
442k
332
442k
  if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx,
333
442k
                                           OffendingDecl))
334
395k
    return;
335
47.3k
336
47.3k
  SourceLocation Loc = Locs.front();
337
47.3k
338
47.3k
  // The declaration can have multiple availability attributes, we are looking
339
47.3k
  // at one of them.
340
47.3k
  const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
341
47.3k
  if (A && 
A->isInherited()43.7k
) {
342
10
    for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
343
10
         
Redecl = Redecl->getPreviousDecl()5
) {
344
10
      const AvailabilityAttr *AForRedecl =
345
10
          getAttrForPlatform(S.Context, Redecl);
346
10
      if (AForRedecl && !AForRedecl->isInherited()) {
347
5
        // If D is a declaration with inherited attributes, the note should
348
5
        // point to the declaration with actual attributes.
349
5
        NoteLocation = Redecl->getLocation();
350
5
        break;
351
5
      }
352
10
    }
353
5
  }
354
47.3k
355
47.3k
  switch (K) {
356
52
  case AR_NotYetIntroduced: {
357
52
    // We would like to emit the diagnostic even if -Wunguarded-availability is
358
52
    // not specified for deployment targets >= to iOS 11 or equivalent or
359
52
    // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
360
52
    // later.
361
52
    const AvailabilityAttr *AA =
362
52
        getAttrForPlatform(S.getASTContext(), OffendingDecl);
363
52
    VersionTuple Introduced = AA->getIntroduced();
364
52
365
52
    bool UseNewWarning = shouldDiagnoseAvailabilityByDefault(
366
52
        S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
367
52
        Introduced);
368
52
    unsigned Warning = UseNewWarning ? 
diag::warn_unguarded_availability_new26
369
52
                                     : 
diag::warn_unguarded_availability26
;
370
52
371
52
    std::string PlatformName(AvailabilityAttr::getPrettyPlatformName(
372
52
        S.getASTContext().getTargetInfo().getPlatformName()));
373
52
374
52
    S.Diag(Loc, Warning) << OffendingDecl << PlatformName
375
52
                         << Introduced.getAsString();
376
52
377
52
    S.Diag(OffendingDecl->getLocation(),
378
52
           diag::note_partial_availability_specified_here)
379
52
        << OffendingDecl << PlatformName << Introduced.getAsString()
380
52
        << S.Context.getTargetInfo().getPlatformMinVersion().getAsString();
381
52
382
52
    if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
383
52
      if (const auto *TD = dyn_cast<TagDecl>(Enclosing))
384
8
        if (TD->getDeclName().isEmpty()) {
385
3
          S.Diag(TD->getLocation(),
386
3
                 diag::note_decl_unguarded_availability_silence)
387
3
              << /*Anonymous*/ 1 << TD->getKindName();
388
3
          return;
389
3
        }
390
49
      auto FixitNoteDiag =
391
49
          S.Diag(Enclosing->getLocation(),
392
49
                 diag::note_decl_unguarded_availability_silence)
393
49
          << /*Named*/ 0 << Enclosing;
394
49
      // Don't offer a fixit for declarations with availability attributes.
395
49
      if (Enclosing->hasAttr<AvailabilityAttr>())
396
7
        return;
397
42
      if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
398
38
        return;
399
4
      Optional<AttributeInsertion> Insertion = createAttributeInsertion(
400
4
          Enclosing, S.getSourceManager(), S.getLangOpts());
401
4
      if (!Insertion)
402
0
        return;
403
4
      std::string PlatformName =
404
4
          AvailabilityAttr::getPlatformNameSourceSpelling(
405
4
              S.getASTContext().getTargetInfo().getPlatformName())
406
4
              .lower();
407
4
      std::string Introduced =
408
4
          OffendingDecl->getVersionIntroduced().getAsString();
409
4
      FixitNoteDiag << FixItHint::CreateInsertion(
410
4
          Insertion->Loc,
411
4
          (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName +
412
4
           "(" + Introduced + "))" + Insertion->Suffix)
413
4
              .str());
414
4
    }
415
52
    
return4
;
416
52
  }
417
46.8k
  case AR_Deprecated:
418
46.8k
    diag = !ObjCPropertyAccess ? 
diag::warn_deprecated46.8k
419
46.8k
                               : 
diag::warn_property_method_deprecated9
;
420
46.8k
    diag_message = diag::warn_deprecated_message;
421
46.8k
    diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
422
46.8k
    property_note_select = /* deprecated */ 0;
423
46.8k
    available_here_select_kind = /* deprecated */ 2;
424
46.8k
    if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>())
425
3.30k
      NoteLocation = AL->getLocation();
426
46.8k
    break;
427
52
428
438
  case AR_Unavailable:
429
438
    diag = !ObjCPropertyAccess ? 
diag::err_unavailable435
430
438
                               : 
diag::err_property_method_unavailable3
;
431
438
    diag_message = diag::err_unavailable_message;
432
438
    diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
433
438
    property_note_select = /* unavailable */ 1;
434
438
    available_here_select_kind = /* unavailable */ 0;
435
438
436
438
    if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) {
437
315
      if (AL->isImplicit() && 
AL->getImplicitReason()12
) {
438
12
        // Most of these failures are due to extra restrictions in ARC;
439
12
        // reflect that in the primary diagnostic when applicable.
440
12
        auto flagARCError = [&] {
441
10
          if (S.getLangOpts().ObjCAutoRefCount &&
442
10
              S.getSourceManager().isInSystemHeader(
443
10
                  OffendingDecl->getLocation()))
444
10
            diag = diag::err_unavailable_in_arc;
445
10
        };
446
12
447
12
        switch (AL->getImplicitReason()) {
448
0
        case UnavailableAttr::IR_None: break;
449
0
450
7
        case UnavailableAttr::IR_ARCForbiddenType:
451
7
          flagARCError();
452
7
          diag_available_here = diag::note_arc_forbidden_type;
453
7
          break;
454
0
455
2
        case UnavailableAttr::IR_ForbiddenWeak:
456
2
          if (S.getLangOpts().ObjCWeakRuntime)
457
2
            diag_available_here = diag::note_arc_weak_disabled;
458
0
          else
459
0
            diag_available_here = diag::note_arc_weak_no_runtime;
460
2
          break;
461
0
462
2
        case UnavailableAttr::IR_ARCForbiddenConversion:
463
2
          flagARCError();
464
2
          diag_available_here = diag::note_performs_forbidden_arc_conversion;
465
2
          break;
466
0
467
0
        case UnavailableAttr::IR_ARCInitReturnsUnrelated:
468
0
          flagARCError();
469
0
          diag_available_here = diag::note_arc_init_returns_unrelated;
470
0
          break;
471
0
472
1
        case UnavailableAttr::IR_ARCFieldWithOwnership:
473
1
          flagARCError();
474
1
          diag_available_here = diag::note_arc_field_with_ownership;
475
1
          break;
476
438
        }
477
438
      }
478
315
    }
479
438
    break;
480
438
481
438
  case AR_Available:
482
0
    llvm_unreachable("Warning for availability of available declaration?");
483
47.2k
  }
484
47.2k
485
47.2k
  SmallVector<FixItHint, 12> FixIts;
486
47.2k
  if (K == AR_Deprecated) {
487
46.8k
    StringRef Replacement;
488
46.8k
    if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>())
489
3.30k
      Replacement = AL->getReplacement();
490
46.8k
    if (auto AL = getAttrForPlatform(S.Context, OffendingDecl))
491
43.5k
      Replacement = AL->getReplacement();
492
46.8k
493
46.8k
    CharSourceRange UseRange;
494
46.8k
    if (!Replacement.empty())
495
53
      UseRange =
496
53
          CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc));
497
46.8k
    if (UseRange.isValid()) {
498
53
      if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) {
499
47
        Selector Sel = MethodDecl->getSelector();
500
47
        SmallVector<StringRef, 12> SelectorSlotNames;
501
47
        Optional<unsigned> NumParams = tryParseObjCMethodName(
502
47
            Replacement, SelectorSlotNames, S.getLangOpts());
503
47
        if (NumParams && 
NumParams.getValue() == Sel.getNumArgs()37
) {
504
30
          assert(SelectorSlotNames.size() == Locs.size());
505
93
          for (unsigned I = 0; I < Locs.size(); 
++I63
) {
506
63
            if (!Sel.getNameForSlot(I).empty()) {
507
60
              CharSourceRange NameRange = CharSourceRange::getCharRange(
508
60
                  Locs[I], S.getLocForEndOfToken(Locs[I]));
509
60
              FixIts.push_back(FixItHint::CreateReplacement(
510
60
                  NameRange, SelectorSlotNames[I]));
511
60
            } else
512
3
              FixIts.push_back(
513
3
                  FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I]));
514
63
          }
515
30
        } else
516
17
          FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
517
47
      } else
518
6
        FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
519
53
    }
520
46.8k
  }
521
47.2k
522
47.2k
  if (!Message.empty()) {
523
46.7k
    S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts;
524
46.7k
    if (ObjCProperty)
525
28
      S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
526
28
          << ObjCProperty->getDeclName() << property_note_select;
527
46.7k
  } else 
if (503
!UnknownObjCClass503
) {
528
492
    S.Diag(Loc, diag) << ReferringDecl << FixIts;
529
492
    if (ObjCProperty)
530
6
      S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
531
6
          << ObjCProperty->getDeclName() << property_note_select;
532
492
  } else {
533
11
    S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts;
534
11
    S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
535
11
  }
536
47.2k
537
47.2k
  S.Diag(NoteLocation, diag_available_here)
538
47.2k
    << OffendingDecl << available_here_select_kind;
539
47.2k
}
540
541
418k
void Sema::handleDelayedAvailabilityCheck(DelayedDiagnostic &DD, Decl *Ctx) {
542
418k
  assert(DD.Kind == DelayedDiagnostic::Availability &&
543
418k
         "Expected an availability diagnostic here");
544
418k
545
418k
  DD.Triggered = true;
546
418k
  DoEmitAvailabilityWarning(
547
418k
      *this, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(),
548
418k
      DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(),
549
418k
      DD.getAvailabilitySelectorLocs(), DD.getUnknownObjCClass(),
550
418k
      DD.getObjCProperty(), false);
551
418k
}
552
553
static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR,
554
                                    const NamedDecl *ReferringDecl,
555
                                    const NamedDecl *OffendingDecl,
556
                                    StringRef Message,
557
                                    ArrayRef<SourceLocation> Locs,
558
                                    const ObjCInterfaceDecl *UnknownObjCClass,
559
                                    const ObjCPropertyDecl *ObjCProperty,
560
442k
                                    bool ObjCPropertyAccess) {
561
442k
  // Delay if we're currently parsing a declaration.
562
442k
  if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
563
418k
    S.DelayedDiagnostics.add(
564
418k
        DelayedDiagnostic::makeAvailability(
565
418k
            AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass,
566
418k
            ObjCProperty, Message, ObjCPropertyAccess));
567
418k
    return;
568
418k
  }
569
23.9k
570
23.9k
  Decl *Ctx = cast<Decl>(S.getCurLexicalContext());
571
23.9k
  DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl,
572
23.9k
                            Message, Locs, UnknownObjCClass, ObjCProperty,
573
23.9k
                            ObjCPropertyAccess);
574
23.9k
}
575
576
namespace {
577
578
/// Returns true if the given statement can be a body-like child of \p Parent.
579
436
bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {
580
436
  switch (Parent->getStmtClass()) {
581
20
  case Stmt::IfStmtClass:
582
20
    return cast<IfStmt>(Parent)->getThen() == S ||
583
20
           
cast<IfStmt>(Parent)->getElse() == S12
;
584
1
  case Stmt::WhileStmtClass:
585
1
    return cast<WhileStmt>(Parent)->getBody() == S;
586
1
  case Stmt::DoStmtClass:
587
1
    return cast<DoStmt>(Parent)->getBody() == S;
588
1
  case Stmt::ForStmtClass:
589
1
    return cast<ForStmt>(Parent)->getBody() == S;
590
0
  case Stmt::CXXForRangeStmtClass:
591
0
    return cast<CXXForRangeStmt>(Parent)->getBody() == S;
592
0
  case Stmt::ObjCForCollectionStmtClass:
593
0
    return cast<ObjCForCollectionStmt>(Parent)->getBody() == S;
594
2
  case Stmt::CaseStmtClass:
595
2
  case Stmt::DefaultStmtClass:
596
2
    return cast<SwitchCase>(Parent)->getSubStmt() == S;
597
411
  default:
598
411
    return false;
599
436
  }
600
436
}
601
602
class StmtUSEFinder : public RecursiveASTVisitor<StmtUSEFinder> {
603
  const Stmt *Target;
604
605
public:
606
49
  bool VisitStmt(Stmt *S) { return S != Target; }
607
608
  /// Returns true if the given statement is present in the given declaration.
609
19
  static bool isContained(const Stmt *Target, const Decl *D) {
610
19
    StmtUSEFinder Visitor;
611
19
    Visitor.Target = Target;
612
19
    return !Visitor.TraverseDecl(const_cast<Decl *>(D));
613
19
  }
614
};
615
616
/// Traverses the AST and finds the last statement that used a given
617
/// declaration.
618
class LastDeclUSEFinder : public RecursiveASTVisitor<LastDeclUSEFinder> {
619
  const Decl *D;
620
621
public:
622
40
  bool VisitDeclRefExpr(DeclRefExpr *DRE) {
623
40
    if (DRE->getDecl() == D)
624
5
      return false;
625
35
    return true;
626
35
  }
627
628
  static const Stmt *findLastStmtThatUsesDecl(const Decl *D,
629
12
                                              const CompoundStmt *Scope) {
630
12
    LastDeclUSEFinder Visitor;
631
12
    Visitor.D = D;
632
34
    for (auto I = Scope->body_rbegin(), E = Scope->body_rend(); I != E; 
++I22
) {
633
27
      const Stmt *S = *I;
634
27
      if (!Visitor.TraverseStmt(const_cast<Stmt *>(S)))
635
5
        return S;
636
27
    }
637
12
    
return nullptr7
;
638
12
  }
639
};
640
641
/// This class implements -Wunguarded-availability.
642
///
643
/// This is done with a traversal of the AST of a function that makes reference
644
/// to a partially available declaration. Whenever we encounter an \c if of the
645
/// form: \c if(@available(...)), we use the version from the condition to visit
646
/// the then statement.
647
class DiagnoseUnguardedAvailability
648
    : public RecursiveASTVisitor<DiagnoseUnguardedAvailability> {
649
  typedef RecursiveASTVisitor<DiagnoseUnguardedAvailability> Base;
650
651
  Sema &SemaRef;
652
  Decl *Ctx;
653
654
  /// Stack of potentially nested 'if (@available(...))'s.
655
  SmallVector<VersionTuple, 8> AvailabilityStack;
656
  SmallVector<const Stmt *, 16> StmtStack;
657
658
  void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range,
659
                                ObjCInterfaceDecl *ClassReceiver = nullptr);
660
661
public:
662
  DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx)
663
127
      : SemaRef(SemaRef), Ctx(Ctx) {
664
127
    AvailabilityStack.push_back(
665
127
        SemaRef.Context.getTargetInfo().getPlatformMinVersion());
666
127
  }
667
668
28
  bool TraverseDecl(Decl *D) {
669
28
    // Avoid visiting nested functions to prevent duplicate warnings.
670
28
    if (!D || isa<FunctionDecl>(D))
671
1
      return true;
672
27
    return Base::TraverseDecl(D);
673
27
  }
674
675
1.68k
  bool TraverseStmt(Stmt *S) {
676
1.68k
    if (!S)
677
53
      return true;
678
1.63k
    StmtStack.push_back(S);
679
1.63k
    bool Result = Base::TraverseStmt(S);
680
1.63k
    StmtStack.pop_back();
681
1.63k
    return Result;
682
1.63k
  }
683
684
127
  void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }
685
686
  bool TraverseIfStmt(IfStmt *If);
687
688
1
  bool TraverseLambdaExpr(LambdaExpr *E) { return true; }
689
690
  // for 'case X:' statements, don't bother looking at the 'X'; it can't lead
691
  // to any useful diagnostics.
692
12
  bool TraverseCaseStmt(CaseStmt *CS) { return TraverseStmt(CS->getSubStmt()); }
693
694
4
  bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) {
695
4
    if (PRE->isClassReceiver())
696
4
      DiagnoseDeclAvailability(PRE->getClassReceiver(), PRE->getReceiverLocation());
697
4
    return true;
698
4
  }
699
700
125
  bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) {
701
125
    if (ObjCMethodDecl *D = Msg->getMethodDecl()) {
702
123
      ObjCInterfaceDecl *ID = nullptr;
703
123
      QualType ReceiverTy = Msg->getClassReceiver();
704
123
      if (!ReceiverTy.isNull() && 
ReceiverTy->getAsObjCInterfaceType()15
)
705
15
        ID = ReceiverTy->getAsObjCInterfaceType()->getInterface();
706
123
707
123
      DiagnoseDeclAvailability(
708
123
          D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID);
709
123
    }
710
125
    return true;
711
125
  }
712
713
366
  bool VisitDeclRefExpr(DeclRefExpr *DRE) {
714
366
    DiagnoseDeclAvailability(DRE->getDecl(),
715
366
                             SourceRange(DRE->getBeginLoc(), DRE->getEndLoc()));
716
366
    return true;
717
366
  }
718
719
8
  bool VisitMemberExpr(MemberExpr *ME) {
720
8
    DiagnoseDeclAvailability(ME->getMemberDecl(),
721
8
                             SourceRange(ME->getBeginLoc(), ME->getEndLoc()));
722
8
    return true;
723
8
  }
724
725
9
  bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
726
9
    SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use)
727
9
        << (!SemaRef.getLangOpts().ObjC);
728
9
    return true;
729
9
  }
730
731
  bool VisitTypeLoc(TypeLoc Ty);
732
};
733
734
void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
735
550
    NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) {
736
550
  AvailabilityResult Result;
737
550
  const NamedDecl *OffendingDecl;
738
550
  std::tie(Result, OffendingDecl) =
739
550
      ShouldDiagnoseAvailabilityOfDecl(SemaRef, D, nullptr, ReceiverClass);
740
550
  if (Result != AR_Available) {
741
263
    // All other diagnostic kinds have already been handled in
742
263
    // DiagnoseAvailabilityOfDecl.
743
263
    if (Result != AR_NotYetIntroduced)
744
43
      return;
745
220
746
220
    const AvailabilityAttr *AA =
747
220
      getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
748
220
    VersionTuple Introduced = AA->getIntroduced();
749
220
750
220
    if (AvailabilityStack.back() >= Introduced)
751
40
      return;
752
180
753
180
    // If the context of this function is less available than D, we should not
754
180
    // emit a diagnostic.
755
180
    if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx,
756
180
                                             OffendingDecl))
757
17
      return;
758
163
759
163
    // We would like to emit the diagnostic even if -Wunguarded-availability is
760
163
    // not specified for deployment targets >= to iOS 11 or equivalent or
761
163
    // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
762
163
    // later.
763
163
    unsigned DiagKind =
764
163
        shouldDiagnoseAvailabilityByDefault(
765
163
            SemaRef.Context,
766
163
            SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced)
767
163
            ? 
diag::warn_unguarded_availability_new28
768
163
            : 
diag::warn_unguarded_availability135
;
769
163
770
163
    std::string PlatformName(AvailabilityAttr::getPrettyPlatformName(
771
163
        SemaRef.getASTContext().getTargetInfo().getPlatformName()));
772
163
773
163
    SemaRef.Diag(Range.getBegin(), DiagKind)
774
163
        << Range << D << PlatformName << Introduced.getAsString();
775
163
776
163
    SemaRef.Diag(OffendingDecl->getLocation(),
777
163
                 diag::note_partial_availability_specified_here)
778
163
        << OffendingDecl << PlatformName << Introduced.getAsString()
779
163
        << SemaRef.Context.getTargetInfo()
780
163
               .getPlatformMinVersion()
781
163
               .getAsString();
782
163
783
163
    auto FixitDiag =
784
163
        SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
785
163
        << Range << D
786
163
        << (SemaRef.getLangOpts().ObjC ? /*@available*/ 
0149
787
163
                                       : /*__builtin_available*/ 
114
);
788
163
789
163
    // Find the statement which should be enclosed in the if @available check.
790
163
    if (StmtStack.empty())
791
0
      return;
792
163
    const Stmt *StmtOfUse = StmtStack.back();
793
163
    const CompoundStmt *Scope = nullptr;
794
579
    for (const Stmt *S : llvm::reverse(StmtStack)) {
795
579
      if (const auto *CS = dyn_cast<CompoundStmt>(S)) {
796
143
        Scope = CS;
797
143
        break;
798
143
      }
799
436
      if (isBodyLikeChildStmt(StmtOfUse, S)) {
800
20
        // The declaration won't be seen outside of the statement, so we don't
801
20
        // have to wrap the uses of any declared variables in if (@available).
802
20
        // Therefore we can avoid setting Scope here.
803
20
        break;
804
20
      }
805
416
      StmtOfUse = S;
806
416
    }
807
163
    const Stmt *LastStmtOfUse = nullptr;
808
163
    if (isa<DeclStmt>(StmtOfUse) && 
Scope19
) {
809
19
      for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) {
810
19
        if (StmtUSEFinder::isContained(StmtStack.back(), D)) {
811
12
          LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope);
812
12
          break;
813
12
        }
814
19
      }
815
18
    }
816
163
817
163
    const SourceManager &SM = SemaRef.getSourceManager();
818
163
    SourceLocation IfInsertionLoc =
819
163
        SM.getExpansionLoc(StmtOfUse->getBeginLoc());
820
163
    SourceLocation StmtEndLoc =
821
163
        SM.getExpansionRange(
822
163
              (LastStmtOfUse ? 
LastStmtOfUse5
:
StmtOfUse158
)->getEndLoc())
823
163
            .getEnd();
824
163
    if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc))
825
0
      return;
826
163
827
163
    StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM);
828
163
    const char *ExtraIndentation = "    ";
829
163
    std::string FixItString;
830
163
    llvm::raw_string_ostream FixItOS(FixItString);
831
163
    FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? 
"@available"149
832
163
                                                     : 
"__builtin_available"14
)
833
163
            << "("
834
163
            << AvailabilityAttr::getPlatformNameSourceSpelling(
835
163
                   SemaRef.getASTContext().getTargetInfo().getPlatformName())
836
163
            << " " << Introduced.getAsString() << ", *)) {\n"
837
163
            << Indentation << ExtraIndentation;
838
163
    FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str());
839
163
    SourceLocation ElseInsertionLoc = Lexer::findLocationAfterToken(
840
163
        StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(),
841
163
        /*SkipTrailingWhitespaceAndNewLine=*/false);
842
163
    if (ElseInsertionLoc.isInvalid())
843
19
      ElseInsertionLoc =
844
19
          Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts());
845
163
    FixItOS.str().clear();
846
163
    FixItOS << "\n"
847
163
            << Indentation << "} else {\n"
848
163
            << Indentation << ExtraIndentation
849
163
            << "// Fallback on earlier versions\n"
850
163
            << Indentation << "}";
851
163
    FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str());
852
163
  }
853
550
}
854
855
101
bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
856
101
  const Type *TyPtr = Ty.getTypePtr();
857
101
  SourceRange Range{Ty.getBeginLoc(), Ty.getEndLoc()};
858
101
859
101
  if (Range.isInvalid())
860
7
    return true;
861
94
862
94
  if (const auto *TT = dyn_cast<TagType>(TyPtr)) {
863
4
    TagDecl *TD = TT->getDecl();
864
4
    DiagnoseDeclAvailability(TD, Range);
865
4
866
90
  } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) {
867
30
    TypedefNameDecl *D = TD->getDecl();
868
30
    DiagnoseDeclAvailability(D, Range);
869
30
870
60
  } else if (const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) {
871
15
    if (NamedDecl *D = ObjCO->getInterface())
872
15
      DiagnoseDeclAvailability(D, Range);
873
15
  }
874
94
875
94
  return true;
876
94
}
877
878
87
bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
879
87
  VersionTuple CondVersion;
880
87
  if (auto *E = dyn_cast<ObjCAvailabilityCheckExpr>(If->getCond())) {
881
67
    CondVersion = E->getVersion();
882
67
883
67
    // If we're using the '*' case here or if this check is redundant, then we
884
67
    // use the enclosing version to check both branches.
885
67
    if (CondVersion.empty() || 
CondVersion <= AvailabilityStack.back()56
)
886
21
      return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
887
20
  } else {
888
20
    // This isn't an availability checking 'if', we can just continue.
889
20
    return Base::TraverseIfStmt(If);
890
20
  }
891
46
892
46
  AvailabilityStack.push_back(CondVersion);
893
46
  bool ShouldContinue = TraverseStmt(If->getThen());
894
46
  AvailabilityStack.pop_back();
895
46
896
46
  return ShouldContinue && TraverseStmt(If->getElse());
897
46
}
898
899
} // end anonymous namespace
900
901
128
void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) {
902
128
  Stmt *Body = nullptr;
903
128
904
128
  if (auto *FD = D->getAsFunction()) {
905
104
    // FIXME: We only examine the pattern decl for availability violations now,
906
104
    // but we should also examine instantiated templates.
907
104
    if (FD->isTemplateInstantiation())
908
1
      return;
909
103
910
103
    Body = FD->getBody();
911
103
  } else 
if (auto *24
MD24
= dyn_cast<ObjCMethodDecl>(D))
912
22
    Body = MD->getBody();
913
2
  else if (auto *BD = dyn_cast<BlockDecl>(D))
914
2
    Body = BD->getBody();
915
128
916
128
  assert(Body && "Need a body here!");
917
127
918
127
  DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);
919
127
}
920
921
void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D,
922
                                      ArrayRef<SourceLocation> Locs,
923
                                      const ObjCInterfaceDecl *UnknownObjCClass,
924
                                      bool ObjCPropertyAccess,
925
                                      bool AvoidPartialAvailabilityChecks,
926
49.4M
                                      ObjCInterfaceDecl *ClassReceiver) {
927
49.4M
  std::string Message;
928
49.4M
  AvailabilityResult Result;
929
49.4M
  const NamedDecl* OffendingDecl;
930
49.4M
  // See if this declaration is unavailable, deprecated, or partial.
931
49.4M
  std::tie(Result, OffendingDecl) =
932
49.4M
      ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver);
933
49.4M
  if (Result == AR_Available)
934
48.9M
    return;
935
442k
936
442k
  if (Result == AR_NotYetIntroduced) {
937
303
    if (AvoidPartialAvailabilityChecks)
938
6
      return;
939
297
940
297
    // We need to know the @available context in the current function to
941
297
    // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that
942
297
    // when we're done parsing the current function.
943
297
    if (getCurFunctionOrMethodDecl()) {
944
230
      getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
945
230
      return;
946
230
    } else 
if (67
getCurBlock()67
||
getCurLambda()63
) {
947
6
      getCurFunction()->HasPotentialAvailabilityViolations = true;
948
6
      return;
949
6
    }
950
442k
  }
951
442k
952
442k
  const ObjCPropertyDecl *ObjCPDecl = nullptr;
953
442k
  if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
954
433
    if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
955
37
      AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
956
37
      if (PDeclResult == Result)
957
34
        ObjCPDecl = PD;
958
37
    }
959
433
  }
960
442k
961
442k
  EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs,
962
442k
                          UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
963
442k
}