erik.pilkington created this revision.

This is done by modifying ShouldDiagnoseAvailabilityOfDecl() so that the 
OffendingDecl is the one with the original availability attribute. Also, keep 
track of this availability attribute so we don't have to constantly recompute 
it via getAttrForPlatform().

Thanks for taking a look!
Erik


https://reviews.llvm.org/D35781

Files:
  include/clang/AST/DeclBase.h
  include/clang/Sema/DelayedDiagnostic.h
  lib/AST/DeclBase.cpp
  lib/Sema/DelayedDiagnostic.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/Sema/attr-availability-ios.c
  test/Sema/attr-availability-tvos.c
  test/Sema/attr-availability-watchos.c
  test/Sema/attr-availability.c
  test/SemaObjC/protocol-attribute.m

Index: test/SemaObjC/protocol-attribute.m
===================================================================
--- test/SemaObjC/protocol-attribute.m
+++ test/SemaObjC/protocol-attribute.m
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
 __attribute ((unavailable))
-@protocol FwProto; // expected-note{{marked unavailable}}
+@protocol FwProto; // expected-note 2 {{marked unavailable}}
 
 Class <FwProto> cFw = 0;  // expected-error {{'FwProto' is unavailable}}
 
@@ -33,7 +33,7 @@
 
 Class <MyProto1> clsP1 = 0;  // expected-warning {{'MyProto1' is deprecated}}
 
-@protocol FwProto @end // expected-note{{marked unavailable}}
+@protocol FwProto @end
 
 @interface MyClass2 <FwProto> // expected-error {{'FwProto' is unavailable}}
 @end
Index: test/Sema/attr-availability.c
===================================================================
--- test/Sema/attr-availability.c
+++ test/Sema/attr-availability.c
@@ -16,7 +16,7 @@
 ATSFontGetPostScriptName(int flags) __attribute__((availability(macosx,introduced=8.0,obsoleted=9.0, message="use ATSFontGetFullPostScriptName"))); // expected-note {{'ATSFontGetPostScriptName' has been explicitly marked unavailable here}}
 
 #if defined(WARN_PARTIAL)
-// expected-note@+3 {{has been explicitly marked partial here}}
+// expected-note@+3 2 {{has been explicitly marked partial here}}
 #endif
 extern void
 PartiallyAvailable() __attribute__((availability(macosx,introduced=10.8)));
@@ -38,11 +38,6 @@
   PartiallyAvailable();
 }
 
