mirror of https://github.com/astral-sh/ruff
[`pyupgrade`] Comments within parenthesized value ranges should not affect applicability (`UP040`) (#16027)
## Summary Follow-up to #16026. Previously, the fix for this would be marked as unsafe, even though all comments are preserved: ```python # .pyi T: TypeAlias = ( # Comment int | str ) ``` Now it is safe: comments within the parenthesized range no longer affect applicability. ## Test Plan `cargo nextest run` and `cargo insta test`. --------- Co-authored-by: Dylan <53534755+dylwil3@users.noreply.github.com>
This commit is contained in:
parent
19f3424a1a
commit
a29009e4ed
|
|
@ -12,3 +12,13 @@ x: TypeAlias = tuple[
|
||||||
int, # preserved
|
int, # preserved
|
||||||
float,
|
float,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
T: TypeAlias = ( # comment0
|
||||||
|
# comment1
|
||||||
|
int # comment2
|
||||||
|
# comment3
|
||||||
|
| # comment4
|
||||||
|
# comment5
|
||||||
|
str # comment6
|
||||||
|
# comment7
|
||||||
|
) # comment8
|
||||||
|
|
|
||||||
|
|
@ -170,25 +170,12 @@ pub(crate) fn non_pep695_type_alias_type(checker: &Checker, stmt: &StmtAssign) {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// it would be easier to check for comments in the whole `stmt.range`, but because
|
|
||||||
// `create_diagnostic` uses the full source text of `value`, comments within `value` are
|
|
||||||
// actually preserved. thus, we have to check for comments in `stmt` but outside of `value`
|
|
||||||
let pre_value = TextRange::new(stmt.start(), value.start());
|
|
||||||
let post_value = TextRange::new(value.end(), stmt.end());
|
|
||||||
let comment_ranges = checker.comment_ranges();
|
|
||||||
let safety = if comment_ranges.intersects(pre_value) || comment_ranges.intersects(post_value) {
|
|
||||||
Applicability::Unsafe
|
|
||||||
} else {
|
|
||||||
Applicability::Safe
|
|
||||||
};
|
|
||||||
|
|
||||||
checker.report_diagnostic(create_diagnostic(
|
checker.report_diagnostic(create_diagnostic(
|
||||||
checker,
|
checker,
|
||||||
stmt.into(),
|
stmt.into(),
|
||||||
&target_name.id,
|
&target_name.id,
|
||||||
value,
|
value,
|
||||||
&vars,
|
&vars,
|
||||||
safety,
|
|
||||||
TypeAliasKind::TypeAliasType,
|
TypeAliasKind::TypeAliasType,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -248,13 +235,6 @@ pub(crate) fn non_pep695_type_alias(checker: &Checker, stmt: &StmtAnnAssign) {
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
&vars,
|
&vars,
|
||||||
// The fix is only safe in a type stub because new-style aliases have different runtime behavior
|
|
||||||
// See https://github.com/astral-sh/ruff/issues/6434
|
|
||||||
if checker.source_type.is_stub() {
|
|
||||||
Applicability::Safe
|
|
||||||
} else {
|
|
||||||
Applicability::Unsafe
|
|
||||||
},
|
|
||||||
TypeAliasKind::TypeAlias,
|
TypeAliasKind::TypeAlias,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -266,19 +246,45 @@ fn create_diagnostic(
|
||||||
name: &Name,
|
name: &Name,
|
||||||
value: &Expr,
|
value: &Expr,
|
||||||
type_vars: &[TypeVar],
|
type_vars: &[TypeVar],
|
||||||
applicability: Applicability,
|
|
||||||
type_alias_kind: TypeAliasKind,
|
type_alias_kind: TypeAliasKind,
|
||||||
) -> Diagnostic {
|
) -> Diagnostic {
|
||||||
let source = checker.source();
|
let source = checker.source();
|
||||||
|
let comment_ranges = checker.comment_ranges();
|
||||||
|
|
||||||
let range_with_parentheses =
|
let range_with_parentheses =
|
||||||
parenthesized_range(value.into(), stmt.into(), checker.comment_ranges(), source)
|
parenthesized_range(value.into(), stmt.into(), comment_ranges, source)
|
||||||
.unwrap_or(value.range());
|
.unwrap_or(value.range());
|
||||||
|
|
||||||
let content = format!(
|
let content = format!(
|
||||||
"type {name}{type_params} = {value}",
|
"type {name}{type_params} = {value}",
|
||||||
type_params = DisplayTypeVars { type_vars, source },
|
type_params = DisplayTypeVars { type_vars, source },
|
||||||
value = &source[range_with_parentheses]
|
value = &source[range_with_parentheses]
|
||||||
);
|
);
|
||||||
let edit = Edit::range_replacement(content, stmt.range());
|
let edit = Edit::range_replacement(content, stmt.range());
|
||||||
|
|
||||||
|
let applicability =
|
||||||
|
if type_alias_kind == TypeAliasKind::TypeAlias && !checker.source_type.is_stub() {
|
||||||
|
// The fix is always unsafe in non-stubs
|
||||||
|
// because new-style aliases have different runtime behavior.
|
||||||
|
// See https://github.com/astral-sh/ruff/issues/6434
|
||||||
|
Applicability::Unsafe
|
||||||
|
} else {
|
||||||
|
// In stub files, or in non-stub files for `TypeAliasType` assignments,
|
||||||
|
// the fix is only unsafe if it would delete comments.
|
||||||
|
//
|
||||||
|
// it would be easier to check for comments in the whole `stmt.range`, but because
|
||||||
|
// `create_diagnostic` uses the full source text of `value`, comments within `value` are
|
||||||
|
// actually preserved. thus, we have to check for comments in `stmt` but outside of `value`
|
||||||
|
let pre_value = TextRange::new(stmt.start(), range_with_parentheses.start());
|
||||||
|
let post_value = TextRange::new(range_with_parentheses.end(), stmt.end());
|
||||||
|
|
||||||
|
if comment_ranges.intersects(pre_value) || comment_ranges.intersects(post_value) {
|
||||||
|
Applicability::Unsafe
|
||||||
|
} else {
|
||||||
|
Applicability::Safe
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Diagnostic::new(
|
Diagnostic::new(
|
||||||
NonPEP695TypeAlias {
|
NonPEP695TypeAlias {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,8 @@ UP040.pyi:11:1: UP040 [*] Type alias `x` uses `TypeAlias` annotation instead of
|
||||||
13 | | float,
|
13 | | float,
|
||||||
14 | | ]
|
14 | | ]
|
||||||
| |_^ UP040
|
| |_^ UP040
|
||||||
|
15 |
|
||||||
|
16 | T: TypeAlias = ( # comment0
|
||||||
|
|
|
|
||||||
= help: Use the `type` keyword
|
= help: Use the `type` keyword
|
||||||
|
|
||||||
|
|
@ -60,3 +62,30 @@ UP040.pyi:11:1: UP040 [*] Type alias `x` uses `TypeAlias` annotation instead of
|
||||||
12 12 | int, # preserved
|
12 12 | int, # preserved
|
||||||
13 13 | float,
|
13 13 | float,
|
||||||
14 14 | ]
|
14 14 | ]
|
||||||
|
|
||||||
|
UP040.pyi:16:1: UP040 [*] Type alias `T` uses `TypeAlias` annotation instead of the `type` keyword
|
||||||
|
|
|
||||||
|
14 | ]
|
||||||
|
15 |
|
||||||
|
16 | / T: TypeAlias = ( # comment0
|
||||||
|
17 | | # comment1
|
||||||
|
18 | | int # comment2
|
||||||
|
19 | | # comment3
|
||||||
|
20 | | | # comment4
|
||||||
|
21 | | # comment5
|
||||||
|
22 | | str # comment6
|
||||||
|
23 | | # comment7
|
||||||
|
24 | | ) # comment8
|
||||||
|
| |_^ UP040
|
||||||
|
|
|
||||||
|
= help: Use the `type` keyword
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
13 13 | float,
|
||||||
|
14 14 | ]
|
||||||
|
15 15 |
|
||||||
|
16 |-T: TypeAlias = ( # comment0
|
||||||
|
16 |+type T = ( # comment0
|
||||||
|
17 17 | # comment1
|
||||||
|
18 18 | int # comment2
|
||||||
|
19 19 | # comment3
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue