forked from OSchip/llvm-project
Reapply r277058: "[ObjC] Consider availability of context when emitting availability warnings"
llvm-svn: 277175
This commit is contained in:
parent
99e39a7af8
commit
48c7cc9bc0
|
@ -17,6 +17,7 @@
|
||||||
#include "clang/AST/AttrIterator.h"
|
#include "clang/AST/AttrIterator.h"
|
||||||
#include "clang/AST/DeclarationName.h"
|
#include "clang/AST/DeclarationName.h"
|
||||||
#include "clang/Basic/Specifiers.h"
|
#include "clang/Basic/Specifiers.h"
|
||||||
|
#include "clang/Basic/VersionTuple.h"
|
||||||
#include "llvm/ADT/PointerUnion.h"
|
#include "llvm/ADT/PointerUnion.h"
|
||||||
#include "llvm/ADT/iterator.h"
|
#include "llvm/ADT/iterator.h"
|
||||||
#include "llvm/ADT/iterator_range.h"
|
#include "llvm/ADT/iterator_range.h"
|
||||||
|
@ -603,7 +604,12 @@ public:
|
||||||
/// AR_Available, will be set to a (possibly empty) message
|
/// AR_Available, will be set to a (possibly empty) message
|
||||||
/// describing why the declaration has not been introduced, is
|
/// describing why the declaration has not been introduced, is
|
||||||
/// deprecated, or is unavailable.
|
/// 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'.
|
/// \brief Determine whether this declaration is marked 'deprecated'.
|
||||||
///
|
///
|
||||||
|
|
|
@ -9597,6 +9597,11 @@ public:
|
||||||
|
|
||||||
AvailabilityResult getCurContextAvailability() const;
|
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 *getCurObjCLexicalContext() const {
|
||||||
const DeclContext *DC = getCurLexicalContext();
|
const DeclContext *DC = getCurLexicalContext();
|
||||||
// A category implicitly has the attribute of the interface.
|
// A category implicitly has the attribute of the interface.
|
||||||
|
|
|
@ -400,11 +400,12 @@ const Attr *Decl::getDefiningAttr() const {
|
||||||
/// diagnostics.
|
/// diagnostics.
|
||||||
static AvailabilityResult CheckAvailability(ASTContext &Context,
|
static AvailabilityResult CheckAvailability(ASTContext &Context,
|
||||||
const AvailabilityAttr *A,
|
const AvailabilityAttr *A,
|
||||||
std::string *Message) {
|
std::string *Message,
|
||||||
VersionTuple TargetMinVersion =
|
VersionTuple EnclosingVersion) {
|
||||||
Context.getTargetInfo().getPlatformMinVersion();
|
if (EnclosingVersion.empty())
|
||||||
|
EnclosingVersion = Context.getTargetInfo().getPlatformMinVersion();
|
||||||
|
|
||||||
if (TargetMinVersion.empty())
|
if (EnclosingVersion.empty())
|
||||||
return AR_Available;
|
return AR_Available;
|
||||||
|
|
||||||
// Check if this is an App Extension "platform", and if so chop off
|
// 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.
|
// Make sure that this declaration has already been introduced.
|
||||||
if (!A->getIntroduced().empty() &&
|
if (!A->getIntroduced().empty() &&
|
||||||
TargetMinVersion < A->getIntroduced()) {
|
EnclosingVersion < A->getIntroduced()) {
|
||||||
if (Message) {
|
if (Message) {
|
||||||
Message->clear();
|
Message->clear();
|
||||||
llvm::raw_string_ostream Out(*Message);
|
llvm::raw_string_ostream Out(*Message);
|
||||||
|
@ -463,7 +464,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that this declaration hasn't been obsoleted.
|
// 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) {
|
if (Message) {
|
||||||
Message->clear();
|
Message->clear();
|
||||||
llvm::raw_string_ostream Out(*Message);
|
llvm::raw_string_ostream Out(*Message);
|
||||||
|
@ -477,7 +478,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that this declaration hasn't been deprecated.
|
// 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) {
|
if (Message) {
|
||||||
Message->clear();
|
Message->clear();
|
||||||
llvm::raw_string_ostream Out(*Message);
|
llvm::raw_string_ostream Out(*Message);
|
||||||
|
@ -493,9 +494,10 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
|
||||||
return AR_Available;
|
return AR_Available;
|
||||||
}
|
}
|
||||||
|
|
||||||
AvailabilityResult Decl::getAvailability(std::string *Message) const {
|
AvailabilityResult Decl::getAvailability(std::string *Message,
|
||||||
|
VersionTuple EnclosingVersion) const {
|
||||||
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(this))
|
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(this))
|
||||||
return FTD->getTemplatedDecl()->getAvailability(Message);
|
return FTD->getTemplatedDecl()->getAvailability(Message, EnclosingVersion);
|
||||||
|
|
||||||
AvailabilityResult Result = AR_Available;
|
AvailabilityResult Result = AR_Available;
|
||||||
std::string ResultMessage;
|
std::string ResultMessage;
|
||||||
|
@ -520,7 +522,7 @@ AvailabilityResult Decl::getAvailability(std::string *Message) const {
|
||||||
|
|
||||||
if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) {
|
if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) {
|
||||||
AvailabilityResult AR = CheckAvailability(getASTContext(), Availability,
|
AvailabilityResult AR = CheckAvailability(getASTContext(), Availability,
|
||||||
Message);
|
Message, EnclosingVersion);
|
||||||
|
|
||||||
if (AR == AR_Unavailable)
|
if (AR == AR_Unavailable)
|
||||||
return AR_Unavailable;
|
return AR_Unavailable;
|
||||||
|
@ -579,8 +581,8 @@ bool Decl::isWeakImported() const {
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) {
|
if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) {
|
||||||
if (CheckAvailability(getASTContext(), Availability,
|
if (CheckAvailability(getASTContext(), Availability, nullptr,
|
||||||
nullptr) == AR_NotYetIntroduced)
|
VersionTuple()) == AR_NotYetIntroduced)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6484,3 +6484,26 @@ void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD,
|
||||||
DoEmitAvailabilityWarning(*this, AD, Ctx, D, Message, Loc, UnknownObjCClass,
|
DoEmitAvailabilityWarning(*this, AD, Ctx, D, Message, Loc, UnknownObjCClass,
|
||||||
ObjCProperty, ObjCPropertyAccess);
|
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 DeclVersion;
|
||||||
|
}
|
||||||
|
|
|
@ -107,9 +107,14 @@ static AvailabilityResult
|
||||||
DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
|
DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
|
||||||
const ObjCInterfaceDecl *UnknownObjCClass,
|
const ObjCInterfaceDecl *UnknownObjCClass,
|
||||||
bool ObjCPropertyAccess) {
|
bool ObjCPropertyAccess) {
|
||||||
// See if this declaration is unavailable or deprecated.
|
VersionTuple ContextVersion;
|
||||||
|
if (const DeclContext *DC = S.getCurObjCLexicalContext())
|
||||||
|
ContextVersion = S.getVersionForDecl(cast<Decl>(DC));
|
||||||
|
|
||||||
|
// See if this declaration is unavailable, deprecated, or partial in the
|
||||||
|
// current context.
|
||||||
std::string Message;
|
std::string Message;
|
||||||
AvailabilityResult Result = D->getAvailability(&Message);
|
AvailabilityResult Result = D->getAvailability(&Message, ContextVersion);
|
||||||
|
|
||||||
// For typedefs, if the typedef declaration appears available look
|
// For typedefs, if the typedef declaration appears available look
|
||||||
// to the underlying type to see if it is more restrictive.
|
// 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 (Result == AR_Available) {
|
||||||
if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
|
if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
|
||||||
D = TT->getDecl();
|
D = TT->getDecl();
|
||||||
Result = D->getAvailability(&Message);
|
Result = D->getAvailability(&Message, ContextVersion);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +133,7 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
|
||||||
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
|
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
|
||||||
if (IDecl->getDefinition()) {
|
if (IDecl->getDefinition()) {
|
||||||
D = 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) {
|
if (Result == AR_Available) {
|
||||||
const DeclContext *DC = ECD->getDeclContext();
|
const DeclContext *DC = ECD->getDeclContext();
|
||||||
if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
|
if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
|
||||||
Result = TheEnumDecl->getAvailability(&Message);
|
Result = TheEnumDecl->getAvailability(&Message, ContextVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ObjCPropertyDecl *ObjCPDecl = nullptr;
|
const ObjCPropertyDecl *ObjCPDecl = nullptr;
|
||||||
|
@ -144,7 +149,8 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
|
||||||
Result == AR_NotYetIntroduced) {
|
Result == AR_NotYetIntroduced) {
|
||||||
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
||||||
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
|
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
|
||||||
AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
|
AvailabilityResult PDeclResult =
|
||||||
|
PD->getAvailability(nullptr, ContextVersion);
|
||||||
if (PDeclResult == Result)
|
if (PDeclResult == Result)
|
||||||
ObjCPDecl = PD;
|
ObjCPDecl = PD;
|
||||||
}
|
}
|
||||||
|
|
|
@ -294,3 +294,34 @@ __attribute__((objc_root_class))
|
||||||
[obj method]; // expected-error{{'method' is unavailable}}
|
[obj method]; // expected-error{{'method' is unavailable}}
|
||||||
}
|
}
|
||||||
@end
|
@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
|
||||||
|
|
Loading…
Reference in New Issue