-#ifdef WARN_PARTIAL
-// FIXME: This note should point to the declaration with the availability
-// attribute.
-// expected-note@+2 {{marked partial here}}
-#endif
 extern void PartiallyAvailable() ;
 void with_redeclaration() {
 #ifdef WARN_PARTIAL
Index: test/Sema/attr-availability-watchos.c
===================================================================
--- test/Sema/attr-availability-watchos.c
+++ test/Sema/attr-availability-watchos.c
@@ -32,8 +32,8 @@
 void f5_attr_reversed_watchos(int) __attribute__((availability(ios, deprecated=3.0))) __attribute__((availability(watchos,introduced=2.0)));
 void f5b_watchos(int) __attribute__((availability(watchos,introduced=2.0))) __attribute__((availability(watchos,deprecated=3.0))); // expected-note {{'f5b_watchos' has been explicitly marked deprecated here}}
 void f5c_watchos(int) __attribute__((availability(ios,introduced=2.0))) __attribute__((availability(ios,deprecated=3.0))); // expected-note {{'f5c_watchos' has been explicitly marked deprecated here}}
-void f6_watchos(int) __attribute__((availability(watchos,deprecated=3.0)));
-void f6_watchos(int) __attribute__((availability(watchos,introduced=2.0))); // expected-note {{'f6_watchos' has been explicitly marked deprecated here}}
+void f6_watchos(int) __attribute__((availability(watchos,deprecated=3.0))); // expected-note {{'f6_watchos' has been explicitly marked deprecated here}}
+void f6_watchos(int) __attribute__((availability(watchos,introduced=2.0)));
 
 void test_watchos() {
   f0_watchos(0); // expected-warning{{'f0_watchos' is deprecated: first deprecated in watchOS 2.1}}
Index: test/Sema/attr-availability-tvos.c
===================================================================
--- test/Sema/attr-availability-tvos.c
+++ test/Sema/attr-availability-tvos.c
@@ -7,8 +7,8 @@
 void f4(int) __attribute__((availability(macosx,introduced=10.1,deprecated=10.3,obsoleted=10.5), availability(tvos,introduced=2.0,deprecated=2.1,obsoleted=3.0))); // expected-note{{explicitly marked unavailable}}
 
 void f5(int) __attribute__((availability(tvos,introduced=2.0))) __attribute__((availability(tvos,deprecated=3.0))); // expected-note {{'f5' has been explicitly marked deprecated here}}
-void f6(int) __attribute__((availability(tvos,deprecated=3.0)));
-void f6(int) __attribute__((availability(tvos,introduced=2.0))); // expected-note {{'f6' has been explicitly marked deprecated here}}
+void f6(int) __attribute__((availability(tvos,deprecated=3.0))); // expected-note {{'f6' has been explicitly marked deprecated here}}
+void f6(int) __attribute__((availability(tvos,introduced=2.0)));
 
 void test() {
   f0(0); // expected-warning{{'f0' is deprecated: first deprecated in tvOS 2.1}}
@@ -43,8 +43,8 @@
 void f5_attr_reversed_tvos(int) __attribute__((availability(ios, deprecated=3.0))) __attribute__((availability(tvos,introduced=2.0)));
 void f5b_tvos(int) __attribute__((availability(tvos,introduced=2.0))) __attribute__((availability(tvos,deprecated=3.0))); // expected-note {{'f5b_tvos' has been explicitly marked deprecated here}}
 void f5c_tvos(int) __attribute__((availability(ios,introduced=2.0))) __attribute__((availability(ios,deprecated=3.0))); // expected-note {{'f5c_tvos' has been explicitly marked deprecated here}}
-void f6_tvos(int) __attribute__((availability(tvos,deprecated=3.0)));
-void f6_tvos(int) __attribute__((availability(tvos,introduced=2.0))); // expected-note {{'f6_tvos' has been explicitly marked deprecated here}}
+void f6_tvos(int) __attribute__((availability(tvos,deprecated=3.0))); // expected-note {{'f6_tvos' has been explicitly marked deprecated here}}
+void f6_tvos(int) __attribute__((availability(tvos,introduced=2.0)));
 
 void test_tvos() {
   f0_tvos(0); // expected-warning{{'f0_tvos' is deprecated: first deprecated in tvOS 2.1}}
Index: test/Sema/attr-availability-ios.c
===================================================================
--- test/Sema/attr-availability-ios.c
+++ test/Sema/attr-availability-ios.c
@@ -7,8 +7,8 @@
 void f4(int) __attribute__((availability(macosx,introduced=10.1,deprecated=10.3,obsoleted=10.5), availability(ios,introduced=2.0,deprecated=2.1,obsoleted=3.0))); // expected-note{{explicitly marked unavailable}}
 
 void f5(int) __attribute__((availability(ios,introduced=2.0))) __attribute__((availability(ios,deprecated=3.0))); // expected-note {{'f5' has been explicitly marked deprecated here}}
-void f6(int) __attribute__((availability(ios,deprecated=3.0)));
-void f6(int) __attribute__((availability(ios,introduced=2.0))); // expected-note {{'f6' has been explicitly marked deprecated here}}
+void f6(int) __attribute__((availability(ios,deprecated=3.0))); // expected-note {{'f6' has been explicitly marked deprecated here}}
+void f6(int) __attribute__((availability(ios,introduced=2.0)));
 
 void test() {
   f0(0); // expected-warning{{'f0' is deprecated: first deprecated in iOS 2.1}}
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6854,51 +6854,24 @@
   diag.Triggered = true;
 }
 
-static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
-                                                  const Decl *D) {
-  // Check each AvailabilityAttr to find the one for this platform.
-  for (const auto *A : D->attrs()) {
-    if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
-      // FIXME: this is copied from CheckAvailability. We should try to
-      // de-duplicate.
-
-      // Check if this is an App Extension "platform", and if so chop off
-      // the suffix for matching with the actual platform.
-      StringRef ActualPlatform = Avail->getPlatform()->getName();
-      StringRef RealizedPlatform = ActualPlatform;
-      if (Context.getLangOpts().AppExt) {
-        size_t suffix = RealizedPlatform.rfind("_app_extension");
-        if (suffix != StringRef::npos)
-          RealizedPlatform = RealizedPlatform.slice(0, suffix);
-      }
-
-      StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
-
-      // Match the platform name.
-      if (RealizedPlatform == TargetPlatform)
-        return Avail;
-    }
-  }
-  return nullptr;
-}
-
 /// The diagnostic we should emit for \c D, and the declaration that
 /// originated it, or \c AR_Available.
 ///
 /// \param D The declaration to check.
 /// \param Message If non-null, this will be populated with the message from
 /// the availability attribute that is selected.
-static std::pair<AvailabilityResult, const NamedDecl *>
+static std::tuple<AvailabilityResult, const NamedDecl *, const Attr *>
 ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) {
-  AvailabilityResult Result = D->getAvailability(Message);
+  const Attr *Attribute = nullptr;
+  AvailabilityResult Result = D->getAvailability(Message, &Attribute);
 
   // For typedefs, if the typedef declaration appears available look
   // to the underlying type to see if it is more restrictive.
   while (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
     if (Result == AR_Available) {
       if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
         D = TT->getDecl();
-        Result = D->getAvailability(Message);
+        Result = D->getAvailability(Message, &Attribute);
         continue;
       }
     }
@@ -6909,20 +6882,78 @@
   if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
     if (IDecl->getDefinition()) {
       D = IDecl->getDefinition();
-      Result = D->getAvailability(Message);
+      Result = D->getAvailability(Message, &Attribute);
     }
   }
 
   if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
     if (Result == AR_Available) {
       const DeclContext *DC = ECD->getDeclContext();
       if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
-        Result = TheEnumDecl->getAvailability(Message);
+        Result = TheEnumDecl->getAvailability(Message, &Attribute);
         D = TheEnumDecl;
       }
     }
 
