Files
swift-mirror/lib/Frontend/ParseableInterfaceSupport.cpp

127 lines
4.7 KiB
C++

//===--- ParseableInterfaceSupport.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 "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/AST/Module.h"
#include "swift/Frontend/ParseableInterfaceSupport.h"
#include "clang/Basic/Module.h"
#include "llvm/Support/Regex.h"
using namespace swift;
#define SWIFT_TOOLS_VERSION_KEY "swift-tools-version"
#define SWIFT_MODULE_FLAGS_KEY "swift-module-flags"
/// 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::parseable_interface_scoped_import_unsupported);
}
}
/// Prints to \p out a comment containing a tool-versions identifier as well
/// as any relevant command-line flags in \p Opts used to construct \p M.
static void printToolVersionAndFlagsComment(raw_ostream &out,
TextualInterfaceOptions const &Opts,
ModuleDecl *M) {
auto &Ctx = M->getASTContext();
out << "// " SWIFT_TOOLS_VERSION_KEY ": "
<< Ctx.LangOpts.EffectiveLanguageVersion << "\n";
out << "// " SWIFT_MODULE_FLAGS_KEY ": "
<< Opts.TextualInterfaceFlags << "\n";
}
llvm::Regex swift::getSwiftInterfaceToolsVersionRegex() {
return llvm::Regex("^// " SWIFT_TOOLS_VERSION_KEY ": ([0-9\\.]+)$",
llvm::Regex::Newline);
}
llvm::Regex swift::getSwiftInterfaceModuleFlagsRegex() {
return llvm::Regex("^// " SWIFT_MODULE_FLAGS_KEY ": (.*)$",
llvm::Regex::Newline);
}
/// 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,
TextualInterfaceOptions const &Opts,
ModuleDecl *M) {
assert(M);
printToolVersionAndFlagsComment(out, Opts, 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;
}