Skip to content

[ClangImporter] Refactor availability attribute importing logic. NFC. #22872

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions lib/ClangImporter/ClangAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down
133 changes: 78 additions & 55 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.

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; };
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";
} 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; };
break;

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";
"APIs deprecated as of macOS 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;
}
}

Expand Down
14 changes: 6 additions & 8 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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())
Expand Down
21 changes: 13 additions & 8 deletions lib/ClangImporter/ImporterImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// 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;
private:
PlatformKind platformKind;

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.
Expand Down
2 changes: 1 addition & 1 deletion test/ClangImporter/availability_macosx.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Foundation
import AvailabilityExtras

func test_unavailable_because_deprecated() {
_ = NSRealMemoryAvailable() // expected-error {{APIs deprecated as of OS X 10.9 and earlier are unavailable in Swift}}
_ = NSRealMemoryAvailable() // expected-error {{APIs deprecated as of macOS 10.9 and earlier are unavailable in Swift}}
}

func test_swift_unavailable_wins() {
Expand Down
2 changes: 1 addition & 1 deletion test/SourceKit/DocSupport/doc_clang_module.swift.response
Original file line number Diff line number Diff line change
Expand Up @@ -7014,7 +7014,7 @@ var FooSubUnnamedEnumeratorA1: Int { get }
key.kind: source.lang.swift.attribute.availability,
key.platform: source.availability.platform.osx,
key.is_unavailable: 1,
key.message: "APIs deprecated as of OS X 10.9 and earlier are unavailable in Swift",
key.message: "APIs deprecated as of macOS 10.9 and earlier are unavailable in Swift",
key.deprecated: "10.1"
}
],
Expand Down