-  return {Result, D};
+  // This decl could only have an inherited attribute, prefer pointing at the
+  // decl with the original availability attribute.
+  if (Attribute && Attribute->isInherited()) {
+    for (const NamedDecl *Redecl = D->getMostRecentDecl(); Redecl;
+         Redecl = cast_or_null<NamedDecl>(Redecl->getPreviousDecl())) {
+      for (const auto *RedeclAttr : Redecl->attrs()) {
+        if (RedeclAttr->isInherited())
+          continue;
+
+        if (isa<UnavailableAttr>(Attribute) && isa<UnavailableAttr>(RedeclAttr))
+          return {AR_Unavailable, Redecl, cast<UnavailableAttr>(RedeclAttr)};
+
+        if (isa<DeprecatedAttr>(Attribute) && isa<DeprecatedAttr>(RedeclAttr))
+          return {AR_Deprecated, Redecl, cast<DeprecatedAttr>(RedeclAttr)};
+
+        const AvailabilityAttr *RedeclAA =
+            dyn_cast<AvailabilityAttr>(RedeclAttr);
+        const AvailabilityAttr *OrigAA = dyn_cast<AvailabilityAttr>(Attribute);
+        if (!RedeclAA || !OrigAA)
+          continue;
+
+        // Check if this is an App Extension "platform", and if so chop off
+        // the suffix for matching with the actual platform.
+        StringRef ActualPlatform = RedeclAA->getPlatform()->getName();
+        StringRef RealizedPlatform = ActualPlatform;
+        if (Redecl->getASTContext().getLangOpts().AppExt) {
+          size_t suffix = RealizedPlatform.rfind("_app_extension");
+          if (suffix != StringRef::npos)
+            RealizedPlatform = RealizedPlatform.slice(0, suffix);
+        }
+
+        StringRef TargetPlatform =
+            Redecl->getASTContext().getTargetInfo().getPlatformName();
+
+        // Match the platform name.
+        if (RealizedPlatform != TargetPlatform)
+          continue;
+
+        bool EqualAttr;
+        switch (Result) {
+        case AR_NotYetIntroduced:
+          EqualAttr = RedeclAA->getIntroduced() == OrigAA->getIntroduced();
+          break;
+        case AR_Deprecated:
+          EqualAttr = RedeclAA->getDeprecated() == OrigAA->getDeprecated();
+          break;
+        case AR_Unavailable:
+          EqualAttr = RedeclAA->getObsoleted() == OrigAA->getObsoleted();
+          break;
+        default:
+          EqualAttr = false;
+        }
+        if (EqualAttr)
+          return {Result, Redecl, RedeclAA};
+      }
+    }
+  }
+
+  return {Result, D, Attribute};
 }
 
 
@@ -6937,9 +6968,8 @@
   // Checks if we should emit the availability diagnostic in the context of C.
   auto CheckContext = [&](const Decl *C) {
     if (K == AR_NotYetIntroduced) {
-      if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C))
-        if (AA->getIntroduced() >= DeclVersion)
-          return true;
+      if (C->getVersionIntroduced() >= DeclVersion)
+        return true;
     } else if (K == AR_Deprecated)
       if (C->isDeprecated())
         return true;
