mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[ClangImporter] Refactor availability attribute importing logic. NFC.
Refactor the PlatformAvailability logic for determining which Clang availability attributes are relevant when importing. The goal is to separate the logic for attribute relevance for a given platform from the logic to determine whether a deprecated attribute should be imported as unavailable in Swift. This also makes it possible for the "deprecated-as-unavailable" logic to refer to the underlying Clang declaration, which is functionality that will be used in a later commit. This commit has no intended functional change. Part of rdar://problem/48348822
This commit is contained in:
@@ -718,19 +718,17 @@ bool importer::isUnavailableInSwift(
|
||||
if (attr->getPlatform()->getName() == "swift")
|
||||
return true;
|
||||
|
||||
if (platformAvailability.filter &&
|
||||
!platformAvailability.filter(attr->getPlatform()->getName())) {
|
||||
if (!platformAvailability.isPlatformRelevant(
|
||||
attr->getPlatform()->getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (platformAvailability.deprecatedAsUnavailableFilter) {
|
||||
llvm::VersionTuple version = attr->getDeprecated();
|
||||
if (version.empty())
|
||||
continue;
|
||||
if (platformAvailability.deprecatedAsUnavailableFilter(
|
||||
version.getMajor(), version.getMinor())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
llvm::VersionTuple version = attr->getDeprecated();
|
||||
if (version.empty())
|
||||
continue;
|
||||
if (platformAvailability.treatDeprecatedAsUnavailable(decl, version)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1684,65 +1684,88 @@ ModuleDecl *ClangImporter::getImportedHeaderModule() const {
|
||||
return Impl.ImportedHeaderUnit->getParentModule();
|
||||
}
|
||||
|
||||
PlatformAvailability::PlatformAvailability(LangOptions &langOpts) {
|
||||
// Add filters to determine if a Clang availability attribute
|
||||
// applies in Swift, and if so, what is the cutoff for deprecated
|
||||
// declarations that are now considered unavailable in Swift.
|
||||
PlatformAvailability::PlatformAvailability(LangOptions &langOpts)
|
||||
: platformKind(targetPlatform(langOpts)) {
|
||||
switch (platformKind) {
|
||||
case PlatformKind::iOS:
|
||||
case PlatformKind::iOSApplicationExtension:
|
||||
case PlatformKind::tvOS:
|
||||
case PlatformKind::tvOSApplicationExtension:
|
||||
deprecatedAsUnavailableMessage =
|
||||
"APIs deprecated as of iOS 7 and earlier are unavailable in Swift";
|
||||
break;
|
||||
|
||||
if (langOpts.Target.isiOS() && !langOpts.Target.isTvOS()) {
|
||||
if (!langOpts.EnableAppExtensionRestrictions) {
|
||||
filter = [](StringRef Platform) { return Platform == "ios"; };
|
||||
} else {
|
||||
filter = [](StringRef Platform) {
|
||||
return Platform == "ios" || Platform == "ios_app_extension";
|
||||
};
|
||||
}
|
||||
// Anything deprecated in iOS 7.x and earlier is unavailable in Swift.
|
||||
deprecatedAsUnavailableFilter = [](
|
||||
unsigned major, llvm::Optional<unsigned> minor) { return major <= 7; };
|
||||
deprecatedAsUnavailableMessage =
|
||||
"APIs deprecated as of iOS 7 and earlier are unavailable in Swift";
|
||||
} else if (langOpts.Target.isTvOS()) {
|
||||
if (!langOpts.EnableAppExtensionRestrictions) {
|
||||
filter = [](StringRef Platform) { return Platform == "tvos"; };
|
||||
} else {
|
||||
filter = [](StringRef Platform) {
|
||||
return Platform == "tvos" || Platform == "tvos_app_extension";
|
||||
};
|
||||
}
|
||||
// Anything deprecated in iOS 7.x and earlier is unavailable in Swift.
|
||||
deprecatedAsUnavailableFilter = [](
|
||||
unsigned major, llvm::Optional<unsigned> minor) { return major <= 7; };
|
||||
deprecatedAsUnavailableMessage =
|
||||
"APIs deprecated as of iOS 7 and earlier are unavailable in Swift";
|
||||
} else if (langOpts.Target.isWatchOS()) {
|
||||
if (!langOpts.EnableAppExtensionRestrictions) {
|
||||
filter = [](StringRef Platform) { return Platform == "watchos"; };
|
||||
} else {
|
||||
filter = [](StringRef Platform) {
|
||||
return Platform == "watchos" || Platform == "watchos_app_extension";
|
||||
};
|
||||
}
|
||||
// No deprecation filter on watchOS
|
||||
deprecatedAsUnavailableFilter = [](
|
||||
unsigned major, llvm::Optional<unsigned> minor) { return false; };
|
||||
case PlatformKind::watchOS:
|
||||
case PlatformKind::watchOSApplicationExtension:
|
||||
deprecatedAsUnavailableMessage = "";
|
||||
} else if (langOpts.Target.isMacOSX()) {
|
||||
if (!langOpts.EnableAppExtensionRestrictions) {
|
||||
filter = [](StringRef Platform) { return Platform == "macos"; };
|
||||
} else {
|
||||
filter = [](StringRef Platform) {
|
||||
return Platform == "macos" || Platform == "macos_app_extension";
|
||||
};
|
||||
}
|
||||
// Anything deprecated in OSX 10.9.x and earlier is unavailable in Swift.
|
||||
deprecatedAsUnavailableFilter = [](unsigned major,
|
||||
llvm::Optional<unsigned> minor) {
|
||||
return major < 10 ||
|
||||
(major == 10 && (!minor.hasValue() || minor.getValue() <= 9));
|
||||
};
|
||||
break;
|
||||
|
||||
case PlatformKind::OSX:
|
||||
case PlatformKind::OSXApplicationExtension:
|
||||
deprecatedAsUnavailableMessage =
|
||||
"APIs deprecated as of OS X 10.9 and earlier are unavailable in Swift";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool PlatformAvailability::isPlatformRelevant(StringRef name) const {
|
||||
switch (platformKind) {
|
||||
case PlatformKind::OSX:
|
||||
return name == "macos";
|
||||
case PlatformKind::OSXApplicationExtension:
|
||||
return name == "macos" || name == "macos_app_extension";
|
||||
|
||||
case PlatformKind::iOS:
|
||||
return name == "ios";
|
||||
case PlatformKind::iOSApplicationExtension:
|
||||
return name == "ios" || name == "ios_app_extension";
|
||||
|
||||
case PlatformKind::tvOS:
|
||||
return name == "tvos";
|
||||
case PlatformKind::tvOSApplicationExtension:
|
||||
return name == "tvos" || name == "tvos_app_extension";
|
||||
|
||||
case PlatformKind::watchOS:
|
||||
return name == "watchos";
|
||||
case PlatformKind::watchOSApplicationExtension:
|
||||
return name == "watchos" || name == "watchos_app_extension";
|
||||
|
||||
case PlatformKind::none:
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm_unreachable("Unexpected platform");
|
||||
}
|
||||
|
||||
bool PlatformAvailability::treatDeprecatedAsUnavailable(
|
||||
const clang::Decl *clangDecl, const llvm::VersionTuple &version) const {
|
||||
assert(!version.empty() && "Must provide version when deprecated");
|
||||
unsigned major = version.getMajor();
|
||||
Optional<unsigned> minor = version.getMinor();
|
||||
|
||||
switch (platformKind) {
|
||||
case PlatformKind::OSX:
|
||||
// Anything deprecated in OSX 10.9.x and earlier is unavailable in Swift.
|
||||
return major < 10 ||
|
||||
(major == 10 && (!minor.hasValue() || minor.getValue() <= 9));
|
||||
|
||||
case PlatformKind::iOS:
|
||||
case PlatformKind::iOSApplicationExtension:
|
||||
case PlatformKind::tvOS:
|
||||
case PlatformKind::tvOSApplicationExtension:
|
||||
// Anything deprecated in iOS 7.x and earlier is unavailable in Swift.
|
||||
return major <= 7;
|
||||
|
||||
case PlatformKind::watchOS:
|
||||
case PlatformKind::watchOSApplicationExtension:
|
||||
// No deprecation filter on watchOS
|
||||
return false;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5913,10 +5913,10 @@ SwiftDeclConverter::findLatestIntroduction(const clang::Decl *D) {
|
||||
|
||||
// Does this availability attribute map to the platform we are
|
||||
// currently targeting?
|
||||
if (!Impl.platformAvailability.filter ||
|
||||
!Impl.platformAvailability.filter(attr->getPlatform()->getName()))
|
||||
if (!Impl.platformAvailability.isPlatformRelevant(
|
||||
attr->getPlatform()->getName())) {
|
||||
continue;
|
||||
|
||||
}
|
||||
// Take advantage of the empty version being 0.0.0.0.
|
||||
result = std::max(result, attr->getIntroduced());
|
||||
}
|
||||
@@ -7321,8 +7321,7 @@ void ClangImporter::Implementation::importAttributes(
|
||||
|
||||
// Does this availability attribute map to the platform we are
|
||||
// currently targeting?
|
||||
if (!platformAvailability.filter ||
|
||||
!platformAvailability.filter(Platform))
|
||||
if (!platformAvailability.isPlatformRelevant(Platform))
|
||||
continue;
|
||||
|
||||
auto platformK =
|
||||
@@ -7354,9 +7353,8 @@ void ClangImporter::Implementation::importAttributes(
|
||||
llvm::VersionTuple deprecated = avail->getDeprecated();
|
||||
|
||||
if (!deprecated.empty()) {
|
||||
if (platformAvailability.deprecatedAsUnavailableFilter &&
|
||||
platformAvailability.deprecatedAsUnavailableFilter(
|
||||
deprecated.getMajor(), deprecated.getMinor())) {
|
||||
if (platformAvailability.treatDeprecatedAsUnavailable(ClangDecl,
|
||||
deprecated)) {
|
||||
AnyUnavailable = true;
|
||||
PlatformAgnostic = PlatformAgnosticAvailabilityKind::Unavailable;
|
||||
if (message.empty())
|
||||
|
||||
@@ -248,14 +248,19 @@ enum class FactoryAsInitKind {
|
||||
|
||||
namespace importer {
|
||||
struct PlatformAvailability {
|
||||
/// A predicate that indicates if the given platform should be
|
||||
/// considered for availability.
|
||||
std::function<bool(StringRef PlatformName)> filter;
|
||||
private:
|
||||
PlatformKind platformKind;
|
||||
|
||||
/// A predicate that indicates if the given platform version should
|
||||
/// should be included in the cutoff of deprecated APIs marked unavailable.
|
||||
std::function<bool(unsigned major, llvm::Optional<unsigned> minor)>
|
||||
deprecatedAsUnavailableFilter;
|
||||
public:
|
||||
/// Returns true when the given platform should be considered for
|
||||
/// availabilityon imported declarations.
|
||||
bool isPlatformRelevant(StringRef platform) const;
|
||||
|
||||
/// Returns true when the given declaration with the given deprecation
|
||||
/// should be inlucded in the cutoff of imported deprecated APIs marked
|
||||
/// unavailable.
|
||||
bool treatDeprecatedAsUnavailable(const clang::Decl *clangDecl,
|
||||
const llvm::VersionTuple &version) const;
|
||||
|
||||
/// The message to embed for implicitly unavailability if a deprecated
|
||||
/// API is now unavailable.
|
||||
|
||||
Reference in New Issue
Block a user