mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 02:13:08 +00:00
Introduce a ruff_python_semantic
crate (#3865)
This commit is contained in:
parent
46bcb1f725
commit
d919adc13c
64 changed files with 267 additions and 225 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()),
|
||||
))
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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).
|
||||
///
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<Item = &'a str>,
|
||||
) -> Option<SubscriptKind> {
|
||||
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,
|
||||
|
|
|
@ -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" }
|
||||
|
||||
|
|
19
crates/ruff_python_semantic/Cargo.toml
Normal file
19
crates/ruff_python_semantic/Cargo.toml
Normal file
|
@ -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 }
|
|
@ -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__"];
|
|
@ -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<Self> {
|
||||
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.
|
4
crates/ruff_python_semantic/src/analyze/mod.rs
Normal file
4
crates/ruff_python_semantic/src/analyze/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
pub mod function_type;
|
||||
pub mod logging;
|
||||
pub mod typing;
|
||||
pub mod visibility;
|
70
crates/ruff_python_semantic/src/analyze/typing.rs
Normal file
70
crates/ruff_python_semantic/src/analyze/typing.rs
Normal file
|
@ -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<Item = &'a str>,
|
||||
) -> Option<SubscriptKind> {
|
||||
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())
|
||||
})
|
||||
}
|
|
@ -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 {
|
|
@ -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> {
|
|
@ -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> {
|
4
crates/ruff_python_semantic/src/lib.rs
Normal file
4
crates/ruff_python_semantic/src/lib.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
pub mod analyze;
|
||||
pub mod binding;
|
||||
pub mod context;
|
||||
pub mod scope;
|
|
@ -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
|
|
@ -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;
|
||||
|
|
25
crates/ruff_python_stdlib/src/logging.rs
Normal file
25
crates/ruff_python_stdlib/src/logging.rs
Normal file
|
@ -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<Self> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue