Skip to content

Commit d282fd7

Browse files
committed
Allow suppressing individual diagnostics.
Extend DiagnosticState to track per-diagnostic desired behaviors, allowing users of the APIs to individually suppress diagnostics.
1 parent 411e2a1 commit d282fd7

File tree

2 files changed

+84
-55
lines changed

2 files changed

+84
-55
lines changed

include/swift/AST/DiagnosticEngine.h

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ namespace swift {
384384
class DiagnosticState {
385385
public:
386386
/// \brief Describes the current behavior to take with a diagnostic
387-
enum class Behavior {
387+
enum class Behavior : uint8_t {
388388
Unspecified,
389389
Ignore,
390390
Note,
@@ -410,11 +410,15 @@ namespace swift {
410410
/// \brief Track the previous emitted Behavior, useful for notes
411411
Behavior previousBehavior = Behavior::Unspecified;
412412

413+
/// \brief Track settable, per-diagnostic state that we store
414+
std::vector<Behavior> perDiagnosticState;
415+
413416
public:
414-
DiagnosticState() {}
417+
DiagnosticState();
415418

416-
/// \brief Figure out the Behavior for the given diagnostic
417-
Behavior getBehavior(const Diagnostic &);
419+
/// \brief Figure out the Behavior for the given diagnostic, taking current
420+
/// state such as fatality into account.
421+
Behavior determineBehavior(DiagID);
418422

419423
bool hadAnyError() const { return anyErrorOccurred; }
420424
bool hasFatalErrorOccurred() const { return fatalErrorOccurred; }
@@ -432,10 +436,12 @@ namespace swift {
432436
fatalErrorOccurred = false;
433437
}
434438

435-
private:
436-
/// \returns true if diagnostic is marked as fatal.
437-
bool isDiagnosticFatal(DiagID ID) const;
439+
/// Set per-diagnostic behavior
440+
void setDiagnosticBehavior(DiagID id, Behavior behavior) {
441+
perDiagnosticState[(unsigned)id] = behavior;
442+
}
438443

444+
private:
439445
// Make the state movable only
440446
DiagnosticState(const DiagnosticState &) = delete;
441447
const DiagnosticState &operator=(const DiagnosticState &) = delete;
@@ -497,6 +503,10 @@ namespace swift {
497503
return state.getIgnoreAllWarnings();
498504
}
499505

506+
void ignoreDiagnostic(DiagID id) {
507+
state.setDiagnosticBehavior(id, DiagnosticState::Behavior::Ignore);
508+
}
509+
500510
void resetHadAnyError() {
501511
state.resetHadAnyError();
502512
}

lib/AST/DiagnosticEngine.cpp

Lines changed: 67 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@
2828
#include "llvm/ADT/SmallString.h"
2929
#include "llvm/ADT/Twine.h"
3030
#include "llvm/Support/raw_ostream.h"
31+
3132
using namespace swift;
3233

34+
namespace {
3335
enum class DiagnosticOptions {
3436
/// No options.
3537
none,
@@ -46,29 +48,48 @@ enum class DiagnosticOptions {
4648
Fatal,
4749
};
4850

49-
struct StoredDiagnosticInfo {
50-
/// \brief The kind of diagnostic we're dealing with.
51-
DiagnosticKind Kind;
52-
53-
DiagnosticOptions Options;
51+
// Reproduce the DiagIDs, as we want both the size and access to the raw ids
52+
// themselves.
53+
enum LocalDiagID : uint32_t {
54+
#define DIAG(KIND, ID, Category, Options, Text, Signature) ID,
55+
#include "swift/AST/DiagnosticsAll.def"
56+
NumDiags
57+
};
58+
}
5459

55-
// FIXME: Category
56-
57-
/// \brief Text associated with the diagnostic
58-
const char *Text;
60+
static const char *DiagnosticStrings[] = {
61+
#define ERROR(ID, Category, Options, Text, Signature) Text,
62+
#define WARNING(ID, Category, Options, Text, Signature) Text,
63+
#define NOTE(ID, Category, Options, Text, Signature) Text,
64+
#include "swift/AST/DiagnosticsAll.def"
65+
"<not a diagnostic>",
5966
};
6067

61-
static StoredDiagnosticInfo StoredDiagnosticInfos[] = {
62-
#define ERROR(ID,Category,Options,Text,Signature) \
63-
{ DiagnosticKind::Error, DiagnosticOptions::Options, Text },
64-
#define WARNING(ID,Category,Options,Text,Signature) \
65-
{ DiagnosticKind::Warning, DiagnosticOptions::Options, Text },
66-
#define NOTE(ID,Category,Options,Text,Signature) \
67-
{ DiagnosticKind::Note, DiagnosticOptions::Options, Text },
68+
static bool DiagnosticPointsToFirstBadToken[] = {
69+
#define ERROR(ID, Category, Options, Text, Signature) \
70+
DiagnosticOptions::Options == DiagnosticOptions::PointsToFirstBadToken,
71+
#define WARNING(ID, Category, Options, Text, Signature) \
72+
DiagnosticOptions::Options == DiagnosticOptions::PointsToFirstBadToken,
73+
#define NOTE(ID, Category, Options, Text, Signature) \
74+
DiagnosticOptions::Options == DiagnosticOptions::PointsToFirstBadToken,
6875
#include "swift/AST/DiagnosticsAll.def"
69-
{ DiagnosticKind::Error, DiagnosticOptions::none, "<not a diagnostic>" }
76+
"<not a diagnostic>",
7077
};
7178

79+
DiagnosticState::DiagnosticState() {
80+
// Initialize our per-diagnostic state to the default
81+
perDiagnosticState.resize(LocalDiagID::NumDiags);
82+
#define ERROR(ID, Category, Options, Text, Signature) \
83+
perDiagnosticState[LocalDiagID::ID] = \
84+
DiagnosticOptions::Options == DiagnosticOptions::Fatal ? Behavior::Fatal \
85+
: Behavior::Err;
86+
#define WARNING(ID, Category, Options, Text, Signature) \
87+
perDiagnosticState[LocalDiagID::ID] = Behavior::Warn;
88+
#define NOTE(ID, Category, Options, Text, Signature) \
89+
perDiagnosticState[LocalDiagID::ID] = Behavior::Note;
90+
#include "swift/AST/DiagnosticsAll.def"
91+
}
92+
7293
static CharSourceRange toCharSourceRange(SourceManager &SM, SourceRange SR) {
7394
return CharSourceRange(SM, SR.Start, Lexer::getLocForEndOfToken(SM, SR.End));
7495
}
@@ -175,15 +196,7 @@ void InFlightDiagnostic::flush() {
175196
}
176197

177198
bool DiagnosticEngine::isDiagnosticPointsToFirstBadToken(DiagID ID) const {
178-
const StoredDiagnosticInfo &StoredInfo =
179-
StoredDiagnosticInfos[(unsigned) ID];
180-
return StoredInfo.Options == DiagnosticOptions::PointsToFirstBadToken;
181-
}
182-
183-
bool DiagnosticState::isDiagnosticFatal(DiagID ID) const {
184-
const StoredDiagnosticInfo &StoredInfo =
185-
StoredDiagnosticInfos[(unsigned) ID];
186-
return StoredInfo.Options == DiagnosticOptions::Fatal;
199+
return DiagnosticPointsToFirstBadToken[(unsigned)ID];
187200
}
188201

189202
/// \brief Skip forward to one of the given delimiters.
@@ -443,13 +456,29 @@ static void formatDiagnosticText(StringRef InText,
443456
(void)Result;
444457
assert(ArgIndex < Args.size() && "Out-of-range argument index");
445458
InText = InText.substr(Length);
446-
459+
447460
// Convert the argument to a string.
448461
formatDiagnosticArgument(Modifier, ModifierArguments, Args, ArgIndex, Out);
449462
}
450463
}
451464

452-
DiagnosticState::Behavior DiagnosticState::getBehavior(const Diagnostic &diag) {
465+
static DiagnosticKind toDiagnosticKind(DiagnosticState::Behavior behavior) {
466+
switch (behavior) {
467+
case DiagnosticState::Behavior::Unspecified:
468+
llvm_unreachable("unspecified behavior");
469+
case DiagnosticState::Behavior::Ignore:
470+
llvm_unreachable("trying to map an ignored diagnostic");
471+
case DiagnosticState::Behavior::Err:
472+
case DiagnosticState::Behavior::Fatal:
473+
return DiagnosticKind::Error;
474+
case DiagnosticState::Behavior::Note:
475+
return DiagnosticKind::Note;
476+
case DiagnosticState::Behavior::Warn:
477+
return DiagnosticKind::Warning;
478+
}
479+
}
480+
481+
DiagnosticState::Behavior DiagnosticState::determineBehavior(DiagID id) {
453482
auto set = [this](DiagnosticState::Behavior lvl) {
454483
if (lvl == Behavior::Fatal) {
455484
fatalErrorOccurred = true;
@@ -462,33 +491,26 @@ DiagnosticState::Behavior DiagnosticState::getBehavior(const Diagnostic &diag) {
462491
return lvl;
463492
};
464493

465-
auto diagKind = StoredDiagnosticInfos[(unsigned)diag.getID()].Kind;
494+
auto behavior = perDiagnosticState[(unsigned)id];
466495

467496
// Notes relating to ignored diagnostics should also be ignored
468-
if (previousBehavior == Behavior::Ignore && diagKind == DiagnosticKind::Note)
497+
if (previousBehavior == Behavior::Ignore && behavior == Behavior::Note)
469498
return set(Behavior::Ignore);
470499

471500
// Suppress diagnostics when in a fatal state, except for follow-on notes
472501
// about the original fatal diag
473502
if (fatalErrorOccurred) {
474503
bool emitAnyways = showDiagnosticsAfterFatalError ||
475-
(diagKind == DiagnosticKind::Note &&
504+
(behavior == Behavior::Note &&
476505
previousBehavior != Behavior::Ignore);
477506
if (!emitAnyways)
478507
return set(Behavior::Ignore);
479-
} else if (isDiagnosticFatal(diag.getID())) {
480-
return set(Behavior::Fatal);
481508
}
482509

483-
// Re-map as appropriate
484-
switch (diagKind) {
485-
case DiagnosticKind::Error:
486-
return set(Behavior::Err);
487-
case DiagnosticKind::Warning:
488-
return set(ignoreAllWarnings ? Behavior::Ignore : Behavior::Warn);
489-
case DiagnosticKind::Note:
490-
return set(Behavior::Note);
491-
}
510+
if (behavior == Behavior::Warn && ignoreAllWarnings)
511+
return set(Behavior::Ignore);
512+
513+
return set(behavior);
492514
}
493515

494516
void DiagnosticEngine::flushActiveDiagnostic() {
@@ -509,13 +531,10 @@ void DiagnosticEngine::emitTentativeDiagnostics() {
509531
}
510532

511533
void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) {
512-
auto behavior = state.getBehavior(diagnostic);
534+
auto behavior = state.determineBehavior(diagnostic.getID());
513535
if (behavior == DiagnosticState::Behavior::Ignore)
514536
return;
515537

516-
const StoredDiagnosticInfo &StoredInfo
517-
= StoredDiagnosticInfos[(unsigned)diagnostic.getID()];
518-
519538
// Figure out the source location.
520539
SourceLoc loc = diagnostic.getLoc();
521540
if (loc.isInvalid() && diagnostic.getDecl()) {
@@ -634,7 +653,7 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) {
634653
llvm::SmallString<256> Text;
635654
{
636655
llvm::raw_svector_ostream Out(Text);
637-
formatDiagnosticText(StoredInfo.Text, diagnostic.getArgs(), Out);
656+
formatDiagnosticText(DiagnosticStrings[(unsigned)diagnostic.getID()], diagnostic.getArgs(), Out);
638657
}
639658

640659
// Pass the diagnostic off to the consumer.
@@ -643,7 +662,7 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) {
643662
Info.Ranges = diagnostic.getRanges();
644663
Info.FixIts = diagnostic.getFixIts();
645664
for (auto &Consumer : Consumers) {
646-
Consumer->handleDiagnostic(SourceMgr, loc, StoredInfo.Kind, Text, Info);
665+
Consumer->handleDiagnostic(SourceMgr, loc, toDiagnosticKind(behavior), Text, Info);
647666
}
648667
}
649668

0 commit comments

Comments
 (0)