Skip to content

Commit dcb1924

Browse files
committed
Introduce DiagnosticState to track how we should handle diagnostics
Refactor DiagnosticEngine to separate out diagnostic state tracking. This allows gives us a base from which to add further refinements, e.g. warning suppression.
1 parent 1f5a6b3 commit dcb1924

File tree

2 files changed

+116
-52
lines changed

2 files changed

+116
-52
lines changed

include/swift/AST/DiagnosticEngine.h

Lines changed: 72 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,70 @@ namespace swift {
378378
return fixItReplaceChars(Start, End, {});
379379
}
380380
};
381+
382+
/// \brief Class to track, map, and remap diagnostic severity and fatality
383+
///
384+
class DiagnosticState {
385+
public:
386+
/// \brief Describes the current behavior to take with a diagnostic
387+
enum class Behavior {
388+
Unspecified,
389+
Ignore,
390+
Note,
391+
Warn,
392+
Err,
393+
Fatal,
394+
};
395+
396+
private:
397+
/// \brief Whether we should continue to emit diagnostics, even after a
398+
/// fatal error
399+
bool showDiagnosticsAfterFatalError = false;
400+
401+
/// \brief Whether any error diagnostics have been emitted.
402+
bool anyErrorOccurred = false;
403+
404+
/// Fatal error tracking
405+
enum class FatalErrorState {
406+
None,
407+
JustEmitted,
408+
Fatal
409+
};
410+
411+
/// Sticky flag set to \c true when a fatal error is emitted.
412+
FatalErrorState fatalState = FatalErrorState::None;
413+
414+
public:
415+
DiagnosticState() {}
416+
417+
/// \brief Figure out the Behavior for the given diagnostic
418+
Behavior getBehavior(const Diagnostic &);
419+
420+
bool hadAnyError() const { return anyErrorOccurred; }
421+
bool hasFatalErrorOccurred() const {
422+
return fatalState != FatalErrorState::None;
423+
}
424+
425+
void setShowDiagnosticsAfterFatalError(bool val = true) {
426+
showDiagnosticsAfterFatalError = val;
427+
}
428+
429+
void resetHadAnyError() {
430+
anyErrorOccurred = false;
431+
fatalState = FatalErrorState::None;
432+
}
433+
434+
private:
435+
/// \returns true if diagnostic is marked as fatal.
436+
bool isDiagnosticFatal(DiagID ID) const;
437+
438+
// Make the state movable only
439+
DiagnosticState(const DiagnosticState &) = delete;
440+
const DiagnosticState &operator=(const DiagnosticState &) = delete;
441+
442+
DiagnosticState(DiagnosticState &&) = default;
443+
DiagnosticState &operator=(DiagnosticState &&) = default;
444+
};
381445

