mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-26 11:59:10 +00:00
Add convenience helper methods for AST nodes representing function parameters (#15871)
This commit is contained in:
parent
bcdb3f9840
commit
d9a1034db0
36 changed files with 150 additions and 238 deletions
|
@ -605,7 +605,7 @@ impl<'db> SemanticIndexBuilder<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_parameter(&mut self, parameter: &'db ast::ParameterWithDefault) {
|
fn declare_parameter(&mut self, parameter: &'db ast::ParameterWithDefault) {
|
||||||
let symbol = self.add_symbol(parameter.parameter.name.id().clone());
|
let symbol = self.add_symbol(parameter.name().id().clone());
|
||||||
|
|
||||||
let definition = self.add_definition(symbol, parameter);
|
let definition = self.add_definition(symbol, parameter);
|
||||||
|
|
||||||
|
|
|
@ -1294,7 +1294,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
parameter: &ast::Parameter,
|
parameter: &ast::Parameter,
|
||||||
definition: Definition<'db>,
|
definition: Definition<'db>,
|
||||||
) {
|
) {
|
||||||
if let Some(annotation) = parameter.annotation.as_ref() {
|
if let Some(annotation) = parameter.annotation() {
|
||||||
let _annotated_ty = self.file_expression_type(annotation);
|
let _annotated_ty = self.file_expression_type(annotation);
|
||||||
// TODO `tuple[annotated_ty, ...]`
|
// TODO `tuple[annotated_ty, ...]`
|
||||||
let ty = KnownClass::Tuple.to_instance(self.db());
|
let ty = KnownClass::Tuple.to_instance(self.db());
|
||||||
|
@ -1323,7 +1323,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
parameter: &ast::Parameter,
|
parameter: &ast::Parameter,
|
||||||
definition: Definition<'db>,
|
definition: Definition<'db>,
|
||||||
) {
|
) {
|
||||||
if let Some(annotation) = parameter.annotation.as_ref() {
|
if let Some(annotation) = parameter.annotation() {
|
||||||
let _annotated_ty = self.file_expression_type(annotation);
|
let _annotated_ty = self.file_expression_type(annotation);
|
||||||
// TODO `dict[str, annotated_ty]`
|
// TODO `dict[str, annotated_ty]`
|
||||||
let ty = KnownClass::Dict.to_instance(self.db());
|
let ty = KnownClass::Dict.to_instance(self.db());
|
||||||
|
|
|
@ -93,10 +93,9 @@ impl<'db> Parameters<'db> {
|
||||||
kwarg,
|
kwarg,
|
||||||
range: _,
|
range: _,
|
||||||
} = parameters;
|
} = parameters;
|
||||||
let default_ty = |parameter_with_default: &ast::ParameterWithDefault| {
|
let default_ty = |param: &ast::ParameterWithDefault| {
|
||||||
parameter_with_default
|
param
|
||||||
.default
|
.default()
|
||||||
.as_deref()
|
|
||||||
.map(|default| definition_expression_type(db, definition, default))
|
.map(|default| definition_expression_type(db, definition, default))
|
||||||
};
|
};
|
||||||
let positional_only = posonlyargs.iter().map(|arg| {
|
let positional_only = posonlyargs.iter().map(|arg| {
|
||||||
|
@ -243,8 +242,7 @@ impl<'db> Parameter<'db> {
|
||||||
Self {
|
Self {
|
||||||
name: Some(parameter.name.id.clone()),
|
name: Some(parameter.name.id.clone()),
|
||||||
annotated_ty: parameter
|
annotated_ty: parameter
|
||||||
.annotation
|
.annotation()
|
||||||
.as_deref()
|
|
||||||
.map(|annotation| definition_expression_type(db, definition, annotation)),
|
.map(|annotation| definition_expression_type(db, definition, annotation)),
|
||||||
kind,
|
kind,
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,14 +164,14 @@ fn check_function_parameters(checker: &mut Checker, function_def: &StmtFunctionD
|
||||||
}
|
}
|
||||||
|
|
||||||
for param in function_def.parameters.iter_non_variadic_params() {
|
for param in function_def.parameters.iter_non_variadic_params() {
|
||||||
let param_name = param.parameter.name.as_str();
|
let param_name = param.name();
|
||||||
if REMOVED_CONTEXT_KEYS.contains(¶m_name) {
|
if REMOVED_CONTEXT_KEYS.contains(¶m_name.as_str()) {
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
Airflow3Removal {
|
Airflow3Removal {
|
||||||
deprecated: param_name.to_string(),
|
deprecated: param_name.to_string(),
|
||||||
replacement: Replacement::None,
|
replacement: Replacement::None,
|
||||||
},
|
},
|
||||||
param.parameter.name.range(),
|
param_name.range(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,8 +107,7 @@ pub(crate) fn fastapi_non_annotated_dependency(
|
||||||
.iter()
|
.iter()
|
||||||
.chain(&function_def.parameters.kwonlyargs)
|
.chain(&function_def.parameters.kwonlyargs)
|
||||||
{
|
{
|
||||||
let (Some(annotation), Some(default)) =
|
let (Some(annotation), Some(default)) = (parameter.annotation(), parameter.default())
|
||||||
(¶meter.parameter.annotation, ¶meter.default)
|
|
||||||
else {
|
else {
|
||||||
seen_default |= parameter.default.is_some();
|
seen_default |= parameter.default.is_some();
|
||||||
continue;
|
continue;
|
||||||
|
@ -120,7 +119,7 @@ pub(crate) fn fastapi_non_annotated_dependency(
|
||||||
annotation,
|
annotation,
|
||||||
default,
|
default,
|
||||||
kind: dependency,
|
kind: dependency,
|
||||||
name: ¶meter.parameter.name,
|
name: parameter.name(),
|
||||||
range: parameter.range,
|
range: parameter.range,
|
||||||
};
|
};
|
||||||
seen_default = create_diagnostic(
|
seen_default = create_diagnostic(
|
||||||
|
|
|
@ -183,7 +183,7 @@ pub(crate) fn fastapi_unused_path_parameter(
|
||||||
.parameters
|
.parameters
|
||||||
.posonlyargs
|
.posonlyargs
|
||||||
.iter()
|
.iter()
|
||||||
.any(|arg| arg.parameter.name.as_str() == path_param);
|
.any(|param| param.name() == path_param);
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = Diagnostic::new(
|
||||||
FastApiUnusedPathParameter {
|
FastApiUnusedPathParameter {
|
||||||
|
@ -258,25 +258,17 @@ impl<'a> Dependency<'a> {
|
||||||
/// ): ...
|
/// ): ...
|
||||||
/// ```
|
/// ```
|
||||||
fn from_parameter(
|
fn from_parameter(
|
||||||
parameter_with_default: &'a ParameterWithDefault,
|
parameter: &'a ParameterWithDefault,
|
||||||
semantic: &SemanticModel<'a>,
|
semantic: &SemanticModel<'a>,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let ParameterWithDefault {
|
if let Some(dependency) = parameter
|
||||||
parameter, default, ..
|
.default()
|
||||||
} = parameter_with_default;
|
|
||||||
|
|
||||||
if let Some(dependency) = default
|
|
||||||
.as_deref()
|
|
||||||
.and_then(|default| Self::from_default(default, semantic))
|
.and_then(|default| Self::from_default(default, semantic))
|
||||||
{
|
{
|
||||||
return Some(dependency);
|
return Some(dependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
let Expr::Subscript(ExprSubscript { value, slice, .. }) =
|
let ExprSubscript { value, slice, .. } = parameter.annotation()?.as_subscript_expr()?;
|
||||||
¶meter.annotation.as_deref()?
|
|
||||||
else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
if !semantic.match_typing_expr(value, "Annotated") {
|
if !semantic.match_typing_expr(value, "Annotated") {
|
||||||
return None;
|
return None;
|
||||||
|
@ -327,7 +319,7 @@ impl<'a> Dependency<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let parameter_names = non_posonly_non_variadic_parameters(function_def)
|
let parameter_names = non_posonly_non_variadic_parameters(function_def)
|
||||||
.map(|ParameterWithDefault { parameter, .. }| &*parameter.name)
|
.map(|param| param.name().as_str())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Some(Self::Function(parameter_names))
|
Some(Self::Function(parameter_names))
|
||||||
|
|
|
@ -3,7 +3,7 @@ use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
use ruff_python_ast::helpers::ReturnStatementVisitor;
|
use ruff_python_ast::helpers::ReturnStatementVisitor;
|
||||||
use ruff_python_ast::identifier::Identifier;
|
use ruff_python_ast::identifier::Identifier;
|
||||||
use ruff_python_ast::visitor::Visitor;
|
use ruff_python_ast::visitor::Visitor;
|
||||||
use ruff_python_ast::{self as ast, Expr, ParameterWithDefault, Stmt};
|
use ruff_python_ast::{self as ast, Expr, Stmt};
|
||||||
use ruff_python_semantic::analyze::visibility;
|
use ruff_python_semantic::analyze::visibility;
|
||||||
use ruff_python_semantic::Definition;
|
use ruff_python_semantic::Definition;
|
||||||
use ruff_python_stdlib::typing::simple_magic_return_type;
|
use ruff_python_stdlib::typing::simple_magic_return_type;
|
||||||
|
@ -613,21 +613,17 @@ pub(crate) fn definition(
|
||||||
let is_overridden = visibility::is_override(decorator_list, checker.semantic());
|
let is_overridden = visibility::is_override(decorator_list, checker.semantic());
|
||||||
|
|
||||||
// If this is a non-static method, skip `cls` or `self`.
|
// If this is a non-static method, skip `cls` or `self`.
|
||||||
for ParameterWithDefault {
|
for parameter in parameters.iter_non_variadic_params().skip(usize::from(
|
||||||
parameter,
|
|
||||||
default: _,
|
|
||||||
range: _,
|
|
||||||
} in parameters.iter_non_variadic_params().skip(usize::from(
|
|
||||||
is_method && !visibility::is_staticmethod(decorator_list, checker.semantic()),
|
is_method && !visibility::is_staticmethod(decorator_list, checker.semantic()),
|
||||||
)) {
|
)) {
|
||||||
// ANN401 for dynamically typed parameters
|
// ANN401 for dynamically typed parameters
|
||||||
if let Some(annotation) = ¶meter.annotation {
|
if let Some(annotation) = parameter.annotation() {
|
||||||
has_any_typed_arg = true;
|
has_any_typed_arg = true;
|
||||||
if checker.enabled(Rule::AnyType) && !is_overridden {
|
if checker.enabled(Rule::AnyType) && !is_overridden {
|
||||||
check_dynamically_typed(
|
check_dynamically_typed(
|
||||||
checker,
|
checker,
|
||||||
annotation,
|
annotation,
|
||||||
|| parameter.name.to_string(),
|
|| parameter.name().to_string(),
|
||||||
&mut diagnostics,
|
&mut diagnostics,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -636,14 +632,14 @@ pub(crate) fn definition(
|
||||||
&& checker
|
&& checker
|
||||||
.settings
|
.settings
|
||||||
.dummy_variable_rgx
|
.dummy_variable_rgx
|
||||||
.is_match(¶meter.name))
|
.is_match(parameter.name()))
|
||||||
{
|
{
|
||||||
if checker.enabled(Rule::MissingTypeFunctionArgument) {
|
if checker.enabled(Rule::MissingTypeFunctionArgument) {
|
||||||
diagnostics.push(Diagnostic::new(
|
diagnostics.push(Diagnostic::new(
|
||||||
MissingTypeFunctionArgument {
|
MissingTypeFunctionArgument {
|
||||||
name: parameter.name.to_string(),
|
name: parameter.name().to_string(),
|
||||||
},
|
},
|
||||||
parameter.range(),
|
parameter.parameter.range(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -915,7 +911,7 @@ pub(crate) fn definition(
|
||||||
.posonlyargs
|
.posonlyargs
|
||||||
.first()
|
.first()
|
||||||
.or_else(|| parameters.args.first())
|
.or_else(|| parameters.args.first())
|
||||||
.is_some_and(|first_param| first_param.parameter.annotation.is_some()))
|
.is_some_and(|first_param| first_param.annotation().is_some()))
|
||||||
{
|
{
|
||||||
diagnostics
|
diagnostics
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{Expr, Parameter, ParameterWithDefault, Parameters};
|
use ruff_python_ast::{Expr, Parameter, Parameters};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
|
@ -70,16 +70,11 @@ fn check_password_kwarg(parameter: &Parameter, default: &Expr) -> Option<Diagnos
|
||||||
|
|
||||||
/// S107
|
/// S107
|
||||||
pub(crate) fn hardcoded_password_default(checker: &mut Checker, parameters: &Parameters) {
|
pub(crate) fn hardcoded_password_default(checker: &mut Checker, parameters: &Parameters) {
|
||||||
for ParameterWithDefault {
|
for parameter in parameters.iter_non_variadic_params() {
|
||||||
parameter,
|
let Some(default) = parameter.default() else {
|
||||||
default,
|
|
||||||
range: _,
|
|
||||||
} in parameters.iter_non_variadic_params()
|
|
||||||
{
|
|
||||||
let Some(default) = default else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if let Some(diagnostic) = check_password_kwarg(parameter, default) {
|
if let Some(diagnostic) = check_password_kwarg(¶meter.parameter, default) {
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
|
use ruff_python_ast::identifier::Identifier;
|
||||||
use ruff_python_ast::name::UnqualifiedName;
|
use ruff_python_ast::name::UnqualifiedName;
|
||||||
use ruff_python_ast::{Decorator, ParameterWithDefault, Parameters};
|
use ruff_python_ast::{Decorator, Expr, Parameters};
|
||||||
use ruff_python_semantic::analyze::visibility;
|
use ruff_python_semantic::analyze::visibility;
|
||||||
use ruff_text_size::Ranged;
|
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::rules::flake8_boolean_trap::helpers::is_allowed_func_def;
|
use crate::rules::flake8_boolean_trap::helpers::is_allowed_func_def;
|
||||||
|
@ -115,16 +115,8 @@ pub(crate) fn boolean_default_value_positional_argument(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ParameterWithDefault {
|
for param in parameters.posonlyargs.iter().chain(¶meters.args) {
|
||||||
parameter,
|
if param.default().is_some_and(Expr::is_boolean_literal_expr) {
|
||||||
default,
|
|
||||||
range: _,
|
|
||||||
} in parameters.posonlyargs.iter().chain(¶meters.args)
|
|
||||||
{
|
|
||||||
if default
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|default| default.is_boolean_literal_expr())
|
|
||||||
{
|
|
||||||
// Allow Boolean defaults in setters.
|
// Allow Boolean defaults in setters.
|
||||||
if decorator_list.iter().any(|decorator| {
|
if decorator_list.iter().any(|decorator| {
|
||||||
UnqualifiedName::from_expr(&decorator.expression)
|
UnqualifiedName::from_expr(&decorator.expression)
|
||||||
|
@ -141,7 +133,7 @@ pub(crate) fn boolean_default_value_positional_argument(
|
||||||
|
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
BooleanDefaultValuePositionalArgument,
|
BooleanDefaultValuePositionalArgument,
|
||||||
parameter.name.range(),
|
param.identifier(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use ruff_diagnostics::Diagnostic;
|
use ruff_diagnostics::Diagnostic;
|
||||||
use ruff_diagnostics::Violation;
|
use ruff_diagnostics::Violation;
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
|
use ruff_python_ast::identifier::Identifier;
|
||||||
use ruff_python_ast::name::UnqualifiedName;
|
use ruff_python_ast::name::UnqualifiedName;
|
||||||
use ruff_python_ast::{self as ast, Decorator, Expr, ParameterWithDefault, Parameters};
|
use ruff_python_ast::{self as ast, Decorator, Expr, Parameters};
|
||||||
use ruff_python_semantic::analyze::visibility;
|
use ruff_python_semantic::analyze::visibility;
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
use ruff_text_size::Ranged;
|
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::rules::flake8_boolean_trap::helpers::is_allowed_func_def;
|
use crate::rules::flake8_boolean_trap::helpers::is_allowed_func_def;
|
||||||
|
@ -124,13 +124,8 @@ pub(crate) fn boolean_type_hint_positional_argument(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ParameterWithDefault {
|
for parameter in parameters.posonlyargs.iter().chain(¶meters.args) {
|
||||||
parameter,
|
let Some(annotation) = parameter.annotation() else {
|
||||||
default: _,
|
|
||||||
range: _,
|
|
||||||
} in parameters.posonlyargs.iter().chain(¶meters.args)
|
|
||||||
{
|
|
||||||
let Some(annotation) = parameter.annotation.as_ref() else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if checker.settings.preview.is_enabled() {
|
if checker.settings.preview.is_enabled() {
|
||||||
|
@ -164,7 +159,7 @@ pub(crate) fn boolean_type_hint_positional_argument(
|
||||||
|
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
BooleanTypeHintPositionalArgument,
|
BooleanTypeHintPositionalArgument,
|
||||||
parameter.name.range(),
|
parameter.identifier(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, ParameterWithDefault, Parameters};
|
use ruff_python_ast::{self as ast, Expr, Parameters};
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use ruff_diagnostics::Violation;
|
use ruff_diagnostics::Violation;
|
||||||
|
@ -139,17 +139,12 @@ pub(crate) fn function_call_in_argument_default(checker: &mut Checker, parameter
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut visitor = ArgumentDefaultVisitor::new(checker.semantic(), &extend_immutable_calls);
|
let mut visitor = ArgumentDefaultVisitor::new(checker.semantic(), &extend_immutable_calls);
|
||||||
for ParameterWithDefault {
|
for parameter in parameters.iter_non_variadic_params() {
|
||||||
default,
|
if let Some(default) = parameter.default() {
|
||||||
parameter,
|
if !parameter.annotation().is_some_and(|expr| {
|
||||||
range: _,
|
|
||||||
} in parameters.iter_non_variadic_params()
|
|
||||||
{
|
|
||||||
if let Some(expr) = &default {
|
|
||||||
if !parameter.annotation.as_ref().is_some_and(|expr| {
|
|
||||||
is_immutable_annotation(expr, checker.semantic(), &extend_immutable_calls)
|
is_immutable_annotation(expr, checker.semantic(), &extend_immutable_calls)
|
||||||
}) {
|
}) {
|
||||||
visitor.visit_expr(expr);
|
visitor.visit_expr(default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, ParameterWithDefault};
|
use ruff_python_ast::{self as ast, Expr};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
|
@ -101,13 +101,8 @@ impl<'a> Visitor<'a> for NameFinder<'a> {
|
||||||
visitor::walk_expr(self, body);
|
visitor::walk_expr(self, body);
|
||||||
|
|
||||||
if let Some(parameters) = parameters {
|
if let Some(parameters) = parameters {
|
||||||
for ParameterWithDefault {
|
for parameter in parameters.iter_non_variadic_params() {
|
||||||
parameter,
|
self.names.remove(parameter.name().as_str());
|
||||||
default: _,
|
|
||||||
range: _,
|
|
||||||
} in parameters.iter_non_variadic_params()
|
|
||||||
{
|
|
||||||
self.names.remove(parameter.name.as_str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
use ruff_python_ast::helpers::is_docstring_stmt;
|
use ruff_python_ast::helpers::is_docstring_stmt;
|
||||||
use ruff_python_ast::name::QualifiedName;
|
use ruff_python_ast::name::QualifiedName;
|
||||||
use ruff_python_ast::{self as ast, Expr, Parameter, ParameterWithDefault};
|
use ruff_python_ast::{self as ast, Expr, Parameter};
|
||||||
use ruff_python_codegen::{Generator, Stylist};
|
use ruff_python_codegen::{Generator, Stylist};
|
||||||
use ruff_python_index::Indexer;
|
use ruff_python_index::Indexer;
|
||||||
use ruff_python_semantic::analyze::function_type::is_stub;
|
use ruff_python_semantic::analyze::function_type::is_stub;
|
||||||
|
@ -91,13 +91,8 @@ pub(crate) fn mutable_argument_default(checker: &mut Checker, function_def: &ast
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ParameterWithDefault {
|
for parameter in function_def.parameters.iter_non_variadic_params() {
|
||||||
parameter,
|
let Some(default) = parameter.default() else {
|
||||||
default,
|
|
||||||
range: _,
|
|
||||||
} in function_def.parameters.iter_non_variadic_params()
|
|
||||||
{
|
|
||||||
let Some(default) = default else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -110,7 +105,7 @@ pub(crate) fn mutable_argument_default(checker: &mut Checker, function_def: &ast
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if is_mutable_expr(default, checker.semantic())
|
if is_mutable_expr(default, checker.semantic())
|
||||||
&& !parameter.annotation.as_ref().is_some_and(|expr| {
|
&& !parameter.annotation().is_some_and(|expr| {
|
||||||
is_immutable_annotation(expr, checker.semantic(), extend_immutable_calls.as_slice())
|
is_immutable_annotation(expr, checker.semantic(), extend_immutable_calls.as_slice())
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
|
@ -119,7 +114,7 @@ pub(crate) fn mutable_argument_default(checker: &mut Checker, function_def: &ast
|
||||||
// If the function body is on the same line as the function def, do not fix
|
// If the function body is on the same line as the function def, do not fix
|
||||||
if let Some(fix) = move_initialization(
|
if let Some(fix) = move_initialization(
|
||||||
function_def,
|
function_def,
|
||||||
parameter,
|
¶meter.parameter,
|
||||||
default,
|
default,
|
||||||
checker.semantic(),
|
checker.semantic(),
|
||||||
checker.locator(),
|
checker.locator(),
|
||||||
|
@ -165,12 +160,12 @@ fn move_initialization(
|
||||||
|
|
||||||
// Add an `if`, to set the argument to its original value if still `None`.
|
// Add an `if`, to set the argument to its original value if still `None`.
|
||||||
let mut content = String::new();
|
let mut content = String::new();
|
||||||
content.push_str(&format!("if {} is None:", parameter.name.as_str()));
|
content.push_str(&format!("if {} is None:", parameter.name()));
|
||||||
content.push_str(stylist.line_ending().as_str());
|
content.push_str(stylist.line_ending().as_str());
|
||||||
content.push_str(stylist.indentation());
|
content.push_str(stylist.indentation());
|
||||||
content.push_str(&format!(
|
content.push_str(&format!(
|
||||||
"{} = {}",
|
"{} = {}",
|
||||||
parameter.name.as_str(),
|
parameter.name(),
|
||||||
generator.expr(default)
|
generator.expr(default)
|
||||||
));
|
));
|
||||||
content.push_str(stylist.line_ending().as_str());
|
content.push_str(stylist.line_ending().as_str());
|
||||||
|
|
|
@ -65,7 +65,7 @@ impl Violation for BuiltinArgumentShadowing {
|
||||||
/// A002
|
/// A002
|
||||||
pub(crate) fn builtin_argument_shadowing(checker: &mut Checker, parameter: &Parameter) {
|
pub(crate) fn builtin_argument_shadowing(checker: &mut Checker, parameter: &Parameter) {
|
||||||
if shadows_builtin(
|
if shadows_builtin(
|
||||||
parameter.name.as_str(),
|
parameter.name(),
|
||||||
checker.source_type,
|
checker.source_type,
|
||||||
&checker.settings.flake8_builtins.builtins_ignorelist,
|
&checker.settings.flake8_builtins.builtins_ignorelist,
|
||||||
checker.settings.target_version,
|
checker.settings.target_version,
|
||||||
|
|
|
@ -39,9 +39,9 @@ pub(crate) fn builtin_lambda_argument_shadowing(checker: &mut Checker, lambda: &
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
for param in parameters.iter_non_variadic_params() {
|
for param in parameters.iter_non_variadic_params() {
|
||||||
let name = ¶m.parameter.name;
|
let name = param.name();
|
||||||
if shadows_builtin(
|
if shadows_builtin(
|
||||||
name.as_ref(),
|
name,
|
||||||
checker.source_type,
|
checker.source_type,
|
||||||
&checker.settings.flake8_builtins.builtins_ignorelist,
|
&checker.settings.flake8_builtins.builtins_ignorelist,
|
||||||
checker.settings.target_version,
|
checker.settings.target_version,
|
||||||
|
|
|
@ -68,7 +68,7 @@ pub(crate) fn any_eq_ne_annotation(checker: &mut Checker, name: &str, parameters
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(annotation) = ¶meters.args[1].parameter.annotation else {
|
let Some(annotation) = ¶meters.args[1].annotation() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ pub(crate) fn custom_type_var_return_type(
|
||||||
.iter()
|
.iter()
|
||||||
.chain(¶meters.args)
|
.chain(¶meters.args)
|
||||||
.next()
|
.next()
|
||||||
.and_then(|parameter_with_default| parameter_with_default.parameter.annotation.as_ref())
|
.and_then(|parameter_with_default| parameter_with_default.annotation())
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -341,12 +341,8 @@ fn remove_first_parameter_annotation(parameters: &Parameters) -> Edit {
|
||||||
// The first parameter is guaranteed to be `self`/`cls`,
|
// The first parameter is guaranteed to be `self`/`cls`,
|
||||||
// as verified by `uses_custom_var()`.
|
// as verified by `uses_custom_var()`.
|
||||||
let mut non_variadic_positional = parameters.posonlyargs.iter().chain(¶meters.args);
|
let mut non_variadic_positional = parameters.posonlyargs.iter().chain(¶meters.args);
|
||||||
let first = &non_variadic_positional.next().unwrap().parameter;
|
let first = &non_variadic_positional.next().unwrap();
|
||||||
|
Edit::deletion(first.name().end(), first.end())
|
||||||
let name_end = first.name.range.end();
|
|
||||||
let annotation_end = first.range.end();
|
|
||||||
|
|
||||||
Edit::deletion(name_end, annotation_end)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_return_annotation_with_self(self_symbol_binding: String, returns: &Expr) -> Edit {
|
fn replace_return_annotation_with_self(self_symbol_binding: String, returns: &Expr) -> Edit {
|
||||||
|
|
|
@ -199,8 +199,7 @@ pub(crate) fn bad_exit_annotation(checker: &mut Checker, function: &StmtFunction
|
||||||
fn check_short_args_list(checker: &mut Checker, parameters: &Parameters, func_kind: FuncKind) {
|
fn check_short_args_list(checker: &mut Checker, parameters: &Parameters, func_kind: FuncKind) {
|
||||||
if let Some(varargs) = ¶meters.vararg {
|
if let Some(varargs) = ¶meters.vararg {
|
||||||
if let Some(annotation) = varargs
|
if let Some(annotation) = varargs
|
||||||
.annotation
|
.annotation()
|
||||||
.as_ref()
|
|
||||||
.filter(|ann| !is_object_or_unused(ann, checker.semantic()))
|
.filter(|ann| !is_object_or_unused(ann, checker.semantic()))
|
||||||
{
|
{
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = Diagnostic::new(
|
||||||
|
@ -238,7 +237,7 @@ fn check_short_args_list(checker: &mut Checker, parameters: &Parameters, func_ki
|
||||||
/// (that is not decorated with `@typing.overload`) are annotated correctly.
|
/// (that is not decorated with `@typing.overload`) are annotated correctly.
|
||||||
fn check_positional_args_for_non_overloaded_method(
|
fn check_positional_args_for_non_overloaded_method(
|
||||||
checker: &mut Checker,
|
checker: &mut Checker,
|
||||||
non_self_positional_args: &[&ParameterWithDefault],
|
non_self_positional_params: &[&ParameterWithDefault],
|
||||||
kind: FuncKind,
|
kind: FuncKind,
|
||||||
) {
|
) {
|
||||||
// For each argument, define the predicate against which to check the annotation.
|
// For each argument, define the predicate against which to check the annotation.
|
||||||
|
@ -252,8 +251,10 @@ fn check_positional_args_for_non_overloaded_method(
|
||||||
(ErrorKind::ThirdArgBadAnnotation, is_traceback_type),
|
(ErrorKind::ThirdArgBadAnnotation, is_traceback_type),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (arg, (error_info, predicate)) in non_self_positional_args.iter().take(3).zip(validations) {
|
for (param, (error_info, predicate)) in
|
||||||
let Some(annotation) = arg.parameter.annotation.as_ref() else {
|
non_self_positional_params.iter().take(3).zip(validations)
|
||||||
|
{
|
||||||
|
let Some(annotation) = param.annotation() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -293,11 +294,7 @@ fn check_positional_args_for_overloaded_method(
|
||||||
predicate: impl FnOnce(&Expr) -> bool,
|
predicate: impl FnOnce(&Expr) -> bool,
|
||||||
semantic: &SemanticModel,
|
semantic: &SemanticModel,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
parameter
|
parameter.annotation().map_or(true, |annotation| {
|
||||||
.parameter
|
|
||||||
.annotation
|
|
||||||
.as_ref()
|
|
||||||
.map_or(true, |annotation| {
|
|
||||||
predicate(annotation) || is_object_or_unused(annotation, semantic)
|
predicate(annotation) || is_object_or_unused(annotation, semantic)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ pub(crate) fn pep_484_positional_parameter(
|
||||||
|
|
||||||
/// Returns `true` if the [`ParameterWithDefault`] is an old-style positional-only parameter (i.e.,
|
/// Returns `true` if the [`ParameterWithDefault`] is an old-style positional-only parameter (i.e.,
|
||||||
/// its name starts with `__` and does not end with `__`).
|
/// its name starts with `__` and does not end with `__`).
|
||||||
fn is_old_style_positional_only(arg: &ParameterWithDefault) -> bool {
|
fn is_old_style_positional_only(param: &ParameterWithDefault) -> bool {
|
||||||
let arg_name = &arg.parameter.name;
|
let arg_name = param.name();
|
||||||
arg_name.starts_with("__") && !arg_name.ends_with("__")
|
arg_name.starts_with("__") && !arg_name.ends_with("__")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, Violation};
|
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, Violation};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
use ruff_python_ast::name::QualifiedName;
|
use ruff_python_ast::name::QualifiedName;
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{self as ast, Expr, Operator, Parameters, Stmt, UnaryOp};
|
||||||
self as ast, Expr, Operator, ParameterWithDefault, Parameters, Stmt, UnaryOp,
|
|
||||||
};
|
|
||||||
use ruff_python_semantic::{analyze::class::is_enumeration, ScopeKind, SemanticModel};
|
use ruff_python_semantic::{analyze::class::is_enumeration, ScopeKind, SemanticModel};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
|
@ -489,16 +487,11 @@ fn is_annotatable_type_alias(value: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
|
|
||||||
/// PYI011
|
/// PYI011
|
||||||
pub(crate) fn typed_argument_simple_defaults(checker: &mut Checker, parameters: &Parameters) {
|
pub(crate) fn typed_argument_simple_defaults(checker: &mut Checker, parameters: &Parameters) {
|
||||||
for ParameterWithDefault {
|
for parameter in parameters.iter_non_variadic_params() {
|
||||||
parameter,
|
let Some(default) = parameter.default() else {
|
||||||
default,
|
|
||||||
range: _,
|
|
||||||
} in parameters.iter_non_variadic_params()
|
|
||||||
{
|
|
||||||
let Some(default) = default else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if parameter.annotation.is_some() {
|
if parameter.annotation().is_some() {
|
||||||
if !is_valid_default_value_with_annotation(
|
if !is_valid_default_value_with_annotation(
|
||||||
default,
|
default,
|
||||||
true,
|
true,
|
||||||
|
@ -520,16 +513,11 @@ pub(crate) fn typed_argument_simple_defaults(checker: &mut Checker, parameters:
|
||||||
|
|
||||||
/// PYI014
|
/// PYI014
|
||||||
pub(crate) fn argument_simple_defaults(checker: &mut Checker, parameters: &Parameters) {
|
pub(crate) fn argument_simple_defaults(checker: &mut Checker, parameters: &Parameters) {
|
||||||
for ParameterWithDefault {
|
for parameter in parameters.iter_non_variadic_params() {
|
||||||
parameter,
|
let Some(default) = parameter.default() else {
|
||||||
default,
|
|
||||||
range: _,
|
|
||||||
} in parameters.iter_non_variadic_params()
|
|
||||||
{
|
|
||||||
let Some(default) = default else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if parameter.annotation.is_none() {
|
if parameter.annotation().is_none() {
|
||||||
if !is_valid_default_value_with_annotation(
|
if !is_valid_default_value_with_annotation(
|
||||||
default,
|
default,
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -809,7 +809,7 @@ fn check_fixture_returns(checker: &mut Checker, name: &str, body: &[Stmt], retur
|
||||||
/// PT019
|
/// PT019
|
||||||
fn check_test_function_args(checker: &mut Checker, parameters: &Parameters) {
|
fn check_test_function_args(checker: &mut Checker, parameters: &Parameters) {
|
||||||
for parameter in parameters.iter_non_variadic_params() {
|
for parameter in parameters.iter_non_variadic_params() {
|
||||||
let name = ¶meter.parameter.name;
|
let name = parameter.name();
|
||||||
if name.starts_with('_') {
|
if name.starts_with('_') {
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
PytestFixtureParamWithoutValue {
|
PytestFixtureParamWithoutValue {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::checkers::ast::Checker;
|
||||||
use crate::rules::flake8_pytest_style::rules::helpers::is_likely_pytest_test;
|
use crate::rules::flake8_pytest_style::rules::helpers::is_likely_pytest_test;
|
||||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, Violation};
|
use ruff_diagnostics::{Diagnostic, Edit, Fix, Violation};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
use ruff_python_ast::{ParameterWithDefault, StmtFunctionDef};
|
use ruff_python_ast::StmtFunctionDef;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -58,25 +58,15 @@ pub(crate) fn parameter_with_default_argument(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let parameters = function_def.parameters.as_ref();
|
for parameter in function_def.parameters.iter_non_variadic_params() {
|
||||||
|
let Some(default) = parameter.default() else {
|
||||||
for ParameterWithDefault {
|
|
||||||
parameter,
|
|
||||||
default,
|
|
||||||
range: pwd_range,
|
|
||||||
} in parameters.iter_non_variadic_params()
|
|
||||||
{
|
|
||||||
let Some(default) = default else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
let parameter_name = parameter.name().to_string();
|
||||||
let parameter_name = parameter.name.to_string();
|
|
||||||
let kind = PytestParameterWithDefaultArgument { parameter_name };
|
let kind = PytestParameterWithDefaultArgument { parameter_name };
|
||||||
let diagnostic = Diagnostic::new(kind, default.range());
|
let diagnostic = Diagnostic::new(kind, default.range());
|
||||||
|
let edit = Edit::deletion(parameter.parameter.end(), parameter.end());
|
||||||
let edit = Edit::deletion(parameter.end(), pwd_range.end());
|
|
||||||
let fix = Fix::display_only_edit(edit);
|
let fix = Fix::display_only_edit(edit);
|
||||||
|
|
||||||
checker.diagnostics.push(diagnostic.with_fix(fix));
|
checker.diagnostics.push(diagnostic.with_fix(fix));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -330,11 +330,11 @@ fn call<'a>(
|
||||||
) {
|
) {
|
||||||
diagnostics.extend(parameters.filter_map(|arg| {
|
diagnostics.extend(parameters.filter_map(|arg| {
|
||||||
let binding = scope
|
let binding = scope
|
||||||
.get(arg.name.as_str())
|
.get(arg.name())
|
||||||
.map(|binding_id| semantic.binding(binding_id))?;
|
.map(|binding_id| semantic.binding(binding_id))?;
|
||||||
if binding.kind.is_argument()
|
if binding.kind.is_argument()
|
||||||
&& binding.is_unused()
|
&& binding.is_unused()
|
||||||
&& !dummy_variable_rgx.is_match(arg.name.as_str())
|
&& !dummy_variable_rgx.is_match(arg.name())
|
||||||
{
|
{
|
||||||
Some(Diagnostic::new(
|
Some(Diagnostic::new(
|
||||||
argumentable.check_for(arg.name.to_string()),
|
argumentable.check_for(arg.name.to_string()),
|
||||||
|
|
|
@ -8,7 +8,6 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
use ruff_python_ast::docstrings::{clean_space, leading_space};
|
use ruff_python_ast::docstrings::{clean_space, leading_space};
|
||||||
use ruff_python_ast::identifier::Identifier;
|
use ruff_python_ast::identifier::Identifier;
|
||||||
use ruff_python_ast::ParameterWithDefault;
|
|
||||||
use ruff_python_semantic::analyze::visibility::is_staticmethod;
|
use ruff_python_semantic::analyze::visibility::is_staticmethod;
|
||||||
use ruff_python_trivia::textwrap::dedent;
|
use ruff_python_trivia::textwrap::dedent;
|
||||||
use ruff_source_file::NewlineWithTrailingNewline;
|
use ruff_source_file::NewlineWithTrailingNewline;
|
||||||
|
@ -1791,11 +1790,7 @@ fn missing_args(checker: &mut Checker, docstring: &Docstring, docstrings_args: &
|
||||||
let mut missing_arg_names: FxHashSet<String> = FxHashSet::default();
|
let mut missing_arg_names: FxHashSet<String> = FxHashSet::default();
|
||||||
|
|
||||||
// If this is a non-static method, skip `cls` or `self`.
|
// If this is a non-static method, skip `cls` or `self`.
|
||||||
for ParameterWithDefault {
|
for parameter in function
|
||||||
parameter,
|
|
||||||
default: _,
|
|
||||||
range: _,
|
|
||||||
} in function
|
|
||||||
.parameters
|
.parameters
|
||||||
.iter_non_variadic_params()
|
.iter_non_variadic_params()
|
||||||
.skip(usize::from(
|
.skip(usize::from(
|
||||||
|
@ -1803,7 +1798,7 @@ fn missing_args(checker: &mut Checker, docstring: &Docstring, docstrings_args: &
|
||||||
&& !is_staticmethod(&function.decorator_list, checker.semantic()),
|
&& !is_staticmethod(&function.decorator_list, checker.semantic()),
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
let arg_name = parameter.name.as_str();
|
let arg_name = parameter.name().as_str();
|
||||||
if !arg_name.starts_with('_') && !docstrings_args.contains(arg_name) {
|
if !arg_name.starts_with('_') && !docstrings_args.contains(arg_name) {
|
||||||
missing_arg_names.insert(arg_name.to_string());
|
missing_arg_names.insert(arg_name.to_string());
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,17 +104,11 @@ pub(crate) fn no_self_use(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identify the `self` parameter.
|
// Identify the `self` parameter.
|
||||||
let Some(parameter) = parameters
|
let Some(parameter) = parameters.posonlyargs.iter().chain(¶meters.args).next() else {
|
||||||
.posonlyargs
|
|
||||||
.iter()
|
|
||||||
.chain(¶meters.args)
|
|
||||||
.next()
|
|
||||||
.map(|param| ¶m.parameter)
|
|
||||||
else {
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if parameter.name.as_str() != "self" {
|
if parameter.name() != "self" {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
use ruff_python_ast::{self as ast, Expr, ParameterWithDefault};
|
use ruff_python_ast::{self as ast, Expr};
|
||||||
use ruff_python_semantic::analyze::function_type::{self as function_type, FunctionType};
|
use ruff_python_semantic::analyze::function_type::{self as function_type, FunctionType};
|
||||||
use ruff_python_semantic::ScopeKind;
|
use ruff_python_semantic::ScopeKind;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
@ -82,10 +82,7 @@ pub(crate) fn self_or_cls_assignment(checker: &mut Checker, target: &Expr) {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(ParameterWithDefault {
|
let Some(self_or_cls) = parameters
|
||||||
parameter: self_or_cls,
|
|
||||||
..
|
|
||||||
}) = parameters
|
|
||||||
.posonlyargs
|
.posonlyargs
|
||||||
.first()
|
.first()
|
||||||
.or_else(|| parameters.args.first())
|
.or_else(|| parameters.args.first())
|
||||||
|
@ -102,7 +99,7 @@ pub(crate) fn self_or_cls_assignment(checker: &mut Checker, target: &Expr) {
|
||||||
&checker.settings.pep8_naming.staticmethod_decorators,
|
&checker.settings.pep8_naming.staticmethod_decorators,
|
||||||
);
|
);
|
||||||
|
|
||||||
let method_type = match (function_type, self_or_cls.name.as_str()) {
|
let method_type = match (function_type, self_or_cls.name().as_str()) {
|
||||||
(FunctionType::Method { .. }, "self") => MethodType::Instance,
|
(FunctionType::Method { .. }, "self") => MethodType::Instance,
|
||||||
(FunctionType::ClassMethod { .. }, "cls") => MethodType::Class,
|
(FunctionType::ClassMethod { .. }, "cls") => MethodType::Class,
|
||||||
_ => return,
|
_ => return,
|
||||||
|
|
|
@ -68,12 +68,7 @@ pub(crate) fn too_many_arguments(checker: &mut Checker, function_def: &ast::Stmt
|
||||||
let num_arguments = function_def
|
let num_arguments = function_def
|
||||||
.parameters
|
.parameters
|
||||||
.iter_non_variadic_params()
|
.iter_non_variadic_params()
|
||||||
.filter(|arg| {
|
.filter(|param| !checker.settings.dummy_variable_rgx.is_match(param.name()))
|
||||||
!checker
|
|
||||||
.settings
|
|
||||||
.dummy_variable_rgx
|
|
||||||
.is_match(&arg.parameter.name)
|
|
||||||
})
|
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
if num_arguments <= checker.settings.pylint.max_args {
|
if num_arguments <= checker.settings.pylint.max_args {
|
||||||
|
|
|
@ -72,12 +72,7 @@ pub(crate) fn too_many_positional_arguments(
|
||||||
.posonlyargs
|
.posonlyargs
|
||||||
.iter()
|
.iter()
|
||||||
.chain(&function_def.parameters.args)
|
.chain(&function_def.parameters.args)
|
||||||
.filter(|param| {
|
.filter(|param| !checker.settings.dummy_variable_rgx.is_match(param.name()))
|
||||||
!checker
|
|
||||||
.settings
|
|
||||||
.dummy_variable_rgx
|
|
||||||
.is_match(¶m.parameter.name)
|
|
||||||
})
|
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
if num_positional_args <= checker.settings.pylint.max_positional_args {
|
if num_positional_args <= checker.settings.pylint.max_positional_args {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
use ruff_python_ast::{self as ast, Expr, Parameter, ParameterWithDefault, Stmt};
|
use ruff_python_ast::{self as ast, Expr, Stmt};
|
||||||
use ruff_text_size::{Ranged, TextSize};
|
use ruff_text_size::{Ranged, TextSize};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
@ -90,13 +90,7 @@ pub(crate) fn super_call_with_parameters(checker: &mut Checker, call: &ast::Expr
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extract the name of the first argument to the enclosing function.
|
// Extract the name of the first argument to the enclosing function.
|
||||||
let Some(ParameterWithDefault {
|
let Some(parent_arg) = parent_parameters.args.first() else {
|
||||||
parameter: Parameter {
|
|
||||||
name: parent_arg, ..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
}) = parent_parameters.args.first()
|
|
||||||
else {
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -122,7 +116,7 @@ pub(crate) fn super_call_with_parameters(checker: &mut Checker, call: &ast::Expr
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if !(first_arg_id == parent_name.as_str() && second_arg_id == parent_arg.as_str()) {
|
if !(first_arg_id == parent_name.as_str() && second_arg_id == parent_arg.name().as_str()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
use ruff_python_ast::ExprSubscript;
|
use ruff_python_ast::{Expr, ExprSubscript};
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
|
|
||||||
use crate::{checkers::ast::Checker, settings::types::PythonVersion};
|
use crate::{checkers::ast::Checker, settings::types::PythonVersion};
|
||||||
|
@ -142,7 +142,7 @@ fn in_vararg(expr: &ExprSubscript, semantic: &SemanticModel) -> bool {
|
||||||
.parameters
|
.parameters
|
||||||
.vararg
|
.vararg
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|vararg| vararg.annotation.as_ref())
|
.and_then(|vararg| vararg.annotation())
|
||||||
.and_then(|annotation| annotation.as_subscript_expr())
|
.and_then(Expr::as_subscript_expr)
|
||||||
== Some(expr)
|
== Some(expr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -456,11 +456,11 @@ fn match_arguments(
|
||||||
/// Returns `true` if the given argument is the "same" as the given expression. For example, if
|
/// Returns `true` if the given argument is the "same" as the given expression. For example, if
|
||||||
/// the argument has a default, it is not considered the same as any expression; if both match the
|
/// the argument has a default, it is not considered the same as any expression; if both match the
|
||||||
/// same name, they are considered the same.
|
/// same name, they are considered the same.
|
||||||
fn is_same_expression(arg: &ast::ParameterWithDefault, expr: &Expr) -> bool {
|
fn is_same_expression(param: &ast::ParameterWithDefault, expr: &Expr) -> bool {
|
||||||
if arg.default.is_some() {
|
if param.default.is_some() {
|
||||||
false
|
false
|
||||||
} else if let Expr::Name(name) = expr {
|
} else if let Expr::Name(name) = expr {
|
||||||
name.id == arg.parameter.name.as_str()
|
name.id == param.name().as_str()
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
|
|
||||||
use ruff_python_ast::name::Name;
|
use ruff_python_ast::name::Name;
|
||||||
use ruff_python_ast::{self as ast, Expr, Operator, ParameterWithDefault, Parameters};
|
use ruff_python_ast::{self as ast, Expr, Operator, Parameters};
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
@ -163,21 +163,15 @@ fn generate_fix(checker: &Checker, conversion_type: ConversionType, expr: &Expr)
|
||||||
|
|
||||||
/// RUF013
|
/// RUF013
|
||||||
pub(crate) fn implicit_optional(checker: &mut Checker, parameters: &Parameters) {
|
pub(crate) fn implicit_optional(checker: &mut Checker, parameters: &Parameters) {
|
||||||
for ParameterWithDefault {
|
for parameter in parameters.iter_non_variadic_params() {
|
||||||
parameter,
|
let Some(Expr::NoneLiteral(_)) = parameter.default() else {
|
||||||
default,
|
|
||||||
range: _,
|
|
||||||
} in parameters.iter_non_variadic_params()
|
|
||||||
{
|
|
||||||
let Some(default) = default else { continue };
|
|
||||||
if !default.is_none_literal_expr() {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
};
|
||||||
let Some(annotation) = ¶meter.annotation else {
|
let Some(annotation) = parameter.annotation() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Expr::StringLiteral(string_expr) = annotation.as_ref() {
|
if let Expr::StringLiteral(string_expr) = annotation {
|
||||||
// Quoted annotation.
|
// Quoted annotation.
|
||||||
if let Ok(parsed_annotation) = checker.parse_type_annotation(string_expr) {
|
if let Ok(parsed_annotation) = checker.parse_type_annotation(string_expr) {
|
||||||
let Some(expr) = type_hint_explicitly_allows_none(
|
let Some(expr) = type_hint_explicitly_allows_none(
|
||||||
|
|
|
@ -104,20 +104,21 @@ pub(crate) fn post_init_default(checker: &mut Checker, function_def: &ast::StmtF
|
||||||
let mut stopped_fixes = false;
|
let mut stopped_fixes = false;
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
|
||||||
for ast::ParameterWithDefault {
|
for parameter in function_def.parameters.iter_non_variadic_params() {
|
||||||
parameter,
|
let Some(default) = parameter.default() else {
|
||||||
default,
|
|
||||||
range: _,
|
|
||||||
} in function_def.parameters.iter_non_variadic_params()
|
|
||||||
{
|
|
||||||
let Some(default) = default else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let mut diagnostic = Diagnostic::new(PostInitDefault, default.range());
|
let mut diagnostic = Diagnostic::new(PostInitDefault, default.range());
|
||||||
|
|
||||||
if !stopped_fixes {
|
if !stopped_fixes {
|
||||||
diagnostic.try_set_fix(|| {
|
diagnostic.try_set_fix(|| {
|
||||||
use_initvar(current_scope, function_def, parameter, default, checker)
|
use_initvar(
|
||||||
|
current_scope,
|
||||||
|
function_def,
|
||||||
|
¶meter.parameter,
|
||||||
|
default,
|
||||||
|
checker,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
// Need to stop fixes as soon as there is a parameter we cannot fix.
|
// Need to stop fixes as soon as there is a parameter we cannot fix.
|
||||||
// Otherwise, we risk a syntax error (a parameter without a default
|
// Otherwise, we risk a syntax error (a parameter without a default
|
||||||
|
@ -169,8 +170,7 @@ fn use_initvar(
|
||||||
let line_ending = checker.stylist().line_ending().as_str();
|
let line_ending = checker.stylist().line_ending().as_str();
|
||||||
|
|
||||||
if let Some(annotation) = ¶meter
|
if let Some(annotation) = ¶meter
|
||||||
.annotation
|
.annotation()
|
||||||
.as_deref()
|
|
||||||
.map(|annotation| locator.slice(annotation))
|
.map(|annotation| locator.slice(annotation))
|
||||||
{
|
{
|
||||||
format!("{parameter_name}: {initvar_binding}[{annotation}] = {default}{line_ending}")
|
format!("{parameter_name}: {initvar_binding}[{annotation}] = {default}{line_ending}")
|
||||||
|
|
|
@ -2654,6 +2654,16 @@ pub struct Parameter {
|
||||||
pub annotation: Option<Box<Expr>>,
|
pub annotation: Option<Box<Expr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Parameter {
|
||||||
|
pub const fn name(&self) -> &Identifier {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn annotation(&self) -> Option<&Expr> {
|
||||||
|
self.annotation.as_deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// See also [keyword](https://docs.python.org/3/library/ast.html#ast.keyword)
|
/// See also [keyword](https://docs.python.org/3/library/ast.html#ast.keyword)
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Keyword {
|
pub struct Keyword {
|
||||||
|
@ -3147,6 +3157,20 @@ pub struct ParameterWithDefault {
|
||||||
pub default: Option<Box<Expr>>,
|
pub default: Option<Box<Expr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ParameterWithDefault {
|
||||||
|
pub fn default(&self) -> Option<&Expr> {
|
||||||
|
self.default.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn name(&self) -> &Identifier {
|
||||||
|
self.parameter.name()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn annotation(&self) -> Option<&Expr> {
|
||||||
|
self.parameter.annotation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An AST node used to represent the arguments passed to a function call or class definition.
|
/// An AST node used to represent the arguments passed to a function call or class definition.
|
||||||
///
|
///
|
||||||
/// For example, given:
|
/// For example, given:
|
||||||
|
|
|
@ -798,7 +798,7 @@ fn handle_parameter_comment<'a>(
|
||||||
parameter: &'a Parameter,
|
parameter: &'a Parameter,
|
||||||
source: &str,
|
source: &str,
|
||||||
) -> CommentPlacement<'a> {
|
) -> CommentPlacement<'a> {
|
||||||
if parameter.annotation.as_deref().is_some() {
|
if parameter.annotation().is_some() {
|
||||||
let colon = first_non_trivia_token(parameter.name.end(), source).expect(
|
let colon = first_non_trivia_token(parameter.name.end(), source).expect(
|
||||||
"A annotated parameter should have a colon following its name when it is valid syntax.",
|
"A annotated parameter should have a colon following its name when it is valid syntax.",
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! Analysis rules for the `typing` module.
|
//! Analysis rules for the `typing` module.
|
||||||
|
|
||||||
use ruff_python_ast::helpers::{any_over_expr, is_const_false, map_subscript};
|
use ruff_python_ast::helpers::{any_over_expr, is_const_false, map_subscript};
|
||||||
|
use ruff_python_ast::identifier::Identifier;
|
||||||
use ruff_python_ast::name::QualifiedName;
|
use ruff_python_ast::name::QualifiedName;
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
self as ast, Expr, ExprCall, Int, Operator, ParameterWithDefault, Parameters, Stmt, StmtAssign,
|
self as ast, Expr, ExprCall, Int, Operator, ParameterWithDefault, Parameters, Stmt, StmtAssign,
|
||||||
|
@ -617,7 +618,7 @@ fn check_type<T: TypeChecker>(binding: &Binding, semantic: &SemanticModel) -> bo
|
||||||
let Some(parameter) = find_parameter(parameters, binding) else {
|
let Some(parameter) = find_parameter(parameters, binding) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let Some(ref annotation) = parameter.parameter.annotation else {
|
let Some(annotation) = parameter.annotation() else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
T::match_annotation(annotation, semantic)
|
T::match_annotation(annotation, semantic)
|
||||||
|
@ -1026,7 +1027,7 @@ fn find_parameter<'a>(
|
||||||
) -> Option<&'a ParameterWithDefault> {
|
) -> Option<&'a ParameterWithDefault> {
|
||||||
parameters
|
parameters
|
||||||
.iter_non_variadic_params()
|
.iter_non_variadic_params()
|
||||||
.find(|arg| arg.parameter.name.range() == binding.range())
|
.find(|param| param.identifier() == binding.range())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the [`QualifiedName`] of the value to which the given [`Expr`] is assigned, if any.
|
/// Return the [`QualifiedName`] of the value to which the given [`Expr`] is assigned, if any.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue