11use core:: fmt:: { self , Display } ;
2+ use core:: ops:: Range ;
23use core:: slice;
34use core:: str:: FromStr ;
45use rustc_lexer:: { self as lexer, FrontmatterAllowed } ;
@@ -166,9 +167,85 @@ impl Version {
166167 }
167168}
168169
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+
169245pub struct ClippyInfo {
170246 pub path : PathBuf ,
171247 pub version : Version ,
248+ pub has_intellij_hook : bool ,
172249}
173250impl ClippyInfo {
174251 #[ must_use]
@@ -178,35 +255,22 @@ impl ClippyInfo {
178255 loop {
179256 path. push ( "Cargo.toml" ) ;
180257 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 {
206272 panic ! ( "error reading clippy version from {}" , file. path. display( ) ) ;
207- } ;
208- path. pop ( ) ;
209- return ClippyInfo { path, version } ;
273+ }
210274 }
211275 }
212276
0 commit comments