Lints and suggestions for the Nix programming language

feat!: rm nix_version config option

it is unused complexity

Co-authored-by: Wes Gray <wes.gray@gmail.com>

+65 -244
+2 -19
bin/src/config.rs
··· 8 8 use crate::{LintMap, dirs, err::ConfigErr, utils}; 9 9 10 10 use clap::Parser; 11 - use lib::{LINTS, session::Version}; 11 + use lib::LINTS; 12 12 use serde::{Deserialize, Serialize}; 13 13 use vfs::ReadOnlyVfs; 14 14 ··· 260 260 #[serde(default = "Vec::new")] 261 261 disabled: Vec<String>, 262 262 263 - nix_version: Option<String>, 264 - 265 263 #[serde(default = "Vec::new")] 266 264 pub ignore: Vec<String>, 267 265 } ··· 290 288 pub fn dump(&self) -> String { 291 289 let ideal_config = { 292 290 let disabled = vec![]; 293 - let nix_version = Some(utils::default_nix_version()); 294 291 let ignore = vec![".direnv".into()]; 295 - Self { 296 - disabled, 297 - nix_version, 298 - ignore, 299 - } 292 + Self { disabled, ignore } 300 293 }; 301 294 toml::ser::to_string_pretty(&ideal_config).unwrap() 302 295 } ··· 310 303 .collect::<Vec<_>>() 311 304 .as_slice(), 312 305 ) 313 - } 314 - pub fn version(&self) -> Result<Version, ConfigErr> { 315 - if let Some(v) = &self.nix_version { 316 - v.parse::<Version>() 317 - .map_err(|()| ConfigErr::ConfFileVersionParse(v.clone())) 318 - } else if let Some(v) = utils::get_version_info().and_then(|o| o.parse::<Version>().ok()) { 319 - Ok(v) 320 - } else { 321 - Ok(utils::default_nix_version().parse::<Version>().unwrap()) 322 - } 323 306 } 324 307 } 325 308
+3 -22
bin/src/fix.rs
··· 2 2 3 3 use crate::LintMap; 4 4 5 - use lib::session::SessionInfo; 6 5 use rnix::TextRange; 7 6 8 7 mod all; ··· 17 16 pub src: Source<'a>, 18 17 pub fixed: Vec<Fixed>, 19 18 pub lints: &'a LintMap, 20 - pub sess: &'a SessionInfo, 21 19 } 22 20 23 21 #[derive(Debug, Clone)] ··· 27 25 } 28 26 29 27 impl<'a> FixResult<'a> { 30 - fn empty(src: Source<'a>, lints: &'a LintMap, sess: &'a SessionInfo) -> Self { 28 + fn empty(src: Source<'a>, lints: &'a LintMap) -> Self { 31 29 Self { 32 30 src, 33 31 fixed: Vec::new(), 34 32 lints, 35 - sess, 36 33 } 37 34 } 38 35 } ··· 47 44 err::{FixErr, StatixErr}, 48 45 }; 49 46 50 - use lib::session::SessionInfo; 51 47 use similar::TextDiff; 52 48 53 49 pub fn all(fix_config: &FixConfig) -> Result<(), StatixErr> { ··· 55 51 let vfs = fix_config.vfs(conf_file.ignore.as_slice())?; 56 52 57 53 let lints = conf_file.lints(); 58 - let version = conf_file.version()?; 59 - 60 - let session = SessionInfo::from_version(version); 61 54 62 55 for entry in vfs.iter() { 63 - match ( 64 - fix_config.out(), 65 - super::all_with(entry.contents, &lints, &session), 66 - ) { 56 + match (fix_config.out(), super::all_with(entry.contents, &lints)) { 67 57 (FixOut::Diff, fix_result) => { 68 58 let src = fix_result 69 59 .map(|r| r.src) ··· 102 92 let original_src = entry.contents; 103 93 let (line, col) = single_config.position; 104 94 105 - let conf_file = ConfFile::discover(&single_config.conf_path)?; 106 - 107 - let version = conf_file.version()?; 108 - 109 - let session = SessionInfo::from_version(version); 110 - 111 - match ( 112 - single_config.out(), 113 - super::single(line, col, original_src, &session), 114 - ) { 95 + match (single_config.out(), super::single(line, col, original_src)) { 115 96 (FixOut::Diff, single_result) => { 116 97 let fixed_src = single_result 117 98 .map(|r| r.src)
+6 -15
bin/src/fix/all.rs
··· 1 1 use std::borrow::Cow; 2 2 3 - use lib::{Report, session::SessionInfo}; 3 + use lib::Report; 4 4 use rnix::{Root, WalkEvent, parser::ParseError as RnixParseErr}; 5 5 use rowan::ast::AstNode as _; 6 6 ··· 9 9 fix::{FixResult, Fixed}, 10 10 }; 11 11 12 - fn collect_fixes( 13 - source: &str, 14 - lints: &LintMap, 15 - sess: &SessionInfo, 16 - ) -> Result<Vec<Report>, RnixParseErr> { 12 + fn collect_fixes(source: &str, lints: &LintMap) -> Result<Vec<Report>, RnixParseErr> { 17 13 let parsed = Root::parse(source).ok()?; 18 14 19 15 Ok(parsed ··· 23 19 WalkEvent::Enter(child) => lints.get(&child.kind()).map(|rules| { 24 20 rules 25 21 .iter() 26 - .filter_map(|rule| rule.validate(&child, sess)) 22 + .filter_map(|rule| rule.validate(&child)) 27 23 .filter(|report| report.total_suggestion_range().is_some()) 28 24 .collect::<Vec<_>>() 29 25 }), ··· 62 58 impl<'a> Iterator for FixResult<'a> { 63 59 type Item = FixResult<'a>; 64 60 fn next(&mut self) -> Option<Self::Item> { 65 - let all_reports = collect_fixes(&self.src, self.lints, self.sess).ok()?; 61 + let all_reports = collect_fixes(&self.src, self.lints).ok()?; 66 62 if all_reports.is_empty() { 67 63 return None; 68 64 } ··· 83 79 src: self.src.clone(), 84 80 fixed, 85 81 lints: self.lints, 86 - sess: self.sess, 87 82 }) 88 83 } 89 84 } 90 85 91 - pub fn all_with<'a>( 92 - src: &'a str, 93 - lints: &'a LintMap, 94 - sess: &'a SessionInfo, 95 - ) -> Option<FixResult<'a>> { 86 + pub fn all_with<'a>(src: &'a str, lints: &'a LintMap) -> Option<FixResult<'a>> { 96 87 let src = Cow::from(src); 97 88 let _ = Root::parse(&src).ok().ok()?; 98 - let initial = FixResult::empty(src, lints, sess); 89 + let initial = FixResult::empty(src, lints); 99 90 initial.into_iter().last() 100 91 }
+5 -10
bin/src/fix/single.rs
··· 1 1 use std::{borrow::Cow, convert::TryFrom}; 2 2 3 - use lib::{Report, session::SessionInfo}; 3 + use lib::Report; 4 4 use rnix::{Root, TextSize, WalkEvent}; 5 5 6 6 use crate::{err::SingleFixErr, fix::Source, utils}; ··· 27 27 } 28 28 } 29 29 30 - fn find(offset: TextSize, src: &str, sess: &SessionInfo) -> Result<Report, SingleFixErr> { 30 + fn find(offset: TextSize, src: &str) -> Result<Report, SingleFixErr> { 31 31 // we don't really need the source to form a completely parsed tree 32 32 let parsed = Root::parse(src); 33 33 let lints = utils::lint_map(); ··· 39 39 WalkEvent::Enter(child) => lints.get(&child.kind()).map(|rules| { 40 40 rules 41 41 .iter() 42 - .filter_map(|rule| rule.validate(&child, sess)) 42 + .filter_map(|rule| rule.validate(&child)) 43 43 .find(|report| report.total_suggestion_range().is_some()) 44 44 }), 45 45 WalkEvent::Leave(_) => None, ··· 49 49 .ok_or(SingleFixErr::NoOp) 50 50 } 51 51 52 - pub fn single<'a>( 53 - line: usize, 54 - col: usize, 55 - src: &'a str, 56 - sess: &SessionInfo, 57 - ) -> Result<SingleFixResult<'a>, SingleFixErr> { 52 + pub fn single(line: usize, col: usize, src: &str) -> Result<SingleFixResult<'_>, SingleFixErr> { 58 53 let mut src = Cow::from(src); 59 54 let offset = pos_to_byte(line, col, &src)?; 60 - let report = find(offset, &src, sess)?; 55 + let report = find(offset, &src)?; 61 56 62 57 report.apply(src.to_mut()); 63 58
+6 -9
bin/src/lint.rs
··· 1 1 use crate::{LintMap, utils}; 2 2 3 - use lib::{Report, session::SessionInfo}; 3 + use lib::Report; 4 4 use rnix::{Root, WalkEvent}; 5 5 use vfs::{FileId, VfsEntry}; 6 6 ··· 11 11 } 12 12 13 13 #[must_use] 14 - pub fn lint_with(vfs_entry: &VfsEntry, lints: &LintMap, sess: &SessionInfo) -> LintResult { 14 + pub fn lint_with(vfs_entry: &VfsEntry, lints: &LintMap) -> LintResult { 15 15 let file_id = vfs_entry.file_id; 16 16 let source = vfs_entry.contents; 17 17 let parsed = Root::parse(source); ··· 27 27 WalkEvent::Enter(child) => lints.get(&child.kind()).map(|rules| { 28 28 rules 29 29 .iter() 30 - .filter_map(|rule| rule.validate(&child, sess)) 30 + .filter_map(|rule| rule.validate(&child)) 31 31 .collect::<Vec<_>>() 32 32 }), 33 33 WalkEvent::Leave(_) => None, ··· 40 40 } 41 41 42 42 #[must_use] 43 - pub fn lint(vfs_entry: &VfsEntry, sess: &SessionInfo) -> LintResult { 44 - lint_with(vfs_entry, &utils::lint_map(), sess) 43 + pub fn lint(vfs_entry: &VfsEntry) -> LintResult { 44 + lint_with(vfs_entry, &utils::lint_map()) 45 45 } 46 46 47 47 pub mod main { ··· 54 54 traits::WriteDiagnostic, 55 55 }; 56 56 57 - use lib::session::SessionInfo; 58 57 use rayon::prelude::*; 59 58 60 59 pub fn main(check_config: &CheckConfig) -> Result<(), StatixErr> { 61 60 let conf_file = ConfFile::discover(&check_config.conf_path)?; 62 61 let lints = conf_file.lints(); 63 - let version = conf_file.version()?; 64 - let session = SessionInfo::from_version(version); 65 62 66 63 let vfs = check_config.vfs(conf_file.ignore.as_slice())?; 67 64 68 65 let mut stdout = io::stdout(); 69 - let lint = |vfs_entry| lint_with(&vfs_entry, &lints, &session); 66 + let lint = |vfs_entry| lint_with(&vfs_entry, &lints); 70 67 let results = vfs 71 68 .par_iter() 72 69 .map(lint)
-14
bin/src/utils.rs
··· 24 24 pub fn lint_map() -> HashMap<SyntaxKind, Vec<&'static Box<dyn Lint>>> { 25 25 lint_map_of(&LINTS) 26 26 } 27 - 28 - pub fn get_version_info() -> Option<String> { 29 - use std::process::Command; 30 - let program = Command::new("nix").arg("--version").output().ok()?; 31 - std::str::from_utf8(&program.stdout) 32 - .ok()? 33 - .split(' ') 34 - .nth(2) 35 - .map(ToOwned::to_owned) 36 - } 37 - 38 - pub fn default_nix_version() -> String { 39 - String::from("2.4") 40 - }
+8 -22
bin/tests/main.rs
··· 1 1 use std::path::Path; 2 2 3 - use lib::session::{SessionInfo, Version}; 4 - 5 - macro_rules! session_info { 6 - ($version:expr) => {{ 7 - let v: Version = $version.parse().unwrap(); 8 - SessionInfo::from_version(v) 9 - }}; 10 - } 11 - 12 3 mod util { 13 4 #[macro_export] 14 5 macro_rules! test_lint { 15 - ($tname:ident => $sess:expr, $($tail:tt)*) => { 16 - test_lint!($tname => $sess); 6 + ($tname:ident, $($tail:tt)*) => { 7 + test_lint!($tname); 17 8 test_lint!($($tail)*); 18 9 }; 19 10 ($tname:ident, $($tail:tt)*) => { ··· 21 12 test_lint!($($tail)*); 22 13 }; 23 14 ($tname:ident) => { 24 - test_lint!($tname => session_info!("2.6")); 25 - }; 26 - ($tname:ident => $sess:expr) => { 27 15 paste::paste! { 28 16 #[test] 29 17 fn [<$tname _lint>](){ 30 18 let file_path = concat!("data/", stringify!($tname), ".nix"); 31 19 let contents = include_str!(concat!("data/", stringify!($tname), ".nix")); 32 - test_lint(&$sess, file_path, contents); 20 + test_lint(file_path, contents); 33 21 } 34 22 35 23 #[test] ··· 43 31 } 44 32 } 45 33 46 - fn test_lint(session: &SessionInfo, file_path: impl AsRef<Path>, contents: &str) { 34 + fn test_lint(file_path: impl AsRef<Path>, contents: &str) { 47 35 use statix::{config::OutFormat, lint, traits::WriteDiagnostic}; 48 36 use vfs::ReadOnlyVfs; 49 37 50 38 let vfs = ReadOnlyVfs::singleton(file_path, contents.as_bytes()); 51 39 52 40 let mut buffer = Vec::new(); 53 - vfs.iter() 54 - .map(|entry| lint::lint(&entry, session)) 55 - .for_each(|r| { 56 - buffer.write(&r, &vfs, OutFormat::StdErr).unwrap(); 57 - }); 41 + vfs.iter().map(|entry| lint::lint(&entry)).for_each(|r| { 42 + buffer.write(&r, &vfs, OutFormat::StdErr).unwrap(); 43 + }); 58 44 59 45 let stripped = strip_ansi_escapes::strip(&buffer).unwrap(); 60 46 let out = std::str::from_utf8(&stripped).unwrap(); ··· 87 73 redundant_pattern_bind, 88 74 unquoted_uri, 89 75 empty_inherit, 90 - deprecated_to_path => session_info!("2.4"), 76 + deprecated_to_path, 91 77 bool_simplification, 92 78 useless_has_attr, 93 79 repeated_keys,
+1 -3
lib/src/lib.rs
··· 1 1 #![recursion_limit = "1024"] 2 2 mod lints; 3 3 mod make; 4 - pub mod session; 5 4 mod utils; 6 5 7 6 pub use lints::LINTS; 8 - use session::SessionInfo; 9 7 10 8 use rnix::{SyntaxElement, SyntaxKind, TextRange, parser::ParseError}; 11 9 use std::{convert::Into, default::Default}; ··· 249 247 /// Lint logic is defined via this trait. Do not implement manually, 250 248 /// look at the `lint` attribute macro instead for implementing rules 251 249 pub trait Rule { 252 - fn validate(&self, node: &SyntaxElement, sess: &SessionInfo) -> Option<Report>; 250 + fn validate(&self, node: &SyntaxElement) -> Option<Report>; 253 251 } 254 252 255 253 /// Contains information about the lint itself. Do not implement manually,
+2 -2
lib/src/lints/bool_comparison.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule, Suggestion, make}; 2 2 3 3 use macros::lint; 4 4 use rnix::{ ··· 35 35 struct BoolComparison; 36 36 37 37 impl Rule for BoolComparison { 38 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 38 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 39 39 let NodeOrToken::Node(node) = node else { 40 40 return None; 41 41 };
+2 -2
lib/src/lints/bool_simplification.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule, Suggestion, make}; 2 2 3 3 use macros::lint; 4 4 use rnix::{ ··· 32 32 struct BoolSimplification; 33 33 34 34 impl Rule for BoolSimplification { 35 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 35 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 36 36 let NodeOrToken::Node(node) = node else { 37 37 return None; 38 38 };
+2 -2
lib/src/lints/collapsible_let_in.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule, Suggestion}; 2 2 3 3 use macros::lint; 4 4 use rnix::{ ··· 44 44 struct CollapsibleLetIn; 45 45 46 46 impl Rule for CollapsibleLetIn { 47 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 47 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 48 48 let NodeOrToken::Node(node) = node else { 49 49 return None; 50 50 };
+2 -2
lib/src/lints/deprecated_to_path.rs
··· 1 - use crate::{Metadata, Report, Rule, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule}; 2 2 3 3 use macros::lint; 4 4 use rnix::{NodeOrToken, SyntaxElement, SyntaxKind, ast::Apply}; ··· 38 38 static ALLOWED_PATHS: &[&str; 2] = &["builtins.toPath", "toPath"]; 39 39 40 40 impl Rule for DeprecatedToPath { 41 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 41 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 42 42 if let NodeOrToken::Node(node) = node 43 43 && let Some(apply) = Apply::cast(node.clone()) 44 44 && let lambda_path = apply.lambda()?.to_string()
+2 -2
lib/src/lints/empty_inherit.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, session::SessionInfo, utils}; 1 + use crate::{Metadata, Report, Rule, Suggestion, utils}; 2 2 3 3 use macros::lint; 4 4 use rnix::{NodeOrToken, SyntaxElement, SyntaxKind, ast::Inherit}; ··· 26 26 struct EmptyInherit; 27 27 28 28 impl Rule for EmptyInherit { 29 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 29 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 30 30 let NodeOrToken::Node(node) = node else { 31 31 return None; 32 32 };
+2 -2
lib/src/lints/empty_let_in.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule, Suggestion}; 2 2 3 3 use macros::lint; 4 4 use rnix::{ ··· 34 34 struct EmptyLetIn; 35 35 36 36 impl Rule for EmptyLetIn { 37 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 37 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 38 38 if let NodeOrToken::Node(node) = node 39 39 && let Some(let_in_expr) = LetIn::cast(node.clone()) 40 40 && let entries = let_in_expr.entries()
+2 -2
lib/src/lints/empty_list_concat.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule, Suggestion}; 2 2 3 3 use macros::lint; 4 4 use rnix::{ ··· 32 32 struct EmptyListConcat; 33 33 34 34 impl Rule for EmptyListConcat { 35 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 35 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 36 36 let NodeOrToken::Node(node) = node else { 37 37 return None; 38 38 };
+2 -2
lib/src/lints/empty_pattern.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule, Suggestion, make}; 2 2 3 3 use macros::lint; 4 4 use rnix::{ ··· 41 41 struct EmptyPattern; 42 42 43 43 impl Rule for EmptyPattern { 44 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 44 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 45 45 let NodeOrToken::Node(node) = node else { 46 46 return None; 47 47 };
+2 -2
lib/src/lints/eta_reduction.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule, Suggestion}; 2 2 3 3 use macros::lint; 4 4 use rnix::{ ··· 42 42 struct EtaReduction; 43 43 44 44 impl Rule for EtaReduction { 45 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 45 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 46 46 let NodeOrToken::Node(node) = node else { 47 47 return None; 48 48 };
+2 -2
lib/src/lints/legacy_let_syntax.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule, Suggestion, make}; 2 2 3 3 use macros::lint; 4 4 use rnix::{ ··· 44 44 struct ManualInherit; 45 45 46 46 impl Rule for ManualInherit { 47 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 47 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 48 48 let NodeOrToken::Node(node) = node else { 49 49 return None; 50 50 };
+2 -2
lib/src/lints/manual_inherit.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule, Suggestion, make}; 2 2 3 3 use macros::lint; 4 4 use rnix::{ ··· 40 40 struct ManualInherit; 41 41 42 42 impl Rule for ManualInherit { 43 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 43 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 44 44 let NodeOrToken::Node(node) = node else { 45 45 return None; 46 46 };
+2 -2
lib/src/lints/manual_inherit_from.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule, Suggestion, make}; 2 2 3 3 use macros::lint; 4 4 use rnix::{ ··· 40 40 struct ManualInherit; 41 41 42 42 impl Rule for ManualInherit { 43 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 43 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 44 44 let NodeOrToken::Node(node) = node else { 45 45 return None; 46 46 };
+2 -2
lib/src/lints/redundant_pattern_bind.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule, Suggestion}; 2 2 3 3 use macros::lint; 4 4 use rnix::{NodeOrToken, SyntaxElement, SyntaxKind, ast::Pattern}; ··· 32 32 struct RedundantPatternBind; 33 33 34 34 impl Rule for RedundantPatternBind { 35 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 35 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 36 36 let NodeOrToken::Node(node) = node else { 37 37 return None; 38 38 };
+2 -2
lib/src/lints/repeated_keys.rs
··· 1 1 use std::fmt::Write as _; 2 2 3 - use crate::{Metadata, Report, Rule, session::SessionInfo}; 3 + use crate::{Metadata, Report, Rule}; 4 4 5 5 use macros::lint; 6 6 use rnix::{ ··· 45 45 struct RepeatedKeys; 46 46 47 47 impl Rule for RepeatedKeys { 48 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 48 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 49 49 let NodeOrToken::Node(node) = node else { 50 50 return None; 51 51 };
+2 -2
lib/src/lints/unquoted_uri.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule, Suggestion, make}; 2 2 use rowan::ast::AstNode as _; 3 3 4 4 use macros::lint; ··· 46 46 struct UnquotedUri; 47 47 48 48 impl Rule for UnquotedUri { 49 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 49 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 50 50 let NodeOrToken::Token(token) = node else { 51 51 return None; 52 52 };
+2 -2
lib/src/lints/useless_has_attr.rs
··· 1 - use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 1 + use crate::{Metadata, Report, Rule, Suggestion, make}; 2 2 3 3 use macros::lint; 4 4 use rnix::{ ··· 33 33 struct UselessHasAttr; 34 34 35 35 impl Rule for UselessHasAttr { 36 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 36 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 37 37 let NodeOrToken::Node(node) = node else { 38 38 return None; 39 39 };
+2 -2
lib/src/lints/useless_parens.rs
··· 1 - use crate::{Diagnostic, Metadata, Report, Rule, Suggestion, session::SessionInfo}; 1 + use crate::{Diagnostic, Metadata, Report, Rule, Suggestion}; 2 2 3 3 use macros::lint; 4 4 use rnix::{ ··· 45 45 struct UselessParens; 46 46 47 47 impl Rule for UselessParens { 48 - fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 48 + fn validate(&self, node: &SyntaxElement) -> Option<Report> { 49 49 let NodeOrToken::Node(node) = node else { 50 50 return None; 51 51 };
-96
lib/src/session.rs
··· 1 - use std::{cmp::Ordering, str::FromStr}; 2 - 3 - #[derive(Copy, Clone, Debug, Eq, PartialEq)] 4 - pub struct Version { 5 - major: u16, 6 - minor: u16, 7 - patch: Option<u16>, 8 - } 9 - 10 - impl Ord for Version { 11 - fn cmp(&self, other: &Self) -> Ordering { 12 - let score = |v: &Version| v.major * 100 + v.minor * 10 + v.patch.unwrap_or(0); 13 - score(self).cmp(&score(other)) 14 - } 15 - } 16 - 17 - impl PartialOrd for Version { 18 - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 19 - Some(self.cmp(other)) 20 - } 21 - } 22 - 23 - fn parse_number(s: &str) -> Option<u16> { 24 - s.chars() 25 - .take_while(char::is_ascii_digit) 26 - .collect::<String>() 27 - .parse::<u16>() 28 - .ok() 29 - } 30 - 31 - fn parse_version(s: &str) -> Option<Version> { 32 - let mut parts = s.split('.'); 33 - let major = parse_number(parts.next()?)?; 34 - let minor = parse_number(parts.next()?)?; 35 - let patch = parts.next().and_then(parse_number); 36 - Some(Version { 37 - major, 38 - minor, 39 - patch, 40 - }) 41 - } 42 - 43 - impl FromStr for Version { 44 - type Err = (); 45 - fn from_str(s: &str) -> Result<Self, Self::Err> { 46 - parse_version(s).ok_or(()) 47 - } 48 - } 49 - 50 - #[non_exhaustive] 51 - pub struct SessionInfo { 52 - nix_version: Version, 53 - } 54 - 55 - impl SessionInfo { 56 - #[must_use] 57 - pub fn from_version(nix_version: Version) -> Self { 58 - Self { nix_version } 59 - } 60 - 61 - #[must_use] 62 - pub fn version(&self) -> &Version { 63 - &self.nix_version 64 - } 65 - } 66 - 67 - #[cfg(test)] 68 - mod tests { 69 - use super::*; 70 - 71 - #[test] 72 - fn parse_trivial() { 73 - let v = "1.6.1".parse::<Version>().ok(); 74 - assert!(v.is_some()); 75 - } 76 - 77 - #[test] 78 - fn parse() { 79 - let v = "2.4pre20211006_53e4794".parse::<Version>().ok(); 80 - assert!(v.is_some()); 81 - } 82 - 83 - #[test] 84 - fn compare_trivial() { 85 - let v1 = "1.6.1".parse::<Version>().ok(); 86 - let v2 = "1.7.2".parse::<Version>().ok(); 87 - assert!(v2 > v1); 88 - } 89 - 90 - #[test] 91 - fn compare() { 92 - let v1 = "1.7".parse::<Version>().ok(); 93 - let v2 = "2.4pre20211006_53e4794".parse::<Version>().ok(); 94 - assert!(v2 >= v1); 95 - } 96 - }