Skip to content

Commit

Permalink
[TBDGen] Track unavailable declarations against the active platform f…
Browse files Browse the repository at this point in the history
…or (#73284)

api generation

This resolves the bug where apijson files recorded declarations as
unavailable purely because it was unavailable on a unrelated platforms.

Resolves: rdar://113552185
  • Loading branch information
cyndyishida authored May 1, 2024
1 parent 7757c34 commit 84d3618
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 9 deletions.
23 changes: 14 additions & 9 deletions lib/IRGen/TBDGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -766,22 +766,27 @@ class APIGenRecorder final : public APIRecorder {
llvm::DenseMap<CategoryNameKey, unsigned> CategoryCounts;

apigen::APIAvailability getAvailability(const Decl *decl) {
bool unavailable = false;
std::optional<bool> unavailable;
std::string introduced, obsoleted;
bool hasFallbackUnavailability = false;
auto platform = targetPlatform(module->getASTContext().LangOpts);
for (auto *attr : decl->getAttrs()) {
if (auto *ava = dyn_cast<AvailableAttr>(attr)) {
if (ava->isUnconditionallyUnavailable())
unavailable = true;
if (ava->Platform == platform) {
if (ava->Introduced)
introduced = ava->Introduced->getAsString();
if (ava->Obsoleted)
obsoleted = ava->Obsoleted->getAsString();
if (ava->Platform == PlatformKind::none) {
hasFallbackUnavailability = ava->isUnconditionallyUnavailable();
continue;
}
if (ava->Platform != platform)
continue;
unavailable = ava->isUnconditionallyUnavailable();
if (ava->Introduced)
introduced = ava->Introduced->getAsString();
if (ava->Obsoleted)
obsoleted = ava->Obsoleted->getAsString();
}
}
return {introduced, obsoleted, unavailable};
return {introduced, obsoleted,
unavailable.value_or(hasFallbackUnavailability)};
}

StringRef getSelectorName(SILDeclRef method, SmallString<128> &buffer) {
Expand Down
126 changes: 126 additions & 0 deletions test/APIJSON/availability.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// REQUIRES: objc_interop, OS=macosx
// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/ModuleCache)
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) %s -typecheck -parse-as-library -emit-module-interface-path %t/MyModule.swiftinterface -enable-library-evolution -module-name MyModule -swift-version 5 -emit-api-descriptor-path %t/api.json -target arm64-apple-macos12
// RUN: %validate-json %t/api.json | %FileCheck %s

@available(iOS 13.0, *)
@available(macOS 10.10, *)
@available(tvOS, unavailable)
@available(watchOS 10.0, *)
public class A {}

@available(*, unavailable)
public func callUnavailable() {}

@available(macOS 10.10, *)
@available(*, unavailable)
public func availableOnlyOnActiveOS() {}

@available(tvOS, unavailable)
public func unavailableOnSeperateOS() {}

extension A {
@available(macOS 12, *)
public func getA() -> Void {}

@available(macOS, unavailable)
public func getUnavailableA() -> Void {}
}

// CHECK: {
// CHECK-NEXT: "target": "arm64-apple-macos12",
// CHECK-NEXT: "globals": [
// CHECK-NEXT: {
// CHECK-NEXT: "name": "_$s8MyModule15callUnavailableyyF",
// CHECK-NEXT: "access": "public",
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/availability.swift",
// CHECK-NEXT: "linkage": "exported",
// CHECK-NEXT: "unavailable": true
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "_$s8MyModule1AC15getUnavailableAyyF",
// CHECK-NEXT: "access": "public",
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/availability.swift",
// CHECK-NEXT: "linkage": "exported",
// CHECK-NEXT: "unavailable": true
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "_$s8MyModule1AC4getAyyF",
// CHECK-NEXT: "access": "public",
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/availability.swift",
// CHECK-NEXT: "linkage": "exported",
// CHECK-NEXT: "introduced": "12"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "_$s8MyModule1ACMa",
// CHECK-NEXT: "access": "public",
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/availability.swift",
// CHECK-NEXT: "linkage": "exported",
// CHECK-NEXT: "introduced": "10.10"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "_$s8MyModule1ACMm",
// CHECK-NEXT: "access": "public",
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/availability.swift",
// CHECK-NEXT: "linkage": "exported",
// CHECK-NEXT: "introduced": "10.10"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "_$s8MyModule1ACMn",
// CHECK-NEXT: "access": "public",
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/availability.swift",
// CHECK-NEXT: "linkage": "exported",
// CHECK-NEXT: "introduced": "10.10"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "_$s8MyModule1ACMo",
// CHECK-NEXT: "access": "public",
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/availability.swift",
// CHECK-NEXT: "linkage": "exported",
// CHECK-NEXT: "introduced": "10.10"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "_$s8MyModule1ACMu",
// CHECK-NEXT: "access": "public",
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/availability.swift",
// CHECK-NEXT: "linkage": "exported",
// CHECK-NEXT: "introduced": "10.10"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "_$s8MyModule1ACN",
// CHECK-NEXT: "access": "public",
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/availability.swift",
// CHECK-NEXT: "linkage": "exported",
// CHECK-NEXT: "introduced": "10.10"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "_$s8MyModule1ACfD",
// CHECK-NEXT: "access": "public",
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/availability.swift",
// CHECK-NEXT: "linkage": "exported"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "_$s8MyModule1ACfd",
// CHECK-NEXT: "access": "public",
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/availability.swift",
// CHECK-NEXT: "linkage": "exported"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "_$s8MyModule23availableOnlyOnActiveOSyyF",
// CHECK-NEXT: "access": "public",
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/availability.swift",
// CHECK-NEXT: "linkage": "exported",
// CHECK-NEXT: "introduced": "10.10"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "_$s8MyModule23unavailableOnSeperateOSyyF",
// CHECK-NEXT: "access": "public",
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/availability.swift",
// CHECK-NEXT: "linkage": "exported"
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "interfaces": [],
// CHECK-NEXT: "categories": [],
// CHECK-NEXT: "version": "1.0"
// CHECK-NEXT: }

0 comments on commit 84d3618

Please sign in to comment.