From 796a3e2bdd2710275c4871d00616b5b84aae2e32 Mon Sep 17 00:00:00 2001 From: Erik Pilkington Date: Fri, 5 Aug 2016 22:59:03 +0000 Subject: [PATCH] [NFC][ObjC Availability] Refactor DiagnoseAvailabilityOfDecl Differential revision: https://reviews.llvm.org/D23221 llvm-svn: 277887 --- clang/include/clang/Sema/DelayedDiagnostic.h | 2 +- clang/include/clang/Sema/Sema.h | 20 +++-- clang/lib/Sema/DelayedDiagnostic.cpp | 18 ++-- clang/lib/Sema/SemaDeclAttr.cpp | 32 ++++--- clang/lib/Sema/SemaExpr.cpp | 127 +++++++++++++-------------- 5 files changed, 101 insertions(+), 98 deletions(-) diff --git a/clang/include/clang/Sema/DelayedDiagnostic.h b/clang/include/clang/Sema/DelayedDiagnostic.h index 155b3aa..1d184fb 100644 --- a/clang/include/clang/Sema/DelayedDiagnostic.h +++ b/clang/include/clang/Sema/DelayedDiagnostic.h @@ -122,7 +122,7 @@ public: void Destroy(); - static DelayedDiagnostic makeAvailability(Sema::AvailabilityDiagnostic AD, + static DelayedDiagnostic makeAvailability(AvailabilityResult AR, SourceLocation Loc, const NamedDecl *D, const ObjCInterfaceDecl *UnknownObjCClass, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5e8b3cb..d50fb34 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3629,13 +3629,10 @@ public: void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); - enum AvailabilityDiagnostic { AD_Deprecation, AD_Unavailable, AD_Partial }; - - void EmitAvailabilityWarning(AvailabilityDiagnostic AD, - NamedDecl *D, StringRef Message, - SourceLocation Loc, + void EmitAvailabilityWarning(AvailabilityResult AR, NamedDecl *D, + StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, - const ObjCPropertyDecl *ObjCProperty, + const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess); bool makeUnavailableInSystemHeader(SourceLocation loc, @@ -9608,6 +9605,17 @@ public: /// availability attribuite effectively has the availability of the interface. VersionTuple getVersionForDecl(const Decl *Ctx) const; + /// \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. + /// + /// \param ContextVersion The version to compare availability against. + AvailabilityResult + ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, VersionTuple ContextVersion, + std::string *Message); + const DeclContext *getCurObjCLexicalContext() const { const DeclContext *DC = getCurLexicalContext(); // A category implicitly has the attribute of the interface. diff --git a/clang/lib/Sema/DelayedDiagnostic.cpp b/clang/lib/Sema/DelayedDiagnostic.cpp index ceea04f..f695030 100644 --- a/clang/lib/Sema/DelayedDiagnostic.cpp +++ b/clang/lib/Sema/DelayedDiagnostic.cpp @@ -20,7 +20,7 @@ using namespace clang; using namespace sema; DelayedDiagnostic -DelayedDiagnostic::makeAvailability(Sema::AvailabilityDiagnostic AD, +DelayedDiagnostic::makeAvailability(AvailabilityResult AD, SourceLocation Loc, const NamedDecl *D, const ObjCInterfaceDecl *UnknownObjCClass, @@ -29,14 +29,14 @@ DelayedDiagnostic::makeAvailability(Sema::AvailabilityDiagnostic AD, bool ObjCPropertyAccess) { DelayedDiagnostic DD; switch (AD) { - case Sema::AD_Deprecation: - DD.Kind = Deprecation; - break; - case Sema::AD_Unavailable: - DD.Kind = Unavailable; - break; - case Sema::AD_Partial: - llvm_unreachable("AD_Partial diags should not be delayed"); + case AR_Deprecated: + DD.Kind = Deprecation; + break; + case AR_Unavailable: + DD.Kind = Unavailable; + break; + default: + llvm_unreachable("partial diags should not be delayed"); } DD.Triggered = false; DD.Loc = Loc; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index edecc06..d74cebc 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6246,7 +6246,7 @@ static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, return nullptr; } -static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, +static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *D, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, @@ -6264,7 +6264,7 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, // Don't warn if our current context is deprecated or unavailable. switch (K) { - case Sema::AD_Deprecation: + case AR_Deprecated: if (isDeclDeprecated(Ctx) || isDeclUnavailable(Ctx)) return; diag = !ObjCPropertyAccess ? diag::warn_deprecated @@ -6275,7 +6275,7 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, available_here_select_kind = /* deprecated */ 2; break; - case Sema::AD_Unavailable: + case AR_Unavailable: if (isDeclUnavailable(Ctx)) return; diag = !ObjCPropertyAccess ? diag::err_unavailable @@ -6329,18 +6329,21 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, } break; - case Sema::AD_Partial: + case AR_NotYetIntroduced: diag = diag::warn_partial_availability; diag_message = diag::warn_partial_message; diag_fwdclass_message = diag::warn_partial_fwdclass_message; property_note_select = /* partial */ 2; available_here_select_kind = /* partial */ 3; break; + + case AR_Available: + llvm_unreachable("Warning for availability of available declaration?"); } CharSourceRange UseRange; StringRef Replacement; - if (K == Sema::AD_Deprecation) { + if (K == AR_Deprecated) { if (auto attr = D->getAttr()) Replacement = attr->getReplacement(); if (auto attr = getAttrForPlatform(S.Context, D)) @@ -6393,7 +6396,7 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, S.Diag(D->getLocation(), diag_available_here) << D << available_here_select_kind; - if (K == Sema::AD_Partial) + if (K == AR_NotYetIntroduced) S.Diag(Loc, diag::note_partial_availability_silence) << D; } @@ -6401,12 +6404,12 @@ static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, Decl *Ctx) { assert(DD.Kind == DelayedDiagnostic::Deprecation || DD.Kind == DelayedDiagnostic::Unavailable); - Sema::AvailabilityDiagnostic AD = DD.Kind == DelayedDiagnostic::Deprecation - ? Sema::AD_Deprecation - : Sema::AD_Unavailable; + AvailabilityResult AR = DD.Kind == DelayedDiagnostic::Deprecation + ? AR_Deprecated + : AR_Unavailable; DD.Triggered = true; DoEmitAvailabilityWarning( - S, AD, Ctx, DD.getDeprecationDecl(), DD.getDeprecationMessage(), DD.Loc, + S, AR, Ctx, DD.getDeprecationDecl(), DD.getDeprecationMessage(), DD.Loc, DD.getUnknownObjCClass(), DD.getObjCProperty(), false); } @@ -6466,22 +6469,23 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) { curPool->steal(pool); } -void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD, +void Sema::EmitAvailabilityWarning(AvailabilityResult AR, NamedDecl *D, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { // Delay if we're currently parsing a declaration. - if (DelayedDiagnostics.shouldDelayDiagnostics() && AD != AD_Partial) { + if (DelayedDiagnostics.shouldDelayDiagnostics() && + AR != AR_NotYetIntroduced) { DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability( - AD, Loc, D, UnknownObjCClass, ObjCProperty, Message, + AR, Loc, D, UnknownObjCClass, ObjCProperty, Message, ObjCPropertyAccess)); return; } Decl *Ctx = cast(getCurLexicalContext()); - DoEmitAvailabilityWarning(*this, AD, Ctx, D, Message, Loc, UnknownObjCClass, + DoEmitAvailabilityWarning(*this, AR, Ctx, D, Message, Loc, UnknownObjCClass, ObjCProperty, ObjCPropertyAccess); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 6539790..357a6ad 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -103,18 +103,9 @@ static bool HasRedeclarationWithoutAvailabilityInCategory(const Decl *D) { return false; } -static AvailabilityResult -DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass, - bool ObjCPropertyAccess) { - VersionTuple ContextVersion; - if (const DeclContext *DC = S.getCurObjCLexicalContext()) - ContextVersion = S.getVersionForDecl(cast(DC)); - - // See if this declaration is unavailable, deprecated, or partial in the - // current context. - std::string Message; - AvailabilityResult Result = D->getAvailability(&Message, ContextVersion); +AvailabilityResult Sema::ShouldDiagnoseAvailabilityOfDecl( + NamedDecl *&D, VersionTuple ContextVersion, std::string *Message) { + AvailabilityResult Result = D->getAvailability(Message, ContextVersion); // For typedefs, if the typedef declaration appears available look // to the underlying type to see if it is more restrictive. @@ -122,18 +113,18 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, if (Result == AR_Available) { if (const TagType *TT = TD->getUnderlyingType()->getAs()) { D = TT->getDecl(); - Result = D->getAvailability(&Message, ContextVersion); + Result = D->getAvailability(Message, ContextVersion); continue; } } break; } - + // Forward class declarations get their attributes from their definition. if (ObjCInterfaceDecl *IDecl = dyn_cast(D)) { if (IDecl->getDefinition()) { D = IDecl->getDefinition(); - Result = D->getAvailability(&Message, ContextVersion); + Result = D->getAvailability(Message, ContextVersion); } } @@ -141,12 +132,58 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, if (Result == AR_Available) { const DeclContext *DC = ECD->getDeclContext(); if (const EnumDecl *TheEnumDecl = dyn_cast(DC)) - Result = TheEnumDecl->getAvailability(&Message, ContextVersion); + Result = TheEnumDecl->getAvailability(Message, ContextVersion); } - const ObjCPropertyDecl *ObjCPDecl = nullptr; - if (Result == AR_Deprecated || Result == AR_Unavailable || - Result == AR_NotYetIntroduced) { + switch (Result) { + case AR_Available: + return Result; + + case AR_Unavailable: + case AR_Deprecated: + return getCurContextAvailability() != Result ? Result : AR_Available; + + case AR_NotYetIntroduced: { + // Don't do this for enums, they can't be redeclared. + if (isa(D) || isa(D)) + return AR_Available; + + bool Warn = !D->getAttr()->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(D)) + for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn; + Redecl = Redecl->getPreviousDecl()) + if (!Redecl->hasAttr() || + Redecl->getAttr()->isInherited()) + Warn = false; + + return Warn ? AR_NotYetIntroduced : AR_Available; + } + } +} + +static void +DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass, + bool ObjCPropertyAccess) { + VersionTuple ContextVersion; + if (const DeclContext *DC = S.getCurObjCLexicalContext()) + ContextVersion = S.getVersionForDecl(cast(DC)); + + std::string Message; + // See if this declaration is unavailable, deprecated, or partial in the + // current context. + if (AvailabilityResult Result = + S.ShouldDiagnoseAvailabilityOfDecl(D, ContextVersion, &Message)) { + + const ObjCPropertyDecl *ObjCPDecl = nullptr; if (const ObjCMethodDecl *MD = dyn_cast(D)) { if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { AvailabilityResult PDeclResult = @@ -155,56 +192,10 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, ObjCPDecl = PD; } } - } - - switch (Result) { - case AR_Available: - break; - case AR_Deprecated: - if (S.getCurContextAvailability() != AR_Deprecated) - S.EmitAvailabilityWarning(Sema::AD_Deprecation, - D, Message, Loc, UnknownObjCClass, ObjCPDecl, - ObjCPropertyAccess); - break; - - case AR_NotYetIntroduced: { - // Don't do this for enums, they can't be redeclared. - if (isa(D) || isa(D)) - break; - - bool Warn = !D->getAttr()->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(D)) - for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn; - Redecl = Redecl->getPreviousDecl()) - if (!Redecl->hasAttr() || - Redecl->getAttr()->isInherited()) - Warn = false; - - if (Warn) - S.EmitAvailabilityWarning(Sema::AD_Partial, D, Message, Loc, - UnknownObjCClass, ObjCPDecl, - ObjCPropertyAccess); - break; - } - - case AR_Unavailable: - if (S.getCurContextAvailability() != AR_Unavailable) - S.EmitAvailabilityWarning(Sema::AD_Unavailable, - D, Message, Loc, UnknownObjCClass, ObjCPDecl, - ObjCPropertyAccess); - break; - - } - return Result; + S.EmitAvailabilityWarning(Result, D, Message, Loc, UnknownObjCClass, + ObjCPDecl, ObjCPropertyAccess); + } } /// \brief Emit a note explaining that this function is deleted. -- 2.7.4