1
1
use aho_corasick:: { AhoCorasick , AhoCorasickBuilder } ;
2
2
use core:: fmt:: { self , Display } ;
3
+ use core:: ops:: Range ;
3
4
use core:: slice;
4
5
use core:: str:: FromStr ;
5
6
use rustc_lexer as lexer;
@@ -165,9 +166,85 @@ impl Version {
165
166
}
166
167
}
167
168
169
+ enum TomlPart < ' a > {
170
+ Table ( & ' a str ) ,
171
+ Value ( & ' a str , & ' a str ) ,
172
+ }
173
+
174
+ fn toml_iter ( s : & str ) -> impl Iterator < Item = ( usize , TomlPart < ' _ > ) > {
175
+ let mut pos = 0 ;
176
+ s. split ( '\n' )
177
+ . map ( move |s| {
178
+ let x = pos;
179
+ pos += s. len ( ) + 1 ;
180
+ ( x, s)
181
+ } )
182
+ . filter_map ( |( pos, s) | {
183
+ if let Some ( s) = s. strip_prefix ( '[' ) {
184
+ s. split_once ( ']' ) . map ( |( name, _) | ( pos, TomlPart :: Table ( name) ) )
185
+ } else if matches ! (
186
+ s. as_bytes( ) . get( 0 ) ,
187
+ Some ( b'a' ..=b'z' | b'A' ..=b'Z' | b'0' ..=b'9' | b'_' )
188
+ ) {
189
+ s. split_once ( '=' ) . map ( |( key, value) | ( pos, TomlPart :: Value ( key, value) ) )
190
+ } else {
191
+ None
192
+ }
193
+ } )
194
+ }
195
+
196
+ pub struct CargoPackage < ' a > {
197
+ pub name : & ' a str ,
198
+ pub version_range : Range < usize > ,
199
+ pub not_a_platform_range : Range < usize > ,
200
+ }
201
+
202
+ pub fn parse_cargo_package ( s : & str ) -> CargoPackage < ' _ > {
203
+ let mut in_package = false ;
204
+ let mut in_platform_deps = false ;
205
+ let mut name = "" ;
206
+ let mut version_range = 0 ..0 ;
207
+ let mut not_a_platform_range = 0 ..0 ;
208
+ for ( offset, part) in toml_iter ( s) {
209
+ match part {
210
+ TomlPart :: Table ( name) => {
211
+ if in_platform_deps {
212
+ not_a_platform_range. end = offset;
213
+ }
214
+ in_package = false ;
215
+ in_platform_deps = false ;
216
+
217
+ match name. trim ( ) {
218
+ "package" => in_package = true ,
219
+ "target.'cfg(NOT_A_PLATFORM)'.dependencies" => {
220
+ in_platform_deps = true ;
221
+ not_a_platform_range. start = offset;
222
+ } ,
223
+ _ => { } ,
224
+ }
225
+ } ,
226
+ TomlPart :: Value ( key, value) if in_package => match key. trim_end ( ) {
227
+ "name" => name = value. trim ( ) ,
228
+ "version" => {
229
+ version_range. start = offset + ( value. len ( ) - value. trim ( ) . len ( ) ) + key. len ( ) + 1 ;
230
+ version_range. end = offset + key. len ( ) + value. trim_end ( ) . len ( ) + 1 ;
231
+ } ,
232
+ _ => { } ,
233
+ } ,
234
+ _ => { } ,
235
+ }
236
+ }
237
+ CargoPackage {
238
+ name,
239
+ version_range,
240
+ not_a_platform_range,
241
+ }
242
+ }
243
+
168
244
pub struct ClippyInfo {
169
245
pub path : PathBuf ,
170
246
pub version : Version ,
247
+ pub has_intellij_hook : bool ,
171
248
}
172
249
impl ClippyInfo {
173
250
#[ must_use]
@@ -177,35 +254,22 @@ impl ClippyInfo {
177
254
loop {
178
255
path. push ( "Cargo.toml" ) ;
179
256
if let Some ( mut file) = File :: open_if_exists ( & path, OpenOptions :: new ( ) . read ( true ) ) {
180
- let mut in_package = false ;
181
- let mut is_clippy = false ;
182
- let mut version: Option < Version > = None ;
183
-
184
- // Ad-hoc parsing to avoid dependencies. We control all the file so this
185
- // isn't actually a problem
186
- for line in file. read_to_cleared_string ( & mut buf) . lines ( ) {
187
- if line. starts_with ( '[' ) {
188
- in_package = line. starts_with ( "[package]" ) ;
189
- } else if in_package && let Some ( ( name, value) ) = line. split_once ( '=' ) {
190
- match name. trim ( ) {
191
- "name" => is_clippy = value. trim ( ) == "\" clippy\" " ,
192
- "version"
193
- if let Some ( value) = value. trim ( ) . strip_prefix ( '"' )
194
- && let Some ( value) = value. strip_suffix ( '"' ) =>
195
- {
196
- version = value. parse ( ) . ok ( ) ;
197
- } ,
198
- _ => { } ,
199
- }
200
- }
201
- }
202
-
203
- if is_clippy {
204
- let Some ( version) = version else {
257
+ file. read_to_cleared_string ( & mut buf) ;
258
+ let package = parse_cargo_package ( & buf) ;
259
+ if package. name == "\" clippy\" " {
260
+ if let Some ( version) = buf[ package. version_range ] . strip_prefix ( '"' )
261
+ && let Some ( version) = version. strip_suffix ( '"' )
262
+ && let Ok ( version) = version. parse ( )
263
+ {
264
+ path. pop ( ) ;
265
+ return ClippyInfo {
266
+ path,
267
+ version,
268
+ has_intellij_hook : !package. not_a_platform_range . is_empty ( ) ,
269
+ } ;
270
+ } else {
205
271
panic ! ( "error reading clippy version from {}" , file. path. display( ) ) ;
206
- } ;
207
- path. pop ( ) ;
208
- return ClippyInfo { path, version } ;
272
+ }
209
273
}
210
274
}
211
275
0 commit comments