Hook up -emit-interface-path to a simple AST printer

We'll want more complexity soon, but this is a start.
This commit is contained in:
Jordan Rose
2018-07-20 10:22:37 -07:00
parent 1a1f174786
commit e8e0584785
6 changed files with 110 additions and 31 deletions

View File

@@ -424,6 +424,8 @@ struct PrintOptions {
return result;
}
static PrintOptions printTextualInterfaceFile();
static PrintOptions printModuleInterface();
static PrintOptions printTypeInterface(Type T);

View File

@@ -64,6 +64,21 @@ void PrintOptions::clearSynthesizedExtension() {
TransformContext.reset();
}
PrintOptions PrintOptions::printTextualInterfaceFile() {
PrintOptions result;
result.PrintLongAttrsOnSeparateLines = true;
result.TypeDefinitions = true;
result.PrintIfConfig = false;
result.FullyQualifiedTypes = true;
result.SkipImports = true;
result.AccessFilter = AccessLevel::Public;
// FIXME: We'll need the actual default parameter expression.
result.PrintDefaultParameterPlaceholder = false;
return result;
}
TypeTransformContext::TypeTransformContext(Type T)
: BaseType(T.getPointer()) {
assert(T->mayHaveMembers());

View File

@@ -313,49 +313,89 @@ static bool writeSIL(SILModule &SM, const PrimarySpecificPaths &PSPs,
PSPs.OutputFilename, opts.EmitSortedSIL);
}
static bool printAsObjCIfNeeded(StringRef outputPath, ModuleDecl *M,
StringRef bridgingHeader, bool moduleIsPublic) {
using namespace llvm::sys;
/// Invokes \p action with a raw_ostream that refers to a temporary file, which
/// is then renamed into place as \p outputPath when the action completes.
///
/// If a temporary file cannot be created for whatever reason, \p action will
/// be invoked with a stream directly opened at \p outputPath. Otherwise, if
/// there is already a file at \p outputPath, it will not be overwritten if
/// the new contents are identical.
///
/// If the process is interrupted with a signal, any temporary file will be
/// removed.
///
/// As a special case, an output path of "-" is treated as referring to stdout.
///
/// If an error occurs, it is reported via \p diags.
static bool atomicallyWritingToTextFile(
StringRef outputPath, DiagnosticEngine &diags,
llvm::function_ref<bool(llvm::raw_pwrite_stream &)> action) {
if (outputPath.empty())
return false;
clang::CompilerInstance Clang;
std::string tmpFilePath;
std::error_code EC;
std::unique_ptr<llvm::raw_pwrite_stream> out =
Clang.createOutputFile(outputPath, EC,
/*Binary=*/false,
/*RemoveFileOnSignal=*/true,
/*BaseInput=*/"",
path::extension(outputPath),
/*UseTemporary=*/true,
/*CreateMissingDirectories=*/false,
/*ResultPathName=*/nullptr,
&tmpFilePath);
bool hadError;
{
clang::CompilerInstance Clang;
if (!out) {
M->getASTContext().Diags.diagnose(SourceLoc(), diag::error_opening_output,
tmpFilePath, EC.message());
return true;
std::error_code EC;
std::unique_ptr<llvm::raw_pwrite_stream> out =
Clang.createOutputFile(outputPath, EC,
/*Binary=*/false,
/*RemoveFileOnSignal=*/true,
/*BaseInput=*/"",
llvm::sys::path::extension(outputPath),
/*UseTemporary=*/true,
/*CreateMissingDirectories=*/false,
/*ResultPathName=*/nullptr,
&tmpFilePath);
if (!out) {
diags.diagnose(SourceLoc(), diag::error_opening_output,
tmpFilePath, EC.message());
return true;
}
hadError = action(*out);
}
auto requiredAccess = moduleIsPublic ? AccessLevel::Public
: AccessLevel::Internal;
bool hadError = printAsObjC(*out, M, bridgingHeader, requiredAccess);
out->flush();
EC = swift::moveFileIfDifferent(tmpFilePath, outputPath);
if (EC) {
M->getASTContext().Diags.diagnose(SourceLoc(), diag::error_opening_output,
outputPath, EC.message());
return true;
if (!tmpFilePath.empty()) {
if (auto EC = swift::moveFileIfDifferent(tmpFilePath, outputPath)) {
diags.diagnose(SourceLoc(), diag::error_opening_output,
outputPath, EC.message());
return true;
}
}
return hadError;
}
static bool printAsObjCIfNeeded(StringRef outputPath, ModuleDecl *M,
StringRef bridgingHeader, bool moduleIsPublic) {
return atomicallyWritingToTextFile(outputPath, M->getDiags(),
[&](raw_ostream &out) -> bool {
auto requiredAccess = moduleIsPublic ? AccessLevel::Public
: AccessLevel::Internal;
return printAsObjC(out, M, bridgingHeader, requiredAccess);
});
}
static bool printModuleInterfaceIfNeeded(StringRef outputPath, ModuleDecl *M) {
return atomicallyWritingToTextFile(outputPath, M->getDiags(),
[&](raw_ostream &out) -> bool {
auto 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;
});
}
/// Returns the OutputKind for the given Action.
static IRGenOutputKind getOutputKind(FrontendOptions::ActionType Action) {
switch (Action) {
@@ -1321,6 +1361,10 @@ static bool performCompileStepsPostSILGen(
Instance.getMainModule(),
opts.ImplicitObjCHeaderPath, moduleIsPublic);
(void)printModuleInterfaceIfNeeded(
PSPs.SupplementaryOutputs.ModuleInterfaceOutputPath,
Instance.getMainModule());
if (Action == FrontendOptions::ActionType::EmitSIB)
return serializeSIB(SM.get(), PSPs, Instance.getASTContext(), MSF);

View File

@@ -0,0 +1 @@
public func otherFileFunction() {}

View File

@@ -0,0 +1,9 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -o %t/main~partial.swiftmodule -primary-file %s %S/Inputs/other.swift -module-name main
// RUN: %target-swift-frontend -emit-module -o %t/other~partial.swiftmodule %s -primary-file %S/Inputs/other.swift -module-name main
// RUN: %target-swift-frontend -merge-modules -emit-module -o /dev/null -emit-interface-path - %t/main~partial.swiftmodule -module-name main %t/other~partial.swiftmodule | %FileCheck %s
// CHECK: {{^}}func verySimpleFunction(){{$}}
public func verySimpleFunction() {}
// CHECK: {{^}}func otherFileFunction(){{$}}

View File

@@ -0,0 +1,8 @@
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s | %FileCheck %s
// RUN: %target-swift-frontend -emit-interface-path - -emit-module -o /dev/null %s %S/Inputs/other.swift | %FileCheck -check-prefix CHECK-MULTI-FILE %s
// CHECK: public func verySimpleFunction(){{$}}
// CHECK-MULTI-FILE: public func verySimpleFunction(){{$}}
public func verySimpleFunction() {}
// CHECK-MULTI-FILE: public func otherFileFunction(){{$}}