@@ -7045,6 +7075,7 @@
 static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
                                       Decl *Ctx, const NamedDecl *ReferringDecl,
                                       const NamedDecl *OffendingDecl,
+                                      const Attr *OffendingAttr,
                                       StringRef Message, SourceLocation Loc,
                                       const ObjCInterfaceDecl *UnknownObjCClass,
                                       const ObjCPropertyDecl *ObjCProperty,
@@ -7061,7 +7092,7 @@
   unsigned available_here_select_kind;
 
   VersionTuple DeclVersion;
-  if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl))
+  if (const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(OffendingAttr))
     DeclVersion = AA->getIntroduced();
 
   if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx))
@@ -7087,7 +7118,7 @@
     property_note_select = /* unavailable */ 1;
     available_here_select_kind = /* unavailable */ 0;
 
-    if (auto attr = OffendingDecl->getAttr<UnavailableAttr>()) {
+    if (auto attr = dyn_cast<UnavailableAttr>(OffendingAttr)) {
       if (attr->isImplicit() && attr->getImplicitReason()) {
         // Most of these failures are due to extra restrictions in ARC;
         // reflect that in the primary diagnostic when applicable.
@@ -7137,8 +7168,7 @@
     // not specified for deployment targets >= to iOS 11 or equivalent or
     // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
     // later.
-    const AvailabilityAttr *AA =
-        getAttrForPlatform(S.getASTContext(), OffendingDecl);
+    const AvailabilityAttr *AA = cast<AvailabilityAttr>(OffendingAttr);
     VersionTuple Introduced = AA->getIntroduced();
     bool NewWarning = shouldDiagnoseAvailabilityByDefault(
         S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
@@ -7161,9 +7191,9 @@
   CharSourceRange UseRange;
   StringRef Replacement;
   if (K == AR_Deprecated) {
-    if (auto attr = OffendingDecl->getAttr<DeprecatedAttr>())
+    if (auto attr = dyn_cast<DeprecatedAttr>(OffendingAttr))
       Replacement = attr->getReplacement();
-    if (auto attr = getAttrForPlatform(S.Context, OffendingDecl))
+    if (auto attr = dyn_cast<AvailabilityAttr>(OffendingAttr))
       Replacement = attr->getReplacement();
 
     if (!Replacement.empty())
@@ -7192,26 +7222,8 @@
     S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
   }
 
-  // The declaration can have multiple availability attributes, we are looking
-  // at one of them.
-  const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
-  if (A && A->isInherited()) {
-    for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
-         Redecl = Redecl->getPreviousDecl()) {
-      const AvailabilityAttr *AForRedecl = getAttrForPlatform(S.Context,
-                                                              Redecl);
-      if (AForRedecl && !AForRedecl->isInherited()) {
-        // If D is a declaration with inherited attributes, the note should
-        // point to the declaration with actual attributes.
-        S.Diag(Redecl->getLocation(), diag_available_here) << OffendingDecl
-            << available_here_select_kind;
-        break;
-      }
-    }
-  }
-  else
-    S.Diag(NoteLocation, diag_available_here)
-        << OffendingDecl << available_here_select_kind;
+  S.Diag(NoteLocation, diag_available_here)
+    << OffendingDecl << available_here_select_kind;
 
   if (K == AR_NotYetIntroduced)
     if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
@@ -7234,8 +7246,9 @@
   DD.Triggered = true;
   DoEmitAvailabilityWarning(
       S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(),
-      DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), DD.Loc,
-      DD.getUnknownObjCClass(), DD.getObjCProperty(), false);
+      DD.getAvailabilityOffendingDecl(), DD.getAvailabilityAttr(),
+      DD.getAvailabilityMessage(), DD.Loc, DD.getUnknownObjCClass(),
+      DD.getObjCProperty(), false);
 }
 
 void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
@@ -7296,23 +7309,23 @@
 static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR,
                                     const NamedDecl *ReferringDecl,
                                     const NamedDecl *OffendingDecl,
