mirror of https://github.com/astral-sh/ruff
Implement type(primitive) (#353)
This commit is contained in:
parent
e3a7357187
commit
4cf2682cda
|
|
@ -0,0 +1,5 @@
|
||||||
|
type('')
|
||||||
|
type(b'')
|
||||||
|
type(0)
|
||||||
|
type(0.)
|
||||||
|
type(0j)
|
||||||
|
|
@ -6,6 +6,7 @@ use rustpython_parser::ast::{
|
||||||
Arg, ArgData, Arguments, Cmpop, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprKind,
|
Arg, ArgData, Arguments, Cmpop, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprKind,
|
||||||
Stmt, StmtKind, Unaryop,
|
Stmt, StmtKind, Unaryop,
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::ast::types::{
|
use crate::ast::types::{
|
||||||
Binding, BindingKind, CheckLocator, FunctionScope, Range, Scope, ScopeKind,
|
Binding, BindingKind, CheckLocator, FunctionScope, Range, Scope, ScopeKind,
|
||||||
|
|
@ -155,6 +156,65 @@ pub fn check_unnecessary_abspath(func: &Expr, args: &Vec<Expr>, location: Range)
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum Primitive {
|
||||||
|
Bool,
|
||||||
|
Str,
|
||||||
|
Bytes,
|
||||||
|
Int,
|
||||||
|
Float,
|
||||||
|
Complex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Primitive {
|
||||||
|
fn from_constant(constant: &Constant) -> Option<Self> {
|
||||||
|
match constant {
|
||||||
|
Constant::Bool(_) => Some(Primitive::Bool),
|
||||||
|
Constant::Str(_) => Some(Primitive::Str),
|
||||||
|
Constant::Bytes(_) => Some(Primitive::Bytes),
|
||||||
|
Constant::Int(_) => Some(Primitive::Int),
|
||||||
|
Constant::Float(_) => Some(Primitive::Float),
|
||||||
|
Constant::Complex { .. } => Some(Primitive::Complex),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builtin(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Primitive::Bool => "bool".to_string(),
|
||||||
|
Primitive::Str => "str".to_string(),
|
||||||
|
Primitive::Bytes => "bytes".to_string(),
|
||||||
|
Primitive::Int => "int".to_string(),
|
||||||
|
Primitive::Float => "float".to_string(),
|
||||||
|
Primitive::Complex => "complex".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check TypeOfPrimitive compliance.
|
||||||
|
pub fn check_type_of_primitive(func: &Expr, args: &Vec<Expr>, location: Range) -> Option<Check> {
|
||||||
|
// Validate the arguments.
|
||||||
|
if args.len() == 1 {
|
||||||
|
match &func.node {
|
||||||
|
ExprKind::Attribute { attr: id, .. } | ExprKind::Name { id, .. } => {
|
||||||
|
if id == "type" {
|
||||||
|
if let ExprKind::Constant { value, .. } = &args[0].node {
|
||||||
|
if let Some(primitive) = Primitive::from_constant(value) {
|
||||||
|
return Some(Check::new(
|
||||||
|
CheckKind::TypeOfPrimitive(primitive),
|
||||||
|
location,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn is_ambiguous_name(name: &str) -> bool {
|
fn is_ambiguous_name(name: &str) -> bool {
|
||||||
name == "l" || name == "I" || name == "O"
|
name == "l" || name == "I" || name == "O"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -801,6 +801,10 @@ where
|
||||||
plugins::unnecessary_abspath(self, expr, func, args);
|
plugins::unnecessary_abspath(self, expr, func, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.settings.enabled.contains(&CheckCode::U003) {
|
||||||
|
plugins::type_of_primitive(self, expr, func, args);
|
||||||
|
}
|
||||||
|
|
||||||
if let ExprKind::Name { id, ctx } = &func.node {
|
if let ExprKind::Name { id, ctx } = &func.node {
|
||||||
if id == "locals" && matches!(ctx, ExprContext::Load) {
|
if id == "locals" && matches!(ctx, ExprContext::Load) {
|
||||||
let scope = &mut self.scopes[*(self
|
let scope = &mut self.scopes[*(self
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::ast::types::Range;
|
use crate::ast::checks::Primitive;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustpython_parser::ast::Location;
|
use rustpython_parser::ast::Location;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::ast::types::Range;
|
||||||
|
|
||||||
pub const DEFAULT_CHECK_CODES: [CheckCode; 42] = [
|
pub const DEFAULT_CHECK_CODES: [CheckCode; 42] = [
|
||||||
// pycodestyle
|
// pycodestyle
|
||||||
CheckCode::E402,
|
CheckCode::E402,
|
||||||
|
|
@ -53,7 +55,7 @@ pub const DEFAULT_CHECK_CODES: [CheckCode; 42] = [
|
||||||
CheckCode::F901,
|
CheckCode::F901,
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const ALL_CHECK_CODES: [CheckCode; 57] = [
|
pub const ALL_CHECK_CODES: [CheckCode; 58] = [
|
||||||
// pycodestyle
|
// pycodestyle
|
||||||
CheckCode::E402,
|
CheckCode::E402,
|
||||||
CheckCode::E501,
|
CheckCode::E501,
|
||||||
|
|
@ -115,6 +117,7 @@ pub const ALL_CHECK_CODES: [CheckCode; 57] = [
|
||||||
// pyupgrade
|
// pyupgrade
|
||||||
CheckCode::U001,
|
CheckCode::U001,
|
||||||
CheckCode::U002,
|
CheckCode::U002,
|
||||||
|
CheckCode::U003,
|
||||||
// Refactor
|
// Refactor
|
||||||
CheckCode::R001,
|
CheckCode::R001,
|
||||||
CheckCode::R002,
|
CheckCode::R002,
|
||||||
|
|
@ -185,6 +188,7 @@ pub enum CheckCode {
|
||||||
// pyupgrade
|
// pyupgrade
|
||||||
U001,
|
U001,
|
||||||
U002,
|
U002,
|
||||||
|
U003,
|
||||||
// Refactor
|
// Refactor
|
||||||
R001,
|
R001,
|
||||||
R002,
|
R002,
|
||||||
|
|
@ -256,6 +260,7 @@ impl FromStr for CheckCode {
|
||||||
// pyupgrade
|
// pyupgrade
|
||||||
"U001" => Ok(CheckCode::U001),
|
"U001" => Ok(CheckCode::U001),
|
||||||
"U002" => Ok(CheckCode::U002),
|
"U002" => Ok(CheckCode::U002),
|
||||||
|
"U003" => Ok(CheckCode::U003),
|
||||||
// Refactor
|
// Refactor
|
||||||
"R001" => Ok(CheckCode::R001),
|
"R001" => Ok(CheckCode::R001),
|
||||||
"R002" => Ok(CheckCode::R002),
|
"R002" => Ok(CheckCode::R002),
|
||||||
|
|
@ -330,6 +335,7 @@ impl CheckCode {
|
||||||
// pyupgrade
|
// pyupgrade
|
||||||
CheckCode::U001 => "U001",
|
CheckCode::U001 => "U001",
|
||||||
CheckCode::U002 => "U002",
|
CheckCode::U002 => "U002",
|
||||||
|
CheckCode::U003 => "U003",
|
||||||
// Refactor
|
// Refactor
|
||||||
CheckCode::R001 => "R001",
|
CheckCode::R001 => "R001",
|
||||||
CheckCode::R002 => "R002",
|
CheckCode::R002 => "R002",
|
||||||
|
|
@ -413,6 +419,7 @@ impl CheckCode {
|
||||||
// pyupgrade
|
// pyupgrade
|
||||||
CheckCode::U001 => CheckKind::UselessMetaclassType,
|
CheckCode::U001 => CheckKind::UselessMetaclassType,
|
||||||
CheckCode::U002 => CheckKind::UnnecessaryAbspath,
|
CheckCode::U002 => CheckKind::UnnecessaryAbspath,
|
||||||
|
CheckCode::U003 => CheckKind::UnnecessaryAbspath,
|
||||||
// Refactor
|
// Refactor
|
||||||
CheckCode::R001 => CheckKind::UselessObjectInheritance("...".to_string()),
|
CheckCode::R001 => CheckKind::UselessObjectInheritance("...".to_string()),
|
||||||
CheckCode::R002 => CheckKind::NoAssertEquals,
|
CheckCode::R002 => CheckKind::NoAssertEquals,
|
||||||
|
|
@ -494,6 +501,7 @@ pub enum CheckKind {
|
||||||
PrintFound,
|
PrintFound,
|
||||||
PPrintFound,
|
PPrintFound,
|
||||||
// pyupgrade
|
// pyupgrade
|
||||||
|
TypeOfPrimitive(Primitive),
|
||||||
UnnecessaryAbspath,
|
UnnecessaryAbspath,
|
||||||
UselessMetaclassType,
|
UselessMetaclassType,
|
||||||
// Refactor
|
// Refactor
|
||||||
|
|
@ -564,6 +572,7 @@ impl CheckKind {
|
||||||
CheckKind::PrintFound => "PrintFound",
|
CheckKind::PrintFound => "PrintFound",
|
||||||
CheckKind::PPrintFound => "PPrintFound",
|
CheckKind::PPrintFound => "PPrintFound",
|
||||||
// pyupgrade
|
// pyupgrade
|
||||||
|
CheckKind::TypeOfPrimitive(_) => "TypeOfPrimitive",
|
||||||
CheckKind::UnnecessaryAbspath => "UnnecessaryAbspath",
|
CheckKind::UnnecessaryAbspath => "UnnecessaryAbspath",
|
||||||
CheckKind::UselessMetaclassType => "UselessMetaclassType",
|
CheckKind::UselessMetaclassType => "UselessMetaclassType",
|
||||||
// Refactor
|
// Refactor
|
||||||
|
|
@ -634,6 +643,7 @@ impl CheckKind {
|
||||||
CheckKind::PrintFound => &CheckCode::T201,
|
CheckKind::PrintFound => &CheckCode::T201,
|
||||||
CheckKind::PPrintFound => &CheckCode::T203,
|
CheckKind::PPrintFound => &CheckCode::T203,
|
||||||
// pyupgrade
|
// pyupgrade
|
||||||
|
CheckKind::TypeOfPrimitive(_) => &CheckCode::U003,
|
||||||
CheckKind::UnnecessaryAbspath => &CheckCode::U002,
|
CheckKind::UnnecessaryAbspath => &CheckCode::U002,
|
||||||
CheckKind::UselessMetaclassType => &CheckCode::U001,
|
CheckKind::UselessMetaclassType => &CheckCode::U001,
|
||||||
// Refactor
|
// Refactor
|
||||||
|
|
@ -806,6 +816,9 @@ impl CheckKind {
|
||||||
CheckKind::PrintFound => "`print` found".to_string(),
|
CheckKind::PrintFound => "`print` found".to_string(),
|
||||||
CheckKind::PPrintFound => "`pprint` found".to_string(),
|
CheckKind::PPrintFound => "`pprint` found".to_string(),
|
||||||
// pyupgrade
|
// pyupgrade
|
||||||
|
CheckKind::TypeOfPrimitive(primitive) => {
|
||||||
|
format!("Use `{}` instead of `type(...)`", primitive.builtin())
|
||||||
|
}
|
||||||
CheckKind::UnnecessaryAbspath => {
|
CheckKind::UnnecessaryAbspath => {
|
||||||
"`abspath(__file__)` is unnecessary in Python 3.9 and later".to_string()
|
"`abspath(__file__)` is unnecessary in Python 3.9 and later".to_string()
|
||||||
}
|
}
|
||||||
|
|
@ -833,6 +846,7 @@ impl CheckKind {
|
||||||
| CheckKind::PPrintFound
|
| CheckKind::PPrintFound
|
||||||
| CheckKind::PrintFound
|
| CheckKind::PrintFound
|
||||||
| CheckKind::SuperCallWithParameters
|
| CheckKind::SuperCallWithParameters
|
||||||
|
| CheckKind::TypeOfPrimitive(_)
|
||||||
| CheckKind::UnnecessaryAbspath
|
| CheckKind::UnnecessaryAbspath
|
||||||
| CheckKind::UnusedImport(_)
|
| CheckKind::UnusedImport(_)
|
||||||
| CheckKind::UnusedNOQA(_)
|
| CheckKind::UnusedNOQA(_)
|
||||||
|
|
|
||||||
|
|
@ -893,4 +893,16 @@ mod tests {
|
||||||
insta::assert_yaml_snapshot!(checks);
|
insta::assert_yaml_snapshot!(checks);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn u003() -> Result<()> {
|
||||||
|
let mut checks = check_path(
|
||||||
|
Path::new("./resources/test/fixtures/U003.py"),
|
||||||
|
&settings::Settings::for_rule(CheckCode::U003),
|
||||||
|
&fixer::Mode::Generate,
|
||||||
|
)?;
|
||||||
|
checks.sort_by_key(|check| check.location);
|
||||||
|
insta::assert_yaml_snapshot!(checks);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ mod if_tuple;
|
||||||
mod invalid_print_syntax;
|
mod invalid_print_syntax;
|
||||||
mod print_call;
|
mod print_call;
|
||||||
mod super_call_with_parameters;
|
mod super_call_with_parameters;
|
||||||
|
mod type_of_primitive;
|
||||||
mod unnecessary_abspath;
|
mod unnecessary_abspath;
|
||||||
mod useless_metaclass_type;
|
mod useless_metaclass_type;
|
||||||
mod useless_object_inheritance;
|
mod useless_object_inheritance;
|
||||||
|
|
@ -14,6 +15,7 @@ pub use if_tuple::if_tuple;
|
||||||
pub use invalid_print_syntax::invalid_print_syntax;
|
pub use invalid_print_syntax::invalid_print_syntax;
|
||||||
pub use print_call::print_call;
|
pub use print_call::print_call;
|
||||||
pub use super_call_with_parameters::super_call_with_parameters;
|
pub use super_call_with_parameters::super_call_with_parameters;
|
||||||
|
pub use type_of_primitive::type_of_primitive;
|
||||||
pub use unnecessary_abspath::unnecessary_abspath;
|
pub use unnecessary_abspath::unnecessary_abspath;
|
||||||
pub use useless_metaclass_type::useless_metaclass_type;
|
pub use useless_metaclass_type::useless_metaclass_type;
|
||||||
pub use useless_object_inheritance::useless_object_inheritance;
|
pub use useless_object_inheritance::useless_object_inheritance;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
use rustpython_ast::Expr;
|
||||||
|
|
||||||
|
use crate::ast::checks;
|
||||||
|
use crate::ast::types::{CheckLocator, Range};
|
||||||
|
use crate::autofix::fixer;
|
||||||
|
use crate::check_ast::Checker;
|
||||||
|
use crate::checks::{CheckKind, Fix};
|
||||||
|
|
||||||
|
pub fn type_of_primitive(checker: &mut Checker, expr: &Expr, func: &Expr, args: &Vec<Expr>) {
|
||||||
|
if let Some(mut check) =
|
||||||
|
checks::check_type_of_primitive(func, args, checker.locate_check(Range::from_located(expr)))
|
||||||
|
{
|
||||||
|
if matches!(checker.autofix, fixer::Mode::Generate | fixer::Mode::Apply) {
|
||||||
|
if let CheckKind::TypeOfPrimitive(primitive) = &check.kind {
|
||||||
|
check.amend(Fix {
|
||||||
|
content: primitive.builtin(),
|
||||||
|
location: expr.location,
|
||||||
|
end_location: expr.end_location,
|
||||||
|
applied: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checker.add_check(check);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
---
|
||||||
|
source: src/linter.rs
|
||||||
|
expression: checks
|
||||||
|
---
|
||||||
|
- kind:
|
||||||
|
TypeOfPrimitive: Str
|
||||||
|
location:
|
||||||
|
row: 1
|
||||||
|
column: 1
|
||||||
|
end_location:
|
||||||
|
row: 1
|
||||||
|
column: 9
|
||||||
|
fix:
|
||||||
|
content: str
|
||||||
|
location:
|
||||||
|
row: 1
|
||||||
|
column: 1
|
||||||
|
end_location:
|
||||||
|
row: 1
|
||||||
|
column: 9
|
||||||
|
applied: false
|
||||||
|
- kind:
|
||||||
|
TypeOfPrimitive: Bytes
|
||||||
|
location:
|
||||||
|
row: 2
|
||||||
|
column: 1
|
||||||
|
end_location:
|
||||||
|
row: 2
|
||||||
|
column: 10
|
||||||
|
fix:
|
||||||
|
content: bytes
|
||||||
|
location:
|
||||||
|
row: 2
|
||||||
|
column: 1
|
||||||
|
end_location:
|
||||||
|
row: 2
|
||||||
|
column: 10
|
||||||
|
applied: false
|
||||||
|
- kind:
|
||||||
|
TypeOfPrimitive: Int
|
||||||
|
location:
|
||||||
|
row: 3
|
||||||
|
column: 1
|
||||||
|
end_location:
|
||||||
|
row: 3
|
||||||
|
column: 8
|
||||||
|
fix:
|
||||||
|
content: int
|
||||||
|
location:
|
||||||
|
row: 3
|
||||||
|
column: 1
|
||||||
|
end_location:
|
||||||
|
row: 3
|
||||||
|
column: 8
|
||||||
|
applied: false
|
||||||
|
- kind:
|
||||||
|
TypeOfPrimitive: Float
|
||||||
|
location:
|
||||||
|
row: 4
|
||||||
|
column: 1
|
||||||
|
end_location:
|
||||||
|
row: 4
|
||||||
|
column: 9
|
||||||
|
fix:
|
||||||
|
content: float
|
||||||
|
location:
|
||||||
|
row: 4
|
||||||
|
column: 1
|
||||||
|
end_location:
|
||||||
|
row: 4
|
||||||
|
column: 9
|
||||||
|
applied: false
|
||||||
|
- kind:
|
||||||
|
TypeOfPrimitive: Complex
|
||||||
|
location:
|
||||||
|
row: 5
|
||||||
|
column: 1
|
||||||
|
end_location:
|
||||||
|
row: 5
|
||||||
|
column: 9
|
||||||
|
fix:
|
||||||
|
content: complex
|
||||||
|
location:
|
||||||
|
row: 5
|
||||||
|
column: 1
|
||||||
|
end_location:
|
||||||
|
row: 5
|
||||||
|
column: 9
|
||||||
|
applied: false
|
||||||
|
|
||||||
Loading…
Reference in New Issue