mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:18 +00:00
[ty] Improved diagnostic for reassignments of Final
symbols (#19214)
## Summary Implement [this suggestion](https://github.com/astral-sh/ruff/pull/19178#discussion_r2192658146) by @AlexWaygood. 
This commit is contained in:
parent
a8f2c26143
commit
1a099886ab
3 changed files with 60 additions and 15 deletions
|
@ -12,30 +12,47 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/type_qualifiers/final.md
|
|||
## mdtest_snippet.py
|
||||
|
||||
```
|
||||
1 | from typing import Final
|
||||
2 |
|
||||
3 | MY_CONSTANT: Final[int] = 1
|
||||
4 |
|
||||
5 | # more code
|
||||
6 |
|
||||
7 | MY_CONSTANT = 2 # error: [invalid-assignment]
|
||||
1 | from typing import Final
|
||||
2 |
|
||||
3 | MY_CONSTANT: Final[int] = 1
|
||||
4 |
|
||||
5 | # more code
|
||||
6 |
|
||||
7 | MY_CONSTANT = 2 # error: [invalid-assignment]
|
||||
8 | from _stat import ST_INO
|
||||
9 |
|
||||
10 | ST_INO = 1 # error: [invalid-assignment]
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-assignment]: Reassignment of `Final` symbol `MY_CONSTANT` is not allowed
|
||||
--> src/mdtest_snippet.py:3:1
|
||||
--> src/mdtest_snippet.py:3:14
|
||||
|
|
||||
1 | from typing import Final
|
||||
2 |
|
||||
3 | MY_CONSTANT: Final[int] = 1
|
||||
| --------------------------- Original definition
|
||||
| ---------- Symbol declared as `Final` here
|
||||
4 |
|
||||
5 | # more code
|
||||
6 |
|
||||
7 | MY_CONSTANT = 2 # error: [invalid-assignment]
|
||||
| ^^^^^^^^^^^ Reassignment of `Final` symbol
|
||||
| ^^^^^^^^^^^^^^^ Symbol later reassigned here
|
||||
8 | from _stat import ST_INO
|
||||
|
|
||||
info: rule `invalid-assignment` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-assignment]: Reassignment of `Final` symbol `ST_INO` is not allowed
|
||||
--> src/mdtest_snippet.py:10:1
|
||||
|
|
||||
8 | from _stat import ST_INO
|
||||
9 |
|
||||
10 | ST_INO = 1 # error: [invalid-assignment]
|
||||
| ^^^^^^^^^^ Reassignment of `Final` symbol
|
||||
|
|
||||
info: rule `invalid-assignment` is enabled by default
|
||||
|
||||
|
|
|
@ -260,6 +260,8 @@ class C:
|
|||
|
||||
<!-- snapshot-diagnostics -->
|
||||
|
||||
Annotated assignment:
|
||||
|
||||
```py
|
||||
from typing import Final
|
||||
|
||||
|
@ -270,4 +272,12 @@ MY_CONSTANT: Final[int] = 1
|
|||
MY_CONSTANT = 2 # error: [invalid-assignment]
|
||||
```
|
||||
|
||||
Imported `Final` symbol:
|
||||
|
||||
```py
|
||||
from _stat import ST_INO
|
||||
|
||||
ST_INO = 1 # error: [invalid-assignment]
|
||||
```
|
||||
|
||||
[`typing.final`]: https://docs.python.org/3/library/typing.html#typing.Final
|
||||
|
|
|
@ -1663,7 +1663,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
|
||||
if !is_local || previous_definition.is_some() {
|
||||
let place = place_table.place_expr(binding.place(db));
|
||||
if let Some(builder) = self.context.report_lint(&INVALID_ASSIGNMENT, node) {
|
||||
if let Some(builder) = self.context.report_lint(
|
||||
&INVALID_ASSIGNMENT,
|
||||
binding.full_range(self.db(), self.module()),
|
||||
) {
|
||||
let mut diagnostic = builder.into_diagnostic(format_args!(
|
||||
"Reassignment of `Final` symbol `{place}` is not allowed"
|
||||
));
|
||||
|
@ -1676,10 +1679,25 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
// module, but that information is currently not threaded through attribute
|
||||
// lookup.
|
||||
if !previous_definition.kind(db).is_import() {
|
||||
let range = previous_definition.full_range(self.db(), self.module());
|
||||
if let DefinitionKind::AnnotatedAssignment(assignment) =
|
||||
previous_definition.kind(db)
|
||||
{
|
||||
let range = assignment.annotation(self.module()).range();
|
||||
diagnostic.annotate(
|
||||
self.context.secondary(range).message("Original definition"),
|
||||
self.context
|
||||
.secondary(range)
|
||||
.message("Symbol declared as `Final` here"),
|
||||
);
|
||||
} else {
|
||||
let range =
|
||||
previous_definition.full_range(self.db(), self.module());
|
||||
diagnostic.annotate(
|
||||
self.context
|
||||
.secondary(range)
|
||||
.message("Symbol declared as `Final` here"),
|
||||
);
|
||||
}
|
||||
diagnostic.set_primary_message("Symbol later reassigned here");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue