@@ -35,29 +35,19 @@ use crate::settings::{flags, LinterSettings};
35
35
use crate :: source_kind:: SourceKind ;
36
36
use crate :: { directives, fs} ;
37
37
38
- /// A [`Result`]-like type that returns both data and an error. Used to return
39
- /// diagnostics even in the face of parse errors, since many diagnostics can be
40
- /// generated without a full AST.
41
- pub struct LinterResult < T > {
42
- pub data : T ,
43
- pub error : Option < ParseError > ,
44
- }
45
-
46
- impl < T > LinterResult < T > {
47
- const fn new ( data : T , error : Option < ParseError > ) -> Self {
48
- Self { data, error }
49
- }
50
-
51
- fn map < U , F : FnOnce ( T ) -> U > ( self , f : F ) -> LinterResult < U > {
52
- LinterResult :: new ( f ( self . data ) , self . error )
53
- }
38
+ pub struct LinterResult {
39
+ /// A collection of diagnostic messages generated by the linter.
40
+ pub messages : Vec < Message > ,
41
+ /// A flag indicating the presence of syntax errors in the source file.
42
+ /// If `true`, at least one syntax error was detected in the source file.
43
+ pub has_syntax_error : bool ,
54
44
}
55
45
56
46
pub type FixTable = FxHashMap < Rule , usize > ;
57
47
58
48
pub struct FixerResult < ' a > {
59
49
/// The result returned by the linter, after applying any fixes.
60
- pub result : LinterResult < Vec < Message > > ,
50
+ pub result : LinterResult ,
61
51
/// The resulting source code, after applying any fixes.
62
52
pub transformed : Cow < ' a , SourceKind > ,
63
53
/// The number of fixes applied for each [`Rule`].
@@ -79,7 +69,7 @@ pub fn check_path(
79
69
source_kind : & SourceKind ,
80
70
source_type : PySourceType ,
81
71
parsed : & Parsed < ModModule > ,
82
- ) -> LinterResult < Vec < Diagnostic > > {
72
+ ) -> Vec < Diagnostic > {
83
73
// Aggregate all diagnostics.
84
74
let mut diagnostics = vec ! [ ] ;
85
75
@@ -317,7 +307,7 @@ pub fn check_path(
317
307
}
318
308
}
319
309
320
- LinterResult :: new ( diagnostics, parsed . errors ( ) . iter ( ) . next ( ) . cloned ( ) )
310
+ diagnostics
321
311
}
322
312
323
313
const MAX_ITERATIONS : usize = 100 ;
@@ -351,9 +341,7 @@ pub fn add_noqa_to_path(
351
341
) ;
352
342
353
343
// Generate diagnostics, ignoring any existing `noqa` directives.
354
- let LinterResult {
355
- data : diagnostics, ..
356
- } = check_path (
344
+ let diagnostics = check_path (
357
345
path,
358
346
package,
359
347
& locator,
@@ -390,7 +378,7 @@ pub fn lint_only(
390
378
source_kind : & SourceKind ,
391
379
source_type : PySourceType ,
392
380
source : ParseSource ,
393
- ) -> LinterResult < Vec < Message > > {
381
+ ) -> LinterResult {
394
382
let parsed = source. into_parsed ( source_kind, source_type) ;
395
383
396
384
// Map row and column locations to byte slices (lazily).
@@ -411,7 +399,7 @@ pub fn lint_only(
411
399
) ;
412
400
413
401
// Generate diagnostics.
414
- let result = check_path (
402
+ let diagnostics = check_path (
415
403
path,
416
404
package,
417
405
& locator,
@@ -425,9 +413,16 @@ pub fn lint_only(
425
413
& parsed,
426
414
) ;
427
415
428
- result. map ( |diagnostics| {
429
- diagnostics_to_messages ( diagnostics, parsed. errors ( ) , path, & locator, & directives)
430
- } )
416
+ LinterResult {
417
+ messages : diagnostics_to_messages (
418
+ diagnostics,
419
+ parsed. errors ( ) ,
420
+ path,
421
+ & locator,
422
+ & directives,
423
+ ) ,
424
+ has_syntax_error : !parsed. is_valid ( ) ,
425
+ }
431
426
}
432
427
433
428
/// Convert from diagnostics to messages.
@@ -479,8 +474,8 @@ pub fn lint_fix<'a>(
479
474
// As an escape hatch, bail after 100 iterations.
480
475
let mut iterations = 0 ;
481
476
482
- // Track whether the _initial_ source code was parseable .
483
- let mut parseable = false ;
477
+ // Track whether the _initial_ source code is valid syntax .
478
+ let mut is_valid_syntax = false ;
484
479
485
480
// Continuously fix until the source code stabilizes.
486
481
loop {
@@ -506,7 +501,7 @@ pub fn lint_fix<'a>(
506
501
) ;
507
502
508
503
// Generate diagnostics.
509
- let result = check_path (
504
+ let diagnostics = check_path (
510
505
path,
511
506
package,
512
507
& locator,
@@ -521,19 +516,21 @@ pub fn lint_fix<'a>(
521
516
) ;
522
517
523
518
if iterations == 0 {
524
- parseable = result . error . is_none ( ) ;
519
+ is_valid_syntax = parsed . is_valid ( ) ;
525
520
} else {
526
521
// If the source code was parseable on the first pass, but is no
527
522
// longer parseable on a subsequent pass, then we've introduced a
528
523
// syntax error. Return the original code.
529
- if parseable && result. error . is_some ( ) {
530
- report_fix_syntax_error (
531
- path,
532
- transformed. source_code ( ) ,
533
- & result. error . unwrap ( ) ,
534
- fixed. keys ( ) . copied ( ) ,
535
- ) ;
536
- return Err ( anyhow ! ( "Fix introduced a syntax error" ) ) ;
524
+ if is_valid_syntax {
525
+ if let Some ( error) = parsed. errors ( ) . first ( ) {
526
+ report_fix_syntax_error (
527
+ path,
528
+ transformed. source_code ( ) ,
529
+ error,
530
+ fixed. keys ( ) . copied ( ) ,
531
+ ) ;
532
+ return Err ( anyhow ! ( "Fix introduced a syntax error" ) ) ;
533
+ }
537
534
}
538
535
}
539
536
@@ -542,7 +539,7 @@ pub fn lint_fix<'a>(
542
539
code : fixed_contents,
543
540
fixes : applied,
544
541
source_map,
545
- } ) = fix_file ( & result . data , & locator, unsafe_fixes)
542
+ } ) = fix_file ( & diagnostics , & locator, unsafe_fixes)
546
543
{
547
544
if iterations < MAX_ITERATIONS {
548
545
// Count the number of fixed errors.
@@ -559,13 +556,20 @@ pub fn lint_fix<'a>(
559
556
continue ;
560
557
}
561
558
562
- report_failed_to_converge_error ( path, transformed. source_code ( ) , & result . data ) ;
559
+ report_failed_to_converge_error ( path, transformed. source_code ( ) , & diagnostics ) ;
563
560
}
564
561
565
562
return Ok ( FixerResult {
566
- result : result. map ( |diagnostics| {
567
- diagnostics_to_messages ( diagnostics, parsed. errors ( ) , path, & locator, & directives)
568
- } ) ,
563
+ result : LinterResult {
564
+ messages : diagnostics_to_messages (
565
+ diagnostics,
566
+ parsed. errors ( ) ,
567
+ path,
568
+ & locator,
569
+ & directives,
570
+ ) ,
571
+ has_syntax_error : !is_valid_syntax,
572
+ } ,
569
573
transformed,
570
574
fixed,
571
575
} ) ;
0 commit comments