Skip to content

[5.7-04182022][Parseable Output] Compute file extensions using full extension strings & emit output in WMO #58871

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 90 additions & 37 deletions lib/FrontendTool/FrontendTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,9 +588,32 @@ mapFrontendInvocationToAction(const CompilerInvocation &Invocation) {
// StaticLinkJob, DynamicLinkJob
}

// TODO: Apply elsewhere in the compiler
static swift::file_types::ID computeFileTypeForPath(const StringRef Path) {
if (!llvm::sys::path::has_extension(Path))
return swift::file_types::ID::TY_INVALID;

auto Extension = llvm::sys::path::extension(Path).str();
auto FileType = file_types::lookupTypeForExtension(Extension);
if (FileType == swift::file_types::ID::TY_INVALID) {
auto PathStem = llvm::sys::path::stem(Path);
// If this path has a multiple '.' extension (e.g. .abi.json),
// then iterate over all preceeding possible extension variants.
while (llvm::sys::path::has_extension(PathStem)) {
auto NextExtension = llvm::sys::path::extension(PathStem);
Extension = NextExtension.str() + Extension;
FileType = file_types::lookupTypeForExtension(Extension);
if (FileType != swift::file_types::ID::TY_INVALID)
break;
}
}

return FileType;
}

static DetailedTaskDescription
constructDetailedTaskDescription(const CompilerInvocation &Invocation,
const InputFile &PrimaryInput,
ArrayRef<InputFile> PrimaryInputs,
ArrayRef<const char *> Args) {
// Command line and arguments
std::string Executable = Invocation.getFrontendOptions().MainExecutablePath;
Expand All @@ -604,24 +627,25 @@ constructDetailedTaskDescription(const CompilerInvocation &Invocation,
CommandLine += std::string(" ") + A;
}

// Primary Input only
Inputs.push_back(CommandInput(PrimaryInput.getFileName()));
// Primary Inputs
for (const auto &input : PrimaryInputs) {
Inputs.push_back(CommandInput(input.getFileName()));
}

// Output for this Primary
auto OutputFile = PrimaryInput.outputFilename();
Outputs.push_back(OutputPair(file_types::lookupTypeForExtension(
llvm::sys::path::extension(OutputFile)),
OutputFile));
for (const auto &input : PrimaryInputs) {
// Main outputs
auto OutputFile = input.outputFilename();
if (!OutputFile.empty())
Outputs.push_back(OutputPair(computeFileTypeForPath(OutputFile), OutputFile));

// Supplementary outputs
const auto &primarySpecificFiles = PrimaryInput.getPrimarySpecificPaths();
const auto &supplementaryOutputPaths =
primarySpecificFiles.SupplementaryOutputs;
supplementaryOutputPaths.forEachSetOutput([&](const std::string &output) {
Outputs.push_back(OutputPair(
file_types::lookupTypeForExtension(llvm::sys::path::extension(output)),
output));
});
// Supplementary outputs
const auto &primarySpecificFiles = input.getPrimarySpecificPaths();
const auto &supplementaryOutputPaths =
primarySpecificFiles.SupplementaryOutputs;
supplementaryOutputPaths.forEachSetOutput([&](const std::string &output) {
Outputs.push_back(OutputPair(computeFileTypeForPath(output), output));
});
}
return DetailedTaskDescription{Executable, Arguments, CommandLine, Inputs,
Outputs};
}
Expand Down Expand Up @@ -2125,15 +2149,26 @@ int swift::performFrontend(ArrayRef<const char *> Args,
// making sure it cannot collide with a real PID (always positive). Non-batch
// compilation gets a real OS PID.
int64_t Pid = IO.hasUniquePrimaryInput() ? OSPid : QUASI_PID_START;
IO.forEachPrimaryInputWithIndex([&](const InputFile &Input,
unsigned idx) -> bool {
emitBeganMessage(
llvm::errs(),
mapFrontendInvocationToAction(Invocation),
constructDetailedTaskDescription(Invocation, Input, Args), Pid - idx,
ProcInfo);
return false;
});

if (IO.hasPrimaryInputs()) {
IO.forEachPrimaryInputWithIndex([&](const InputFile &Input,
unsigned idx) -> bool {
ArrayRef<InputFile> Inputs(Input);
emitBeganMessage(llvm::errs(),
mapFrontendInvocationToAction(Invocation),
constructDetailedTaskDescription(Invocation,
Inputs,
Args), Pid - idx,
ProcInfo);
return false;
});
} else {
// If no primary inputs are present, we are in WMO.
emitBeganMessage(llvm::errs(),
mapFrontendInvocationToAction(Invocation),
constructDetailedTaskDescription(Invocation, IO.getAllInputs(), Args),
OSPid, ProcInfo);
}
}

int ReturnValue = 0;
Expand Down Expand Up @@ -2164,23 +2199,41 @@ int swift::performFrontend(ArrayRef<const char *> Args,
// making sure it cannot collide with a real PID (always positive). Non-batch
// compilation gets a real OS PID.
int64_t Pid = IO.hasUniquePrimaryInput() ? OSPid : QUASI_PID_START;
IO.forEachPrimaryInputWithIndex([&](const InputFile &Input,
unsigned idx) -> bool {
assert(FileSpecificDiagnostics.count(Input.getFileName()) != 0 &&
"Expected diagnostic collection for input.");

// Join all diagnostics produced for this file into a single output.
auto PrimaryDiags = FileSpecificDiagnostics.lookup(Input.getFileName());
if (IO.hasPrimaryInputs()) {
IO.forEachPrimaryInputWithIndex([&](const InputFile &Input,
unsigned idx) -> bool {
assert(FileSpecificDiagnostics.count(Input.getFileName()) != 0 &&
"Expected diagnostic collection for input.");

// Join all diagnostics produced for this file into a single output.
auto PrimaryDiags = FileSpecificDiagnostics.lookup(Input.getFileName());
const char *const Delim = "";
std::ostringstream JoinedDiags;
std::copy(PrimaryDiags.begin(), PrimaryDiags.end(),
std::ostream_iterator<std::string>(JoinedDiags, Delim));

emitFinishedMessage(llvm::errs(),
mapFrontendInvocationToAction(Invocation),
JoinedDiags.str(), r, Pid - idx, ProcInfo);
return false;
});
} else {
// If no primary inputs are present, we are in WMO.
std::vector<std::string> AllDiagnostics;
for (const auto &FileDiagnostics : FileSpecificDiagnostics) {
AllDiagnostics.insert(AllDiagnostics.end(),
FileDiagnostics.getValue().begin(),
FileDiagnostics.getValue().end());
}
const char *const Delim = "";
std::ostringstream JoinedDiags;
std::copy(PrimaryDiags.begin(), PrimaryDiags.end(),
std::copy(AllDiagnostics.begin(), AllDiagnostics.end(),
std::ostream_iterator<std::string>(JoinedDiags, Delim));

emitFinishedMessage(llvm::errs(),
mapFrontendInvocationToAction(Invocation),
JoinedDiags.str(), r, Pid - idx, ProcInfo);
return false;
});
JoinedDiags.str(), r, OSPid, ProcInfo);
}
}

return r;
Expand Down
28 changes: 22 additions & 6 deletions test/Frontend/parseable_output.swift
Original file line number Diff line number Diff line change
@@ -1,32 +1,48 @@
// RUN: %target-swift-frontend -primary-file %s -o %t.out -emit-module -emit-module-path %t.swiftmodule -frontend-parseable-output 2>&1 | %FileCheck %s
// RUN: %target-swift-frontend -primary-file %s %S/Inputs/filelist-other.swift -o %t.out -module-name parseable_output -empty-abi-descriptor -emit-abi-descriptor-path %t.abi.json -emit-module -emit-module-path %t.swiftmodule -serialize-diagnostics -serialize-diagnostics-path %t.dia -frontend-parseable-output 2>&1 | %FileCheck %s
// Check without primary files (WMO):
// RUN: %target-swift-frontend %s %S/Inputs/filelist-other.swift -o %t.out -module-name parseable_output -empty-abi-descriptor -emit-abi-descriptor-path %t.abi.json -emit-module -emit-module-path %t.swiftmodule -serialize-diagnostics -serialize-diagnostics-path %t.dia -frontend-parseable-output 2>&1 | %FileCheck %s

