xref: /freebsd-src/contrib/llvm-project/clang/lib/Sema/SemaAvailability.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===--- SemaAvailability.cpp - Availability attribute handling -----------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric //
95ffd83dbSDimitry Andric //  This file processes the availability attribute.
105ffd83dbSDimitry Andric //
115ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
125ffd83dbSDimitry Andric 
135ffd83dbSDimitry Andric #include "clang/AST/Attr.h"
145ffd83dbSDimitry Andric #include "clang/AST/Decl.h"
15*0fca6ea1SDimitry Andric #include "clang/AST/DeclTemplate.h"
165ffd83dbSDimitry Andric #include "clang/AST/RecursiveASTVisitor.h"
175ffd83dbSDimitry Andric #include "clang/Basic/DiagnosticSema.h"
18*0fca6ea1SDimitry Andric #include "clang/Basic/IdentifierTable.h"
19*0fca6ea1SDimitry Andric #include "clang/Basic/LangOptions.h"
205ffd83dbSDimitry Andric #include "clang/Basic/TargetInfo.h"
215ffd83dbSDimitry Andric #include "clang/Lex/Preprocessor.h"
225ffd83dbSDimitry Andric #include "clang/Sema/DelayedDiagnostic.h"
235ffd83dbSDimitry Andric #include "clang/Sema/ScopeInfo.h"
245ffd83dbSDimitry Andric #include "clang/Sema/Sema.h"
25*0fca6ea1SDimitry Andric #include "clang/Sema/SemaObjC.h"
26*0fca6ea1SDimitry Andric #include "llvm/ADT/StringRef.h"
27bdd1243dSDimitry Andric #include <optional>
285ffd83dbSDimitry Andric 
295ffd83dbSDimitry Andric using namespace clang;
305ffd83dbSDimitry Andric using namespace sema;
315ffd83dbSDimitry Andric 
32*0fca6ea1SDimitry Andric static bool hasMatchingEnvironmentOrNone(const ASTContext &Context,
33*0fca6ea1SDimitry Andric                                          const AvailabilityAttr *AA) {
34*0fca6ea1SDimitry Andric   IdentifierInfo *IIEnvironment = AA->getEnvironment();
35*0fca6ea1SDimitry Andric   auto Environment = Context.getTargetInfo().getTriple().getEnvironment();
36*0fca6ea1SDimitry Andric   if (!IIEnvironment || Environment == llvm::Triple::UnknownEnvironment)
37*0fca6ea1SDimitry Andric     return true;
38*0fca6ea1SDimitry Andric 
39*0fca6ea1SDimitry Andric   llvm::Triple::EnvironmentType ET =
40*0fca6ea1SDimitry Andric       AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
41*0fca6ea1SDimitry Andric   return Environment == ET;
42*0fca6ea1SDimitry Andric }
43*0fca6ea1SDimitry Andric 
445ffd83dbSDimitry Andric static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
455ffd83dbSDimitry Andric                                                   const Decl *D) {
46*0fca6ea1SDimitry Andric   AvailabilityAttr const *PartialMatch = nullptr;
475ffd83dbSDimitry Andric   // Check each AvailabilityAttr to find the one for this platform.
48*0fca6ea1SDimitry Andric   // For multiple attributes with the same platform try to find one for this
49*0fca6ea1SDimitry Andric   // environment.
50*0fca6ea1SDimitry Andric   // The attribute is always on the FunctionDecl, not on the
51*0fca6ea1SDimitry Andric   // FunctionTemplateDecl.
52*0fca6ea1SDimitry Andric   if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
53*0fca6ea1SDimitry Andric     D = FTD->getTemplatedDecl();
545ffd83dbSDimitry Andric   for (const auto *A : D->attrs()) {
555ffd83dbSDimitry Andric     if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
565ffd83dbSDimitry Andric       // FIXME: this is copied from CheckAvailability. We should try to
575ffd83dbSDimitry Andric       // de-duplicate.
585ffd83dbSDimitry Andric 
595ffd83dbSDimitry Andric       // Check if this is an App Extension "platform", and if so chop off
605ffd83dbSDimitry Andric       // the suffix for matching with the actual platform.
615ffd83dbSDimitry Andric       StringRef ActualPlatform = Avail->getPlatform()->getName();
625ffd83dbSDimitry Andric       StringRef RealizedPlatform = ActualPlatform;
635ffd83dbSDimitry Andric       if (Context.getLangOpts().AppExt) {
645ffd83dbSDimitry Andric         size_t suffix = RealizedPlatform.rfind("_app_extension");
655ffd83dbSDimitry Andric         if (suffix != StringRef::npos)
665ffd83dbSDimitry Andric           RealizedPlatform = RealizedPlatform.slice(0, suffix);
675ffd83dbSDimitry Andric       }
685ffd83dbSDimitry Andric 
695ffd83dbSDimitry Andric       StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
705ffd83dbSDimitry Andric 
715ffd83dbSDimitry Andric       // Match the platform name.
72*0fca6ea1SDimitry Andric       if (RealizedPlatform == TargetPlatform) {
73*0fca6ea1SDimitry Andric         // Find the best matching attribute for this environment
74*0fca6ea1SDimitry Andric         if (hasMatchingEnvironmentOrNone(Context, Avail))
755ffd83dbSDimitry Andric           return Avail;
76*0fca6ea1SDimitry Andric         PartialMatch = Avail;
775ffd83dbSDimitry Andric       }
785ffd83dbSDimitry Andric     }
79*0fca6ea1SDimitry Andric   }
80*0fca6ea1SDimitry Andric   return PartialMatch;
815ffd83dbSDimitry Andric }
825ffd83dbSDimitry Andric 
835ffd83dbSDimitry Andric /// The diagnostic we should emit for \c D, and the declaration that
845ffd83dbSDimitry Andric /// originated it, or \c AR_Available.
855ffd83dbSDimitry Andric ///
865ffd83dbSDimitry Andric /// \param D The declaration to check.
875ffd83dbSDimitry Andric /// \param Message If non-null, this will be populated with the message from
885ffd83dbSDimitry Andric /// the availability attribute that is selected.
89349cc55cSDimitry Andric /// \param ClassReceiver If we're checking the method of a class message
905ffd83dbSDimitry Andric /// send, the class. Otherwise nullptr.
915ffd83dbSDimitry Andric static std::pair<AvailabilityResult, const NamedDecl *>
925ffd83dbSDimitry Andric ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,
935ffd83dbSDimitry Andric                                  std::string *Message,
945ffd83dbSDimitry Andric                                  ObjCInterfaceDecl *ClassReceiver) {
955ffd83dbSDimitry Andric   AvailabilityResult Result = D->getAvailability(Message);
965ffd83dbSDimitry Andric 
975ffd83dbSDimitry Andric   // For typedefs, if the typedef declaration appears available look
985ffd83dbSDimitry Andric   // to the underlying type to see if it is more restrictive.
995ffd83dbSDimitry Andric   while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
1005ffd83dbSDimitry Andric     if (Result == AR_Available) {
1015ffd83dbSDimitry Andric       if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) {
1025ffd83dbSDimitry Andric         D = TT->getDecl();
1035ffd83dbSDimitry Andric         Result = D->getAvailability(Message);
1045ffd83dbSDimitry Andric         continue;
1055ffd83dbSDimitry Andric       }
1065ffd83dbSDimitry Andric     }
1075ffd83dbSDimitry Andric     break;
1085ffd83dbSDimitry Andric   }
1095ffd83dbSDimitry Andric 
110*0fca6ea1SDimitry Andric   // For alias templates, get the underlying declaration.
111*0fca6ea1SDimitry Andric   if (const auto *ADecl = dyn_cast<TypeAliasTemplateDecl>(D)) {
112*0fca6ea1SDimitry Andric     D = ADecl->getTemplatedDecl();
113*0fca6ea1SDimitry Andric     Result = D->getAvailability(Message);
114*0fca6ea1SDimitry Andric   }
115*0fca6ea1SDimitry Andric 
1165ffd83dbSDimitry Andric   // Forward class declarations get their attributes from their definition.
1175ffd83dbSDimitry Andric   if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
1185ffd83dbSDimitry Andric     if (IDecl->getDefinition()) {
1195ffd83dbSDimitry Andric       D = IDecl->getDefinition();
1205ffd83dbSDimitry Andric       Result = D->getAvailability(Message);
1215ffd83dbSDimitry Andric     }
1225ffd83dbSDimitry Andric   }
1235ffd83dbSDimitry Andric 
1245ffd83dbSDimitry Andric   if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
1255ffd83dbSDimitry Andric     if (Result == AR_Available) {
1265ffd83dbSDimitry Andric       const DeclContext *DC = ECD->getDeclContext();
1275ffd83dbSDimitry Andric       if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
1285ffd83dbSDimitry Andric         Result = TheEnumDecl->getAvailability(Message);
1295ffd83dbSDimitry Andric         D = TheEnumDecl;
1305ffd83dbSDimitry Andric       }
1315ffd83dbSDimitry Andric     }
1325ffd83dbSDimitry Andric 
1335ffd83dbSDimitry Andric   // For +new, infer availability from -init.
1345ffd83dbSDimitry Andric   if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
135*0fca6ea1SDimitry Andric     if (S.ObjC().NSAPIObj && ClassReceiver) {
1365ffd83dbSDimitry Andric       ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod(
137*0fca6ea1SDimitry Andric           S.ObjC().NSAPIObj->getInitSelector());
1385ffd83dbSDimitry Andric       if (Init && Result == AR_Available && MD->isClassMethod() &&
139*0fca6ea1SDimitry Andric           MD->getSelector() == S.ObjC().NSAPIObj->getNewSelector() &&
1405ffd83dbSDimitry Andric           MD->definedInNSObject(S.getASTContext())) {
1415ffd83dbSDimitry Andric         Result = Init->getAvailability(Message);
1425ffd83dbSDimitry Andric         D = Init;
1435ffd83dbSDimitry Andric       }
1445ffd83dbSDimitry Andric     }
1455ffd83dbSDimitry Andric   }
1465ffd83dbSDimitry Andric 
1475ffd83dbSDimitry Andric   return {Result, D};
1485ffd83dbSDimitry Andric }
1495ffd83dbSDimitry Andric 
1505ffd83dbSDimitry Andric 
1515ffd83dbSDimitry Andric /// whether we should emit a diagnostic for \c K and \c DeclVersion in
1525ffd83dbSDimitry Andric /// the context of \c Ctx. For example, we should emit an unavailable diagnostic
1535ffd83dbSDimitry Andric /// in a deprecated context, but not the other way around.
154*0fca6ea1SDimitry Andric static bool ShouldDiagnoseAvailabilityInContext(
155*0fca6ea1SDimitry Andric     Sema &S, AvailabilityResult K, VersionTuple DeclVersion,
156*0fca6ea1SDimitry Andric     const IdentifierInfo *DeclEnv, Decl *Ctx, const NamedDecl *OffendingDecl) {
1575ffd83dbSDimitry Andric   assert(K != AR_Available && "Expected an unavailable declaration here!");
1585ffd83dbSDimitry Andric 
1598a4dda33SDimitry Andric   // If this was defined using CF_OPTIONS, etc. then ignore the diagnostic.
1608a4dda33SDimitry Andric   auto DeclLoc = Ctx->getBeginLoc();
1618a4dda33SDimitry Andric   // This is only a problem in Foundation's C++ implementation for CF_OPTIONS.
1628a4dda33SDimitry Andric   if (DeclLoc.isMacroID() && S.getLangOpts().CPlusPlus &&
1638a4dda33SDimitry Andric       isa<TypedefDecl>(OffendingDecl)) {
1648a4dda33SDimitry Andric     StringRef MacroName = S.getPreprocessor().getImmediateMacroName(DeclLoc);
1658a4dda33SDimitry Andric     if (MacroName == "CF_OPTIONS" || MacroName == "OBJC_OPTIONS" ||
1668a4dda33SDimitry Andric         MacroName == "SWIFT_OPTIONS" || MacroName == "NS_OPTIONS") {
1678a4dda33SDimitry Andric       return false;
1688a4dda33SDimitry Andric     }
1698a4dda33SDimitry Andric   }
1708a4dda33SDimitry Andric 
171*0fca6ea1SDimitry Andric   // In HLSL, skip emitting diagnostic if the diagnostic mode is not set to
172*0fca6ea1SDimitry Andric   // strict (-fhlsl-strict-availability), or if the target is library and the
173*0fca6ea1SDimitry Andric   // availability is restricted to a specific environment/shader stage.
174*0fca6ea1SDimitry Andric   // For libraries the availability will be checked later in
175*0fca6ea1SDimitry Andric   // DiagnoseHLSLAvailability class once where the specific environment/shader
176*0fca6ea1SDimitry Andric   // stage of the caller is known.
177*0fca6ea1SDimitry Andric   if (S.getLangOpts().HLSL) {
178*0fca6ea1SDimitry Andric     if (!S.getLangOpts().HLSLStrictAvailability ||
179*0fca6ea1SDimitry Andric         (DeclEnv != nullptr &&
180*0fca6ea1SDimitry Andric          S.getASTContext().getTargetInfo().getTriple().getEnvironment() ==
181*0fca6ea1SDimitry Andric              llvm::Triple::EnvironmentType::Library))
182*0fca6ea1SDimitry Andric       return false;
183*0fca6ea1SDimitry Andric   }
184*0fca6ea1SDimitry Andric 
1855ffd83dbSDimitry Andric   // Checks if we should emit the availability diagnostic in the context of C.
1865ffd83dbSDimitry Andric   auto CheckContext = [&](const Decl *C) {
1875ffd83dbSDimitry Andric     if (K == AR_NotYetIntroduced) {
1885ffd83dbSDimitry Andric       if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C))
189*0fca6ea1SDimitry Andric         if (AA->getIntroduced() >= DeclVersion &&
190*0fca6ea1SDimitry Andric             AA->getEnvironment() == DeclEnv)
1915ffd83dbSDimitry Andric           return true;
1925ffd83dbSDimitry Andric     } else if (K == AR_Deprecated) {
1935ffd83dbSDimitry Andric       if (C->isDeprecated())
1945ffd83dbSDimitry Andric         return true;
1955ffd83dbSDimitry Andric     } else if (K == AR_Unavailable) {
1965ffd83dbSDimitry Andric       // It is perfectly fine to refer to an 'unavailable' Objective-C method
1975ffd83dbSDimitry Andric       // when it is referenced from within the @implementation itself. In this
1985ffd83dbSDimitry Andric       // context, we interpret unavailable as a form of access control.
1995ffd83dbSDimitry Andric       if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) {
2005ffd83dbSDimitry Andric         if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) {
2015ffd83dbSDimitry Andric           if (MD->getClassInterface() == Impl->getClassInterface())
2025ffd83dbSDimitry Andric             return true;
2035ffd83dbSDimitry Andric         }
2045ffd83dbSDimitry Andric       }
2055ffd83dbSDimitry Andric     }
2065ffd83dbSDimitry Andric 
2075ffd83dbSDimitry Andric     if (C->isUnavailable())
2085ffd83dbSDimitry Andric       return true;
2095ffd83dbSDimitry Andric     return false;
2105ffd83dbSDimitry Andric   };
2115ffd83dbSDimitry Andric 
2125ffd83dbSDimitry Andric   do {
2135ffd83dbSDimitry Andric     if (CheckContext(Ctx))
2145ffd83dbSDimitry Andric       return false;
2155ffd83dbSDimitry Andric 
2165ffd83dbSDimitry Andric     // An implementation implicitly has the availability of the interface.
2175ffd83dbSDimitry Andric     // Unless it is "+load" method.
2185ffd83dbSDimitry Andric     if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx))
2195ffd83dbSDimitry Andric       if (MethodD->isClassMethod() &&
2205ffd83dbSDimitry Andric           MethodD->getSelector().getAsString() == "load")
2215ffd83dbSDimitry Andric         return true;
2225ffd83dbSDimitry Andric 
2235ffd83dbSDimitry Andric     if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) {
2245ffd83dbSDimitry Andric       if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface())
2255ffd83dbSDimitry Andric         if (CheckContext(Interface))
2265ffd83dbSDimitry Andric           return false;
2275ffd83dbSDimitry Andric     }
2285ffd83dbSDimitry Andric     // A category implicitly has the availability of the interface.
2295ffd83dbSDimitry Andric     else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx))
2305ffd83dbSDimitry Andric       if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface())
2315ffd83dbSDimitry Andric         if (CheckContext(Interface))
2325ffd83dbSDimitry Andric           return false;
2335ffd83dbSDimitry Andric   } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext())));
2345ffd83dbSDimitry Andric 
2355ffd83dbSDimitry Andric   return true;
2365ffd83dbSDimitry Andric }
2375ffd83dbSDimitry Andric 
238*0fca6ea1SDimitry Andric static unsigned getAvailabilityDiagnosticKind(
239*0fca6ea1SDimitry Andric     const ASTContext &Context, const VersionTuple &DeploymentVersion,
240*0fca6ea1SDimitry Andric     const VersionTuple &DeclVersion, bool HasMatchingEnv) {
2415ffd83dbSDimitry Andric   const auto &Triple = Context.getTargetInfo().getTriple();
2425ffd83dbSDimitry Andric   VersionTuple ForceAvailabilityFromVersion;
2435ffd83dbSDimitry Andric   switch (Triple.getOS()) {
244*0fca6ea1SDimitry Andric   // For iOS, emit the diagnostic even if -Wunguarded-availability is
245*0fca6ea1SDimitry Andric   // not specified for deployment targets >= to iOS 11 or equivalent or
246*0fca6ea1SDimitry Andric   // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
247*0fca6ea1SDimitry Andric   // later.
2485ffd83dbSDimitry Andric   case llvm::Triple::IOS:
2495ffd83dbSDimitry Andric   case llvm::Triple::TvOS:
2505ffd83dbSDimitry Andric     ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11);
2515ffd83dbSDimitry Andric     break;
2525ffd83dbSDimitry Andric   case llvm::Triple::WatchOS:
2535ffd83dbSDimitry Andric     ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4);
2545ffd83dbSDimitry Andric     break;
2555ffd83dbSDimitry Andric   case llvm::Triple::Darwin:
2565ffd83dbSDimitry Andric   case llvm::Triple::MacOSX:
2575ffd83dbSDimitry Andric     ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
2585ffd83dbSDimitry Andric     break;
259*0fca6ea1SDimitry Andric   // For HLSL, use diagnostic from HLSLAvailability group which
260*0fca6ea1SDimitry Andric   // are reported as errors by default and in strict diagnostic mode
261*0fca6ea1SDimitry Andric   // (-fhlsl-strict-availability) and as warnings in relaxed diagnostic
262*0fca6ea1SDimitry Andric   // mode (-Wno-error=hlsl-availability)
263bdd1243dSDimitry Andric   case llvm::Triple::ShaderModel:
264*0fca6ea1SDimitry Andric     return HasMatchingEnv ? diag::warn_hlsl_availability
265*0fca6ea1SDimitry Andric                           : diag::warn_hlsl_availability_unavailable;
2665ffd83dbSDimitry Andric   default:
267*0fca6ea1SDimitry Andric     // New Apple targets should always warn about availability.
268*0fca6ea1SDimitry Andric     ForceAvailabilityFromVersion =
269*0fca6ea1SDimitry Andric         (Triple.getVendor() == llvm::Triple::Apple)
270*0fca6ea1SDimitry Andric             ? VersionTuple(/*Major=*/0, 0)
271*0fca6ea1SDimitry Andric             : VersionTuple(/*Major=*/(unsigned)-1, (unsigned)-1);
2725ffd83dbSDimitry Andric   }
273*0fca6ea1SDimitry Andric   if (DeploymentVersion >= ForceAvailabilityFromVersion ||
274*0fca6ea1SDimitry Andric       DeclVersion >= ForceAvailabilityFromVersion)
275*0fca6ea1SDimitry Andric     return HasMatchingEnv ? diag::warn_unguarded_availability_new
276*0fca6ea1SDimitry Andric                           : diag::warn_unguarded_availability_unavailable_new;
277*0fca6ea1SDimitry Andric   return HasMatchingEnv ? diag::warn_unguarded_availability
278*0fca6ea1SDimitry Andric                         : diag::warn_unguarded_availability_unavailable;
2795ffd83dbSDimitry Andric }
2805ffd83dbSDimitry Andric 
2815ffd83dbSDimitry Andric static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) {
2825ffd83dbSDimitry Andric   for (Decl *Ctx = OrigCtx; Ctx;
2835ffd83dbSDimitry Andric        Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
2845ffd83dbSDimitry Andric     if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
2855ffd83dbSDimitry Andric       return cast<NamedDecl>(Ctx);
2865ffd83dbSDimitry Andric     if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
2875ffd83dbSDimitry Andric       if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
2885ffd83dbSDimitry Andric         return Imp->getClassInterface();
2895ffd83dbSDimitry Andric       return CD;
2905ffd83dbSDimitry Andric     }
2915ffd83dbSDimitry Andric   }
2925ffd83dbSDimitry Andric 
2935ffd83dbSDimitry Andric   return dyn_cast<NamedDecl>(OrigCtx);
2945ffd83dbSDimitry Andric }
2955ffd83dbSDimitry Andric 
2965ffd83dbSDimitry Andric namespace {
2975ffd83dbSDimitry Andric 
2985ffd83dbSDimitry Andric struct AttributeInsertion {
2995ffd83dbSDimitry Andric   StringRef Prefix;
3005ffd83dbSDimitry Andric   SourceLocation Loc;
3015ffd83dbSDimitry Andric   StringRef Suffix;
3025ffd83dbSDimitry Andric 
3035ffd83dbSDimitry Andric   static AttributeInsertion createInsertionAfter(const NamedDecl *D) {
3045ffd83dbSDimitry Andric     return {" ", D->getEndLoc(), ""};
3055ffd83dbSDimitry Andric   }
3065ffd83dbSDimitry Andric   static AttributeInsertion createInsertionAfter(SourceLocation Loc) {
3075ffd83dbSDimitry Andric     return {" ", Loc, ""};
3085ffd83dbSDimitry Andric   }
3095ffd83dbSDimitry Andric   static AttributeInsertion createInsertionBefore(const NamedDecl *D) {
3105ffd83dbSDimitry Andric     return {"", D->getBeginLoc(), "\n"};
3115ffd83dbSDimitry Andric   }
3125ffd83dbSDimitry Andric };
3135ffd83dbSDimitry Andric 
3145ffd83dbSDimitry Andric } // end anonymous namespace
3155ffd83dbSDimitry Andric 
3165ffd83dbSDimitry Andric /// Tries to parse a string as ObjC method name.
3175ffd83dbSDimitry Andric ///
3185ffd83dbSDimitry Andric /// \param Name The string to parse. Expected to originate from availability
3195ffd83dbSDimitry Andric /// attribute argument.
3205ffd83dbSDimitry Andric /// \param SlotNames The vector that will be populated with slot names. In case
3215ffd83dbSDimitry Andric /// of unsuccessful parsing can contain invalid data.
322bdd1243dSDimitry Andric /// \returns A number of method parameters if parsing was successful,
323bdd1243dSDimitry Andric /// std::nullopt otherwise.
324bdd1243dSDimitry Andric static std::optional<unsigned>
3255ffd83dbSDimitry Andric tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames,
3265ffd83dbSDimitry Andric                        const LangOptions &LangOpts) {
3275ffd83dbSDimitry Andric   // Accept replacements starting with - or + as valid ObjC method names.
3285ffd83dbSDimitry Andric   if (!Name.empty() && (Name.front() == '-' || Name.front() == '+'))
3295ffd83dbSDimitry Andric     Name = Name.drop_front(1);
3305ffd83dbSDimitry Andric   if (Name.empty())
331bdd1243dSDimitry Andric     return std::nullopt;
3325ffd83dbSDimitry Andric   Name.split(SlotNames, ':');
3335ffd83dbSDimitry Andric   unsigned NumParams;
3345ffd83dbSDimitry Andric   if (Name.back() == ':') {
3355ffd83dbSDimitry Andric     // Remove an empty string at the end that doesn't represent any slot.
3365ffd83dbSDimitry Andric     SlotNames.pop_back();
3375ffd83dbSDimitry Andric     NumParams = SlotNames.size();
3385ffd83dbSDimitry Andric   } else {
3395ffd83dbSDimitry Andric     if (SlotNames.size() != 1)
3405ffd83dbSDimitry Andric       // Not a valid method name, just a colon-separated string.
341bdd1243dSDimitry Andric       return std::nullopt;
3425ffd83dbSDimitry Andric     NumParams = 0;
3435ffd83dbSDimitry Andric   }
3445ffd83dbSDimitry Andric   // Verify all slot names are valid.
3455ffd83dbSDimitry Andric   bool AllowDollar = LangOpts.DollarIdents;
3465ffd83dbSDimitry Andric   for (StringRef S : SlotNames) {
3475ffd83dbSDimitry Andric     if (S.empty())
3485ffd83dbSDimitry Andric       continue;
349349cc55cSDimitry Andric     if (!isValidAsciiIdentifier(S, AllowDollar))
350bdd1243dSDimitry Andric       return std::nullopt;
3515ffd83dbSDimitry Andric   }
3525ffd83dbSDimitry Andric   return NumParams;
3535ffd83dbSDimitry Andric }
3545ffd83dbSDimitry Andric 
3555ffd83dbSDimitry Andric /// Returns a source location in which it's appropriate to insert a new
3565ffd83dbSDimitry Andric /// attribute for the given declaration \D.
357bdd1243dSDimitry Andric static std::optional<AttributeInsertion>
3585ffd83dbSDimitry Andric createAttributeInsertion(const NamedDecl *D, const SourceManager &SM,
3595ffd83dbSDimitry Andric                          const LangOptions &LangOpts) {
3605ffd83dbSDimitry Andric   if (isa<ObjCPropertyDecl>(D))
3615ffd83dbSDimitry Andric     return AttributeInsertion::createInsertionAfter(D);
3625ffd83dbSDimitry Andric   if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
3635ffd83dbSDimitry Andric     if (MD->hasBody())
364bdd1243dSDimitry Andric       return std::nullopt;
3655ffd83dbSDimitry Andric     return AttributeInsertion::createInsertionAfter(D);
3665ffd83dbSDimitry Andric   }
3675ffd83dbSDimitry Andric   if (const auto *TD = dyn_cast<TagDecl>(D)) {
3685ffd83dbSDimitry Andric     SourceLocation Loc =
3695ffd83dbSDimitry Andric         Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts);
3705ffd83dbSDimitry Andric     if (Loc.isInvalid())
371bdd1243dSDimitry Andric       return std::nullopt;
3725ffd83dbSDimitry Andric     // Insert after the 'struct'/whatever keyword.
3735ffd83dbSDimitry Andric     return AttributeInsertion::createInsertionAfter(Loc);
3745ffd83dbSDimitry Andric   }
3755ffd83dbSDimitry Andric   return AttributeInsertion::createInsertionBefore(D);
3765ffd83dbSDimitry Andric }
3775ffd83dbSDimitry Andric 
3785ffd83dbSDimitry Andric /// Actually emit an availability diagnostic for a reference to an unavailable
3795ffd83dbSDimitry Andric /// decl.
3805ffd83dbSDimitry Andric ///
3815ffd83dbSDimitry Andric /// \param Ctx The context that the reference occurred in
3825ffd83dbSDimitry Andric /// \param ReferringDecl The exact declaration that was referenced.
3835ffd83dbSDimitry Andric /// \param OffendingDecl A related decl to \c ReferringDecl that has an
3845ffd83dbSDimitry Andric /// availability attribute corresponding to \c K attached to it. Note that this
3855ffd83dbSDimitry Andric /// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
3865ffd83dbSDimitry Andric /// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
3875ffd83dbSDimitry Andric /// and OffendingDecl is the EnumDecl.
3885ffd83dbSDimitry Andric static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
3895ffd83dbSDimitry Andric                                       Decl *Ctx, const NamedDecl *ReferringDecl,
3905ffd83dbSDimitry Andric                                       const NamedDecl *OffendingDecl,
3915ffd83dbSDimitry Andric                                       StringRef Message,
3925ffd83dbSDimitry Andric                                       ArrayRef<SourceLocation> Locs,
3935ffd83dbSDimitry Andric                                       const ObjCInterfaceDecl *UnknownObjCClass,
3945ffd83dbSDimitry Andric                                       const ObjCPropertyDecl *ObjCProperty,
3955ffd83dbSDimitry Andric                                       bool ObjCPropertyAccess) {
3965ffd83dbSDimitry Andric   // Diagnostics for deprecated or unavailable.
3975ffd83dbSDimitry Andric   unsigned diag, diag_message, diag_fwdclass_message;
3985ffd83dbSDimitry Andric   unsigned diag_available_here = diag::note_availability_specified_here;
3995ffd83dbSDimitry Andric   SourceLocation NoteLocation = OffendingDecl->getLocation();
4005ffd83dbSDimitry Andric 
4015ffd83dbSDimitry Andric   // Matches 'diag::note_property_attribute' options.
4025ffd83dbSDimitry Andric   unsigned property_note_select;
4035ffd83dbSDimitry Andric 
4045ffd83dbSDimitry Andric   // Matches diag::note_availability_specified_here.
4055ffd83dbSDimitry Andric   unsigned available_here_select_kind;
4065ffd83dbSDimitry Andric 
4075ffd83dbSDimitry Andric   VersionTuple DeclVersion;
408*0fca6ea1SDimitry Andric   const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl);
409*0fca6ea1SDimitry Andric   const IdentifierInfo *IIEnv = nullptr;
410*0fca6ea1SDimitry Andric   if (AA) {
4115ffd83dbSDimitry Andric     DeclVersion = AA->getIntroduced();
412*0fca6ea1SDimitry Andric     IIEnv = AA->getEnvironment();
413*0fca6ea1SDimitry Andric   }
4145ffd83dbSDimitry Andric 
415*0fca6ea1SDimitry Andric   if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, IIEnv, Ctx,
4165ffd83dbSDimitry Andric                                            OffendingDecl))
4175ffd83dbSDimitry Andric     return;
4185ffd83dbSDimitry Andric 
4195ffd83dbSDimitry Andric   SourceLocation Loc = Locs.front();
4205ffd83dbSDimitry Andric 
4215ffd83dbSDimitry Andric   // The declaration can have multiple availability attributes, we are looking
4225ffd83dbSDimitry Andric   // at one of them.
423*0fca6ea1SDimitry Andric   if (AA && AA->isInherited()) {
4245ffd83dbSDimitry Andric     for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
4255ffd83dbSDimitry Andric          Redecl = Redecl->getPreviousDecl()) {
4265ffd83dbSDimitry Andric       const AvailabilityAttr *AForRedecl =
4275ffd83dbSDimitry Andric           getAttrForPlatform(S.Context, Redecl);
4285ffd83dbSDimitry Andric       if (AForRedecl && !AForRedecl->isInherited()) {
4295ffd83dbSDimitry Andric         // If D is a declaration with inherited attributes, the note should
4305ffd83dbSDimitry Andric         // point to the declaration with actual attributes.
4315ffd83dbSDimitry Andric         NoteLocation = Redecl->getLocation();
4325ffd83dbSDimitry Andric         break;
4335ffd83dbSDimitry Andric       }
4345ffd83dbSDimitry Andric     }
4355ffd83dbSDimitry Andric   }
4365ffd83dbSDimitry Andric 
4375ffd83dbSDimitry Andric   switch (K) {
4385ffd83dbSDimitry Andric   case AR_NotYetIntroduced: {
4395ffd83dbSDimitry Andric     // We would like to emit the diagnostic even if -Wunguarded-availability is
4405ffd83dbSDimitry Andric     // not specified for deployment targets >= to iOS 11 or equivalent or
4415ffd83dbSDimitry Andric     // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
4425ffd83dbSDimitry Andric     // later.
443*0fca6ea1SDimitry Andric     assert(AA != nullptr && "expecting valid availability attribute");
4445ffd83dbSDimitry Andric     VersionTuple Introduced = AA->getIntroduced();
445*0fca6ea1SDimitry Andric     bool EnvironmentMatchesOrNone =
446*0fca6ea1SDimitry Andric         hasMatchingEnvironmentOrNone(S.getASTContext(), AA);
4475ffd83dbSDimitry Andric 
448*0fca6ea1SDimitry Andric     const TargetInfo &TI = S.getASTContext().getTargetInfo();
449*0fca6ea1SDimitry Andric     std::string PlatformName(
450*0fca6ea1SDimitry Andric         AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
451*0fca6ea1SDimitry Andric     llvm::StringRef TargetEnvironment(
452*0fca6ea1SDimitry Andric         llvm::Triple::getEnvironmentTypeName(TI.getTriple().getEnvironment()));
453*0fca6ea1SDimitry Andric     llvm::StringRef AttrEnvironment =
454*0fca6ea1SDimitry Andric         AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
455*0fca6ea1SDimitry Andric     bool UseEnvironment =
456*0fca6ea1SDimitry Andric         (!AttrEnvironment.empty() && !TargetEnvironment.empty());
457*0fca6ea1SDimitry Andric 
458*0fca6ea1SDimitry Andric     unsigned DiagKind = getAvailabilityDiagnosticKind(
4595ffd83dbSDimitry Andric         S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
460*0fca6ea1SDimitry Andric         Introduced, EnvironmentMatchesOrNone);
4615ffd83dbSDimitry Andric 
462*0fca6ea1SDimitry Andric     S.Diag(Loc, DiagKind) << OffendingDecl << PlatformName
463*0fca6ea1SDimitry Andric                           << Introduced.getAsString() << UseEnvironment
464*0fca6ea1SDimitry Andric                           << TargetEnvironment;
4655ffd83dbSDimitry Andric 
4665ffd83dbSDimitry Andric     S.Diag(OffendingDecl->getLocation(),
4675ffd83dbSDimitry Andric            diag::note_partial_availability_specified_here)
4685ffd83dbSDimitry Andric         << OffendingDecl << PlatformName << Introduced.getAsString()
469*0fca6ea1SDimitry Andric         << S.Context.getTargetInfo().getPlatformMinVersion().getAsString()
470*0fca6ea1SDimitry Andric         << UseEnvironment << AttrEnvironment << TargetEnvironment;
471*0fca6ea1SDimitry Andric 
472*0fca6ea1SDimitry Andric     // Do not offer to silence the warning or fixits for HLSL
473*0fca6ea1SDimitry Andric     if (S.getLangOpts().HLSL)
474*0fca6ea1SDimitry Andric       return;
4755ffd83dbSDimitry Andric 
4765ffd83dbSDimitry Andric     if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
4775ffd83dbSDimitry Andric       if (const auto *TD = dyn_cast<TagDecl>(Enclosing))
4785ffd83dbSDimitry Andric         if (TD->getDeclName().isEmpty()) {
4795ffd83dbSDimitry Andric           S.Diag(TD->getLocation(),
4805ffd83dbSDimitry Andric                  diag::note_decl_unguarded_availability_silence)
4815ffd83dbSDimitry Andric               << /*Anonymous*/ 1 << TD->getKindName();
4825ffd83dbSDimitry Andric           return;
4835ffd83dbSDimitry Andric         }
4845ffd83dbSDimitry Andric       auto FixitNoteDiag =
4855ffd83dbSDimitry Andric           S.Diag(Enclosing->getLocation(),
4865ffd83dbSDimitry Andric                  diag::note_decl_unguarded_availability_silence)
4875ffd83dbSDimitry Andric           << /*Named*/ 0 << Enclosing;
4885ffd83dbSDimitry Andric       // Don't offer a fixit for declarations with availability attributes.
4895ffd83dbSDimitry Andric       if (Enclosing->hasAttr<AvailabilityAttr>())
4905ffd83dbSDimitry Andric         return;
4915ffd83dbSDimitry Andric       if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
4925ffd83dbSDimitry Andric         return;
493bdd1243dSDimitry Andric       std::optional<AttributeInsertion> Insertion = createAttributeInsertion(
4945ffd83dbSDimitry Andric           Enclosing, S.getSourceManager(), S.getLangOpts());
4955ffd83dbSDimitry Andric       if (!Insertion)
4965ffd83dbSDimitry Andric         return;
4975ffd83dbSDimitry Andric       std::string PlatformName =
4985ffd83dbSDimitry Andric           AvailabilityAttr::getPlatformNameSourceSpelling(
4995ffd83dbSDimitry Andric               S.getASTContext().getTargetInfo().getPlatformName())
5005ffd83dbSDimitry Andric               .lower();
5015ffd83dbSDimitry Andric       std::string Introduced =
5025ffd83dbSDimitry Andric           OffendingDecl->getVersionIntroduced().getAsString();
5035ffd83dbSDimitry Andric       FixitNoteDiag << FixItHint::CreateInsertion(
5045ffd83dbSDimitry Andric           Insertion->Loc,
5055ffd83dbSDimitry Andric           (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName +
5065ffd83dbSDimitry Andric            "(" + Introduced + "))" + Insertion->Suffix)
5075ffd83dbSDimitry Andric               .str());
5085ffd83dbSDimitry Andric     }
5095ffd83dbSDimitry Andric     return;
5105ffd83dbSDimitry Andric   }
5115ffd83dbSDimitry Andric   case AR_Deprecated:
5125ffd83dbSDimitry Andric     diag = !ObjCPropertyAccess ? diag::warn_deprecated
5135ffd83dbSDimitry Andric                                : diag::warn_property_method_deprecated;
5145ffd83dbSDimitry Andric     diag_message = diag::warn_deprecated_message;
5155ffd83dbSDimitry Andric     diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
5165ffd83dbSDimitry Andric     property_note_select = /* deprecated */ 0;
5175ffd83dbSDimitry Andric     available_here_select_kind = /* deprecated */ 2;
5185ffd83dbSDimitry Andric     if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>())
5195ffd83dbSDimitry Andric       NoteLocation = AL->getLocation();
5205ffd83dbSDimitry Andric     break;
5215ffd83dbSDimitry Andric 
5225ffd83dbSDimitry Andric   case AR_Unavailable:
5235ffd83dbSDimitry Andric     diag = !ObjCPropertyAccess ? diag::err_unavailable
5245ffd83dbSDimitry Andric                                : diag::err_property_method_unavailable;
5255ffd83dbSDimitry Andric     diag_message = diag::err_unavailable_message;
5265ffd83dbSDimitry Andric     diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
5275ffd83dbSDimitry Andric     property_note_select = /* unavailable */ 1;
5285ffd83dbSDimitry Andric     available_here_select_kind = /* unavailable */ 0;
5295ffd83dbSDimitry Andric 
5305ffd83dbSDimitry Andric     if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) {
5315ffd83dbSDimitry Andric       if (AL->isImplicit() && AL->getImplicitReason()) {
5325ffd83dbSDimitry Andric         // Most of these failures are due to extra restrictions in ARC;
5335ffd83dbSDimitry Andric         // reflect that in the primary diagnostic when applicable.
5345ffd83dbSDimitry Andric         auto flagARCError = [&] {
5355ffd83dbSDimitry Andric           if (S.getLangOpts().ObjCAutoRefCount &&
5365ffd83dbSDimitry Andric               S.getSourceManager().isInSystemHeader(
5375ffd83dbSDimitry Andric                   OffendingDecl->getLocation()))
5385ffd83dbSDimitry Andric             diag = diag::err_unavailable_in_arc;
5395ffd83dbSDimitry Andric         };
5405ffd83dbSDimitry Andric 
5415ffd83dbSDimitry Andric         switch (AL->getImplicitReason()) {
5425ffd83dbSDimitry Andric         case UnavailableAttr::IR_None: break;
5435ffd83dbSDimitry Andric 
5445ffd83dbSDimitry Andric         case UnavailableAttr::IR_ARCForbiddenType:
5455ffd83dbSDimitry Andric           flagARCError();
5465ffd83dbSDimitry Andric           diag_available_here = diag::note_arc_forbidden_type;
5475ffd83dbSDimitry Andric           break;
5485ffd83dbSDimitry Andric 
5495ffd83dbSDimitry Andric         case UnavailableAttr::IR_ForbiddenWeak:
5505ffd83dbSDimitry Andric           if (S.getLangOpts().ObjCWeakRuntime)
5515ffd83dbSDimitry Andric             diag_available_here = diag::note_arc_weak_disabled;
5525ffd83dbSDimitry Andric           else
5535ffd83dbSDimitry Andric             diag_available_here = diag::note_arc_weak_no_runtime;
5545ffd83dbSDimitry Andric           break;
5555ffd83dbSDimitry Andric 
5565ffd83dbSDimitry Andric         case UnavailableAttr::IR_ARCForbiddenConversion:
5575ffd83dbSDimitry Andric           flagARCError();
5585ffd83dbSDimitry Andric           diag_available_here = diag::note_performs_forbidden_arc_conversion;
5595ffd83dbSDimitry Andric           break;
5605ffd83dbSDimitry Andric 
5615ffd83dbSDimitry Andric         case UnavailableAttr::IR_ARCInitReturnsUnrelated:
5625ffd83dbSDimitry Andric           flagARCError();
5635ffd83dbSDimitry Andric           diag_available_here = diag::note_arc_init_returns_unrelated;
5645ffd83dbSDimitry Andric           break;
5655ffd83dbSDimitry Andric 
5665ffd83dbSDimitry Andric         case UnavailableAttr::IR_ARCFieldWithOwnership:
5675ffd83dbSDimitry Andric           flagARCError();
5685ffd83dbSDimitry Andric           diag_available_here = diag::note_arc_field_with_ownership;
5695ffd83dbSDimitry Andric           break;
5705ffd83dbSDimitry Andric         }
5715ffd83dbSDimitry Andric       }
5725ffd83dbSDimitry Andric     }
5735ffd83dbSDimitry Andric     break;
5745ffd83dbSDimitry Andric 
5755ffd83dbSDimitry Andric   case AR_Available:
5765ffd83dbSDimitry Andric     llvm_unreachable("Warning for availability of available declaration?");
5775ffd83dbSDimitry Andric   }
5785ffd83dbSDimitry Andric 
5795ffd83dbSDimitry Andric   SmallVector<FixItHint, 12> FixIts;
5805ffd83dbSDimitry Andric   if (K == AR_Deprecated) {
5815ffd83dbSDimitry Andric     StringRef Replacement;
5825ffd83dbSDimitry Andric     if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>())
5835ffd83dbSDimitry Andric       Replacement = AL->getReplacement();
5845ffd83dbSDimitry Andric     if (auto AL = getAttrForPlatform(S.Context, OffendingDecl))
5855ffd83dbSDimitry Andric       Replacement = AL->getReplacement();
5865ffd83dbSDimitry Andric 
5875ffd83dbSDimitry Andric     CharSourceRange UseRange;
5885ffd83dbSDimitry Andric     if (!Replacement.empty())
5895ffd83dbSDimitry Andric       UseRange =
5905ffd83dbSDimitry Andric           CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc));
5915ffd83dbSDimitry Andric     if (UseRange.isValid()) {
5925ffd83dbSDimitry Andric       if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) {
5935ffd83dbSDimitry Andric         Selector Sel = MethodDecl->getSelector();
5945ffd83dbSDimitry Andric         SmallVector<StringRef, 12> SelectorSlotNames;
595bdd1243dSDimitry Andric         std::optional<unsigned> NumParams = tryParseObjCMethodName(
5965ffd83dbSDimitry Andric             Replacement, SelectorSlotNames, S.getLangOpts());
59781ad6265SDimitry Andric         if (NumParams && *NumParams == Sel.getNumArgs()) {
5985ffd83dbSDimitry Andric           assert(SelectorSlotNames.size() == Locs.size());
5995ffd83dbSDimitry Andric           for (unsigned I = 0; I < Locs.size(); ++I) {
6005ffd83dbSDimitry Andric             if (!Sel.getNameForSlot(I).empty()) {
6015ffd83dbSDimitry Andric               CharSourceRange NameRange = CharSourceRange::getCharRange(
6025ffd83dbSDimitry Andric                   Locs[I], S.getLocForEndOfToken(Locs[I]));
6035ffd83dbSDimitry Andric               FixIts.push_back(FixItHint::CreateReplacement(
6045ffd83dbSDimitry Andric                   NameRange, SelectorSlotNames[I]));
6055ffd83dbSDimitry Andric             } else
6065ffd83dbSDimitry Andric               FixIts.push_back(
6075ffd83dbSDimitry Andric                   FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I]));
6085ffd83dbSDimitry Andric           }
6095ffd83dbSDimitry Andric         } else
6105ffd83dbSDimitry Andric           FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
6115ffd83dbSDimitry Andric       } else
6125ffd83dbSDimitry Andric         FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
6135ffd83dbSDimitry Andric     }
6145ffd83dbSDimitry Andric   }
6155ffd83dbSDimitry Andric 
6165f757f3fSDimitry Andric   // We emit deprecation warning for deprecated specializations
6175f757f3fSDimitry Andric   // when their instantiation stacks originate outside
6185f757f3fSDimitry Andric   // of a system header, even if the diagnostics is suppresed at the
6195f757f3fSDimitry Andric   // point of definition.
6205f757f3fSDimitry Andric   SourceLocation InstantiationLoc =
6215f757f3fSDimitry Andric       S.getTopMostPointOfInstantiation(ReferringDecl);
6225f757f3fSDimitry Andric   bool ShouldAllowWarningInSystemHeader =
6235f757f3fSDimitry Andric       InstantiationLoc != Loc &&
6245f757f3fSDimitry Andric       !S.getSourceManager().isInSystemHeader(InstantiationLoc);
6255f757f3fSDimitry Andric   struct AllowWarningInSystemHeaders {
6265f757f3fSDimitry Andric     AllowWarningInSystemHeaders(DiagnosticsEngine &E,
6275f757f3fSDimitry Andric                                 bool AllowWarningInSystemHeaders)
6285f757f3fSDimitry Andric         : Engine(E), Prev(E.getSuppressSystemWarnings()) {
6295f757f3fSDimitry Andric       E.setSuppressSystemWarnings(!AllowWarningInSystemHeaders);
6305f757f3fSDimitry Andric     }
6315f757f3fSDimitry Andric     ~AllowWarningInSystemHeaders() { Engine.setSuppressSystemWarnings(Prev); }
6325f757f3fSDimitry Andric 
6335f757f3fSDimitry Andric   private:
6345f757f3fSDimitry Andric     DiagnosticsEngine &Engine;
6355f757f3fSDimitry Andric     bool Prev;
6365f757f3fSDimitry Andric   } SystemWarningOverrideRAII(S.getDiagnostics(),
6375f757f3fSDimitry Andric                               ShouldAllowWarningInSystemHeader);
6385f757f3fSDimitry Andric 
6395ffd83dbSDimitry Andric   if (!Message.empty()) {
6405ffd83dbSDimitry Andric     S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts;
6415ffd83dbSDimitry Andric     if (ObjCProperty)
6425ffd83dbSDimitry Andric       S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
6435ffd83dbSDimitry Andric           << ObjCProperty->getDeclName() << property_note_select;
6445ffd83dbSDimitry Andric   } else if (!UnknownObjCClass) {
6455ffd83dbSDimitry Andric     S.Diag(Loc, diag) << ReferringDecl << FixIts;
6465ffd83dbSDimitry Andric     if (ObjCProperty)
6475ffd83dbSDimitry Andric       S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
6485ffd83dbSDimitry Andric           << ObjCProperty->getDeclName() << property_note_select;
6495ffd83dbSDimitry Andric   } else {
6505ffd83dbSDimitry Andric     S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts;
6515ffd83dbSDimitry Andric     S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
6525ffd83dbSDimitry Andric   }
6535ffd83dbSDimitry Andric 
6545ffd83dbSDimitry Andric   S.Diag(NoteLocation, diag_available_here)
6555ffd83dbSDimitry Andric     << OffendingDecl << available_here_select_kind;
6565ffd83dbSDimitry Andric }
6575ffd83dbSDimitry Andric 
6585ffd83dbSDimitry Andric void Sema::handleDelayedAvailabilityCheck(DelayedDiagnostic &DD, Decl *Ctx) {
6595ffd83dbSDimitry Andric   assert(DD.Kind == DelayedDiagnostic::Availability &&
6605ffd83dbSDimitry Andric          "Expected an availability diagnostic here");
6615ffd83dbSDimitry Andric 
6625ffd83dbSDimitry Andric   DD.Triggered = true;
6635ffd83dbSDimitry Andric   DoEmitAvailabilityWarning(
6645ffd83dbSDimitry Andric       *this, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(),
6655ffd83dbSDimitry Andric       DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(),
6665ffd83dbSDimitry Andric       DD.getAvailabilitySelectorLocs(), DD.getUnknownObjCClass(),
6675ffd83dbSDimitry Andric       DD.getObjCProperty(), false);
6685ffd83dbSDimitry Andric }
6695ffd83dbSDimitry Andric 
6705ffd83dbSDimitry Andric static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR,
6715ffd83dbSDimitry Andric                                     const NamedDecl *ReferringDecl,
6725ffd83dbSDimitry Andric                                     const NamedDecl *OffendingDecl,
6735ffd83dbSDimitry Andric                                     StringRef Message,
6745ffd83dbSDimitry Andric                                     ArrayRef<SourceLocation> Locs,
6755ffd83dbSDimitry Andric                                     const ObjCInterfaceDecl *UnknownObjCClass,
6765ffd83dbSDimitry Andric                                     const ObjCPropertyDecl *ObjCProperty,
6775ffd83dbSDimitry Andric                                     bool ObjCPropertyAccess) {
6785ffd83dbSDimitry Andric   // Delay if we're currently parsing a declaration.
6795ffd83dbSDimitry Andric   if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
6805ffd83dbSDimitry Andric     S.DelayedDiagnostics.add(
6815ffd83dbSDimitry Andric         DelayedDiagnostic::makeAvailability(
6825ffd83dbSDimitry Andric             AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass,
6835ffd83dbSDimitry Andric             ObjCProperty, Message, ObjCPropertyAccess));
6845ffd83dbSDimitry Andric     return;
6855ffd83dbSDimitry Andric   }
6865ffd83dbSDimitry Andric 
6875ffd83dbSDimitry Andric   Decl *Ctx = cast<Decl>(S.getCurLexicalContext());
6885ffd83dbSDimitry Andric   DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl,
6895ffd83dbSDimitry Andric                             Message, Locs, UnknownObjCClass, ObjCProperty,
6905ffd83dbSDimitry Andric                             ObjCPropertyAccess);
6915ffd83dbSDimitry Andric }
6925ffd83dbSDimitry Andric 
6935ffd83dbSDimitry Andric namespace {
6945ffd83dbSDimitry Andric 
6955ffd83dbSDimitry Andric /// Returns true if the given statement can be a body-like child of \p Parent.
6965ffd83dbSDimitry Andric bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {
6975ffd83dbSDimitry Andric   switch (Parent->getStmtClass()) {
6985ffd83dbSDimitry Andric   case Stmt::IfStmtClass:
6995ffd83dbSDimitry Andric     return cast<IfStmt>(Parent)->getThen() == S ||
7005ffd83dbSDimitry Andric            cast<IfStmt>(Parent)->getElse() == S;
7015ffd83dbSDimitry Andric   case Stmt::WhileStmtClass:
7025ffd83dbSDimitry Andric     return cast<WhileStmt>(Parent)->getBody() == S;
7035ffd83dbSDimitry Andric   case Stmt::DoStmtClass:
7045ffd83dbSDimitry Andric     return cast<DoStmt>(Parent)->getBody() == S;
7055ffd83dbSDimitry Andric   case Stmt::ForStmtClass:
7065ffd83dbSDimitry Andric     return cast<ForStmt>(Parent)->getBody() == S;
7075ffd83dbSDimitry Andric   case Stmt::CXXForRangeStmtClass:
7085ffd83dbSDimitry Andric     return cast<CXXForRangeStmt>(Parent)->getBody() == S;
7095ffd83dbSDimitry Andric   case Stmt::ObjCForCollectionStmtClass:
7105ffd83dbSDimitry Andric     return cast<ObjCForCollectionStmt>(Parent)->getBody() == S;
7115ffd83dbSDimitry Andric   case Stmt::CaseStmtClass:
7125ffd83dbSDimitry Andric   case Stmt::DefaultStmtClass:
7135ffd83dbSDimitry Andric     return cast<SwitchCase>(Parent)->getSubStmt() == S;
7145ffd83dbSDimitry Andric   default:
7155ffd83dbSDimitry Andric     return false;
7165ffd83dbSDimitry Andric   }
7175ffd83dbSDimitry Andric }
7185ffd83dbSDimitry Andric 
7195ffd83dbSDimitry Andric class StmtUSEFinder : public RecursiveASTVisitor<StmtUSEFinder> {
7205ffd83dbSDimitry Andric   const Stmt *Target;
7215ffd83dbSDimitry Andric 
7225ffd83dbSDimitry Andric public:
7235ffd83dbSDimitry Andric   bool VisitStmt(Stmt *S) { return S != Target; }
7245ffd83dbSDimitry Andric 
7255ffd83dbSDimitry Andric   /// Returns true if the given statement is present in the given declaration.
7265ffd83dbSDimitry Andric   static bool isContained(const Stmt *Target, const Decl *D) {
7275ffd83dbSDimitry Andric     StmtUSEFinder Visitor;
7285ffd83dbSDimitry Andric     Visitor.Target = Target;
7295ffd83dbSDimitry Andric     return !Visitor.TraverseDecl(const_cast<Decl *>(D));
7305ffd83dbSDimitry Andric   }
7315ffd83dbSDimitry Andric };
7325ffd83dbSDimitry Andric 
7335ffd83dbSDimitry Andric /// Traverses the AST and finds the last statement that used a given
7345ffd83dbSDimitry Andric /// declaration.
7355ffd83dbSDimitry Andric class LastDeclUSEFinder : public RecursiveASTVisitor<LastDeclUSEFinder> {
7365ffd83dbSDimitry Andric   const Decl *D;
7375ffd83dbSDimitry Andric 
7385ffd83dbSDimitry Andric public:
7395ffd83dbSDimitry Andric   bool VisitDeclRefExpr(DeclRefExpr *DRE) {
7405ffd83dbSDimitry Andric     if (DRE->getDecl() == D)
7415ffd83dbSDimitry Andric       return false;
7425ffd83dbSDimitry Andric     return true;
7435ffd83dbSDimitry Andric   }
7445ffd83dbSDimitry Andric 
7455ffd83dbSDimitry Andric   static const Stmt *findLastStmtThatUsesDecl(const Decl *D,
7465ffd83dbSDimitry Andric                                               const CompoundStmt *Scope) {
7475ffd83dbSDimitry Andric     LastDeclUSEFinder Visitor;
7485ffd83dbSDimitry Andric     Visitor.D = D;
749349cc55cSDimitry Andric     for (const Stmt *S : llvm::reverse(Scope->body())) {
7505ffd83dbSDimitry Andric       if (!Visitor.TraverseStmt(const_cast<Stmt *>(S)))
7515ffd83dbSDimitry Andric         return S;
7525ffd83dbSDimitry Andric     }
7535ffd83dbSDimitry Andric     return nullptr;
7545ffd83dbSDimitry Andric   }
7555ffd83dbSDimitry Andric };
7565ffd83dbSDimitry Andric 
7575ffd83dbSDimitry Andric /// This class implements -Wunguarded-availability.
7585ffd83dbSDimitry Andric ///
7595ffd83dbSDimitry Andric /// This is done with a traversal of the AST of a function that makes reference
7605ffd83dbSDimitry Andric /// to a partially available declaration. Whenever we encounter an \c if of the
7615ffd83dbSDimitry Andric /// form: \c if(@available(...)), we use the version from the condition to visit
7625ffd83dbSDimitry Andric /// the then statement.
7635ffd83dbSDimitry Andric class DiagnoseUnguardedAvailability
7645ffd83dbSDimitry Andric     : public RecursiveASTVisitor<DiagnoseUnguardedAvailability> {
7655ffd83dbSDimitry Andric   typedef RecursiveASTVisitor<DiagnoseUnguardedAvailability> Base;
7665ffd83dbSDimitry Andric 
7675ffd83dbSDimitry Andric   Sema &SemaRef;
7685ffd83dbSDimitry Andric   Decl *Ctx;
7695ffd83dbSDimitry Andric 
7705ffd83dbSDimitry Andric   /// Stack of potentially nested 'if (@available(...))'s.
7715ffd83dbSDimitry Andric   SmallVector<VersionTuple, 8> AvailabilityStack;
7725ffd83dbSDimitry Andric   SmallVector<const Stmt *, 16> StmtStack;
7735ffd83dbSDimitry Andric 
7745ffd83dbSDimitry Andric   void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range,
7755ffd83dbSDimitry Andric                                 ObjCInterfaceDecl *ClassReceiver = nullptr);
7765ffd83dbSDimitry Andric 
7775ffd83dbSDimitry Andric public:
7785ffd83dbSDimitry Andric   DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx)
7795ffd83dbSDimitry Andric       : SemaRef(SemaRef), Ctx(Ctx) {
7805ffd83dbSDimitry Andric     AvailabilityStack.push_back(
7815ffd83dbSDimitry Andric         SemaRef.Context.getTargetInfo().getPlatformMinVersion());
7825ffd83dbSDimitry Andric   }
7835ffd83dbSDimitry Andric 
7845ffd83dbSDimitry Andric   bool TraverseStmt(Stmt *S) {
7855ffd83dbSDimitry Andric     if (!S)
7865ffd83dbSDimitry Andric       return true;
7875ffd83dbSDimitry Andric     StmtStack.push_back(S);
7885ffd83dbSDimitry Andric     bool Result = Base::TraverseStmt(S);
7895ffd83dbSDimitry Andric     StmtStack.pop_back();
7905ffd83dbSDimitry Andric     return Result;
7915ffd83dbSDimitry Andric   }
7925ffd83dbSDimitry Andric 
7935ffd83dbSDimitry Andric   void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }
7945ffd83dbSDimitry Andric 
7955ffd83dbSDimitry Andric   bool TraverseIfStmt(IfStmt *If);
7965ffd83dbSDimitry Andric 
7975ffd83dbSDimitry Andric   // for 'case X:' statements, don't bother looking at the 'X'; it can't lead
7985ffd83dbSDimitry Andric   // to any useful diagnostics.
7995ffd83dbSDimitry Andric   bool TraverseCaseStmt(CaseStmt *CS) { return TraverseStmt(CS->getSubStmt()); }
8005ffd83dbSDimitry Andric 
801fe6060f1SDimitry Andric   bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) { return true; }
8025ffd83dbSDimitry Andric 
8035ffd83dbSDimitry Andric   bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) {
8045ffd83dbSDimitry Andric     if (ObjCMethodDecl *D = Msg->getMethodDecl()) {
8055ffd83dbSDimitry Andric       ObjCInterfaceDecl *ID = nullptr;
8065ffd83dbSDimitry Andric       QualType ReceiverTy = Msg->getClassReceiver();
8075ffd83dbSDimitry Andric       if (!ReceiverTy.isNull() && ReceiverTy->getAsObjCInterfaceType())
8085ffd83dbSDimitry Andric         ID = ReceiverTy->getAsObjCInterfaceType()->getInterface();
8095ffd83dbSDimitry Andric 
8105ffd83dbSDimitry Andric       DiagnoseDeclAvailability(
8115ffd83dbSDimitry Andric           D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID);
8125ffd83dbSDimitry Andric     }
8135ffd83dbSDimitry Andric     return true;
8145ffd83dbSDimitry Andric   }
8155ffd83dbSDimitry Andric 
8165ffd83dbSDimitry Andric   bool VisitDeclRefExpr(DeclRefExpr *DRE) {
8175ffd83dbSDimitry Andric     DiagnoseDeclAvailability(DRE->getDecl(),
8185ffd83dbSDimitry Andric                              SourceRange(DRE->getBeginLoc(), DRE->getEndLoc()));
8195ffd83dbSDimitry Andric     return true;
8205ffd83dbSDimitry Andric   }
8215ffd83dbSDimitry Andric 
8225ffd83dbSDimitry Andric   bool VisitMemberExpr(MemberExpr *ME) {
8235ffd83dbSDimitry Andric     DiagnoseDeclAvailability(ME->getMemberDecl(),
8245ffd83dbSDimitry Andric                              SourceRange(ME->getBeginLoc(), ME->getEndLoc()));
8255ffd83dbSDimitry Andric     return true;
8265ffd83dbSDimitry Andric   }
8275ffd83dbSDimitry Andric 
8285ffd83dbSDimitry Andric   bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
8295ffd83dbSDimitry Andric     SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use)
8305ffd83dbSDimitry Andric         << (!SemaRef.getLangOpts().ObjC);
8315ffd83dbSDimitry Andric     return true;
8325ffd83dbSDimitry Andric   }
8335ffd83dbSDimitry Andric 
8345ffd83dbSDimitry Andric   bool VisitTypeLoc(TypeLoc Ty);
8355ffd83dbSDimitry Andric };
8365ffd83dbSDimitry Andric 
8375ffd83dbSDimitry Andric void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
8385ffd83dbSDimitry Andric     NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) {
8395ffd83dbSDimitry Andric   AvailabilityResult Result;
8405ffd83dbSDimitry Andric   const NamedDecl *OffendingDecl;
8415ffd83dbSDimitry Andric   std::tie(Result, OffendingDecl) =
8425ffd83dbSDimitry Andric       ShouldDiagnoseAvailabilityOfDecl(SemaRef, D, nullptr, ReceiverClass);
8435ffd83dbSDimitry Andric   if (Result != AR_Available) {
8445ffd83dbSDimitry Andric     // All other diagnostic kinds have already been handled in
8455ffd83dbSDimitry Andric     // DiagnoseAvailabilityOfDecl.
8465ffd83dbSDimitry Andric     if (Result != AR_NotYetIntroduced)
8475ffd83dbSDimitry Andric       return;
8485ffd83dbSDimitry Andric 
8495ffd83dbSDimitry Andric     const AvailabilityAttr *AA =
8505ffd83dbSDimitry Andric       getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
851*0fca6ea1SDimitry Andric     assert(AA != nullptr && "expecting valid availability attribute");
852*0fca6ea1SDimitry Andric     bool EnvironmentMatchesOrNone =
853*0fca6ea1SDimitry Andric         hasMatchingEnvironmentOrNone(SemaRef.getASTContext(), AA);
8545ffd83dbSDimitry Andric     VersionTuple Introduced = AA->getIntroduced();
8555ffd83dbSDimitry Andric 
856*0fca6ea1SDimitry Andric     if (EnvironmentMatchesOrNone && AvailabilityStack.back() >= Introduced)
8575ffd83dbSDimitry Andric       return;
8585ffd83dbSDimitry Andric 
8595ffd83dbSDimitry Andric     // If the context of this function is less available than D, we should not
8605ffd83dbSDimitry Andric     // emit a diagnostic.
861*0fca6ea1SDimitry Andric     if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced,
862*0fca6ea1SDimitry Andric                                              AA->getEnvironment(), Ctx,
8635ffd83dbSDimitry Andric                                              OffendingDecl))
8645ffd83dbSDimitry Andric       return;
8655ffd83dbSDimitry Andric 
866*0fca6ea1SDimitry Andric     const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
867*0fca6ea1SDimitry Andric     std::string PlatformName(
868*0fca6ea1SDimitry Andric         AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
869*0fca6ea1SDimitry Andric     llvm::StringRef TargetEnvironment(TI.getTriple().getEnvironmentName());
870*0fca6ea1SDimitry Andric     llvm::StringRef AttrEnvironment =
871*0fca6ea1SDimitry Andric         AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
872*0fca6ea1SDimitry Andric     bool UseEnvironment =
873*0fca6ea1SDimitry Andric         (!AttrEnvironment.empty() && !TargetEnvironment.empty());
8745ffd83dbSDimitry Andric 
875*0fca6ea1SDimitry Andric     unsigned DiagKind = getAvailabilityDiagnosticKind(
876*0fca6ea1SDimitry Andric         SemaRef.Context,
877*0fca6ea1SDimitry Andric         SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced,
878*0fca6ea1SDimitry Andric         EnvironmentMatchesOrNone);
8795ffd83dbSDimitry Andric 
8805ffd83dbSDimitry Andric     SemaRef.Diag(Range.getBegin(), DiagKind)
881*0fca6ea1SDimitry Andric         << Range << D << PlatformName << Introduced.getAsString()
882*0fca6ea1SDimitry Andric         << UseEnvironment << TargetEnvironment;
8835ffd83dbSDimitry Andric 
8845ffd83dbSDimitry Andric     SemaRef.Diag(OffendingDecl->getLocation(),
8855ffd83dbSDimitry Andric                  diag::note_partial_availability_specified_here)
8865ffd83dbSDimitry Andric         << OffendingDecl << PlatformName << Introduced.getAsString()
887*0fca6ea1SDimitry Andric         << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
888*0fca6ea1SDimitry Andric         << UseEnvironment << AttrEnvironment << TargetEnvironment;
889*0fca6ea1SDimitry Andric 
890*0fca6ea1SDimitry Andric     // Do not offer to silence the warning or fixits for HLSL
891*0fca6ea1SDimitry Andric     if (SemaRef.getLangOpts().HLSL)
892*0fca6ea1SDimitry Andric       return;
8935ffd83dbSDimitry Andric 
8945ffd83dbSDimitry Andric     auto FixitDiag =
8955ffd83dbSDimitry Andric         SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
8965ffd83dbSDimitry Andric         << Range << D
8975ffd83dbSDimitry Andric         << (SemaRef.getLangOpts().ObjC ? /*@available*/ 0
8985ffd83dbSDimitry Andric                                        : /*__builtin_available*/ 1);
8995ffd83dbSDimitry Andric 
9005ffd83dbSDimitry Andric     // Find the statement which should be enclosed in the if @available check.
9015ffd83dbSDimitry Andric     if (StmtStack.empty())
9025ffd83dbSDimitry Andric       return;
9035ffd83dbSDimitry Andric     const Stmt *StmtOfUse = StmtStack.back();
9045ffd83dbSDimitry Andric     const CompoundStmt *Scope = nullptr;
9055ffd83dbSDimitry Andric     for (const Stmt *S : llvm::reverse(StmtStack)) {
9065ffd83dbSDimitry Andric       if (const auto *CS = dyn_cast<CompoundStmt>(S)) {
9075ffd83dbSDimitry Andric         Scope = CS;
9085ffd83dbSDimitry Andric         break;
9095ffd83dbSDimitry Andric       }
9105ffd83dbSDimitry Andric       if (isBodyLikeChildStmt(StmtOfUse, S)) {
9115ffd83dbSDimitry Andric         // The declaration won't be seen outside of the statement, so we don't
9125ffd83dbSDimitry Andric         // have to wrap the uses of any declared variables in if (@available).
9135ffd83dbSDimitry Andric         // Therefore we can avoid setting Scope here.
9145ffd83dbSDimitry Andric         break;
9155ffd83dbSDimitry Andric       }
9165ffd83dbSDimitry Andric       StmtOfUse = S;
9175ffd83dbSDimitry Andric     }
9185ffd83dbSDimitry Andric     const Stmt *LastStmtOfUse = nullptr;
9195ffd83dbSDimitry Andric     if (isa<DeclStmt>(StmtOfUse) && Scope) {
9205ffd83dbSDimitry Andric       for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) {
9215ffd83dbSDimitry Andric         if (StmtUSEFinder::isContained(StmtStack.back(), D)) {
9225ffd83dbSDimitry Andric           LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope);
9235ffd83dbSDimitry Andric           break;
9245ffd83dbSDimitry Andric         }
9255ffd83dbSDimitry Andric       }
9265ffd83dbSDimitry Andric     }
9275ffd83dbSDimitry Andric 
9285ffd83dbSDimitry Andric     const SourceManager &SM = SemaRef.getSourceManager();
9295ffd83dbSDimitry Andric     SourceLocation IfInsertionLoc =
9305ffd83dbSDimitry Andric         SM.getExpansionLoc(StmtOfUse->getBeginLoc());
9315ffd83dbSDimitry Andric     SourceLocation StmtEndLoc =
9325ffd83dbSDimitry Andric         SM.getExpansionRange(
9335ffd83dbSDimitry Andric               (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc())
9345ffd83dbSDimitry Andric             .getEnd();
9355ffd83dbSDimitry Andric     if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc))
9365ffd83dbSDimitry Andric       return;
9375ffd83dbSDimitry Andric 
9385ffd83dbSDimitry Andric     StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM);
9395ffd83dbSDimitry Andric     const char *ExtraIndentation = "    ";
9405ffd83dbSDimitry Andric     std::string FixItString;
9415ffd83dbSDimitry Andric     llvm::raw_string_ostream FixItOS(FixItString);
9425ffd83dbSDimitry Andric     FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? "@available"
9435ffd83dbSDimitry Andric                                                      : "__builtin_available")
9445ffd83dbSDimitry Andric             << "("
9455ffd83dbSDimitry Andric             << AvailabilityAttr::getPlatformNameSourceSpelling(
9465ffd83dbSDimitry Andric                    SemaRef.getASTContext().getTargetInfo().getPlatformName())
9475ffd83dbSDimitry Andric             << " " << Introduced.getAsString() << ", *)) {\n"
9485ffd83dbSDimitry Andric             << Indentation << ExtraIndentation;
9495ffd83dbSDimitry Andric     FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str());
9505ffd83dbSDimitry Andric     SourceLocation ElseInsertionLoc = Lexer::findLocationAfterToken(
9515ffd83dbSDimitry Andric         StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(),
9525ffd83dbSDimitry Andric         /*SkipTrailingWhitespaceAndNewLine=*/false);
9535ffd83dbSDimitry Andric     if (ElseInsertionLoc.isInvalid())
9545ffd83dbSDimitry Andric       ElseInsertionLoc =
9555ffd83dbSDimitry Andric           Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts());
9565ffd83dbSDimitry Andric     FixItOS.str().clear();
9575ffd83dbSDimitry Andric     FixItOS << "\n"
9585ffd83dbSDimitry Andric             << Indentation << "} else {\n"
9595ffd83dbSDimitry Andric             << Indentation << ExtraIndentation
9605ffd83dbSDimitry Andric             << "// Fallback on earlier versions\n"
9615ffd83dbSDimitry Andric             << Indentation << "}";
9625ffd83dbSDimitry Andric     FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str());
9635ffd83dbSDimitry Andric   }
9645ffd83dbSDimitry Andric }
9655ffd83dbSDimitry Andric 
9665ffd83dbSDimitry Andric bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
9675ffd83dbSDimitry Andric   const Type *TyPtr = Ty.getTypePtr();
9685ffd83dbSDimitry Andric   SourceRange Range{Ty.getBeginLoc(), Ty.getEndLoc()};
9695ffd83dbSDimitry Andric 
9705ffd83dbSDimitry Andric   if (Range.isInvalid())
9715ffd83dbSDimitry Andric     return true;
9725ffd83dbSDimitry Andric 
9735ffd83dbSDimitry Andric   if (const auto *TT = dyn_cast<TagType>(TyPtr)) {
9745ffd83dbSDimitry Andric     TagDecl *TD = TT->getDecl();
9755ffd83dbSDimitry Andric     DiagnoseDeclAvailability(TD, Range);
9765ffd83dbSDimitry Andric 
9775ffd83dbSDimitry Andric   } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) {
9785ffd83dbSDimitry Andric     TypedefNameDecl *D = TD->getDecl();
9795ffd83dbSDimitry Andric     DiagnoseDeclAvailability(D, Range);
9805ffd83dbSDimitry Andric 
9815ffd83dbSDimitry Andric   } else if (const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) {
9825ffd83dbSDimitry Andric     if (NamedDecl *D = ObjCO->getInterface())
9835ffd83dbSDimitry Andric       DiagnoseDeclAvailability(D, Range);
9845ffd83dbSDimitry Andric   }
9855ffd83dbSDimitry Andric 
9865ffd83dbSDimitry Andric   return true;
9875ffd83dbSDimitry Andric }
9885ffd83dbSDimitry Andric 
9895ffd83dbSDimitry Andric bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
9905ffd83dbSDimitry Andric   VersionTuple CondVersion;
9915ffd83dbSDimitry Andric   if (auto *E = dyn_cast<ObjCAvailabilityCheckExpr>(If->getCond())) {
9925ffd83dbSDimitry Andric     CondVersion = E->getVersion();
9935ffd83dbSDimitry Andric 
9945ffd83dbSDimitry Andric     // If we're using the '*' case here or if this check is redundant, then we
9955ffd83dbSDimitry Andric     // use the enclosing version to check both branches.
9965ffd83dbSDimitry Andric     if (CondVersion.empty() || CondVersion <= AvailabilityStack.back())
9975ffd83dbSDimitry Andric       return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
9985ffd83dbSDimitry Andric   } else {
9995ffd83dbSDimitry Andric     // This isn't an availability checking 'if', we can just continue.
10005ffd83dbSDimitry Andric     return Base::TraverseIfStmt(If);
10015ffd83dbSDimitry Andric   }
10025ffd83dbSDimitry Andric 
10035ffd83dbSDimitry Andric   AvailabilityStack.push_back(CondVersion);
10045ffd83dbSDimitry Andric   bool ShouldContinue = TraverseStmt(If->getThen());
10055ffd83dbSDimitry Andric   AvailabilityStack.pop_back();
10065ffd83dbSDimitry Andric 
10075ffd83dbSDimitry Andric   return ShouldContinue && TraverseStmt(If->getElse());
10085ffd83dbSDimitry Andric }
10095ffd83dbSDimitry Andric 
10105ffd83dbSDimitry Andric } // end anonymous namespace
10115ffd83dbSDimitry Andric 
10125ffd83dbSDimitry Andric void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) {
10135ffd83dbSDimitry Andric   Stmt *Body = nullptr;
10145ffd83dbSDimitry Andric 
10155ffd83dbSDimitry Andric   if (auto *FD = D->getAsFunction()) {
10165ffd83dbSDimitry Andric     Body = FD->getBody();
1017bdd1243dSDimitry Andric 
1018bdd1243dSDimitry Andric     if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
1019bdd1243dSDimitry Andric       for (const CXXCtorInitializer *CI : CD->inits())
1020bdd1243dSDimitry Andric         DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(CI->getInit());
1021bdd1243dSDimitry Andric 
10225ffd83dbSDimitry Andric   } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
10235ffd83dbSDimitry Andric     Body = MD->getBody();
10245ffd83dbSDimitry Andric   else if (auto *BD = dyn_cast<BlockDecl>(D))
10255ffd83dbSDimitry Andric     Body = BD->getBody();
10265ffd83dbSDimitry Andric 
10275ffd83dbSDimitry Andric   assert(Body && "Need a body here!");
10285ffd83dbSDimitry Andric 
10295ffd83dbSDimitry Andric   DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);
10305ffd83dbSDimitry Andric }
10315ffd83dbSDimitry Andric 
1032fe6060f1SDimitry Andric FunctionScopeInfo *Sema::getCurFunctionAvailabilityContext() {
1033fe6060f1SDimitry Andric   if (FunctionScopes.empty())
1034fe6060f1SDimitry Andric     return nullptr;
1035fe6060f1SDimitry Andric 
1036fe6060f1SDimitry Andric   // Conservatively search the entire current function scope context for
1037fe6060f1SDimitry Andric   // availability violations. This ensures we always correctly analyze nested
1038fe6060f1SDimitry Andric   // classes, blocks, lambdas, etc. that may or may not be inside if(@available)
1039fe6060f1SDimitry Andric   // checks themselves.
1040fe6060f1SDimitry Andric   return FunctionScopes.front();
1041fe6060f1SDimitry Andric }
1042fe6060f1SDimitry Andric 
10435ffd83dbSDimitry Andric void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D,
10445ffd83dbSDimitry Andric                                       ArrayRef<SourceLocation> Locs,
10455ffd83dbSDimitry Andric                                       const ObjCInterfaceDecl *UnknownObjCClass,
10465ffd83dbSDimitry Andric                                       bool ObjCPropertyAccess,
10475ffd83dbSDimitry Andric                                       bool AvoidPartialAvailabilityChecks,
10485ffd83dbSDimitry Andric                                       ObjCInterfaceDecl *ClassReceiver) {
10495ffd83dbSDimitry Andric   std::string Message;
10505ffd83dbSDimitry Andric   AvailabilityResult Result;
10515ffd83dbSDimitry Andric   const NamedDecl* OffendingDecl;
10525ffd83dbSDimitry Andric   // See if this declaration is unavailable, deprecated, or partial.
10535ffd83dbSDimitry Andric   std::tie(Result, OffendingDecl) =
10545ffd83dbSDimitry Andric       ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver);
10555ffd83dbSDimitry Andric   if (Result == AR_Available)
10565ffd83dbSDimitry Andric     return;
10575ffd83dbSDimitry Andric 
10585ffd83dbSDimitry Andric   if (Result == AR_NotYetIntroduced) {
10595ffd83dbSDimitry Andric     if (AvoidPartialAvailabilityChecks)
10605ffd83dbSDimitry Andric       return;
10615ffd83dbSDimitry Andric 
10625ffd83dbSDimitry Andric     // We need to know the @available context in the current function to
10635ffd83dbSDimitry Andric     // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that
10645ffd83dbSDimitry Andric     // when we're done parsing the current function.
1065fe6060f1SDimitry Andric     if (FunctionScopeInfo *Context = getCurFunctionAvailabilityContext()) {
1066fe6060f1SDimitry Andric       Context->HasPotentialAvailabilityViolations = true;
10675ffd83dbSDimitry Andric       return;
10685ffd83dbSDimitry Andric     }
10695ffd83dbSDimitry Andric   }
10705ffd83dbSDimitry Andric 
10715ffd83dbSDimitry Andric   const ObjCPropertyDecl *ObjCPDecl = nullptr;
10725ffd83dbSDimitry Andric   if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
10735ffd83dbSDimitry Andric     if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
10745ffd83dbSDimitry Andric       AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
10755ffd83dbSDimitry Andric       if (PDeclResult == Result)
10765ffd83dbSDimitry Andric         ObjCPDecl = PD;
10775ffd83dbSDimitry Andric     }
10785ffd83dbSDimitry Andric   }
10795ffd83dbSDimitry Andric 
10805ffd83dbSDimitry Andric   EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs,
10815ffd83dbSDimitry Andric                           UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
10825ffd83dbSDimitry Andric }
1083