11use aho_corasick:: { AhoCorasick , AhoCorasickBuilder } ;
22use core:: fmt:: { self , Display } ;
3+ use core:: ops:: Range ;
34use core:: slice;
45use core:: str:: FromStr ;
56use rustc_lexer:: { self as lexer, FrontmatterAllowed } ;
@@ -165,9 +166,85 @@ impl Version {
165166 }
166167}
167168
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+
168244pub struct ClippyInfo {
169245 pub path : PathBuf ,
170246 pub version : Version ,
247+ pub has_intellij_hook : bool ,
171248}
172249impl ClippyInfo {
173250 #[ must_use]
@@ -177,35 +254,22 @@ impl ClippyInfo {
177254 loop {
178255 path. push ( "Cargo.toml" ) ;
179256 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 {
205271 panic ! ( "error reading clippy version from {}" , file. path. display( ) ) ;
206- } ;
207- path. pop ( ) ;
208- return ClippyInfo { path, version } ;
272+ }
209273 }
210274 }
211275
0 commit comments