+                                    const Attr *OffendingAttr,
                                     StringRef Message, SourceLocation Loc,
                                     const ObjCInterfaceDecl *UnknownObjCClass,
                                     const ObjCPropertyDecl *ObjCProperty,
                                     bool ObjCPropertyAccess) {
   // Delay if we're currently parsing a declaration.
   if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
-    S.DelayedDiagnostics.add(
-        DelayedDiagnostic::makeAvailability(
-            AR, Loc, ReferringDecl, OffendingDecl, UnknownObjCClass,
-            ObjCProperty, Message, ObjCPropertyAccess));
+    S.DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability(
+        AR, Loc, ReferringDecl, OffendingDecl, OffendingAttr, UnknownObjCClass,
+        ObjCProperty, Message, ObjCPropertyAccess));
     return;
   }
 
   Decl *Ctx = cast<Decl>(S.getCurLexicalContext());
   DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl,
-                            Message, Loc, UnknownObjCClass, ObjCProperty,
-                            ObjCPropertyAccess);
+                            OffendingAttr, Message, Loc, UnknownObjCClass,
+                            ObjCProperty, ObjCPropertyAccess);
 }
 
 namespace {
@@ -7466,17 +7479,17 @@
     NamedDecl *D, SourceRange Range) {
   AvailabilityResult Result;
   const NamedDecl *OffendingDecl;
-  std::tie(Result, OffendingDecl) =
-    ShouldDiagnoseAvailabilityOfDecl(D, nullptr);
+  const Attr *Attribute;
+  std::tie(Result, OffendingDecl, Attribute) =
+      ShouldDiagnoseAvailabilityOfDecl(D, nullptr);
   if (Result != AR_Available) {
     // All other diagnostic kinds have already been handled in
     // DiagnoseAvailabilityOfDecl.
     if (Result != AR_NotYetIntroduced)
       return;
 
-    const AvailabilityAttr *AA =
-      getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
-    VersionTuple Introduced = AA->getIntroduced();
+    VersionTuple Introduced =
+        cast<AvailabilityAttr>(Attribute)->getIntroduced();
 
     if (AvailabilityStack.back() >= Introduced)
       return;
@@ -7653,8 +7666,10 @@
   std::string Message;
   AvailabilityResult Result;
   const NamedDecl* OffendingDecl;
+  const Attr *Attribute;
   // See if this declaration is unavailable, deprecated, or partial.
-  std::tie(Result, OffendingDecl) = ShouldDiagnoseAvailabilityOfDecl(D, &Message);
+  std::tie(Result, OffendingDecl, Attribute) =
+    ShouldDiagnoseAvailabilityOfDecl(D, &Message);
   if (Result == AR_Available)
     return;
 
@@ -7677,12 +7692,12 @@
   const ObjCPropertyDecl *ObjCPDecl = nullptr;
   if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
     if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
-      AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
+      AvailabilityResult PDeclResult = PD->getAvailability();
       if (PDeclResult == Result)
         ObjCPDecl = PD;
     }
   }
 
-  EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Loc,
-                          UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
+  EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Attribute, Message,
+                          Loc, UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
 }
Index: lib/Sema/DelayedDiagnostic.cpp
===================================================================
--- lib/Sema/DelayedDiagnostic.cpp
+++ lib/Sema/DelayedDiagnostic.cpp
@@ -24,6 +24,7 @@
                                     SourceLocation Loc,
                                     const NamedDecl *ReferringDecl,
                                     const NamedDecl *OffendingDecl,
+                                    const Attr *OffendingAttr,
                                     const ObjCInterfaceDecl *UnknownObjCClass,
                                     const ObjCPropertyDecl  *ObjCProperty,
                                     StringRef Msg,
@@ -34,6 +35,7 @@
   DD.Loc = Loc;
   DD.AvailabilityData.ReferringDecl = ReferringDecl;
   DD.AvailabilityData.OffendingDecl = OffendingDecl;
+  DD.AvailabilityData.OffendingAttr = OffendingAttr;
   DD.AvailabilityData.UnknownObjCClass = UnknownObjCClass;
   DD.AvailabilityData.ObjCProperty = ObjCProperty;
   char *MessageData = nullptr;
