diff --git a/Cargo.lock b/Cargo.lock index a4b3201354..adc3187a10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2010,6 +2010,7 @@ dependencies = [ "ruff_diagnostics", "ruff_macros", "ruff_python_ast", + "ruff_python_semantic", "ruff_python_stdlib", "ruff_rustpython", "rustc-hash", @@ -2170,12 +2171,10 @@ dependencies = [ "is-macro", "itertools", "log", - "nohash-hasher", "num-bigint", "num-traits", "once_cell", "regex", - "ruff_python_stdlib", "ruff_rustpython", "rustc-hash", "rustpython-common", @@ -2196,7 +2195,6 @@ dependencies = [ "once_cell", "ruff_formatter", "ruff_python_ast", - "ruff_python_stdlib", "ruff_rustpython", "ruff_testing_macros", "ruff_text_size", @@ -2207,6 +2205,20 @@ dependencies = [ "test-case", ] +[[package]] +name = "ruff_python_semantic" +version = "0.0.0" +dependencies = [ + "bitflags", + "is-macro", + "nohash-hasher", + "ruff_python_ast", + "ruff_python_stdlib", + "rustc-hash", + "rustpython-parser", + "smallvec", +] + [[package]] name = "ruff_python_stdlib" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index 04f86ac887..40aa99ceb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ is-macro = { version = "0.2.2" } itertools = { version = "0.10.5" } libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "80e4c1399f95e5beb532fdd1e209ad2dbb470438" } log = { version = "0.4.17" } +nohash-hasher = { version = "0.2.0" } once_cell = { version = "1.17.1" } path-absolutize = { version = "3.0.14" } proc-macro2 = { version = "1.0.51" } @@ -40,6 +41,7 @@ serde = { version = "1.0.152", features = ["derive"] } serde_json = { version = "1.0.93", features = ["preserve_order"] } shellexpand = { version = "3.0.0" } similar = { version = "2.2.1" } +smallvec = { version = "1.10.0" } strum = { version = "0.24.1", features = ["strum_macros"] } strum_macros = { version = "0.24.3" } syn = { version = "1.0.109" } diff --git a/crates/ruff/Cargo.toml b/crates/ruff/Cargo.toml index c407f931ec..eedf38ea2f 100644 --- a/crates/ruff/Cargo.toml +++ b/crates/ruff/Cargo.toml @@ -18,6 +18,7 @@ ruff_cache = { path = "../ruff_cache" } ruff_diagnostics = { path = "../ruff_diagnostics", features = ["serde"] } ruff_macros = { path = "../ruff_macros" } ruff_python_ast = { path = "../ruff_python_ast" } +ruff_python_semantic = { path = "../ruff_python_semantic" } ruff_python_stdlib = { path = "../ruff_python_stdlib" } ruff_rustpython = { path = "../ruff_rustpython" } @@ -37,7 +38,7 @@ itertools = { workspace = true } libcst = { workspace = true } log = { workspace = true } natord = { version = "1.0.9" } -nohash-hasher = { version = "0.2.0" } +nohash-hasher = { workspace = true } num-bigint = { version = "0.4.3" } num-traits = { version = "0.2.15" } once_cell = { workspace = true } @@ -57,7 +58,7 @@ semver = { version = "1.0.16" } serde = { workspace = true } serde_json = { workspace = true } shellexpand = { workspace = true } -smallvec = { version = "1.10.0" } +smallvec = { workspace = true } strum = { workspace = true } strum_macros = { workspace = true } textwrap = { workspace = true } diff --git a/crates/ruff/src/autofix/actions.rs b/crates/ruff/src/autofix/actions.rs index a1795597f4..d370984112 100644 --- a/crates/ruff/src/autofix/actions.rs +++ b/crates/ruff/src/autofix/actions.rs @@ -8,12 +8,12 @@ use rustpython_parser::ast::{ExcepthandlerKind, Expr, Keyword, Location, Stmt, S use rustpython_parser::{lexer, Mode, Tok}; use ruff_diagnostics::Edit; -use ruff_python_ast::context::Context; use ruff_python_ast::helpers; use ruff_python_ast::helpers::to_absolute; use ruff_python_ast::imports::{AnyImport, Import}; use ruff_python_ast::newlines::NewlineWithTrailingNewline; use ruff_python_ast::source_code::{Indexer, Locator, Stylist}; +use ruff_python_semantic::context::Context; use crate::cst::helpers::compose_module_path; use crate::cst::matchers::match_module; diff --git a/crates/ruff/src/checkers/ast/deferred.rs b/crates/ruff/src/checkers/ast/deferred.rs index 169d9b347b..70b3834a38 100644 --- a/crates/ruff/src/checkers/ast/deferred.rs +++ b/crates/ruff/src/checkers/ast/deferred.rs @@ -1,9 +1,9 @@ -use ruff_python_ast::scope::ScopeStack; +use ruff_python_semantic::scope::ScopeStack; use rustpython_parser::ast::{Expr, Stmt}; use ruff_python_ast::types::Range; use ruff_python_ast::types::RefEquality; -use ruff_python_ast::visibility::{Visibility, VisibleScope}; +use ruff_python_semantic::analyze::visibility::{Visibility, VisibleScope}; use crate::checkers::ast::AnnotationContext; use crate::docstrings::definition::Definition; diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index 811a1d9057..735e5313cc 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -14,22 +14,22 @@ use rustpython_parser::ast::{ use ruff_diagnostics::Diagnostic; use ruff_python_ast::all::{extract_all_names, AllNamesFlags}; -use ruff_python_ast::binding::{ +use ruff_python_ast::helpers::{extract_handled_exceptions, to_module_path}; +use ruff_python_ast::source_code::{Indexer, Locator, Stylist}; +use ruff_python_ast::types::{Node, Range, RefEquality}; +use ruff_python_ast::typing::parse_type_annotation; +use ruff_python_ast::visitor::{walk_excepthandler, walk_pattern, Visitor}; +use ruff_python_ast::{branch_detection, cast, helpers, str, visitor}; +use ruff_python_semantic::analyze; +use ruff_python_semantic::analyze::typing::{Callable, SubscriptKind}; +use ruff_python_semantic::binding::{ Binding, BindingId, BindingKind, Exceptions, ExecutionContext, Export, FromImportation, Importation, StarImportation, SubmoduleImportation, }; -use ruff_python_ast::context::Context; -use ruff_python_ast::helpers::{extract_handled_exceptions, to_module_path}; -use ruff_python_ast::scope::{ +use ruff_python_semantic::context::Context; +use ruff_python_semantic::scope::{ ClassDef, FunctionDef, Lambda, Scope, ScopeId, ScopeKind, ScopeStack, }; -use ruff_python_ast::source_code::{Indexer, Locator, Stylist}; -use ruff_python_ast::types::{Node, Range, RefEquality}; -use ruff_python_ast::typing::{ - match_annotated_subscript, parse_type_annotation, Callable, SubscriptKind, -}; -use ruff_python_ast::visitor::{walk_excepthandler, walk_pattern, Visitor}; -use ruff_python_ast::{branch_detection, cast, helpers, str, typing, visibility, visitor}; use ruff_python_stdlib::builtins::{BUILTINS, MAGIC_GLOBALS}; use ruff_python_stdlib::path::is_python_stub_file; @@ -2248,7 +2248,7 @@ where || (self.settings.target_version >= PythonVersion::Py37 && self.ctx.annotations_future_enabled && self.ctx.in_annotation)) - && typing::is_pep585_builtin(expr, &self.ctx) + && analyze::typing::is_pep585_builtin(expr, &self.ctx) { pyupgrade::rules::use_pep585_annotation(self, expr); } @@ -2291,7 +2291,7 @@ where || (self.settings.target_version >= PythonVersion::Py37 && self.ctx.annotations_future_enabled && self.ctx.in_annotation)) - && typing::is_pep585_builtin(expr, &self.ctx) + && analyze::typing::is_pep585_builtin(expr, &self.ctx) { pyupgrade::rules::use_pep585_annotation(self, expr); } @@ -3632,7 +3632,7 @@ where self.ctx.in_subscript = true; visitor::walk_expr(self, expr); } else { - match match_annotated_subscript( + match analyze::typing::match_annotated_subscript( value, &self.ctx, self.settings.typing_modules.iter().map(String::as_str), @@ -4051,7 +4051,7 @@ impl<'a> Checker<'a> { && binding.redefines(existing) && (!self.settings.dummy_variable_rgx.is_match(name) || existing_is_import) && !(existing.kind.is_function_definition() - && visibility::is_overload( + && analyze::visibility::is_overload( &self.ctx, cast::decorator_list(existing.source.as_ref().unwrap()), )) diff --git a/crates/ruff/src/docstrings/definition.rs b/crates/ruff/src/docstrings/definition.rs index 3da648d0b4..9a6e38d443 100644 --- a/crates/ruff/src/docstrings/definition.rs +++ b/crates/ruff/src/docstrings/definition.rs @@ -1,7 +1,8 @@ -use ruff_python_ast::visibility::{ +use rustpython_parser::ast::{Expr, Stmt}; + +use ruff_python_semantic::analyze::visibility::{ class_visibility, function_visibility, method_visibility, Modifier, Visibility, VisibleScope, }; -use rustpython_parser::ast::{Expr, Stmt}; #[derive(Debug, Clone)] pub enum DefinitionKind<'a> { diff --git a/crates/ruff/src/docstrings/extraction.rs b/crates/ruff/src/docstrings/extraction.rs index 8d1bae2835..7fbe79a2d1 100644 --- a/crates/ruff/src/docstrings/extraction.rs +++ b/crates/ruff/src/docstrings/extraction.rs @@ -2,7 +2,7 @@ use rustpython_parser::ast::{Constant, Expr, ExprKind, Stmt, StmtKind}; -use ruff_python_ast::visibility::{Modifier, VisibleScope}; +use ruff_python_semantic::analyze::visibility; use crate::docstrings::definition::{Definition, DefinitionKind, Documentable}; @@ -28,7 +28,7 @@ pub fn docstring_from(suite: &[Stmt]) -> Option<&Expr> { /// Extract a `Definition` from the AST node defined by a `Stmt`. pub fn extract<'a>( - scope: VisibleScope, + scope: visibility::VisibleScope, stmt: &'a Stmt, body: &'a [Stmt], kind: Documentable, @@ -36,22 +36,22 @@ pub fn extract<'a>( let expr = docstring_from(body); match kind { Documentable::Function => match scope { - VisibleScope { - modifier: Modifier::Module, + visibility::VisibleScope { + modifier: visibility::Modifier::Module, .. } => Definition { kind: DefinitionKind::Function(stmt), docstring: expr, }, - VisibleScope { - modifier: Modifier::Class, + visibility::VisibleScope { + modifier: visibility::Modifier::Class, .. } => Definition { kind: DefinitionKind::Method(stmt), docstring: expr, }, - VisibleScope { - modifier: Modifier::Function, + visibility::VisibleScope { + modifier: visibility::Modifier::Function, .. } => Definition { kind: DefinitionKind::NestedFunction(stmt), @@ -59,22 +59,22 @@ pub fn extract<'a>( }, }, Documentable::Class => match scope { - VisibleScope { - modifier: Modifier::Module, + visibility::VisibleScope { + modifier: visibility::Modifier::Module, .. } => Definition { kind: DefinitionKind::Class(stmt), docstring: expr, }, - VisibleScope { - modifier: Modifier::Class, + visibility::VisibleScope { + modifier: visibility::Modifier::Class, .. } => Definition { kind: DefinitionKind::NestedClass(stmt), docstring: expr, }, - VisibleScope { - modifier: Modifier::Function, + visibility::VisibleScope { + modifier: visibility::Modifier::Function, .. } => Definition { kind: DefinitionKind::NestedClass(stmt), diff --git a/crates/ruff/src/rules/flake8_annotations/helpers.rs b/crates/ruff/src/rules/flake8_annotations/helpers.rs index 5d16e832d4..8702c6f957 100644 --- a/crates/ruff/src/rules/flake8_annotations/helpers.rs +++ b/crates/ruff/src/rules/flake8_annotations/helpers.rs @@ -1,7 +1,7 @@ use rustpython_parser::ast::{Arguments, Expr, Stmt, StmtKind}; use ruff_python_ast::cast; -use ruff_python_ast::visibility; +use ruff_python_semantic::analyze::visibility; use crate::checkers::ast::Checker; use crate::docstrings::definition::{Definition, DefinitionKind}; diff --git a/crates/ruff/src/rules/flake8_annotations/rules.rs b/crates/ruff/src/rules/flake8_annotations/rules.rs index 776a392ffc..0da004ae36 100644 --- a/crates/ruff/src/rules/flake8_annotations/rules.rs +++ b/crates/ruff/src/rules/flake8_annotations/rules.rs @@ -4,10 +4,10 @@ use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::ReturnStatementVisitor; use ruff_python_ast::types::Range; -use ruff_python_ast::visibility::Visibility; -use ruff_python_ast::visibility::{self}; use ruff_python_ast::visitor::Visitor; use ruff_python_ast::{cast, helpers}; +use ruff_python_semantic::analyze::visibility; +use ruff_python_semantic::analyze::visibility::Visibility; use ruff_python_stdlib::typing::SIMPLE_MAGIC_RETURN_TYPES; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/flake8_blind_except/rules.rs b/crates/ruff/src/rules/flake8_blind_except/rules.rs index 15b5fa62ba..556260f424 100644 --- a/crates/ruff/src/rules/flake8_blind_except/rules.rs +++ b/crates/ruff/src/rules/flake8_blind_except/rules.rs @@ -3,8 +3,8 @@ use rustpython_parser::ast::{Expr, ExprKind, Stmt, StmtKind}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::{find_keyword, is_const_true}; -use ruff_python_ast::logging; use ruff_python_ast::types::Range; +use ruff_python_semantic::analyze::logging; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs b/crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs index 2bf4244827..eed77aa051 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs @@ -3,7 +3,7 @@ use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword, Stmt, StmtKind}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::types::Range; -use ruff_python_ast::visibility::{is_abstract, is_overload}; +use ruff_python_semantic::analyze::visibility::{is_abstract, is_overload}; use crate::checkers::ast::Checker; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/cached_instance_method.rs b/crates/ruff/src/rules/flake8_bugbear/rules/cached_instance_method.rs index e849ef94ce..0aa7451e14 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/cached_instance_method.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/cached_instance_method.rs @@ -2,8 +2,8 @@ use rustpython_parser::ast::{Expr, ExprKind}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::scope::ScopeKind; use ruff_python_ast::types::Range; +use ruff_python_semantic::scope::ScopeKind; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/flake8_django/rules/helpers.rs b/crates/ruff/src/rules/flake8_django/rules/helpers.rs index 60f7c1c32a..6d3bc724cc 100644 --- a/crates/ruff/src/rules/flake8_django/rules/helpers.rs +++ b/crates/ruff/src/rules/flake8_django/rules/helpers.rs @@ -1,6 +1,6 @@ use rustpython_parser::ast::Expr; -use ruff_python_ast::context::Context; +use ruff_python_semantic::context::Context; /// Return `true` if a Python class appears to be a Django model, based on its base classes. pub fn is_model(context: &Context, base: &Expr) -> bool { diff --git a/crates/ruff/src/rules/flake8_logging_format/rules.rs b/crates/ruff/src/rules/flake8_logging_format/rules.rs index eafdf5d25b..df60592b70 100644 --- a/crates/ruff/src/rules/flake8_logging_format/rules.rs +++ b/crates/ruff/src/rules/flake8_logging_format/rules.rs @@ -2,8 +2,9 @@ use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword, Location, Operat use ruff_diagnostics::{Diagnostic, Edit}; use ruff_python_ast::helpers::{find_keyword, SimpleCallArgs}; -use ruff_python_ast::logging; use ruff_python_ast::types::Range; +use ruff_python_semantic::analyze::logging; +use ruff_python_stdlib::logging::LoggingLevel; use crate::checkers::ast::Checker; use crate::registry::{AsRule, Rule}; @@ -128,7 +129,7 @@ fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) { #[derive(Copy, Clone)] enum LoggingCallType { /// Logging call with a level method, e.g., `logging.info`. - LevelCall(logging::LoggingLevel), + LevelCall(LoggingLevel), /// Logging call with an integer level as an argument, e.g., `logger.log(level, ...)`. LogCall, } @@ -138,7 +139,7 @@ impl LoggingCallType { if attr == "log" { Some(LoggingCallType::LogCall) } else { - logging::LoggingLevel::from_attribute(attr).map(LoggingCallType::LevelCall) + LoggingLevel::from_attribute(attr).map(LoggingCallType::LevelCall) } } } @@ -173,7 +174,7 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: if checker.settings.rules.enabled(Rule::LoggingWarn) && matches!( logging_call_type, - LoggingCallType::LevelCall(logging::LoggingLevel::Warn) + LoggingCallType::LevelCall(LoggingLevel::Warn) ) { let mut diagnostic = Diagnostic::new(LoggingWarn, level_call_range); @@ -228,14 +229,14 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: if let LoggingCallType::LevelCall(logging_level) = logging_call_type { match logging_level { - logging::LoggingLevel::Error => { + LoggingLevel::Error => { if checker.settings.rules.enabled(Rule::LoggingExcInfo) { checker .diagnostics .push(Diagnostic::new(LoggingExcInfo, level_call_range)); } } - logging::LoggingLevel::Exception => { + LoggingLevel::Exception => { if checker .settings .rules diff --git a/crates/ruff/src/rules/flake8_self/rules/private_member_access.rs b/crates/ruff/src/rules/flake8_self/rules/private_member_access.rs index f7616fdc8f..119c29c6b9 100644 --- a/crates/ruff/src/rules/flake8_self/rules/private_member_access.rs +++ b/crates/ruff/src/rules/flake8_self/rules/private_member_access.rs @@ -3,8 +3,8 @@ use rustpython_parser::ast::{Expr, ExprKind}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::call_path::collect_call_path; -use ruff_python_ast::scope::ScopeKind; use ruff_python_ast::types::Range; +use ruff_python_semantic::scope::ScopeKind; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/flake8_simplify/rules/ast_bool_op.rs b/crates/ruff/src/rules/flake8_simplify/rules/ast_bool_op.rs index 5a16f41b93..e4d8b55c59 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/ast_bool_op.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/ast_bool_op.rs @@ -11,9 +11,9 @@ use rustpython_parser::ast::{ use ruff_diagnostics::{AlwaysAutofixableViolation, AutofixKind, Diagnostic, Edit, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::comparable::ComparableExpr; -use ruff_python_ast::context::Context; use ruff_python_ast::helpers::{contains_effect, create_expr, has_comments, unparse_expr}; use ruff_python_ast::types::Range; +use ruff_python_semantic::context::Context; use crate::checkers::ast::Checker; use crate::registry::AsRule; diff --git a/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs b/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs index fea7226802..b550d3d4e2 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs @@ -7,11 +7,12 @@ use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::comparable::{ComparableConstant, ComparableExpr, ComparableStmt}; use ruff_python_ast::helpers::{ - contains_call_path, contains_effect, create_expr, create_stmt, first_colon_range, has_comments, + any_over_expr, contains_effect, create_expr, create_stmt, first_colon_range, has_comments, has_comments_in, unparse_expr, unparse_stmt, }; use ruff_python_ast::newlines::StrExt; use ruff_python_ast::types::Range; +use ruff_python_semantic::context::Context; use crate::checkers::ast::Checker; use crate::registry::AsRule; @@ -415,6 +416,14 @@ fn ternary(target_var: &Expr, body_value: &Expr, test: &Expr, orelse_value: &Exp }) } +/// Return `true` if the `Expr` contains a reference to `${module}.${target}`. +fn contains_call_path(ctx: &Context, expr: &Expr, target: &[&str]) -> bool { + any_over_expr(expr, &|expr| { + ctx.resolve_call_path(expr) + .map_or(false, |call_path| call_path.as_slice() == target) + }) +} + /// SIM108 pub fn use_ternary_operator(checker: &mut Checker, stmt: &Stmt, parent: Option<&Stmt>) { let StmtKind::If { test, body, orelse } = &stmt.node else { diff --git a/crates/ruff/src/rules/flake8_simplify/rules/ast_unary_op.rs b/crates/ruff/src/rules/flake8_simplify/rules/ast_unary_op.rs index 4c8036e6b5..c187dc4afe 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/ast_unary_op.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/ast_unary_op.rs @@ -3,8 +3,8 @@ use rustpython_parser::ast::{Cmpop, Expr, ExprKind, Stmt, StmtKind, Unaryop}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::{create_expr, unparse_expr}; -use ruff_python_ast::scope::ScopeKind; use ruff_python_ast::types::Range; +use ruff_python_semantic::scope::ScopeKind; use crate::checkers::ast::Checker; use crate::registry::AsRule; diff --git a/crates/ruff/src/rules/flake8_type_checking/helpers.rs b/crates/ruff/src/rules/flake8_type_checking/helpers.rs index 94d41e9f93..86e851e7d9 100644 --- a/crates/ruff/src/rules/flake8_type_checking/helpers.rs +++ b/crates/ruff/src/rules/flake8_type_checking/helpers.rs @@ -1,11 +1,11 @@ use num_traits::Zero; use rustpython_parser::ast::{Constant, Expr, ExprKind}; -use ruff_python_ast::binding::{Binding, BindingKind, ExecutionContext}; use ruff_python_ast::call_path::from_qualified_name; -use ruff_python_ast::context::Context; use ruff_python_ast::helpers::map_callable; -use ruff_python_ast::scope::ScopeKind; +use ruff_python_semantic::binding::{Binding, BindingKind, ExecutionContext}; +use ruff_python_semantic::context::Context; +use ruff_python_semantic::scope::ScopeKind; /// Return `true` if [`Expr`] is a guard for a type-checking block. pub fn is_type_checking_block(context: &Context, test: &Expr) -> bool { diff --git a/crates/ruff/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs b/crates/ruff/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs index 3a56d5b060..3b38be9a5e 100644 --- a/crates/ruff/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs +++ b/crates/ruff/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs @@ -1,6 +1,6 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::binding::{ +use ruff_python_semantic::binding::{ Binding, BindingKind, ExecutionContext, FromImportation, Importation, SubmoduleImportation, }; diff --git a/crates/ruff/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs b/crates/ruff/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs index ab3b92dd22..979ecbad19 100644 --- a/crates/ruff/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs +++ b/crates/ruff/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs @@ -2,7 +2,7 @@ use std::path::Path; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::binding::{ +use ruff_python_semantic::binding::{ Binding, BindingKind, ExecutionContext, FromImportation, Importation, SubmoduleImportation, }; diff --git a/crates/ruff/src/rules/flake8_unused_arguments/rules.rs b/crates/ruff/src/rules/flake8_unused_arguments/rules.rs index 6d9ee58237..f67b362775 100644 --- a/crates/ruff/src/rules/flake8_unused_arguments/rules.rs +++ b/crates/ruff/src/rules/flake8_unused_arguments/rules.rs @@ -5,11 +5,11 @@ use rustpython_parser::ast::{Arg, Arguments}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::binding::Bindings; -use ruff_python_ast::function_type; -use ruff_python_ast::function_type::FunctionType; -use ruff_python_ast::scope::{FunctionDef, Lambda, Scope, ScopeKind}; -use ruff_python_ast::visibility; +use ruff_python_semantic::analyze::function_type; +use ruff_python_semantic::analyze::function_type::FunctionType; +use ruff_python_semantic::analyze::visibility; +use ruff_python_semantic::binding::Bindings; +use ruff_python_semantic::scope::{FunctionDef, Lambda, Scope, ScopeKind}; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pandas_vet/rules/check_attr.rs b/crates/ruff/src/rules/pandas_vet/rules/check_attr.rs index 45e94ad41f..1af4748471 100644 --- a/crates/ruff/src/rules/pandas_vet/rules/check_attr.rs +++ b/crates/ruff/src/rules/pandas_vet/rules/check_attr.rs @@ -3,8 +3,8 @@ use rustpython_parser::ast::{Expr, ExprKind}; use ruff_diagnostics::Violation; use ruff_diagnostics::{Diagnostic, DiagnosticKind}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::binding::BindingKind; use ruff_python_ast::types::Range; +use ruff_python_semantic::binding::BindingKind; use crate::checkers::ast::Checker; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/pandas_vet/rules/check_call.rs b/crates/ruff/src/rules/pandas_vet/rules/check_call.rs index 963c008356..58729ddf31 100644 --- a/crates/ruff/src/rules/pandas_vet/rules/check_call.rs +++ b/crates/ruff/src/rules/pandas_vet/rules/check_call.rs @@ -3,8 +3,8 @@ use rustpython_parser::ast::{Expr, ExprKind}; use ruff_diagnostics::Violation; use ruff_diagnostics::{Diagnostic, DiagnosticKind}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::binding::{BindingKind, Importation}; use ruff_python_ast::types::Range; +use ruff_python_semantic::binding::{BindingKind, Importation}; use crate::checkers::ast::Checker; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/pep8_naming/rules/dunder_function_name.rs b/crates/ruff/src/rules/pep8_naming/rules/dunder_function_name.rs index 8b94be1745..43b3f5827b 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/dunder_function_name.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/dunder_function_name.rs @@ -3,8 +3,8 @@ use rustpython_parser::ast::Stmt; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::identifier_range; -use ruff_python_ast::scope::{Scope, ScopeKind}; use ruff_python_ast::source_code::Locator; +use ruff_python_semantic::scope::{Scope, ScopeKind}; /// ## What it does /// Checks for functions with "dunder" names (that is, names with two diff --git a/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs b/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs index 19bce27712..dea5da31af 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs @@ -2,9 +2,9 @@ use rustpython_parser::ast::{Arguments, Expr}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::function_type; -use ruff_python_ast::scope::Scope; use ruff_python_ast::types::Range; +use ruff_python_semantic::analyze::function_type; +use ruff_python_semantic::scope::Scope; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs b/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs index f090d8b1cd..8819edb483 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs @@ -2,9 +2,9 @@ use rustpython_parser::ast::{Arguments, Expr}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::function_type; -use ruff_python_ast::scope::Scope; use ruff_python_ast::types::Range; +use ruff_python_semantic::analyze::function_type; +use ruff_python_semantic::scope::Scope; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pycodestyle/rules/lambda_assignment.rs b/crates/ruff/src/rules/pycodestyle/rules/lambda_assignment.rs index 50c1887272..26a422c391 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/lambda_assignment.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/lambda_assignment.rs @@ -4,10 +4,10 @@ use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::{match_leading_content, match_trailing_content, unparse_stmt}; use ruff_python_ast::newlines::StrExt; -use ruff_python_ast::scope::ScopeKind; use ruff_python_ast::source_code::Stylist; use ruff_python_ast::types::Range; use ruff_python_ast::whitespace::leading_space; +use ruff_python_semantic::scope::ScopeKind; use crate::checkers::ast::Checker; use crate::registry::AsRule; diff --git a/crates/ruff/src/rules/pydocstyle/rules/if_needed.rs b/crates/ruff/src/rules/pydocstyle/rules/if_needed.rs index 43c0d4b3eb..ecb2d9e299 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/if_needed.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/if_needed.rs @@ -2,7 +2,7 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::cast; use ruff_python_ast::helpers::identifier_range; -use ruff_python_ast::visibility::is_overload; +use ruff_python_semantic::analyze::visibility::is_overload; use crate::checkers::ast::Checker; use crate::docstrings::definition::{DefinitionKind, Docstring}; diff --git a/crates/ruff/src/rules/pydocstyle/rules/non_imperative_mood.rs b/crates/ruff/src/rules/pydocstyle/rules/non_imperative_mood.rs index a869efdb3d..91a38951d8 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/non_imperative_mood.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/non_imperative_mood.rs @@ -9,7 +9,7 @@ use ruff_python_ast::call_path::{from_qualified_name, CallPath}; use ruff_python_ast::cast; use ruff_python_ast::newlines::StrExt; use ruff_python_ast::types::Range; -use ruff_python_ast::visibility::{is_property, is_test}; +use ruff_python_semantic::analyze::visibility::{is_property, is_test}; use crate::checkers::ast::Checker; use crate::docstrings::definition::{DefinitionKind, Docstring}; diff --git a/crates/ruff/src/rules/pydocstyle/rules/not_missing.rs b/crates/ruff/src/rules/pydocstyle/rules/not_missing.rs index a0852a21df..dd3ed14616 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/not_missing.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/not_missing.rs @@ -3,7 +3,7 @@ use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::cast; use ruff_python_ast::helpers::identifier_range; use ruff_python_ast::types::Range; -use ruff_python_ast::visibility::{ +use ruff_python_semantic::analyze::visibility::{ is_call, is_init, is_magic, is_new, is_overload, is_override, Visibility, }; diff --git a/crates/ruff/src/rules/pydocstyle/rules/sections.rs b/crates/ruff/src/rules/pydocstyle/rules/sections.rs index 19c591fdbf..7621f3605c 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/sections.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/sections.rs @@ -10,8 +10,8 @@ use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::identifier_range; use ruff_python_ast::newlines::NewlineWithTrailingNewline; use ruff_python_ast::types::Range; -use ruff_python_ast::visibility::is_staticmethod; use ruff_python_ast::{cast, whitespace}; +use ruff_python_semantic::analyze::visibility::is_staticmethod; use crate::checkers::ast::Checker; use crate::docstrings::definition::{DefinitionKind, Docstring}; diff --git a/crates/ruff/src/rules/pyflakes/rules/return_outside_function.rs b/crates/ruff/src/rules/pyflakes/rules/return_outside_function.rs index d5688ac43c..73254b6e47 100644 --- a/crates/ruff/src/rules/pyflakes/rules/return_outside_function.rs +++ b/crates/ruff/src/rules/pyflakes/rules/return_outside_function.rs @@ -2,8 +2,8 @@ use rustpython_parser::ast::Stmt; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::scope::ScopeKind; use ruff_python_ast::types::Range; +use ruff_python_semantic::scope::ScopeKind; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pyflakes/rules/undefined_export.rs b/crates/ruff/src/rules/pyflakes/rules/undefined_export.rs index a4ad0520f4..2b2ed7313f 100644 --- a/crates/ruff/src/rules/pyflakes/rules/undefined_export.rs +++ b/crates/ruff/src/rules/pyflakes/rules/undefined_export.rs @@ -1,7 +1,7 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::scope::Scope; use ruff_python_ast::types::Range; +use ruff_python_semantic::scope::Scope; #[violation] pub struct UndefinedExport { diff --git a/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs b/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs index b8d5d90c16..456fd3841a 100644 --- a/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs +++ b/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs @@ -2,8 +2,8 @@ use std::string::ToString; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::binding::Bindings; -use ruff_python_ast::scope::{Scope, ScopeKind}; +use ruff_python_semantic::binding::Bindings; +use ruff_python_semantic::scope::{Scope, ScopeKind}; #[violation] pub struct UndefinedLocal { diff --git a/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs b/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs index 80f87b988e..65f60ed927 100644 --- a/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs +++ b/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs @@ -1,6 +1,6 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::scope::ScopeId; +use ruff_python_semantic::scope::ScopeId; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pyflakes/rules/unused_variable.rs b/crates/ruff/src/rules/pyflakes/rules/unused_variable.rs index b9e5bff4cd..47f0454b15 100644 --- a/crates/ruff/src/rules/pyflakes/rules/unused_variable.rs +++ b/crates/ruff/src/rules/pyflakes/rules/unused_variable.rs @@ -6,9 +6,9 @@ use rustpython_parser::{lexer, Mode, Tok}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::contains_effect; -use ruff_python_ast::scope::{ScopeId, ScopeKind}; use ruff_python_ast::source_code::Locator; use ruff_python_ast::types::{Range, RefEquality}; +use ruff_python_semantic::scope::{ScopeId, ScopeKind}; use crate::autofix::actions::delete_stmt; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pyflakes/rules/yield_outside_function.rs b/crates/ruff/src/rules/pyflakes/rules/yield_outside_function.rs index b10964aedd..5f58c6fadf 100644 --- a/crates/ruff/src/rules/pyflakes/rules/yield_outside_function.rs +++ b/crates/ruff/src/rules/pyflakes/rules/yield_outside_function.rs @@ -4,8 +4,8 @@ use rustpython_parser::ast::{Expr, ExprKind}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::scope::ScopeKind; use ruff_python_ast::types::Range; +use ruff_python_semantic::scope::ScopeKind; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pylint/helpers.rs b/crates/ruff/src/rules/pylint/helpers.rs index d083a42b04..b33965b129 100644 --- a/crates/ruff/src/rules/pylint/helpers.rs +++ b/crates/ruff/src/rules/pylint/helpers.rs @@ -1,6 +1,6 @@ -use ruff_python_ast::function_type; -use ruff_python_ast::function_type::FunctionType; -use ruff_python_ast::scope::{FunctionDef, ScopeKind}; +use ruff_python_semantic::analyze::function_type; +use ruff_python_semantic::analyze::function_type::FunctionType; +use ruff_python_semantic::scope::{FunctionDef, ScopeKind}; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pylint/rules/await_outside_async.rs b/crates/ruff/src/rules/pylint/rules/await_outside_async.rs index 73e72135d4..f5b9317c8d 100644 --- a/crates/ruff/src/rules/pylint/rules/await_outside_async.rs +++ b/crates/ruff/src/rules/pylint/rules/await_outside_async.rs @@ -2,8 +2,8 @@ use rustpython_parser::ast::Expr; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::scope::{FunctionDef, ScopeKind}; use ruff_python_ast::types::Range; +use ruff_python_semantic::scope::{FunctionDef, ScopeKind}; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pylint/rules/load_before_global_declaration.rs b/crates/ruff/src/rules/pylint/rules/load_before_global_declaration.rs index 100df18cfa..291c4c0b43 100644 --- a/crates/ruff/src/rules/pylint/rules/load_before_global_declaration.rs +++ b/crates/ruff/src/rules/pylint/rules/load_before_global_declaration.rs @@ -2,8 +2,8 @@ use rustpython_parser::ast::Expr; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::scope::ScopeKind; use ruff_python_ast::types::Range; +use ruff_python_semantic::scope::ScopeKind; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pylint/rules/logging.rs b/crates/ruff/src/rules/pylint/rules/logging.rs index f3634e58f1..2242b4ca81 100644 --- a/crates/ruff/src/rules/pylint/rules/logging.rs +++ b/crates/ruff/src/rules/pylint/rules/logging.rs @@ -3,8 +3,9 @@ use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::SimpleCallArgs; -use ruff_python_ast::logging; use ruff_python_ast::types::Range; +use ruff_python_semantic::analyze::logging; +use ruff_python_stdlib::logging::LoggingLevel; use crate::checkers::ast::Checker; use crate::registry::Rule; @@ -105,7 +106,7 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: } if let ExprKind::Attribute { attr, .. } = &func.node { - if logging::LoggingLevel::from_attribute(attr.as_str()).is_some() { + if LoggingLevel::from_attribute(attr.as_str()).is_some() { let call_args = SimpleCallArgs::new(args, keywords); if let Some(msg) = call_args.argument("msg", 0) { if let ExprKind::Constant { diff --git a/crates/ruff/src/rules/pyupgrade/rules/os_error_alias.rs b/crates/ruff/src/rules/pyupgrade/rules/os_error_alias.rs index e47d51161e..4e026acbf6 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/os_error_alias.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/os_error_alias.rs @@ -3,9 +3,9 @@ use rustpython_parser::ast::{Excepthandler, ExcepthandlerKind, Expr, ExprContext use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::call_path::compose_call_path; -use ruff_python_ast::context::Context; use ruff_python_ast::helpers::{create_expr, unparse_expr}; use ruff_python_ast::types::Range; +use ruff_python_semantic::context::Context; use crate::checkers::ast::Checker; use crate::registry::AsRule; diff --git a/crates/ruff/src/rules/pyupgrade/rules/super_call_with_parameters.rs b/crates/ruff/src/rules/pyupgrade/rules/super_call_with_parameters.rs index 36d26d4f56..156173d128 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/super_call_with_parameters.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/super_call_with_parameters.rs @@ -2,8 +2,8 @@ use rustpython_parser::ast::{ArgData, Expr, ExprKind, Stmt, StmtKind}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::scope::ScopeKind; use ruff_python_ast::types::Range; +use ruff_python_semantic::scope::ScopeKind; use crate::checkers::ast::Checker; use crate::registry::AsRule; diff --git a/crates/ruff/src/rules/pyupgrade/rules/useless_object_inheritance.rs b/crates/ruff/src/rules/pyupgrade/rules/useless_object_inheritance.rs index 48d5202c8c..014d4d6eb4 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/useless_object_inheritance.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/useless_object_inheritance.rs @@ -2,9 +2,9 @@ use rustpython_parser::ast::{Expr, ExprKind, Keyword, Stmt}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::binding::{Binding, BindingKind, Bindings}; -use ruff_python_ast::scope::Scope; use ruff_python_ast::types::Range; +use ruff_python_semantic::binding::{Binding, BindingKind, Bindings}; +use ruff_python_semantic::scope::Scope; use crate::autofix::actions::remove_argument; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/tryceratops/helpers.rs b/crates/ruff/src/rules/tryceratops/helpers.rs index 16a4d4aab1..f9a204dc69 100644 --- a/crates/ruff/src/rules/tryceratops/helpers.rs +++ b/crates/ruff/src/rules/tryceratops/helpers.rs @@ -1,8 +1,9 @@ use rustpython_parser::ast::{Expr, ExprKind}; -use ruff_python_ast::context::Context; +use ruff_python_ast::visitor; use ruff_python_ast::visitor::Visitor; -use ruff_python_ast::{logging, visitor}; +use ruff_python_semantic::analyze::logging; +use ruff_python_semantic::context::Context; /// Collect `logging`-like calls from an AST. pub struct LoggerCandidateVisitor<'a> { diff --git a/crates/ruff_python_ast/Cargo.toml b/crates/ruff_python_ast/Cargo.toml index 635a315c80..1ecb46b9f1 100644 --- a/crates/ruff_python_ast/Cargo.toml +++ b/crates/ruff_python_ast/Cargo.toml @@ -8,7 +8,6 @@ rust-version = { workspace = true } [lib] [dependencies] -ruff_python_stdlib = { path = "../ruff_python_stdlib" } ruff_rustpython = { path = "../ruff_rustpython" } anyhow = { workspace = true } @@ -16,7 +15,6 @@ bitflags = { workspace = true } is-macro = { workspace = true } itertools = { workspace = true } log = { workspace = true } -nohash-hasher = { version = "0.2.0" } num-bigint = { version = "0.4.3" } num-traits = { version = "0.2.15" } once_cell = { workspace = true } @@ -25,4 +23,4 @@ rustc-hash = { workspace = true } rustpython-common = { workspace = true } rustpython-parser = { workspace = true } serde = { workspace = true } -smallvec = { version = "1.10.0" } +smallvec = { workspace = true } diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index 005dca7051..6956899193 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -13,7 +13,6 @@ use rustpython_parser::{lexer, Mode, Tok}; use smallvec::SmallVec; use crate::call_path::CallPath; -use crate::context::Context; use crate::source_code::{Generator, Indexer, Locator, Stylist}; use crate::types::Range; use crate::visitor; @@ -50,14 +49,6 @@ pub fn unparse_constant(constant: &Constant, stylist: &Stylist) -> String { generator.generate() } -/// Return `true` if the `Expr` contains a reference to `${module}.${target}`. -pub fn contains_call_path(ctx: &Context, expr: &Expr, target: &[&str]) -> bool { - any_over_expr(expr, &|expr| { - ctx.resolve_call_path(expr) - .map_or(false, |call_path| call_path.as_slice() == target) - }) -} - /// Return `true` if the `Expr` contains an expression that appears to include a /// side-effect (like a function call). /// diff --git a/crates/ruff_python_ast/src/lib.rs b/crates/ruff_python_ast/src/lib.rs index 65d810962a..14afd50a66 100644 --- a/crates/ruff_python_ast/src/lib.rs +++ b/crates/ruff_python_ast/src/lib.rs @@ -1,23 +1,17 @@ pub mod all; -pub mod binding; pub mod branch_detection; pub mod call_path; pub mod cast; pub mod comparable; -pub mod context; -pub mod function_type; pub mod hashable; pub mod helpers; pub mod imports; -pub mod logging; pub mod newlines; pub mod relocate; -pub mod scope; pub mod source_code; pub mod str; pub mod token_kind; pub mod types; pub mod typing; -pub mod visibility; pub mod visitor; pub mod whitespace; diff --git a/crates/ruff_python_ast/src/typing.rs b/crates/ruff_python_ast/src/typing.rs index 729c904891..6beb47a406 100644 --- a/crates/ruff_python_ast/src/typing.rs +++ b/crates/ruff_python_ast/src/typing.rs @@ -1,80 +1,12 @@ use anyhow::Result; use rustpython_parser as parser; -use rustpython_parser::ast::{Expr, ExprKind, Location}; +use rustpython_parser::ast::{Expr, Location}; -use ruff_python_stdlib::typing::{PEP_585_BUILTINS_ELIGIBLE, PEP_593_SUBSCRIPTS, SUBSCRIPTS}; - -use crate::call_path::{from_unqualified_name, CallPath}; -use crate::context::Context; use crate::relocate::relocate_expr; use crate::source_code::Locator; use crate::str; use crate::types::Range; -#[derive(Copy, Clone)] -pub enum Callable { - Cast, - NewType, - TypeVar, - NamedTuple, - TypedDict, - MypyExtension, -} - -#[derive(Copy, Clone)] -pub enum SubscriptKind { - AnnotatedSubscript, - PEP593AnnotatedSubscript, -} - -pub fn match_annotated_subscript<'a>( - expr: &Expr, - context: &Context, - typing_modules: impl Iterator, -) -> Option { - if !matches!( - expr.node, - ExprKind::Name { .. } | ExprKind::Attribute { .. } - ) { - return None; - } - - context.resolve_call_path(expr).and_then(|call_path| { - if SUBSCRIPTS.contains(&call_path.as_slice()) { - return Some(SubscriptKind::AnnotatedSubscript); - } - if PEP_593_SUBSCRIPTS.contains(&call_path.as_slice()) { - return Some(SubscriptKind::PEP593AnnotatedSubscript); - } - - for module in typing_modules { - let module_call_path: CallPath = from_unqualified_name(module); - if call_path.starts_with(&module_call_path) { - for subscript in SUBSCRIPTS.iter() { - if call_path.last() == subscript.last() { - return Some(SubscriptKind::AnnotatedSubscript); - } - } - for subscript in PEP_593_SUBSCRIPTS.iter() { - if call_path.last() == subscript.last() { - return Some(SubscriptKind::PEP593AnnotatedSubscript); - } - } - } - } - - None - }) -} - -/// Returns `true` if `Expr` represents a reference to a typing object with a -/// PEP 585 built-in. -pub fn is_pep585_builtin(expr: &Expr, context: &Context) -> bool { - context.resolve_call_path(expr).map_or(false, |call_path| { - PEP_585_BUILTINS_ELIGIBLE.contains(&call_path.as_slice()) - }) -} - #[derive(is_macro::Is, Copy, Clone)] pub enum AnnotationKind { /// The annotation is defined as part a simple string literal, diff --git a/crates/ruff_python_formatter/Cargo.toml b/crates/ruff_python_formatter/Cargo.toml index a4d1a93d45..d2772f4358 100644 --- a/crates/ruff_python_formatter/Cargo.toml +++ b/crates/ruff_python_formatter/Cargo.toml @@ -8,7 +8,6 @@ rust-version = { workspace = true } [dependencies] ruff_formatter = { path = "../ruff_formatter" } ruff_python_ast = { path = "../ruff_python_ast" } -ruff_python_stdlib = { path = "../ruff_python_stdlib" } ruff_rustpython = { path = "../ruff_rustpython" } ruff_text_size = { path = "../ruff_text_size" } diff --git a/crates/ruff_python_semantic/Cargo.toml b/crates/ruff_python_semantic/Cargo.toml new file mode 100644 index 0000000000..9eea6557c9 --- /dev/null +++ b/crates/ruff_python_semantic/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "ruff_python_semantic" +version = "0.0.0" +publish = false +edition = { workspace = true } +rust-version = { workspace = true } + +[lib] + +[dependencies] +ruff_python_ast = { path = "../ruff_python_ast" } +ruff_python_stdlib = { path = "../ruff_python_stdlib" } + +bitflags = { workspace = true } +is-macro = { workspace = true } +nohash-hasher = { workspace = true } +rustc-hash = { workspace = true } +rustpython-parser = { workspace = true } +smallvec = { workspace = true } diff --git a/crates/ruff_python_ast/src/function_type.rs b/crates/ruff_python_semantic/src/analyze/function_type.rs similarity index 95% rename from crates/ruff_python_ast/src/function_type.rs rename to crates/ruff_python_semantic/src/analyze/function_type.rs index 913a66d4cc..1df2f34a07 100644 --- a/crates/ruff_python_ast/src/function_type.rs +++ b/crates/ruff_python_semantic/src/analyze/function_type.rs @@ -1,8 +1,9 @@ use rustpython_parser::ast::Expr; -use crate::call_path::from_qualified_name; +use ruff_python_ast::call_path::from_qualified_name; +use ruff_python_ast::helpers::map_callable; + use crate::context::Context; -use crate::helpers::map_callable; use crate::scope::{Scope, ScopeKind}; const CLASS_METHODS: [&str; 3] = ["__new__", "__init_subclass__", "__class_getitem__"]; diff --git a/crates/ruff_python_ast/src/logging.rs b/crates/ruff_python_semantic/src/analyze/logging.rs similarity index 59% rename from crates/ruff_python_ast/src/logging.rs rename to crates/ruff_python_semantic/src/analyze/logging.rs index d189ac9ea9..4dcdf41c29 100644 --- a/crates/ruff_python_ast/src/logging.rs +++ b/crates/ruff_python_semantic/src/analyze/logging.rs @@ -1,34 +1,9 @@ use rustpython_parser::ast::{Expr, ExprKind}; -use crate::call_path::collect_call_path; +use ruff_python_ast::call_path::collect_call_path; + use crate::context::Context; -#[derive(Copy, Clone)] -pub enum LoggingLevel { - Debug, - Critical, - Error, - Exception, - Info, - Warn, - Warning, -} - -impl LoggingLevel { - pub fn from_attribute(level: &str) -> Option { - match level { - "debug" => Some(LoggingLevel::Debug), - "critical" => Some(LoggingLevel::Critical), - "error" => Some(LoggingLevel::Error), - "exception" => Some(LoggingLevel::Exception), - "info" => Some(LoggingLevel::Info), - "warn" => Some(LoggingLevel::Warn), - "warning" => Some(LoggingLevel::Warning), - _ => None, - } - } -} - /// Return `true` if the given `Expr` is a potential logging call. Matches /// `logging.error`, `logger.error`, `self.logger.error`, etc., but not /// arbitrary `foo.error` calls. diff --git a/crates/ruff_python_semantic/src/analyze/mod.rs b/crates/ruff_python_semantic/src/analyze/mod.rs new file mode 100644 index 0000000000..7298cbc87a --- /dev/null +++ b/crates/ruff_python_semantic/src/analyze/mod.rs @@ -0,0 +1,4 @@ +pub mod function_type; +pub mod logging; +pub mod typing; +pub mod visibility; diff --git a/crates/ruff_python_semantic/src/analyze/typing.rs b/crates/ruff_python_semantic/src/analyze/typing.rs new file mode 100644 index 0000000000..23018322e6 --- /dev/null +++ b/crates/ruff_python_semantic/src/analyze/typing.rs @@ -0,0 +1,70 @@ +use rustpython_parser::ast::{Expr, ExprKind}; + +use ruff_python_ast::call_path::{from_unqualified_name, CallPath}; +use ruff_python_stdlib::typing::{PEP_585_BUILTINS_ELIGIBLE, PEP_593_SUBSCRIPTS, SUBSCRIPTS}; + +use crate::context::Context; + +#[derive(Copy, Clone)] +pub enum Callable { + Cast, + NewType, + TypeVar, + NamedTuple, + TypedDict, + MypyExtension, +} + +#[derive(Copy, Clone)] +pub enum SubscriptKind { + AnnotatedSubscript, + PEP593AnnotatedSubscript, +} + +pub fn match_annotated_subscript<'a>( + expr: &Expr, + context: &Context, + typing_modules: impl Iterator, +) -> Option { + if !matches!( + expr.node, + ExprKind::Name { .. } | ExprKind::Attribute { .. } + ) { + return None; + } + + context.resolve_call_path(expr).and_then(|call_path| { + if SUBSCRIPTS.contains(&call_path.as_slice()) { + return Some(SubscriptKind::AnnotatedSubscript); + } + if PEP_593_SUBSCRIPTS.contains(&call_path.as_slice()) { + return Some(SubscriptKind::PEP593AnnotatedSubscript); + } + + for module in typing_modules { + let module_call_path: CallPath = from_unqualified_name(module); + if call_path.starts_with(&module_call_path) { + for subscript in SUBSCRIPTS.iter() { + if call_path.last() == subscript.last() { + return Some(SubscriptKind::AnnotatedSubscript); + } + } + for subscript in PEP_593_SUBSCRIPTS.iter() { + if call_path.last() == subscript.last() { + return Some(SubscriptKind::PEP593AnnotatedSubscript); + } + } + } + } + + None + }) +} + +/// Returns `true` if `Expr` represents a reference to a typing object with a +/// PEP 585 built-in. +pub fn is_pep585_builtin(expr: &Expr, context: &Context) -> bool { + context.resolve_call_path(expr).map_or(false, |call_path| { + PEP_585_BUILTINS_ELIGIBLE.contains(&call_path.as_slice()) + }) +} diff --git a/crates/ruff_python_ast/src/visibility.rs b/crates/ruff_python_semantic/src/analyze/visibility.rs similarity index 98% rename from crates/ruff_python_ast/src/visibility.rs rename to crates/ruff_python_semantic/src/analyze/visibility.rs index 7945590d27..3d707de69f 100644 --- a/crates/ruff_python_ast/src/visibility.rs +++ b/crates/ruff_python_semantic/src/analyze/visibility.rs @@ -2,10 +2,10 @@ use std::path::Path; use rustpython_parser::ast::{Expr, Stmt, StmtKind}; -use crate::call_path::collect_call_path; -use crate::call_path::CallPath; +use ruff_python_ast::call_path::{collect_call_path, CallPath}; +use ruff_python_ast::helpers::map_callable; + use crate::context::Context; -use crate::helpers::map_callable; #[derive(Debug, Clone, Copy)] pub enum Modifier { diff --git a/crates/ruff_python_ast/src/binding.rs b/crates/ruff_python_semantic/src/binding.rs similarity index 99% rename from crates/ruff_python_ast/src/binding.rs rename to crates/ruff_python_semantic/src/binding.rs index c977c689cb..c3fb40d03d 100644 --- a/crates/ruff_python_ast/src/binding.rs +++ b/crates/ruff_python_semantic/src/binding.rs @@ -4,8 +4,9 @@ use std::ops::{Deref, Index, IndexMut}; use bitflags::bitflags; use rustpython_parser::ast::Stmt; +use ruff_python_ast::types::{Range, RefEquality}; + use crate::scope::ScopeId; -use crate::types::{Range, RefEquality}; #[derive(Debug, Clone)] pub struct Binding<'a> { diff --git a/crates/ruff_python_ast/src/context.rs b/crates/ruff_python_semantic/src/context.rs similarity index 98% rename from crates/ruff_python_ast/src/context.rs rename to crates/ruff_python_semantic/src/context.rs index 462bf993d7..ed6f73a932 100644 --- a/crates/ruff_python_ast/src/context.rs +++ b/crates/ruff_python_semantic/src/context.rs @@ -1,10 +1,15 @@ use std::path::Path; use nohash_hasher::{BuildNoHashHasher, IntMap}; +use ruff_python_ast::call_path::{collect_call_path, from_unqualified_name, CallPath}; +use ruff_python_ast::helpers::from_relative_import; +use ruff_python_ast::types::RefEquality; +use ruff_python_ast::typing::AnnotationKind; use rustc_hash::FxHashMap; use rustpython_parser::ast::{Expr, Stmt}; use smallvec::smallvec; +use crate::analyze::visibility::{module_visibility, Modifier, VisibleScope}; use ruff_python_stdlib::path::is_python_stub_file; use ruff_python_stdlib::typing::TYPING_EXTENSIONS; @@ -12,12 +17,7 @@ use crate::binding::{ Binding, BindingId, BindingKind, Bindings, Exceptions, ExecutionContext, FromImportation, Importation, SubmoduleImportation, }; -use crate::call_path::{collect_call_path, from_unqualified_name, CallPath}; -use crate::helpers::from_relative_import; use crate::scope::{Scope, ScopeId, ScopeKind, ScopeStack, Scopes}; -use crate::types::RefEquality; -use crate::typing::AnnotationKind; -use crate::visibility::{module_visibility, Modifier, VisibleScope}; #[allow(clippy::struct_excessive_bools)] pub struct Context<'a> { diff --git a/crates/ruff_python_semantic/src/lib.rs b/crates/ruff_python_semantic/src/lib.rs new file mode 100644 index 0000000000..f6c8f3fd46 --- /dev/null +++ b/crates/ruff_python_semantic/src/lib.rs @@ -0,0 +1,4 @@ +pub mod analyze; +pub mod binding; +pub mod context; +pub mod scope; diff --git a/crates/ruff_python_ast/src/scope.rs b/crates/ruff_python_semantic/src/scope.rs similarity index 99% rename from crates/ruff_python_ast/src/scope.rs rename to crates/ruff_python_semantic/src/scope.rs index aa7c059e55..0493cbc33b 100644 --- a/crates/ruff_python_ast/src/scope.rs +++ b/crates/ruff_python_semantic/src/scope.rs @@ -189,7 +189,7 @@ impl<'a> Scopes<'a> { } /// Pushes a new scope and returns its unique id - pub(crate) fn push_scope(&mut self, kind: ScopeKind<'a>) -> ScopeId { + pub fn push_scope(&mut self, kind: ScopeKind<'a>) -> ScopeId { let next_id = ScopeId::try_from(self.0.len()).unwrap(); self.0.push(Scope::local(next_id, kind)); next_id diff --git a/crates/ruff_python_stdlib/src/lib.rs b/crates/ruff_python_stdlib/src/lib.rs index e64bb5c4c3..009aebe0d4 100644 --- a/crates/ruff_python_stdlib/src/lib.rs +++ b/crates/ruff_python_stdlib/src/lib.rs @@ -2,6 +2,7 @@ pub mod builtins; pub mod future; pub mod identifiers; pub mod keyword; +pub mod logging; pub mod path; pub mod str; pub mod sys; diff --git a/crates/ruff_python_stdlib/src/logging.rs b/crates/ruff_python_stdlib/src/logging.rs new file mode 100644 index 0000000000..262132967d --- /dev/null +++ b/crates/ruff_python_stdlib/src/logging.rs @@ -0,0 +1,25 @@ +#[derive(Copy, Clone)] +pub enum LoggingLevel { + Debug, + Critical, + Error, + Exception, + Info, + Warn, + Warning, +} + +impl LoggingLevel { + pub fn from_attribute(level: &str) -> Option { + match level { + "debug" => Some(LoggingLevel::Debug), + "critical" => Some(LoggingLevel::Critical), + "error" => Some(LoggingLevel::Error), + "exception" => Some(LoggingLevel::Exception), + "info" => Some(LoggingLevel::Info), + "warn" => Some(LoggingLevel::Warn), + "warning" => Some(LoggingLevel::Warning), + _ => None, + } + } +}