From: Erik Pilkington Date: Fri, 29 Jul 2016 17:37:38 +0000 (+0000) Subject: Reapply r277058: "[ObjC] Consider availability of context when emitting availability... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=30526a0d0c20a6e41b59b936d5a10103dd5115e7;p=clang Reapply r277058: "[ObjC] Consider availability of context when emitting availability warnings" git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@277175 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index ec8bb3aaa3..f2912a116b 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -17,6 +17,7 @@ #include "clang/AST/AttrIterator.h" #include "clang/AST/DeclarationName.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/VersionTuple.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" @@ -603,7 +604,12 @@ public: /// AR_Available, will be set to a (possibly empty) message /// describing why the declaration has not been introduced, is /// deprecated, or is unavailable. - AvailabilityResult getAvailability(std::string *Message = nullptr) const; + /// + /// \param EnclosingVersion The version to compare with. If empty, assume the + /// deployment target version. + AvailabilityResult + getAvailability(std::string *Message = nullptr, + VersionTuple EnclosingVersion = VersionTuple()) const; /// \brief Determine whether this declaration is marked 'deprecated'. /// diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index a04ab9496f..dd99abe9f6 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -9596,7 +9596,12 @@ public: } 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; + const DeclContext *getCurObjCLexicalContext() const { const DeclContext *DC = getCurLexicalContext(); // A category implicitly has the attribute of the interface. diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 8918e18d43..8342c0f2e3 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -400,11 +400,12 @@ const Attr *Decl::getDefiningAttr() const { /// diagnostics. static AvailabilityResult CheckAvailability(ASTContext &Context, const AvailabilityAttr *A, - std::string *Message) { - VersionTuple TargetMinVersion = - Context.getTargetInfo().getPlatformMinVersion(); + std::string *Message, + VersionTuple EnclosingVersion) { + if (EnclosingVersion.empty()) + EnclosingVersion = Context.getTargetInfo().getPlatformMinVersion(); - if (TargetMinVersion.empty()) + if (EnclosingVersion.empty()) return AR_Available; // Check if this is an App Extension "platform", and if so chop off @@ -449,7 +450,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, // Make sure that this declaration has already been introduced. if (!A->getIntroduced().empty() && - TargetMinVersion < A->getIntroduced()) { + EnclosingVersion < A->getIntroduced()) { if (Message) { Message->clear(); llvm::raw_string_ostream Out(*Message); @@ -463,7 +464,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, } // Make sure that this declaration hasn't been obsoleted. - if (!A->getObsoleted().empty() && TargetMinVersion >= A->getObsoleted()) { + if (!A->getObsoleted().empty() && EnclosingVersion >= A->getObsoleted()) { if (Message) { Message->clear(); llvm::raw_string_ostream Out(*Message); @@ -477,7 +478,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, } // Make sure that this declaration hasn't been deprecated. - if (!A->getDeprecated().empty() && TargetMinVersion >= A->getDeprecated()) { + if (!A->getDeprecated().empty() && EnclosingVersion >= A->getDeprecated()) { if (Message) { Message->clear(); llvm::raw_string_ostream Out(*Message); @@ -493,9 +494,10 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, return AR_Available; } -AvailabilityResult Decl::getAvailability(std::string *Message) const { +AvailabilityResult Decl::getAvailability(std::string *Message, + VersionTuple EnclosingVersion) const { if (auto *FTD = dyn_cast(this)) - return FTD->getTemplatedDecl()->getAvailability(Message); + return FTD->getTemplatedDecl()->getAvailability(Message, EnclosingVersion); AvailabilityResult Result = AR_Available; std::string ResultMessage; @@ -520,7 +522,7 @@ AvailabilityResult Decl::getAvailability(std::string *Message) const { if (const auto *Availability = dyn_cast(A)) { AvailabilityResult AR = CheckAvailability(getASTContext(), Availability, - Message); + Message, EnclosingVersion); if (AR == AR_Unavailable) return AR_Unavailable; @@ -579,8 +581,8 @@ bool Decl::isWeakImported() const { return true; if (const auto *Availability = dyn_cast(A)) { - if (CheckAvailability(getASTContext(), Availability, - nullptr) == AR_NotYetIntroduced) + if (CheckAvailability(getASTContext(), Availability, nullptr, + VersionTuple()) == AR_NotYetIntroduced) return true; } } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 73fd057a2a..287632382d 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -6484,3 +6484,26 @@ void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD, DoEmitAvailabilityWarning(*this, AD, Ctx, D, Message, Loc, UnknownObjCClass, 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(D)) + Interface = MD->getClassInterface(); + else if (const auto *ID = dyn_cast(D)) + Interface = ID->getClassInterface(); + + if (Interface) { + if (const auto *AA = getAttrForPlatform(getASTContext(), Interface)) + if (AA->getIntroduced() > DeclVersion) + DeclVersion = AA->getIntroduced(); + } + + return DeclVersion; +} diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 19a3d035d3..6539790224 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -107,9 +107,14 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess) { - // See if this declaration is unavailable or deprecated. + 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); + 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. @@ -117,7 +122,7 @@ 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); + Result = D->getAvailability(&Message, ContextVersion); continue; } } @@ -128,7 +133,7 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, if (ObjCInterfaceDecl *IDecl = dyn_cast(D)) { if (IDecl->getDefinition()) { D = IDecl->getDefinition(); - Result = D->getAvailability(&Message); + Result = D->getAvailability(&Message, ContextVersion); } } @@ -136,7 +141,7 @@ 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); + Result = TheEnumDecl->getAvailability(&Message, ContextVersion); } const ObjCPropertyDecl *ObjCPDecl = nullptr; @@ -144,7 +149,8 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, Result == AR_NotYetIntroduced) { if (const ObjCMethodDecl *MD = dyn_cast(D)) { if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { - AvailabilityResult PDeclResult = PD->getAvailability(nullptr); + AvailabilityResult PDeclResult = + PD->getAvailability(nullptr, ContextVersion); if (PDeclResult == Result) ObjCPDecl = PD; } @@ -198,7 +204,7 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, break; } - return Result; + return Result; } /// \brief Emit a note explaining that this function is deleted. diff --git a/test/SemaObjC/attr-availability.m b/test/SemaObjC/attr-availability.m index 6cbb3cc22d..1be949086d 100644 --- a/test/SemaObjC/attr-availability.m +++ b/test/SemaObjC/attr-availability.m @@ -294,3 +294,34 @@ __attribute__((objc_root_class)) [obj method]; // expected-error{{'method' is unavailable}} } @end + +#if defined(WARN_PARTIAL) + +int fn_10_7() __attribute__((availability(macosx, introduced=10.7))); // expected-note{{marked partial here}} +int fn_10_8() __attribute__((availability(macosx, introduced=10.8))) { // expected-note{{marked partial here}} + return fn_10_7(); +} + +__attribute__((objc_root_class)) +@interface LookupAvailabilityBase +-(void) method1; +@end + +@implementation LookupAvailabilityBase +-(void)method1 { fn_10_7(); } // expected-warning{{partial}} expected-note{{explicitly redeclare}} +@end + +__attribute__((availability(macosx, introduced=10.7))) +@interface LookupAvailability : LookupAvailabilityBase +- (void)method2; +- (void)method3; +- (void)method4 __attribute__((availability(macosx, introduced=10.8))); +@end + +@implementation LookupAvailability +-(void)method2 { fn_10_7(); } +-(void)method3 { fn_10_8(); } // expected-warning{{partial}} expected-note{{explicitly redeclare}} +-(void)method4 { fn_10_8(); } +@end + +#endif