diff --git a/Cargo.lock b/Cargo.lock index a31250def0..5ad74852f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1708,6 +1708,7 @@ version = "0.0.24" dependencies = [ "anyhow", "bincode", + "bumpalo", "cacache", "chrono", "clap", diff --git a/Cargo.toml b/Cargo.toml index d40a01f410..7bd9075500 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ serde = { version = "1.0.143", features = ["derive"] } serde_json = { version = "1.0.83" } toml = { version = "0.5.9" } walkdir = { version = "2.3.2" } +bumpalo = "3.11.0" [profile.release] panic = "abort" diff --git a/resources/test/src/F634.py b/resources/test/src/F634.py index 501a7f8ad2..bd7b7f7a16 100644 --- a/resources/test/src/F634.py +++ b/resources/test/src/F634.py @@ -6,3 +6,7 @@ for _ in range(5): pass elif (3, 4): pass + + +class Foo(object): + pass diff --git a/src/check_cst.rs b/src/check_cst.rs index 19dafc2043..9f1af3e504 100644 --- a/src/check_cst.rs +++ b/src/check_cst.rs @@ -1,10 +1,9 @@ use std::collections::BTreeMap; -use libcst_native::{Expression, If, Module}; +use libcst_native::{Codegen, Module}; use rustpython_parser::ast::Location; -use crate::checks::{Check, CheckKind}; -use crate::cst_visitor; +use crate::checks::Check; use crate::cst_visitor::CSTVisitor; use crate::settings::Settings; @@ -53,7 +52,7 @@ impl Checker<'_> { } impl CSTVisitor for Checker<'_> { - fn visit_If<'a>(&'a mut self, node: &'a If) -> &'a If { + fn visit_If(&mut self, node: &If) { if let Expression::Tuple { .. } = node.test { self.checks.push(Check { kind: CheckKind::IfTuple, @@ -61,14 +60,43 @@ impl CSTVisitor for Checker<'_> { }); } cst_visitor::walk_If(self, node); - node + } + + fn visit_ClassDef<'a>(&mut self, node: &'a ClassDef<'a>) -> ClassDef<'a> { + let bases: Vec> = node + .bases + .clone() + .into_iter() + .filter(|node| { + if let Expression::Name(node) = &node.value { + node.value != "object" + } else { + true + } + }) + .collect(); + + let mut transformed: ClassDef<'a> = node.clone(); + transformed.bases = bases; + transformed.lpar = None; + transformed.rpar = None; + transformed } } -pub fn check_cst(python_cst: &Module, settings: &Settings) -> Vec { +pub fn check_cst<'a>(python_cst: &'a Module<'a>, settings: &Settings) -> Vec { + // // Create a new arena to bump allocate into. + // let bump = Bump::new(); + // + // // Allocate values into the arena. + // let scooter = bump.alloc(python_cst.clone()); + let mut checker = Checker::new(settings); - for node in &python_cst.body { - checker.visit_Statement(node); - } + let mut transformed = checker.visit_Module(python_cst); + + let mut state = Default::default(); + transformed.codegen(&mut state); + println!("{}", state); + checker.checks } diff --git a/src/cst_visitor.rs b/src/cst_visitor.rs index 50ad2450e0..219a953619 100644 --- a/src/cst_visitor.rs +++ b/src/cst_visitor.rs @@ -9,23 +9,32 @@ use libcst_native::{ ExceptStarHandler, Expr, Expression, Finally, Float, For, FormattedString, FormattedStringContent, FormattedStringExpression, FormattedStringText, From, FunctionDef, GeneratorExp, Global, If, IfExp, Imaginary, Import, ImportAlias, ImportFrom, ImportNames, - ImportStar, IndentedBlock, Index, Integer, Lambda, List, ListComp, Match, Name, NameItem, - NameOrAttribute, NamedExpr, Nonlocal, OrElse, Param, ParamStar, Parameters, Pass, Raise, - Return, Set, SetComp, SimpleStatementLine, SimpleStatementSuite, SimpleString, Slice, + ImportStar, IndentedBlock, Index, Integer, Lambda, List, ListComp, Match, Module, Name, + NameItem, NameOrAttribute, NamedExpr, Nonlocal, OrElse, Param, ParamStar, Parameters, Pass, + Raise, Return, Set, SetComp, SimpleStatementLine, SimpleStatementSuite, SimpleString, Slice, SmallStatement, StarArg, StarredDictElement, StarredElement, Statement, Subscript, SubscriptElement, Suite, Try, TryStar, Tuple, UnaryOp, UnaryOperation, While, With, WithItem, Yield, YieldValue, }; pub trait CSTVisitor { - fn visit_Statement(&mut self, node: &Statement) { - walk_Statement(self, node); + fn visit_Module<'a>(&mut self, node: &'a Module<'a>) -> Module<'a> { + walk_Module(self, node) } - fn visit_SimpleStatementLine(&mut self, node: &SimpleStatementLine) { - walk_SimpleStatementLine(self, node); + fn visit_Statement<'a>(&mut self, node: &'a Statement<'a>) -> Option> { + walk_Statement(self, node) } - fn visit_CompoundStatement(&mut self, node: &CompoundStatement) { - walk_CompoundStatement(self, node); + fn visit_SimpleStatementLine<'a>( + &mut self, + node: &'a SimpleStatementLine<'a>, + ) -> Option> { + walk_SimpleStatementLine(self, node) + } + fn visit_CompoundStatement<'a>( + &mut self, + node: &'a CompoundStatement<'a>, + ) -> Option> { + walk_CompoundStatement(self, node) } fn visit_SmallStatement(&mut self, node: &SmallStatement) { walk_SmallStatement(self, node); @@ -90,8 +99,8 @@ pub trait CSTVisitor { fn visit_Call(&mut self, node: &Call) { walk_Call(self, node); } - fn visit_ClassDef(&mut self, node: &ClassDef) { - walk_ClassDef(self, node); + fn visit_ClassDef<'a>(&mut self, node: &'a ClassDef<'a>) -> ClassDef<'a> { + walk_ClassDef(self, node) } fn visit_CompFor(&mut self, node: &CompFor) { walk_CompFor(self, node); @@ -180,9 +189,8 @@ pub trait CSTVisitor { fn visit_Global(&mut self, node: &Global) { walk_Global(self, node); } - fn visit_If<'a>(&'a mut self, node: &'a If) -> &'a If { + fn visit_If(&mut self, node: &If) { walk_If(self, node); - return node; } fn visit_IfExp(&mut self, node: &IfExp) { walk_IfExp(self, node); @@ -333,36 +341,68 @@ pub trait CSTVisitor { } } -pub fn walk_Statement(visitor: &mut V, node: &Statement) { +pub fn walk_Module<'a, V: CSTVisitor + ?Sized>(visitor: &mut V, node: &'a Module<'a>) -> Module<'a> +where + 'a: 'a, +{ + let mut body: Vec = vec![]; + for node in &node.body { + if let Some(node) = visitor.visit_Statement(node) { + body.push(node) + } + } + + let mut transformed: Module<'a> = node.clone(); + transformed.body = body; + transformed +} + +pub fn walk_Statement<'a, V: CSTVisitor + ?Sized>( + visitor: &mut V, + node: &'a Statement<'a>, +) -> Option> { match node { - Statement::Simple(node) => visitor.visit_SimpleStatementLine(node), - Statement::Compound(node) => visitor.visit_CompoundStatement(node), + Statement::Simple(node) => visitor + .visit_SimpleStatementLine(node) + .map(Statement::Simple), + Statement::Compound(node) => visitor + .visit_CompoundStatement(node) + .map(Statement::Compound), } } -pub fn walk_SimpleStatementLine( +pub fn walk_SimpleStatementLine<'a, V: CSTVisitor + ?Sized>( visitor: &mut V, - node: &SimpleStatementLine, -) { + node: &'a SimpleStatementLine<'a>, +) -> Option> { for node in &node.body { visitor.visit_SmallStatement(node); } + Some(node.clone()) } -pub fn walk_CompoundStatement(visitor: &mut V, node: &CompoundStatement) { +pub fn walk_CompoundStatement<'a, V: CSTVisitor + ?Sized>( + visitor: &mut V, + node: &'a CompoundStatement<'a>, +) -> Option> { match node { - CompoundStatement::FunctionDef(node) => visitor.visit_FunctionDef(node), CompoundStatement::If(node) => { visitor.visit_If(node); + return None; } + CompoundStatement::FunctionDef(node) => visitor.visit_FunctionDef(node), CompoundStatement::For(node) => visitor.visit_For(node), CompoundStatement::While(node) => visitor.visit_While(node), - CompoundStatement::ClassDef(node) => visitor.visit_ClassDef(node), + CompoundStatement::ClassDef(node) => { + return Some(CompoundStatement::ClassDef(visitor.visit_ClassDef(node))) + } CompoundStatement::Try(node) => visitor.visit_Try(node), CompoundStatement::TryStar(node) => visitor.visit_TryStar(node), CompoundStatement::With(node) => visitor.visit_With(node), CompoundStatement::Match(node) => visitor.visit_Match(node), } + + Some(node.clone()) } pub fn walk_SmallStatement(visitor: &mut V, node: &SmallStatement) { @@ -428,7 +468,7 @@ pub fn walk_AssignTargetExpression( visitor: &mut V, node: &AssignTargetExpression, ) { - match &node { + match node { AssignTargetExpression::Name(node) => visitor.visit_Name(node), AssignTargetExpression::Attribute(node) => visitor.visit_Attribute(node), AssignTargetExpression::StarredElement(node) => visitor.visit_StarredElement(node), @@ -439,8 +479,8 @@ pub fn walk_AssignTargetExpression( } pub fn walk_AnnAssign(visitor: &mut V, node: &AnnAssign) { visitor.visit_AssignTargetExpression(&node.target); - if let Some(expression) = &node.value { - visitor.visit_Expression(expression) + if let Some(node) = &node.value { + visitor.visit_Expression(node) } } pub fn walk_Annotation(visitor: &mut V, node: &Annotation) { @@ -508,7 +548,10 @@ pub fn walk_Call(visitor: &mut V, node: &Call) { } visitor.visit_Expression(&node.func) } -pub fn walk_ClassDef(visitor: &mut V, node: &ClassDef) { +pub fn walk_ClassDef<'a, V: CSTVisitor + ?Sized>( + visitor: &mut V, + node: &'a ClassDef<'a>, +) -> ClassDef<'a> { visitor.visit_Name(&node.name); for node in &node.bases { visitor.visit_Arg(node); @@ -523,6 +566,8 @@ pub fn walk_ClassDef(visitor: &mut V, node: &ClassDef) { Suite::IndentedBlock(node) => visitor.visit_IndentedBlock(node), Suite::SimpleStatementSuite(node) => visitor.visit_SimpleStatementSuite(node), } + + node.clone() } pub fn walk_CompFor(visitor: &mut V, node: &CompFor) { if let Some(node) = &node.asynchronous { @@ -569,7 +614,7 @@ pub fn walk_DelTargetExpression( visitor: &mut V, node: &DelTargetExpression, ) { - match &node { + match node { DelTargetExpression::Name(node) => visitor.visit_Name(node), DelTargetExpression::Attribute(node) => visitor.visit_Attribute(node), DelTargetExpression::Tuple(node) => visitor.visit_Tuple(node), @@ -588,7 +633,7 @@ pub fn walk_DictComp(visitor: &mut V, node: &DictComp) { visitor.visit_CompFor(&node.for_in); } pub fn walk_DictElement(visitor: &mut V, node: &DictElement) { - match &node { + match node { DictElement::Simple { key, value, .. } => { visitor.visit_Expression(key); visitor.visit_Expression(value); @@ -597,7 +642,7 @@ pub fn walk_DictElement(visitor: &mut V, node: &DictElem } } pub fn walk_Element(visitor: &mut V, node: &Element) { - match &node { + match node { Element::Simple { value: node, .. } => visitor.visit_Expression(node), Element::Starred(node) => visitor.visit_StarredElement(node), } @@ -707,7 +752,7 @@ pub fn walk_GeneratorExp(visitor: &mut V, node: &Generat } pub fn walk_Global(visitor: &mut V, node: &Global) { for node in &node.names { - visitor.visit_NameItem(&node) + visitor.visit_NameItem(node) } } pub fn walk_If(visitor: &mut V, node: &If) { @@ -757,7 +802,7 @@ pub fn walk_ImportStar(visitor: &mut V, node: &ImportSta } pub fn walk_IndentedBlock(visitor: &mut V, node: &IndentedBlock) { for node in &node.body { - visitor.visit_Statement(node) + visitor.visit_Statement(node); } } pub fn walk_Index(visitor: &mut V, node: &Index) { @@ -831,7 +876,7 @@ pub fn walk_Parameters(visitor: &mut V, node: &Parameter visitor.visit_Param(node); } if let Some(node) = &node.star_arg { - match &node { + match node { StarArg::Star(node) => visitor.visit_ParamStar(node), StarArg::Param(node) => visitor.visit_Param(node), } @@ -971,7 +1016,7 @@ pub fn walk_Yield(visitor: &mut V, node: &Yield) { } } pub fn walk_YieldValue(visitor: &mut V, node: &YieldValue) { - match &node { + match node { YieldValue::Expression(node) => visitor.visit_Expression(node), YieldValue::From(node) => visitor.visit_From(node), } diff --git a/src/linter.rs b/src/linter.rs index 5792bd5949..242b0deae9 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -2,12 +2,9 @@ use std::path::Path; use anyhow::Result; use log::debug; -use rustpython_parser::parser; -use crate::check_ast::check_ast; use crate::check_cst::check_cst; -use crate::check_lines::check_lines; -use crate::checks::{Check, LintSource}; +use crate::checks::Check; use crate::message::Message; use crate::settings::Settings; use crate::{cache, fs};