r284265 - [Sema] Refactor context checking for availability diagnostics
Erik Pilkington via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 14 12:08:01 PDT 2016
Author: epilk
Date: Fri Oct 14 14:08:01 2016
New Revision: 284265
URL: http://llvm.org/viewvc/llvm-project?rev=284265&view=rev
Log:
[Sema] Refactor context checking for availability diagnostics
This commit combines a couple of redundant functions that do availability
attribute context checking into a more correct/simpler one.
Differential revision: https://reviews.llvm.org/D25283
Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/test/SemaObjC/class-unavail-warning.m
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=284265&r1=284264&r2=284265&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Oct 14 14:08:01 2016
@@ -9889,23 +9889,16 @@ public:
return OriginalLexicalContext ? OriginalLexicalContext : CurContext;
}
- AvailabilityResult getCurContextAvailability() const;
-
- /// \brief Get the verison that this context implies.
- /// For instance, a method in an interface that is annotated with an
- /// 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);
+ /// \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);
const DeclContext *getCurObjCLexicalContext() const {
const DeclContext *DC = getCurLexicalContext();
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=284265&r1=284264&r2=284265&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Oct 14 14:08:01 2016
@@ -15615,29 +15615,3 @@ void Sema::ActOnPragmaWeakAlias(Identifi
Decl *Sema::getObjCDeclContext() const {
return (dyn_cast_or_null<ObjCContainerDecl>(CurContext));
}
-
-AvailabilityResult Sema::getCurContextAvailability() const {
- const Decl *D = cast_or_null<Decl>(getCurObjCLexicalContext());
- if (!D)
- return AR_Available;
-
- // If we are within an Objective-C method, we should consult
- // both the availability of the method as well as the
- // enclosing class. If the class is (say) deprecated,
- // the entire method is considered deprecated from the
- // purpose of checking if the current context is deprecated.
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- AvailabilityResult R = MD->getAvailability();
- if (R != AR_Available)
- return R;
- D = MD->getClassInterface();
- }
- // If we are within an Objective-c @implementation, it
- // gets the same availability context as the @interface.
- else if (const ObjCImplementationDecl *ID =
- dyn_cast<ObjCImplementationDecl>(D)) {
- D = ID->getClassInterface();
- }
- // Recover from user error.
- return D ? D->getAvailability() : AR_Available;
-}
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=284265&r1=284264&r2=284265&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Oct 14 14:08:01 2016
@@ -6317,30 +6317,6 @@ static void handleDelayedForbiddenType(S
diag.Triggered = true;
}
-static bool isDeclDeprecated(Decl *D) {
- do {
- if (D->isDeprecated())
- return true;
- // A category implicitly has the availability of the interface.
- if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D))
- if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface())
- return Interface->isDeprecated();
- } while ((D = cast_or_null<Decl>(D->getDeclContext())));
- return false;
-}
-
-static bool isDeclUnavailable(Decl *D) {
- do {
- if (D->isUnavailable())
- return true;
- // A category implicitly has the availability of the interface.
- if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D))
- if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface())
- return Interface->isUnavailable();
- } while ((D = cast_or_null<Decl>(D->getDeclContext())));
- return false;
-}
-
static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
const Decl *D) {
// Check each AvailabilityAttr to find the one for this platform.
@@ -6369,6 +6345,49 @@ static const AvailabilityAttr *getAttrFo
return nullptr;
}
+/// \brief whether we should emit a diagnostic for \c K and \c DeclVersion in
+/// the context of \c Ctx. For example, we should emit an unavailable diagnostic
+/// in a deprecated context, but not the other way around.
+static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K,
+ VersionTuple DeclVersion,
+ Decl *Ctx) {
+ assert(K != AR_Available && "Expected an unavailable declaration here!");
+
+ // 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;
+ } else if (K == AR_Deprecated)
+ if (C->isDeprecated())
+ return true;
+
+ if (C->isUnavailable())
+ return true;
+ return false;
+ };
+
+ do {
+ if (CheckContext(Ctx))
+ return false;
+
+ // An implementation implicitly has the availability of the interface.
+ if (auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) {
+ if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface())
+ if (CheckContext(Interface))
+ return false;
+ }
+ // A category implicitly has the availability of the interface.
+ else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx))
+ if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface())
+ if (CheckContext(Interface))
+ return false;
+ } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext())));
+
+ return true;
+}
+
static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
Decl *Ctx, const NamedDecl *D,
StringRef Message, SourceLocation Loc,
@@ -6385,11 +6404,15 @@ static void DoEmitAvailabilityWarning(Se
// Matches diag::note_availability_specified_here.
unsigned available_here_select_kind;
- // Don't warn if our current context is deprecated or unavailable.
+ VersionTuple DeclVersion;
+ if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, D))
+ DeclVersion = AA->getIntroduced();
+
+ if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx))
+ return;
+
switch (K) {
case AR_Deprecated:
- if (isDeclDeprecated(Ctx) || isDeclUnavailable(Ctx))
- return;
diag = !ObjCPropertyAccess ? diag::warn_deprecated
: diag::warn_property_method_deprecated;
diag_message = diag::warn_deprecated_message;
@@ -6399,8 +6422,6 @@ static void DoEmitAvailabilityWarning(Se
break;
case AR_Unavailable:
- if (isDeclUnavailable(Ctx))
- return;
diag = !ObjCPropertyAccess ? diag::err_unavailable
: diag::err_property_method_unavailable;
diag_message = diag::err_unavailable_message;
@@ -6615,29 +6636,6 @@ void Sema::EmitAvailabilityWarning(Avail
ObjCProperty, ObjCPropertyAccess);
}
-VersionTuple Sema::getVersionForDecl(const Decl *D) const {
- assert(D && "Expected a declaration here!");
-
- VersionTuple DeclVersion;
- if (const auto *AA = getAttrForPlatform(getASTContext(), D))
- DeclVersion = AA->getIntroduced();
-
- const ObjCInterfaceDecl *Interface = nullptr;
-
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
- Interface = MD->getClassInterface();
- else if (const auto *ID = dyn_cast<ObjCImplementationDecl>(D))
- Interface = ID->getClassInterface();
-
- if (Interface) {
- if (const auto *AA = getAttrForPlatform(getASTContext(), Interface))
- if (AA->getIntroduced() > DeclVersion)
- DeclVersion = AA->getIntroduced();
- }
-
- return std::max(DeclVersion, Context.getTargetInfo().getPlatformMinVersion());
-}
-
namespace {
/// \brief This class implements -Wunguarded-availability.
@@ -6651,6 +6649,7 @@ class DiagnoseUnguardedAvailability
typedef RecursiveASTVisitor<DiagnoseUnguardedAvailability> Base;
Sema &SemaRef;
+ Decl *Ctx;
/// Stack of potentially nested 'if (@available(...))'s.
SmallVector<VersionTuple, 8> AvailabilityStack;
@@ -6658,9 +6657,10 @@ class DiagnoseUnguardedAvailability
void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range);
public:
- DiagnoseUnguardedAvailability(Sema &SemaRef, VersionTuple BaseVersion)
- : SemaRef(SemaRef) {
- AvailabilityStack.push_back(BaseVersion);
+ DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx)
+ : SemaRef(SemaRef), Ctx(Ctx) {
+ AvailabilityStack.push_back(
+ SemaRef.Context.getTargetInfo().getPlatformMinVersion());
}
void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }
@@ -6693,8 +6693,8 @@ void DiagnoseUnguardedAvailability::Diag
NamedDecl *D, SourceRange Range) {
VersionTuple ContextVersion = AvailabilityStack.back();
- if (AvailabilityResult Result = SemaRef.ShouldDiagnoseAvailabilityOfDecl(
- D, ContextVersion, nullptr)) {
+ if (AvailabilityResult Result =
+ SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr)) {
// All other diagnostic kinds have already been handled in
// DiagnoseAvailabilityOfDecl.
if (Result != AR_NotYetIntroduced)
@@ -6703,6 +6703,14 @@ void DiagnoseUnguardedAvailability::Diag
const AvailabilityAttr *AA = getAttrForPlatform(SemaRef.getASTContext(), D);
VersionTuple Introduced = AA->getIntroduced();
+ if (ContextVersion >= Introduced)
+ return;
+
+ // If the context of this function is less available than D, we should not
+ // emit a diagnostic.
+ if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx))
+ return;
+
SemaRef.Diag(Range.getBegin(), diag::warn_unguarded_availability)
<< Range << D
<< AvailabilityAttr::getPrettyPlatformName(
@@ -6777,6 +6785,5 @@ void Sema::DiagnoseUnguardedAvailability
assert(Body && "Need a body here!");
- VersionTuple BaseVersion = getVersionForDecl(D);
- DiagnoseUnguardedAvailability(*this, BaseVersion).IssueDiagnostics(Body);
+ DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);
}
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=284265&r1=284264&r2=284265&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Oct 14 14:08:01 2016
@@ -103,9 +103,9 @@ static bool HasRedeclarationWithoutAvail
return false;
}
-AvailabilityResult Sema::ShouldDiagnoseAvailabilityOfDecl(
- NamedDecl *&D, VersionTuple ContextVersion, std::string *Message) {
- AvailabilityResult Result = D->getAvailability(Message, ContextVersion);
+AvailabilityResult
+Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) {
+ AvailabilityResult Result = D->getAvailability(Message);
// For typedefs, if the typedef declaration appears available look
// to the underlying type to see if it is more restrictive.
@@ -113,7 +113,7 @@ AvailabilityResult Sema::ShouldDiagnoseA
if (Result == AR_Available) {
if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
D = TT->getDecl();
- Result = D->getAvailability(Message, ContextVersion);
+ Result = D->getAvailability(Message);
continue;
}
}
@@ -124,7 +124,7 @@ AvailabilityResult Sema::ShouldDiagnoseA
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
if (IDecl->getDefinition()) {
D = IDecl->getDefinition();
- Result = D->getAvailability(Message, ContextVersion);
+ Result = D->getAvailability(Message);
}
}
@@ -132,18 +132,10 @@ AvailabilityResult Sema::ShouldDiagnoseA
if (Result == AR_Available) {
const DeclContext *DC = ECD->getDeclContext();
if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
- Result = TheEnumDecl->getAvailability(Message, ContextVersion);
+ Result = TheEnumDecl->getAvailability(Message);
}
- switch (Result) {
- case AR_Available:
- return Result;
-
- case AR_Unavailable:
- case AR_Deprecated:
- return getCurContextAvailability() != Result ? Result : AR_Available;
-
- case AR_NotYetIntroduced: {
+ 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;
@@ -166,23 +158,18 @@ AvailabilityResult Sema::ShouldDiagnoseA
return Warn ? AR_NotYetIntroduced : AR_Available;
}
- }
- llvm_unreachable("Unknown availability result!");
+
+ return Result;
}
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<Decl>(DC));
-
std::string Message;
- // See if this declaration is unavailable, deprecated, or partial in the
- // current context.
+ // See if this declaration is unavailable, deprecated, or partial.
if (AvailabilityResult Result =
- S.ShouldDiagnoseAvailabilityOfDecl(D, ContextVersion, &Message)) {
+ S.ShouldDiagnoseAvailabilityOfDecl(D, &Message)) {
if (Result == AR_NotYetIntroduced && S.getCurFunctionOrMethodDecl()) {
S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
@@ -192,8 +179,7 @@ DiagnoseAvailabilityOfDecl(Sema &S, Name
const ObjCPropertyDecl *ObjCPDecl = nullptr;
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
- AvailabilityResult PDeclResult =
- PD->getAvailability(nullptr, ContextVersion);
+ AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
if (PDeclResult == Result)
ObjCPDecl = PD;
}
Modified: cfe/trunk/test/SemaObjC/class-unavail-warning.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/class-unavail-warning.m?rev=284265&r1=284264&r2=284265&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/class-unavail-warning.m (original)
+++ cfe/trunk/test/SemaObjC/class-unavail-warning.m Fri Oct 14 14:08:01 2016
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fblocks -triple x86_64-apple-darwin10 -verify %s
// rdar://9092208
__attribute__((unavailable("not available")))
@@ -98,3 +98,19 @@ UNAVAILABLE
@end
@interface UnavailSub(cat)<SomeProto> // no error
@end
+
+int unavail_global UNAVAILABLE;
+
+UNAVAILABLE __attribute__((objc_root_class))
+ at interface TestAttrContext
+-meth;
+ at end
+
+ at implementation TestAttrContext
+-meth {
+ unavail_global = 2; // no warn
+ (void) ^{
+ unavail_global = 4; // no warn
+ };
+}
+ at end
More information about the cfe-commits
mailing list