// CHECK: {{[1-9][0-9]*}}
// CHECK-NEXT: {
// CHECK-NEXT: "kind": "began",
// CHECK-NEXT: "name": "compile",
// CHECK-NEXT: "command": "{{.*[\\/]}}swift-frontend{{(\.exe)?}}{{.*}}-primary-file {{.*[\\/]}}parseable_output.swift -o {{.*[\\/]}}parseable_output.swift.tmp.out -emit-module -emit-module-path {{.*[\\/]}}parseable_output.swift.tmp.swiftmodule -frontend-parseable-output",
// CHECK-NEXT: "command": "{{.*[\\/]}}swift-frontend{{(\.exe)?}}{{.*}} {{.*[\\/]}}parseable_output.swift {{.*[\\/]}}filelist-other.swift -o {{.*[\\/]}}parseable_output.swift.tmp.out -module-name parseable_output -empty-abi-descriptor -emit-abi-descriptor-path {{.*[\\/]}}parseable_output.swift.tmp.abi.json -emit-module -emit-module-path {{.*[\\/]}}parseable_output.swift.tmp.swiftmodule -serialize-diagnostics -serialize-diagnostics-path {{.*[\\/]}}parseable_output.swift.tmp.dia -frontend-parseable-output",
// CHECK-NEXT: "command_executable": "{{.*[\\/]}}swift{{(-frontend|c)?(\.exe)?}}",
// CHECK-NEXT: "command_arguments": [
// CHECK: "-primary-file",
// CHECK-NEXT: "{{.*[\\/]}}parseable_output.swift",
// CHECK: "{{.*[\\/]}}parseable_output.swift",
// CHECK: "-o",
// CHECK-NEXT: "{{.*[\\/]}}parseable_output.swift.tmp.out",
// CHECK-NEXT: "-module-name",
// CHECK-NEXT: "parseable_output",
// CHECK-NEXT: "-empty-abi-descriptor",
// CHECK-NEXT: "-emit-abi-descriptor-path",
// CHECK-NEXT: "{{.*[\\/]}}parseable_output.swift.tmp.abi.json",
// CHECK-NEXT: "-emit-module",
// CHECK-NEXT: "-emit-module-path",
// CHECK-NEXT: "{{.*[\\/]}}parseable_output.swift.tmp.swiftmodule",
// CHECK-NEXT: "-serialize-diagnostics",
// CHECK-NEXT: "-serialize-diagnostics-path"
// CHECK-NEXT: "{{.*[\\/]}}parseable_output.swift.tmp.dia",
// CHECK-NEXT: "-frontend-parseable-output"
// CHECK-NEXT: ],
// CHECK-NEXT: "inputs": [
// CHECK-NEXT: "{{.*[\\/]}}parseable_output.swift"
// CHECK-NEXT: ],
// CHECK-NEXT: "outputs": [
// CHECK: "outputs": [
// CHECK-NEXT: {
// CHECK-NEXT: "type": "image",
// CHECK-NEXT: "path": "{{.*[\\/]}}parseable_output.swift.tmp.out"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "type": "swiftmodule",
// CHECK-NEXT: "path": "{{.*[\\/]}}parseable_output.swift.tmp.swiftmodule"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "type": "diagnostics",
// CHECK-NEXT: "path": "{{.*[\\/]}}parseable_output.swift.tmp.dia"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "type": "abi-baseline-json",
// CHECK-NEXT: "path": "{{.*[\\/]}}parseable_output.swift.tmp.abi.json"
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "pid": [[PID:[0-9]*]]
Expand Down
9 changes: 5 additions & 4 deletions test/Frontend/parseable_output_error.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// RUN: not %target-swift-frontend -primary-file %s -o %t.out -emit-module -emit-module-path %t.swiftmodule -frontend-parseable-output 2>&1 | %FileCheck %s
// Check without primary files (WMO):
// RUN: not %target-swift-frontend %s -o %t.out -emit-module -emit-module-path %t.swiftmodule -frontend-parseable-output 2>&1 | %FileCheck %s

func foo() {
return 11;
Expand All @@ -7,11 +9,10 @@ func foo() {
// CHECK-NEXT: {
// CHECK-NEXT: "kind": "began",
// CHECK-NEXT: "name": "compile",
// CHECK-NEXT: "command": "{{.*[\\/]}}swift-frontend{{(\.exe)?}}{{.*}}-primary-file {{.*[\\/]}}parseable_output_error.swift -o {{.*[\\/]}}parseable_output_error.swift.tmp.out -emit-module -emit-module-path {{.*[\\/]}}parseable_output_error.swift.tmp.swiftmodule -frontend-parseable-output",
// CHECK-NEXT: "command": "{{.*[\\/]}}swift-frontend{{(\.exe)?}}{{.*}} {{.*[\\/]}}parseable_output_error.swift -o {{.*[\\/]}}parseable_output_error.swift.tmp.out -emit-module -emit-module-path {{.*[\\/]}}parseable_output_error.swift.tmp.swiftmodule -frontend-parseable-output",
// CHECK-NEXT: "command_executable": "{{.*[\\/]}}swift{{(-frontend|c)?(\.exe)?}}",
// CHECK-NEXT: "command_arguments": [
// CHECK: "-primary-file",
// CHECK-NEXT: "{{.*[\\/]}}parseable_output_error.swift",
// CHECK: "{{.*[\\/]}}parseable_output_error.swift",
// CHECK-NEXT: "-o",
// CHECK-NEXT: "{{.*[\\/]}}parseable_output_error.swift.tmp.out",
// CHECK-NEXT: "-emit-module",
Expand Down Expand Up @@ -43,7 +44,7 @@ func foo() {
// CHECK-NEXT: "kind": "finished",
// CHECK-NEXT: "name": "compile",
// CHECK-NEXT: "pid": [[PID]],
// CHECK-NEXT: "output": "{{.*[\\/]}}parseable_output_error.swift:4:12: error: unexpected non-void return value in void function{{.*}}return 11;{{.*[\\/]}}parseable_output_error.swift:4:12: note: did you mean to add a return type?{{.*}}return 11;
// CHECK-NEXT: "output": "{{.*[\\/]}}parseable_output_error.swift:6:12: error: unexpected non-void return value in void function{{.*}}return 11;{{.*[\\/]}}parseable_output_error.swift:6:12: note: did you mean to add a return type?{{.*}}return 11;
// CHECK-NEXT: "process": {
// CHECK-NEXT: "real_pid": [[PID]]
// CHECK-NEXT: },
Expand Down