mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 18:28:24 +00:00
Enable autofix for annotations within 'simple' string literals (#3657)
This commit is contained in:
parent
8593739f88
commit
3a8e98341b
21 changed files with 307 additions and 148 deletions
|
@ -14,6 +14,7 @@ use crate::scope::{
|
|||
ScopeStack, Scopes,
|
||||
};
|
||||
use crate::types::{CallPath, RefEquality};
|
||||
use crate::typing::AnnotationKind;
|
||||
use crate::visibility::{module_visibility, Modifier, VisibleScope};
|
||||
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
|
@ -41,7 +42,7 @@ pub struct Context<'a> {
|
|||
pub visible_scope: VisibleScope,
|
||||
pub in_annotation: bool,
|
||||
pub in_type_definition: bool,
|
||||
pub in_deferred_string_type_definition: bool,
|
||||
pub in_deferred_string_type_definition: Option<AnnotationKind>,
|
||||
pub in_deferred_type_definition: bool,
|
||||
pub in_exception_handler: bool,
|
||||
pub in_literal: bool,
|
||||
|
@ -79,7 +80,7 @@ impl<'a> Context<'a> {
|
|||
},
|
||||
in_annotation: false,
|
||||
in_type_definition: false,
|
||||
in_deferred_string_type_definition: false,
|
||||
in_deferred_string_type_definition: None,
|
||||
in_deferred_type_definition: false,
|
||||
in_exception_handler: false,
|
||||
in_literal: false,
|
||||
|
@ -311,7 +312,7 @@ impl<'a> Context<'a> {
|
|||
pub const fn execution_context(&self) -> ExecutionContext {
|
||||
if self.in_type_checking_block
|
||||
|| self.in_annotation
|
||||
|| self.in_deferred_string_type_definition
|
||||
|| self.in_deferred_string_type_definition.is_some()
|
||||
{
|
||||
ExecutionContext::Typing
|
||||
} else {
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
use rustpython_parser::ast::{Expr, ExprKind};
|
||||
use anyhow::Result;
|
||||
use rustpython_parser as parser;
|
||||
use rustpython_parser::ast::{Expr, ExprKind, Location};
|
||||
|
||||
use ruff_python_stdlib::typing::{PEP_585_BUILTINS_ELIGIBLE, PEP_593_SUBSCRIPTS, SUBSCRIPTS};
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::relocate::relocate_expr;
|
||||
use crate::source_code::Locator;
|
||||
use crate::str;
|
||||
use crate::types::Range;
|
||||
|
||||
pub enum Callable {
|
||||
ForwardRef,
|
||||
|
@ -66,3 +72,48 @@ pub fn is_pep585_builtin(expr: &Expr, context: &Context) -> bool {
|
|||
PEP_585_BUILTINS_ELIGIBLE.contains(&call_path.as_slice())
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(is_macro::Is)]
|
||||
pub enum AnnotationKind {
|
||||
/// The annotation is defined as part a simple string literal,
|
||||
/// e.g. `x: "List[int]" = []`. Annotations within simple literals
|
||||
/// can be accurately located. For example, we can underline specific
|
||||
/// expressions within the annotation and apply automatic fixes, which is
|
||||
/// not possible for complex string literals.
|
||||
Simple,
|
||||
/// The annotation is defined as part of a complex string literal, such as
|
||||
/// a literal containing an implicit concatenation or escaped characters,
|
||||
/// e.g. `x: "List" "[int]" = []`. These are comparatively rare, but valid.
|
||||
Complex,
|
||||
}
|
||||
|
||||
/// Parse a type annotation from a string.
|
||||
pub fn parse_type_annotation(
|
||||
value: &str,
|
||||
range: Range,
|
||||
locator: &Locator,
|
||||
) -> Result<(Expr, AnnotationKind)> {
|
||||
let expression = locator.slice(range);
|
||||
let body = str::raw_contents(expression);
|
||||
if body == value {
|
||||
// The annotation is considered "simple" if and only if the raw representation (e.g.,
|
||||
// `List[int]` within "List[int]") exactly matches the parsed representation. This
|
||||
// isn't the case, e.g., for implicit concatenations, or for annotations that contain
|
||||
// escaped quotes.
|
||||
let leading_quote = str::leading_quote(expression).unwrap();
|
||||
let expr = parser::parse_expression_located(
|
||||
body,
|
||||
"<filename>",
|
||||
Location::new(
|
||||
range.location.row(),
|
||||
range.location.column() + leading_quote.len(),
|
||||
),
|
||||
)?;
|
||||
Ok((expr, AnnotationKind::Simple))
|
||||
} else {
|
||||
// Otherwise, consider this a "complex" annotation.
|
||||
let mut expr = parser::parse_expression(value, "<filename>")?;
|
||||
relocate_expr(&mut expr, range);
|
||||
Ok((expr, AnnotationKind::Complex))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue