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