mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 04:19:18 +00:00
Rename semantic_model
and model
usages to semantic
(#5097)
## Summary As discussed in Discord, and similar to oxc, we're going to refer to this as `.semantic()` everywhere. While I was auditing usages of `model: &SemanticModel`, I also changed as many function signatures as I could find to consistently take the model as the _last_ argument, rather than the first.
This commit is contained in:
parent
65dbfd2556
commit
bae183b823
209 changed files with 1058 additions and 1167 deletions
File diff suppressed because it is too large
Load diff
|
@ -116,7 +116,7 @@ impl<'a> Importer<'a> {
|
||||||
&self,
|
&self,
|
||||||
import: &StmtImports,
|
import: &StmtImports,
|
||||||
at: TextSize,
|
at: TextSize,
|
||||||
semantic_model: &SemanticModel,
|
semantic: &SemanticModel,
|
||||||
) -> Result<TypingImportEdit> {
|
) -> Result<TypingImportEdit> {
|
||||||
// Generate the modified import statement.
|
// Generate the modified import statement.
|
||||||
let content = autofix::codemods::retain_imports(
|
let content = autofix::codemods::retain_imports(
|
||||||
|
@ -130,7 +130,7 @@ impl<'a> Importer<'a> {
|
||||||
let (type_checking_edit, type_checking) = self.get_or_import_symbol(
|
let (type_checking_edit, type_checking) = self.get_or_import_symbol(
|
||||||
&ImportRequest::import_from("typing", "TYPE_CHECKING"),
|
&ImportRequest::import_from("typing", "TYPE_CHECKING"),
|
||||||
at,
|
at,
|
||||||
semantic_model,
|
semantic,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Add the import to a `TYPE_CHECKING` block.
|
// Add the import to a `TYPE_CHECKING` block.
|
||||||
|
@ -164,11 +164,11 @@ impl<'a> Importer<'a> {
|
||||||
&self,
|
&self,
|
||||||
symbol: &ImportRequest,
|
symbol: &ImportRequest,
|
||||||
at: TextSize,
|
at: TextSize,
|
||||||
semantic_model: &SemanticModel,
|
semantic: &SemanticModel,
|
||||||
) -> Result<(Edit, String), ResolutionError> {
|
) -> Result<(Edit, String), ResolutionError> {
|
||||||
match self.get_symbol(symbol, at, semantic_model) {
|
match self.get_symbol(symbol, at, semantic) {
|
||||||
Some(result) => result,
|
Some(result) => result,
|
||||||
None => self.import_symbol(symbol, at, semantic_model),
|
None => self.import_symbol(symbol, at, semantic),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,11 +177,10 @@ impl<'a> Importer<'a> {
|
||||||
&self,
|
&self,
|
||||||
symbol: &ImportRequest,
|
symbol: &ImportRequest,
|
||||||
at: TextSize,
|
at: TextSize,
|
||||||
semantic_model: &SemanticModel,
|
semantic: &SemanticModel,
|
||||||
) -> Option<Result<(Edit, String), ResolutionError>> {
|
) -> Option<Result<(Edit, String), ResolutionError>> {
|
||||||
// If the symbol is already available in the current scope, use it.
|
// If the symbol is already available in the current scope, use it.
|
||||||
let imported_name =
|
let imported_name = semantic.resolve_qualified_import_name(symbol.module, symbol.member)?;
|
||||||
semantic_model.resolve_qualified_import_name(symbol.module, symbol.member)?;
|
|
||||||
|
|
||||||
// If the symbol source (i.e., the import statement) comes after the current location,
|
// If the symbol source (i.e., the import statement) comes after the current location,
|
||||||
// abort. For example, we could be generating an edit within a function, and the import
|
// abort. For example, we could be generating an edit within a function, and the import
|
||||||
|
@ -196,7 +195,7 @@ impl<'a> Importer<'a> {
|
||||||
|
|
||||||
// If the symbol source (i.e., the import statement) is in a typing-only context, but we're
|
// If the symbol source (i.e., the import statement) is in a typing-only context, but we're
|
||||||
// in a runtime context, abort.
|
// in a runtime context, abort.
|
||||||
if imported_name.context().is_typing() && semantic_model.execution_context().is_runtime() {
|
if imported_name.context().is_typing() && semantic.execution_context().is_runtime() {
|
||||||
return Some(Err(ResolutionError::IncompatibleContext));
|
return Some(Err(ResolutionError::IncompatibleContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,13 +232,13 @@ impl<'a> Importer<'a> {
|
||||||
&self,
|
&self,
|
||||||
symbol: &ImportRequest,
|
symbol: &ImportRequest,
|
||||||
at: TextSize,
|
at: TextSize,
|
||||||
semantic_model: &SemanticModel,
|
semantic: &SemanticModel,
|
||||||
) -> Result<(Edit, String), ResolutionError> {
|
) -> Result<(Edit, String), ResolutionError> {
|
||||||
if let Some(stmt) = self.find_import_from(symbol.module, at) {
|
if let Some(stmt) = self.find_import_from(symbol.module, at) {
|
||||||
// Case 1: `from functools import lru_cache` is in scope, and we're trying to reference
|
// Case 1: `from functools import lru_cache` is in scope, and we're trying to reference
|
||||||
// `functools.cache`; thus, we add `cache` to the import, and return `"cache"` as the
|
// `functools.cache`; thus, we add `cache` to the import, and return `"cache"` as the
|
||||||
// bound name.
|
// bound name.
|
||||||
if semantic_model.is_available(symbol.member) {
|
if semantic.is_available(symbol.member) {
|
||||||
let Ok(import_edit) = self.add_member(stmt, symbol.member) else {
|
let Ok(import_edit) = self.add_member(stmt, symbol.member) else {
|
||||||
return Err(ResolutionError::InvalidEdit);
|
return Err(ResolutionError::InvalidEdit);
|
||||||
};
|
};
|
||||||
|
@ -252,7 +251,7 @@ impl<'a> Importer<'a> {
|
||||||
ImportStyle::Import => {
|
ImportStyle::Import => {
|
||||||
// Case 2a: No `functools` import is in scope; thus, we add `import functools`,
|
// Case 2a: No `functools` import is in scope; thus, we add `import functools`,
|
||||||
// and return `"functools.cache"` as the bound name.
|
// and return `"functools.cache"` as the bound name.
|
||||||
if semantic_model.is_available(symbol.module) {
|
if semantic.is_available(symbol.module) {
|
||||||
let import_edit =
|
let import_edit =
|
||||||
self.add_import(&AnyImport::Import(Import::module(symbol.module)), at);
|
self.add_import(&AnyImport::Import(Import::module(symbol.module)), at);
|
||||||
Ok((
|
Ok((
|
||||||
|
@ -270,7 +269,7 @@ impl<'a> Importer<'a> {
|
||||||
ImportStyle::ImportFrom => {
|
ImportStyle::ImportFrom => {
|
||||||
// Case 2b: No `functools` import is in scope; thus, we add
|
// Case 2b: No `functools` import is in scope; thus, we add
|
||||||
// `from functools import cache`, and return `"cache"` as the bound name.
|
// `from functools import cache`, and return `"cache"` as the bound name.
|
||||||
if semantic_model.is_available(symbol.member) {
|
if semantic.is_available(symbol.member) {
|
||||||
let import_edit = self.add_import(
|
let import_edit = self.add_import(
|
||||||
&AnyImport::ImportFrom(ImportFrom::member(
|
&AnyImport::ImportFrom(ImportFrom::member(
|
||||||
symbol.module,
|
symbol.module,
|
||||||
|
|
|
@ -67,7 +67,7 @@ pub(crate) fn variable_name_task_id(
|
||||||
|
|
||||||
// If the function doesn't come from Airflow, we can't do anything.
|
// If the function doesn't come from Airflow, we can't do anything.
|
||||||
if !checker
|
if !checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| matches!(call_path[0], "airflow"))
|
.map_or(false, |call_path| matches!(call_path[0], "airflow"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ use rustpython_parser::ast::Expr;
|
||||||
|
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
|
|
||||||
pub(super) fn is_sys(model: &SemanticModel, expr: &Expr, target: &str) -> bool {
|
pub(super) fn is_sys(expr: &Expr, target: &str, semantic: &SemanticModel) -> bool {
|
||||||
model
|
semantic
|
||||||
.resolve_call_path(expr)
|
.resolve_call_path(expr)
|
||||||
.map_or(false, |call_path| call_path.as_slice() == ["sys", target])
|
.map_or(false, |call_path| call_path.as_slice() == ["sys", target])
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ impl Violation for SysVersionCmpStr10 {
|
||||||
pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &[Expr]) {
|
pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &[Expr]) {
|
||||||
match left {
|
match left {
|
||||||
Expr::Subscript(ast::ExprSubscript { value, slice, .. })
|
Expr::Subscript(ast::ExprSubscript { value, slice, .. })
|
||||||
if is_sys(checker.semantic_model(), value, "version_info") =>
|
if is_sys(value, "version_info", checker.semantic()) =>
|
||||||
{
|
{
|
||||||
if let Expr::Constant(ast::ExprConstant {
|
if let Expr::Constant(ast::ExprConstant {
|
||||||
value: Constant::Int(i),
|
value: Constant::Int(i),
|
||||||
|
@ -111,7 +111,7 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], compara
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Attribute(ast::ExprAttribute { value, attr, .. })
|
Expr::Attribute(ast::ExprAttribute { value, attr, .. })
|
||||||
if is_sys(checker.semantic_model(), value, "version_info") && attr == "minor" =>
|
if is_sys(value, "version_info", checker.semantic()) && attr == "minor" =>
|
||||||
{
|
{
|
||||||
if let (
|
if let (
|
||||||
[Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE],
|
[Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE],
|
||||||
|
@ -132,7 +132,7 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], compara
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_sys(checker.semantic_model(), left, "version") {
|
if is_sys(left, "version", checker.semantic()) {
|
||||||
if let (
|
if let (
|
||||||
[Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE],
|
[Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE],
|
||||||
[Expr::Constant(ast::ExprConstant {
|
[Expr::Constant(ast::ExprConstant {
|
||||||
|
|
|
@ -18,7 +18,7 @@ impl Violation for SixPY3 {
|
||||||
/// YTT202
|
/// YTT202
|
||||||
pub(crate) fn name_or_attribute(checker: &mut Checker, expr: &Expr) {
|
pub(crate) fn name_or_attribute(checker: &mut Checker, expr: &Expr) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(expr)
|
.resolve_call_path(expr)
|
||||||
.map_or(false, |call_path| call_path.as_slice() == ["six", "PY3"])
|
.map_or(false, |call_path| call_path.as_slice() == ["six", "PY3"])
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,7 +50,7 @@ impl Violation for SysVersionSlice1 {
|
||||||
|
|
||||||
/// YTT101, YTT102, YTT301, YTT303
|
/// YTT101, YTT102, YTT301, YTT303
|
||||||
pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||||
if is_sys(checker.semantic_model(), value, "version") {
|
if is_sys(value, "version", checker.semantic()) {
|
||||||
match slice {
|
match slice {
|
||||||
Expr::Slice(ast::ExprSlice {
|
Expr::Slice(ast::ExprSlice {
|
||||||
lower: None,
|
lower: None,
|
||||||
|
|
|
@ -35,14 +35,14 @@ pub(super) fn match_function_def(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the name of the function, if it's overloaded.
|
/// Return the name of the function, if it's overloaded.
|
||||||
pub(crate) fn overloaded_name(model: &SemanticModel, definition: &Definition) -> Option<String> {
|
pub(crate) fn overloaded_name(definition: &Definition, semantic: &SemanticModel) -> Option<String> {
|
||||||
if let Definition::Member(Member {
|
if let Definition::Member(Member {
|
||||||
kind: MemberKind::Function | MemberKind::NestedFunction | MemberKind::Method,
|
kind: MemberKind::Function | MemberKind::NestedFunction | MemberKind::Method,
|
||||||
stmt,
|
stmt,
|
||||||
..
|
..
|
||||||
}) = definition
|
}) = definition
|
||||||
{
|
{
|
||||||
if visibility::is_overload(model, cast::decorator_list(stmt)) {
|
if visibility::is_overload(cast::decorator_list(stmt), semantic) {
|
||||||
let (name, ..) = match_function_def(stmt);
|
let (name, ..) = match_function_def(stmt);
|
||||||
Some(name.to_string())
|
Some(name.to_string())
|
||||||
} else {
|
} else {
|
||||||
|
@ -56,9 +56,9 @@ pub(crate) fn overloaded_name(model: &SemanticModel, definition: &Definition) ->
|
||||||
/// Return `true` if the definition is the implementation for an overloaded
|
/// Return `true` if the definition is the implementation for an overloaded
|
||||||
/// function.
|
/// function.
|
||||||
pub(crate) fn is_overload_impl(
|
pub(crate) fn is_overload_impl(
|
||||||
model: &SemanticModel,
|
|
||||||
definition: &Definition,
|
definition: &Definition,
|
||||||
overloaded_name: &str,
|
overloaded_name: &str,
|
||||||
|
semantic: &SemanticModel,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Definition::Member(Member {
|
if let Definition::Member(Member {
|
||||||
kind: MemberKind::Function | MemberKind::NestedFunction | MemberKind::Method,
|
kind: MemberKind::Function | MemberKind::NestedFunction | MemberKind::Method,
|
||||||
|
@ -66,7 +66,7 @@ pub(crate) fn is_overload_impl(
|
||||||
..
|
..
|
||||||
}) = definition
|
}) = definition
|
||||||
{
|
{
|
||||||
if visibility::is_overload(model, cast::decorator_list(stmt)) {
|
if visibility::is_overload(cast::decorator_list(stmt), semantic) {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
let (name, ..) = match_function_def(stmt);
|
let (name, ..) = match_function_def(stmt);
|
||||||
|
|
|
@ -431,15 +431,15 @@ fn is_none_returning(body: &[Stmt]) -> bool {
|
||||||
|
|
||||||
/// ANN401
|
/// ANN401
|
||||||
fn check_dynamically_typed<F>(
|
fn check_dynamically_typed<F>(
|
||||||
model: &SemanticModel,
|
|
||||||
annotation: &Expr,
|
annotation: &Expr,
|
||||||
func: F,
|
func: F,
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
is_overridden: bool,
|
is_overridden: bool,
|
||||||
|
semantic: &SemanticModel,
|
||||||
) where
|
) where
|
||||||
F: FnOnce() -> String,
|
F: FnOnce() -> String,
|
||||||
{
|
{
|
||||||
if !is_overridden && model.match_typing_expr(annotation, "Any") {
|
if !is_overridden && semantic.match_typing_expr(annotation, "Any") {
|
||||||
diagnostics.push(Diagnostic::new(
|
diagnostics.push(Diagnostic::new(
|
||||||
AnyType { name: func() },
|
AnyType { name: func() },
|
||||||
annotation.range(),
|
annotation.range(),
|
||||||
|
@ -480,7 +480,7 @@ pub(crate) fn definition(
|
||||||
// unless configured to suppress ANN* for declarations that are fully untyped.
|
// unless configured to suppress ANN* for declarations that are fully untyped.
|
||||||
let mut diagnostics = Vec::new();
|
let mut diagnostics = Vec::new();
|
||||||
|
|
||||||
let is_overridden = visibility::is_override(checker.semantic_model(), decorator_list);
|
let is_overridden = visibility::is_override(decorator_list, checker.semantic());
|
||||||
|
|
||||||
// ANN001, ANN401
|
// ANN001, ANN401
|
||||||
for arg in args
|
for arg in args
|
||||||
|
@ -492,10 +492,7 @@ pub(crate) fn definition(
|
||||||
// If this is a non-static method, skip `cls` or `self`.
|
// If this is a non-static method, skip `cls` or `self`.
|
||||||
usize::from(
|
usize::from(
|
||||||
is_method
|
is_method
|
||||||
&& !visibility::is_staticmethod(
|
&& !visibility::is_staticmethod(cast::decorator_list(stmt), checker.semantic()),
|
||||||
checker.semantic_model(),
|
|
||||||
cast::decorator_list(stmt),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -504,11 +501,11 @@ pub(crate) fn definition(
|
||||||
has_any_typed_arg = true;
|
has_any_typed_arg = true;
|
||||||
if checker.enabled(Rule::AnyType) {
|
if checker.enabled(Rule::AnyType) {
|
||||||
check_dynamically_typed(
|
check_dynamically_typed(
|
||||||
checker.semantic_model(),
|
|
||||||
annotation,
|
annotation,
|
||||||
|| arg.arg.to_string(),
|
|| arg.arg.to_string(),
|
||||||
&mut diagnostics,
|
&mut diagnostics,
|
||||||
is_overridden,
|
is_overridden,
|
||||||
|
checker.semantic(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -535,11 +532,11 @@ pub(crate) fn definition(
|
||||||
if checker.enabled(Rule::AnyType) {
|
if checker.enabled(Rule::AnyType) {
|
||||||
let name = &arg.arg;
|
let name = &arg.arg;
|
||||||
check_dynamically_typed(
|
check_dynamically_typed(
|
||||||
checker.semantic_model(),
|
|
||||||
expr,
|
expr,
|
||||||
|| format!("*{name}"),
|
|| format!("*{name}"),
|
||||||
&mut diagnostics,
|
&mut diagnostics,
|
||||||
is_overridden,
|
is_overridden,
|
||||||
|
checker.semantic(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -567,11 +564,11 @@ pub(crate) fn definition(
|
||||||
if checker.enabled(Rule::AnyType) {
|
if checker.enabled(Rule::AnyType) {
|
||||||
let name = &arg.arg;
|
let name = &arg.arg;
|
||||||
check_dynamically_typed(
|
check_dynamically_typed(
|
||||||
checker.semantic_model(),
|
|
||||||
expr,
|
expr,
|
||||||
|| format!("**{name}"),
|
|| format!("**{name}"),
|
||||||
&mut diagnostics,
|
&mut diagnostics,
|
||||||
is_overridden,
|
is_overridden,
|
||||||
|
checker.semantic(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -592,13 +589,10 @@ pub(crate) fn definition(
|
||||||
}
|
}
|
||||||
|
|
||||||
// ANN101, ANN102
|
// ANN101, ANN102
|
||||||
if is_method
|
if is_method && !visibility::is_staticmethod(cast::decorator_list(stmt), checker.semantic()) {
|
||||||
&& !visibility::is_staticmethod(checker.semantic_model(), cast::decorator_list(stmt))
|
|
||||||
{
|
|
||||||
if let Some(arg) = args.posonlyargs.first().or_else(|| args.args.first()) {
|
if let Some(arg) = args.posonlyargs.first().or_else(|| args.args.first()) {
|
||||||
if arg.annotation.is_none() {
|
if arg.annotation.is_none() {
|
||||||
if visibility::is_classmethod(checker.semantic_model(), cast::decorator_list(stmt))
|
if visibility::is_classmethod(cast::decorator_list(stmt), checker.semantic()) {
|
||||||
{
|
|
||||||
if checker.enabled(Rule::MissingTypeCls) {
|
if checker.enabled(Rule::MissingTypeCls) {
|
||||||
diagnostics.push(Diagnostic::new(
|
diagnostics.push(Diagnostic::new(
|
||||||
MissingTypeCls {
|
MissingTypeCls {
|
||||||
|
@ -628,11 +622,11 @@ pub(crate) fn definition(
|
||||||
has_typed_return = true;
|
has_typed_return = true;
|
||||||
if checker.enabled(Rule::AnyType) {
|
if checker.enabled(Rule::AnyType) {
|
||||||
check_dynamically_typed(
|
check_dynamically_typed(
|
||||||
checker.semantic_model(),
|
|
||||||
expr,
|
expr,
|
||||||
|| name.to_string(),
|
|| name.to_string(),
|
||||||
&mut diagnostics,
|
&mut diagnostics,
|
||||||
is_overridden,
|
is_overridden,
|
||||||
|
checker.semantic(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if !(
|
} else if !(
|
||||||
|
@ -640,9 +634,7 @@ pub(crate) fn definition(
|
||||||
// (explicitly or implicitly).
|
// (explicitly or implicitly).
|
||||||
checker.settings.flake8_annotations.suppress_none_returning && is_none_returning(body)
|
checker.settings.flake8_annotations.suppress_none_returning && is_none_returning(body)
|
||||||
) {
|
) {
|
||||||
if is_method
|
if is_method && visibility::is_classmethod(cast::decorator_list(stmt), checker.semantic()) {
|
||||||
&& visibility::is_classmethod(checker.semantic_model(), cast::decorator_list(stmt))
|
|
||||||
{
|
|
||||||
if checker.enabled(Rule::MissingReturnTypeClassMethod) {
|
if checker.enabled(Rule::MissingReturnTypeClassMethod) {
|
||||||
diagnostics.push(Diagnostic::new(
|
diagnostics.push(Diagnostic::new(
|
||||||
MissingReturnTypeClassMethod {
|
MissingReturnTypeClassMethod {
|
||||||
|
@ -652,7 +644,7 @@ pub(crate) fn definition(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
} else if is_method
|
} else if is_method
|
||||||
&& visibility::is_staticmethod(checker.semantic_model(), cast::decorator_list(stmt))
|
&& visibility::is_staticmethod(cast::decorator_list(stmt), checker.semantic())
|
||||||
{
|
{
|
||||||
if checker.enabled(Rule::MissingReturnTypeStaticMethod) {
|
if checker.enabled(Rule::MissingReturnTypeStaticMethod) {
|
||||||
diagnostics.push(Diagnostic::new(
|
diagnostics.push(Diagnostic::new(
|
||||||
|
|
|
@ -64,9 +64,9 @@ const BLOCKING_HTTP_CALLS: &[&[&str]] = &[
|
||||||
|
|
||||||
/// ASYNC100
|
/// ASYNC100
|
||||||
pub(crate) fn blocking_http_call(checker: &mut Checker, expr: &Expr) {
|
pub(crate) fn blocking_http_call(checker: &mut Checker, expr: &Expr) {
|
||||||
if checker.semantic_model().in_async_context() {
|
if checker.semantic().in_async_context() {
|
||||||
if let Expr::Call(ast::ExprCall { func, .. }) = expr {
|
if let Expr::Call(ast::ExprCall { func, .. }) = expr {
|
||||||
let call_path = checker.semantic_model().resolve_call_path(func);
|
let call_path = checker.semantic().resolve_call_path(func);
|
||||||
let is_blocking =
|
let is_blocking =
|
||||||
call_path.map_or(false, |path| BLOCKING_HTTP_CALLS.contains(&path.as_slice()));
|
call_path.map_or(false, |path| BLOCKING_HTTP_CALLS.contains(&path.as_slice()));
|
||||||
|
|
||||||
|
|
|
@ -56,10 +56,10 @@ const UNSAFE_OS_METHODS: &[&[&str]] = &[
|
||||||
|
|
||||||
/// ASYNC102
|
/// ASYNC102
|
||||||
pub(crate) fn blocking_os_call(checker: &mut Checker, expr: &Expr) {
|
pub(crate) fn blocking_os_call(checker: &mut Checker, expr: &Expr) {
|
||||||
if checker.semantic_model().in_async_context() {
|
if checker.semantic().in_async_context() {
|
||||||
if let Expr::Call(ast::ExprCall { func, .. }) = expr {
|
if let Expr::Call(ast::ExprCall { func, .. }) = expr {
|
||||||
let is_unsafe_os_method = checker
|
let is_unsafe_os_method = checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |path| UNSAFE_OS_METHODS.contains(&path.as_slice()));
|
.map_or(false, |path| UNSAFE_OS_METHODS.contains(&path.as_slice()));
|
||||||
|
|
||||||
|
|
|
@ -59,10 +59,10 @@ const OPEN_SLEEP_OR_SUBPROCESS_CALL: &[&[&str]] = &[
|
||||||
|
|
||||||
/// ASYNC101
|
/// ASYNC101
|
||||||
pub(crate) fn open_sleep_or_subprocess_call(checker: &mut Checker, expr: &Expr) {
|
pub(crate) fn open_sleep_or_subprocess_call(checker: &mut Checker, expr: &Expr) {
|
||||||
if checker.semantic_model().in_async_context() {
|
if checker.semantic().in_async_context() {
|
||||||
if let Expr::Call(ast::ExprCall { func, .. }) = expr {
|
if let Expr::Call(ast::ExprCall { func, .. }) = expr {
|
||||||
let is_open_sleep_or_subprocess_call = checker
|
let is_open_sleep_or_subprocess_call = checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |path| {
|
.map_or(false, |path| {
|
||||||
OPEN_SLEEP_OR_SUBPROCESS_CALL.contains(&path.as_slice())
|
OPEN_SLEEP_OR_SUBPROCESS_CALL.contains(&path.as_slice())
|
||||||
|
|
|
@ -22,20 +22,24 @@ pub(super) fn matches_password_name(string: &str) -> bool {
|
||||||
PASSWORD_CANDIDATE_REGEX.is_match(string)
|
PASSWORD_CANDIDATE_REGEX.is_match(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn is_untyped_exception(type_: Option<&Expr>, model: &SemanticModel) -> bool {
|
pub(super) fn is_untyped_exception(type_: Option<&Expr>, semantic: &SemanticModel) -> bool {
|
||||||
type_.map_or(true, |type_| {
|
type_.map_or(true, |type_| {
|
||||||
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = &type_ {
|
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = &type_ {
|
||||||
elts.iter().any(|type_| {
|
elts.iter().any(|type_| {
|
||||||
model.resolve_call_path(type_).map_or(false, |call_path| {
|
semantic
|
||||||
|
.resolve_call_path(type_)
|
||||||
|
.map_or(false, |call_path| {
|
||||||
|
call_path.as_slice() == ["", "Exception"]
|
||||||
|
|| call_path.as_slice() == ["", "BaseException"]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
semantic
|
||||||
|
.resolve_call_path(type_)
|
||||||
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["", "Exception"]
|
call_path.as_slice() == ["", "Exception"]
|
||||||
|| call_path.as_slice() == ["", "BaseException"]
|
|| call_path.as_slice() == ["", "BaseException"]
|
||||||
})
|
})
|
||||||
})
|
|
||||||
} else {
|
|
||||||
model.resolve_call_path(type_).map_or(false, |call_path| {
|
|
||||||
call_path.as_slice() == ["", "Exception"]
|
|
||||||
|| call_path.as_slice() == ["", "BaseException"]
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ pub(crate) fn bad_file_permissions(
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) {
|
) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| call_path.as_slice() == ["os", "chmod"])
|
.map_or(false, |call_path| call_path.as_slice() == ["os", "chmod"])
|
||||||
{
|
{
|
||||||
|
|
|
@ -60,7 +60,7 @@ fn unparse_string_format_expression(checker: &mut Checker, expr: &Expr) -> Optio
|
||||||
op: Operator::Add | Operator::Mod,
|
op: Operator::Add | Operator::Mod,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let Some(parent) = checker.semantic_model().expr_parent() else {
|
let Some(parent) = checker.semantic().expr_parent() else {
|
||||||
if any_over_expr(expr, &has_string_literal) {
|
if any_over_expr(expr, &has_string_literal) {
|
||||||
return Some(checker.generator().expr(expr));
|
return Some(checker.generator().expr(expr));
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,20 +48,19 @@ pub(crate) fn hashlib_insecure_hash_functions(
|
||||||
args: &[Expr],
|
args: &[Expr],
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) {
|
) {
|
||||||
if let Some(hashlib_call) =
|
if let Some(hashlib_call) = checker
|
||||||
checker
|
.semantic()
|
||||||
.semantic_model()
|
.resolve_call_path(func)
|
||||||
.resolve_call_path(func)
|
.and_then(|call_path| {
|
||||||
.and_then(|call_path| {
|
if call_path.as_slice() == ["hashlib", "new"] {
|
||||||
if call_path.as_slice() == ["hashlib", "new"] {
|
Some(HashlibCall::New)
|
||||||
Some(HashlibCall::New)
|
} else {
|
||||||
} else {
|
WEAK_HASHES
|
||||||
WEAK_HASHES
|
.iter()
|
||||||
.iter()
|
.find(|hash| call_path.as_slice() == ["hashlib", hash])
|
||||||
.find(|hash| call_path.as_slice() == ["hashlib", hash])
|
.map(|hash| HashlibCall::WeakHash(hash))
|
||||||
.map(|hash| HashlibCall::WeakHash(hash))
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
{
|
{
|
||||||
match hashlib_call {
|
match hashlib_call {
|
||||||
HashlibCall::New => {
|
HashlibCall::New => {
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub(crate) fn jinja2_autoescape_false(
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) {
|
) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["jinja2", "Environment"]
|
call_path.as_slice() == ["jinja2", "Environment"]
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub(crate) fn logging_config_insecure_listen(
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) {
|
) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["logging", "config", "listen"]
|
call_path.as_slice() == ["logging", "config", "listen"]
|
||||||
|
|
|
@ -18,7 +18,7 @@ impl Violation for ParamikoCall {
|
||||||
/// S601
|
/// S601
|
||||||
pub(crate) fn paramiko_call(checker: &mut Checker, func: &Expr) {
|
pub(crate) fn paramiko_call(checker: &mut Checker, func: &Expr) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["paramiko", "exec_command"]
|
call_path.as_slice() == ["paramiko", "exec_command"]
|
||||||
|
|
|
@ -44,7 +44,7 @@ pub(crate) fn request_with_no_cert_validation(
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) {
|
) {
|
||||||
if let Some(target) = checker
|
if let Some(target) = checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.and_then(|call_path| {
|
.and_then(|call_path| {
|
||||||
if call_path.len() == 2 {
|
if call_path.len() == 2 {
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub(crate) fn request_without_timeout(
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) {
|
) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
HTTP_VERBS
|
HTTP_VERBS
|
||||||
|
|
|
@ -102,8 +102,8 @@ pub(crate) fn shell_injection(
|
||||||
args: &[Expr],
|
args: &[Expr],
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) {
|
) {
|
||||||
let call_kind = get_call_kind(func, checker.semantic_model());
|
let call_kind = get_call_kind(func, checker.semantic());
|
||||||
let shell_keyword = find_shell_keyword(checker.semantic_model(), keywords);
|
let shell_keyword = find_shell_keyword(keywords, checker.semantic());
|
||||||
|
|
||||||
if matches!(call_kind, Some(CallKind::Subprocess)) {
|
if matches!(call_kind, Some(CallKind::Subprocess)) {
|
||||||
if let Some(arg) = args.first() {
|
if let Some(arg) = args.first() {
|
||||||
|
@ -227,8 +227,8 @@ enum CallKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the [`CallKind`] of the given function call.
|
/// Return the [`CallKind`] of the given function call.
|
||||||
fn get_call_kind(func: &Expr, model: &SemanticModel) -> Option<CallKind> {
|
fn get_call_kind(func: &Expr, semantic: &SemanticModel) -> Option<CallKind> {
|
||||||
model
|
semantic
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.and_then(|call_path| match call_path.as_slice() {
|
.and_then(|call_path| match call_path.as_slice() {
|
||||||
&[module, submodule] => match module {
|
&[module, submodule] => match module {
|
||||||
|
@ -269,14 +269,14 @@ struct ShellKeyword<'a> {
|
||||||
|
|
||||||
/// Return the `shell` keyword argument to the given function call, if any.
|
/// Return the `shell` keyword argument to the given function call, if any.
|
||||||
fn find_shell_keyword<'a>(
|
fn find_shell_keyword<'a>(
|
||||||
model: &SemanticModel,
|
|
||||||
keywords: &'a [Keyword],
|
keywords: &'a [Keyword],
|
||||||
|
semantic: &SemanticModel,
|
||||||
) -> Option<ShellKeyword<'a>> {
|
) -> Option<ShellKeyword<'a>> {
|
||||||
keywords
|
keywords
|
||||||
.iter()
|
.iter()
|
||||||
.find(|keyword| keyword.arg.as_ref().map_or(false, |arg| arg == "shell"))
|
.find(|keyword| keyword.arg.as_ref().map_or(false, |arg| arg == "shell"))
|
||||||
.map(|keyword| ShellKeyword {
|
.map(|keyword| ShellKeyword {
|
||||||
truthiness: Truthiness::from_expr(&keyword.value, |id| model.is_builtin(id)),
|
truthiness: Truthiness::from_expr(&keyword.value, |id| semantic.is_builtin(id)),
|
||||||
keyword,
|
keyword,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub(crate) fn snmp_insecure_version(
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) {
|
) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["pysnmp", "hlapi", "CommunityData"]
|
call_path.as_slice() == ["pysnmp", "hlapi", "CommunityData"]
|
||||||
|
|
|
@ -27,7 +27,7 @@ pub(crate) fn snmp_weak_cryptography(
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) {
|
) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["pysnmp", "hlapi", "UsmUserData"]
|
call_path.as_slice() == ["pysnmp", "hlapi", "UsmUserData"]
|
||||||
|
|
|
@ -470,7 +470,7 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, expr: &Expr) {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(reason) = checker.semantic_model().resolve_call_path(func).and_then(|call_path| {
|
let Some(reason) = checker.semantic().resolve_call_path(func).and_then(|call_path| {
|
||||||
for module in SUSPICIOUS_MEMBERS {
|
for module in SUSPICIOUS_MEMBERS {
|
||||||
for member in module.members {
|
for member in module.members {
|
||||||
if call_path.as_slice() == *member {
|
if call_path.as_slice() == *member {
|
||||||
|
|
|
@ -27,7 +27,7 @@ pub(crate) fn try_except_continue(
|
||||||
) {
|
) {
|
||||||
if body.len() == 1
|
if body.len() == 1
|
||||||
&& body[0].is_continue_stmt()
|
&& body[0].is_continue_stmt()
|
||||||
&& (check_typed_exception || is_untyped_exception(type_, checker.semantic_model()))
|
&& (check_typed_exception || is_untyped_exception(type_, checker.semantic()))
|
||||||
{
|
{
|
||||||
checker
|
checker
|
||||||
.diagnostics
|
.diagnostics
|
||||||
|
|
|
@ -27,7 +27,7 @@ pub(crate) fn try_except_pass(
|
||||||
) {
|
) {
|
||||||
if body.len() == 1
|
if body.len() == 1
|
||||||
&& body[0].is_pass_stmt()
|
&& body[0].is_pass_stmt()
|
||||||
&& (check_typed_exception || is_untyped_exception(type_, checker.semantic_model()))
|
&& (check_typed_exception || is_untyped_exception(type_, checker.semantic()))
|
||||||
{
|
{
|
||||||
checker
|
checker
|
||||||
.diagnostics
|
.diagnostics
|
||||||
|
|
|
@ -38,14 +38,14 @@ pub(crate) fn unsafe_yaml_load(
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) {
|
) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| call_path.as_slice() == ["yaml", "load"])
|
.map_or(false, |call_path| call_path.as_slice() == ["yaml", "load"])
|
||||||
{
|
{
|
||||||
let call_args = SimpleCallArgs::new(args, keywords);
|
let call_args = SimpleCallArgs::new(args, keywords);
|
||||||
if let Some(loader_arg) = call_args.argument("Loader", 1) {
|
if let Some(loader_arg) = call_args.argument("Loader", 1) {
|
||||||
if !checker
|
if !checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(loader_arg)
|
.resolve_call_path(loader_arg)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["yaml", "SafeLoader"]
|
call_path.as_slice() == ["yaml", "SafeLoader"]
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub(crate) fn blind_except(
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
for exception in ["BaseException", "Exception"] {
|
for exception in ["BaseException", "Exception"] {
|
||||||
if id == exception && checker.semantic_model().is_builtin(exception) {
|
if id == exception && checker.semantic().is_builtin(exception) {
|
||||||
// If the exception is re-raised, don't flag an error.
|
// If the exception is re-raised, don't flag an error.
|
||||||
if body.iter().any(|stmt| {
|
if body.iter().any(|stmt| {
|
||||||
if let Stmt::Raise(ast::StmtRaise { exc, .. }) = stmt {
|
if let Stmt::Raise(ast::StmtRaise { exc, .. }) = stmt {
|
||||||
|
@ -58,7 +58,7 @@ pub(crate) fn blind_except(
|
||||||
if body.iter().any(|stmt| {
|
if body.iter().any(|stmt| {
|
||||||
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt {
|
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt {
|
||||||
if let Expr::Call(ast::ExprCall { func, keywords, .. }) = value.as_ref() {
|
if let Expr::Call(ast::ExprCall { func, keywords, .. }) = value.as_ref() {
|
||||||
if logging::is_logger_candidate(func, checker.semantic_model()) {
|
if logging::is_logger_candidate(func, checker.semantic()) {
|
||||||
if let Some(attribute) = func.as_attribute_expr() {
|
if let Some(attribute) = func.as_attribute_expr() {
|
||||||
let attr = attribute.attr.as_str();
|
let attr = attribute.attr.as_str();
|
||||||
if attr == "exception" {
|
if attr == "exception" {
|
||||||
|
|
|
@ -36,16 +36,16 @@ impl Violation for EmptyMethodWithoutAbstractDecorator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_abc_class(model: &SemanticModel, bases: &[Expr], keywords: &[Keyword]) -> bool {
|
fn is_abc_class(bases: &[Expr], keywords: &[Keyword], semantic: &SemanticModel) -> bool {
|
||||||
keywords.iter().any(|keyword| {
|
keywords.iter().any(|keyword| {
|
||||||
keyword.arg.as_ref().map_or(false, |arg| arg == "metaclass")
|
keyword.arg.as_ref().map_or(false, |arg| arg == "metaclass")
|
||||||
&& model
|
&& semantic
|
||||||
.resolve_call_path(&keyword.value)
|
.resolve_call_path(&keyword.value)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["abc", "ABCMeta"]
|
call_path.as_slice() == ["abc", "ABCMeta"]
|
||||||
})
|
})
|
||||||
}) || bases.iter().any(|base| {
|
}) || bases.iter().any(|base| {
|
||||||
model
|
semantic
|
||||||
.resolve_call_path(base)
|
.resolve_call_path(base)
|
||||||
.map_or(false, |call_path| call_path.as_slice() == ["abc", "ABC"])
|
.map_or(false, |call_path| call_path.as_slice() == ["abc", "ABC"])
|
||||||
})
|
})
|
||||||
|
@ -80,7 +80,7 @@ pub(crate) fn abstract_base_class(
|
||||||
if bases.len() + keywords.len() != 1 {
|
if bases.len() + keywords.len() != 1 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if !is_abc_class(checker.semantic_model(), bases, keywords) {
|
if !is_abc_class(bases, keywords, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ pub(crate) fn abstract_base_class(
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let has_abstract_decorator = is_abstract(checker.semantic_model(), decorator_list);
|
let has_abstract_decorator = is_abstract(decorator_list, checker.semantic());
|
||||||
has_abstract_method |= has_abstract_decorator;
|
has_abstract_method |= has_abstract_decorator;
|
||||||
|
|
||||||
if !checker.enabled(Rule::EmptyMethodWithoutAbstractDecorator) {
|
if !checker.enabled(Rule::EmptyMethodWithoutAbstractDecorator) {
|
||||||
|
@ -118,7 +118,7 @@ pub(crate) fn abstract_base_class(
|
||||||
|
|
||||||
if !has_abstract_decorator
|
if !has_abstract_decorator
|
||||||
&& is_empty_body(body)
|
&& is_empty_body(body)
|
||||||
&& !is_overload(checker.semantic_model(), decorator_list)
|
&& !is_overload(decorator_list, checker.semantic())
|
||||||
{
|
{
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
EmptyMethodWithoutAbstractDecorator {
|
EmptyMethodWithoutAbstractDecorator {
|
||||||
|
|
|
@ -66,7 +66,7 @@ pub(crate) fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items:
|
||||||
}
|
}
|
||||||
|
|
||||||
if !checker
|
if !checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(args.first().unwrap())
|
.resolve_call_path(args.first().unwrap())
|
||||||
.map_or(false, |call_path| call_path.as_slice() == ["", "Exception"])
|
.map_or(false, |call_path| call_path.as_slice() == ["", "Exception"])
|
||||||
{
|
{
|
||||||
|
@ -78,7 +78,7 @@ pub(crate) fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items:
|
||||||
{
|
{
|
||||||
AssertionKind::AssertRaises
|
AssertionKind::AssertRaises
|
||||||
} else if checker
|
} else if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["pytest", "raises"]
|
call_path.as_slice() == ["pytest", "raises"]
|
||||||
|
|
|
@ -18,8 +18,8 @@ impl Violation for CachedInstanceMethod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_cache_func(model: &SemanticModel, expr: &Expr) -> bool {
|
fn is_cache_func(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
model.resolve_call_path(expr).map_or(false, |call_path| {
|
semantic.resolve_call_path(expr).map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["functools", "lru_cache"]
|
call_path.as_slice() == ["functools", "lru_cache"]
|
||||||
|| call_path.as_slice() == ["functools", "cache"]
|
|| call_path.as_slice() == ["functools", "cache"]
|
||||||
})
|
})
|
||||||
|
@ -27,7 +27,7 @@ fn is_cache_func(model: &SemanticModel, expr: &Expr) -> bool {
|
||||||
|
|
||||||
/// B019
|
/// B019
|
||||||
pub(crate) fn cached_instance_method(checker: &mut Checker, decorator_list: &[Decorator]) {
|
pub(crate) fn cached_instance_method(checker: &mut Checker, decorator_list: &[Decorator]) {
|
||||||
if !checker.semantic_model().scope().kind.is_class() {
|
if !checker.semantic().scope().kind.is_class() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for decorator in decorator_list {
|
for decorator in decorator_list {
|
||||||
|
@ -41,11 +41,11 @@ pub(crate) fn cached_instance_method(checker: &mut Checker, decorator_list: &[De
|
||||||
}
|
}
|
||||||
for decorator in decorator_list {
|
for decorator in decorator_list {
|
||||||
if is_cache_func(
|
if is_cache_func(
|
||||||
checker.semantic_model(),
|
|
||||||
match &decorator.expression {
|
match &decorator.expression {
|
||||||
Expr::Call(ast::ExprCall { func, .. }) => func,
|
Expr::Call(ast::ExprCall { func, .. }) => func,
|
||||||
_ => &decorator.expression,
|
_ => &decorator.expression,
|
||||||
},
|
},
|
||||||
|
checker.semantic(),
|
||||||
) {
|
) {
|
||||||
checker
|
checker
|
||||||
.diagnostics
|
.diagnostics
|
||||||
|
|
|
@ -73,7 +73,7 @@ impl Violation for FunctionCallInDefaultArgument {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ArgumentDefaultVisitor<'a> {
|
struct ArgumentDefaultVisitor<'a> {
|
||||||
model: &'a SemanticModel<'a>,
|
semantic: &'a SemanticModel<'a>,
|
||||||
extend_immutable_calls: Vec<CallPath<'a>>,
|
extend_immutable_calls: Vec<CallPath<'a>>,
|
||||||
diagnostics: Vec<(DiagnosticKind, TextRange)>,
|
diagnostics: Vec<(DiagnosticKind, TextRange)>,
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ struct ArgumentDefaultVisitor<'a> {
|
||||||
impl<'a> ArgumentDefaultVisitor<'a> {
|
impl<'a> ArgumentDefaultVisitor<'a> {
|
||||||
fn new(model: &'a SemanticModel<'a>, extend_immutable_calls: Vec<CallPath<'a>>) -> Self {
|
fn new(model: &'a SemanticModel<'a>, extend_immutable_calls: Vec<CallPath<'a>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
model,
|
semantic: model,
|
||||||
extend_immutable_calls,
|
extend_immutable_calls,
|
||||||
diagnostics: Vec::new(),
|
diagnostics: Vec::new(),
|
||||||
}
|
}
|
||||||
|
@ -95,8 +95,8 @@ where
|
||||||
fn visit_expr(&mut self, expr: &'b Expr) {
|
fn visit_expr(&mut self, expr: &'b Expr) {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Call(ast::ExprCall { func, .. }) => {
|
Expr::Call(ast::ExprCall { func, .. }) => {
|
||||||
if !is_mutable_func(self.model, func)
|
if !is_mutable_func(func, self.semantic)
|
||||||
&& !is_immutable_func(self.model, func, &self.extend_immutable_calls)
|
&& !is_immutable_func(func, self.semantic, &self.extend_immutable_calls)
|
||||||
{
|
{
|
||||||
self.diagnostics.push((
|
self.diagnostics.push((
|
||||||
FunctionCallInDefaultArgument {
|
FunctionCallInDefaultArgument {
|
||||||
|
@ -125,8 +125,7 @@ pub(crate) fn function_call_argument_default(checker: &mut Checker, arguments: &
|
||||||
.map(|target| from_qualified_name(target))
|
.map(|target| from_qualified_name(target))
|
||||||
.collect();
|
.collect();
|
||||||
let diagnostics = {
|
let diagnostics = {
|
||||||
let mut visitor =
|
let mut visitor = ArgumentDefaultVisitor::new(checker.semantic(), extend_immutable_calls);
|
||||||
ArgumentDefaultVisitor::new(checker.semantic_model(), extend_immutable_calls);
|
|
||||||
for expr in arguments
|
for expr in arguments
|
||||||
.defaults
|
.defaults
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -26,15 +26,15 @@ const MUTABLE_FUNCS: &[&[&str]] = &[
|
||||||
&["collections", "deque"],
|
&["collections", "deque"],
|
||||||
];
|
];
|
||||||
|
|
||||||
pub(crate) fn is_mutable_func(model: &SemanticModel, func: &Expr) -> bool {
|
pub(crate) fn is_mutable_func(func: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
model.resolve_call_path(func).map_or(false, |call_path| {
|
semantic.resolve_call_path(func).map_or(false, |call_path| {
|
||||||
MUTABLE_FUNCS
|
MUTABLE_FUNCS
|
||||||
.iter()
|
.iter()
|
||||||
.any(|target| call_path.as_slice() == *target)
|
.any(|target| call_path.as_slice() == *target)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_mutable_expr(model: &SemanticModel, expr: &Expr) -> bool {
|
fn is_mutable_expr(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::List(_)
|
Expr::List(_)
|
||||||
| Expr::Dict(_)
|
| Expr::Dict(_)
|
||||||
|
@ -42,7 +42,7 @@ fn is_mutable_expr(model: &SemanticModel, expr: &Expr) -> bool {
|
||||||
| Expr::ListComp(_)
|
| Expr::ListComp(_)
|
||||||
| Expr::DictComp(_)
|
| Expr::DictComp(_)
|
||||||
| Expr::SetComp(_) => true,
|
| Expr::SetComp(_) => true,
|
||||||
Expr::Call(ast::ExprCall { func, .. }) => is_mutable_func(model, func),
|
Expr::Call(ast::ExprCall { func, .. }) => is_mutable_func(func, semantic),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,9 +64,9 @@ pub(crate) fn mutable_argument_default(checker: &mut Checker, arguments: &Argume
|
||||||
.zip(arguments.defaults.iter().rev()),
|
.zip(arguments.defaults.iter().rev()),
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if is_mutable_expr(checker.semantic_model(), default)
|
if is_mutable_expr(default, checker.semantic())
|
||||||
&& !arg.annotation.as_ref().map_or(false, |expr| {
|
&& !arg.annotation.as_ref().map_or(false, |expr| {
|
||||||
is_immutable_annotation(checker.semantic_model(), expr)
|
is_immutable_annotation(expr, checker.semantic())
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
checker
|
checker
|
||||||
|
|
|
@ -45,7 +45,7 @@ pub(crate) fn no_explicit_stacklevel(
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) {
|
) {
|
||||||
if !checker
|
if !checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["warnings", "warn"]
|
call_path.as_slice() == ["warnings", "warn"]
|
||||||
|
|
|
@ -342,7 +342,7 @@ pub(crate) fn reuse_of_groupby_generator(
|
||||||
};
|
};
|
||||||
// Check if the function call is `itertools.groupby`
|
// Check if the function call is `itertools.groupby`
|
||||||
if !checker
|
if !checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["itertools", "groupby"]
|
call_path.as_slice() == ["itertools", "groupby"]
|
||||||
|
|
|
@ -75,7 +75,7 @@ pub(crate) fn setattr_with_constant(
|
||||||
if let Stmt::Expr(ast::StmtExpr {
|
if let Stmt::Expr(ast::StmtExpr {
|
||||||
value: child,
|
value: child,
|
||||||
range: _,
|
range: _,
|
||||||
}) = checker.semantic_model().stmt()
|
}) = checker.semantic().stmt()
|
||||||
{
|
{
|
||||||
if expr == child.as_ref() {
|
if expr == child.as_ref() {
|
||||||
let mut diagnostic = Diagnostic::new(SetAttrWithConstant, expr.range());
|
let mut diagnostic = Diagnostic::new(SetAttrWithConstant, expr.range());
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use rustpython_parser::ast::{self, Expr, Ranged, Stmt};
|
use rustpython_parser::ast::{self, Expr, Ranged, Stmt};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
@ -30,7 +29,7 @@ use ruff_python_ast::{helpers, visitor};
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
use crate::registry::AsRule;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, result_like::BoolLike)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, result_like::BoolLike)]
|
||||||
enum Certainty {
|
enum Certainty {
|
||||||
Certain,
|
Certain,
|
||||||
Uncertain,
|
Uncertain,
|
||||||
|
@ -129,7 +128,7 @@ pub(crate) fn unused_loop_control_variable(checker: &mut Checker, target: &Expr,
|
||||||
|
|
||||||
// Avoid fixing any variables that _may_ be used, but undetectably so.
|
// Avoid fixing any variables that _may_ be used, but undetectably so.
|
||||||
let certainty = Certainty::from(!helpers::uses_magic_variable_access(body, |id| {
|
let certainty = Certainty::from(!helpers::uses_magic_variable_access(body, |id| {
|
||||||
checker.semantic_model().is_builtin(id)
|
checker.semantic().is_builtin(id)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Attempt to rename the variable by prepending an underscore, but avoid
|
// Attempt to rename the variable by prepending an underscore, but avoid
|
||||||
|
@ -154,10 +153,10 @@ pub(crate) fn unused_loop_control_variable(checker: &mut Checker, target: &Expr,
|
||||||
if certainty.into() && checker.patch(diagnostic.kind.rule()) {
|
if certainty.into() && checker.patch(diagnostic.kind.rule()) {
|
||||||
// Avoid fixing if the variable, or any future bindings to the variable, are
|
// Avoid fixing if the variable, or any future bindings to the variable, are
|
||||||
// used _after_ the loop.
|
// used _after_ the loop.
|
||||||
let scope = checker.semantic_model().scope();
|
let scope = checker.semantic().scope();
|
||||||
if scope
|
if scope
|
||||||
.get_all(name)
|
.get_all(name)
|
||||||
.map(|binding_id| checker.semantic_model().binding(binding_id))
|
.map(|binding_id| checker.semantic().binding(binding_id))
|
||||||
.all(|binding| !binding.is_used())
|
.all(|binding| !binding.is_used())
|
||||||
{
|
{
|
||||||
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
|
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
|
||||||
|
|
|
@ -27,7 +27,7 @@ pub(crate) fn useless_contextlib_suppress(
|
||||||
) {
|
) {
|
||||||
if args.is_empty()
|
if args.is_empty()
|
||||||
&& checker
|
&& checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["contextlib", "suppress"]
|
call_path.as_slice() == ["contextlib", "suppress"]
|
||||||
|
|
|
@ -53,7 +53,7 @@ pub(crate) fn useless_expression(checker: &mut Checker, value: &Expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore statements that have side effects.
|
// Ignore statements that have side effects.
|
||||||
if contains_effect(value, |id| checker.semantic_model().is_builtin(id)) {
|
if contains_effect(value, |id| checker.semantic().is_builtin(id)) {
|
||||||
// Flag attributes as useless expressions, even if they're attached to calls or other
|
// Flag attributes as useless expressions, even if they're attached to calls or other
|
||||||
// expressions.
|
// expressions.
|
||||||
if matches!(value, Expr::Attribute(_)) {
|
if matches!(value, Expr::Attribute(_)) {
|
||||||
|
|
|
@ -27,13 +27,13 @@ pub(crate) fn zip_without_explicit_strict(
|
||||||
) {
|
) {
|
||||||
if let Expr::Name(ast::ExprName { id, .. }) = func {
|
if let Expr::Name(ast::ExprName { id, .. }) = func {
|
||||||
if id == "zip"
|
if id == "zip"
|
||||||
&& checker.semantic_model().is_builtin("zip")
|
&& checker.semantic().is_builtin("zip")
|
||||||
&& !kwargs
|
&& !kwargs
|
||||||
.iter()
|
.iter()
|
||||||
.any(|keyword| keyword.arg.as_ref().map_or(false, |name| name == "strict"))
|
.any(|keyword| keyword.arg.as_ref().map_or(false, |name| name == "strict"))
|
||||||
&& !args
|
&& !args
|
||||||
.iter()
|
.iter()
|
||||||
.any(|arg| is_infinite_iterator(arg, checker.semantic_model()))
|
.any(|arg| is_infinite_iterator(arg, checker.semantic()))
|
||||||
{
|
{
|
||||||
checker
|
checker
|
||||||
.diagnostics
|
.diagnostics
|
||||||
|
@ -44,14 +44,13 @@ pub(crate) fn zip_without_explicit_strict(
|
||||||
|
|
||||||
/// Return `true` if the [`Expr`] appears to be an infinite iterator (e.g., a call to
|
/// Return `true` if the [`Expr`] appears to be an infinite iterator (e.g., a call to
|
||||||
/// `itertools.cycle` or similar).
|
/// `itertools.cycle` or similar).
|
||||||
fn is_infinite_iterator(arg: &Expr, model: &SemanticModel) -> bool {
|
fn is_infinite_iterator(arg: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
let Expr::Call(ast::ExprCall { func, args, keywords, .. }) = &arg else {
|
let Expr::Call(ast::ExprCall { func, args, keywords, .. }) = &arg else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
return model
|
semantic.resolve_call_path(func).map_or(false, |call_path| {
|
||||||
.resolve_call_path(func)
|
match call_path.as_slice() {
|
||||||
.map_or(false, |call_path| match call_path.as_slice() {
|
|
||||||
["itertools", "cycle" | "count"] => true,
|
["itertools", "cycle" | "count"] => true,
|
||||||
["itertools", "repeat"] => {
|
["itertools", "repeat"] => {
|
||||||
// Ex) `itertools.repeat(1)`
|
// Ex) `itertools.repeat(1)`
|
||||||
|
@ -76,5 +75,6 @@ fn is_infinite_iterator(arg: &Expr, model: &SemanticModel) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
});
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,11 +72,11 @@ pub(crate) fn builtin_attribute_shadowing(
|
||||||
if shadows_builtin(name, &checker.settings.flake8_builtins.builtins_ignorelist) {
|
if shadows_builtin(name, &checker.settings.flake8_builtins.builtins_ignorelist) {
|
||||||
// Ignore shadowing within `TypedDict` definitions, since these are only accessible through
|
// Ignore shadowing within `TypedDict` definitions, since these are only accessible through
|
||||||
// subscripting and not through attribute access.
|
// subscripting and not through attribute access.
|
||||||
if class_def.bases.iter().any(|base| {
|
if class_def
|
||||||
checker
|
.bases
|
||||||
.semantic_model()
|
.iter()
|
||||||
.match_typing_expr(base, "TypedDict")
|
.any(|base| checker.semantic().match_typing_expr(base, "TypedDict"))
|
||||||
}) {
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -502,7 +502,7 @@ pub(crate) fn fix_unnecessary_collection_call(
|
||||||
/// this method will pad the start and end of an expression as needed to
|
/// this method will pad the start and end of an expression as needed to
|
||||||
/// avoid producing invalid syntax.
|
/// avoid producing invalid syntax.
|
||||||
fn pad_expression(content: String, range: TextRange, checker: &Checker) -> String {
|
fn pad_expression(content: String, range: TextRange, checker: &Checker) -> String {
|
||||||
if !checker.semantic_model().in_f_string() {
|
if !checker.semantic().in_f_string() {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ pub(crate) fn unnecessary_call_around_sorted(
|
||||||
if inner != "sorted" {
|
if inner != "sorted" {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if !checker.semantic_model().is_builtin(inner) || !checker.semantic_model().is_builtin(outer) {
|
if !checker.semantic().is_builtin(inner) || !checker.semantic().is_builtin(outer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = Diagnostic::new(
|
||||||
|
|
|
@ -79,7 +79,7 @@ pub(crate) fn unnecessary_collection_call(
|
||||||
}
|
}
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
if !checker.semantic_model().is_builtin(id) {
|
if !checker.semantic().is_builtin(id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = Diagnostic::new(
|
||||||
|
|
|
@ -56,7 +56,7 @@ fn add_diagnostic(checker: &mut Checker, expr: &Expr) {
|
||||||
Expr::DictComp(_) => "dict",
|
Expr::DictComp(_) => "dict",
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
if !checker.semantic_model().is_builtin(id) {
|
if !checker.semantic().is_builtin(id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = Diagnostic::new(
|
||||||
|
|
|
@ -76,7 +76,7 @@ pub(crate) fn unnecessary_comprehension_any_all(
|
||||||
if is_async_generator(elt) {
|
if is_async_generator(elt) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if !checker.semantic_model().is_builtin(id) {
|
if !checker.semantic().is_builtin(id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryComprehensionAnyAll, args[0].range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryComprehensionAnyAll, args[0].range());
|
||||||
|
|
|
@ -90,7 +90,7 @@ pub(crate) fn unnecessary_double_cast_or_process(
|
||||||
let Some(inner) = helpers::expr_name(func) else {
|
let Some(inner) = helpers::expr_name(func) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !checker.semantic_model().is_builtin(inner) || !checker.semantic_model().is_builtin(outer) {
|
if !checker.semantic().is_builtin(inner) || !checker.semantic().is_builtin(outer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ pub(crate) fn unnecessary_generator_list(
|
||||||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("list", func, args, keywords) else {
|
let Some(argument) = helpers::exactly_one_argument_with_matching_function("list", func, args, keywords) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !checker.semantic_model().is_builtin("list") {
|
if !checker.semantic().is_builtin("list") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Expr::GeneratorExp(_) = argument {
|
if let Expr::GeneratorExp(_) = argument {
|
||||||
|
|
|
@ -52,7 +52,7 @@ pub(crate) fn unnecessary_generator_set(
|
||||||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !checker.semantic_model().is_builtin("set") {
|
if !checker.semantic().is_builtin("set") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Expr::GeneratorExp(_) = argument {
|
if let Expr::GeneratorExp(_) = argument {
|
||||||
|
|
|
@ -48,7 +48,7 @@ pub(crate) fn unnecessary_list_call(
|
||||||
let Some(argument) = helpers::first_argument_with_matching_function("list", func, args) else {
|
let Some(argument) = helpers::first_argument_with_matching_function("list", func, args) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !checker.semantic_model().is_builtin("list") {
|
if !checker.semantic().is_builtin("list") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if !argument.is_list_comp_expr() {
|
if !argument.is_list_comp_expr() {
|
||||||
|
|
|
@ -50,7 +50,7 @@ pub(crate) fn unnecessary_list_comprehension_dict(
|
||||||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !checker.semantic_model().is_builtin("dict") {
|
if !checker.semantic().is_builtin("dict") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let Expr::ListComp(ast::ExprListComp { elt, .. }) = argument else {
|
let Expr::ListComp(ast::ExprListComp { elt, .. }) = argument else {
|
||||||
|
|
|
@ -50,7 +50,7 @@ pub(crate) fn unnecessary_list_comprehension_set(
|
||||||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !checker.semantic_model().is_builtin("set") {
|
if !checker.semantic().is_builtin("set") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if argument.is_list_comp_expr() {
|
if argument.is_list_comp_expr() {
|
||||||
|
|
|
@ -57,7 +57,7 @@ pub(crate) fn unnecessary_literal_dict(
|
||||||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !checker.semantic_model().is_builtin("dict") {
|
if !checker.semantic().is_builtin("dict") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let (kind, elts) = match argument {
|
let (kind, elts) = match argument {
|
||||||
|
|
|
@ -58,7 +58,7 @@ pub(crate) fn unnecessary_literal_set(
|
||||||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !checker.semantic_model().is_builtin("set") {
|
if !checker.semantic().is_builtin("set") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let kind = match argument {
|
let kind = match argument {
|
||||||
|
|
|
@ -76,7 +76,7 @@ pub(crate) fn unnecessary_literal_within_dict_call(
|
||||||
let Some(argument) = helpers::first_argument_with_matching_function("dict", func, args) else {
|
let Some(argument) = helpers::first_argument_with_matching_function("dict", func, args) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !checker.semantic_model().is_builtin("dict") {
|
if !checker.semantic().is_builtin("dict") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let argument_kind = match argument {
|
let argument_kind = match argument {
|
||||||
|
|
|
@ -79,7 +79,7 @@ pub(crate) fn unnecessary_literal_within_list_call(
|
||||||
let Some(argument) = helpers::first_argument_with_matching_function("list", func, args) else {
|
let Some(argument) = helpers::first_argument_with_matching_function("list", func, args) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !checker.semantic_model().is_builtin("list") {
|
if !checker.semantic().is_builtin("list") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let argument_kind = match argument {
|
let argument_kind = match argument {
|
||||||
|
|
|
@ -80,7 +80,7 @@ pub(crate) fn unnecessary_literal_within_tuple_call(
|
||||||
let Some(argument) = helpers::first_argument_with_matching_function("tuple", func, args) else {
|
let Some(argument) = helpers::first_argument_with_matching_function("tuple", func, args) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !checker.semantic_model().is_builtin("tuple") {
|
if !checker.semantic().is_builtin("tuple") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let argument_kind = match argument {
|
let argument_kind = match argument {
|
||||||
|
|
|
@ -88,7 +88,7 @@ pub(crate) fn unnecessary_map(
|
||||||
};
|
};
|
||||||
match id {
|
match id {
|
||||||
"map" => {
|
"map" => {
|
||||||
if !checker.semantic_model().is_builtin(id) {
|
if !checker.semantic().is_builtin(id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ pub(crate) fn unnecessary_map(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"list" | "set" => {
|
"list" | "set" => {
|
||||||
if !checker.semantic_model().is_builtin(id) {
|
if !checker.semantic().is_builtin(id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ pub(crate) fn unnecessary_map(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"dict" => {
|
"dict" => {
|
||||||
if !checker.semantic_model().is_builtin(id) {
|
if !checker.semantic().is_builtin(id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ pub(crate) fn unnecessary_subscript_reversal(
|
||||||
if !(id == "set" || id == "sorted" || id == "reversed") {
|
if !(id == "set" || id == "sorted" || id == "reversed") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if !checker.semantic_model().is_builtin(id) {
|
if !checker.semantic().is_builtin(id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let Expr::Subscript(ast::ExprSubscript { slice, .. }) = first_arg else {
|
let Expr::Subscript(ast::ExprSubscript { slice, .. }) = first_arg else {
|
||||||
|
|
|
@ -27,7 +27,7 @@ impl Violation for CallDateFromtimestamp {
|
||||||
/// Use `datetime.datetime.fromtimestamp(, tz=).date()` instead.
|
/// Use `datetime.datetime.fromtimestamp(, tz=).date()` instead.
|
||||||
pub(crate) fn call_date_fromtimestamp(checker: &mut Checker, func: &Expr, location: TextRange) {
|
pub(crate) fn call_date_fromtimestamp(checker: &mut Checker, func: &Expr, location: TextRange) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["datetime", "date", "fromtimestamp"]
|
call_path.as_slice() == ["datetime", "date", "fromtimestamp"]
|
||||||
|
|
|
@ -27,7 +27,7 @@ impl Violation for CallDateToday {
|
||||||
/// Use `datetime.datetime.now(tz=).date()` instead.
|
/// Use `datetime.datetime.now(tz=).date()` instead.
|
||||||
pub(crate) fn call_date_today(checker: &mut Checker, func: &Expr, location: TextRange) {
|
pub(crate) fn call_date_today(checker: &mut Checker, func: &Expr, location: TextRange) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["datetime", "date", "today"]
|
call_path.as_slice() == ["datetime", "date", "today"]
|
||||||
|
|
|
@ -28,7 +28,7 @@ pub(crate) fn call_datetime_fromtimestamp(
|
||||||
location: TextRange,
|
location: TextRange,
|
||||||
) {
|
) {
|
||||||
if !checker
|
if !checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["datetime", "datetime", "fromtimestamp"]
|
call_path.as_slice() == ["datetime", "datetime", "fromtimestamp"]
|
||||||
|
|
|
@ -26,7 +26,7 @@ pub(crate) fn call_datetime_now_without_tzinfo(
|
||||||
location: TextRange,
|
location: TextRange,
|
||||||
) {
|
) {
|
||||||
if !checker
|
if !checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["datetime", "datetime", "now"]
|
call_path.as_slice() == ["datetime", "datetime", "now"]
|
||||||
|
|
|
@ -28,7 +28,7 @@ pub(crate) fn call_datetime_strptime_without_zone(
|
||||||
location: TextRange,
|
location: TextRange,
|
||||||
) {
|
) {
|
||||||
if !checker
|
if !checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["datetime", "datetime", "strptime"]
|
call_path.as_slice() == ["datetime", "datetime", "strptime"]
|
||||||
|
@ -49,7 +49,7 @@ pub(crate) fn call_datetime_strptime_without_zone(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (Some(grandparent), Some(parent)) = (checker.semantic_model().expr_grandparent(), checker.semantic_model().expr_parent()) else {
|
let (Some(grandparent), Some(parent)) = (checker.semantic().expr_grandparent(), checker.semantic().expr_parent()) else {
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
CallDatetimeStrptimeWithoutZone,
|
CallDatetimeStrptimeWithoutZone,
|
||||||
location,
|
location,
|
||||||
|
|
|
@ -27,7 +27,7 @@ impl Violation for CallDatetimeToday {
|
||||||
/// Use `datetime.datetime.now(tz=)` instead.
|
/// Use `datetime.datetime.now(tz=)` instead.
|
||||||
pub(crate) fn call_datetime_today(checker: &mut Checker, func: &Expr, location: TextRange) {
|
pub(crate) fn call_datetime_today(checker: &mut Checker, func: &Expr, location: TextRange) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["datetime", "datetime", "today"]
|
call_path.as_slice() == ["datetime", "datetime", "today"]
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub(crate) fn call_datetime_utcfromtimestamp(
|
||||||
location: TextRange,
|
location: TextRange,
|
||||||
) {
|
) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["datetime", "datetime", "utcfromtimestamp"]
|
call_path.as_slice() == ["datetime", "datetime", "utcfromtimestamp"]
|
||||||
|
|
|
@ -29,7 +29,7 @@ impl Violation for CallDatetimeUtcnow {
|
||||||
/// current time in UTC is by calling `datetime.now(timezone.utc)`.
|
/// current time in UTC is by calling `datetime.now(timezone.utc)`.
|
||||||
pub(crate) fn call_datetime_utcnow(checker: &mut Checker, func: &Expr, location: TextRange) {
|
pub(crate) fn call_datetime_utcnow(checker: &mut Checker, func: &Expr, location: TextRange) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["datetime", "datetime", "utcnow"]
|
call_path.as_slice() == ["datetime", "datetime", "utcnow"]
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub(crate) fn call_datetime_without_tzinfo(
|
||||||
location: TextRange,
|
location: TextRange,
|
||||||
) {
|
) {
|
||||||
if !checker
|
if !checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["datetime", "datetime"]
|
call_path.as_slice() == ["datetime", "datetime"]
|
||||||
|
|
|
@ -44,7 +44,7 @@ const DEBUGGERS: &[&[&str]] = &[
|
||||||
/// Checks for the presence of a debugger call.
|
/// Checks for the presence of a debugger call.
|
||||||
pub(crate) fn debugger_call(checker: &mut Checker, expr: &Expr, func: &Expr) {
|
pub(crate) fn debugger_call(checker: &mut Checker, expr: &Expr, func: &Expr) {
|
||||||
if let Some(target) = checker
|
if let Some(target) = checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.and_then(|call_path| {
|
.and_then(|call_path| {
|
||||||
DEBUGGERS
|
DEBUGGERS
|
||||||
|
|
|
@ -54,7 +54,7 @@ pub(crate) fn all_with_model_form(
|
||||||
) -> Option<Diagnostic> {
|
) -> Option<Diagnostic> {
|
||||||
if !bases
|
if !bases
|
||||||
.iter()
|
.iter()
|
||||||
.any(|base| is_model_form(checker.semantic_model(), base))
|
.any(|base| is_model_form(base, checker.semantic()))
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ pub(crate) fn exclude_with_model_form(
|
||||||
) -> Option<Diagnostic> {
|
) -> Option<Diagnostic> {
|
||||||
if !bases
|
if !bases
|
||||||
.iter()
|
.iter()
|
||||||
.any(|base| is_model_form(checker.semantic_model(), base))
|
.any(|base| is_model_form(base, checker.semantic()))
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,23 +3,23 @@ use rustpython_parser::ast::Expr;
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
|
|
||||||
/// Return `true` if a Python class appears to be a Django model, based on its base classes.
|
/// Return `true` if a Python class appears to be a Django model, based on its base classes.
|
||||||
pub(super) fn is_model(model: &SemanticModel, base: &Expr) -> bool {
|
pub(super) fn is_model(base: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
model.resolve_call_path(base).map_or(false, |call_path| {
|
semantic.resolve_call_path(base).map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["django", "db", "models", "Model"]
|
call_path.as_slice() == ["django", "db", "models", "Model"]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if a Python class appears to be a Django model form, based on its base classes.
|
/// Return `true` if a Python class appears to be a Django model form, based on its base classes.
|
||||||
pub(super) fn is_model_form(model: &SemanticModel, base: &Expr) -> bool {
|
pub(super) fn is_model_form(base: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
model.resolve_call_path(base).map_or(false, |call_path| {
|
semantic.resolve_call_path(base).map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["django", "forms", "ModelForm"]
|
call_path.as_slice() == ["django", "forms", "ModelForm"]
|
||||||
|| call_path.as_slice() == ["django", "forms", "models", "ModelForm"]
|
|| call_path.as_slice() == ["django", "forms", "models", "ModelForm"]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if the expression is constructor for a Django model field.
|
/// Return `true` if the expression is constructor for a Django model field.
|
||||||
pub(super) fn is_model_field(model: &SemanticModel, expr: &Expr) -> bool {
|
pub(super) fn is_model_field(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
model.resolve_call_path(expr).map_or(false, |call_path| {
|
semantic.resolve_call_path(expr).map_or(false, |call_path| {
|
||||||
call_path
|
call_path
|
||||||
.as_slice()
|
.as_slice()
|
||||||
.starts_with(&["django", "db", "models"])
|
.starts_with(&["django", "db", "models"])
|
||||||
|
@ -28,10 +28,10 @@ pub(super) fn is_model_field(model: &SemanticModel, expr: &Expr) -> bool {
|
||||||
|
|
||||||
/// Return the name of the field type, if the expression is constructor for a Django model field.
|
/// Return the name of the field type, if the expression is constructor for a Django model field.
|
||||||
pub(super) fn get_model_field_name<'a>(
|
pub(super) fn get_model_field_name<'a>(
|
||||||
model: &'a SemanticModel,
|
|
||||||
expr: &'a Expr,
|
expr: &'a Expr,
|
||||||
|
semantic: &'a SemanticModel,
|
||||||
) -> Option<&'a str> {
|
) -> Option<&'a str> {
|
||||||
model.resolve_call_path(expr).and_then(|call_path| {
|
semantic.resolve_call_path(expr).and_then(|call_path| {
|
||||||
let call_path = call_path.as_slice();
|
let call_path = call_path.as_slice();
|
||||||
if !call_path.starts_with(&["django", "db", "models"]) {
|
if !call_path.starts_with(&["django", "db", "models"]) {
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -51,7 +51,7 @@ pub(crate) fn locals_in_render_function(
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) {
|
) {
|
||||||
if !checker
|
if !checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["django", "shortcuts", "render"]
|
call_path.as_slice() == ["django", "shortcuts", "render"]
|
||||||
|
@ -61,7 +61,7 @@ pub(crate) fn locals_in_render_function(
|
||||||
}
|
}
|
||||||
|
|
||||||
let locals = if args.len() >= 3 {
|
let locals = if args.len() >= 3 {
|
||||||
if !is_locals_call(checker.semantic_model(), &args[2]) {
|
if !is_locals_call(&args[2], checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
&args[2]
|
&args[2]
|
||||||
|
@ -69,7 +69,7 @@ pub(crate) fn locals_in_render_function(
|
||||||
.iter()
|
.iter()
|
||||||
.find(|keyword| keyword.arg.as_ref().map_or(false, |arg| arg == "context"))
|
.find(|keyword| keyword.arg.as_ref().map_or(false, |arg| arg == "context"))
|
||||||
{
|
{
|
||||||
if !is_locals_call(checker.semantic_model(), &keyword.value) {
|
if !is_locals_call(&keyword.value, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
&keyword.value
|
&keyword.value
|
||||||
|
@ -83,11 +83,11 @@ pub(crate) fn locals_in_render_function(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_locals_call(model: &SemanticModel, expr: &Expr) -> bool {
|
fn is_locals_call(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
let Expr::Call(ast::ExprCall { func, .. }) = expr else {
|
let Expr::Call(ast::ExprCall { func, .. }) = expr else {
|
||||||
return false
|
return false
|
||||||
};
|
};
|
||||||
model
|
semantic
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| call_path.as_slice() == ["", "locals"])
|
.map_or(false, |call_path| call_path.as_slice() == ["", "locals"])
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ pub(crate) fn model_without_dunder_str(
|
||||||
body: &[Stmt],
|
body: &[Stmt],
|
||||||
class_location: &Stmt,
|
class_location: &Stmt,
|
||||||
) -> Option<Diagnostic> {
|
) -> Option<Diagnostic> {
|
||||||
if !checker_applies(checker.semantic_model(), bases, body) {
|
if !is_non_abstract_model(bases, body, checker.semantic()) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if !has_dunder_method(body) {
|
if !has_dunder_method(body) {
|
||||||
|
@ -80,12 +80,12 @@ fn has_dunder_method(body: &[Stmt]) -> bool {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn checker_applies(model: &SemanticModel, bases: &[Expr], body: &[Stmt]) -> bool {
|
fn is_non_abstract_model(bases: &[Expr], body: &[Stmt], semantic: &SemanticModel) -> bool {
|
||||||
for base in bases.iter() {
|
for base in bases.iter() {
|
||||||
if is_model_abstract(body) {
|
if is_model_abstract(body) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if helpers::is_model(model, base) {
|
if helpers::is_model(base, semantic) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ fn is_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a st
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(valid_field_name) = helpers::get_model_field_name(checker.semantic_model(), func) else {
|
let Some(valid_field_name) = helpers::get_model_field_name(func, checker.semantic()) else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -100,11 +100,11 @@ impl fmt::Display for ContentType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_element_type(model: &SemanticModel, element: &Stmt) -> Option<ContentType> {
|
fn get_element_type(element: &Stmt, semantic: &SemanticModel) -> Option<ContentType> {
|
||||||
match element {
|
match element {
|
||||||
Stmt::Assign(ast::StmtAssign { targets, value, .. }) => {
|
Stmt::Assign(ast::StmtAssign { targets, value, .. }) => {
|
||||||
if let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() {
|
if let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() {
|
||||||
if helpers::is_model_field(model, func) {
|
if helpers::is_model_field(func, semantic) {
|
||||||
return Some(ContentType::FieldDeclaration);
|
return Some(ContentType::FieldDeclaration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,13 +145,13 @@ pub(crate) fn unordered_body_content_in_model(
|
||||||
) {
|
) {
|
||||||
if !bases
|
if !bases
|
||||||
.iter()
|
.iter()
|
||||||
.any(|base| helpers::is_model(checker.semantic_model(), base))
|
.any(|base| helpers::is_model(base, checker.semantic()))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut elements_type_found = Vec::new();
|
let mut elements_type_found = Vec::new();
|
||||||
for element in body.iter() {
|
for element in body.iter() {
|
||||||
let Some(current_element_type) = get_element_type(checker.semantic_model(), element) else {
|
let Some(current_element_type) = get_element_type(element, checker.semantic()) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let Some(&element_type) = elements_type_found
|
let Some(&element_type) = elements_type_found
|
||||||
|
|
|
@ -190,7 +190,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
|
||||||
if let Some(indentation) =
|
if let Some(indentation) =
|
||||||
whitespace::indentation(checker.locator, stmt)
|
whitespace::indentation(checker.locator, stmt)
|
||||||
{
|
{
|
||||||
if checker.semantic_model().is_available("msg") {
|
if checker.semantic().is_available("msg") {
|
||||||
diagnostic.set_fix(generate_fix(
|
diagnostic.set_fix(generate_fix(
|
||||||
stmt,
|
stmt,
|
||||||
first,
|
first,
|
||||||
|
@ -213,7 +213,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
|
||||||
if let Some(indentation) =
|
if let Some(indentation) =
|
||||||
whitespace::indentation(checker.locator, stmt)
|
whitespace::indentation(checker.locator, stmt)
|
||||||
{
|
{
|
||||||
if checker.semantic_model().is_available("msg") {
|
if checker.semantic().is_available("msg") {
|
||||||
diagnostic.set_fix(generate_fix(
|
diagnostic.set_fix(generate_fix(
|
||||||
stmt,
|
stmt,
|
||||||
first,
|
first,
|
||||||
|
@ -240,7 +240,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
|
||||||
if let Some(indentation) =
|
if let Some(indentation) =
|
||||||
whitespace::indentation(checker.locator, stmt)
|
whitespace::indentation(checker.locator, stmt)
|
||||||
{
|
{
|
||||||
if checker.semantic_model().is_available("msg") {
|
if checker.semantic().is_available("msg") {
|
||||||
diagnostic.set_fix(generate_fix(
|
diagnostic.set_fix(generate_fix(
|
||||||
stmt,
|
stmt,
|
||||||
first,
|
first,
|
||||||
|
|
|
@ -65,7 +65,7 @@ impl Violation for FutureRewritableTypeAnnotation {
|
||||||
/// FA100
|
/// FA100
|
||||||
pub(crate) fn future_rewritable_type_annotation(checker: &mut Checker, expr: &Expr) {
|
pub(crate) fn future_rewritable_type_annotation(checker: &mut Checker, expr: &Expr) {
|
||||||
let name = checker
|
let name = checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(expr)
|
.resolve_call_path(expr)
|
||||||
.map(|binding| format_call_path(&binding));
|
.map(|binding| format_call_path(&binding));
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) {
|
||||||
}
|
}
|
||||||
Expr::Call(ast::ExprCall { func, keywords, .. }) => {
|
Expr::Call(ast::ExprCall { func, keywords, .. }) => {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| call_path.as_slice() == ["", "dict"])
|
.map_or(false, |call_path| call_path.as_slice() == ["", "dict"])
|
||||||
{
|
{
|
||||||
|
@ -151,7 +151,7 @@ pub(crate) fn logging_call(
|
||||||
args: &[Expr],
|
args: &[Expr],
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) {
|
) {
|
||||||
if !logging::is_logger_candidate(func, checker.semantic_model()) {
|
if !logging::is_logger_candidate(func, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,10 +193,10 @@ pub(crate) fn logging_call(
|
||||||
|
|
||||||
// G201, G202
|
// G201, G202
|
||||||
if checker.any_enabled(&[Rule::LoggingExcInfo, Rule::LoggingRedundantExcInfo]) {
|
if checker.any_enabled(&[Rule::LoggingExcInfo, Rule::LoggingRedundantExcInfo]) {
|
||||||
if !checker.semantic_model().in_exception_handler() {
|
if !checker.semantic().in_exception_handler() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let Some(exc_info) = logging::exc_info(keywords, checker.semantic_model()) else {
|
let Some(exc_info) = logging::exc_info(keywords, checker.semantic()) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if let LoggingCallType::LevelCall(logging_level) = logging_call_type {
|
if let LoggingCallType::LevelCall(logging_level) = logging_call_type {
|
||||||
|
|
|
@ -66,7 +66,7 @@ pub(crate) fn non_unique_enums<'a, 'b>(
|
||||||
|
|
||||||
if !bases.iter().any(|expr| {
|
if !bases.iter().any(|expr| {
|
||||||
checker
|
checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(expr)
|
.resolve_call_path(expr)
|
||||||
.map_or(false, |call_path| call_path.as_slice() == ["enum", "Enum"])
|
.map_or(false, |call_path| call_path.as_slice() == ["enum", "Enum"])
|
||||||
}) {
|
}) {
|
||||||
|
@ -81,7 +81,7 @@ pub(crate) fn non_unique_enums<'a, 'b>(
|
||||||
|
|
||||||
if let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() {
|
if let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
.map_or(false, |call_path| call_path.as_slice() == ["enum", "auto"])
|
.map_or(false, |call_path| call_path.as_slice() == ["enum", "auto"])
|
||||||
{
|
{
|
||||||
|
|
|
@ -69,7 +69,7 @@ pub(crate) fn reimplemented_list_builtin(checker: &mut Checker, expr: &ExprLambd
|
||||||
if elts.is_empty() {
|
if elts.is_empty() {
|
||||||
let mut diagnostic = Diagnostic::new(ReimplementedListBuiltin, expr.range());
|
let mut diagnostic = Diagnostic::new(ReimplementedListBuiltin, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if checker.patch(diagnostic.kind.rule()) {
|
||||||
if checker.semantic_model().is_builtin("list") {
|
if checker.semantic().is_builtin("list") {
|
||||||
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
|
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
|
||||||
"list".to_string(),
|
"list".to_string(),
|
||||||
expr.range(),
|
expr.range(),
|
||||||
|
|
|
@ -78,7 +78,7 @@ impl Violation for PPrint {
|
||||||
/// T201, T203
|
/// T201, T203
|
||||||
pub(crate) fn print_call(checker: &mut Checker, func: &Expr, keywords: &[Keyword]) {
|
pub(crate) fn print_call(checker: &mut Checker, func: &Expr, keywords: &[Keyword]) {
|
||||||
let diagnostic = {
|
let diagnostic = {
|
||||||
let call_path = checker.semantic_model().resolve_call_path(func);
|
let call_path = checker.semantic().resolve_call_path(func);
|
||||||
if call_path
|
if call_path
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(false, |call_path| *call_path.as_slice() == ["", "print"])
|
.map_or(false, |call_path| *call_path.as_slice() == ["", "print"])
|
||||||
|
@ -90,14 +90,13 @@ pub(crate) fn print_call(checker: &mut Checker, func: &Expr, keywords: &[Keyword
|
||||||
.find(|keyword| keyword.arg.as_ref().map_or(false, |arg| arg == "file"))
|
.find(|keyword| keyword.arg.as_ref().map_or(false, |arg| arg == "file"))
|
||||||
{
|
{
|
||||||
if !is_const_none(&keyword.value) {
|
if !is_const_none(&keyword.value) {
|
||||||
if checker
|
if checker.semantic().resolve_call_path(&keyword.value).map_or(
|
||||||
.semantic_model()
|
true,
|
||||||
.resolve_call_path(&keyword.value)
|
|call_path| {
|
||||||
.map_or(true, |call_path| {
|
|
||||||
call_path.as_slice() != ["sys", "stdout"]
|
call_path.as_slice() != ["sys", "stdout"]
|
||||||
&& call_path.as_slice() != ["sys", "stderr"]
|
&& call_path.as_slice() != ["sys", "stderr"]
|
||||||
})
|
},
|
||||||
{
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,14 +66,11 @@ pub(crate) fn any_eq_ne_annotation(checker: &mut Checker, name: &str, args: &Arg
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if !checker.semantic_model().scope().kind.is_class() {
|
if !checker.semantic().scope().kind.is_class() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if checker
|
if checker.semantic().match_typing_expr(annotation, "Any") {
|
||||||
.semantic_model()
|
|
||||||
.match_typing_expr(annotation, "Any")
|
|
||||||
{
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = Diagnostic::new(
|
||||||
AnyEqNeAnnotation {
|
AnyEqNeAnnotation {
|
||||||
method_name: name.to_string(),
|
method_name: name.to_string(),
|
||||||
|
@ -82,7 +79,7 @@ pub(crate) fn any_eq_ne_annotation(checker: &mut Checker, name: &str, args: &Arg
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if checker.patch(diagnostic.kind.rule()) {
|
||||||
// Ex) `def __eq__(self, obj: Any): ...`
|
// Ex) `def __eq__(self, obj: Any): ...`
|
||||||
if checker.semantic_model().is_builtin("object") {
|
if checker.semantic().is_builtin("object") {
|
||||||
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
|
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
|
||||||
"object".to_string(),
|
"object".to_string(),
|
||||||
annotation.range(),
|
annotation.range(),
|
||||||
|
|
|
@ -69,7 +69,7 @@ pub(crate) fn bad_version_info_comparison(
|
||||||
};
|
};
|
||||||
|
|
||||||
if !checker
|
if !checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(left)
|
.resolve_call_path(left)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["sys", "version_info"]
|
call_path.as_slice() == ["sys", "version_info"]
|
||||||
|
|
|
@ -51,7 +51,7 @@ impl Violation for CollectionsNamedTuple {
|
||||||
/// PYI024
|
/// PYI024
|
||||||
pub(crate) fn collections_named_tuple(checker: &mut Checker, expr: &Expr) {
|
pub(crate) fn collections_named_tuple(checker: &mut Checker, expr: &Expr) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(expr)
|
.resolve_call_path(expr)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
matches!(call_path.as_slice(), ["collections", "namedtuple"])
|
matches!(call_path.as_slice(), ["collections", "namedtuple"])
|
||||||
|
|
|
@ -101,7 +101,7 @@ pub(crate) fn iter_method_return_iterable(checker: &mut Checker, definition: &De
|
||||||
};
|
};
|
||||||
|
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(annotation)
|
.resolve_call_path(annotation)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
if async_ {
|
if async_ {
|
||||||
|
|
|
@ -56,10 +56,7 @@ pub(crate) fn no_return_argument_annotation(checker: &mut Checker, args: &Argume
|
||||||
)
|
)
|
||||||
.filter_map(|arg| arg.annotation.as_ref())
|
.filter_map(|arg| arg.annotation.as_ref())
|
||||||
{
|
{
|
||||||
if checker
|
if checker.semantic().match_typing_expr(annotation, "NoReturn") {
|
||||||
.semantic_model()
|
|
||||||
.match_typing_expr(annotation, "NoReturn")
|
|
||||||
{
|
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
NoReturnArgumentAnnotationInStub {
|
NoReturnArgumentAnnotationInStub {
|
||||||
module: if checker.settings.target_version >= Py311 {
|
module: if checker.settings.target_version >= Py311 {
|
||||||
|
|
|
@ -118,7 +118,7 @@ pub(crate) fn non_self_return_type(
|
||||||
args: &Arguments,
|
args: &Arguments,
|
||||||
async_: bool,
|
async_: bool,
|
||||||
) {
|
) {
|
||||||
let ScopeKind::Class(class_def) = checker.semantic_model().scope().kind else {
|
let ScopeKind::Class(class_def) = checker.semantic().scope().kind else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -131,8 +131,8 @@ pub(crate) fn non_self_return_type(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Skip any abstract or overloaded methods.
|
// Skip any abstract or overloaded methods.
|
||||||
if is_abstract(checker.semantic_model(), decorator_list)
|
if is_abstract(decorator_list, checker.semantic())
|
||||||
|| is_overload(checker.semantic_model(), decorator_list)
|
|| is_overload(decorator_list, checker.semantic())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ pub(crate) fn non_self_return_type(
|
||||||
if async_ {
|
if async_ {
|
||||||
if name == "__aenter__"
|
if name == "__aenter__"
|
||||||
&& is_name(returns, &class_def.name)
|
&& is_name(returns, &class_def.name)
|
||||||
&& !is_final(checker.semantic_model(), &class_def.decorator_list)
|
&& !is_final(&class_def.decorator_list, checker.semantic())
|
||||||
{
|
{
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
NonSelfReturnType {
|
NonSelfReturnType {
|
||||||
|
@ -155,7 +155,7 @@ pub(crate) fn non_self_return_type(
|
||||||
|
|
||||||
// In-place methods that are expected to return `Self`.
|
// In-place methods that are expected to return `Self`.
|
||||||
if INPLACE_BINOP_METHODS.contains(&name) {
|
if INPLACE_BINOP_METHODS.contains(&name) {
|
||||||
if !is_self(returns, checker.semantic_model()) {
|
if !is_self(returns, checker.semantic()) {
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
NonSelfReturnType {
|
NonSelfReturnType {
|
||||||
class_name: class_def.name.to_string(),
|
class_name: class_def.name.to_string(),
|
||||||
|
@ -169,7 +169,7 @@ pub(crate) fn non_self_return_type(
|
||||||
|
|
||||||
if is_name(returns, &class_def.name) {
|
if is_name(returns, &class_def.name) {
|
||||||
if matches!(name, "__enter__" | "__new__")
|
if matches!(name, "__enter__" | "__new__")
|
||||||
&& !is_final(checker.semantic_model(), &class_def.decorator_list)
|
&& !is_final(&class_def.decorator_list, checker.semantic())
|
||||||
{
|
{
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
NonSelfReturnType {
|
NonSelfReturnType {
|
||||||
|
@ -184,8 +184,8 @@ pub(crate) fn non_self_return_type(
|
||||||
|
|
||||||
match name {
|
match name {
|
||||||
"__iter__" => {
|
"__iter__" => {
|
||||||
if is_iterable(returns, checker.semantic_model())
|
if is_iterable(returns, checker.semantic())
|
||||||
&& is_iterator(&class_def.bases, checker.semantic_model())
|
&& is_iterator(&class_def.bases, checker.semantic())
|
||||||
{
|
{
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
NonSelfReturnType {
|
NonSelfReturnType {
|
||||||
|
@ -197,8 +197,8 @@ pub(crate) fn non_self_return_type(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"__aiter__" => {
|
"__aiter__" => {
|
||||||
if is_async_iterable(returns, checker.semantic_model())
|
if is_async_iterable(returns, checker.semantic())
|
||||||
&& is_async_iterator(&class_def.bases, checker.semantic_model())
|
&& is_async_iterator(&class_def.bases, checker.semantic())
|
||||||
{
|
{
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
NonSelfReturnType {
|
NonSelfReturnType {
|
||||||
|
@ -238,14 +238,14 @@ fn is_name(expr: &Expr, name: &str) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if the given expression resolves to `typing.Self`.
|
/// Return `true` if the given expression resolves to `typing.Self`.
|
||||||
fn is_self(expr: &Expr, model: &SemanticModel) -> bool {
|
fn is_self(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
model.match_typing_expr(expr, "Self")
|
semantic.match_typing_expr(expr, "Self")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if the given class extends `collections.abc.Iterator`.
|
/// Return `true` if the given class extends `collections.abc.Iterator`.
|
||||||
fn is_iterator(bases: &[Expr], model: &SemanticModel) -> bool {
|
fn is_iterator(bases: &[Expr], semantic: &SemanticModel) -> bool {
|
||||||
bases.iter().any(|expr| {
|
bases.iter().any(|expr| {
|
||||||
model
|
semantic
|
||||||
.resolve_call_path(map_subscript(expr))
|
.resolve_call_path(map_subscript(expr))
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
matches!(
|
matches!(
|
||||||
|
@ -257,8 +257,8 @@ fn is_iterator(bases: &[Expr], model: &SemanticModel) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if the given expression resolves to `collections.abc.Iterable`.
|
/// Return `true` if the given expression resolves to `collections.abc.Iterable`.
|
||||||
fn is_iterable(expr: &Expr, model: &SemanticModel) -> bool {
|
fn is_iterable(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
model
|
semantic
|
||||||
.resolve_call_path(map_subscript(expr))
|
.resolve_call_path(map_subscript(expr))
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
matches!(
|
matches!(
|
||||||
|
@ -270,9 +270,9 @@ fn is_iterable(expr: &Expr, model: &SemanticModel) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if the given class extends `collections.abc.AsyncIterator`.
|
/// Return `true` if the given class extends `collections.abc.AsyncIterator`.
|
||||||
fn is_async_iterator(bases: &[Expr], model: &SemanticModel) -> bool {
|
fn is_async_iterator(bases: &[Expr], semantic: &SemanticModel) -> bool {
|
||||||
bases.iter().any(|expr| {
|
bases.iter().any(|expr| {
|
||||||
model
|
semantic
|
||||||
.resolve_call_path(map_subscript(expr))
|
.resolve_call_path(map_subscript(expr))
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
matches!(
|
matches!(
|
||||||
|
@ -284,8 +284,8 @@ fn is_async_iterator(bases: &[Expr], model: &SemanticModel) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if the given expression resolves to `collections.abc.AsyncIterable`.
|
/// Return `true` if the given expression resolves to `collections.abc.AsyncIterable`.
|
||||||
fn is_async_iterable(expr: &Expr, model: &SemanticModel) -> bool {
|
fn is_async_iterable(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
model
|
semantic
|
||||||
.resolve_call_path(map_subscript(expr))
|
.resolve_call_path(map_subscript(expr))
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
matches!(
|
matches!(
|
||||||
|
|
|
@ -70,12 +70,12 @@ pub(crate) fn prefix_type_params(checker: &mut Checker, value: &Expr, targets: &
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Expr::Call(ast::ExprCall { func, .. }) = value {
|
if let Expr::Call(ast::ExprCall { func, .. }) = value {
|
||||||
let Some(kind) = checker.semantic_model().resolve_call_path(func).and_then(|call_path| {
|
let Some(kind) = checker.semantic().resolve_call_path(func).and_then(|call_path| {
|
||||||
if checker.semantic_model().match_typing_call_path(&call_path, "ParamSpec") {
|
if checker.semantic().match_typing_call_path(&call_path, "ParamSpec") {
|
||||||
Some(VarKind::ParamSpec)
|
Some(VarKind::ParamSpec)
|
||||||
} else if checker.semantic_model().match_typing_call_path(&call_path, "TypeVar") {
|
} else if checker.semantic().match_typing_call_path(&call_path, "TypeVar") {
|
||||||
Some(VarKind::TypeVar)
|
Some(VarKind::TypeVar)
|
||||||
} else if checker.semantic_model().match_typing_call_path(&call_path, "TypeVarTuple") {
|
} else if checker.semantic().match_typing_call_path(&call_path, "TypeVarTuple") {
|
||||||
Some(VarKind::TypeVarTuple)
|
Some(VarKind::TypeVarTuple)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -123,7 +123,7 @@ fn is_valid_default_value_with_annotation(
|
||||||
default: &Expr,
|
default: &Expr,
|
||||||
allow_container: bool,
|
allow_container: bool,
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
model: &SemanticModel,
|
semantic: &SemanticModel,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match default {
|
match default {
|
||||||
Expr::Constant(_) => {
|
Expr::Constant(_) => {
|
||||||
|
@ -136,7 +136,7 @@ fn is_valid_default_value_with_annotation(
|
||||||
&& elts.len() <= 10
|
&& elts.len() <= 10
|
||||||
&& elts
|
&& elts
|
||||||
.iter()
|
.iter()
|
||||||
.all(|e| is_valid_default_value_with_annotation(e, false, locator, model));
|
.all(|e| is_valid_default_value_with_annotation(e, false, locator, semantic));
|
||||||
}
|
}
|
||||||
Expr::Dict(ast::ExprDict {
|
Expr::Dict(ast::ExprDict {
|
||||||
keys,
|
keys,
|
||||||
|
@ -147,8 +147,8 @@ fn is_valid_default_value_with_annotation(
|
||||||
&& keys.len() <= 10
|
&& keys.len() <= 10
|
||||||
&& keys.iter().zip(values).all(|(k, v)| {
|
&& keys.iter().zip(values).all(|(k, v)| {
|
||||||
k.as_ref().map_or(false, |k| {
|
k.as_ref().map_or(false, |k| {
|
||||||
is_valid_default_value_with_annotation(k, false, locator, model)
|
is_valid_default_value_with_annotation(k, false, locator, semantic)
|
||||||
}) && is_valid_default_value_with_annotation(v, false, locator, model)
|
}) && is_valid_default_value_with_annotation(v, false, locator, semantic)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Expr::UnaryOp(ast::ExprUnaryOp {
|
Expr::UnaryOp(ast::ExprUnaryOp {
|
||||||
|
@ -164,12 +164,15 @@ fn is_valid_default_value_with_annotation(
|
||||||
}) => return true,
|
}) => return true,
|
||||||
// Ex) `-math.inf`, `-math.pi`, etc.
|
// Ex) `-math.inf`, `-math.pi`, etc.
|
||||||
Expr::Attribute(_) => {
|
Expr::Attribute(_) => {
|
||||||
if model.resolve_call_path(operand).map_or(false, |call_path| {
|
if semantic
|
||||||
ALLOWED_MATH_ATTRIBUTES_IN_DEFAULTS.iter().any(|target| {
|
.resolve_call_path(operand)
|
||||||
// reject `-math.nan`
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == *target && *target != ["math", "nan"]
|
ALLOWED_MATH_ATTRIBUTES_IN_DEFAULTS.iter().any(|target| {
|
||||||
|
// reject `-math.nan`
|
||||||
|
call_path.as_slice() == *target && *target != ["math", "nan"]
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}) {
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,12 +217,15 @@ fn is_valid_default_value_with_annotation(
|
||||||
}
|
}
|
||||||
// Ex) `math.inf`, `sys.stdin`, etc.
|
// Ex) `math.inf`, `sys.stdin`, etc.
|
||||||
Expr::Attribute(_) => {
|
Expr::Attribute(_) => {
|
||||||
if model.resolve_call_path(default).map_or(false, |call_path| {
|
if semantic
|
||||||
ALLOWED_MATH_ATTRIBUTES_IN_DEFAULTS
|
.resolve_call_path(default)
|
||||||
.iter()
|
.map_or(false, |call_path| {
|
||||||
.chain(ALLOWED_ATTRIBUTES_IN_DEFAULTS.iter())
|
ALLOWED_MATH_ATTRIBUTES_IN_DEFAULTS
|
||||||
.any(|target| call_path.as_slice() == *target)
|
.iter()
|
||||||
}) {
|
.chain(ALLOWED_ATTRIBUTES_IN_DEFAULTS.iter())
|
||||||
|
.any(|target| call_path.as_slice() == *target)
|
||||||
|
})
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,11 +271,11 @@ fn is_valid_default_value_without_annotation(default: &Expr) -> bool {
|
||||||
|
|
||||||
/// Returns `true` if an [`Expr`] appears to be `TypeVar`, `TypeVarTuple`, `NewType`, or `ParamSpec`
|
/// Returns `true` if an [`Expr`] appears to be `TypeVar`, `TypeVarTuple`, `NewType`, or `ParamSpec`
|
||||||
/// call.
|
/// call.
|
||||||
fn is_type_var_like_call(model: &SemanticModel, expr: &Expr) -> bool {
|
fn is_type_var_like_call(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
let Expr::Call(ast::ExprCall { func, .. } )= expr else {
|
let Expr::Call(ast::ExprCall { func, .. } )= expr else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
model.resolve_call_path(func).map_or(false, |call_path| {
|
semantic.resolve_call_path(func).map_or(false, |call_path| {
|
||||||
matches!(
|
matches!(
|
||||||
call_path.as_slice(),
|
call_path.as_slice(),
|
||||||
[
|
[
|
||||||
|
@ -282,11 +288,11 @@ fn is_type_var_like_call(model: &SemanticModel, expr: &Expr) -> bool {
|
||||||
|
|
||||||
/// Returns `true` if this is a "special" assignment which must have a value (e.g., an assignment to
|
/// Returns `true` if this is a "special" assignment which must have a value (e.g., an assignment to
|
||||||
/// `__all__`).
|
/// `__all__`).
|
||||||
fn is_special_assignment(model: &SemanticModel, target: &Expr) -> bool {
|
fn is_special_assignment(target: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
if let Expr::Name(ast::ExprName { id, .. }) = target {
|
if let Expr::Name(ast::ExprName { id, .. }) = target {
|
||||||
match id.as_str() {
|
match id.as_str() {
|
||||||
"__all__" => model.scope().kind.is_module(),
|
"__all__" => semantic.scope().kind.is_module(),
|
||||||
"__match_args__" | "__slots__" => model.scope().kind.is_class(),
|
"__match_args__" | "__slots__" => semantic.scope().kind.is_class(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -295,9 +301,9 @@ fn is_special_assignment(model: &SemanticModel, target: &Expr) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the a class is an enum, based on its base classes.
|
/// Returns `true` if the a class is an enum, based on its base classes.
|
||||||
fn is_enum(model: &SemanticModel, bases: &[Expr]) -> bool {
|
fn is_enum(bases: &[Expr], semantic: &SemanticModel) -> bool {
|
||||||
return bases.iter().any(|expr| {
|
return bases.iter().any(|expr| {
|
||||||
model.resolve_call_path(expr).map_or(false, |call_path| {
|
semantic.resolve_call_path(expr).map_or(false, |call_path| {
|
||||||
matches!(
|
matches!(
|
||||||
call_path.as_slice(),
|
call_path.as_slice(),
|
||||||
[
|
[
|
||||||
|
@ -323,7 +329,7 @@ pub(crate) fn typed_argument_simple_defaults(checker: &mut Checker, args: &Argum
|
||||||
default,
|
default,
|
||||||
true,
|
true,
|
||||||
checker.locator,
|
checker.locator,
|
||||||
checker.semantic_model(),
|
checker.semantic(),
|
||||||
) {
|
) {
|
||||||
let mut diagnostic =
|
let mut diagnostic =
|
||||||
Diagnostic::new(TypedArgumentDefaultInStub, default.range());
|
Diagnostic::new(TypedArgumentDefaultInStub, default.range());
|
||||||
|
@ -354,7 +360,7 @@ pub(crate) fn typed_argument_simple_defaults(checker: &mut Checker, args: &Argum
|
||||||
default,
|
default,
|
||||||
true,
|
true,
|
||||||
checker.locator,
|
checker.locator,
|
||||||
checker.semantic_model(),
|
checker.semantic(),
|
||||||
) {
|
) {
|
||||||
let mut diagnostic =
|
let mut diagnostic =
|
||||||
Diagnostic::new(TypedArgumentDefaultInStub, default.range());
|
Diagnostic::new(TypedArgumentDefaultInStub, default.range());
|
||||||
|
@ -388,7 +394,7 @@ pub(crate) fn argument_simple_defaults(checker: &mut Checker, args: &Arguments)
|
||||||
default,
|
default,
|
||||||
true,
|
true,
|
||||||
checker.locator,
|
checker.locator,
|
||||||
checker.semantic_model(),
|
checker.semantic(),
|
||||||
) {
|
) {
|
||||||
let mut diagnostic =
|
let mut diagnostic =
|
||||||
Diagnostic::new(ArgumentDefaultInStub, default.range());
|
Diagnostic::new(ArgumentDefaultInStub, default.range());
|
||||||
|
@ -419,7 +425,7 @@ pub(crate) fn argument_simple_defaults(checker: &mut Checker, args: &Arguments)
|
||||||
default,
|
default,
|
||||||
true,
|
true,
|
||||||
checker.locator,
|
checker.locator,
|
||||||
checker.semantic_model(),
|
checker.semantic(),
|
||||||
) {
|
) {
|
||||||
let mut diagnostic =
|
let mut diagnostic =
|
||||||
Diagnostic::new(ArgumentDefaultInStub, default.range());
|
Diagnostic::new(ArgumentDefaultInStub, default.range());
|
||||||
|
@ -448,21 +454,16 @@ pub(crate) fn assignment_default_in_stub(checker: &mut Checker, targets: &[Expr]
|
||||||
if !target.is_name_expr() {
|
if !target.is_name_expr() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if is_special_assignment(checker.semantic_model(), target) {
|
if is_special_assignment(target, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if is_type_var_like_call(checker.semantic_model(), value) {
|
if is_type_var_like_call(value, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if is_valid_default_value_without_annotation(value) {
|
if is_valid_default_value_without_annotation(value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if is_valid_default_value_with_annotation(
|
if is_valid_default_value_with_annotation(value, true, checker.locator, checker.semantic()) {
|
||||||
value,
|
|
||||||
true,
|
|
||||||
checker.locator,
|
|
||||||
checker.semantic_model(),
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,23 +485,18 @@ pub(crate) fn annotated_assignment_default_in_stub(
|
||||||
annotation: &Expr,
|
annotation: &Expr,
|
||||||
) {
|
) {
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.match_typing_expr(annotation, "TypeAlias")
|
.match_typing_expr(annotation, "TypeAlias")
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if is_special_assignment(checker.semantic_model(), target) {
|
if is_special_assignment(target, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if is_type_var_like_call(checker.semantic_model(), value) {
|
if is_type_var_like_call(value, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if is_valid_default_value_with_annotation(
|
if is_valid_default_value_with_annotation(value, true, checker.locator, checker.semantic()) {
|
||||||
value,
|
|
||||||
true,
|
|
||||||
checker.locator,
|
|
||||||
checker.semantic_model(),
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,27 +523,21 @@ pub(crate) fn unannotated_assignment_in_stub(
|
||||||
let Expr::Name(ast::ExprName { id, .. }) = target else {
|
let Expr::Name(ast::ExprName { id, .. }) = target else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if is_special_assignment(checker.semantic_model(), target) {
|
if is_special_assignment(target, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if is_type_var_like_call(checker.semantic_model(), value) {
|
if is_type_var_like_call(value, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if is_valid_default_value_without_annotation(value) {
|
if is_valid_default_value_without_annotation(value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if !is_valid_default_value_with_annotation(
|
if !is_valid_default_value_with_annotation(value, true, checker.locator, checker.semantic()) {
|
||||||
value,
|
|
||||||
true,
|
|
||||||
checker.locator,
|
|
||||||
checker.semantic_model(),
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ScopeKind::Class(ast::StmtClassDef { bases, .. }) = checker.semantic_model().scope().kind
|
if let ScopeKind::Class(ast::StmtClassDef { bases, .. }) = checker.semantic().scope().kind {
|
||||||
{
|
if is_enum(bases, checker.semantic()) {
|
||||||
if is_enum(checker.semantic_model(), bases) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -569,7 +559,7 @@ pub(crate) fn unassigned_special_variable_in_stub(
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if !is_special_assignment(checker.semantic_model(), target) {
|
if !is_special_assignment(target, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ pub(crate) fn str_or_repr_defined_in_stub(checker: &mut Checker, stmt: &Stmt) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !checker.semantic_model().scope().kind.is_class() {
|
if !checker.semantic().scope().kind.is_class() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,12 +72,12 @@ pub(crate) fn str_or_repr_defined_in_stub(checker: &mut Checker, stmt: &Stmt) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_abstract(checker.semantic_model(), decorator_list) {
|
if is_abstract(decorator_list, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if checker
|
if checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(returns)
|
.resolve_call_path(returns)
|
||||||
.map_or(true, |call_path| {
|
.map_or(true, |call_path| {
|
||||||
!matches!(call_path.as_slice(), ["" | "builtins", "str"])
|
!matches!(call_path.as_slice(), ["" | "builtins", "str"])
|
||||||
|
@ -93,8 +93,8 @@ pub(crate) fn str_or_repr_defined_in_stub(checker: &mut Checker, stmt: &Stmt) {
|
||||||
identifier_range(stmt, checker.locator),
|
identifier_range(stmt, checker.locator),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if checker.patch(diagnostic.kind.rule()) {
|
||||||
let stmt = checker.semantic_model().stmt();
|
let stmt = checker.semantic().stmt();
|
||||||
let parent = checker.semantic_model().stmt_parent();
|
let parent = checker.semantic().stmt_parent();
|
||||||
let edit = delete_stmt(
|
let edit = delete_stmt(
|
||||||
stmt,
|
stmt,
|
||||||
parent,
|
parent,
|
||||||
|
@ -103,7 +103,7 @@ pub(crate) fn str_or_repr_defined_in_stub(checker: &mut Checker, stmt: &Stmt) {
|
||||||
checker.stylist,
|
checker.stylist,
|
||||||
);
|
);
|
||||||
diagnostic.set_fix(
|
diagnostic.set_fix(
|
||||||
Fix::automatic(edit).isolate(checker.isolation(checker.semantic_model().stmt_parent())),
|
Fix::automatic(edit).isolate(checker.isolation(checker.semantic().stmt_parent())),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
|
|
|
@ -103,7 +103,7 @@ pub(crate) fn unrecognized_platform(
|
||||||
let diagnostic_unrecognized_platform_check =
|
let diagnostic_unrecognized_platform_check =
|
||||||
Diagnostic::new(UnrecognizedPlatformCheck, expr.range());
|
Diagnostic::new(UnrecognizedPlatformCheck, expr.range());
|
||||||
if !checker
|
if !checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(left)
|
.resolve_call_path(left)
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["sys", "platform"]
|
call_path.as_slice() == ["sys", "platform"]
|
||||||
|
|
|
@ -194,9 +194,9 @@ pub(crate) fn unittest_assertion(
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if checker.patch(diagnostic.kind.rule()) {
|
||||||
// We're converting an expression to a statement, so avoid applying the fix if
|
// We're converting an expression to a statement, so avoid applying the fix if
|
||||||
// the assertion is part of a larger expression.
|
// the assertion is part of a larger expression.
|
||||||
if checker.semantic_model().stmt().is_expr_stmt()
|
if checker.semantic().stmt().is_expr_stmt()
|
||||||
&& checker.semantic_model().expr_parent().is_none()
|
&& checker.semantic().expr_parent().is_none()
|
||||||
&& !checker.semantic_model().scope().kind.is_lambda()
|
&& !checker.semantic().scope().kind.is_lambda()
|
||||||
&& !has_comments_in(expr.range(), checker.locator)
|
&& !has_comments_in(expr.range(), checker.locator)
|
||||||
{
|
{
|
||||||
if let Ok(stmt) = unittest_assert.generate_assert(args, keywords) {
|
if let Ok(stmt) = unittest_assert.generate_assert(args, keywords) {
|
||||||
|
@ -219,7 +219,7 @@ pub(crate) fn unittest_assertion(
|
||||||
|
|
||||||
/// PT015
|
/// PT015
|
||||||
pub(crate) fn assert_falsy(checker: &mut Checker, stmt: &Stmt, test: &Expr) {
|
pub(crate) fn assert_falsy(checker: &mut Checker, stmt: &Stmt, test: &Expr) {
|
||||||
if Truthiness::from_expr(test, |id| checker.semantic_model().is_builtin(id)).is_falsey() {
|
if Truthiness::from_expr(test, |id| checker.semantic().is_builtin(id)).is_falsey() {
|
||||||
checker
|
checker
|
||||||
.diagnostics
|
.diagnostics
|
||||||
.push(Diagnostic::new(PytestAssertAlwaysFalse, stmt.range()));
|
.push(Diagnostic::new(PytestAssertAlwaysFalse, stmt.range()));
|
||||||
|
|
|
@ -19,7 +19,7 @@ impl Violation for PytestFailWithoutMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fail_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: &[Keyword]) {
|
pub(crate) fn fail_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: &[Keyword]) {
|
||||||
if is_pytest_fail(checker.semantic_model(), func) {
|
if is_pytest_fail(func, checker.semantic()) {
|
||||||
let call_args = SimpleCallArgs::new(args, keywords);
|
let call_args = SimpleCallArgs::new(args, keywords);
|
||||||
|
|
||||||
// Allow either `pytest.fail(reason="...")` (introduced in pytest 7.0) or
|
// Allow either `pytest.fail(reason="...")` (introduced in pytest 7.0) or
|
||||||
|
|
|
@ -245,11 +245,11 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_fixture_decorator<'a>(
|
fn get_fixture_decorator<'a>(
|
||||||
model: &SemanticModel,
|
|
||||||
decorators: &'a [Decorator],
|
decorators: &'a [Decorator],
|
||||||
|
semantic: &SemanticModel,
|
||||||
) -> Option<&'a Decorator> {
|
) -> Option<&'a Decorator> {
|
||||||
decorators.iter().find(|decorator| {
|
decorators.iter().find(|decorator| {
|
||||||
is_pytest_fixture(model, decorator) || is_pytest_yield_fixture(model, decorator)
|
is_pytest_fixture(decorator, semantic) || is_pytest_yield_fixture(decorator, semantic)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,7 +436,7 @@ fn check_test_function_args(checker: &mut Checker, args: &Arguments) {
|
||||||
|
|
||||||
/// PT020
|
/// PT020
|
||||||
fn check_fixture_decorator_name(checker: &mut Checker, decorator: &Decorator) {
|
fn check_fixture_decorator_name(checker: &mut Checker, decorator: &Decorator) {
|
||||||
if is_pytest_yield_fixture(checker.semantic_model(), decorator) {
|
if is_pytest_yield_fixture(decorator, checker.semantic()) {
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
PytestDeprecatedYieldFixture,
|
PytestDeprecatedYieldFixture,
|
||||||
decorator.range(),
|
decorator.range(),
|
||||||
|
@ -504,7 +504,7 @@ pub(crate) fn fixture(
|
||||||
decorators: &[Decorator],
|
decorators: &[Decorator],
|
||||||
body: &[Stmt],
|
body: &[Stmt],
|
||||||
) {
|
) {
|
||||||
let decorator = get_fixture_decorator(checker.semantic_model(), decorators);
|
let decorator = get_fixture_decorator(decorators, checker.semantic());
|
||||||
if let Some(decorator) = decorator {
|
if let Some(decorator) = decorator {
|
||||||
if checker.enabled(Rule::PytestFixtureIncorrectParenthesesStyle)
|
if checker.enabled(Rule::PytestFixtureIncorrectParenthesesStyle)
|
||||||
|| checker.enabled(Rule::PytestFixturePositionalArgs)
|
|| checker.enabled(Rule::PytestFixturePositionalArgs)
|
||||||
|
@ -522,7 +522,7 @@ pub(crate) fn fixture(
|
||||||
if (checker.enabled(Rule::PytestMissingFixtureNameUnderscore)
|
if (checker.enabled(Rule::PytestMissingFixtureNameUnderscore)
|
||||||
|| checker.enabled(Rule::PytestIncorrectFixtureNameUnderscore)
|
|| checker.enabled(Rule::PytestIncorrectFixtureNameUnderscore)
|
||||||
|| checker.enabled(Rule::PytestUselessYieldFixture))
|
|| checker.enabled(Rule::PytestUselessYieldFixture))
|
||||||
&& !is_abstract(checker.semantic_model(), decorators)
|
&& !is_abstract(decorators, checker.semantic())
|
||||||
{
|
{
|
||||||
check_fixture_returns(checker, stmt, name, body);
|
check_fixture_returns(checker, stmt, name, body);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,41 +20,41 @@ pub(super) fn get_mark_decorators(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn is_pytest_fail(model: &SemanticModel, call: &Expr) -> bool {
|
pub(super) fn is_pytest_fail(call: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
model.resolve_call_path(call).map_or(false, |call_path| {
|
semantic.resolve_call_path(call).map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["pytest", "fail"]
|
call_path.as_slice() == ["pytest", "fail"]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn is_pytest_fixture(model: &SemanticModel, decorator: &Decorator) -> bool {
|
pub(super) fn is_pytest_fixture(decorator: &Decorator, semantic: &SemanticModel) -> bool {
|
||||||
model
|
semantic
|
||||||
.resolve_call_path(map_callable(&decorator.expression))
|
.resolve_call_path(map_callable(&decorator.expression))
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["pytest", "fixture"]
|
call_path.as_slice() == ["pytest", "fixture"]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn is_pytest_yield_fixture(model: &SemanticModel, decorator: &Decorator) -> bool {
|
pub(super) fn is_pytest_yield_fixture(decorator: &Decorator, semantic: &SemanticModel) -> bool {
|
||||||
model
|
semantic
|
||||||
.resolve_call_path(map_callable(&decorator.expression))
|
.resolve_call_path(map_callable(&decorator.expression))
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["pytest", "yield_fixture"]
|
call_path.as_slice() == ["pytest", "yield_fixture"]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn is_pytest_parametrize(model: &SemanticModel, decorator: &Decorator) -> bool {
|
pub(super) fn is_pytest_parametrize(decorator: &Decorator, semantic: &SemanticModel) -> bool {
|
||||||
model
|
semantic
|
||||||
.resolve_call_path(map_callable(&decorator.expression))
|
.resolve_call_path(map_callable(&decorator.expression))
|
||||||
.map_or(false, |call_path| {
|
.map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["pytest", "mark", "parametrize"]
|
call_path.as_slice() == ["pytest", "mark", "parametrize"]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn keyword_is_literal(kw: &Keyword, literal: &str) -> bool {
|
pub(super) fn keyword_is_literal(keyword: &Keyword, literal: &str) -> bool {
|
||||||
if let Expr::Constant(ast::ExprConstant {
|
if let Expr::Constant(ast::ExprConstant {
|
||||||
value: Constant::Str(string),
|
value: Constant::Str(string),
|
||||||
..
|
..
|
||||||
}) = &kw.value
|
}) = &keyword.value
|
||||||
{
|
{
|
||||||
string == literal
|
string == literal
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -419,7 +419,7 @@ fn handle_value_rows(
|
||||||
|
|
||||||
pub(crate) fn parametrize(checker: &mut Checker, decorators: &[Decorator]) {
|
pub(crate) fn parametrize(checker: &mut Checker, decorators: &[Decorator]) {
|
||||||
for decorator in decorators {
|
for decorator in decorators {
|
||||||
if is_pytest_parametrize(checker.semantic_model(), decorator) {
|
if is_pytest_parametrize(decorator, checker.semantic()) {
|
||||||
if let Expr::Call(ast::ExprCall { args, .. }) = &decorator.expression {
|
if let Expr::Call(ast::ExprCall { args, .. }) = &decorator.expression {
|
||||||
if checker.enabled(Rule::PytestParametrizeNamesWrongType) {
|
if checker.enabled(Rule::PytestParametrizeNamesWrongType) {
|
||||||
if let Some(names) = args.get(0) {
|
if let Some(names) = args.get(0) {
|
||||||
|
|
|
@ -47,8 +47,8 @@ impl Violation for PytestRaisesWithoutException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_pytest_raises(func: &Expr, model: &SemanticModel) -> bool {
|
fn is_pytest_raises(func: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
model.resolve_call_path(func).map_or(false, |call_path| {
|
semantic.resolve_call_path(func).map_or(false, |call_path| {
|
||||||
call_path.as_slice() == ["pytest", "raises"]
|
call_path.as_slice() == ["pytest", "raises"]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ const fn is_non_trivial_with_body(body: &[Stmt]) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn raises_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: &[Keyword]) {
|
pub(crate) fn raises_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: &[Keyword]) {
|
||||||
if is_pytest_raises(func, checker.semantic_model()) {
|
if is_pytest_raises(func, checker.semantic()) {
|
||||||
if checker.enabled(Rule::PytestRaisesWithoutException) {
|
if checker.enabled(Rule::PytestRaisesWithoutException) {
|
||||||
if args.is_empty() && keywords.is_empty() {
|
if args.is_empty() && keywords.is_empty() {
|
||||||
checker
|
checker
|
||||||
|
@ -100,7 +100,7 @@ pub(crate) fn complex_raises(
|
||||||
let mut is_too_complex = false;
|
let mut is_too_complex = false;
|
||||||
|
|
||||||
let raises_called = items.iter().any(|item| match &item.context_expr {
|
let raises_called = items.iter().any(|item| match &item.context_expr {
|
||||||
Expr::Call(ast::ExprCall { func, .. }) => is_pytest_raises(func, checker.semantic_model()),
|
Expr::Call(ast::ExprCall { func, .. }) => is_pytest_raises(func, checker.semantic()),
|
||||||
_ => false,
|
_ => false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ pub(crate) fn complex_raises(
|
||||||
/// PT011
|
/// PT011
|
||||||
fn exception_needs_match(checker: &mut Checker, exception: &Expr) {
|
fn exception_needs_match(checker: &mut Checker, exception: &Expr) {
|
||||||
if let Some(call_path) = checker
|
if let Some(call_path) = checker
|
||||||
.semantic_model()
|
.semantic()
|
||||||
.resolve_call_path(exception)
|
.resolve_call_path(exception)
|
||||||
.and_then(|call_path| {
|
.and_then(|call_path| {
|
||||||
let is_broad_exception = checker
|
let is_broad_exception = checker
|
||||||
|
|
|
@ -398,12 +398,12 @@ const NORETURN_FUNCS: &[&[&str]] = &[
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Return `true` if the `func` is a known function that never returns.
|
/// Return `true` if the `func` is a known function that never returns.
|
||||||
fn is_noreturn_func(model: &SemanticModel, func: &Expr) -> bool {
|
fn is_noreturn_func(func: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
model.resolve_call_path(func).map_or(false, |call_path| {
|
semantic.resolve_call_path(func).map_or(false, |call_path| {
|
||||||
NORETURN_FUNCS
|
NORETURN_FUNCS
|
||||||
.iter()
|
.iter()
|
||||||
.any(|target| call_path.as_slice() == *target)
|
.any(|target| call_path.as_slice() == *target)
|
||||||
|| model.match_typing_call_path(&call_path, "assert_never")
|
|| semantic.match_typing_call_path(&call_path, "assert_never")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,7 +489,7 @@ fn implicit_return(checker: &mut Checker, stmt: &Stmt) {
|
||||||
if matches!(
|
if matches!(
|
||||||
value.as_ref(),
|
value.as_ref(),
|
||||||
Expr::Call(ast::ExprCall { func, .. })
|
Expr::Call(ast::ExprCall { func, .. })
|
||||||
if is_noreturn_func(checker.semantic_model(), func)
|
if is_noreturn_func(func, checker.semantic())
|
||||||
) => {}
|
) => {}
|
||||||
_ => {
|
_ => {
|
||||||
let mut diagnostic = Diagnostic::new(ImplicitReturn, stmt.range());
|
let mut diagnostic = Diagnostic::new(ImplicitReturn, stmt.range());
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue