blob: 37e592697315abd66f3c8a0e30ad1bf0da32ea92 [file] [log] [blame]
//===--- TextualInterfaceGeneration.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 "TextualInterfaceGeneration.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 textual 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::textual_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::emitModuleInterface(raw_ostream &out, ModuleDecl *M) {
assert(M);
printImports(out, M);
const PrintOptions printOptions = PrintOptions::printTextualInterfaceFile();
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;
}