@@ -4,142 +4,103 @@ use rustc_data_structures::fx::FxHashSet;
44use rustc_errors:: Applicability ;
55use rustc_lint:: { LateContext , unerased_lint_store} ;
66use rustc_span:: { BytePos , Pos , SourceFile , Span , SyntaxContext } ;
7- use serde:: { Deserialize , Serialize } ;
8- use std:: collections:: BTreeMap ;
97use std:: ops:: Range ;
108use std:: path:: Path ;
119use toml:: Spanned ;
10+ use toml:: de:: { DeTable , DeValue } ;
1211
13- #[ derive( Deserialize , Serialize , Debug ) ]
14- struct LintConfigTable {
15- level : String ,
16- priority : Option < i64 > ,
12+ fn toml_span ( range : Range < usize > , file : & SourceFile ) -> Span {
13+ Span :: new (
14+ file. start_pos + BytePos :: from_usize ( range. start ) ,
15+ file. start_pos + BytePos :: from_usize ( range. end ) ,
16+ SyntaxContext :: root ( ) ,
17+ None ,
18+ )
1719}
1820
19- #[ derive( Deserialize , Debug ) ]
20- #[ serde( untagged) ]
21- enum LintConfig {
22- Level ( String ) ,
23- Table ( LintConfigTable ) ,
21+ struct LintConfig < ' a > {
22+ sp : Range < usize > ,
23+ level : & ' a str ,
24+ priority : Option < i64 > ,
2425}
25-
26- impl LintConfig {
27- fn level ( & self ) -> & str {
28- match self {
29- LintConfig :: Level ( level) => level,
30- LintConfig :: Table ( table) => & table. level ,
31- }
32- }
33-
26+ impl < ' a > LintConfig < ' a > {
3427 fn priority ( & self ) -> i64 {
35- match self {
36- LintConfig :: Level ( _) => 0 ,
37- LintConfig :: Table ( table) => table. priority . unwrap_or ( 0 ) ,
38- }
28+ self . priority . unwrap_or ( 0 )
3929 }
4030
4131 fn is_implicit ( & self ) -> bool {
42- if let LintConfig :: Table ( table) = self {
43- table. priority . is_none ( )
44- } else {
45- true
46- }
32+ self . priority . is_none ( )
4733 }
48- }
49-
50- type LintTable = BTreeMap < Spanned < String > , Spanned < LintConfig > > ;
51-
52- #[ derive( Deserialize , Debug , Default ) ]
53- struct Lints {
54- #[ serde( default ) ]
55- rust : LintTable ,
56- #[ serde( default ) ]
57- clippy : LintTable ,
58- }
59-
60- #[ derive( Deserialize , Debug , Default ) ]
61- struct Workspace {
62- #[ serde( default ) ]
63- lints : Lints ,
64- }
6534
66- #[ derive( Deserialize , Debug ) ]
67- struct CargoToml {
68- #[ serde( default ) ]
69- lints : Lints ,
70- #[ serde( default ) ]
71- workspace : Workspace ,
72- }
73-
74- fn toml_span ( range : Range < usize > , file : & SourceFile ) -> Span {
75- Span :: new (
76- file. start_pos + BytePos :: from_usize ( range. start ) ,
77- file. start_pos + BytePos :: from_usize ( range. end ) ,
78- SyntaxContext :: root ( ) ,
79- None ,
80- )
35+ fn parse ( value : & ' a Spanned < DeValue < ' a > > ) -> Option < Self > {
36+ let sp = value. span ( ) ;
37+ let ( level, priority) = match value. get_ref ( ) {
38+ DeValue :: String ( level) => ( & * * level, None ) ,
39+ DeValue :: Table ( tbl) => {
40+ let level = tbl. get ( "level" ) ?. get_ref ( ) . as_str ( ) ?;
41+ let priority = if let Some ( priority) = tbl. get ( "priority" ) {
42+ let priority = priority. get_ref ( ) . as_integer ( ) ?;
43+ Some ( i64:: from_str_radix ( priority. as_str ( ) , priority. radix ( ) ) . ok ( ) ?)
44+ } else {
45+ None
46+ } ;
47+ ( level, priority)
48+ } ,
49+ _ => return None ,
50+ } ;
51+ Some ( Self { sp, level, priority } )
52+ }
8153}
8254
83- fn check_table ( cx : & LateContext < ' _ > , table : LintTable , known_groups : & FxHashSet < & str > , file : & SourceFile ) {
55+ fn check_table ( cx : & LateContext < ' _ > , table : & DeTable < ' _ > , known_groups : & FxHashSet < & str > , file : & SourceFile ) {
8456 let mut lints = Vec :: new ( ) ;
8557 let mut groups = Vec :: new ( ) ;
8658 for ( name, config) in table {
87- if name. get_ref ( ) == "warnings" {
88- continue ;
89- }
90-
91- if known_groups . contains ( name . get_ref ( ) . as_str ( ) ) {
92- groups . push ( ( name , config ) ) ;
93- } else {
94- lints . push ( ( name , config . into_inner ( ) ) ) ;
59+ if name. get_ref ( ) != "warnings"
60+ && let Some ( config ) = LintConfig :: parse ( config )
61+ {
62+ if known_groups . contains ( & * * name . get_ref ( ) ) {
63+ groups . push ( ( name , config ) ) ;
64+ } else {
65+ lints . push ( ( name , config ) ) ;
66+ }
9567 }
9668 }
9769
9870 for ( group, group_config) in groups {
99- let priority = group_config. get_ref ( ) . priority ( ) ;
100- let level = group_config. get_ref ( ) . level ( ) ;
101- if let Some ( ( conflict, _) ) = lints
102- . iter ( )
103- . rfind ( |( _, lint_config) | lint_config. priority ( ) == priority && lint_config. level ( ) != level)
104- {
71+ if let Some ( ( conflict, _) ) = lints. iter ( ) . rfind ( |( _, lint_config) | {
72+ lint_config. priority ( ) == group_config. priority ( ) && lint_config. level != group_config. level
73+ } ) {
10574 span_lint_and_then (
10675 cx,
10776 LINT_GROUPS_PRIORITY ,
10877 toml_span ( group. span ( ) , file) ,
10978 format ! (
110- "lint group `{}` has the same priority ({priority}) as a lint" ,
111- group. as_ref( )
79+ "lint group `{}` has the same priority ({}) as a lint" ,
80+ group. as_ref( ) ,
81+ group_config. priority( ) ,
11282 ) ,
11383 |diag| {
114- let config_span = toml_span ( group_config. span ( ) , file) ;
84+ let config_span = toml_span ( group_config. sp . clone ( ) , file) ;
11585
116- if group_config. as_ref ( ) . is_implicit ( ) {
86+ if group_config. is_implicit ( ) {
11787 diag. span_label ( config_span, "has an implicit priority of 0" ) ;
11888 }
11989 diag. span_label ( toml_span ( conflict. span ( ) , file) , "has the same priority as this lint" ) ;
12090 diag. note ( "the order of the lints in the table is ignored by Cargo" ) ;
12191
122- let mut suggestion = String :: new ( ) ;
12392 let low_priority = lints
12493 . iter ( )
125- . map ( |( _, config ) | config . priority ( ) . saturating_sub ( 1 ) )
94+ . map ( |( _, lint_config ) | lint_config . priority ( ) . saturating_sub ( 1 ) )
12695 . min ( )
12796 . unwrap_or ( -1 ) ;
128- Serialize :: serialize (
129- & LintConfigTable {
130- level : level. into ( ) ,
131- priority : Some ( low_priority) ,
132- } ,
133- toml:: ser:: ValueSerializer :: new ( & mut suggestion) ,
134- )
135- . unwrap ( ) ;
13697 diag. span_suggestion_verbose (
13798 config_span,
13899 format ! (
139100 "to have lints override the group set `{}` to a lower priority" ,
140101 group. as_ref( )
141102 ) ,
142- suggestion ,
103+ format ! ( "{{ level = {:?}, priority = {low_priority} }}" , group_config . level , ) ,
143104 Applicability :: MaybeIncorrect ,
144105 ) ;
145106 } ,
@@ -148,10 +109,29 @@ fn check_table(cx: &LateContext<'_>, table: LintTable, known_groups: &FxHashSet<
148109 }
149110}
150111
112+ struct LintTbls < ' a > {
113+ rust : Option < & ' a DeTable < ' a > > ,
114+ clippy : Option < & ' a DeTable < ' a > > ,
115+ }
116+ fn get_lint_tbls < ' a > ( tbl : & ' a DeTable < ' a > ) -> LintTbls < ' a > {
117+ if let Some ( lints) = tbl. get ( "lints" )
118+ && let Some ( lints) = lints. get_ref ( ) . as_table ( )
119+ {
120+ let rust = lints. get ( "rust" ) . and_then ( |x| x. get_ref ( ) . as_table ( ) ) ;
121+ let clippy = lints. get ( "clippy" ) . and_then ( |x| x. get_ref ( ) . as_table ( ) ) ;
122+ LintTbls { rust, clippy }
123+ } else {
124+ LintTbls {
125+ rust : None ,
126+ clippy : None ,
127+ }
128+ }
129+ }
130+
151131pub fn check ( cx : & LateContext < ' _ > ) {
152132 if let Ok ( file) = cx. tcx . sess . source_map ( ) . load_file ( Path :: new ( "Cargo.toml" ) )
153133 && let Some ( src) = file. src . as_deref ( )
154- && let Ok ( cargo_toml) = toml :: from_str :: < CargoToml > ( src)
134+ && let Ok ( cargo_toml) = DeTable :: parse ( src)
155135 {
156136 let mut rustc_groups = FxHashSet :: default ( ) ;
157137 let mut clippy_groups = FxHashSet :: default ( ) ;
@@ -167,9 +147,23 @@ pub fn check(cx: &LateContext<'_>) {
167147 }
168148 }
169149
170- check_table ( cx, cargo_toml. lints . rust , & rustc_groups, & file) ;
171- check_table ( cx, cargo_toml. lints . clippy , & clippy_groups, & file) ;
172- check_table ( cx, cargo_toml. workspace . lints . rust , & rustc_groups, & file) ;
173- check_table ( cx, cargo_toml. workspace . lints . clippy , & clippy_groups, & file) ;
150+ let lints = get_lint_tbls ( cargo_toml. get_ref ( ) ) ;
151+ if let Some ( lints) = lints. rust {
152+ check_table ( cx, lints, & rustc_groups, & file) ;
153+ }
154+ if let Some ( lints) = lints. clippy {
155+ check_table ( cx, lints, & clippy_groups, & file) ;
156+ }
157+ if let Some ( tbl) = cargo_toml. get_ref ( ) . get ( "workspace" )
158+ && let Some ( tbl) = tbl. get_ref ( ) . as_table ( )
159+ {
160+ let lints = get_lint_tbls ( tbl) ;
161+ if let Some ( lints) = lints. rust {
162+ check_table ( cx, lints, & rustc_groups, & file) ;
163+ }
164+ if let Some ( lints) = lints. clippy {
165+ check_table ( cx, lints, & clippy_groups, & file) ;
166+ }
167+ }
174168 }
175169}
0 commit comments