Lints and suggestions for the Nix programming language
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #123 from molybdenumsoftware/clippy-pedantic

clippy pedantic

authored by

Shahar "Dawn" Or and committed by
GitHub
0c7343c2 abb787cb

+127 -112
+6
Cargo.toml
··· 7 7 "vfs", 8 8 ] 9 9 10 + [workspace.lints.clippy] 11 + pedantic = { level = "deny", priority = -1 } 12 + 13 + missing_errors_doc = "allow" 14 + missing_panics_doc = "allow" 15 + module_name_repetitions = "allow"
+3
bin/Cargo.toml
··· 41 41 42 42 [features] 43 43 json = [ "lib/json-out", "serde_json" ] 44 + 45 + [lints] 46 + workspace = true
+12 -21
bin/src/config.rs
··· 79 79 let all_ignores = [self.ignore.as_slice(), extra_ignores].concat(); 80 80 let ignore = dirs::build_ignore_set(&all_ignores, &self.target, self.unrestricted)?; 81 81 let files = dirs::walk_nix_files(ignore, &self.target)?; 82 - vfs(files.collect::<Vec<_>>()) 82 + Ok(vfs(&files.collect::<Vec<_>>())) 83 83 } 84 84 } 85 85 } ··· 132 132 let all_ignores = [self.ignore.as_slice(), extra_ignores].concat(); 133 133 let ignore = dirs::build_ignore_set(&all_ignores, &self.target, self.unrestricted)?; 134 134 let files = dirs::walk_nix_files(ignore, &self.target)?; 135 - vfs(files.collect::<Vec<_>>()) 135 + Ok(vfs(&files.collect::<Vec<_>>())) 136 136 } 137 137 } 138 138 139 139 // i need this ugly helper because clap's data model 140 140 // does not reflect what i have in mind 141 + #[must_use] 141 142 pub fn out(&self) -> FixOut { 142 143 if self.diff_only { 143 144 FixOut::Diff ··· 189 190 Ok(ReadOnlyVfs::singleton("<stdin>", src.as_bytes())) 190 191 } 191 192 } 193 + #[must_use] 192 194 pub fn out(&self) -> FixOut { 193 195 if self.diff_only { 194 196 FixOut::Diff ··· 253 255 } 254 256 } 255 257 256 - #[derive(Serialize, Deserialize, Debug)] 258 + #[derive(Serialize, Deserialize, Debug, Default)] 257 259 pub struct ConfFile { 258 260 #[serde(default = "Vec::new")] 259 261 disabled: Vec<String>, ··· 264 266 pub ignore: Vec<String>, 265 267 } 266 268 267 - impl Default for ConfFile { 268 - fn default() -> Self { 269 - let disabled = Default::default(); 270 - let ignore = Default::default(); 271 - let nix_version = Default::default(); 272 - Self { 273 - disabled, 274 - nix_version, 275 - ignore, 276 - } 277 - } 278 - } 279 - 280 269 impl ConfFile { 281 270 pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, ConfigErr> { 282 271 let path = path.as_ref(); ··· 297 286 } 298 287 Ok(Self::default()) 299 288 } 289 + #[must_use] 300 290 pub fn dump(&self) -> String { 301 291 let ideal_config = { 302 292 let disabled = vec![]; ··· 310 300 }; 311 301 toml::ser::to_string_pretty(&ideal_config).unwrap() 312 302 } 303 + #[must_use] 313 304 pub fn lints(&self) -> LintMap { 314 305 utils::lint_map_of( 315 306 (*LINTS) 316 307 .iter() 317 308 .filter(|l| !self.disabled.iter().any(|check| check == l.name())) 318 - .cloned() 309 + .copied() 319 310 .collect::<Vec<_>>() 320 311 .as_slice(), 321 312 ) ··· 323 314 pub fn version(&self) -> Result<Version, ConfigErr> { 324 315 if let Some(v) = &self.nix_version { 325 316 v.parse::<Version>() 326 - .map_err(|_| ConfigErr::ConfFileVersionParse(v.clone())) 317 + .map_err(|()| ConfigErr::ConfFileVersionParse(v.clone())) 327 318 } else if let Some(v) = utils::get_version_info().and_then(|o| o.parse::<Version>().ok()) { 328 319 Ok(v) 329 320 } else { ··· 363 354 } 364 355 } 365 356 366 - fn vfs(files: Vec<PathBuf>) -> Result<ReadOnlyVfs, ConfigErr> { 357 + fn vfs(files: &[PathBuf]) -> vfs::ReadOnlyVfs { 367 358 let mut vfs = ReadOnlyVfs::default(); 368 - for file in files.iter() { 359 + for file in files { 369 360 if let Ok(data) = fs::read_to_string(file) { 370 361 let _id = vfs.alloc_file_id(file); 371 362 vfs.set_file_contents(file, data.as_bytes()); ··· 373 364 println!("`{}` contains non-utf8 content", file.display()); 374 365 }; 375 366 } 376 - Ok(vfs) 367 + vfs 377 368 }
+2 -2
bin/src/explain.rs
··· 17 17 18 18 use crate::{config::Explain as ExplainConfig, err::StatixErr}; 19 19 20 - pub fn main(explain_config: ExplainConfig) -> Result<(), StatixErr> { 20 + pub fn main(explain_config: &ExplainConfig) -> Result<(), StatixErr> { 21 21 let explanation = super::explain(explain_config.target)?; 22 - println!("{}", explanation); 22 + println!("{explanation}"); 23 23 Ok(()) 24 24 } 25 25 }
+4 -4
bin/src/fix.rs
··· 50 50 use lib::session::SessionInfo; 51 51 use similar::TextDiff; 52 52 53 - pub fn all(fix_config: FixConfig) -> Result<(), StatixErr> { 53 + pub fn all(fix_config: &FixConfig) -> Result<(), StatixErr> { 54 54 let conf_file = ConfFile::discover(&fix_config.conf_path)?; 55 55 let vfs = fix_config.vfs(conf_file.ignore.as_slice())?; 56 56 ··· 83 83 let src = fix_result 84 84 .map(|r| r.src) 85 85 .unwrap_or(Cow::Borrowed(entry.contents)); 86 - println!("{}", &src) 86 + println!("{}", &src); 87 87 } 88 88 (FixOut::Write, Some(fix_result)) => { 89 89 let path = entry.file_path; ··· 95 95 Ok(()) 96 96 } 97 97 98 - pub fn single(single_config: SingleConfig) -> Result<(), StatixErr> { 98 + pub fn single(single_config: &SingleConfig) -> Result<(), StatixErr> { 99 99 let vfs = single_config.vfs()?; 100 100 let entry = vfs.iter().next().unwrap(); 101 101 let path = entry.file_path.display().to_string(); ··· 131 131 let src = single_result 132 132 .map(|r| r.src) 133 133 .unwrap_or(Cow::Borrowed(original_src)); 134 - println!("{}", &src) 134 + println!("{}", &src); 135 135 } 136 136 (FixOut::Write, Ok(single_result)) => { 137 137 let path = entry.file_path;
+2 -2
bin/src/fix/all.rs
··· 26 26 .filter(|report| report.total_suggestion_range().is_some()) 27 27 .collect::<Vec<_>>() 28 28 }), 29 - _ => None, 29 + WalkEvent::Leave(_) => None, 30 30 }) 31 31 .flatten() 32 32 .collect()) ··· 46 46 .fold(VecDeque::new(), |mut deque: VecDeque<Report>, new_elem| { 47 47 let front = deque.front(); 48 48 let new_range = new_elem.range(); 49 - if let Some(front_range) = front.map(|f| f.range()) { 49 + if let Some(front_range) = front.map(lib::Report::range) { 50 50 if new_range.start() > front_range.end() { 51 51 deque.push_front(new_elem); 52 52 }
+1 -1
bin/src/fix/single.rs
··· 42 42 .filter_map(|rule| rule.validate(&child, sess)) 43 43 .find(|report| report.total_suggestion_range().is_some()) 44 44 }), 45 - _ => None, 45 + WalkEvent::Leave(_) => None, 46 46 }) 47 47 .flatten() 48 48 .find(|report| report.total_diagnostic_range().unwrap().contains(offset))
+11 -6
bin/src/lint.rs
··· 10 10 pub reports: Vec<Report>, 11 11 } 12 12 13 - pub fn lint_with(vfs_entry: VfsEntry, lints: &LintMap, sess: &SessionInfo) -> LintResult { 13 + #[must_use] 14 + pub fn lint_with(vfs_entry: &VfsEntry, lints: &LintMap, sess: &SessionInfo) -> LintResult { 14 15 let file_id = vfs_entry.file_id; 15 16 let source = vfs_entry.contents; 16 17 let parsed = rnix::parse(source); 17 18 18 - let error_reports = parsed.errors().into_iter().map(Report::from_parse_err); 19 + let error_reports = parsed 20 + .errors() 21 + .into_iter() 22 + .map(|err: rnix::parser::ParseError| Report::from_parse_err(&err)); 19 23 let reports = parsed 20 24 .node() 21 25 .preorder_with_tokens() ··· 26 30 .filter_map(|rule| rule.validate(&child, sess)) 27 31 .collect::<Vec<_>>() 28 32 }), 29 - _ => None, 33 + WalkEvent::Leave(_) => None, 30 34 }) 31 35 .flatten() 32 36 .chain(error_reports) ··· 35 39 LintResult { file_id, reports } 36 40 } 37 41 38 - pub fn lint(vfs_entry: VfsEntry, sess: &SessionInfo) -> LintResult { 42 + #[must_use] 43 + pub fn lint(vfs_entry: &VfsEntry, sess: &SessionInfo) -> LintResult { 39 44 lint_with(vfs_entry, &utils::lint_map(), sess) 40 45 } 41 46 ··· 52 57 use lib::session::SessionInfo; 53 58 use rayon::prelude::*; 54 59 55 - pub fn main(check_config: CheckConfig) -> Result<(), StatixErr> { 60 + pub fn main(check_config: &CheckConfig) -> Result<(), StatixErr> { 56 61 let conf_file = ConfFile::discover(&check_config.conf_path)?; 57 62 let lints = conf_file.lints(); 58 63 let version = conf_file.version()?; ··· 61 66 let vfs = check_config.vfs(conf_file.ignore.as_slice())?; 62 67 63 68 let mut stdout = io::stdout(); 64 - let lint = |vfs_entry| lint_with(vfs_entry, &lints, &session); 69 + let lint = |vfs_entry| lint_with(&vfs_entry, &lints, &session); 65 70 let results = vfs 66 71 .par_iter() 67 72 .map(lint)
+5 -5
bin/src/main.rs
··· 10 10 fn _main() -> Result<(), StatixErr> { 11 11 let opts = Opts::parse(); 12 12 match opts.cmd { 13 - SubCommand::Check(config) => lint::main::main(config), 14 - SubCommand::Fix(config) => fix::main::all(config), 15 - SubCommand::Single(config) => fix::main::single(config), 16 - SubCommand::Explain(config) => explain::main::main(config), 13 + SubCommand::Check(config) => lint::main::main(&config), 14 + SubCommand::Fix(config) => fix::main::all(&config), 15 + SubCommand::Single(config) => fix::main::single(&config), 16 + SubCommand::Explain(config) => explain::main::main(&config), 17 17 SubCommand::Dump(_) => dump::main::main(), 18 18 SubCommand::List(_) => list::main::main(), 19 19 } ··· 21 21 22 22 fn main() { 23 23 if let Err(e) = _main() { 24 - eprintln!("{}", e); 24 + eprintln!("{e}"); 25 25 } 26 26 }
+5 -6
bin/src/traits.rs
··· 51 51 let path = vfs.file_path(file_id); 52 52 let range = |at: TextRange| at.start().into()..at.end().into(); 53 53 let src_id = path.to_str().unwrap_or("<unknown>"); 54 - for report in lint_result.reports.iter() { 54 + for report in &lint_result.reports { 55 55 let offset = report 56 56 .diagnostics 57 57 .iter() ··· 99 99 let file_id = lint_result.file_id; 100 100 let src = str::from_utf8(vfs.get(file_id)).unwrap(); 101 101 let path = vfs.file_path(file_id); 102 - for report in lint_result.reports.iter() { 103 - for diagnostic in report.diagnostics.iter() { 102 + for report in &lint_result.reports { 103 + for diagnostic in &report.diagnostics { 104 104 let line = line(diagnostic.at.start(), src); 105 105 let col = column(diagnostic.at.start(), src); 106 106 writeln!( ··· 240 240 241 241 fn column(at: TextSize, src: &str) -> usize { 242 242 let at = at.into(); 243 - src[..at].rfind('\n').map(|c| at - c).unwrap_or(at + 1) 243 + src[..at].rfind('\n').map_or_else(|| at + 1, |c| at - c) 244 244 } 245 245 246 246 // everything within backticks is colorized, backticks are removed ··· 255 255 part.to_string() 256 256 } 257 257 }) 258 - .collect::<Vec<_>>() 259 - .join("") 258 + .collect::<String>() 260 259 }
+1 -1
bin/src/utils.rs
··· 8 8 lints: &[&'static Box<dyn Lint>], 9 9 ) -> HashMap<SyntaxKind, Vec<&'static Box<dyn Lint>>> { 10 10 let mut map = HashMap::new(); 11 - for lint in lints.iter() { 11 + for lint in lints { 12 12 let lint = *lint; 13 13 let matches = lint.match_kind(); 14 14 for m in matches {
+1 -1
bin/tests/main.rs
··· 36 36 let session = $sess; 37 37 38 38 let mut buffer = Vec::new(); 39 - vfs.iter().map(|entry| lint::lint(entry, &session)).for_each(|r| { 39 + vfs.iter().map(|entry| lint::lint(&entry, &session)).for_each(|r| { 40 40 buffer.write(&r, &vfs, OutFormat::StdErr).unwrap(); 41 41 }); 42 42
+3
lib/Cargo.toml
··· 22 22 [features] 23 23 default = [] 24 24 json-out = [ "serde", "serde_json" ] 25 + 26 + [lints] 27 + workspace = true
+23 -22
lib/src/lib.rs
··· 16 16 Serialize, 17 17 }; 18 18 19 - #[derive(Debug)] 19 + #[derive(Debug, Default)] 20 20 #[cfg_attr(feature = "json-out", derive(Serialize))] 21 21 pub enum Severity { 22 + #[default] 22 23 Warn, 23 24 Error, 24 25 Hint, 25 26 } 26 27 27 - impl Default for Severity { 28 - fn default() -> Self { 29 - Self::Warn 30 - } 31 - } 32 - 33 28 /// Report generated by a lint 34 29 #[derive(Debug, Default)] 35 30 #[cfg_attr(feature = "json-out", derive(Serialize))] ··· 46 41 47 42 impl Report { 48 43 /// Construct a report. Do not invoke `Report::new` manually, see `lint` macro 44 + #[must_use] 49 45 pub fn new(note: &'static str, code: u32) -> Self { 50 46 Self { 51 47 note, ··· 54 50 } 55 51 } 56 52 /// Add a diagnostic to this report 53 + #[allow(clippy::return_self_not_must_use)] 57 54 pub fn diagnostic<S: AsRef<str>>(mut self, at: TextRange, message: S) -> Self { 58 55 self.diagnostics.push(Diagnostic::new(at, message)); 59 56 self 60 57 } 61 58 /// Add a diagnostic with a fix to this report 59 + #[allow(clippy::return_self_not_must_use)] 62 60 pub fn suggest<S: AsRef<str>>( 63 61 mut self, 64 62 at: TextRange, ··· 70 68 self 71 69 } 72 70 /// Set severity level 71 + #[allow(clippy::return_self_not_must_use, clippy::must_use_candidate)] 73 72 pub fn severity(mut self, severity: Severity) -> Self { 74 73 self.severity = severity; 75 74 self ··· 78 77 pub fn total_suggestion_range(&self) -> Option<TextRange> { 79 78 self.diagnostics 80 79 .iter() 81 - .flat_map(|d| Some(d.suggestion.as_ref()?.at)) 82 - .reduce(|acc, next| acc.cover(next)) 80 + .filter_map(|d| Some(d.suggestion.as_ref()?.at)) 81 + .reduce(rnix::TextRange::cover) 83 82 } 84 83 /// A range that encompasses all the diagnostics provided in this report 85 84 pub fn total_diagnostic_range(&self) -> Option<TextRange> { 86 85 self.diagnostics 87 86 .iter() 88 - .flat_map(|d| Some(d.at)) 89 - .reduce(|acc, next| acc.cover(next)) 87 + .map(|d| d.at) 88 + .reduce(rnix::TextRange::cover) 90 89 } 91 90 /// Unsafe but handy replacement for above 91 + #[must_use] 92 92 pub fn range(&self) -> TextRange { 93 93 self.total_suggestion_range().unwrap() 94 94 } 95 95 /// Apply all diagnostics. Assumption: diagnostics do not overlap 96 96 pub fn apply(&self, src: &mut String) { 97 - for d in self.diagnostics.iter() { 97 + for d in &self.diagnostics { 98 98 d.apply(src); 99 99 } 100 100 } 101 101 /// Create a report out of a parse error 102 - pub fn from_parse_err(err: ParseError) -> Self { 102 + #[must_use] 103 + pub fn from_parse_err(err: &ParseError) -> Self { 103 104 let at = match err { 104 - ParseError::Unexpected(at) => at, 105 - ParseError::UnexpectedExtra(at) => at, 106 - ParseError::UnexpectedWanted(_, at, _) => at, 107 - ParseError::UnexpectedDoubleBind(at) => at, 105 + ParseError::Unexpected(at) 106 + | ParseError::UnexpectedExtra(at) 107 + | ParseError::UnexpectedWanted(_, at, _) 108 + | ParseError::UnexpectedDoubleBind(at) 109 + | ParseError::DuplicatedArgs(at, _) => at, 108 110 ParseError::UnexpectedEOF | ParseError::UnexpectedEOFWanted(_) => { 109 - TextRange::empty(0u32.into()) 111 + &TextRange::empty(0u32.into()) 110 112 } 111 - ParseError::DuplicatedArgs(at, _) => at, 112 113 _ => panic!("report a bug, pepper forgot to handle a parse error"), 113 114 }; 114 115 let mut message = err.to_string(); ··· 118 119 .unwrap() 119 120 .make_ascii_uppercase(); 120 121 Self::new("Syntax error", 0) 121 - .diagnostic(at, message) 122 + .diagnostic(*at, message) 122 123 .severity(Severity::Error) 123 124 } 124 125 } ··· 198 199 pub fn apply(&self, src: &mut String) { 199 200 let start = usize::from(self.at.start()); 200 201 let end = usize::from(self.at.end()); 201 - src.replace_range(start..end, &self.fix.to_string()) 202 + src.replace_range(start..end, &self.fix.to_string()); 202 203 } 203 204 } 204 205 ··· 257 258 pub trait Lint: Metadata + Explain + Rule + Send + Sync {} 258 259 259 260 /// Helper utility to take lints from modules and insert them into a map for efficient 260 - /// access. Mapping is from a SyntaxKind to a list of lints that apply on that Kind. 261 + /// access. Mapping is from a `SyntaxKind` to a list of lints that apply on that Kind. 261 262 /// 262 263 /// See `lints.rs` for usage. 263 264 #[macro_export]
+1 -3
lib/src/lints/bool_comparison.rs
··· 87 87 } 88 88 }; 89 89 let message = format!( 90 - "Comparing `{}` with boolean literal `{}`", 91 - non_bool_side, 92 - bool_side 90 + "Comparing `{non_bool_side}` with boolean literal `{bool_side}`" 93 91 ); 94 92 Some(self.report().suggest(at, message, Suggestion::new(at, replacement))) 95 93 } else {
+1 -1
lib/src/lints/deprecated_to_path.rs
··· 49 49 if ALLOWED_PATHS.iter().any(|&p| p == lambda_path.as_str()); 50 50 then { 51 51 let at = node.text_range(); 52 - let message = format!("`{}` is deprecated, see `:doc builtins.toPath` within the REPL for more", lambda_path); 52 + let message = format!("`{lambda_path}` is deprecated, see `:doc builtins.toPath` within the REPL for more"); 53 53 Some(self.report().diagnostic(at, message)) 54 54 } else { 55 55 None
+1 -3
lib/src/lints/empty_list_concat.rs
··· 58 58 } 59 59 60 60 fn is_empty_array(node: &SyntaxNode) -> bool { 61 - List::cast(node.clone()) 62 - .map(|list| list.items().count() == 0) 63 - .unwrap_or_default() 61 + List::cast(node.clone()).is_some_and(|list| list.items().count() == 0) 64 62 }
+1 -1
lib/src/lints/manual_inherit_from.rs
··· 61 61 let at = node.text_range(); 62 62 let replacement = { 63 63 let set = value.set()?; 64 - make::inherit_from_stmt(set, &[key]).node().clone() 64 + make::inherit_from_stmt(&set, &[key]).node().clone() 65 65 }; 66 66 let message = "This assignment is better written with `inherit`"; 67 67 Some(self.report().suggest(at, message, Suggestion::new(at, replacement)))
+1 -1
lib/src/lints/repeated_keys.rs
··· 94 94 let mut message = match remaining_occurrences { 95 95 0 => "... and here.".to_string(), 96 96 1 => "... and here (`1` occurrence omitted).".to_string(), 97 - n => format!("... and here (`{}` occurrences omitted).", n), 97 + n => format!("... and here (`{n}` occurrences omitted)."), 98 98 }; 99 99 message.push_str(&format!(" Try `{} = {{ {}=...; {}=...; {}=...; }}` instead.", first_component_ident.as_str(), first_subkey, second_subkey, third_subkey)); 100 100 message
+1 -2
lib/src/lints/useless_has_attr.rs
··· 69 69 }; 70 70 let replacement = make::or_default(&set, &attr_path, &default_with_parens).node().clone(); 71 71 let message = format!( 72 - "Consider using `{}` instead of this `if` expression", 73 - replacement 72 + "Consider using `{replacement}` instead of this `if` expression" 74 73 ); 75 74 Some( 76 75 self.report()
+11 -11
lib/src/make.rs
··· 21 21 } 22 22 23 23 pub fn parenthesize(node: &SyntaxNode) -> types::Paren { 24 - ast_from_text(&format!("({})", node)) 24 + ast_from_text(&format!("({node})")) 25 25 } 26 26 27 27 pub fn quote(node: &SyntaxNode) -> types::Str { 28 - ast_from_text(&format!("\"{}\"", node)) 28 + ast_from_text(&format!("\"{node}\"")) 29 29 } 30 30 31 31 pub fn unary_not(node: &SyntaxNode) -> types::UnaryOp { 32 - ast_from_text(&format!("!{}", node)) 32 + ast_from_text(&format!("!{node}")) 33 33 } 34 34 35 35 pub fn inherit_stmt<'a>(nodes: impl IntoIterator<Item = &'a types::Ident>) -> types::Inherit { ··· 38 38 .map(|i| i.as_str().to_owned()) 39 39 .collect::<Vec<_>>() 40 40 .join(" "); 41 - ast_from_text(&format!("{{ inherit {}; }}", inherited_idents)) 41 + ast_from_text(&format!("{{ inherit {inherited_idents}; }}")) 42 42 } 43 43 44 44 pub fn inherit_from_stmt<'a>( 45 - from: SyntaxNode, 45 + from: &SyntaxNode, 46 46 nodes: impl IntoIterator<Item = &'a types::Ident>, 47 47 ) -> types::Inherit { 48 48 let inherited_idents = nodes ··· 50 50 .map(|i| i.as_str().to_owned()) 51 51 .collect::<Vec<_>>() 52 52 .join(" "); 53 - ast_from_text(&format!("{{ inherit ({}) {}; }}", from, inherited_idents)) 53 + ast_from_text(&format!("{{ inherit ({from}) {inherited_idents}; }}")) 54 54 } 55 55 56 56 pub fn attrset( ··· 61 61 let mut buffer = String::new(); 62 62 63 63 writeln!(buffer, "{}{{", if recursive { "rec " } else { "" }).unwrap(); 64 - for inherit in inherits.into_iter() { 64 + for inherit in inherits { 65 65 writeln!(buffer, " {}", inherit.node().text()).unwrap(); 66 66 } 67 - for entry in entries.into_iter() { 67 + for entry in entries { 68 68 writeln!(buffer, " {}", entry.node().text()).unwrap(); 69 69 } 70 70 write!(buffer, "}}").unwrap(); ··· 73 73 } 74 74 75 75 pub fn select(set: &SyntaxNode, index: &SyntaxNode) -> types::Select { 76 - ast_from_text(&format!("{}.{}", set, index)) 76 + ast_from_text(&format!("{set}.{index}")) 77 77 } 78 78 79 79 pub fn ident(text: &str) -> types::Ident { ··· 86 86 87 87 // TODO: make `op` strongly typed here 88 88 pub fn binary(lhs: &SyntaxNode, op: &str, rhs: &SyntaxNode) -> types::BinOp { 89 - ast_from_text(&format!("{} {} {}", lhs, op, rhs)) 89 + ast_from_text(&format!("{lhs} {op} {rhs}")) 90 90 } 91 91 92 92 pub fn or_default(set: &SyntaxNode, index: &SyntaxNode, default: &SyntaxNode) -> types::OrDefault { 93 - ast_from_text(&format!("{}.{} or {}", set, index, default)) 93 + ast_from_text(&format!("{set}.{index} or {default}")) 94 94 }
+5 -3
lib/src/session.rs
··· 22 22 23 23 fn parse_number(s: &str) -> Option<u16> { 24 24 s.chars() 25 - .take_while(|c| c.is_ascii_digit()) 25 + .take_while(char::is_ascii_digit) 26 26 .collect::<String>() 27 27 .parse::<u16>() 28 28 .ok() ··· 53 53 } 54 54 55 55 impl SessionInfo { 56 + #[must_use] 56 57 pub fn from_version(nix_version: Version) -> Self { 57 58 Self { nix_version } 58 59 } 59 60 61 + #[must_use] 60 62 pub fn version(&self) -> &Version { 61 63 &self.nix_version 62 64 } ··· 69 71 #[test] 70 72 fn parse_trivial() { 71 73 let v = "1.6.1".parse::<Version>().ok(); 72 - assert!(v.is_some()) 74 + assert!(v.is_some()); 73 75 } 74 76 75 77 #[test] 76 78 fn parse() { 77 79 let v = "2.4pre20211006_53e4794".parse::<Version>().ok(); 78 - assert!(v.is_some()) 80 + assert!(v.is_some()); 79 81 } 80 82 81 83 #[test]
+5 -5
lib/src/utils.rs
··· 1 1 use rnix::{SyntaxKind, SyntaxNode, TextRange}; 2 2 3 3 pub fn with_preceeding_whitespace(node: &SyntaxNode) -> TextRange { 4 - let start = node 5 - .prev_sibling_or_token() 6 - .map(|t| { 4 + let start = node.prev_sibling_or_token().map_or_else( 5 + || node.text_range().start(), 6 + |t| { 7 7 if t.kind() == SyntaxKind::TOKEN_WHITESPACE { 8 8 t.text_range().start() 9 9 } else { 10 10 t.text_range().end() 11 11 } 12 - }) 13 - .unwrap_or(node.text_range().start()); 12 + }, 13 + ); 14 14 let end = node.text_range().end(); 15 15 TextRange::new(start, end) 16 16 }
+3
macros/Cargo.toml
··· 16 16 17 17 [lib] 18 18 proc-macro = true 19 + 20 + [lints] 21 + workspace = true
+3 -3
macros/src/lib.rs
··· 11 11 fn generate_self_impl(struct_name: &Ident) -> TokenStream2 { 12 12 quote! { 13 13 impl #struct_name { 14 - pub fn new() -> Box<Self> { 15 - Box::new(Self) 14 + pub fn new() -> Self { 15 + Self 16 16 } 17 17 } 18 18 } ··· 32 32 #struct_item 33 33 34 34 ::lazy_static::lazy_static! { 35 - pub static ref LINT: Box<dyn crate::Lint> = #struct_name::new(); 35 + pub static ref LINT: Box<dyn crate::Lint> = Box::new(#struct_name::new()); 36 36 } 37 37 38 38 #self_impl
+2 -2
macros/src/metadata.rs
··· 146 146 } 147 147 } 148 148 149 - fn generate_report_fn(&self) -> TokenStream2 { 149 + fn generate_report_fn() -> TokenStream2 { 150 150 quote! { 151 151 fn report(&self) -> crate::Report { 152 152 crate::Report::new(self.note(), self.code()) ··· 162 162 let code_fn = not_raw.generate_code_fn(); 163 163 let match_with_fn = not_raw.generate_match_with_fn(); 164 164 let match_kind = not_raw.generate_match_kind_fn(); 165 - let report_fn = not_raw.generate_report_fn(); 165 + let report_fn = LintMeta::generate_report_fn(); 166 166 167 167 quote! { 168 168 impl crate::Metadata for #struct_name {
+3
vfs/Cargo.toml
··· 7 7 [dependencies] 8 8 indexmap = "1.6.2" 9 9 rayon = "1.5.1" 10 + 11 + [lints] 12 + workspace = true
+10 -6
vfs/src/lib.rs
··· 8 8 use rayon::prelude::*; 9 9 10 10 #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)] 11 - pub struct FileId(pub u32); 11 + pub struct FileId(pub usize); 12 12 13 13 #[derive(Debug, Default)] 14 14 pub struct Interner { ··· 17 17 18 18 impl Interner { 19 19 pub fn get<P: AsRef<Path>>(&self, path: P) -> Option<FileId> { 20 - self.map 21 - .get_index_of(path.as_ref()) 22 - .map(|i| FileId(i as u32)) 20 + self.map.get_index_of(path.as_ref()).map(FileId) 23 21 } 24 22 pub fn intern(&mut self, path: PathBuf) -> FileId { 25 23 let (id, _) = self.map.insert_full(path); 26 - FileId(id as u32) 24 + FileId(id) 27 25 } 28 26 pub fn lookup(&self, file: FileId) -> Option<&Path> { 29 - self.map.get_index(file.0 as usize).map(|p| p.as_path()) 27 + self.map.get_index(file.0).map(PathBuf::as_path) 30 28 } 31 29 } 32 30 ··· 45 43 pub fn alloc_file_id<P: AsRef<Path>>(&mut self, path: P) -> FileId { 46 44 self.interner.intern(path.as_ref().to_owned()) 47 45 } 46 + #[must_use] 48 47 pub fn len(&self) -> usize { 49 48 self.data.len() 50 49 } 50 + #[must_use] 51 51 pub fn is_empty(&self) -> bool { 52 52 self.data.is_empty() 53 53 } 54 + #[must_use] 54 55 pub fn file_path(&self, file_id: FileId) -> &Path { 55 56 self.interner.lookup(file_id).unwrap() 56 57 } 58 + #[must_use] 57 59 pub fn get(&self, file_id: FileId) -> &Vec<u8> { 58 60 self.data.get(&file_id).unwrap() 59 61 } 62 + #[must_use] 60 63 pub fn get_str(&self, file_id: FileId) -> &str { 61 64 std::str::from_utf8(self.get(file_id)).unwrap() 62 65 } ··· 74 77 contents: self.get_str(*file_id), 75 78 }) 76 79 } 80 + #[must_use] 77 81 pub fn par_iter(&self) -> impl ParallelIterator<Item = VfsEntry> { 78 82 self.data.par_iter().map(move |(file_id, _)| VfsEntry { 79 83 file_id: *file_id,