@@ -5,11 +5,15 @@ pub(crate) mod ast;
55pub ( crate ) mod hir;
66
77use self :: { ast:: run_ast_lints, hir:: run_hir_lints} ;
8- use crate :: lints:: { ast:: AstLint , hir:: HirLint } ;
8+ use crate :: {
9+ lints:: { ast:: AstLint , hir:: HirLint } ,
10+ GroupConfig ,
11+ } ;
912use miette:: { Diagnostic , LabeledSpan } ;
1013use qsc_data_structures:: span:: Span ;
1114use qsc_frontend:: compile:: { CompileUnit , PackageStore } ;
1215use qsc_hir:: hir:: { Item , ItemId } ;
16+ use rustc_hash:: FxHashMap ;
1317use serde:: { Deserialize , Serialize } ;
1418use std:: fmt:: Display ;
1519
@@ -19,7 +23,7 @@ use std::fmt::Display;
1923pub fn run_lints (
2024 package_store : & PackageStore ,
2125 compile_unit : & CompileUnit ,
22- config : Option < & [ LintConfig ] > ,
26+ config : Option < & [ LintOrGroupConfig ] > ,
2327) -> Vec < Lint > {
2428 let mut lints = run_lints_without_deduplication ( package_store, compile_unit, config) ;
2529 remove_duplicates ( & mut lints) ;
@@ -33,22 +37,61 @@ pub fn run_lints(
3337pub ( crate ) fn run_lints_without_deduplication (
3438 package_store : & PackageStore ,
3539 compile_unit : & CompileUnit ,
36- config : Option < & [ LintConfig ] > ,
40+ config : Option < & [ LintOrGroupConfig ] > ,
3741) -> Vec < Lint > {
3842 let compilation = Compilation {
3943 package_store,
4044 compile_unit,
4145 } ;
4246
43- let mut ast_lints = run_ast_lints ( & compile_unit. ast . package , config, compilation) ;
44- let mut hir_lints = run_hir_lints ( & compile_unit. package , config, compilation) ;
47+ let unfolded_config = config. map ( unfold_groups) ;
48+
49+ let mut ast_lints = run_ast_lints (
50+ & compile_unit. ast . package ,
51+ unfolded_config. as_deref ( ) ,
52+ compilation,
53+ ) ;
54+ let mut hir_lints = run_hir_lints (
55+ & compile_unit. package ,
56+ unfolded_config. as_deref ( ) ,
57+ compilation,
58+ ) ;
4559
4660 let mut lints = Vec :: new ( ) ;
4761 lints. append ( & mut ast_lints) ;
4862 lints. append ( & mut hir_lints) ;
4963 lints
5064}
5165
66+ /// Unfolds groups into lists of lints. Specific lints override group configs.
67+ pub ( crate ) fn unfold_groups ( config : & [ LintOrGroupConfig ] ) -> Vec < LintConfig > {
68+ let mut config_map: FxHashMap < LintKind , LintLevel > = FxHashMap :: default ( ) ;
69+
70+ // Unfold groups in the order they appear.
71+ for elt in config {
72+ if let LintOrGroupConfig :: Group ( group) = elt {
73+ for lint in group. lint_group . unfold ( ) {
74+ config_map. insert ( lint, group. level ) ;
75+ }
76+ }
77+ }
78+
79+ // Specific lints override group configs.
80+ for elt in config {
81+ if let LintOrGroupConfig :: Lint ( lint) = elt {
82+ config_map. insert ( lint. kind , lint. level ) ;
83+ }
84+ }
85+
86+ config_map
87+ . iter ( )
88+ . map ( |( kind, level) | LintConfig {
89+ kind : * kind,
90+ level : * level,
91+ } )
92+ . collect ( )
93+ }
94+
5295pub ( crate ) fn remove_duplicates < T : Eq + std:: hash:: Hash + Clone > ( vec : & mut Vec < T > ) {
5396 let mut seen = rustc_hash:: FxHashSet :: default ( ) ;
5497 vec. retain ( |x| seen. insert ( x. clone ( ) ) ) ;
@@ -211,11 +254,21 @@ impl Display for LintLevel {
211254 }
212255}
213256
214- /// End-user configuration for each lint level.
257+ /// End-user configuration for a specific lint or a lint group.
258+ #[ derive( Debug , Clone , Deserialize , Serialize , PartialEq , Eq ) ]
259+ #[ serde( untagged) ]
260+ pub enum LintOrGroupConfig {
261+ /// An specific lint configuration.
262+ Lint ( LintConfig ) ,
263+ /// A lint group configuration.
264+ Group ( GroupConfig ) ,
265+ }
266+
267+ /// End-user configuration for a specific lint.
215268#[ derive( Debug , Clone , Deserialize , Serialize , PartialEq , Eq ) ]
216269pub struct LintConfig {
217270 #[ serde( rename = "lint" ) ]
218- /// Represents the lint name.
271+ /// The lint name.
219272 pub kind : LintKind ,
220273 /// The lint level.
221274 pub level : LintLevel ,
0 commit comments