Skip to content

Commit 8d9ef80

Browse files
committed
[frontend] Introduce a new frontend option '-dump-api-path', which outputs a swift interface file for each compiled source file.
This is primarily intended for use with the stdlib.
1 parent 717b017 commit 8d9ef80

File tree

5 files changed

+87
-1
lines changed

5 files changed

+87
-1
lines changed

include/swift/Frontend/FrontendOptions.h

+3
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ class FrontendOptions {
122122
/// should only be used for debugging and experimental features.
123123
std::vector<std::string> LLVMArgs;
124124

125+
/// The path to output swift interface files for the compiled source files.
126+
std::string DumpAPIPath;
127+
125128
enum ActionType {
126129
NoneAction, ///< No specific action
127130
Parse, ///< Parse and type-check only

include/swift/Option/FrontendOptions.td

+3
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,9 @@ def dump_interface_hash : Flag<["-"], "dump-interface-hash">,
280280
HelpText<"Parse input file(s) and dump interface token hash(es)">,
281281
ModeOpt;
282282

283+
def dump_api_path : Separate<["-"], "dump-api-path">,
284+
HelpText<"The path to output swift interface files for the compiled source files">;
285+
283286
def enable_resilience : Flag<["-"], "enable-resilience">,
284287
HelpText<"Treat all types as resilient by default">;
285288

lib/AST/Decl.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,8 @@ bool Decl::isPrivateStdlibDecl(bool whitelistProtocols) const {
394394
if (!FU)
395395
return false;
396396
// Check for Swift module and overlays.
397-
if (FU->getKind() != FileUnitKind::SerializedAST)
397+
if (!DC->getParentModule()->isStdlibModule() &&
398+
FU->getKind() != FileUnitKind::SerializedAST)
398399
return false;
399400

400401
auto hasInternalParameter = [](ArrayRef<const Pattern *> Pats) -> bool {
@@ -436,6 +437,11 @@ bool Decl::isPrivateStdlibDecl(bool whitelistProtocols) const {
436437
return false;
437438
}
438439

440+
if (auto ImportD = dyn_cast<ImportDecl>(D)) {
441+
if (ImportD->getModule()->isSwiftShimsModule())
442+
return true;
443+
}
444+
439445
auto VD = dyn_cast<ValueDecl>(D);
440446
if (!VD || !VD->hasName())
441447
return false;

lib/Frontend/CompilerInvocation.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
111111
}
112112
}
113113

114+
if (const Arg *A = Args.getLastArg(OPT_dump_api_path)) {
115+
Opts.DumpAPIPath = A->getValue();
116+
}
117+
114118
Opts.EmitVerboseSIL |= Args.hasArg(OPT_emit_verbose_sil);
115119
Opts.EmitSortedSIL |= Args.hasArg(OPT_emit_sorted_sil);
116120

@@ -650,6 +654,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
650654
DiagnosticEngine &Diags, bool isImmediate) {
651655
using namespace options;
652656

657+
Opts.AttachCommentsToDecls |= Args.hasArg(OPT_dump_api_path);
658+
653659
Opts.UseMalloc |= Args.hasArg(OPT_use_malloc);
654660

655661
Opts.EnableExperimentalPatterns |=

tools/driver/frontend_main.cpp

+68
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#include "llvm/Support/YAMLParser.h"
5656

5757
#include <memory>
58+
#include <unordered_set>
5859

5960
using namespace swift;
6061

@@ -921,6 +922,68 @@ static bool performCompile(CompilerInstance &Instance,
921922
return false;
922923
}
923924

925+
/// Returns true if an error occurred.
926+
static bool dumpAPI(Module *Mod, StringRef OutDir) {
927+
using namespace llvm::sys;
928+
929+
auto getOutPath = [&](SourceFile *SF) -> std::string {
930+
SmallString<256> Path = OutDir;
931+
StringRef Filename = SF->getFilename();
932+
path::append(Path, path::filename(Filename));
933+
return Path.str();
934+
};
935+
936+
std::unordered_set<std::string> Filenames;
937+
938+
auto dumpFile = [&](SourceFile *SF) -> bool {
939+
SmallString<512> TempBuf;
940+
llvm::raw_svector_ostream TempOS(TempBuf);
941+
942+
PrintOptions PO = PrintOptions::printInterface();
943+
PO.PrintOriginalSourceText = true;
944+
PO.Indent = 2;
945+
PO.PrintAccessibility = false;
946+
PO.SkipUnderscoredStdlibProtocols = true;
947+
SF->print(TempOS, PO);
948+
if (TempOS.str().trim().empty())
949+
return false; // nothing to show.
950+
951+
std::string OutPath = getOutPath(SF);
952+
bool WasInserted = Filenames.insert(OutPath).second;
953+
if (!WasInserted) {
954+
llvm::errs() << "multiple source files ended up with the same dump API "
955+
"filename to write to: " << OutPath << '\n';
956+
return true;
957+
}
958+
959+
std::error_code EC;
960+
llvm::raw_fd_ostream OS(OutPath, EC, fs::OpenFlags::F_RW);
961+
if (EC) {
962+
llvm::errs() << "error opening file '" << OutPath << "': "
963+
<< EC.message() << '\n';
964+
return true;
965+
}
966+
967+
OS << TempOS.str();
968+
return false;
969+
};
970+
971+
std::error_code EC = fs::create_directories(OutDir);
972+
if (EC) {
973+
llvm::errs() << "error creating directory '" << OutDir << "': "
974+
<< EC.message() << '\n';
975+
return true;
976+
}
977+
978+
for (auto *FU : Mod->getFiles()) {
979+
if (SourceFile *SF = dyn_cast<SourceFile>(FU))
980+
if (dumpFile(SF))
981+
return true;
982+
}
983+
984+
return false;
985+
}
986+
924987
int frontend_main(ArrayRef<const char *>Args,
925988
const char *Argv0, void *MainAddr) {
926989
llvm::InitializeAllTargets();
@@ -1045,6 +1108,11 @@ int frontend_main(ArrayRef<const char *>Args,
10451108
bool HadError = performCompile(Instance, Invocation, Args, ReturnValue) ||
10461109
Instance.getASTContext().hadError();
10471110

1111+
if (!HadError && !Invocation.getFrontendOptions().DumpAPIPath.empty()) {
1112+
HadError = dumpAPI(Instance.getMainModule(),
1113+
Invocation.getFrontendOptions().DumpAPIPath);
1114+
}
1115+
10481116
if (Invocation.getDiagnosticOptions().VerifyDiagnostics) {
10491117
HadError = verifyDiagnostics(Instance.getSourceMgr(),
10501118
Instance.getInputBufferIDs());

0 commit comments

Comments
 (0)