Make Binding::range() point to the range of a type parameter's name, not the full type parameter (#15935)

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
This commit is contained in:
Alex Waygood 2025-02-04 14:14:21 +00:00 committed by GitHub
parent ff87ea8d42
commit f23802e219
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 29 additions and 44 deletions

View file

@ -1759,12 +1759,12 @@ impl<'a> Visitor<'a> for Checker<'a> {
fn visit_type_param(&mut self, type_param: &'a ast::TypeParam) { fn visit_type_param(&mut self, type_param: &'a ast::TypeParam) {
// Step 1: Binding // Step 1: Binding
match type_param { match type_param {
ast::TypeParam::TypeVar(ast::TypeParamTypeVar { name, range, .. }) ast::TypeParam::TypeVar(ast::TypeParamTypeVar { name, .. })
| ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple { name, range, .. }) | ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple { name, .. })
| ast::TypeParam::ParamSpec(ast::TypeParamParamSpec { name, range, .. }) => { | ast::TypeParam::ParamSpec(ast::TypeParamParamSpec { name, .. }) => {
self.add_binding( self.add_binding(
name.as_str(), name.as_str(),
*range, name.range(),
BindingKind::TypeParam, BindingKind::TypeParam,
BindingFlags::empty(), BindingFlags::empty(),
); );

View file

@ -198,7 +198,7 @@ pub(crate) fn custom_type_var_instead_of_self(
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(
CustomTypeVarForSelf { CustomTypeVarForSelf {
typevar_name: custom_typevar.name.to_string(), typevar_name: custom_typevar.name(checker).to_string(),
}, },
diagnostic_range, diagnostic_range,
); );
@ -207,7 +207,7 @@ pub(crate) fn custom_type_var_instead_of_self(
replace_custom_typevar_with_self( replace_custom_typevar_with_self(
checker, checker,
function_def, function_def,
&custom_typevar, custom_typevar,
self_or_cls_parameter, self_or_cls_parameter,
self_or_cls_annotation, self_or_cls_annotation,
function_header_end, function_header_end,
@ -294,14 +294,9 @@ impl ClassMethod<'_> {
return None; return None;
} }
let binding = semantic semantic
.resolve_name(cls_annotation_typevar) .resolve_name(cls_annotation_typevar)
.map(|binding_id| semantic.binding(binding_id))?; .map(|binding_id| TypeVar(semantic.binding(binding_id)))
Some(TypeVar {
name: cls_annotation_typevar_name,
binding,
})
} }
} }
@ -371,14 +366,9 @@ impl InstanceMethod<'_> {
return None; return None;
} }
let binding = semantic semantic
.resolve_name(self_annotation) .resolve_name(self_annotation)
.map(|binding_id| semantic.binding(binding_id))?; .map(|binding_id| TypeVar(semantic.binding(binding_id)))
Some(TypeVar {
name: first_arg_type,
binding,
})
} }
} }
@ -448,10 +438,7 @@ fn custom_typevar_preview<'a>(
.iter() .iter()
.filter_map(ast::TypeParam::as_type_var) .filter_map(ast::TypeParam::as_type_var)
.any(|ast::TypeParamTypeVar { name, .. }| name.id == typevar_expr.id) .any(|ast::TypeParamTypeVar { name, .. }| name.id == typevar_expr.id)
.then_some(TypeVar { .then_some(TypeVar(binding));
name: &typevar_expr.id,
binding,
});
} }
// Example: // Example:
@ -471,10 +458,7 @@ fn custom_typevar_preview<'a>(
semantic semantic
.match_typing_expr(&rhs_function.func, "TypeVar") .match_typing_expr(&rhs_function.func, "TypeVar")
.then_some(TypeVar { .then_some(TypeVar(binding))
name: &typevar_expr.id,
binding,
})
} }
/// Add a "Replace with `Self`" fix that does the following: /// Add a "Replace with `Self`" fix that does the following:
@ -486,7 +470,7 @@ fn custom_typevar_preview<'a>(
fn replace_custom_typevar_with_self( fn replace_custom_typevar_with_self(
checker: &Checker, checker: &Checker,
function_def: &ast::StmtFunctionDef, function_def: &ast::StmtFunctionDef,
custom_typevar: &TypeVar, custom_typevar: TypeVar,
self_or_cls_parameter: &ast::ParameterWithDefault, self_or_cls_parameter: &ast::ParameterWithDefault,
self_or_cls_annotation: &ast::Expr, self_or_cls_annotation: &ast::Expr,
function_header_end: TextSize, function_header_end: TextSize,
@ -576,7 +560,7 @@ fn import_self(checker: &Checker, position: TextSize) -> Result<(Edit, String),
/// Only references within `editable_range` will be modified. /// Only references within `editable_range` will be modified.
/// This ensures that no edit in this series will overlap with other edits. /// This ensures that no edit in this series will overlap with other edits.
fn replace_typevar_usages_with_self<'a>( fn replace_typevar_usages_with_self<'a>(
typevar: &'a TypeVar<'a>, typevar: TypeVar<'a>,
self_or_cls_annotation_range: TextRange, self_or_cls_annotation_range: TextRange,
self_symbol_binding: &'a str, self_symbol_binding: &'a str,
editable_range: TextRange, editable_range: TextRange,
@ -599,10 +583,10 @@ fn replace_typevar_usages_with_self<'a>(
/// Return `None` if we fail to find a `TypeVar` that matches the range of `typevar_binding`. /// Return `None` if we fail to find a `TypeVar` that matches the range of `typevar_binding`.
fn remove_pep695_typevar_declaration( fn remove_pep695_typevar_declaration(
type_params: &ast::TypeParams, type_params: &ast::TypeParams,
custom_typevar: &TypeVar, custom_typevar: TypeVar,
) -> Option<Edit> { ) -> Option<Edit> {
if let [sole_typevar] = &**type_params { if let [sole_typevar] = &**type_params {
return (sole_typevar.range() == custom_typevar.range()) return (sole_typevar.name().range() == custom_typevar.range())
.then(|| Edit::range_deletion(type_params.range)); .then(|| Edit::range_deletion(type_params.range));
} }
@ -625,22 +609,23 @@ fn remove_pep695_typevar_declaration(
Some(Edit::range_deletion(deletion_range)) Some(Edit::range_deletion(deletion_range))
} }
#[derive(Debug)] #[derive(Debug, Copy, Clone)]
struct TypeVar<'a> { struct TypeVar<'a>(&'a Binding<'a>);
name: &'a str,
binding: &'a Binding<'a>,
}
impl TypeVar<'_> { impl<'a> TypeVar<'a> {
const fn is_pep695_typevar(&self) -> bool { const fn is_pep695_typevar(self) -> bool {
self.binding.kind.is_type_param() self.0.kind.is_type_param()
} }
fn references<'a>( fn name(self, checker: &'a Checker) -> &'a str {
&'a self, self.0.name(checker.source())
}
fn references(
self,
semantic: &'a SemanticModel<'a>, semantic: &'a SemanticModel<'a>,
) -> impl Iterator<Item = &'a ResolvedReference> + 'a { ) -> impl Iterator<Item = &'a ResolvedReference> + 'a {
self.binding self.0
.references() .references()
.map(|reference_id| semantic.reference(reference_id)) .map(|reference_id| semantic.reference(reference_id))
} }
@ -648,6 +633,6 @@ impl TypeVar<'_> {
impl Ranged for TypeVar<'_> { impl Ranged for TypeVar<'_> {
fn range(&self) -> TextRange { fn range(&self) -> TextRange {
self.binding.range() self.0.range()
} }
} }