@@ -4,142 +4,103 @@ use rustc_data_structures::fx::FxHashSet;
4
4
use rustc_errors:: Applicability ;
5
5
use rustc_lint:: { LateContext , unerased_lint_store} ;
6
6
use rustc_span:: { BytePos , Pos , SourceFile , Span , SyntaxContext } ;
7
- use serde:: { Deserialize , Serialize } ;
8
- use std:: collections:: BTreeMap ;
9
7
use std:: ops:: Range ;
10
8
use std:: path:: Path ;
11
9
use toml:: Spanned ;
10
+ use toml:: de:: { DeTable , DeValue } ;
12
11
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
+ )
17
19
}
18
20
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 > ,
24
25
}
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 > {
34
27
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 )
39
29
}
40
30
41
31
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 ( )
47
33
}
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
- }
65
34
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
+ }
81
53
}
82
54
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 ) {
84
56
let mut lints = Vec :: new ( ) ;
85
57
let mut groups = Vec :: new ( ) ;
86
58
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
+ }
95
67
}
96
68
}
97
69
98
70
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
+ } ) {
105
74
span_lint_and_then (
106
75
cx,
107
76
LINT_GROUPS_PRIORITY ,
108
77
toml_span ( group. span ( ) , file) ,
109
78
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( ) ,
112
82
) ,
113
83
|diag| {
114
- let config_span = toml_span ( group_config. span ( ) , file) ;
84
+ let config_span = toml_span ( group_config. sp . clone ( ) , file) ;
115
85
116
- if group_config. as_ref ( ) . is_implicit ( ) {
86
+ if group_config. is_implicit ( ) {
117
87
diag. span_label ( config_span, "has an implicit priority of 0" ) ;
118
88
}
119
89
diag. span_label ( toml_span ( conflict. span ( ) , file) , "has the same priority as this lint" ) ;
120
90
diag. note ( "the order of the lints in the table is ignored by Cargo" ) ;
121
91
122
- let mut suggestion = String :: new ( ) ;
123
92
let low_priority = lints
124
93
. iter ( )
125
- . map ( |( _, config ) | config . priority ( ) . saturating_sub ( 1 ) )
94
+ . map ( |( _, lint_config ) | lint_config . priority ( ) . saturating_sub ( 1 ) )
126
95
. min ( )
127
96
. 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 ( ) ;
136
97
diag. span_suggestion_verbose (
137
98
config_span,
138
99
format ! (
139
100
"to have lints override the group set `{}` to a lower priority" ,
140
101
group. as_ref( )
141
102
) ,
142
- suggestion ,
103
+ format ! ( "{{ level = {:?}, priority = {low_priority} }}" , group_config . level , ) ,
143
104
Applicability :: MaybeIncorrect ,
144
105
) ;
145
106
} ,
@@ -148,10 +109,29 @@ fn check_table(cx: &LateContext<'_>, table: LintTable, known_groups: &FxHashSet<
148
109
}
149
110
}
150
111
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
+
151
131
pub fn check ( cx : & LateContext < ' _ > ) {
152
132
if let Ok ( file) = cx. tcx . sess . source_map ( ) . load_file ( Path :: new ( "Cargo.toml" ) )
153
133
&& 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)
155
135
{
156
136
let mut rustc_groups = FxHashSet :: default ( ) ;
157
137
let mut clippy_groups = FxHashSet :: default ( ) ;
@@ -167,9 +147,23 @@ pub fn check(cx: &LateContext<'_>) {
167
147
}
168
148
}
169
149
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
+ }
174
168
}
175
169
}
0 commit comments