Move CallPath into its own module (#3847)

This commit is contained in:
Charlie Marsh 2023-04-01 11:25:04 -04:00 committed by GitHub
parent 2f90157ce2
commit d822e08111
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 129 additions and 102 deletions

View file

@ -5,7 +5,8 @@ use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword, Operator};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{compose_call_path, SimpleCallArgs};
use ruff_python_ast::call_path::compose_call_path;
use ruff_python_ast::helpers::SimpleCallArgs;
use ruff_python_ast::types::Range;
use crate::checkers::ast::Checker;

View file

@ -3,7 +3,7 @@ use rustpython_parser::ast::{Arguments, Constant, Expr, ExprKind};
use ruff_diagnostics::Violation;
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::collect_call_path;
use ruff_python_ast::call_path::collect_call_path;
use ruff_python_ast::types::Range;
use crate::checkers::ast::Checker;

View file

@ -7,9 +7,10 @@ use rustpython_parser::ast::{
use ruff_diagnostics::{AlwaysAutofixableViolation, Violation};
use ruff_diagnostics::{Diagnostic, Edit};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers;
use ruff_python_ast::call_path;
use ruff_python_ast::call_path::CallPath;
use ruff_python_ast::helpers::unparse_expr;
use ruff_python_ast::types::{CallPath, Range};
use ruff_python_ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{AsRule, Rule};
@ -69,7 +70,7 @@ fn duplicate_handler_exceptions<'a>(
let mut duplicates: FxHashSet<CallPath> = FxHashSet::default();
let mut unique_elts: Vec<&Expr> = Vec::default();
for type_ in elts {
let call_path = helpers::collect_call_path(type_);
let call_path = call_path::collect_call_path(type_);
if !call_path.is_empty() {
if seen.contains_key(&call_path) {
duplicates.insert(call_path);
@ -124,7 +125,7 @@ pub fn duplicate_exceptions(checker: &mut Checker, handlers: &[Excepthandler]) {
};
match &type_.node {
ExprKind::Attribute { .. } | ExprKind::Name { .. } => {
let call_path = helpers::collect_call_path(type_);
let call_path = call_path::collect_call_path(type_);
if !call_path.is_empty() {
if seen.contains(&call_path) {
duplicates.entry(call_path).or_default().push(type_);

View file

@ -3,8 +3,9 @@ use rustpython_parser::ast::{Arguments, Constant, Expr, ExprKind};
use ruff_diagnostics::Violation;
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{compose_call_path, to_call_path};
use ruff_python_ast::types::{CallPath, Range};
use ruff_python_ast::call_path::to_call_path;
use ruff_python_ast::call_path::{compose_call_path, CallPath};
use ruff_python_ast::types::Range;
use ruff_python_ast::visitor;
use ruff_python_ast::visitor::Visitor;

View file

@ -2,7 +2,7 @@ use rustpython_parser::ast::{Expr, Stmt};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::format_call_path;
use ruff_python_ast::call_path::format_call_path;
use ruff_python_ast::types::Range;
use crate::checkers::ast::Checker;

View file

@ -1,6 +1,7 @@
use ruff_python_ast::context::Context;
use rustpython_parser::ast::Expr;
use ruff_python_ast::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 {
context.resolve_call_path(base).map_or(false, |call_path| {

View file

@ -2,7 +2,8 @@ use rustpython_parser::ast::{Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::types::{CallPath, Range};
use ruff_python_ast::call_path::CallPath;
use ruff_python_ast::types::Range;
/// ## What it does
/// Checks that Django's `@receiver` decorator is listed first, prior to

View file

@ -1,9 +1,10 @@
use std::fmt;
use rustpython_parser::ast::{Expr, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::types::Range;
use rustpython_parser::ast::{Expr, ExprKind, Stmt, StmtKind};
use crate::checkers::ast::Checker;

View file

@ -4,7 +4,8 @@ use rustpython_parser::ast::{Arguments, Expr, ExprKind, Keyword, Location, Stmt,
use ruff_diagnostics::{AlwaysAutofixableViolation, Violation};
use ruff_diagnostics::{Diagnostic, Edit};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{collect_arg_names, collect_call_path};
use ruff_python_ast::call_path::collect_call_path;
use ruff_python_ast::helpers::collect_arg_names;
use ruff_python_ast::source_code::Locator;
use ruff_python_ast::types::Range;
use ruff_python_ast::visitor;

View file

@ -1,7 +1,8 @@
use num_traits::identities::Zero;
use ruff_python_ast::call_path::collect_call_path;
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword};
use ruff_python_ast::helpers::{collect_call_path, map_callable};
use ruff_python_ast::helpers::map_callable;
use crate::checkers::ast::Checker;

View file

@ -3,7 +3,8 @@ use rustpython_parser::ast::{Expr, ExprKind, Keyword};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{collect_arg_names, compose_call_path, SimpleCallArgs};
use ruff_python_ast::call_path::compose_call_path;
use ruff_python_ast::helpers::{collect_arg_names, SimpleCallArgs};
use ruff_python_ast::types::Range;
use ruff_python_ast::visitor;
use ruff_python_ast::visitor::Visitor;

View file

@ -2,7 +2,8 @@ use rustpython_parser::ast::{Expr, ExprKind, Keyword, Stmt, StmtKind, Withitem};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{format_call_path, to_call_path};
use ruff_python_ast::call_path::format_call_path;
use ruff_python_ast::call_path::to_call_path;
use ruff_python_ast::types::Range;
use crate::checkers::ast::Checker;

View file

@ -2,7 +2,7 @@ use rustpython_parser::ast::{Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::collect_call_path;
use ruff_python_ast::call_path::collect_call_path;
use ruff_python_ast::scope::ScopeKind;
use ruff_python_ast::types::Range;

View file

@ -2,8 +2,8 @@ use rustpython_parser::ast::{Excepthandler, ExcepthandlerKind, Located, Stmt, St
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::call_path::compose_call_path;
use ruff_python_ast::helpers;
use ruff_python_ast::helpers::compose_call_path;
use ruff_python_ast::types::Range;
use crate::checkers::ast::Checker;

View file

@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation, CacheKey};
use ruff_python_ast::types::{CallPath, Range};
use ruff_python_ast::call_path::CallPath;
use ruff_python_ast::types::Range;
use crate::checkers::ast::Checker;

View file

@ -2,8 +2,9 @@ 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::to_call_path;
use ruff_python_ast::context::Context;
use ruff_python_ast::helpers::{map_callable, to_call_path};
use ruff_python_ast::helpers::map_callable;
use ruff_python_ast::scope::ScopeKind;
/// Return `true` if [`Expr`] is a guard for a type-checking block.

View file

@ -1,7 +1,8 @@
use ruff_python_ast::call_path::to_call_path;
use std::collections::BTreeSet;
use ruff_python_ast::cast;
use ruff_python_ast::helpers::{map_callable, to_call_path};
use ruff_python_ast::helpers::map_callable;
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::str::is_implicit_concatenation;

View file

@ -1,8 +1,9 @@
use unicode_width::UnicodeWidthStr;
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::str::leading_quote;
use ruff_python_ast::types::Range;
use unicode_width::UnicodeWidthStr;
use crate::checkers::ast::Checker;
use crate::docstrings::definition::{DefinitionKind, Docstring};

View file

@ -5,10 +5,10 @@ use once_cell::sync::Lazy;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::call_path::{to_call_path, CallPath};
use ruff_python_ast::cast;
use ruff_python_ast::helpers::to_call_path;
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::types::{CallPath, Range};
use ruff_python_ast::types::Range;
use ruff_python_ast::visibility::{is_property, is_test};
use crate::checkers::ast::Checker;

View file

@ -2,7 +2,7 @@ use rustpython_parser::ast::Expr;
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::collect_call_path;
use ruff_python_ast::call_path::collect_call_path;
use ruff_python_ast::types::Range;
use crate::checkers::ast::Checker;

View file

@ -8,7 +8,7 @@ use rustpython_parser::ast::{Expr, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::collect_call_path;
use ruff_python_ast::call_path::collect_call_path;
use ruff_python_ast::source_code::{Locator, Stylist};
use ruff_python_ast::types::Range;
use ruff_python_ast::whitespace::indentation;

View file

@ -2,8 +2,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::{compose_call_path, create_expr, unparse_expr};
use ruff_python_ast::helpers::{create_expr, unparse_expr};
use ruff_python_ast::types::Range;
use crate::checkers::ast::Checker;

View file

@ -4,7 +4,8 @@ use rustpython_parser::ast::{Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::types::{CallPath, Range};
use ruff_python_ast::call_path::CallPath;
use ruff_python_ast::types::Range;
/// ## What it does
/// Checks for `asyncio.create_task` and `asyncio.ensure_future` calls

View file

@ -0,0 +1,63 @@
use rustpython_parser::ast::{Expr, ExprKind};
use smallvec::smallvec;
/// A representation of a qualified name, like `typing.List`.
pub type CallPath<'a> = smallvec::SmallVec<[&'a str; 8]>;
fn collect_call_path_inner<'a>(expr: &'a Expr, parts: &mut CallPath<'a>) -> bool {
match &expr.node {
ExprKind::Attribute { value, attr, .. } => {
if collect_call_path_inner(value, parts) {
parts.push(attr);
true
} else {
false
}
}
ExprKind::Name { id, .. } => {
parts.push(id);
true
}
_ => false,
}
}
/// Convert an `Expr` to its [`CallPath`] segments (like `["typing", "List"]`).
pub fn collect_call_path(expr: &Expr) -> CallPath {
let mut segments = smallvec![];
collect_call_path_inner(expr, &mut segments);
segments
}
/// Convert an `Expr` to its call path (like `List`, or `typing.List`).
pub fn compose_call_path(expr: &Expr) -> Option<String> {
let call_path = collect_call_path(expr);
if call_path.is_empty() {
None
} else {
Some(format_call_path(&call_path))
}
}
/// Format a call path for display.
pub fn format_call_path(call_path: &[&str]) -> String {
if call_path
.first()
.expect("Unable to format empty call path")
.is_empty()
{
call_path[1..].join(".")
} else {
call_path.join(".")
}
}
/// Split a fully-qualified name (like `typing.List`) into (`typing`, `List`).
pub fn to_call_path(target: &str) -> CallPath {
if target.contains('.') {
target.split('.').collect()
} else {
// Special-case: for builtins, return `["", "int"]` instead of `["int"]`.
smallvec!["", target]
}
}

View file

@ -1,14 +1,13 @@
//! An equivalent object hierarchy to the [`Expr`] hierarchy, but with the
//! ability to compare expressions for equality (via [`Eq`] and [`Hash`]).
use num_bigint::BigInt;
use rustpython_parser::ast::{
Alias, Arg, Arguments, Boolop, Cmpop, Comprehension, Constant, Excepthandler,
ExcepthandlerKind, Expr, ExprContext, ExprKind, Keyword, MatchCase, Operator, Pattern,
PatternKind, Stmt, StmtKind, Unaryop, Withitem,
};
use num_bigint::BigInt;
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
pub enum ComparableExprContext {
Load,

View file

@ -12,9 +12,10 @@ use crate::binding::{
Binding, BindingId, BindingKind, Bindings, Exceptions, ExecutionContext, FromImportation,
Importation, SubmoduleImportation,
};
use crate::helpers::{collect_call_path, from_relative_import};
use crate::call_path::{collect_call_path, CallPath};
use crate::helpers::from_relative_import;
use crate::scope::{Scope, ScopeId, ScopeKind, ScopeStack, Scopes};
use crate::types::{CallPath, RefEquality};
use crate::types::RefEquality;
use crate::typing::AnnotationKind;
use crate::visibility::{module_visibility, Modifier, VisibleScope};

View file

@ -1,7 +1,8 @@
use rustpython_parser::ast::Expr;
use crate::call_path::to_call_path;
use crate::context::Context;
use crate::helpers::{map_callable, to_call_path};
use crate::helpers::map_callable;
use crate::scope::{Scope, ScopeKind};
const CLASS_METHODS: [&str; 3] = ["__new__", "__init_subclass__", "__class_getitem__"];

View file

@ -10,11 +10,12 @@ use rustpython_parser::ast::{
KeywordData, Located, Location, MatchCase, Pattern, PatternKind, Stmt, StmtKind,
};
use rustpython_parser::{lexer, Mode, Tok};
use smallvec::{smallvec, SmallVec};
use smallvec::SmallVec;
use crate::call_path::CallPath;
use crate::context::Context;
use crate::source_code::{Generator, Indexer, Locator, Stylist};
use crate::types::{CallPath, Range};
use crate::types::Range;
use crate::visitor;
use crate::visitor::Visitor;
@ -49,54 +50,6 @@ pub fn unparse_constant(constant: &Constant, stylist: &Stylist) -> String {
generator.generate()
}
fn collect_call_path_inner<'a>(expr: &'a Expr, parts: &mut CallPath<'a>) -> bool {
match &expr.node {
ExprKind::Attribute { value, attr, .. } => {
if collect_call_path_inner(value, parts) {
parts.push(attr);
true
} else {
false
}
}
ExprKind::Name { id, .. } => {
parts.push(id);
true
}
_ => false,
}
}
/// Convert an `Expr` to its [`CallPath`] segments (like `["typing", "List"]`).
pub fn collect_call_path(expr: &Expr) -> CallPath {
let mut segments = smallvec![];
collect_call_path_inner(expr, &mut segments);
segments
}
/// Convert an `Expr` to its call path (like `List`, or `typing.List`).
pub fn compose_call_path(expr: &Expr) -> Option<String> {
let call_path = collect_call_path(expr);
if call_path.is_empty() {
None
} else {
Some(format_call_path(&call_path))
}
}
/// Format a call path for display.
pub fn format_call_path(call_path: &[&str]) -> String {
if call_path
.first()
.expect("Unable to format empty call path")
.is_empty()
{
call_path[1..].join(".")
} else {
call_path.join(".")
}
}
/// 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| {
@ -748,15 +701,6 @@ pub fn format_import_from_member(
full_name
}
/// Split a target string (like `typing.List`) into (`typing`, `List`).
pub fn to_call_path(target: &str) -> CallPath {
if target.contains('.') {
target.split('.').collect()
} else {
smallvec!["", target]
}
}
/// Create a module path from a (package, path) pair.
///
/// For example, if the package is `foo/bar` and the path is `foo/bar/baz.py`,

View file

@ -1,6 +1,7 @@
pub mod all;
pub mod binding;
pub mod branch_detection;
pub mod call_path;
pub mod cast;
pub mod comparable;
pub mod context;

View file

@ -1,7 +1,8 @@
use crate::context::Context;
use crate::helpers::collect_call_path;
use rustpython_parser::ast::{Expr, ExprKind};
use crate::call_path::collect_call_path;
use crate::context::Context;
#[derive(Copy, Clone)]
pub enum LoggingLevel {
Debug,

View file

@ -208,9 +208,10 @@ impl Utf8Index {
#[cfg(test)]
mod tests {
use crate::source_code::locator::{AsciiIndex, Index, Utf8Index};
use rustpython_parser::ast::Location;
use crate::source_code::locator::{AsciiIndex, Index, Utf8Index};
fn index_ascii(content: &str) -> AsciiIndex {
match Index::from(content) {
Index::Ascii(ascii) => ascii,

View file

@ -8,9 +8,9 @@ use rustpython_parser::ast::Location;
use rustpython_parser::lexer::LexResult;
use rustpython_parser::Tok;
use crate::source_code::Locator;
use ruff_rustpython::vendor;
use crate::source_code::Locator;
use crate::str::leading_quote;
use crate::types::Range;
@ -213,11 +213,12 @@ fn detect_line_ending(contents: &str) -> Option<LineEnding> {
#[cfg(test)]
mod tests {
use crate::source_code::stylist::{detect_line_ending, Indentation, LineEnding, Quote};
use crate::source_code::{Locator, Stylist};
use rustpython_parser::lexer::lex;
use rustpython_parser::Mode;
use crate::source_code::stylist::{detect_line_ending, Indentation, LineEnding, Quote};
use crate::source_code::{Locator, Stylist};
#[test]
fn indentation() {
let contents = r#"x = 1"#;

View file

@ -97,5 +97,3 @@ impl<'a> From<&RefEquality<'a, Expr>> for &'a Expr {
r.0
}
}
pub type CallPath<'a> = smallvec::SmallVec<[&'a str; 8]>;

View file

@ -2,9 +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 crate::context::Context;
use crate::helpers::{collect_call_path, map_callable};
use crate::types::CallPath;
use crate::helpers::map_callable;
#[derive(Debug, Clone, Copy)]
pub enum Modifier {