mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
We already have something called "module interfaces" -- it's the generated interface view that you can see in Xcode, the interface that's meant for developers using a library. Of course, that's also a textual format. To reduce confusion, rename the new module stability feature to "parseable [module] interfaces".
99 lines
3.5 KiB
C++
99 lines
3.5 KiB
C++
//===--- ParseableInterfaceGeneration.cpp - swiftinterface files ----------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2018 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ParseableInterfaceGeneration.h"
|
|
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/DiagnosticsFrontend.h"
|
|
#include "swift/AST/Module.h"
|
|
#include "clang/Basic/Module.h"
|
|
|
|
using namespace swift;
|
|
|
|
/// Diagnose any scoped imports in \p imports, i.e. those with a non-empty
|
|
/// access path. These are not yet supported by parseable interfaces, since the
|
|
/// information about the declaration kind is not preserved through the binary
|
|
/// serialization that happens as an intermediate step in non-whole-module
|
|
/// builds.
|
|
///
|
|
/// These come from declarations like `import class FooKit.MainFooController`.
|
|
static void diagnoseScopedImports(DiagnosticEngine &diags,
|
|
ArrayRef<ModuleDecl::ImportedModule> imports){
|
|
for (const ModuleDecl::ImportedModule &importPair : imports) {
|
|
if (importPair.first.empty())
|
|
continue;
|
|
diags.diagnose(importPair.first.front().second,
|
|
diag::parseable_interface_scoped_import_unsupported);
|
|
}
|
|
}
|
|
|
|
/// Prints the imported modules in \p M to \p out in the form of \c import
|
|
/// source declarations.
|
|
static void printImports(raw_ostream &out, ModuleDecl *M) {
|
|
// FIXME: This is very similar to what's in Serializer::writeInputBlock, but
|
|
// it's not obvious what higher-level optimization would be factored out here.
|
|
SmallVector<ModuleDecl::ImportedModule, 8> allImports;
|
|
M->getImportedModules(allImports, ModuleDecl::ImportFilter::All);
|
|
ModuleDecl::removeDuplicateImports(allImports);
|
|
diagnoseScopedImports(M->getASTContext().Diags, allImports);
|
|
|
|
// Collect the public imports as a subset so that we can mark them with
|
|
// '@_exported'.
|
|
SmallVector<ModuleDecl::ImportedModule, 8> publicImports;
|
|
M->getImportedModules(publicImports, ModuleDecl::ImportFilter::Public);
|
|
llvm::SmallSet<ModuleDecl::ImportedModule, 8,
|
|
ModuleDecl::OrderImportedModules> publicImportSet;
|
|
publicImportSet.insert(publicImports.begin(), publicImports.end());
|
|
|
|
for (auto import : allImports) {
|
|
if (import.second->isStdlibModule() ||
|
|
import.second->isOnoneSupportModule() ||
|
|
import.second->isBuiltinModule()) {
|
|
continue;
|
|
}
|
|
|
|
if (publicImportSet.count(import))
|
|
out << "@_exported ";
|
|
out << "import ";
|
|
import.second->getReverseFullModuleName().printForward(out);
|
|
|
|
// Write the access path we should be honoring but aren't.
|
|
// (See diagnoseScopedImports above.)
|
|
if (!import.first.empty()) {
|
|
out << "/*";
|
|
for (const auto &accessPathElem : import.first)
|
|
out << "." << accessPathElem.first;
|
|
out << "*/";
|
|
}
|
|
|
|
out << "\n";
|
|
}
|
|
}
|
|
|
|
bool swift::emitParseableInterface(raw_ostream &out, ModuleDecl *M) {
|
|
assert(M);
|
|
|
|
printImports(out, M);
|
|
|
|
const PrintOptions printOptions = PrintOptions::printParseableInterfaceFile();
|
|
SmallVector<Decl *, 16> topLevelDecls;
|
|
M->getTopLevelDecls(topLevelDecls);
|
|
for (const Decl *D : topLevelDecls) {
|
|
if (!D->shouldPrintInContext(printOptions))
|
|
continue;
|
|
D->print(out, printOptions);
|
|
out << "\n";
|
|
}
|
|
return false;
|
|
}
|