Files
swift-mirror/lib/IRGen/APIGen.cpp
Zixu Wang 18a9d7002f [APIGen] Handle SPI availability for nested decls (#85048)
- Add SPI availability information to `APIAvailability` from attribute
`@_spi_available`.
- Correctly obtain effective availability for nested declarations
without immediate availability attributes.

Resolves rdar://159702280

<!--
If this pull request is targeting a release branch, please fill out the
following form:

https://github.com/swiftlang/.github/blob/main/PULL_REQUEST_TEMPLATE/release.md?plain=1

Otherwise, replace this comment with a description of your changes and
rationale. Provide links to external references/discussions if
appropriate.
If this pull request resolves any GitHub issues, link them like so:

  Resolves <link to issue>, resolves <link to another issue>.

For more information about linking a pull request to an issue, see:

https://docs.github.com/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue
-->

<!--
Before merging this pull request, you must run the Swift continuous
integration tests.
For information about triggering CI builds via @swift-ci, see:

https://github.com/apple/swift/blob/main/docs/ContinuousIntegration.md#swift-ci

Thank you for your contribution to Swift!
-->
2025-11-04 11:34:05 -08:00

216 lines
6.8 KiB
C++

//===--- APIGen.cpp - Swift API Generation --------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements the entrypoints into API file generation.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/raw_ostream.h"
#include "APIGen.h"
namespace swift {
namespace apigen {
void API::addSymbol(StringRef symbol, APILoc loc, APILinkage linkage,
APIFlags flags, APIAccess access,
APIAvailability availability) {
auto *global = new (allocator) GlobalRecord(
symbol, loc, linkage, flags, access, GVKind::Function, availability);
globals.push_back(global);
}
ObjCInterfaceRecord *API::addObjCClass(StringRef name, APILinkage linkage,
APILoc loc, APIAccess access,
APIAvailability availability,
StringRef superClassName) {
auto *interface = new (allocator) ObjCInterfaceRecord(
name, linkage, loc, access, availability, superClassName);
interfaces.push_back(interface);
return interface;
}
ObjCCategoryRecord *API::addObjCCategory(StringRef name, APILinkage linkage,
APILoc loc, APIAccess access,
APIAvailability availability,
StringRef interface) {
auto *category = new (allocator)
ObjCCategoryRecord(name, linkage, loc, access, availability, interface);
categories.push_back(category);
return category;
}
void API::addObjCMethod(ObjCContainerRecord *record, StringRef name, APILoc loc,
APIAccess access, bool isInstanceMethod,
bool isOptional, APIAvailability availability) {
auto method = new (allocator) ObjCMethodRecord(
name, loc, access, isInstanceMethod, isOptional, availability);
record->methods.push_back(method);
}
static void serialize(llvm::json::OStream &OS, APIAccess access) {
switch (access) {
case APIAccess::Public:
OS.attribute("access", "public");
break;
case APIAccess::Private:
OS.attribute("access", "private");
break;
case APIAccess::Project:
OS.attribute("access", "project");
break;
case APIAccess::Unknown:
break;
}
}
static void serialize(llvm::json::OStream &OS, APIAvailability availability) {
if (availability.empty())
return;
if (!availability.introduced.empty())
OS.attribute("introduced", availability.introduced);
if (!availability.obsoleted.empty())
OS.attribute("obsoleted", availability.obsoleted);
if (availability.unavailable)
OS.attribute("unavailable", availability.unavailable);
if (availability.spiAvailable)
OS.attribute("SPIAvailable", availability.spiAvailable);
}
static void serialize(llvm::json::OStream &OS, APILinkage linkage) {
switch (linkage) {
case APILinkage::Exported:
OS.attribute("linkage", "exported");
break;
case APILinkage::Reexported:
OS.attribute("linkage", "re-exported");
break;
case APILinkage::Internal:
OS.attribute("linkage", "internal");
break;
case APILinkage::External:
OS.attribute("linkage", "external");
break;
case APILinkage::Unknown:
// do nothing;
break;
}
}
static void serialize(llvm::json::OStream &OS, APILoc loc) {
OS.attribute("file", loc.getFilename());
}
static void serialize(llvm::json::OStream &OS, const GlobalRecord &record) {
OS.object([&]() {
OS.attribute("name", record.name);
serialize(OS, record.access);
serialize(OS, record.loc);
serialize(OS, record.linkage);
serialize(OS, record.availability);
});
}
static void serialize(llvm::json::OStream &OS, const ObjCMethodRecord &record) {
OS.object([&]() {
OS.attribute("name", record.name);
serialize(OS, record.access);
serialize(OS, record.loc);
serialize(OS, record.linkage);
serialize(OS, record.availability);
if (record.isOptional)
OS.attribute("optional", record.isOptional);
});
}
static bool sortAPIRecords(const APIRecord *base, const APIRecord *compare) {
return base->name < compare->name;
}
static void serialize(llvm::json::OStream &OS,
const ObjCInterfaceRecord &record) {
OS.object([&]() {
OS.attribute("name", record.name);
serialize(OS, record.access);
serialize(OS, record.loc);
serialize(OS, record.linkage);
serialize(OS, record.availability);
OS.attribute("super", record.superClassName);
OS.attributeArray("instanceMethods", [&]() {
for (auto &method : record.methods) {
if (method->isInstanceMethod)
serialize(OS, *method);
}
});
OS.attributeArray("classMethods", [&]() {
for (auto &method : record.methods) {
if (!method->isInstanceMethod)
serialize(OS, *method);
}
});
});
}
static void serialize(llvm::json::OStream &OS,
const ObjCCategoryRecord &record) {
OS.object([&]() {
OS.attribute("name", record.name);
serialize(OS, record.access);
serialize(OS, record.loc);
serialize(OS, record.linkage);
serialize(OS, record.availability);
OS.attribute("interface", record.interface);
OS.attributeArray("instanceMethods", [&]() {
for (auto &method : record.methods) {
if (method->isInstanceMethod)
serialize(OS, *method);
}
});
OS.attributeArray("classMethods", [&]() {
for (auto &method : record.methods) {
if (!method->isInstanceMethod)
serialize(OS, *method);
}
});
});
}
void API::writeAPIJSONFile(llvm::raw_ostream &os, bool PrettyPrint) {
unsigned indentSize = PrettyPrint ? 2 : 0;
llvm::json::OStream JSON(os, indentSize);
JSON.object([&]() {
JSON.attribute("target", target.str());
JSON.attributeArray("globals", [&]() {
llvm::sort(globals, sortAPIRecords);
for (const auto *g : globals)
serialize(JSON, *g);
});
JSON.attributeArray("interfaces", [&]() {
llvm::sort(interfaces, sortAPIRecords);
for (const auto *i : interfaces)
serialize(JSON, *i);
});
JSON.attributeArray("categories", [&]() {
llvm::sort(categories, sortAPIRecords);
for (const auto *c : categories)
serialize(JSON, *c);
});
JSON.attribute("version", "1.0");
});
}
} // end namespace apigen
} // end namespace swift