Skip to content

Commit 37fbe58

Browse files
authored
Document LinterResult::has_syntax_error and add Parsed::has_no_syntax_errors (#16443)
Summary -- This is a follow up addressing the comments on #16425. As @dhruvmanila pointed out, the naming is a bit tricky. I went with `has_no_errors` to try to differentiate it from `is_valid`. It actually ends up negated in most uses, so it would be more convenient to have `has_any_errors` or `has_errors`, but I thought it would sound too much like the opposite of `is_valid` in that case. I'm definitely open to suggestions here. Test Plan -- Existing tests.
1 parent a3ae76e commit 37fbe58

File tree

6 files changed

+50
-26
lines changed

6 files changed

+50
-26
lines changed

crates/ruff_db/src/parsed.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ mod tests {
102102

103103
let parsed = parsed_module(&db, file);
104104

105-
assert!(parsed.is_valid());
105+
assert!(parsed.has_valid_syntax());
106106

107107
Ok(())
108108
}
@@ -118,7 +118,7 @@ mod tests {
118118

119119
let parsed = parsed_module(&db, file);
120120

121-
assert!(parsed.is_valid());
121+
assert!(parsed.has_valid_syntax());
122122

123123
Ok(())
124124
}
@@ -134,7 +134,7 @@ mod tests {
134134

135135
let parsed = parsed_module(&db, virtual_file.file());
136136

137-
assert!(parsed.is_valid());
137+
assert!(parsed.has_valid_syntax());
138138

139139
Ok(())
140140
}
@@ -150,7 +150,7 @@ mod tests {
150150

151151
let parsed = parsed_module(&db, virtual_file.file());
152152

153-
assert!(parsed.is_valid());
153+
assert!(parsed.has_valid_syntax());
154154

155155
Ok(())
156156
}
@@ -181,6 +181,6 @@ else:
181181

182182
let parsed = parsed_module(&db, file);
183183

184-
assert!(parsed.is_valid());
184+
assert!(parsed.has_valid_syntax());
185185
}
186186
}

crates/ruff_linter/src/linter.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ pub struct LinterResult {
4242
pub messages: Vec<Message>,
4343
/// A flag indicating the presence of syntax errors in the source file.
4444
/// If `true`, at least one syntax error was detected in the source file.
45+
///
46+
/// This includes both [`ParseError`]s and [`UnsupportedSyntaxError`]s.
4547
pub has_syntax_error: bool,
4648
}
4749

@@ -133,7 +135,7 @@ pub fn check_path(
133135
}
134136

