Range formatting: Fix invalid syntax after parenthesizing expression (#9751)

This commit is contained in:
Micha Reiser 2024-02-02 17:56:25 +01:00 committed by GitHub
parent 50bfbcf568
commit 4f7fb566f0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 351 additions and 212 deletions

View file

@ -3,7 +3,7 @@ use tracing::Level;
pub use range::format_range;
use ruff_formatter::prelude::*;
use ruff_formatter::{format, FormatError, Formatted, PrintError, Printed, SourceCode};
use ruff_formatter::{format, write, FormatError, Formatted, PrintError, Printed, SourceCode};
use ruff_python_ast::AstNode;
use ruff_python_ast::Mod;
use ruff_python_index::tokens_and_ranges;
@ -19,6 +19,7 @@ pub use crate::options::{
DocstringCode, DocstringCodeLineWidth, MagicTrailingComma, PreviewMode, PyFormatOptions,
PythonVersion, QuoteStyle,
};
use crate::range::is_logical_line;
pub use crate::shared_traits::{AsFormat, FormattedIter, FormattedIterExt, IntoFormat};
use crate::verbatim::suppressed_node;
@ -59,19 +60,27 @@ where
} else {
leading_comments(node_comments.leading).fmt(f)?;
let is_source_map_enabled = f.options().source_map_generation().is_enabled();
let node_ref = node.as_any_node_ref();
if is_source_map_enabled {
source_position(node.start()).fmt(f)?;
}
// Emit source map information for nodes that are valid "narrowing" targets
// in range formatting. Never emit source map information if they're disabled
// for performance reasons.
let emit_source_position = (is_logical_line(node_ref) || node_ref.is_mod_module())
&& f.options().source_map_generation().is_enabled();
emit_source_position
.then_some(source_position(node.start()))
.fmt(f)?;
self.fmt_fields(node, f)?;
if is_source_map_enabled {
source_position(node.end()).fmt(f)?;
}
trailing_comments(node_comments.trailing).fmt(f)
write!(
f,
[
emit_source_position.then_some(source_position(node.end())),
trailing_comments(node_comments.trailing)
]
)
}
}
@ -249,15 +258,36 @@ def main() -> None:
#[ignore]
#[test]
fn range_formatting_quick_test() {
let source = r#"def test2( a): print("body" )
"#;
let source = r#"def convert_str(value: str) -> str: # Trailing comment
"""Return a string as-is."""
let start = TextSize::new(20);
let end = TextSize::new(35);
<RANGE_START>
return value # Trailing comment
<RANGE_END>"#;
let mut source = source.to_string();
let start = TextSize::try_from(
source
.find("<RANGE_START>")
.expect("Start marker not found"),
)
.unwrap();
source.replace_range(
start.to_usize()..start.to_usize() + "<RANGE_START>".len(),
"",
);
let end =
TextSize::try_from(source.find("<RANGE_END>").expect("End marker not found")).unwrap();
source.replace_range(end.to_usize()..end.to_usize() + "<RANGE_END>".len(), "");
let source_type = PySourceType::Python;
let options = PyFormatOptions::from_source_type(source_type);
let printed = format_range(source, TextRange::new(start, end), options).unwrap();
let printed = format_range(&source, TextRange::new(start, end), options).unwrap();
let mut formatted = source.to_string();
formatted.replace_range(
@ -267,9 +297,11 @@ def main() -> None:
assert_eq!(
formatted,
r#"def test2(a):
print("body")
"#
r#"print ( "format me" )
print("format me")
print("format me")
print ( "format me" )
print ( "format me" )"#
);
}
@ -300,7 +332,7 @@ def main() -> None:
while let Some(word) = words.next() {
let is_last = words.peek().is_none();
let format_word = format_with(|f| {
write!(f, [text(word, None)])?;
write!(f, [text(word)])?;
if is_last {
write!(f, [token("\"")])?;