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:
Charlie Marsh 2023-06-14 15:01:51 -04:00 committed by GitHub
parent 65dbfd2556
commit bae183b823
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
209 changed files with 1058 additions and 1167 deletions

File diff suppressed because it is too large Load diff

View file

@ -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,

View file

@ -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"))
{ {

View file

@ -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])
} }

View file

@ -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 {

View file

@ -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"])
{ {

View file

@ -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,

View file

@ -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);

View file

@ -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(

View file

@ -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()));

View file

@ -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()));

View file

@ -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())

View file

@ -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"]
})
} }
}) })
} }

View file

@ -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"])
{ {

View file

@ -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));
} }

View file

@ -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 => {

View file

@ -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"]

View file

@ -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"]

View file

@ -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"]

View file

@ -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 {

View file

@ -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

View file

@ -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,
}) })
} }

View file

@ -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"]

View file

@ -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"]

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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"]

View file

@ -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" {

View file

@ -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 {

View file

@ -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"]

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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"]

View file

@ -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"]

View file

@ -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());

View file

@ -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(

View file

@ -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"]

View file

@ -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(_)) {

View file

@ -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,
}); }
})
} }

View file

@ -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;
} }

View file

@ -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;
} }

View file

@ -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(

View file

@ -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(

View file

@ -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(

View file

@ -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());

View file

@ -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;
} }

View file

@ -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 {

View file

@ -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 {

View file

@ -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() {

View file

@ -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 {

View file

@ -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() {

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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;
} }

View file

@ -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 {

View file

@ -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"]

View file

@ -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"]

View file

@ -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"]

View file

@ -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"]

View file

@ -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,

View file

@ -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"]

View file

@ -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"]

View file

@ -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"]

View file

@ -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"]

View file

@ -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

View file

@ -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;
} }

View file

@ -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;
} }

View file

@ -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;

View file

@ -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"])
} }

View file

@ -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;
} }
} }

View file

@ -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;
}; };

View file

@ -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

View file

@ -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,

View file

@ -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));

View file

@ -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 {

View file

@ -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"])
{ {

View file

@ -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(),

View file

@ -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;
} }
} }

View file

@ -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(),

View file

@ -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"]

View file

@ -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"])

View file

@ -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_ {

View file

@ -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 {

View file

@ -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!(

View file

@ -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

View file

@ -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;
} }

View file

@ -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);

View file

@ -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"]

View file

@ -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()));

View file

@ -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

View file

@ -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);
} }

View file

@ -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 {

View file

@ -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) {

View file

@ -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

View file

@ -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