Index: lib/AST/DeclBase.cpp
===================================================================
--- lib/AST/DeclBase.cpp
+++ lib/AST/DeclBase.cpp
@@ -474,11 +474,9 @@
 /// diagnostics.
 static AvailabilityResult CheckAvailability(ASTContext &Context,
                                             const AvailabilityAttr *A,
-                                            std::string *Message,
-                                            VersionTuple EnclosingVersion) {
-  if (EnclosingVersion.empty())
-    EnclosingVersion = Context.getTargetInfo().getPlatformMinVersion();
-
+                                            std::string *Message) {
+  VersionTuple EnclosingVersion =
+    Context.getTargetInfo().getPlatformMinVersion();
   if (EnclosingVersion.empty())
     return AR_Available;
 
@@ -560,11 +558,12 @@
 }
 
 AvailabilityResult Decl::getAvailability(std::string *Message,
-                                         VersionTuple EnclosingVersion) const {
+                                         const Attr **Attribute) const {
   if (auto *FTD = dyn_cast<FunctionTemplateDecl>(this))
-    return FTD->getTemplatedDecl()->getAvailability(Message, EnclosingVersion);
+    return FTD->getTemplatedDecl()->getAvailability(Message, Attribute);
 
   AvailabilityResult Result = AR_Available;
+  const Attr *CorrispondingAttr = nullptr;
   std::string ResultMessage;
 
   for (const auto *A : attrs()) {
@@ -574,26 +573,32 @@
 
       if (Message)
         ResultMessage = Deprecated->getMessage();
-
+      CorrispondingAttr = Deprecated;
       Result = AR_Deprecated;
       continue;
     }
 
     if (const auto *Unavailable = dyn_cast<UnavailableAttr>(A)) {
       if (Message)
         *Message = Unavailable->getMessage();
+      if (Attribute)
+        *Attribute = Unavailable;
       return AR_Unavailable;
     }
 
     if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) {
-      AvailabilityResult AR = CheckAvailability(getASTContext(), Availability,
-                                                Message, EnclosingVersion);
+      AvailabilityResult AR =
+          CheckAvailability(getASTContext(), Availability, Message);
 
-      if (AR == AR_Unavailable)
+      if (AR == AR_Unavailable) {
+        if (Attribute)
+          *Attribute = Availability;
         return AR_Unavailable;
+      }
 
       if (AR > Result) {
         Result = AR;
+        CorrispondingAttr = Availability;
         if (Message)
           ResultMessage.swap(*Message);
       }
@@ -603,6 +608,8 @@
 
   if (Message)
     Message->swap(ResultMessage);
+  if (Attribute)
+    *Attribute = CorrispondingAttr;
   return Result;
 }
 
@@ -660,8 +667,8 @@
       return true;
 
     if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) {
-      if (CheckAvailability(getASTContext(), Availability, nullptr,
-                            VersionTuple()) == AR_NotYetIntroduced)
+      if (CheckAvailability(getASTContext(), Availability, nullptr) ==
+          AR_NotYetIntroduced)
         return true;
     }
   }
Index: include/clang/Sema/DelayedDiagnostic.h
===================================================================
--- include/clang/Sema/DelayedDiagnostic.h
+++ include/clang/Sema/DelayedDiagnostic.h
@@ -126,6 +126,7 @@
                                             SourceLocation Loc,
                                             const NamedDecl *ReferringDecl,
                                             const NamedDecl *OffendingDecl,
+                                            const Attr *OffendingAttr,
                                             const ObjCInterfaceDecl *UnknownObjCClass,
                                             const ObjCPropertyDecl  *ObjCProperty,
                                             StringRef Msg,
@@ -215,11 +216,16 @@
     return AvailabilityData.ObjCPropertyAccess;
   }
 
+  const Attr *getAvailabilityAttr() const {
+    return AvailabilityData.OffendingAttr;
+  }
+
 private:
 
   struct AD {
     const NamedDecl *ReferringDecl;
     const NamedDecl *OffendingDecl;
+    const Attr *OffendingAttr;
     const ObjCInterfaceDecl *UnknownObjCClass;
     const ObjCPropertyDecl  *ObjCProperty;
     const char *Message;
Index: include/clang/AST/DeclBase.h
===================================================================
--- include/clang/AST/DeclBase.h
+++ include/clang/AST/DeclBase.h
@@ -628,11 +628,10 @@
   /// describing why the declaration has not been introduced, is
   /// deprecated, or is unavailable.
   ///
-  /// \param EnclosingVersion The version to compare with. If empty, assume the
-  /// deployment target version.
-  AvailabilityResult
-  getAvailability(std::string *Message = nullptr,
-                  VersionTuple EnclosingVersion = VersionTuple()) const;
+  /// \param Attribute The attribute that lead to this result. One of
+  /// UnavailableAttr, DeprecatedAttr, AvailabilityAttr, or nullptr.
+  AvailabilityResult getAvailability(std::string *Message = nullptr,
+                                     const Attr **Attribute = nullptr) const;
 
   /// \brief Retrieve the version of the target platform in which this
   /// declaration was introduced.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D35781: [Sema] Mak... Erik Pilkington via Phabricator via cfe-commits

Reply via email to