Skip to content

Commit 8322f5f

Browse files
[Caching] Teach libSwiftScan to replay all diagnostics kind
Add support for serialized diagnostics, parseable output, and other kinds of output from diagnostics engine to the libSwiftScan replayCompilation API. rdar://129015959 (cherry picked from commit 1912d0b)
1 parent 61cb964 commit 8322f5f

File tree

7 files changed

+172
-26
lines changed

7 files changed

+172
-26
lines changed

include/swift/Frontend/DiagnosticHelper.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define SWIFT_FRONTEND_DIAGNOSTIC_HELPER_H
1919

2020
#include "swift/Basic/LLVM.h"
21+
#include "llvm/Support/raw_ostream.h"
2122

2223
namespace swift {
2324
class CompilerInstance;
@@ -30,7 +31,10 @@ class DiagnosticHelper {
3031

3132
public:
3233
/// Create a DiagnosticHelper class to emit diagnostics from frontend actions.
34+
/// OS is the stream to print diagnostics. useQuasiPID determines if using
35+
/// real PID when priting parseable output.
3336
static DiagnosticHelper create(CompilerInstance &instance,
37+
llvm::raw_pwrite_stream &OS = llvm::errs(),
3438
bool useQuasiPID = false);
3539

3640
/// Initialized all DiagConsumers and add to the CompilerInstance.
@@ -57,7 +61,8 @@ class DiagnosticHelper {
5761
~DiagnosticHelper();
5862

5963
private:
60-
DiagnosticHelper(CompilerInstance &instance, bool useQuasiPID);
64+
DiagnosticHelper(CompilerInstance &instance, llvm::raw_pwrite_stream &OS,
65+
bool useQuasiPID);
6166
};
6267

6368
} // namespace swift

lib/Frontend/DiagnosticHelper.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "swift/Frontend/DiagnosticHelper.h"
1818
#include "swift/AST/DiagnosticEngine.h"
19+
#include "swift/AST/DiagnosticsFrontend.h"
1920
#include "swift/Basic/Edit.h"
2021
#include "swift/Basic/ParseableOutput.h"
2122
#include "swift/Basic/SourceManager.h"
@@ -24,6 +25,7 @@
2425
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
2526
#include "swift/Frontend/SerializedDiagnosticConsumer.h"
2627
#include "swift/Migrator/FixitFilter.h"
28+
#include "llvm/Support/raw_ostream.h"
2729

2830
#if __has_include(<unistd.h>)
2931
#include <unistd.h>
@@ -38,7 +40,8 @@ class LLVM_LIBRARY_VISIBILITY DiagnosticHelper::Implementation {
3840
friend class DiagnosticHelper;
3941

4042
public:
41-
Implementation(CompilerInstance &instance, bool useQuasiPID);
43+
Implementation(CompilerInstance &instance, llvm::raw_pwrite_stream &OS,
44+
bool useQuasiPID);
4245

4346
void initDiagConsumers(CompilerInvocation &invocation);
4447

@@ -59,6 +62,7 @@ class LLVM_LIBRARY_VISIBILITY DiagnosticHelper::Implementation {
5962
const sys::TaskProcessInformation procInfo;
6063

6164
CompilerInstance &instance;
65+
llvm::raw_pwrite_stream &errOS;
6266

6367
// potentially created diagnostic consumers.
6468
PrintingDiagnosticConsumer PDC;
@@ -226,9 +230,10 @@ createJSONFixItDiagnosticConsumerIfNeeded(
226230
}
227231

228232
DiagnosticHelper::Implementation::Implementation(CompilerInstance &instance,
233+
llvm::raw_pwrite_stream &OS,
229234
bool useQuasiPID)
230235
: OSPid(useQuasiPID ? QUASI_PID_START : getpid()), procInfo(OSPid),
231-
instance(instance) {
236+
instance(instance), errOS(OS), PDC(OS) {
232237
instance.addDiagnosticConsumer(&PDC);
233238
}
234239

@@ -396,7 +401,7 @@ void DiagnosticHelper::Implementation::beginMessage(
396401
[&](const InputFile &Input, unsigned idx) -> bool {
397402
ArrayRef<InputFile> Inputs(Input);
398403
emitBeganMessage(
399-
llvm::errs(), mapFrontendInvocationToAction(invocation),
404+
errOS, mapFrontendInvocationToAction(invocation),
400405
constructDetailedTaskDescription(invocation, Inputs, args),
401406
pid - idx, procInfo);
402407
return false;
@@ -405,7 +410,7 @@ void DiagnosticHelper::Implementation::beginMessage(
405410
// If no primary inputs are present, we are in WMO or EmitModule.
406411
bool isEmitModule = invocation.getFrontendOptions().RequestedAction ==
407412
FrontendOptions::ActionType::EmitModuleOnly;
408-
emitBeganMessage(llvm::errs(), mapFrontendInvocationToAction(invocation),
413+
emitBeganMessage(errOS, mapFrontendInvocationToAction(invocation),
409414
constructDetailedTaskDescription(
410415
invocation, IO.getAllInputs(), args, isEmitModule),
411416
OSPid, procInfo);
@@ -438,7 +443,7 @@ void DiagnosticHelper::Implementation::endMessage(int retCode) {
438443
std::copy(PrimaryDiags.begin(), PrimaryDiags.end(),
439444
std::ostream_iterator<std::string>(JoinedDiags, Delim));
440445

441-
emitFinishedMessage(llvm::errs(),
446+
emitFinishedMessage(errOS,
442447
mapFrontendInvocationToAction(invocation),
443448
JoinedDiags.str(), retCode, pid - idx, procInfo);
444449
return false;
@@ -455,7 +460,7 @@ void DiagnosticHelper::Implementation::endMessage(int retCode) {
455460
std::ostringstream JoinedDiags;
456461
std::copy(AllDiagnostics.begin(), AllDiagnostics.end(),
457462
std::ostream_iterator<std::string>(JoinedDiags, Delim));
458-
emitFinishedMessage(llvm::errs(), mapFrontendInvocationToAction(invocation),
463+
emitFinishedMessage(errOS, mapFrontendInvocationToAction(invocation),
459464
JoinedDiags.str(), retCode, OSPid, procInfo);
460465
}
461466

@@ -492,12 +497,15 @@ void DiagnosticHelper::Implementation::diagnoseFatalError(const char *reason,
492497
}
493498

494499
DiagnosticHelper DiagnosticHelper::create(CompilerInstance &instance,
500+
llvm::raw_pwrite_stream &OS,
495501
bool useQuasiPID) {
496-
return DiagnosticHelper(instance, useQuasiPID);
502+
return DiagnosticHelper(instance, OS, useQuasiPID);
497503
}
498504

499-
DiagnosticHelper::DiagnosticHelper(CompilerInstance &instance, bool useQuasiPID)
500-
: Impl(*new Implementation(instance, useQuasiPID)) {}
505+
DiagnosticHelper::DiagnosticHelper(CompilerInstance &instance,
506+
llvm::raw_pwrite_stream &OS,
507+
bool useQuasiPID)
508+
: Impl(*new Implementation(instance, OS, useQuasiPID)) {}
501509

502510
DiagnosticHelper::~DiagnosticHelper() { delete &Impl; }
503511

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test -O \
5+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \
6+
// RUN: %t/a.swift %t/b.swift %t/c.swift -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas
7+
8+
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json Test > %t/MyApp.cmd
9+
// RUN: echo "\"-disable-implicit-string-processing-module-import\"" >> %t/MyApp.cmd
10+
// RUN: echo "\"-disable-implicit-concurrency-module-import\"" >> %t/MyApp.cmd
11+
// RUN: echo "\"-parse-stdlib\"" >> %t/MyApp.cmd
12+
13+
// RUN: %swift-scan-test -action compute_cache_key_from_index -cas-path %t/cas -input 0 -- \
14+
// RUN: %target-swift-frontend -cache-compile-job -primary-file %t/a.swift -primary-file %t/b.swift %t/c.swift \
15+
// RUN: -c -emit-dependencies -module-name Test -o %t/a.o -o %t/b.o -cas-path %t/cas \
16+
// RUN: @%t/MyApp.cmd > %t/key0.casid
17+
18+
// RUN: %swift-scan-test -action compute_cache_key_from_index -cas-path %t/cas -input 1 -- \
19+
// RUN: %target-swift-frontend -cache-compile-job -primary-file %t/a.swift -primary-file %t/b.swift %t/c.swift \
20+
// RUN: -c -emit-dependencies -module-name Test -o %t/a.o -o %t/b.o -cas-path %t/cas \
21+
// RUN: @%t/MyApp.cmd > %t/key1.casid
22+
23+
// RUN: %target-swift-frontend -cache-compile-job \
24+
// RUN: -primary-file %t/a.swift -primary-file %t/b.swift %t/c.swift \
25+
// RUN: -c -emit-dependencies \
26+
// RUN: -module-name Test -o %t/a.o -o %t/b.o -cas-path %t/cas @%t/MyApp.cmd
27+
28+
// RUN: %target-swift-frontend -cache-compile-job \
29+
// RUN: %t/a.swift %t/b.swift -primary-file %t/c.swift \
30+
// RUN: -c -emit-dependencies \
31+
// RUN: -module-name Test -o %t/c.o -cas-path %t/cas @%t/MyApp.cmd
32+
33+
// RUN: %swift-scan-test -action replay_result -cas-path %t/cas -id @%t/key0.casid -- %target-swift-frontend -cache-compile-job \
34+
// RUN: -primary-file %t/a.swift -primary-file %t/b.swift %t/c.swift \
35+
// RUN: -c -emit-dependencies -module-name Test -o %t/a2.o -o %t/b2.o -cas-path %t/cas \
36+
// RUN: -serialize-diagnostics -serialize-diagnostics-path %t/a2.dia -serialize-diagnostics-path %t/b2.dia \
37+
// RUN: @%t/MyApp.cmd -frontend-parseable-output 2>&1 | %FileCheck %s --check-prefix=PARSEABLE
38+
39+
// RUN: c-index-test -read-diagnostics %t/a2.dia 2>&1 | %FileCheck %s --check-prefix=A-WARN
40+
// RUN: c-index-test -read-diagnostics %t/b2.dia 2>&1 | %FileCheck %s --check-prefix=B-WARN
41+
42+
// A-WARN: warning: This is a warning
43+
// B-WARN: warning: This is also a warning
44+
45+
// RUN: %swift-scan-test -action replay_result -cas-path %t/cas -id @%t/key1.casid -- %target-swift-frontend -cache-compile-job \
46+
// RUN: -primary-file %t/a.swift -primary-file %t/b.swift %t/c.swift \
47+
// RUN: -c -emit-dependencies -module-name Test -o %t/a2.o -o %t/b2.o -cas-path %t/cas \
48+
// RUN: -serialize-diagnostics -serialize-diagnostics-path %t/a2.dia -serialize-diagnostics-path %t/b2.dia \
49+
// RUN: @%t/MyApp.cmd -frontend-parseable-output 2>&1 | %FileCheck %s --check-prefix=NO-OUTPUT --allow-empty
50+
51+
// PARSEABLE-COUNT-1: "kind": "began",
52+
// PARSEABLE-COUNT-1: "kind": "finished",
53+
// PRASEABLE-NOT: "kind": "began",
54+
// PRASEABLE-NOT: "kind": "finished",
55+
56+
// NO-OUTPUT-NOT: "kind": "began",
57+
58+
//--- a.swift
59+
#warning("This is a warning")
60+
//--- b.swift
61+
#warning("This is also a warning")
62+
//--- c.swift
63+
#warning("This is another warning")

test/CAS/swift-scan-diagnostics.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test -O \
4+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \
5+
// RUN: %s -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas
6+
7+
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json Test > %t/MyApp.cmd
8+
// RUN: echo "\"-disable-implicit-string-processing-module-import\"" >> %t/MyApp.cmd
9+
// RUN: echo "\"-disable-implicit-concurrency-module-import\"" >> %t/MyApp.cmd
10+
// RUN: echo "\"-parse-stdlib\"" >> %t/MyApp.cmd
11+
12+
// RUN: %swift-scan-test -action compute_cache_key -cas-path %t/cas -input %s -- %target-swift-frontend -cache-compile-job %s \
13+
// RUN: -emit-module -emit-module-path %t/Test.swiftmodule -c -emit-dependencies -module-name Test -o %t/test.o -cas-path %t/cas \
14+
// RUN: @%t/MyApp.cmd > %t/key.casid
15+
16+
// RUN: %swift-scan-test -action compute_cache_key_from_index -cas-path %t/cas -input 0 -- %target-swift-frontend -cache-compile-job %s \
17+
// RUN: -emit-module -emit-module-path %t/Test.swiftmodule -c -emit-dependencies -module-name Test -o %t/test.o -cas-path %t/cas \
18+
// RUN: @%t/MyApp.cmd > %t/key1.casid
19+
20+
// RUN: diff %t/key.casid %t/key1.casid
21+
22+
// RUN: not %swift-scan-test -action cache_query -id @%t/key.casid -cas-path %t/cas 2>&1 | %FileCheck %s --check-prefix=CHECK-QUERY-NOT-FOUND
23+
24+
// RUN: %target-swift-frontend -cache-compile-job %s -emit-module -emit-module-path %t/Test.swiftmodule -c -emit-dependencies \
25+
// RUN: -serialize-diagnostics -serialize-diagnostics-path %t/test.dia \
26+
// RUN: -module-name Test -o %t/test.o -cas-path %t/cas @%t/MyApp.cmd
27+
28+
// RUN: %swift-scan-test -action cache_query -id @%t/key.casid -cas-path %t/cas | %FileCheck %s --check-prefix=CHECK-QUERY
29+
30+
// RUN: %swift-scan-test -action replay_result -cas-path %t/cas -id @%t/key.casid -- %target-swift-frontend -cache-compile-job %s \
31+
// RUN: -emit-module -emit-module-path %t/Test2.swiftmodule -c -emit-dependencies -module-name Test -o %t/test2.o -cas-path %t/cas \
32+
// RUN: -serialize-diagnostics -serialize-diagnostics-path %t/test2.dia \
33+
// RUN: @%t/MyApp.cmd
34+
35+
// RUN: diff %t/Test.swiftmodule %t/Test2.swiftmodule
36+
// RUN: diff %t/test.o %t/test2.o
37+
// RUN: diff %t/test.dia %t/test2.dia
38+
39+
// CHECK-QUERY-NOT-FOUND: cached output not found
40+
// CHECK-QUERY: Cached Compilation for key "llvmcas://{{.*}}" has 4 outputs:
41+
// CHECK-QUERY-NEXT: object: llvmcas://
42+
// CHECK-QUERY-NEXT: dependencies: llvmcas://
43+
// CHECK-QUERY-NEXT: swiftmodule: llvmcas://
44+
// CHECK-QUERY-NEXT: cached-diagnostics: llvmcas://
45+
46+
// RUN: %swift-scan-test -action replay_result -cas-path %t/cas -id @%t/key.casid -- %target-swift-frontend -cache-compile-job %s \
47+
// RUN: -emit-module -emit-module-path %t/Test2.swiftmodule -c -emit-dependencies -module-name Test -o %t/test2.o -cas-path %t/cas \
48+
// RUN: -frontend-parseable-output -serialize-diagnostics -serialize-diagnostics-path %t/test3.dia \
49+
// RUN: @%t/MyApp.cmd 2>&1 | %FileCheck %s --check-prefix=PARSEABLE
50+
51+
// RUN: diff %t/test.dia %t/test3.dia
52+
53+
// PARSEABLE: {{[1-9][0-9]*}}
54+
// PARSEABLE-NEXT: {
55+
// PARSEABLE-NEXT: "kind": "began",
56+
// PARSEABLE-NEXT: "name": "compile",
57+
58+
// PARSEABLE: "kind": "finished",
59+
// PARSEABLE-NEXT: "name": "compile",
60+
61+
62+
#warning("This is a warning")

test/CAS/swift-scan-test.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
// RUN: @%t/MyApp.cmd
3232

3333
// RUN: diff %t/Test.swiftmodule %t/Test2.swiftmodule
34-
// RUN: diff %t/test.o %t/test.o
34+
// RUN: diff %t/test.o %t/test2.o
3535

3636
// CHECK-QUERY-NOT-FOUND: cached output not found
3737
// CHECK-QUERY: Cached Compilation for key "llvmcas://{{.*}}" has 4 outputs:

tools/libSwiftScan/SwiftCaching.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "swift/Frontend/CachingUtils.h"
2727
#include "swift/Frontend/CompileJobCacheKey.h"
2828
#include "swift/Frontend/CompileJobCacheResult.h"
29+
#include "swift/Frontend/DiagnosticHelper.h"
2930
#include "swift/Frontend/Frontend.h"
3031
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
3132
#include "swift/Option/Options.h"
@@ -917,19 +918,7 @@ static llvm::Error replayCompilation(SwiftScanReplayInstance &Instance,
917918
const auto &Input = AllInputs[Comp.InputIndex];
918919

919920
// Setup DiagnosticsConsumers.
920-
// FIXME: Reduce code duplication against `performFrontend()` and add support
921-
// for JSONFIXIT, SerializedDiagnostics, etc.
922-
PrintingDiagnosticConsumer PDC(Err);
923-
Inst.addDiagnosticConsumer(&PDC);
924-
925-
if (Invocation.getDiagnosticOptions().UseColor)
926-
PDC.forceColors();
927-
PDC.setPrintEducationalNotes(
928-
Invocation.getDiagnosticOptions().PrintEducationalNotes);
929-
PDC.setFormattingStyle(
930-
Invocation.getDiagnosticOptions().PrintedFormattingStyle);
931-
PDC.setEmitMacroExpansionFiles(
932-
Invocation.getDiagnosticOptions().EmitMacroExpansionFiles);
921+
DiagnosticHelper DH = DiagnosticHelper::create(Inst, Err, /*QuasiPID=*/true);
933922

934923
std::string InstanceSetupError;
935924
if (Inst.setupForReplay(Instance.Invocation, InstanceSetupError,
@@ -989,15 +978,29 @@ static llvm::Error replayCompilation(SwiftScanReplayInstance &Instance,
989978
// Replay diagnostics first.
990979
// FIXME: Currently, the diagnostics is replay from the first file.
991980
if (DiagnosticsOutput) {
981+
DH.initDiagConsumers(Invocation);
982+
DH.beginMessage(Invocation, Instance.Args);
983+
992984
if (auto E = CDP->replayCachedDiagnostics(DiagnosticsOutput->getData()))
993985
return E;
994986

995987
if (Remarks)
996988
Inst.getDiags().diagnose(SourceLoc(), diag::replay_output,
997989
"<cached-diagnostics>",
998990
CAS.getID(Comp.Key).toString());
991+
} else {
992+
// Don't write anything when parseable output is requested.
993+
if (Invocation.getFrontendOptions().FrontendParseableOutput)
994+
DH.setSuppressOutput(true);
999995
}
1000996

997+
SWIFT_DEFER {
998+
if (DiagnosticsOutput) {
999+
DH.endMessage(0);
1000+
Inst.getDiags().finishProcessing();
1001+
}
1002+
};
1003+
10011004
// OutputBackend for replay.
10021005
ReplayOutputBackend Backend(
10031006
makeIntrusiveRefCnt<llvm::vfs::OnDiskOutputBackend>(), Out);

tools/swift-scan-test/swift-scan-test.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,13 @@ static int action_replay_result(swiftscan_cas_t cas, const char *key,
145145
std::vector<const char *> &Args) {
146146
swiftscan_string_ref_t err_msg;
147147
auto comp = swiftscan_cache_query(cas, key, /*globally=*/false, &err_msg);
148-
if (!comp)
149-
return printError(err_msg);
148+
if (!comp) {
149+
if (err_msg.length != 0)
150+
return printError(err_msg);
151+
152+
llvm::errs() << "key " << key << " not found for replay\n";
153+
return EXIT_FAILURE;
154+
}
150155

151156
SWIFT_DEFER { swiftscan_cached_compilation_dispose(comp); };
152157
auto numOutput = swiftscan_cached_compilation_get_num_outputs(comp);

0 commit comments

Comments
 (0)