Skip to content

Commit 47da04f

Browse files
authored
Merge pull request #34417 from artemcm/FrontendParseableOutput
Add support for parseable-output straight from the frontend
2 parents fd1fd25 + 915186a commit 47da04f

18 files changed

+919
-357
lines changed

include/swift/Basic/ParseableOutput.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//===----- ParseableOutput.h - Helpers for parseable output ------- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// \file
14+
/// Helpers for emitting the compiler's parseable output.
15+
///
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_PARSEABLEOUTPUT_H
19+
#define SWIFT_PARSEABLEOUTPUT_H
20+
21+
#include "swift/Basic/LLVM.h"
22+
#include "swift/Basic/TaskQueue.h"
23+
#include "swift/Basic/FileTypes.h"
24+
25+
namespace swift {
26+
27+
namespace parseable_output {
28+
29+
/// Quasi-PIDs are _negative_ PID-like unique keys used to
30+
/// masquerade batch job constituents as (quasi)processes, when writing
31+
/// parseable output to consumers that don't understand the idea of a batch
32+
/// job. They are negative in order to avoid possibly colliding with real
33+
/// PIDs (which are always positive). We start at -1000 here as a crude but
34+
/// harmless hedge against colliding with an errno value that might slip
35+
/// into the stream of real PIDs (say, due to a TaskQueue bug).
36+
const int QUASI_PID_START = -1000;
37+
38+
struct CommandInput {
39+
std::string Path;
40+
CommandInput() {}
41+
CommandInput(StringRef Path) : Path(Path) {}
42+
};
43+
44+
using OutputPair = std::pair<file_types::ID, std::string>;
45+
46+
/// A client-agnostic (e.g. either the compiler driver or `swift-frontend`)
47+
/// description of a task that is the subject of a parseable-output message.
48+
struct DetailedTaskDescription {
49+
std::string Executable;
50+
SmallVector<std::string, 16> Arguments;
51+
std::string CommandLine;
52+
SmallVector<CommandInput, 4> Inputs;
53+
SmallVector<OutputPair, 8> Outputs;
54+
};
55+
56+
/// Emits a "began" message to the given stream.
57+
void emitBeganMessage(raw_ostream &os, StringRef Name,
58+
DetailedTaskDescription TascDesc,
59+
int64_t Pid, sys::TaskProcessInformation ProcInfo);
60+
61+
/// Emits a "finished" message to the given stream.
62+
void emitFinishedMessage(raw_ostream &os, StringRef Name,
63+
std::string Output, int ExitStatus,
64+
int64_t Pid, sys::TaskProcessInformation ProcInfo);
65+
66+
/// Emits a "signalled" message to the given stream.
67+
void emitSignalledMessage(raw_ostream &os, StringRef Name, StringRef ErrorMsg,
68+
StringRef Output, Optional<int> Signal,
69+
int64_t Pid, sys::TaskProcessInformation ProcInfo);
70+
71+
/// Emits a "skipped" message to the given stream.
72+
void emitSkippedMessage(raw_ostream &os, StringRef Name,
73+
DetailedTaskDescription TascDesc);
74+
75+
} // end namespace parseable_output
76+
} // end namespace swift
77+
78+
#endif

include/swift/Basic/SupplementaryOutputPaths.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define SWIFT_FRONTEND_SUPPLEMENTARYOUTPUTPATHS_H
1515

1616
#include "swift/Basic/LLVM.h"
17+
#include "llvm/IR/Function.h"
1718

1819
#include <string>
1920

