mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-14 14:56:47 +00:00
[Sema] Don't allow -Wunguarded-availability to be silenced with redecls
Differential revision: https://reviews.llvm.org/D33816 llvm-svn: 307175
This commit is contained in:
parent
aa5a6a1c30
commit
4042f3cf8e
@ -2880,7 +2880,7 @@ def warn_partial_availability : Warning<"%0 is only available conditionally">,
|
||||
def warn_partial_availability_new : Warning<warn_partial_availability.Text>,
|
||||
InGroup<UnguardedAvailabilityNew>;
|
||||
def note_partial_availability_silence : Note<
|
||||
"explicitly redeclare %0 to silence this warning">;
|
||||
"annotate %select{%1|anonymous %1}0 with an availability attribute to silence">;
|
||||
def note_unguarded_available_silence : Note<
|
||||
"enclose %0 in %select{an @available|a __builtin_available}1 check to silence"
|
||||
" this warning">;
|
||||
|
@ -124,7 +124,8 @@ public:
|
||||
|
||||
static DelayedDiagnostic makeAvailability(AvailabilityResult AR,
|
||||
SourceLocation Loc,
|
||||
const NamedDecl *D,
|
||||
const NamedDecl *ReferringDecl,
|
||||
const NamedDecl *OffendingDecl,
|
||||
const ObjCInterfaceDecl *UnknownObjCClass,
|
||||
const ObjCPropertyDecl *ObjCProperty,
|
||||
StringRef Msg,
|
||||
@ -164,9 +165,13 @@ public:
|
||||
return *reinterpret_cast<const AccessedEntity*>(AccessData);
|
||||
}
|
||||
|
||||
const NamedDecl *getAvailabilityDecl() const {
|
||||
const NamedDecl *getAvailabilityReferringDecl() const {
|
||||
assert(Kind == Availability && "Not an availability diagnostic.");
|
||||
return AvailabilityData.Decl;
|
||||
return AvailabilityData.ReferringDecl;
|
||||
}
|
||||
|
||||
const NamedDecl *getAvailabilityOffendingDecl() const {
|
||||
return AvailabilityData.OffendingDecl;
|
||||
}
|
||||
|
||||
StringRef getAvailabilityMessage() const {
|
||||
@ -213,7 +218,8 @@ public:
|
||||
private:
|
||||
|
||||
struct AD {
|
||||
const NamedDecl *Decl;
|
||||
const NamedDecl *ReferringDecl;
|
||||
const NamedDecl *OffendingDecl;
|
||||
const ObjCInterfaceDecl *UnknownObjCClass;
|
||||
const ObjCPropertyDecl *ObjCProperty;
|
||||
const char *Message;
|
||||
|
@ -3881,7 +3881,9 @@ public:
|
||||
|
||||
void redelayDiagnostics(sema::DelayedDiagnosticPool &pool);
|
||||
|
||||
void EmitAvailabilityWarning(AvailabilityResult AR, NamedDecl *D,
|
||||
void EmitAvailabilityWarning(AvailabilityResult AR,
|
||||
const NamedDecl *ReferringDecl,
|
||||
const NamedDecl *OffendingDecl,
|
||||
StringRef Message, SourceLocation Loc,
|
||||
const ObjCInterfaceDecl *UnknownObjCClass,
|
||||
const ObjCPropertyDecl *ObjCProperty,
|
||||
@ -10413,16 +10415,14 @@ public:
|
||||
return OriginalLexicalContext ? OriginalLexicalContext : CurContext;
|
||||
}
|
||||
|
||||
/// \brief The diagnostic we should emit for \c D, or \c AR_Available.
|
||||
///
|
||||
/// \param D The declaration to check. Note that this may be altered to point
|
||||
/// to another declaration that \c D gets it's availability from. i.e., we
|
||||
/// walk the list of typedefs to find an availability attribute.
|
||||
/// 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.
|
||||
AvailabilityResult ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D,
|
||||
std::string *Message);
|
||||
std::pair<AvailabilityResult, const NamedDecl *>
|
||||
ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message);
|
||||
|
||||
const DeclContext *getCurObjCLexicalContext() const {
|
||||
const DeclContext *DC = getCurLexicalContext();
|
||||
|
@ -22,7 +22,8 @@ using namespace sema;
|
||||
DelayedDiagnostic
|
||||
DelayedDiagnostic::makeAvailability(AvailabilityResult AR,
|
||||
SourceLocation Loc,
|
||||
const NamedDecl *D,
|
||||
const NamedDecl *ReferringDecl,
|
||||
const NamedDecl *OffendingDecl,
|
||||
const ObjCInterfaceDecl *UnknownObjCClass,
|
||||
const ObjCPropertyDecl *ObjCProperty,
|
||||
StringRef Msg,
|
||||
@ -31,7 +32,8 @@ DelayedDiagnostic::makeAvailability(AvailabilityResult AR,
|
||||
DD.Kind = Availability;
|
||||
DD.Triggered = false;
|
||||
DD.Loc = Loc;
|
||||
DD.AvailabilityData.Decl = D;
|
||||
DD.AvailabilityData.ReferringDecl = ReferringDecl;
|
||||
DD.AvailabilityData.OffendingDecl = OffendingDecl;
|
||||
DD.AvailabilityData.UnknownObjCClass = UnknownObjCClass;
|
||||
DD.AvailabilityData.ObjCProperty = ObjCProperty;
|
||||
char *MessageData = nullptr;
|
||||
|
@ -6929,8 +6929,34 @@ shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
|
||||
DeclVersion >= ForceAvailabilityFromVersion;
|
||||
}
|
||||
|
||||
static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) {
|
||||
for (Decl *Ctx = OrigCtx; Ctx;
|
||||
Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
|
||||
if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
|
||||
return cast<NamedDecl>(Ctx);
|
||||
if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
|
||||
if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
|
||||
return Imp->getClassInterface();
|
||||
return CD;
|
||||
}
|
||||
}
|
||||
|
||||
return dyn_cast<NamedDecl>(OrigCtx);
|
||||
}
|
||||
|
||||
/// Actually emit an availability diagnostic for a reference to an unavailable
|
||||
/// decl.
|
||||
///
|
||||
/// \param Ctx The context that the reference occurred in
|
||||
/// \param ReferringDecl The exact declaration that was referenced.
|
||||
/// \param OffendingDecl A related decl to \c ReferringDecl that has an
|
||||
/// availability attribute corrisponding to \c K attached to it. Note that this
|
||||
/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
|
||||
/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
|
||||
/// and OffendingDecl is the EnumDecl.
|
||||
static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
|
||||
Decl *Ctx, const NamedDecl *D,
|
||||
Decl *Ctx, const NamedDecl *ReferringDecl,
|
||||
const NamedDecl *OffendingDecl,
|
||||
StringRef Message, SourceLocation Loc,
|
||||
const ObjCInterfaceDecl *UnknownObjCClass,
|
||||
const ObjCPropertyDecl *ObjCProperty,
|
||||
@ -6938,7 +6964,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
|
||||
// Diagnostics for deprecated or unavailable.
|
||||
unsigned diag, diag_message, diag_fwdclass_message;
|
||||
unsigned diag_available_here = diag::note_availability_specified_here;
|
||||
SourceLocation NoteLocation = D->getLocation();
|
||||
SourceLocation NoteLocation = OffendingDecl->getLocation();
|
||||
|
||||
// Matches 'diag::note_property_attribute' options.
|
||||
unsigned property_note_select;
|
||||
@ -6947,7 +6973,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
|
||||
unsigned available_here_select_kind;
|
||||
|
||||
VersionTuple DeclVersion;
|
||||
if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, D))
|
||||
if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl))
|
||||
DeclVersion = AA->getIntroduced();
|
||||
|
||||
if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx))
|
||||
@ -6961,7 +6987,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
|
||||
diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
|
||||
property_note_select = /* deprecated */ 0;
|
||||
available_here_select_kind = /* deprecated */ 2;
|
||||
if (const auto *attr = D->getAttr<DeprecatedAttr>())
|
||||
if (const auto *attr = OffendingDecl->getAttr<DeprecatedAttr>())
|
||||
NoteLocation = attr->getLocation();
|
||||
break;
|
||||
|
||||
@ -6973,13 +6999,14 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
|
||||
property_note_select = /* unavailable */ 1;
|
||||
available_here_select_kind = /* unavailable */ 0;
|
||||
|
||||
if (auto attr = D->getAttr<UnavailableAttr>()) {
|
||||
if (auto attr = OffendingDecl->getAttr<UnavailableAttr>()) {
|
||||
if (attr->isImplicit() && attr->getImplicitReason()) {
|
||||
// Most of these failures are due to extra restrictions in ARC;
|
||||
// reflect that in the primary diagnostic when applicable.
|
||||
auto flagARCError = [&] {
|
||||
if (S.getLangOpts().ObjCAutoRefCount &&
|
||||
S.getSourceManager().isInSystemHeader(D->getLocation()))
|
||||
S.getSourceManager().isInSystemHeader(
|
||||
OffendingDecl->getLocation()))
|
||||
diag = diag::err_unavailable_in_arc;
|
||||
};
|
||||
|
||||
@ -7022,7 +7049,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
|
||||
// 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(), D);
|
||||
const AvailabilityAttr *AA =
|
||||
getAttrForPlatform(S.getASTContext(), OffendingDecl);
|
||||
VersionTuple Introduced = AA->getIntroduced();
|
||||
bool NewWarning = shouldDiagnoseAvailabilityByDefault(
|
||||
S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
|
||||
@ -7045,9 +7073,9 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
|
||||
CharSourceRange UseRange;
|
||||
StringRef Replacement;
|
||||
if (K == AR_Deprecated) {
|
||||
if (auto attr = D->getAttr<DeprecatedAttr>())
|
||||
if (auto attr = OffendingDecl->getAttr<DeprecatedAttr>())
|
||||
Replacement = attr->getReplacement();
|
||||
if (auto attr = getAttrForPlatform(S.Context, D))
|
||||
if (auto attr = getAttrForPlatform(S.Context, OffendingDecl))
|
||||
Replacement = attr->getReplacement();
|
||||
|
||||
if (!Replacement.empty())
|
||||
@ -7056,21 +7084,21 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
|
||||
}
|
||||
|
||||
if (!Message.empty()) {
|
||||
S.Diag(Loc, diag_message) << D << Message
|
||||
S.Diag(Loc, diag_message) << ReferringDecl << Message
|
||||
<< (UseRange.isValid() ?
|
||||
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
|
||||
if (ObjCProperty)
|
||||
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
|
||||
<< ObjCProperty->getDeclName() << property_note_select;
|
||||
} else if (!UnknownObjCClass) {
|
||||
S.Diag(Loc, diag) << D
|
||||
S.Diag(Loc, diag) << ReferringDecl
|
||||
<< (UseRange.isValid() ?
|
||||
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
|
||||
if (ObjCProperty)
|
||||
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
|
||||
<< ObjCProperty->getDeclName() << property_note_select;
|
||||
} else {
|
||||
S.Diag(Loc, diag_fwdclass_message) << D
|
||||
S.Diag(Loc, diag_fwdclass_message) << ReferringDecl
|
||||
<< (UseRange.isValid() ?
|
||||
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
|
||||
S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
|
||||
@ -7078,16 +7106,16 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
|
||||
|
||||
// The declaration can have multiple availability attributes, we are looking
|
||||
// at one of them.
|
||||
const AvailabilityAttr *A = getAttrForPlatform(S.Context, D);
|
||||
const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
|
||||
if (A && A->isInherited()) {
|
||||
for (const Decl *Redecl = D->getMostRecentDecl(); Redecl;
|
||||
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) << D
|
||||
S.Diag(Redecl->getLocation(), diag_available_here) << OffendingDecl
|
||||
<< available_here_select_kind;
|
||||
break;
|
||||
}
|
||||
@ -7095,10 +7123,19 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
|
||||
}
|
||||
else
|
||||
S.Diag(NoteLocation, diag_available_here)
|
||||
<< D << available_here_select_kind;
|
||||
<< OffendingDecl << available_here_select_kind;
|
||||
|
||||
if (K == AR_NotYetIntroduced)
|
||||
S.Diag(Loc, diag::note_partial_availability_silence) << D;
|
||||
if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
|
||||
if (auto *TD = dyn_cast<TagDecl>(Enclosing))
|
||||
if (TD->getDeclName().isEmpty()) {
|
||||
S.Diag(TD->getLocation(), diag::note_partial_availability_silence)
|
||||
<< /*Anonymous*/1 << TD->getKindName();
|
||||
return;
|
||||
}
|
||||
S.Diag(Enclosing->getLocation(), diag::note_partial_availability_silence)
|
||||
<< /*Named*/0 << Enclosing;
|
||||
}
|
||||
}
|
||||
|
||||
static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
|
||||
@ -7108,9 +7145,9 @@ static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
|
||||
|
||||
DD.Triggered = true;
|
||||
DoEmitAvailabilityWarning(
|
||||
S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityDecl(),
|
||||
DD.getAvailabilityMessage(), DD.Loc, DD.getUnknownObjCClass(),
|
||||
DD.getObjCProperty(), false);
|
||||
S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(),
|
||||
DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), DD.Loc,
|
||||
DD.getUnknownObjCClass(), DD.getObjCProperty(), false);
|
||||
}
|
||||
|
||||
void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
|
||||
@ -7169,22 +7206,25 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) {
|
||||
}
|
||||
|
||||
void Sema::EmitAvailabilityWarning(AvailabilityResult AR,
|
||||
NamedDecl *D, StringRef Message,
|
||||
SourceLocation Loc,
|
||||
const NamedDecl *ReferringDecl,
|
||||
const NamedDecl *OffendingDecl,
|
||||
StringRef Message, SourceLocation Loc,
|
||||
const ObjCInterfaceDecl *UnknownObjCClass,
|
||||
const ObjCPropertyDecl *ObjCProperty,
|
||||
const ObjCPropertyDecl *ObjCProperty,
|
||||
bool ObjCPropertyAccess) {
|
||||
// Delay if we're currently parsing a declaration.
|
||||
if (DelayedDiagnostics.shouldDelayDiagnostics()) {
|
||||
DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability(
|
||||
AR, Loc, D, UnknownObjCClass, ObjCProperty, Message,
|
||||
ObjCPropertyAccess));
|
||||
DelayedDiagnostics.add(
|
||||
DelayedDiagnostic::makeAvailability(
|
||||
AR, Loc, ReferringDecl, OffendingDecl, UnknownObjCClass,
|
||||
ObjCProperty, Message, ObjCPropertyAccess));
|
||||
return;
|
||||
}
|
||||
|
||||
Decl *Ctx = cast<Decl>(getCurLexicalContext());
|
||||
DoEmitAvailabilityWarning(*this, AR, Ctx, D, Message, Loc, UnknownObjCClass,
|
||||
ObjCProperty, ObjCPropertyAccess);
|
||||
DoEmitAvailabilityWarning(*this, AR, Ctx, ReferringDecl, OffendingDecl,
|
||||
Message, Loc, UnknownObjCClass, ObjCProperty,
|
||||
ObjCPropertyAccess);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -7336,19 +7376,21 @@ public:
|
||||
|
||||
void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
|
||||
NamedDecl *D, SourceRange Range) {
|
||||
|
||||
VersionTuple ContextVersion = AvailabilityStack.back();
|
||||
if (AvailabilityResult Result =
|
||||
SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr)) {
|
||||
AvailabilityResult Result;
|
||||
const NamedDecl *OffendingDecl;
|
||||
std::tie(Result, OffendingDecl) =
|
||||
SemaRef.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(), D);
|
||||
const AvailabilityAttr *AA =
|
||||
getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
|
||||
VersionTuple Introduced = AA->getIntroduced();
|
||||
|
||||
if (ContextVersion >= Introduced)
|
||||
if (AvailabilityStack.back() >= Introduced)
|
||||
return;
|
||||
|
||||
// If the context of this function is less available than D, we should not
|
||||
@ -7373,8 +7415,9 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
|
||||
SemaRef.getASTContext().getTargetInfo().getPlatformName())
|
||||
<< Introduced.getAsString();
|
||||
|
||||
SemaRef.Diag(D->getLocation(), diag::note_availability_specified_here)
|
||||
<< D << /* partial */ 3;
|
||||
SemaRef.Diag(OffendingDecl->getLocation(),
|
||||
diag::note_availability_specified_here)
|
||||
<< OffendingDecl << /* partial */ 3;
|
||||
|
||||
auto FixitDiag =
|
||||
SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
|
||||
|
@ -87,24 +87,9 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool HasRedeclarationWithoutAvailabilityInCategory(const Decl *D) {
|
||||
const auto *OMD = dyn_cast<ObjCMethodDecl>(D);
|
||||
if (!OMD)
|
||||
return false;
|
||||
const ObjCInterfaceDecl *OID = OMD->getClassInterface();
|
||||
if (!OID)
|
||||
return false;
|
||||
|
||||
for (const ObjCCategoryDecl *Cat : OID->visible_categories())
|
||||
if (ObjCMethodDecl *CatMeth =
|
||||
Cat->getMethod(OMD->getSelector(), OMD->isInstanceMethod()))
|
||||
if (!CatMeth->hasAttr<AvailabilityAttr>())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
AvailabilityResult
|
||||
Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) {
|
||||
std::pair<AvailabilityResult, const NamedDecl *>
|
||||
Sema::ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D,
|
||||
std::string *Message) {
|
||||
AvailabilityResult Result = D->getAvailability(Message);
|
||||
|
||||
// For typedefs, if the typedef declaration appears available look
|
||||
@ -121,45 +106,23 @@ Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) {
|
||||
}
|
||||
|
||||
// Forward class declarations get their attributes from their definition.
|
||||
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
|
||||
if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
|
||||
if (IDecl->getDefinition()) {
|
||||
D = IDecl->getDefinition();
|
||||
Result = D->getAvailability(Message);
|
||||
}
|
||||
}
|
||||
|
||||
if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
|
||||
if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
|
||||
if (Result == AR_Available) {
|
||||
const DeclContext *DC = ECD->getDeclContext();
|
||||
if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
|
||||
if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
|
||||
Result = TheEnumDecl->getAvailability(Message);
|
||||
D = TheEnumDecl;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result == AR_NotYetIntroduced) {
|
||||
// Don't do this for enums, they can't be redeclared.
|
||||
if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D))
|
||||
return AR_Available;
|
||||
|
||||
bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited();
|
||||
// Objective-C method declarations in categories are not modelled as
|
||||
// redeclarations, so manually look for a redeclaration in a category
|
||||
// if necessary.
|
||||
if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D))
|
||||
Warn = false;
|
||||
// In general, D will point to the most recent redeclaration. However,
|
||||
// for `@class A;` decls, this isn't true -- manually go through the
|
||||
// redecl chain in that case.
|
||||
if (Warn && isa<ObjCInterfaceDecl>(D))
|
||||
for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn;
|
||||
Redecl = Redecl->getPreviousDecl())
|
||||
if (!Redecl->hasAttr<AvailabilityAttr>() ||
|
||||
Redecl->getAttr<AvailabilityAttr>()->isInherited())
|
||||
Warn = false;
|
||||
|
||||
return Warn ? AR_NotYetIntroduced : AR_Available;
|
||||
}
|
||||
|
||||
return Result;
|
||||
return {Result, D};
|
||||
}
|
||||
|
||||
static void
|
||||
@ -167,32 +130,34 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
|
||||
const ObjCInterfaceDecl *UnknownObjCClass,
|
||||
bool ObjCPropertyAccess) {
|
||||
std::string Message;
|
||||
AvailabilityResult Result;
|
||||
const NamedDecl* OffendingDecl;
|
||||
// See if this declaration is unavailable, deprecated, or partial.
|
||||
if (AvailabilityResult Result =
|
||||
S.ShouldDiagnoseAvailabilityOfDecl(D, &Message)) {
|
||||
std::tie(Result, OffendingDecl) = S.ShouldDiagnoseAvailabilityOfDecl(D, &Message);
|
||||
if (Result == AR_Available)
|
||||
return;
|
||||
|
||||
if (Result == AR_NotYetIntroduced) {
|
||||
if (S.getCurFunctionOrMethodDecl()) {
|
||||
S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
|
||||
return;
|
||||
} else if (S.getCurBlock() || S.getCurLambda()) {
|
||||
S.getCurFunction()->HasPotentialAvailabilityViolations = true;
|
||||
return;
|
||||
}
|
||||
if (Result == AR_NotYetIntroduced) {
|
||||
if (S.getCurFunctionOrMethodDecl()) {
|
||||
S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
|
||||
return;
|
||||
} else if (S.getCurBlock() || S.getCurLambda()) {
|
||||
S.getCurFunction()->HasPotentialAvailabilityViolations = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const ObjCPropertyDecl *ObjCPDecl = nullptr;
|
||||
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
||||
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
|
||||
AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
|
||||
if (PDeclResult == Result)
|
||||
ObjCPDecl = PD;
|
||||
}
|
||||
}
|
||||
|
||||
S.EmitAvailabilityWarning(Result, D, Message, Loc, UnknownObjCClass,
|
||||
ObjCPDecl, ObjCPropertyAccess);
|
||||
}
|
||||
|
||||
const ObjCPropertyDecl *ObjCPDecl = nullptr;
|
||||
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
||||
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
|
||||
AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
|
||||
if (PDeclResult == Result)
|
||||
ObjCPDecl = PD;
|
||||
}
|
||||
}
|
||||
|
||||
S.EmitAvailabilityWarning(Result, D, OffendingDecl, Message, Loc,
|
||||
UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
|
||||
}
|
||||
|
||||
/// \brief Emit a note explaining that this function is deleted.
|
||||
|
@ -21,6 +21,9 @@ ATSFontGetPostScriptName(int flags) __attribute__((availability(macosx,introduce
|
||||
extern void
|
||||
PartiallyAvailable() __attribute__((availability(macosx,introduced=10.8)));
|
||||
|
||||
#ifdef WARN_PARTIAL
|
||||
// expected-note@+2 2 {{marked partial here}}
|
||||
#endif
|
||||
enum __attribute__((availability(macosx,introduced=10.8))) PartialEnum {
|
||||
kPartialEnumConstant,
|
||||
};
|
||||
@ -35,11 +38,19 @@ void test_10095131() {
|
||||
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() {
|
||||
PartiallyAvailable(); // Don't warn.
|
||||
|
||||
// enums should never warn.
|
||||
#ifdef WARN_PARTIAL
|
||||
// expected-warning@+4 {{'PartiallyAvailable' is only available on macOS 10.8 or newer}} expected-note@+4 {{__builtin_available}}
|
||||
// expected-warning@+4 {{'PartialEnum' is only available on macOS 10.8 or newer}} expected-note@+4 {{__builtin_available}}
|
||||
// expected-warning@+3 {{'kPartialEnumConstant' is only available on macOS 10.8 or newer}} expected-note@+3 {{__builtin_available}}
|
||||
#endif
|
||||
PartiallyAvailable();
|
||||
enum PartialEnum p = kPartialEnumConstant;
|
||||
}
|
||||
|
||||
@ -86,13 +97,13 @@ enum Original {
|
||||
OriginalUnavailable __attribute__((availability(macosx, unavailable))) // expected-note + {{'OriginalUnavailable' has been explicitly marked unavailable here}}
|
||||
};
|
||||
|
||||
enum AllDeprecated {
|
||||
AllDeprecatedCase, // expected-note + {{'AllDeprecatedCase' has been explicitly marked deprecated here}}
|
||||
enum AllDeprecated { // expected-note + {{'AllDeprecated' has been explicitly marked deprecated here}}
|
||||
AllDeprecatedCase,
|
||||
AllDeprecatedUnavailable __attribute__((availability(macosx, unavailable))) // expected-note + {{'AllDeprecatedUnavailable' has been explicitly marked unavailable here}}
|
||||
} __attribute__((availability(macosx, deprecated=10.2)));
|
||||
|
||||
enum AllUnavailable {
|
||||
AllUnavailableCase, // expected-note + {{'AllUnavailableCase' has been explicitly marked unavailable here}}
|
||||
enum AllUnavailable { // expected-note + {{'AllUnavailable' has been explicitly marked unavailable here}}
|
||||
AllUnavailableCase,
|
||||
} __attribute__((availability(macosx, unavailable)));
|
||||
|
||||
enum User {
|
||||
|
@ -104,9 +104,9 @@ foo_dep test17, // expected-warning {{'foo_dep' is deprecated}}
|
||||
test19;
|
||||
|
||||
// rdar://problem/8518751
|
||||
enum __attribute__((deprecated)) Test20 { // expected-note {{'Test20' has been explicitly marked deprecated here}}
|
||||
enum __attribute__((deprecated)) Test20 { // expected-note 2 {{'Test20' has been explicitly marked deprecated here}}
|
||||
test20_a __attribute__((deprecated)), // expected-note {{'test20_a' has been explicitly marked deprecated here}}
|
||||
test20_b // expected-note {{'test20_b' has been explicitly marked deprecated here}}
|
||||
test20_b
|
||||
};
|
||||
void test20() {
|
||||
enum Test20 f; // expected-warning {{'Test20' is deprecated}}
|
||||
|
@ -36,13 +36,13 @@ void unavail(void) {
|
||||
|
||||
// rdar://10201690
|
||||
enum foo {
|
||||
a = 1, // expected-note {{'a' has been explicitly marked deprecated here}}
|
||||
a = 1,
|
||||
b __attribute__((deprecated())) = 2, // expected-note {{'b' has been explicitly marked deprecated here}}
|
||||
c = 3
|
||||
}__attribute__((deprecated()));
|
||||
}__attribute__((deprecated())); // expected-note {{'foo' has been explicitly marked deprecated here}}
|
||||
|
||||
enum fee { // expected-note {{'fee' has been explicitly marked unavailable here}}
|
||||
r = 1, // expected-note {{'r' has been explicitly marked unavailable here}}
|
||||
enum fee { // expected-note 2 {{'fee' has been explicitly marked unavailable here}}
|
||||
r = 1,
|
||||
s = 2,
|
||||
t = 3
|
||||
}__attribute__((unavailable()));
|
||||
|
@ -199,8 +199,8 @@ namespace test5 {
|
||||
|
||||
// rdar://problem/8518751
|
||||
namespace test6 {
|
||||
enum __attribute__((deprecated)) A { // expected-note {{'A' has been explicitly marked deprecated here}}
|
||||
a0 // expected-note {{'a0' has been explicitly marked deprecated here}}
|
||||
enum __attribute__((deprecated)) A { // expected-note 2 {{'A' has been explicitly marked deprecated here}}
|
||||
a0
|
||||
};
|
||||
void testA() {
|
||||
A x; // expected-warning {{'A' is deprecated}}
|
||||
@ -218,8 +218,8 @@ namespace test6 {
|
||||
}
|
||||
|
||||
template <class T> struct C {
|
||||
enum __attribute__((deprecated)) Enum { // expected-note {{'Enum' has been explicitly marked deprecated here}}
|
||||
c0 // expected-note {{'c0' has been explicitly marked deprecated here}}
|
||||
enum __attribute__((deprecated)) Enum { // expected-note 2 {{'Enum' has been explicitly marked deprecated here}}
|
||||
c0
|
||||
};
|
||||
};
|
||||
void testC() {
|
||||
|
@ -13,7 +13,7 @@
|
||||
@interface A <P>
|
||||
- (void)method __attribute__((availability(macosx,introduced=10.1,deprecated=10.2))); // expected-note {{'method' has been explicitly marked deprecated here}}
|
||||
#if defined(WARN_PARTIAL)
|
||||
// expected-note@+2 {{'partialMethod' has been explicitly marked partial here}}
|
||||
// expected-note@+2 2 {{'partialMethod' has been explicitly marked partial here}}
|
||||
#endif
|
||||
- (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
|
||||
|
||||
@ -66,7 +66,10 @@ void f(A *a, B *b) {
|
||||
@end
|
||||
|
||||
void f_after_redecl(A *a, B *b) {
|
||||
[a partialMethod]; // no warning
|
||||
#ifdef WARN_PARTIAL
|
||||
// expected-warning@+2{{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2 {{@available}}
|
||||
#endif
|
||||
[a partialMethod];
|
||||
[b partialMethod]; // no warning
|
||||
[a partial_proto_method]; // no warning
|
||||
[b partial_proto_method]; // no warning
|
||||
@ -133,6 +136,10 @@ id NSNibOwner, topNibObjects;
|
||||
@end
|
||||
|
||||
@interface PartialI <PartialProt>
|
||||
#ifdef WARN_PARTIAL
|
||||
// expected-note@+3{{marked partial here}}
|
||||
// expected-note@+3{{marked partial here}}
|
||||
#endif
|
||||
- (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
|
||||
+ (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
|
||||
@end
|
||||
@ -160,14 +167,20 @@ id NSNibOwner, topNibObjects;
|
||||
@end
|
||||
|
||||
void partialfun(PartialI* a) {
|
||||
[a partialMethod]; // no warning
|
||||
#ifdef WARN_PARTIAL
|
||||
// expected-warning@+2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2{{@available}}
|
||||
#endif
|
||||
[a partialMethod];
|
||||
[a ipartialMethod1]; // no warning
|
||||
#if defined(WARN_PARTIAL)
|
||||
// expected-warning@+2 {{'ipartialMethod2' is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'ipartialMethod2' in an @available check to silence this warning}}
|
||||
#endif
|
||||
[a ipartialMethod2];
|
||||
[a ppartialMethod]; // no warning
|
||||
[PartialI partialMethod]; // no warning
|
||||
#ifdef WARN_PARTIAL
|
||||
// expected-warning@+2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2 {{@available}}
|
||||
#endif
|
||||
[PartialI partialMethod];
|
||||
[PartialI ipartialMethod1]; // no warning
|
||||
#if defined(WARN_PARTIAL)
|
||||
// expected-warning@+2 {{'ipartialMethod2' is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'ipartialMethod2' in an @available check to silence this warning}}
|
||||
@ -177,20 +190,23 @@ void partialfun(PartialI* a) {
|
||||
}
|
||||
|
||||
#if defined(WARN_PARTIAL)
|
||||
// expected-note@+2 {{'PartialI2' has been explicitly marked partial here}}
|
||||
// expected-note@+2 2 {{'PartialI2' has been explicitly marked partial here}}
|
||||
#endif
|
||||
__attribute__((availability(macosx, introduced = 10.8))) @interface PartialI2
|
||||
@end
|
||||
|
||||
#if defined(WARN_PARTIAL)
|
||||
// expected-warning@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{explicitly redeclare 'PartialI2' to silence this warning}}
|
||||
// expected-warning@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{annotate 'partialinter1' with an availability attribute to silence}}
|
||||
#endif
|
||||
void partialinter1(PartialI2* p) {
|
||||
}
|
||||
|
||||
@class PartialI2;
|
||||
|
||||
void partialinter2(PartialI2* p) { // no warning
|
||||
#ifdef WARN_PARTIAL
|
||||
// expected-warning@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{annotate 'partialinter2' with an availability attribute to silence}}
|
||||
#endif
|
||||
void partialinter2(PartialI2* p) {
|
||||
}
|
||||
|
||||
|
||||
|
@ -96,16 +96,16 @@ typedef int AVAILABLE_NEXT new_int;
|
||||
FUNC_AVAILABLE new_int x;
|
||||
#ifndef NO_WARNING
|
||||
#ifdef MAC
|
||||
// expected-warning@-3 {{'new_int' is partial: introduced in macOS 10.14}} expected-note@-3 {{explicitly redeclare 'new_int' to silence this warning}}
|
||||
// expected-warning@-3 {{'new_int' is partial: introduced in macOS 10.14}} expected-note@-3 {{annotate 'x' with an availability attribute to silence}}
|
||||
#endif
|
||||
#ifdef IOS
|
||||
// expected-warning@-6 {{'new_int' is partial: introduced in iOS 12}} expected-note@-6 {{explicitly redeclare 'new_int' to silence this warning}}
|
||||
// expected-warning@-6 {{'new_int' is partial: introduced in iOS 12}} expected-note@-6 {{annotate 'x' with an availability attribute to silence}}
|
||||
#endif
|
||||
#ifdef TVOS
|
||||
// expected-warning@-9 {{'new_int' is partial: introduced in tvOS 13}} expected-note@-9 {{explicitly redeclare 'new_int' to silence this warning}}
|
||||
// expected-warning@-9 {{'new_int' is partial: introduced in tvOS 13}} expected-note@-9 {{annotate 'x' with an availability attribute to silence}}
|
||||
#endif
|
||||
#ifdef WATCHOS
|
||||
// expected-warning@-12 {{'new_int' is partial: introduced in watchOS 5}} expected-note@-12 {{explicitly redeclare 'new_int' to silence this warning}}
|
||||
// expected-warning@-12 {{'new_int' is partial: introduced in watchOS 5}} expected-note@-12 {{annotate 'x' with an availability attribute to silence}}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
#define AVAILABLE_10_11 __attribute__((availability(macos, introduced = 10.11)))
|
||||
#define AVAILABLE_10_12 __attribute__((availability(macos, introduced = 10.12)))
|
||||
|
||||
typedef int AVAILABLE_10_12 new_int; // expected-note + {{marked partial here}}
|
||||
|
||||
int func_10_11() AVAILABLE_10_11; // expected-note 4 {{'func_10_11' has been explicitly marked partial here}}
|
||||
|
||||
#ifdef OBJCPP
|
||||
@ -70,9 +72,9 @@ void use_typedef() {
|
||||
}
|
||||
|
||||
__attribute__((objc_root_class))
|
||||
AVAILABLE_10_11 @interface Class_10_11 {
|
||||
AVAILABLE_10_11 @interface Class_10_11 { // expected-note{{annotate 'Class_10_11' with an availability attribute to silence}}
|
||||
int_10_11 foo;
|
||||
int_10_12 bar; // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}}
|
||||
int_10_12 bar; // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}}
|
||||
}
|
||||
- (void)method1;
|
||||
- (void)method2;
|
||||
@ -125,7 +127,7 @@ void test_blocks() {
|
||||
};
|
||||
}
|
||||
|
||||
void test_params(int_10_12 x); // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}}
|
||||
void test_params(int_10_12 x); // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{annotate 'test_params' with an availability attribute to silence}}
|
||||
|
||||
void test_params2(int_10_12 x) AVAILABLE_10_12; // no warn
|
||||
|
||||
@ -234,3 +236,30 @@ void functionInFunction() {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct InStruct { // expected-note{{annotate 'InStruct' with an availability attribute to silence}}
|
||||
new_int mem; // expected-warning{{'new_int' is partial}}
|
||||
|
||||
struct { new_int mem; } anon; // expected-warning{{'new_int' is partial}} expected-note{{annotate anonymous struct with an availability attribute}}
|
||||
};
|
||||
|
||||
#ifdef OBJCPP
|
||||
static constexpr int AVAILABLE_10_12 SomeConstexprValue = 2; // expected-note{{marked partial here}}
|
||||
typedef enum { // expected-note{{annotate anonymous enum with an availability attribute}}
|
||||
SomeValue = SomeConstexprValue // expected-warning{{'SomeConstexprValue' is partial}}
|
||||
} SomeEnum;
|
||||
#endif
|
||||
|
||||
@interface InInterface
|
||||
-(new_int)meth; // expected-warning{{'new_int' is partial}} expected-note{{annotate 'meth' with an availability attribute}}
|
||||
@end
|
||||
|
||||
@interface Proper // expected-note{{annotate 'Proper' with an availability attribute}}
|
||||
@property (class) new_int x; // expected-warning{{'new_int' is partial}}
|
||||
@end
|
||||
|
||||
void with_local_struct() {
|
||||
struct local { // expected-note{{annotate 'local' with an availability attribute}}
|
||||
new_int x; // expected-warning{{'new_int' is partial}}
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user