2121#include " swift/AST/DeclNameLoc.h"
2222#include " swift/AST/DiagnosticArgument.h"
2323#include " swift/AST/DiagnosticConsumer.h"
24+ #include " swift/AST/DiagnosticGroups.h"
2425#include " swift/AST/TypeLoc.h"
2526#include " swift/Basic/PrintDiagnosticNamesMode.h"
2627#include " swift/Basic/Statistic.h"
2728#include " swift/Basic/Version.h"
28- #include " swift/Basic/WarningAsErrorRule .h"
29+ #include " swift/Basic/WarningGroupBehaviorRule .h"
2930#include " swift/Localization/LocalizationFormat.h"
3031#include " llvm/ADT/BitVector.h"
32+ #include " llvm/ADT/MapVector.h"
3133#include " llvm/ADT/StringRef.h"
3234#include " llvm/ADT/StringSet.h"
3335#include " llvm/Support/Allocator.h"
@@ -612,6 +614,10 @@ namespace swift {
612614 ArrayRef<DiagnosticArgument> Args);
613615 };
614616
617+
618+ using WarningGroupBehaviorMap =
619+ llvm::MapVector<swift::DiagGroupID, WarningGroupBehaviorRule>;
620+
615621 // / Class to track, map, and remap diagnostic severity and fatality
616622 // /
617623 class DiagnosticState {
@@ -628,13 +634,13 @@ namespace swift {
628634 // / Don't emit any remarks
629635 bool suppressRemarks = false ;
630636
631- // / A mapping from `DiagGroupID` identifiers to Boolean values indicating
632- // / whether warnings belonging to the respective diagnostic groups should be
633- // / escalated to errors.
634- llvm::BitVector warningsAsErrors;
635-
636- // / Track which diagnostic group (`DiagGroupID`) warnings should be ignored .
637- llvm::BitVector ignoredDiagnosticGroups ;
637+ // / A mapping from `DiagGroupID` identifiers to `WarningGroupBehaviorRule`
638+ // / values indicating how warnings belonging to the respective diagnostic groups
639+ // / should be emitted. While there is duplication between this data structure
640+ // / being a map keyed with `DiagGroupID` and containing a rule object which also
641+ // / contains a matching `DiagGroupID`, this significantly simplifies bridging
642+ // / values of this map to Swift clients .
643+ WarningGroupBehaviorMap warningGroupBehaviorMap ;
638644
639645 // / For compiler-internal purposes only, track which diagnostics should
640646 // / be ignored completely. For example, this is used by LLDB to
@@ -657,7 +663,8 @@ namespace swift {
657663
658664 // / Figure out the Behavior for the given diagnostic, taking current
659665 // / state such as fatality into account.
660- DiagnosticBehavior determineBehavior (const Diagnostic &diag) const ;
666+ DiagnosticBehavior determineBehavior (const Diagnostic &diag,
667+ SourceManager &sourceMgr) const ;
661668
662669 // / Updates the diagnostic state for a diagnostic to emit.
663670 void updateFor (DiagnosticBehavior behavior);
@@ -684,45 +691,37 @@ namespace swift {
684691 void setSuppressRemarks (bool val) { suppressRemarks = val; }
685692 bool getSuppressRemarks () const { return suppressRemarks; }
686693
687- // / Sets whether warnings belonging to the diagnostic group identified by
688- // / `id` should be escalated to errors.
689- void setWarningsAsErrorsForDiagGroupID (DiagGroupID id, bool value) {
690- warningsAsErrors[(unsigned )id] = value;
694+ // / Configure the command-line warning group handling
695+ // / rules (`-Werrr`,`-Wwarning`,`-warnings-as-errors`)
696+ void setWarningGroupControlRules (
697+ const llvm::SmallVector<WarningGroupBehaviorRule, 4 > &rules);
698+
699+ // / Add an individual command-line warning group behavior
700+ void addWarningGroupControl (const DiagGroupID &groupID,
701+ WarningGroupBehavior behavior) {
702+ warningGroupBehaviorMap.insert_or_assign (
703+ groupID, WarningGroupBehaviorRule (behavior, groupID));
691704 }
692705
693- // / Returns a Boolean value indicating whether warnings belonging to the
694- // / diagnostic group identified by `id` should be escalated to errors.
695- bool getWarningsAsErrorsForDiagGroupID (DiagGroupID id) const {
696- return warningsAsErrors[(unsigned )id];
706+ const WarningGroupBehaviorMap&
707+ getWarningGroupBehaviorControlMap () const {
708+ return warningGroupBehaviorMap;
697709 }
698710
699- // / Whether all warnings should be upgraded to errors or not.
700- void setAllWarningsAsErrors (bool value) {
701- // This works as intended because every diagnostic belongs to either a
702- // custom group or the top-level `DiagGroupID::no_group`, which is also
703- // a group.
704- if (value) {
705- warningsAsErrors.set ();
706- } else {
707- warningsAsErrors.reset ();
708- }
711+ const std::vector<const WarningGroupBehaviorRule*>
712+ getWarningGroupBehaviorControlRefArray () const {
713+ std::vector<const WarningGroupBehaviorRule*> ruleRefArray;
714+ ruleRefArray.reserve (warningGroupBehaviorMap.size ());
715+ for (const auto &rule: warningGroupBehaviorMap)
716+ ruleRefArray.push_back (&rule.second );
717+ return ruleRefArray;
709718 }
710719
711720 void resetHadAnyError () {
712721 anyErrorOccurred = false ;
713722 fatalErrorOccurred = false ;
714723 }
715724
716- // / Set whether a diagnostic group should be ignored.
717- void setIgnoredDiagnosticGroup (DiagGroupID id, bool ignored) {
718- ignoredDiagnosticGroups[(unsigned )id] = ignored;
719- }
720-
721- // / Query whether a specific diagnostic group is ignored.
722- bool isIgnoredDiagnosticGroup (DiagGroupID id) const {
723- return ignoredDiagnosticGroups[(unsigned )id];
724- }
725-
726725 // / Set a specific diagnostic to be ignored by the compiler.
727726 void compilerInternalIgnoreDiagnostic (DiagID id) {
728727 compilerIgnoredDiagnostics[(unsigned )id] = true ;
@@ -738,11 +737,10 @@ namespace swift {
738737 std::swap (suppressWarnings, other.suppressWarnings );
739738 std::swap (suppressNotes, other.suppressNotes );
740739 std::swap (suppressRemarks, other.suppressRemarks );
741- std::swap (warningsAsErrors , other.warningsAsErrors );
740+ std::swap (warningGroupBehaviorMap , other.warningGroupBehaviorMap );
742741 std::swap (fatalErrorOccurred, other.fatalErrorOccurred );
743742 std::swap (anyErrorOccurred, other.anyErrorOccurred );
744743 std::swap (previousBehavior, other.previousBehavior );
745- std::swap (ignoredDiagnosticGroups, other.ignoredDiagnosticGroups );
746744 }
747745
748746 private:
@@ -752,6 +750,13 @@ namespace swift {
752750
753751 DiagnosticState (DiagnosticState &&) = default ;
754752 DiagnosticState &operator =(DiagnosticState &&) = default ;
753+
754+ // / If this diagnostic is a warning belonging to a diagnostic group,
755+ // / figure out if there is a source-level (`@warn`) control for this group
756+ // / for this diagnostic's source location.
757+ std::optional<DiagnosticBehavior>
758+ determineUserControlledWarningBehavior (const Diagnostic &diag,
759+ SourceManager &sourceMgr) const ;
755760 };
756761
757762 // / A lightweight reference to a diagnostic that's been fully applied to
@@ -951,7 +956,20 @@ namespace swift {
951956 // / Rules are applied in order they appear in the vector.
952957 // / In case the vector contains rules affecting the same diagnostic ID
953958 // / the last rule wins.
954- void setWarningsAsErrorsRules (const std::vector<WarningAsErrorRule> &rules);
959+ void setWarningGroupControlRules (
960+ const llvm::SmallVector<WarningGroupBehaviorRule, 4 > &rules) {
961+ state.setWarningGroupControlRules (rules);
962+ }
963+
964+ const WarningGroupBehaviorMap&
965+ getWarningGroupBehaviorControlMap () const {
966+ return state.getWarningGroupBehaviorControlMap ();
967+ }
968+
969+ const std::vector<const WarningGroupBehaviorRule*>
970+ getWarningGroupBehaviorControlRefArray () const {
971+ return state.getWarningGroupBehaviorControlRefArray ();
972+ }
955973
956974 // / Whether to print diagnostic names after their messages
957975 void setPrintDiagnosticNamesMode (PrintDiagnosticNamesMode val) {
@@ -982,13 +1000,9 @@ namespace swift {
9821000 localization = diag::LocalizationProducer::producerFor (locale, path);
9831001 }
9841002
985- bool isIgnoredDiagnosticGroup (DiagGroupID id) const {
986- return state.isIgnoredDiagnosticGroup (id);
987- }
988-
989- bool isIgnoredDiagnosticGroupTree (DiagGroupID id) const {
990- return state.isIgnoredDiagnosticGroupTree (id);
991- }
1003+ // / Whether the specified SourceFile enables a given diagnostic group
1004+ // / either syntactically, or via command-line flags.
1005+ bool isDiagnosticGroupEnabled (SourceFile *sf, DiagGroupID groupID) const ;
9921006
9931007 void ignoreDiagnostic (DiagID id) {
9941008 state.compilerInternalIgnoreDiagnostic (id);
@@ -1366,7 +1380,8 @@ namespace swift {
13661380 Engine.TentativeDiagnostics .end ());
13671381
13681382 for (auto &diagnostic : diagnostics) {
1369- auto behavior = Engine.state .determineBehavior (diagnostic.Diag );
1383+ auto behavior = Engine.state .determineBehavior (diagnostic.Diag ,
1384+ Engine.SourceMgr );
13701385 if (behavior == DiagnosticBehavior::Fatal ||
13711386 behavior == DiagnosticBehavior::Error)
13721387 return true ;
0 commit comments