@@ -171,6 +172,42 @@ struct SupplementaryOutputPaths {
171172
SupplementaryOutputPaths() = default;
172173
SupplementaryOutputPaths(const SupplementaryOutputPaths &) = default;
173174

175+
/// Apply a given function for each existing (non-empty string) supplementary output
176+
void forEachSetOutput(llvm::function_ref<void(const std::string&)> fn) const {
177+
if (!ObjCHeaderOutputPath.empty())
178+
fn(ObjCHeaderOutputPath);
179+
if (!ModuleOutputPath.empty())
180+
fn(ModuleOutputPath);
181+
if (!ModuleSourceInfoOutputPath.empty())
182+
fn(ModuleSourceInfoOutputPath);
183+
if (!ModuleDocOutputPath.empty())
184+
fn(ModuleDocOutputPath);
185+
if (!DependenciesFilePath.empty())
186+
fn(DependenciesFilePath);
187+
if (!ReferenceDependenciesFilePath.empty())
188+
fn(ReferenceDependenciesFilePath);
189+
if (!SwiftRangesFilePath.empty())
190+
fn(SwiftRangesFilePath);
191+
if (!CompiledSourceFilePath.empty())
192+
fn(CompiledSourceFilePath);
193+
if (!SerializedDiagnosticsPath.empty())
194+
fn(SerializedDiagnosticsPath);
195+
if (!FixItsOutputPath.empty())
196+
fn(FixItsOutputPath);
197+
if (!LoadedModuleTracePath.empty())
198+
fn(LoadedModuleTracePath);
199+
if (!TBDPath.empty())
200+
fn(TBDPath);
201+
if (!ModuleInterfaceOutputPath.empty())
202+
fn(ModuleInterfaceOutputPath);
203+
if (!PrivateModuleInterfaceOutputPath.empty())
204+
fn(PrivateModuleInterfaceOutputPath);
205+
if (!LdAddCFilePath.empty())
206+
fn(LdAddCFilePath);
207+
if (!ModuleSummaryOutputPath.empty())
208+
fn(ModuleSummaryOutputPath);
209+
}
210+
174211
bool empty() const {
175212
return ObjCHeaderOutputPath.empty() && ModuleOutputPath.empty() &&
176213
ModuleDocOutputPath.empty() && DependenciesFilePath.empty() &&

include/swift/Driver/ParseableOutput.h

Lines changed: 0 additions & 53 deletions
This file was deleted.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//===- AccumulatingDiagnosticConsumer.h - Collect Text Diagnostics C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines the AccumulatingDiagnosticConsumer class, which collects
14+
// all emitted diagnostics into an externally-owned collection.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_ACCUMULATINGDIAGNOSTICCONSUMER_H
19+
#define SWIFT_ACCUMULATINGDIAGNOSTICCONSUMER_H
20+
21+
#include "swift/AST/DiagnosticConsumer.h"
22+
#include "swift/Basic/DiagnosticOptions.h"
23+
#include "swift/Basic/LLVM.h"
24+
25+
#include <string>
26+
#include <sstream>
27+
28+
namespace swift {
29+
/// Diagnostic consumer that simply collects all emitted diagnostics into the provided
30+
/// collection.
31+
class AccumulatingFileDiagnosticConsumer : public DiagnosticConsumer {
32+
std::vector<std::string> &Diagnostics;
33+
34+
public:
35+
AccumulatingFileDiagnosticConsumer(std::vector<std::string> &DiagBuffer)
36+
: Diagnostics(DiagBuffer) {}
37+
38+
private:
39+
void handleDiagnostic(SourceManager &SM,
40+
const DiagnosticInfo &Info) override {
41+
addDiagnostic(SM, Info);
42+
43+
for (auto ChildInfo : Info.ChildDiagnosticInfo) {
44+
addDiagnostic(SM, *ChildInfo);
45+
}
46+
}
47+
48+
// TODO: Support Swift-style diagnostic formatting
49+
void addDiagnostic(SourceManager &SM, const DiagnosticInfo &Info) {
50+
// Determine what kind of diagnostic we're emitting.
51+
llvm::SourceMgr::DiagKind SMKind;
52+
switch (Info.Kind) {
53+
case DiagnosticKind::Error:
54+
SMKind = llvm::SourceMgr::DK_Error;
55+
break;
56+
case DiagnosticKind::Warning:
57+
SMKind = llvm::SourceMgr::DK_Warning;
58+
break;
59+
60+
case DiagnosticKind::Note:
61+
SMKind = llvm::SourceMgr::DK_Note;
62+
break;
63+
64+
case DiagnosticKind::Remark:
65+
SMKind = llvm::SourceMgr::DK_Remark;
66+
break;
67+
}
68+
69+
// Translate ranges.
70+
SmallVector<llvm::SMRange, 2> Ranges;
71+
for (auto R : Info.Ranges)
72+
Ranges.push_back(getRawRange(SM, R));
73+
74+
// Translate fix-its.
75+
SmallVector<llvm::SMFixIt, 2> FixIts;
76+
for (DiagnosticInfo::FixIt F : Info.FixIts)
77+
FixIts.push_back(getRawFixIt(SM, F));
78+
79+
// Actually substitute the diagnostic arguments into the diagnostic text.
80+
llvm::SmallString<256> Text;
81+
{
82+
llvm::raw_svector_ostream Out(Text);
83+
DiagnosticEngine::formatDiagnosticText(Out, Info.FormatString,
84+
Info.FormatArgs);
85+
}
86+
87+
const llvm::SourceMgr &rawSM = SM.getLLVMSourceMgr();
88+
auto Msg = SM.GetMessage(Info.Loc, SMKind, Text, Ranges, FixIts);
89+
std::string result;
90+
llvm::raw_string_ostream os(result);
91+
rawSM.PrintMessage(os, Msg, false);
92+
os.flush();
93+
Diagnostics.push_back(result);
94+
}
95+
};
96+
}
97+
#endif

include/swift/Frontend/FrontendInputsAndOutputs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ class FrontendInputsAndOutputs {
110110
bool
111111
forEachPrimaryInput(llvm::function_ref<bool(const InputFile &)> fn) const;
112112

113+
/// Iterates over primary inputs, exposing their unique ordered index
114+
/// If \p fn returns true, exit early and return true.
115+
bool forEachPrimaryInputWithIndex(
116+
llvm::function_ref<bool(const InputFile &, unsigned index)> fn) const;
117+
113118
/// If \p fn returns true, exit early and return true.
114119
bool
115120
forEachNonPrimaryInput(llvm::function_ref<bool(const InputFile &)> fn) const;

include/swift/Frontend/FrontendOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,11 @@ class FrontendOptions {
184184
/// entity.
185185
bool ProfileEntities = false;
186186

187+
/// Emit parseable-output directly from the frontend, instead of relying
188+
/// the driver to emit it. This is used in context where frontend jobs are executed by
189+
/// clients other than the driver.
190+
bool FrontendParseableOutput = false;
191+
187192
/// Indicates whether or not an import statement can pick up a Swift source
188193
/// file (as opposed to a module file).
189194
bool EnableSourceImport = false;

include/swift/Option/FrontendOptions.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ def output_filelist : Separate<["-"], "output-filelist">,
3030
def supplementary_output_file_map : Separate<["-"], "supplementary-output-file-map">,
3131
HelpText<"Specify supplementary outputs in a file rather than on the command line">;
3232

33+
def frontend_parseable_output : Flag<["-"], "frontend-parseable-output">,
34+
HelpText<"Emit textual output in a parseable format">;
3335

3436
def emit_module_doc : Flag<["-"], "emit-module-doc">,
3537
HelpText<"Emit a module documentation file based on documentation "

lib/Basic/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ add_swift_host_library(swiftBasic STATIC
5252
FileSystem.cpp
5353
FileTypes.cpp
5454
Fingerprint.cpp
55+
ParseableOutput.cpp
5556
JSONSerialization.cpp
5657
LangOptions.cpp
5758
Located.cpp

0 commit comments

Comments
 (0)