@@ -36,29 +36,19 @@ use crate::settings::{flags, LinterSettings};
36
36
use crate :: source_kind:: SourceKind ;
37
37
use crate :: { directives, fs} ;
38
38
39
- /// A [`Result`]-like type that returns both data and an error. Used to return
40
- /// diagnostics even in the face of parse errors, since many diagnostics can be
41
- /// generated without a full AST.
42
- pub struct LinterResult < T > {
43
- pub data : T ,
44
- pub error : Option < ParseError > ,
45
- }
46
-
47
- impl < T > LinterResult < T > {
48
- const fn new ( data : T , error : Option < ParseError > ) -> Self {
49
- Self { data, error }
50
- }
51
-
52
- fn map < U , F : FnOnce ( T ) -> U > ( self , f : F ) -> LinterResult < U > {
53
- LinterResult :: new ( f ( self . data ) , self . error )
54
- }
39
+ pub struct LinterResult {
40
+ /// A collection of diagnostic messages generated by the linter.
41
+ pub messages : Vec < Message > ,
42
+ /// A flag indicating the presence of syntax errors in the source file.
43
+ /// If `true`, at least one syntax error was detected in the source file.
44
+ pub has_error : bool ,
55
45
}
56
46
57
47
pub type FixTable = FxHashMap < Rule , usize > ;
58
48
59
49
pub struct FixerResult < ' a > {
60
50
/// The result returned by the linter, after applying any fixes.
61
- pub result : LinterResult < Vec < Message > > ,
51
+ pub result : LinterResult ,
62
52
/// The resulting source code, after applying any fixes.
63
53
pub transformed : Cow < ' a , SourceKind > ,
64
54
/// The number of fixes applied for each [`Rule`].
@@ -80,7 +70,7 @@ pub fn check_path(
80
70
source_kind : & SourceKind ,
81
71
source_type : PySourceType ,
82
72
parsed : & Parsed < ModModule > ,
83
- ) -> LinterResult < Vec < Diagnostic > > {
73
+ ) -> Vec < Diagnostic > {
84
74
// Aggregate all diagnostics.
85
75
let mut diagnostics = vec ! [ ] ;
86
76
@@ -328,7 +318,7 @@ pub fn check_path(
328
318
}
329
319
}
330
320
331
- LinterResult :: new ( diagnostics, parsed . errors ( ) . iter ( ) . next ( ) . cloned ( ) )
321
+ diagnostics
332
322
}
333
323
334
324
const MAX_ITERATIONS : usize = 100 ;
@@ -362,9 +352,7 @@ pub fn add_noqa_to_path(
362
352
) ;
363
353
364
354
// Generate diagnostics, ignoring any existing `noqa` directives.
365
- let LinterResult {
366
- data : diagnostics, ..
367
- } = check_path (
355
+ let diagnostics = check_path (
368
356
path,
369
357
package,
370
358
& locator,
@@ -401,7 +389,7 @@ pub fn lint_only(
401
389
source_kind : & SourceKind ,
402
390
source_type : PySourceType ,
403
391
source : ParseSource ,
404
- ) -> LinterResult < Vec < Message > > {
392
+ ) -> LinterResult {
405
393
let parsed = source. into_parsed ( source_kind, source_type) ;
406
394
407
395
// Map row and column locations to byte slices (lazily).
@@ -422,7 +410,7 @@ pub fn lint_only(
422
410
) ;
423
411
424
412
// Generate diagnostics.
425
- let result = check_path (
413
+ let diagnostics = check_path (
426
414
path,
427
415
package,
428
416
& locator,
@@ -436,7 +424,10 @@ pub fn lint_only(
436
424
& parsed,
437
425
) ;
438
426
439
- result. map ( |diagnostics| diagnostics_to_messages ( diagnostics, path, & locator, & directives) )
427
+ LinterResult {
428
+ messages : diagnostics_to_messages ( diagnostics, path, & locator, & directives) ,
429
+ has_error : !parsed. is_valid ( ) ,
430
+ }
440
431
}
441
432
442
433
/// Convert from diagnostics to messages.
@@ -513,7 +504,7 @@ pub fn lint_fix<'a>(
513
504
) ;
514
505
515
506
// Generate diagnostics.
516
- let result = check_path (
507
+ let diagnostics = check_path (
517
508
path,
518
509
package,
519
510
& locator,
@@ -528,19 +519,21 @@ pub fn lint_fix<'a>(
528
519
) ;
529
520
530
521
if iterations == 0 {
531
- parseable = result . error . is_none ( ) ;
522
+ parseable = parsed . is_valid ( ) ;
532
523
} else {
533
524
// If the source code was parseable on the first pass, but is no
534
525
// longer parseable on a subsequent pass, then we've introduced a
535
526
// syntax error. Return the original code.
536
- if parseable && result. error . is_some ( ) {
537
- report_fix_syntax_error (
538
- path,
539
- transformed. source_code ( ) ,
540
- & result. error . unwrap ( ) ,
541
- fixed. keys ( ) . copied ( ) ,
542
- ) ;
543
- return Err ( anyhow ! ( "Fix introduced a syntax error" ) ) ;
527
+ if parseable {
528
+ if let [ error, ..] = parsed. errors ( ) {
529
+ report_fix_syntax_error (
530
+ path,
531
+ transformed. source_code ( ) ,
532
+ error,
533
+ fixed. keys ( ) . copied ( ) ,
534
+ ) ;
535
+ return Err ( anyhow ! ( "Fix introduced a syntax error" ) ) ;
536
+ }
544
537
}
545
538
}
546
539
@@ -549,7 +542,7 @@ pub fn lint_fix<'a>(
549
542
code : fixed_contents,
550
543
fixes : applied,
551
544
source_map,
552
- } ) = fix_file ( & result . data , & locator, unsafe_fixes)
545
+ } ) = fix_file ( & diagnostics , & locator, unsafe_fixes)
553
546
{
554
547
if iterations < MAX_ITERATIONS {
555
548
// Count the number of fixed errors.
@@ -566,13 +559,14 @@ pub fn lint_fix<'a>(
566
559
continue ;
567
560
}
568
561
569
- report_failed_to_converge_error ( path, transformed. source_code ( ) , & result . data ) ;
562
+ report_failed_to_converge_error ( path, transformed. source_code ( ) , & diagnostics ) ;
570
563
}
571
564
572
565
return Ok ( FixerResult {
573
- result : result. map ( |diagnostics| {
574
- diagnostics_to_messages ( diagnostics, path, & locator, & directives)
575
- } ) ,
566
+ result : LinterResult {
567
+ messages : diagnostics_to_messages ( diagnostics, path, & locator, & directives) ,
568
+ has_error : !parseable,
569
+ } ,
576
570
transformed,
577
571
fixed,
578
572
} ) ;
0 commit comments