Compare commits

...

3 Commits

Author SHA1 Message Date
Charlie Marsh
948f3e538f Revert changes to concat 2023-06-13 19:52:19 -04:00
Charlie Marsh
d1759a75ba Try to get this to work 2023-06-13 18:38:02 -04:00
Charlie Marsh
69fab0f18f Add a verbatim, formattable AST 2023-06-13 18:38:02 -04:00
8 changed files with 3058 additions and 12 deletions

View File

@@ -36,3 +36,14 @@ if (True) == TrueElement or x == TrueElement:
assert (not foo) in bar
assert {"x": not foo} in bar
assert [42, not foo] in bar
# Preserve raw strings.
not (re.search(r"^.:\\Users\\[^\\]*\\Downloads\\.*") is None)
# Preserve comments
not (
re.search( # Comment
r"^.:\\Users\\[^\\]*\\Downloads\\.*",
)
is None
)

View File

@@ -12,7 +12,9 @@ use rustpython_parser::ast::{
use ruff_diagnostics::{Diagnostic, IsolationLevel};
use ruff_python_ast::all::{extract_all_names, AllNamesFlags};
use ruff_python_ast::helpers::{extract_handled_exceptions, to_module_path};
use ruff_python_ast::source_code::{Generator, Indexer, Locator, Quote, Stylist};
use ruff_python_ast::source_code::{
Generator, Indexer, Locator, Quote, Stylist, VerbatimGenerator,
};
use ruff_python_ast::str::trailing_quote;
use ruff_python_ast::types::Node;
use ruff_python_ast::typing::{parse_type_annotation, AnnotationKind};
@@ -144,6 +146,16 @@ impl<'a> Checker<'a> {
)
}
/// Create a [`VerbatimGenerator`] to generate source code based on the current AST state.
pub(crate) fn verbatim_generator(&self) -> VerbatimGenerator {
VerbatimGenerator::new(
self.locator,
self.stylist.indentation(),
self.f_string_quote_style().unwrap_or(self.stylist.quote()),
self.stylist.line_ending(),
)
}
/// Returns the appropriate quoting for f-string by reversing the one used outside of
/// the f-string.
///

View File

@@ -2,10 +2,11 @@ use rustpython_parser::ast::{self, Cmpop, Expr, Ranged, Unaryop};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::source_code::VerbatimGenerator;
use ruff_python_ast::verbatim;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
use crate::rules::pycodestyle::helpers::compare;
/// ## What it does
/// Checks for negative comparison using `not {foo} in {bar}`.
@@ -99,13 +100,12 @@ pub(crate) fn not_tests(
if check_not_in {
let mut diagnostic = Diagnostic::new(NotInTest, operand.range());
if checker.patch(diagnostic.kind.rule()) {
#[allow(deprecated)]
diagnostic.set_fix(Fix::unspecified(Edit::range_replacement(
compare(
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
create_comparison(
left,
&[Cmpop::NotIn],
Cmpop::NotIn,
comparators,
checker.generator(),
checker.verbatim_generator(),
),
expr.range(),
)));
@@ -117,13 +117,12 @@ pub(crate) fn not_tests(
if check_not_is {
let mut diagnostic = Diagnostic::new(NotIsTest, operand.range());
if checker.patch(diagnostic.kind.rule()) {
#[allow(deprecated)]
diagnostic.set_fix(Fix::unspecified(Edit::range_replacement(
compare(
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
create_comparison(
left,
&[Cmpop::IsNot],
Cmpop::IsNot,
comparators,
checker.generator(),
checker.verbatim_generator(),
),
expr.range(),
)));
@@ -137,3 +136,16 @@ pub(crate) fn not_tests(
}
}
}
fn create_comparison(
left: &Expr,
op: Cmpop,
comparators: &[Expr],
generator: VerbatimGenerator,
) -> String {
generator.expr(&verbatim::Expr::Compare(verbatim::ExprCompare {
left: Box::new(verbatim::Expr::verbatim(left)),
ops: vec![verbatim::Cmpop::from(op)],
comparators: comparators.iter().map(verbatim::Expr::verbatim).collect(),
}))
}

View File

@@ -39,4 +39,51 @@ E714.py:5:8: E714 [*] Test for object identity should be `is not`
7 7 |
8 8 | #: Okay
E714.py:41:6: E714 [*] Test for object identity should be `is not`
|
40 | # Preserve raw strings.
41 | not (re.search(r"^.:\\Users\\[^\\]*\\Downloads\\.*") is None)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E714
42 |
43 | # Preserve comments
|
= help: Convert to `is not`
Suggested fix
38 38 | assert [42, not foo] in bar
39 39 |
40 40 | # Preserve raw strings.
41 |-not (re.search(r"^.:\\Users\\[^\\]*\\Downloads\\.*") is None)
41 |+re.search(r"^.:\\Users\\[^\\]*\\Downloads\\.*") is not None
42 42 |
43 43 | # Preserve comments
44 44 | not (
E714.py:45:5: E714 [*] Test for object identity should be `is not`
|
43 | # Preserve comments
44 | not (
45 | re.search( # Comment
| _____^
46 | | r"^.:\\Users\\[^\\]*\\Downloads\\.*",
47 | | )
48 | | is None
| |___________^ E714
49 | )
|
= help: Convert to `is not`
Suggested fix
41 41 | not (re.search(r"^.:\\Users\\[^\\]*\\Downloads\\.*") is None)
42 42 |
43 43 | # Preserve comments
44 |-not (
45 |- re.search( # Comment
44 |+re.search( # Comment
46 45 | r"^.:\\Users\\[^\\]*\\Downloads\\.*",
47 |- )
48 |- is None
49 |-)
46 |+ ) is not None

View File

@@ -16,5 +16,6 @@ pub mod str;
pub mod token_kind;
pub mod types;
pub mod typing;
pub mod verbatim;
pub mod visitor;
pub mod whitespace;

View File

@@ -12,6 +12,7 @@ pub use generator::Generator;
pub use indexer::Indexer;
pub use locator::Locator;
pub use stylist::{Quote, Stylist};
pub use verbatim_generator::VerbatimGenerator;
pub use crate::source_code::line_index::{LineIndex, OneIndexed};
@@ -21,6 +22,7 @@ mod indexer;
mod line_index;
mod locator;
mod stylist;
mod verbatim_generator;
/// Run round-trip source code generation on a given Python code.
pub fn round_trip(code: &str, source_path: &str) -> Result<String, ParseError> {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff