From 943a0de62b47fade57779827751873aab6229e01 Mon Sep 17 00:00:00 2001 From: Charles Marsh Date: Sat, 13 Aug 2022 17:58:19 -0400 Subject: [PATCH] Add a check for long lines --- Cargo.lock | 2 +- Cargo.toml | 2 +- resources/test/src/line_too_long.py | 4 ++++ src/{checker.rs => check_ast.rs} | 2 +- src/check_lines.rs | 21 ++++++++++++++++++ src/checks.rs | 3 +++ src/fs.rs | 14 ++++++++++-- src/lib.rs | 4 ++-- src/linter.rs | 33 +++++++++++++++++++++++++---- src/message.rs | 5 +++-- src/parser.rs | 15 ------------- 11 files changed, 77 insertions(+), 28 deletions(-) create mode 100644 resources/test/src/line_too_long.py rename src/{checker.rs => check_ast.rs} (98%) create mode 100644 src/check_lines.rs delete mode 100644 src/parser.rs diff --git a/Cargo.lock b/Cargo.lock index 54f1830cde..5801588c52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1493,7 +1493,7 @@ dependencies = [ [[package]] name = "rust-python-linter" -version = "0.0.8" +version = "0.0.9" dependencies = [ "anyhow", "bincode", diff --git a/Cargo.toml b/Cargo.toml index adfcbd76bb..11f5f4743a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rust-python-linter" -version = "0.0.8" +version = "0.0.9" edition = "2021" [lib] diff --git a/resources/test/src/line_too_long.py b/resources/test/src/line_too_long.py new file mode 100644 index 0000000000..337d845359 --- /dev/null +++ b/resources/test/src/line_too_long.py @@ -0,0 +1,4 @@ +"""Lorem ipsum dolor sit amet. + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +""" diff --git a/src/checker.rs b/src/check_ast.rs similarity index 98% rename from src/checker.rs rename to src/check_ast.rs index c5de2f9ef1..4af031efd2 100644 --- a/src/checker.rs +++ b/src/check_ast.rs @@ -85,7 +85,7 @@ pub fn check_ast(python_ast: &Suite) -> Vec { mod tests { use rustpython_parser::ast::{Alias, Location, Stmt, StmtKind}; - use crate::checker::Checker; + use crate::check_ast::Checker; use crate::checks::Check; use crate::checks::CheckKind::ImportStarUsage; use crate::visitor::Visitor; diff --git a/src/check_lines.rs b/src/check_lines.rs new file mode 100644 index 0000000000..86162f7851 --- /dev/null +++ b/src/check_lines.rs @@ -0,0 +1,21 @@ +use rustpython_parser::ast::Location; + +use crate::checks::Check; +use crate::checks::CheckKind::LineTooLong; + +pub fn check_lines(contents: &str) -> Vec { + contents + .lines() + .enumerate() + .filter_map(|(row, line)| { + if line.len() > 79 { + Some(Check { + kind: LineTooLong, + location: Location::new(row + 1, 79 + 1), + }) + } else { + None + } + }) + .collect() +} diff --git a/src/checks.rs b/src/checks.rs index adebda18af..0746361319 100644 --- a/src/checks.rs +++ b/src/checks.rs @@ -6,6 +6,7 @@ pub enum CheckKind { DuplicateArgumentName, ImportStarUsage, IfTuple, + LineTooLong, } impl CheckKind { @@ -15,6 +16,7 @@ impl CheckKind { CheckKind::DuplicateArgumentName => "F831", CheckKind::IfTuple => "F634", CheckKind::ImportStarUsage => "F403", + CheckKind::LineTooLong => "E501", } } @@ -24,6 +26,7 @@ impl CheckKind { CheckKind::DuplicateArgumentName => "Duplicate argument name in function definition", CheckKind::IfTuple => "If test is a tuple, which is always `True`", CheckKind::ImportStarUsage => "Unable to detect undefined names", + CheckKind::LineTooLong => "Line too long (> 79 characters)", } } } diff --git a/src/fs.rs b/src/fs.rs index 096aa80ed1..096526741b 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1,5 +1,7 @@ -use std::path::PathBuf; - +use anyhow::Result; +use std::fs::File; +use std::io::{BufReader, Read}; +use std::path::{Path, PathBuf}; use walkdir::{DirEntry, WalkDir}; fn is_not_hidden(entry: &DirEntry) -> bool { @@ -18,3 +20,11 @@ pub fn iter_python_files(path: &PathBuf) -> impl Iterator { .filter_map(|entry| entry.ok()) .filter(|entry| entry.path().to_string_lossy().ends_with(".py")) } + +pub fn read_file(path: &Path) -> Result { + let file = File::open(path)?; + let mut buf_reader = BufReader::new(file); + let mut contents = String::new(); + buf_reader.read_to_string(&mut contents)?; + Ok(contents) +} diff --git a/src/lib.rs b/src/lib.rs index 61547eeabb..fb6ce26356 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,9 @@ mod cache; -pub mod checker; +pub mod check_ast; +mod check_lines; mod checks; pub mod fs; pub mod linter; pub mod logging; pub mod message; -mod parser; mod visitor; diff --git a/src/linter.rs b/src/linter.rs index 209fc881fb..1429cc2933 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -2,10 +2,12 @@ use std::path::Path; use anyhow::Result; use log::debug; +use rustpython_parser::parser; -use crate::checker::check_ast; +use crate::check_ast::check_ast; +use crate::check_lines::check_lines; use crate::message::Message; -use crate::{cache, parser}; +use crate::{cache, fs}; pub fn check_path(path: &Path, mode: &cache::Mode) -> Result> { // Check the cache. @@ -14,10 +16,14 @@ pub fn check_path(path: &Path, mode: &cache::Mode) -> Result> { return Ok(messages); } + // Read the file from disk. + let contents = fs::read_file(path)?; + // Run the linter. - let python_ast = parser::parse(path)?; + let python_ast = parser::parse_program(&contents)?; let messages: Vec = check_ast(&python_ast) .into_iter() + .chain(check_lines(&contents)) .map(|check| Message { kind: check.kind, location: check.location, @@ -37,7 +43,7 @@ mod tests { use rustpython_parser::ast::Location; use crate::cache; - use crate::checks::CheckKind::{DuplicateArgumentName, IfTuple, ImportStarUsage}; + use crate::checks::CheckKind::{DuplicateArgumentName, IfTuple, ImportStarUsage, LineTooLong}; use crate::linter::check_path; use crate::message::Message; @@ -116,4 +122,23 @@ mod tests { Ok(()) } + + #[test] + fn line_too_long() -> Result<()> { + let actual = check_path( + &Path::new("./resources/test/src/line_too_long.py"), + &cache::Mode::None, + )?; + let expected = vec![Message { + kind: LineTooLong, + location: Location::new(3, 80), + filename: "./resources/test/src/line_too_long.py".to_string(), + }]; + assert_eq!(actual.len(), expected.len()); + for i in 1..actual.len() { + assert_eq!(actual[i], expected[i]); + } + + Ok(()) + } } diff --git a/src/message.rs b/src/message.rs index b6d3c38b92..ce7f80ac5f 100644 --- a/src/message.rs +++ b/src/message.rs @@ -33,12 +33,13 @@ impl fmt::Display for Message { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, - "{}{}{}{}{}\t{}\t{}", + "{}{}{}{}{}{} {} {}", self.filename.white().bold(), ":".cyan(), + self.location.row(), + ":".cyan(), self.location.column(), ":".cyan(), - self.location.row(), self.kind.code().red().bold(), self.kind.body() ) diff --git a/src/parser.rs b/src/parser.rs deleted file mode 100644 index 94a8dcbbc2..0000000000 --- a/src/parser.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::fs::File; -use std::io::{BufReader, Read}; -use std::path::Path; - -use anyhow::Result; -use rustpython_parser::ast::Suite; -use rustpython_parser::parser; - -pub fn parse(path: &Path) -> Result { - let file = File::open(path)?; - let mut buf_reader = BufReader::new(file); - let mut contents = String::new(); - buf_reader.read_to_string(&mut contents)?; - parser::parse_program(&contents).map_err(|e| e.into()) -}