Coverage Report

Created: 2020-09-22 08:39

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