135137
// Run the AST-based rules only if there are no syntax errors.
136-
if parsed.is_valid() {
138+
if parsed.has_valid_syntax() {
137139
let use_ast = settings
138140
.rules
139141
.iter_enabled()
@@ -283,7 +285,7 @@ pub fn check_path(
283285
locator,
284286
comment_ranges,
285287
&directives.noqa_line_for,
286-
parsed.is_valid(),
288+
parsed.has_valid_syntax(),
287289
&per_file_ignores,
288290
settings,
289291
);
@@ -294,7 +296,7 @@ pub fn check_path(
294296
}
295297
}
296298

297-
if parsed.is_valid() {
299+
if parsed.has_valid_syntax() {
298300
// Remove fixes for any rules marked as unfixable.
299301
for diagnostic in &mut diagnostics {
300302
if !settings.rules.should_fix(diagnostic.kind.rule()) {
@@ -445,7 +447,7 @@ pub fn lint_only(
445447
&locator,
446448
&directives,
447449
),
448-
has_syntax_error: !parsed.is_valid() || !parsed.unsupported_syntax_errors().is_empty(),
450+
has_syntax_error: parsed.has_syntax_errors(),
449451
}
450452
}
451453

@@ -546,7 +548,7 @@ pub fn lint_fix<'a>(
546548
);
547549

548550
if iterations == 0 {
549-
is_valid_syntax = parsed.is_valid() && parsed.unsupported_syntax_errors().is_empty();
551+
is_valid_syntax = parsed.has_no_syntax_errors();
550552
} else {
551553
// If the source code was parseable on the first pass, but is no
552554
// longer parseable on a subsequent pass, then we've introduced a

crates/ruff_linter/src/test.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ pub(crate) fn test_contents<'a>(
141141
target_version,
142142
);
143143

144-
let source_has_errors = !parsed.is_valid();
144+
let source_has_errors = parsed.has_invalid_syntax();
145145

146146
// Detect fixes that don't converge after multiple iterations.
147147
let mut iterations = 0;
@@ -207,7 +207,7 @@ pub(crate) fn test_contents<'a>(
207207
target_version,
208208
);
209209

210-
if !parsed.is_valid() && !source_has_errors {
210+
if parsed.has_invalid_syntax() && !source_has_errors {
211211
// Previous fix introduced a syntax error, abort
212212
let fixes = print_diagnostics(diagnostics, path, source_kind);
213213
let syntax_errors =

crates/ruff_python_parser/src/lib.rs

+32-6
Original file line numberDiff line numberDiff line change
@@ -342,21 +342,47 @@ impl<T> Parsed<T> {
342342
self.errors
343343
}
344344

345-
/// Returns `true` if the parsed source code is valid i.e., it has no syntax errors.
345+
/// Returns `true` if the parsed source code is valid i.e., it has no [`ParseError`]s.
346346
///
347-
/// Note that this does not include version-related
348-
/// [`unsupported_syntax_errors`](Parsed::unsupported_syntax_errors).
349-
pub fn is_valid(&self) -> bool {
347+
/// Note that this does not include version-related [`UnsupportedSyntaxError`]s.
348+
///
349+
/// See [`Parsed::has_no_syntax_errors`] for a version that takes these into account.
350+
pub fn has_valid_syntax(&self) -> bool {
350351
self.errors.is_empty()
351352
}
352353

354+
/// Returns `true` if the parsed source code is invalid i.e., it has [`ParseError`]s.
355+
///
356+
/// Note that this does not include version-related [`UnsupportedSyntaxError`]s.
357+
///
358+
/// See [`Parsed::has_no_syntax_errors`] for a version that takes these into account.
359+
pub fn has_invalid_syntax(&self) -> bool {
360+
!self.has_valid_syntax()
361+
}
362+
363+
/// Returns `true` if the parsed source code does not contain any [`ParseError`]s *or*
364+
/// [`UnsupportedSyntaxError`]s.
365+
///
366+
/// See [`Parsed::has_valid_syntax`] for a version specific to [`ParseError`]s.
367+
pub fn has_no_syntax_errors(&self) -> bool {
368+
self.has_valid_syntax() && self.unsupported_syntax_errors.is_empty()
369+
}
370+
371+
/// Returns `true` if the parsed source code contains any [`ParseError`]s *or*
372+
/// [`UnsupportedSyntaxError`]s.
373+
///
374+
/// See [`Parsed::has_invalid_syntax`] for a version specific to [`ParseError`]s.
375+
pub fn has_syntax_errors(&self) -> bool {
376+
!self.has_no_syntax_errors()
377+
}
378+
353379
/// Returns the [`Parsed`] output as a [`Result`], returning [`Ok`] if it has no syntax errors,
354380
/// or [`Err`] containing the first [`ParseError`] encountered.
355381
///
356382
/// Note that any [`unsupported_syntax_errors`](Parsed::unsupported_syntax_errors) will not
357383
/// cause [`Err`] to be returned.
358384
pub fn as_result(&self) -> Result<&Parsed<T>, &[ParseError]> {
359-
if self.is_valid() {
385+
if self.has_valid_syntax() {
360386
Ok(self)
361387
} else {
362388
Err(&self.errors)
@@ -369,7 +395,7 @@ impl<T> Parsed<T> {
369395
/// Note that any [`unsupported_syntax_errors`](Parsed::unsupported_syntax_errors) will not
370396
/// cause [`Err`] to be returned.
371397
pub(crate) fn into_result(self) -> Result<Parsed<T>, ParseError> {
372-
if self.is_valid() {
398+
if self.has_valid_syntax() {
373399
Ok(self)
374400
} else {
375401
Err(self.into_errors().into_iter().next().unwrap())

crates/ruff_python_parser/tests/fixtures.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@ fn test_valid_syntax(input_path: &Path) {
3939
});
4040
let parsed = parse_unchecked(&source, options);
4141

42-
let is_valid = parsed.is_valid() && parsed.unsupported_syntax_errors().is_empty();
43-
44-
if !is_valid {
42+
if parsed.has_syntax_errors() {
4543
let line_index = LineIndex::from_source_text(&source);
4644
let source_code = SourceCode::new(&source, &line_index);
4745

@@ -101,10 +99,8 @@ fn test_invalid_syntax(input_path: &Path) {
10199
});
102100
let parsed = parse_unchecked(&source, options);
103101

104-
let is_valid = parsed.is_valid() && parsed.unsupported_syntax_errors().is_empty();
105-
106102
assert!(
107-
!is_valid,
103+
parsed.has_syntax_errors(),
108104
"{input_path:?}: Expected parser to generate at least one syntax error for a program containing syntax errors."
109105
);
110106

@@ -224,7 +220,7 @@ f'{foo!r'
224220
println!("AST:\n----\n{:#?}", parsed.syntax());
225221
println!("Tokens:\n-------\n{:#?}", parsed.tokens());
226222

227-
if !parsed.is_valid() {
223+
if parsed.has_invalid_syntax() {
228224
println!("Errors:\n-------");
229225

230226
let line_index = LineIndex::from_source_text(source);

fuzz/fuzz_targets/red_knot_check_invalid_syntax.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ fn do_fuzz(case: &[u8]) -> Corpus {
135135
};
136136

137137
let parsed = parse_unchecked(code, ParseOptions::from(Mode::Module));
138-
if parsed.is_valid() {
138+
if parsed.has_valid_syntax() {
139139
return Corpus::Reject;
140140
}
141141

0 commit comments

Comments
 (0)