@@ -848,6 +848,7 @@ namespace swift {
848848 friend class DiagnosticTransaction ;
849849 friend class CompoundDiagnosticTransaction ;
850850 friend class DiagnosticStateRAII ;
851+ friend class DiagnosticQueue ;
851852
852853 public:
853854 explicit DiagnosticEngine (SourceManager &SourceMgr)
@@ -1137,10 +1138,20 @@ namespace swift {
11371138 // / Send \c diag to all diagnostic consumers.
11381139 void emitDiagnostic (const Diagnostic &diag);
11391140
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+
11401148 // / Send all tentative diagnostics to all diagnostic consumers and
11411149 // / delete them.
11421150 void emitTentativeDiagnostics ();
11431151
1152+ // / Forward all tentative diagnostics to a different diagnostic engine.
1153+ void forwardTentativeDiagnosticsTo (DiagnosticEngine &targetEngine);
1154+
11441155 public:
11451156 DiagnosticKind declaredDiagnosticKindFor (const DiagID id);
11461157
@@ -1333,6 +1344,78 @@ namespace swift {
13331344 }
13341345 };
13351346
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+
13361419 inline void
13371420 DiagnosticEngine::diagnoseWithNotes (InFlightDiagnostic parentDiag,
13381421 llvm::function_ref<void (void )> builder) {
0 commit comments