382446
/// \brief Class responsible for formatting diagnostics and presenting them
383447
/// to the user.
@@ -390,19 +454,7 @@ namespace swift {
390454
/// emitting diagnostics.
391455
SmallVector<DiagnosticConsumer *, 2> Consumers;
392456

393-
/// HadAnyError - True if any error diagnostics have been emitted.
394-
bool HadAnyError;
395-
396-
enum class FatalErrorState {
397-
None,
398-
JustEmitted,
399-
Fatal
400-
};
401-
402-
/// Sticky flag set to \c true when a fatal error is emitted.
403-
FatalErrorState FatalState = FatalErrorState::None;
404-
405-
bool ShowDiagnosticsAfterFatalError = false;
457+
DiagnosticState state;
406458

407459
/// \brief The currently active diagnostic, if there is one.
408460
Optional<Diagnostic> ActiveDiagnostic;
@@ -424,25 +476,22 @@ namespace swift {
424476

425477
public:
426478
explicit DiagnosticEngine(SourceManager &SourceMgr)
427-
: SourceMgr(SourceMgr), HadAnyError(false), ActiveDiagnostic() {
479+
: SourceMgr(SourceMgr), state(), ActiveDiagnostic() {
428480
}
429481

430482
/// hadAnyError - return true if any *error* diagnostics have been emitted.
431-
bool hadAnyError() const {
432-
return HadAnyError;
433-
}
483+
bool hadAnyError() const { return state.hadAnyError(); }
434484

435485
bool hasFatalErrorOccurred() const {
436-
return FatalState != FatalErrorState::None;
486+
return state.hasFatalErrorOccurred();
437487
}
438488

439-
void setShowDiagnosticsAfterFatalError(bool Val = true) {
440-
ShowDiagnosticsAfterFatalError = Val;
489+
void setShowDiagnosticsAfterFatalError(bool val = true) {
490+
state.setShowDiagnosticsAfterFatalError(val);
441491
}
442492

443493
void resetHadAnyError() {
444-
HadAnyError = false;
445-
FatalState = FatalErrorState::None;
494+
state.resetHadAnyError();
446495
}
447496

448497
/// \brief Add an additional DiagnosticConsumer to receive diagnostics.
@@ -572,10 +621,7 @@ namespace swift {
572621

573622
/// \returns true if diagnostic is marked with PointsToFirstBadToken
574623
/// option.
575-
bool isDiagnosticPointsToFirstBadToken(DiagID ID) const;
576-
577-
/// \returns true if diagnostic is marked as fatal.
578-
bool isDiagnosticFatal(DiagID ID) const;
624+
bool isDiagnosticPointsToFirstBadToken(DiagID id) const;
579625

580626
private:
581627
/// \brief Flush the active diagnostic.

lib/AST/DiagnosticEngine.cpp

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ bool DiagnosticEngine::isDiagnosticPointsToFirstBadToken(DiagID ID) const {
180180
return StoredInfo.Options == DiagnosticOptions::PointsToFirstBadToken;
181181
}
182182

183-
bool DiagnosticEngine::isDiagnosticFatal(DiagID ID) const {
183+
bool DiagnosticState::isDiagnosticFatal(DiagID ID) const {
184184
const StoredDiagnosticInfo &StoredInfo =
185185
StoredDiagnosticInfos[(unsigned) ID];
186186
return StoredInfo.Options == DiagnosticOptions::Fatal;
@@ -449,6 +449,45 @@ static void formatDiagnosticText(StringRef InText,
449449
}
450450
}
451451

452+
DiagnosticState::Behavior DiagnosticState::getBehavior(const Diagnostic &diag) {
453+
auto set = [this](DiagnosticState::Behavior lvl) {
454+
if (lvl == Behavior::Fatal) {
455+
fatalState = FatalErrorState::JustEmitted;
456+
anyErrorOccurred = true;
457+
} else if (lvl == Behavior::Err) {
458+
anyErrorOccurred = true;
459+
}
460+
return lvl;
461+
};
462+
463+
auto diagKind = StoredDiagnosticInfos[(unsigned)diag.getID()].Kind;
464+
465+
if (fatalState != FatalErrorState::None) {
466+
bool shouldIgnore = true;
467+
if (diagKind == DiagnosticKind::Note)
468+
shouldIgnore = (fatalState == FatalErrorState::Fatal);
469+
else
470+
fatalState = FatalErrorState::Fatal;
471+
472+
if (shouldIgnore && !showDiagnosticsAfterFatalError) {
473+
return set(Behavior::Ignore);
474+
}
475+
}
476+
477+
if (isDiagnosticFatal(diag.getID()))
478+
return set(Behavior::Fatal);
479+
480+
// Re-map as appropriate
481+
switch (diagKind) {
482+
case DiagnosticKind::Error:
483+
return set(Behavior::Err);
484+
case DiagnosticKind::Warning:
485+
return set(Behavior::Warn);
486+
case DiagnosticKind::Note:
487+
return set(Behavior::Note);
488+
}
489+
}
490+
452491
void DiagnosticEngine::flushActiveDiagnostic() {
453492
assert(ActiveDiagnostic && "No active diagnostic to flush");
454493
if (TransactionCount == 0) {
@@ -467,34 +506,13 @@ void DiagnosticEngine::emitTentativeDiagnostics() {
467506
}
468507

469508
void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) {
509+
auto behavior = state.getBehavior(diagnostic);
510+
if (behavior == DiagnosticState::Behavior::Ignore)
511+
return;
512+
470513
const StoredDiagnosticInfo &StoredInfo
471514
= StoredDiagnosticInfos[(unsigned)diagnostic.getID()];
472515

473-
if (FatalState != FatalErrorState::None) {
474-
bool shouldIgnore = true;
475-
if (StoredInfo.Kind == DiagnosticKind::Note)
476-
shouldIgnore = (FatalState == FatalErrorState::Fatal);
477-
else
478-
FatalState = FatalErrorState::Fatal;
479-
480-
if (shouldIgnore && !ShowDiagnosticsAfterFatalError) {
481-
return;
482-
}
483-
}
484-
485-
// Check whether this is an error.
486-
switch (StoredInfo.Kind) {
487-
case DiagnosticKind::Error:
488-
HadAnyError = true;
489-
if (isDiagnosticFatal(diagnostic.getID()))
490-
FatalState = FatalErrorState::JustEmitted;
491-
break;
492-
493-
case DiagnosticKind::Note:
494-
case DiagnosticKind::Warning:
495-
break;
496-
}
497-
498516
// Figure out the source location.
499517
SourceLoc loc = diagnostic.getLoc();
500518
if (loc.isInvalid() && diagnostic.getDecl()) {

0 commit comments

Comments
 (0)