Skip to content

Commit d9a1034

Browse files
authored
Add convenience helper methods for AST nodes representing function parameters (#15871)
1 parent bcdb3f9 commit d9a1034

36 files changed

+150
-238
lines changed

crates/red_knot_python_semantic/src/semantic_index/builder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ impl<'db> SemanticIndexBuilder<'db> {
605605
}
606606

607607
fn declare_parameter(&mut self, parameter: &'db ast::ParameterWithDefault) {
608-
let symbol = self.add_symbol(parameter.parameter.name.id().clone());
608+
let symbol = self.add_symbol(parameter.name().id().clone());
609609

610610
let definition = self.add_definition(symbol, parameter);
611611

crates/red_knot_python_semantic/src/types/infer.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1294,7 +1294,7 @@ impl<'db> TypeInferenceBuilder<'db> {
12941294
parameter: &ast::Parameter,
12951295
definition: Definition<'db>,
12961296
) {
1297-
if let Some(annotation) = parameter.annotation.as_ref() {
1297+
if let Some(annotation) = parameter.annotation() {
12981298
let _annotated_ty = self.file_expression_type(annotation);
12991299
// TODO `tuple[annotated_ty, ...]`
13001300
let ty = KnownClass::Tuple.to_instance(self.db());
@@ -1323,7 +1323,7 @@ impl<'db> TypeInferenceBuilder<'db> {
13231323
parameter: &ast::Parameter,
13241324
definition: Definition<'db>,
13251325
) {
1326-
if let Some(annotation) = parameter.annotation.as_ref() {
1326+
if let Some(annotation) = parameter.annotation() {
13271327
let _annotated_ty = self.file_expression_type(annotation);
13281328
// TODO `dict[str, annotated_ty]`
13291329
let ty = KnownClass::Dict.to_instance(self.db());

crates/red_knot_python_semantic/src/types/signatures.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,9 @@ impl<'db> Parameters<'db> {
9393
kwarg,
9494
range: _,
9595
} = parameters;
96-
let default_ty = |parameter_with_default: &ast::ParameterWithDefault| {
97-
parameter_with_default
98-
.default
99-
.as_deref()
96+
let default_ty = |param: &ast::ParameterWithDefault| {
97+
param
98+
.default()
10099
.map(|default| definition_expression_type(db, definition, default))
101100
};
102101
let positional_only = posonlyargs.iter().map(|arg| {
@@ -243,8 +242,7 @@ impl<'db> Parameter<'db> {
243242
Self {
244243
name: Some(parameter.name.id.clone()),
245244
annotated_ty: parameter
246-
.annotation
247-
.as_deref()
245+
.annotation()
248246
.map(|annotation| definition_expression_type(db, definition, annotation)),
249247
kind,
250248
}

crates/ruff_linter/src/rules/airflow/rules/removal_in_3.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,14 @@ fn check_function_parameters(checker: &mut Checker, function_def: &StmtFunctionD
164164
}
165165

166166
for param in function_def.parameters.iter_non_variadic_params() {
167-
let param_name = param.parameter.name.as_str();
168-
if REMOVED_CONTEXT_KEYS.contains(&param_name) {
167+
let param_name = param.name();
168+
if REMOVED_CONTEXT_KEYS.contains(&param_name.as_str()) {
169169
checker.diagnostics.push(Diagnostic::new(
170170
Airflow3Removal {
171171
deprecated: param_name.to_string(),
172172
replacement: Replacement::None,
173173
},
174-
param.parameter.name.range(),
174+
param_name.range(),
175175
));
176176
}
177177
}

crates/ruff_linter/src/rules/fastapi/rules/fastapi_non_annotated_dependency.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,7 @@ pub(crate) fn fastapi_non_annotated_dependency(
107107
.iter()
108108
.chain(&function_def.parameters.kwonlyargs)
109109
{
110-
let (Some(annotation), Some(default)) =
111-
(&parameter.parameter.annotation, &parameter.default)
110+
let (Some(annotation), Some(default)) = (parameter.annotation(), parameter.default())
112111
else {
113112
seen_default |= parameter.default.is_some();
114113
continue;
@@ -120,7 +119,7 @@ pub(crate) fn fastapi_non_annotated_dependency(
120119
annotation,
121120
default,
122121
kind: dependency,
123-
name: &parameter.parameter.name,
122+
name: parameter.name(),
124123
range: parameter.range,
125124
};
126125
seen_default = create_diagnostic(

crates/ruff_linter/src/rules/fastapi/rules/fastapi_unused_path_parameter.rs

+6-14
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ pub(crate) fn fastapi_unused_path_parameter(
183183
.parameters
184184
.posonlyargs
185185
.iter()
186-
.any(|arg| arg.parameter.name.as_str() == path_param);
186+
.any(|param| param.name() == path_param);
187187

188188
let mut diagnostic = Diagnostic::new(
189189
FastApiUnusedPathParameter {
@@ -258,25 +258,17 @@ impl<'a> Dependency<'a> {
258258
/// ): ...
259259
/// ```
260260
fn from_parameter(
261-
parameter_with_default: &'a ParameterWithDefault,
261+
parameter: &'a ParameterWithDefault,
262262
semantic: &SemanticModel<'a>,
263263
) -> Option<Self> {
264-
let ParameterWithDefault {
265-
parameter, default, ..
266-
} = parameter_with_default;
267-
268-
if let Some(dependency) = default
269-
.as_deref()
264+
if let Some(dependency) = parameter
265+
.default()
270266
.and_then(|default| Self::from_default(default, semantic))
271267
{
272268
return Some(dependency);
273269
}
274270

275-
let Expr::Subscript(ExprSubscript { value, slice, .. }) =
276-
&parameter.annotation.as_deref()?
277-
else {
278-
return None;
279-
};
271+
let ExprSubscript { value, slice, .. } = parameter.annotation()?.as_subscript_expr()?;
280272

281273
if !semantic.match_typing_expr(value, "Annotated") {
282274
return None;
@@ -327,7 +319,7 @@ impl<'a> Dependency<'a> {
327319
};
328320

329321
let parameter_names = non_posonly_non_variadic_parameters(function_def)
330-
.map(|ParameterWithDefault { parameter, .. }| &*parameter.name)
322+
.map(|param| param.name().as_str())
331323
.collect();
332324

333325
Some(Self::Function(parameter_names))

crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use ruff_macros::{derive_message_formats, ViolationMetadata};
33
use ruff_python_ast::helpers::ReturnStatementVisitor;
44
use ruff_python_ast::identifier::Identifier;
55
use ruff_python_ast::visitor::Visitor;
6-
use ruff_python_ast::{self as ast, Expr, ParameterWithDefault, Stmt};
6+
use ruff_python_ast::{self as ast, Expr, Stmt};
77
use ruff_python_semantic::analyze::visibility;
88
use ruff_python_semantic::Definition;
99
use ruff_python_stdlib::typing::simple_magic_return_type;
@@ -613,21 +613,17 @@ pub(crate) fn definition(
613613
let is_overridden = visibility::is_override(decorator_list, checker.semantic());
614614

615615
// If this is a non-static method, skip `cls` or `self`.
616-
for ParameterWithDefault {
617-
parameter,
618-
default: _,
619-
range: _,
620-
} in parameters.iter_non_variadic_params().skip(usize::from(
616+
for parameter in parameters.iter_non_variadic_params().skip(usize::from(
621617
is_method && !visibility::is_staticmethod(decorator_list, checker.semantic()),
622618
)) {
623619
// ANN401 for dynamically typed parameters
624-
if let Some(annotation) = &parameter.annotation {
620+
if let Some(annotation) = parameter.annotation() {
625621
has_any_typed_arg = true;
626622
if checker.enabled(Rule::AnyType) && !is_overridden {
627623
check_dynamically_typed(
628624
checker,
629625
annotation,
630-
|| parameter.name.to_string(),
626+
|| parameter.name().to_string(),
631627
&mut diagnostics,
632628
);
633629
}
@@ -636,14 +632,14 @@ pub(crate) fn definition(
636632
&& checker
637633
.settings
638634
.dummy_variable_rgx
639-
.is_match(&parameter.name))
635+
.is_match(parameter.name()))
640636
{
641637
if checker.enabled(Rule::MissingTypeFunctionArgument) {
642638
diagnostics.push(Diagnostic::new(
643639
MissingTypeFunctionArgument {
644-
name: parameter.name.to_string(),
640+
name: parameter.name().to_string(),
645641
},
646-
parameter.range(),
642+
parameter.parameter.range(),
647643
));
648644
}
649645
}
@@ -915,7 +911,7 @@ pub(crate) fn definition(
915911
.posonlyargs
916912
.first()
917913
.or_else(|| parameters.args.first())
918-
.is_some_and(|first_param| first_param.parameter.annotation.is_some()))
914+
.is_some_and(|first_param| first_param.annotation().is_some()))
919915
{
920916
diagnostics
921917
} else {

crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_password_default.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use ruff_python_ast::{Expr, Parameter, ParameterWithDefault, Parameters};
1+
use ruff_python_ast::{Expr, Parameter, Parameters};
22

33
use ruff_diagnostics::{Diagnostic, Violation};
44
use ruff_macros::{derive_message_formats, ViolationMetadata};
@@ -70,16 +70,11 @@ fn check_password_kwarg(parameter: &Parameter, default: &Expr) -> Option<Diagnos
7070

7171
/// S107
7272
pub(crate) fn hardcoded_password_default(checker: &mut Checker, parameters: &Parameters) {
73-
for ParameterWithDefault {
74-
parameter,
75-
default,
76-
range: _,
77-
} in parameters.iter_non_variadic_params()
78-
{
79-
let Some(default) = default else {
73+
for parameter in parameters.iter_non_variadic_params() {
74+
let Some(default) = parameter.default() else {
8075
continue;
8176
};
82-
if let Some(diagnostic) = check_password_kwarg(parameter, default) {
77+
if let Some(diagnostic) = check_password_kwarg(&parameter.parameter, default) {
8378
checker.diagnostics.push(diagnostic);
8479
}
8580
}

crates/ruff_linter/src/rules/flake8_boolean_trap/rules/boolean_default_value_positional_argument.rs

+5-13
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use ruff_diagnostics::{Diagnostic, Violation};
22
use ruff_macros::{derive_message_formats, ViolationMetadata};
3+
use ruff_python_ast::identifier::Identifier;
34
use ruff_python_ast::name::UnqualifiedName;
4-
use ruff_python_ast::{Decorator, ParameterWithDefault, Parameters};
5+
use ruff_python_ast::{Decorator, Expr, Parameters};
56
use ruff_python_semantic::analyze::visibility;
6-
use ruff_text_size::Ranged;
77

88
use crate::checkers::ast::Checker;
99
use crate::rules::flake8_boolean_trap::helpers::is_allowed_func_def;
@@ -115,16 +115,8 @@ pub(crate) fn boolean_default_value_positional_argument(
115115
return;
116116
}
117117

118-
for ParameterWithDefault {
119-
parameter,
120-
default,
121-
range: _,
122-
} in parameters.posonlyargs.iter().chain(&parameters.args)
123-
{
124-
if default
125-
.as_ref()
126-
.is_some_and(|default| default.is_boolean_literal_expr())
127-
{
118+
for param in parameters.posonlyargs.iter().chain(&parameters.args) {
119+
if param.default().is_some_and(Expr::is_boolean_literal_expr) {
128120
// Allow Boolean defaults in setters.
129121
if decorator_list.iter().any(|decorator| {
130122
UnqualifiedName::from_expr(&decorator.expression)
@@ -141,7 +133,7 @@ pub(crate) fn boolean_default_value_positional_argument(
141133

142134
checker.diagnostics.push(Diagnostic::new(
143135
BooleanDefaultValuePositionalArgument,
144-
parameter.name.range(),
136+
param.identifier(),
145137
));
146138
}
147139
}

crates/ruff_linter/src/rules/flake8_boolean_trap/rules/boolean_type_hint_positional_argument.rs

+5-10
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use ruff_diagnostics::Diagnostic;
22
use ruff_diagnostics::Violation;
33
use ruff_macros::{derive_message_formats, ViolationMetadata};
4+
use ruff_python_ast::identifier::Identifier;
45
use ruff_python_ast::name::UnqualifiedName;
5-
use ruff_python_ast::{self as ast, Decorator, Expr, ParameterWithDefault, Parameters};
6+
use ruff_python_ast::{self as ast, Decorator, Expr, Parameters};
67
use ruff_python_semantic::analyze::visibility;
78
use ruff_python_semantic::SemanticModel;
8-
use ruff_text_size::Ranged;
99

1010
use crate::checkers::ast::Checker;
1111
use crate::rules::flake8_boolean_trap::helpers::is_allowed_func_def;
@@ -124,13 +124,8 @@ pub(crate) fn boolean_type_hint_positional_argument(
124124
return;
125125
}
126126

127-
for ParameterWithDefault {
128-
parameter,
129-
default: _,
130-
range: _,
131-
} in parameters.posonlyargs.iter().chain(&parameters.args)
132-
{
133-
let Some(annotation) = parameter.annotation.as_ref() else {
127+
for parameter in parameters.posonlyargs.iter().chain(&parameters.args) {
128+
let Some(annotation) = parameter.annotation() else {
134129
continue;
135130
};
136131
if checker.settings.preview.is_enabled() {
@@ -164,7 +159,7 @@ pub(crate) fn boolean_type_hint_positional_argument(
164159

165160
checker.diagnostics.push(Diagnostic::new(
166161
BooleanTypeHintPositionalArgument,
167-
parameter.name.range(),
162+
parameter.identifier(),
168163
));
169164
}
170165
}

crates/ruff_linter/src/rules/flake8_bugbear/rules/function_call_in_argument_default.rs

+5-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use ruff_python_ast::{self as ast, Expr, ParameterWithDefault, Parameters};
1+
use ruff_python_ast::{self as ast, Expr, Parameters};
22
use ruff_text_size::{Ranged, TextRange};
33

44
use ruff_diagnostics::Violation;
@@ -139,17 +139,12 @@ pub(crate) fn function_call_in_argument_default(checker: &mut Checker, parameter
139139
.collect();
140140

141141
let mut visitor = ArgumentDefaultVisitor::new(checker.semantic(), &extend_immutable_calls);
142-
for ParameterWithDefault {
143-
default,
144-
parameter,
145-
range: _,
146-
} in parameters.iter_non_variadic_params()
147-
{
148-
if let Some(expr) = &default {
149-
if !parameter.annotation.as_ref().is_some_and(|expr| {
142+
for parameter in parameters.iter_non_variadic_params() {
143+
if let Some(default) = parameter.default() {
144+
if !parameter.annotation().is_some_and(|expr| {
150145
is_immutable_annotation(expr, checker.semantic(), &extend_immutable_calls)
151146
}) {
152-
visitor.visit_expr(expr);
147+
visitor.visit_expr(default);
153148
}
154149
}
155150
}

crates/ruff_linter/src/rules/flake8_bugbear/rules/loop_variable_overrides_iterator.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use ruff_python_ast::{self as ast, Expr, ParameterWithDefault};
1+
use ruff_python_ast::{self as ast, Expr};
22
use rustc_hash::FxHashMap;
33

44
use ruff_diagnostics::{Diagnostic, Violation};
@@ -101,13 +101,8 @@ impl<'a> Visitor<'a> for NameFinder<'a> {
101101
visitor::walk_expr(self, body);
102102

103103
if let Some(parameters) = parameters {
104-
for ParameterWithDefault {
105-
parameter,
106-
default: _,
107-
range: _,
108-
} in parameters.iter_non_variadic_params()
109-
{
110-
self.names.remove(parameter.name.as_str());
104+
for parameter in parameters.iter_non_variadic_params() {
105+
self.names.remove(parameter.name().as_str());
111106
}
112107
}
113108
}

0 commit comments

Comments
 (0)