@@ -848,6 +848,7 @@ namespace swift {
848
848
friend class DiagnosticTransaction ;
849
849
friend class CompoundDiagnosticTransaction ;
850
850
friend class DiagnosticStateRAII ;
851
+ friend class DiagnosticQueue ;
851
852
852
853
public:
853
854
explicit DiagnosticEngine (SourceManager &SourceMgr)
@@ -1137,10 +1138,20 @@ namespace swift {
1137
1138
// / Send \c diag to all diagnostic consumers.
1138
1139
void emitDiagnostic (const Diagnostic &diag);
1139
1140
1141
+ // / Handle a new diagnostic, which will either be emitted, or added to an
1142
+ // / active transaction.
1143
+ void handleDiagnostic (Diagnostic &&diag);
1144
+
1145
+ // / Clear any tentative diagnostics.
1146
+ void clearTentativeDiagnostics ();
1147
+
1140
1148
// / Send all tentative diagnostics to all diagnostic consumers and
1141
1149
// / delete them.
1142
1150
void emitTentativeDiagnostics ();
1143
1151
1152
+ // / Forward all tentative diagnostics to a different diagnostic engine.
1153
+ void forwardTentativeDiagnosticsTo (DiagnosticEngine &targetEngine);
1154
+
1144
1155
public:
1145
1156
DiagnosticKind declaredDiagnosticKindFor (const DiagID id);
1146
1157
@@ -1333,6 +1344,78 @@ namespace swift {
1333
1344
}
1334
1345
};
1335
1346
1347
+ // / Represents a queue of diagnostics that have their emission delayed until
1348
+ // / the queue is destroyed. This is similar to DiagnosticTransaction, but
1349
+ // / with a few key differences:
1350
+ // /
1351
+ // / - The queue maintains its own diagnostic engine (which may be accessed
1352
+ // / through `getDiags()`), and diagnostics must be specifically emitted
1353
+ // / using that engine to be enqueued.
1354
+ // / - It allows for non-LIFO transactions, as each queue operates
1355
+ // / independently.
1356
+ // / - A queue can be drained multiple times without having to be recreated
1357
+ // / (unlike DiagnosticTransaction, it has no concept of "closing").
1358
+ // /
1359
+ // / Note you may add DiagnosticTransactions to the queue's diagnostic engine,
1360
+ // / but they must be closed before attempting to clear or emit the diagnostics
1361
+ // / in the queue.
1362
+ // /
1363
+ class DiagnosticQueue final {
1364
+ // / The underlying diagnostic engine that the diagnostics will be emitted
1365
+ // / by.
1366
+ DiagnosticEngine &UnderlyingEngine;
1367
+
1368
+ // / A temporary engine used to queue diagnostics.
1369
+ DiagnosticEngine QueueEngine;
1370
+
1371
+ // / Whether the queued diagnostics should be emitted on the destruction of
1372
+ // / the queue, or whether they should be cleared.
1373
+ bool EmitOnDestruction;
1374
+
1375
+ public:
1376
+ DiagnosticQueue (const DiagnosticQueue &) = delete ;
1377
+ DiagnosticQueue &operator =(const DiagnosticQueue &) = delete ;
1378
+
1379
+ // / Create a new diagnostic queue with a given engine to forward the
1380
+ // / diagnostics to.
1381
+ explicit DiagnosticQueue (DiagnosticEngine &engine, bool emitOnDestruction)
1382
+ : UnderlyingEngine(engine), QueueEngine(engine.SourceMgr),
1383
+ EmitOnDestruction(emitOnDestruction) {
1384
+ // Open a transaction to avoid emitting any diagnostics for the temporary
1385
+ // engine.
1386
+ QueueEngine.TransactionCount ++;
1387
+ }
1388
+
1389
+ // / Retrieve the engine which may be used to enqueue diagnostics.
1390
+ DiagnosticEngine &getDiags () { return QueueEngine; }
1391
+
1392
+ // / Retrieve the underlying engine which will receive the diagnostics.
1393
+ DiagnosticEngine &getUnderlyingDiags () { return UnderlyingEngine; }
1394
+
1395
+ // / Clear this queue and erase all diagnostics recorded.
1396
+ void clear () {
1397
+ assert (QueueEngine.TransactionCount == 1 &&
1398
+ " Must close outstanding DiagnosticTransactions before draining" );
1399
+ QueueEngine.clearTentativeDiagnostics ();
1400
+ }
1401
+
1402
+ // / Emit all the diagnostics recorded by this queue.
1403
+ void emit () {
1404
+ assert (QueueEngine.TransactionCount == 1 &&
1405
+ " Must close outstanding DiagnosticTransactions before draining" );
1406
+ QueueEngine.forwardTentativeDiagnosticsTo (UnderlyingEngine);
1407
+ }
1408
+
1409
+ ~DiagnosticQueue () {
1410
+ if (EmitOnDestruction) {
1411
+ emit ();
1412
+ } else {
1413
+ clear ();
1414
+ }
1415
+ QueueEngine.TransactionCount --;
1416
+ }
1417
+ };
1418
+
1336
1419
inline void
1337
1420
DiagnosticEngine::diagnoseWithNotes (InFlightDiagnostic parentDiag,
1338
1421
llvm::function_ref<void (void )> builder) {
0 commit comments