From b30f015e5329f95c51b52bd5ded5625f2334ebda Mon Sep 17 00:00:00 2001 From: damc Date: Mon, 19 Jun 2023 18:41:30 +0200 Subject: [PATCH 1/8] api Made it so plugins return a Vec of rules # Conflicts: # src/linter.rs --- src/linter.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/linter.rs b/src/linter.rs index ced40cae..ad2a981b 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -92,12 +92,15 @@ impl Linter { self.plugins.push(lib); let lib = self.plugins.last().unwrap(); - let get_plugin: Result *mut dyn SyntaxRule>, _> = + let get_plugin: Result Vec<*mut dyn SyntaxRule>>, _> = unsafe { lib.get(b"get_plugin") }; if let Ok(get_plugin) = get_plugin { - let plugin = unsafe { Box::from_raw(get_plugin()) }; - self.ctl_enabled.insert(plugin.name(), true); - self.syntaxrules.push(plugin); + let vec = get_plugin(); + for plug in vec { + let plugin = unsafe { Box::from_raw(plug) }; + self.ctl_enabled.insert(plugin.name(), true); + self.syntaxrules.push(plugin); + } } } } From 099c5726504da8b1466ce6eef3d57b98db30cc90 Mon Sep 17 00:00:00 2001 From: damc Date: Mon, 19 Jun 2023 18:56:50 +0200 Subject: [PATCH 2/8] api Expect a vector of enum values, rather than vector of SyntaxRules. --- src/linter.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/linter.rs b/src/linter.rs index ad2a981b..c1d57567 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -33,6 +33,12 @@ pub enum SyntaxRuleResult { FailLocate(Locate), } +#[derive(Clone, Copy)] +pub enum Rule { + Text(*mut dyn TextRule), + Syntax(*mut dyn SyntaxRule), +} + pub trait SyntaxRule: Sync + Send { fn check( &mut self, @@ -92,14 +98,22 @@ impl Linter { self.plugins.push(lib); let lib = self.plugins.last().unwrap(); - let get_plugin: Result Vec<*mut dyn SyntaxRule>>, _> = + let get_plugin: Result Vec>, _> = unsafe { lib.get(b"get_plugin") }; if let Ok(get_plugin) = get_plugin { - let vec = get_plugin(); - for plug in vec { - let plugin = unsafe { Box::from_raw(plug) }; - self.ctl_enabled.insert(plugin.name(), true); - self.syntaxrules.push(plugin); + let plugins = get_plugin(); + for plugin in plugins { + match plugin { + Rule::Text(p) => { + let plugin = unsafe { Box::from_raw(p) }; + self.textrules.push(plugin); + }, + Rule::Syntax(p) => { + let plugin = unsafe { Box::from_raw(p) }; + self.ctl_enabled.insert(plugin.name(), true); + self.syntaxrules.push(plugin); + }, + } } } } From f4d2fee3a49078d428c534afbf10850a2ae0b8a2 Mon Sep 17 00:00:00 2001 From: damc Date: Mon, 19 Jun 2023 19:54:53 +0200 Subject: [PATCH 3/8] api When plugins are given, don't enable all rules. --- src/main.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6ea6ffd7..6797dde4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -171,14 +171,18 @@ pub fn run_opt(printer: &mut Printer, opt: &Opt) -> Result { _ => true, }; - if !opt.silent && !do_dump_filelist && !opt.preprocess_only { - let msg = format!( - "Config file '{}' is not found. Enable all rules", - opt.config.to_string_lossy() - ); - printer.print_warning(&msg)?; + if !opt.plugins.is_empty() { + Config::new() + } else { + if !opt.silent && !do_dump_filelist && !opt.preprocess_only { + let msg = format!( + "Config file '{}' is not found. Enable all rules", + opt.config.to_string_lossy() + ); + printer.print_warning(&msg)?; + } + Config::new().enable_all() } - Config::new().enable_all() }; run_opt_config(printer, opt, config) From 9463c6d50861c3622c75da758f0bfc099ee4d013 Mon Sep 17 00:00:00 2001 From: damc Date: Tue, 20 Jun 2023 11:35:56 +0200 Subject: [PATCH 4/8] api Provide helper macro `pluginrule` for tidier plugin code. --- src/linter.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/linter.rs b/src/linter.rs index c1d57567..cf4cd92d 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -33,12 +33,6 @@ pub enum SyntaxRuleResult { FailLocate(Locate), } -#[derive(Clone, Copy)] -pub enum Rule { - Text(*mut dyn TextRule), - Syntax(*mut dyn SyntaxRule), -} - pub trait SyntaxRule: Sync + Send { fn check( &mut self, @@ -256,6 +250,27 @@ impl Linter { } } +// Rule enum is for use by plugins. +#[derive(Clone, Copy)] +pub enum Rule { + Text(*mut dyn TextRule), + Syntax(*mut dyn SyntaxRule), +} + +// Macro for use within plugins. +// Example usage within a plugin's `get_plugin` function: +// let mut ret: Vec = Vec::new(); +// ret.push(pluginrule!(Syntax, SamplePlugin)); +#[macro_export] +macro_rules! pluginrule { + ( $e:ident,$t:ty ) => { + { + let boxed = Box::<$t>::default(); + Rule::$e(Box::into_raw(boxed)) + } + } +} + // Utility function used by syntaxrules `re_(required|forbidden)_*`. pub fn check_regex( required_not_forbidden: bool, From 224bdb6e755aa0c1ddd248fd2b976e1930ebd99a Mon Sep 17 00:00:00 2001 From: damc Date: Tue, 20 Jun 2023 20:24:44 +0200 Subject: [PATCH 5/8] api Report potential errors loading plugins. --- src/linter.rs | 43 ++++++++++++++++++++++--------------------- src/main.rs | 2 +- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/linter.rs b/src/linter.rs index cf4cd92d..0f4b38ab 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -86,31 +86,32 @@ impl Linter { } } - pub fn load(&mut self, path: &Path) { - let lib = unsafe { Library::new(path) }; - if let Ok(lib) = lib { - self.plugins.push(lib); - let lib = self.plugins.last().unwrap(); + pub fn load(&mut self, path: &Path) -> Result<(), libloading::Error> { + let lib = unsafe { Library::new(path) }?; - let get_plugin: Result Vec>, _> = - unsafe { lib.get(b"get_plugin") }; - if let Ok(get_plugin) = get_plugin { - let plugins = get_plugin(); - for plugin in plugins { - match plugin { - Rule::Text(p) => { - let plugin = unsafe { Box::from_raw(p) }; - self.textrules.push(plugin); - }, - Rule::Syntax(p) => { - let plugin = unsafe { Box::from_raw(p) }; - self.ctl_enabled.insert(plugin.name(), true); - self.syntaxrules.push(plugin); - }, - } + self.plugins.push(lib); + let lib = self.plugins.last().unwrap(); + + let get_plugin: Result Vec>, _> = + unsafe { lib.get(b"get_plugin") }; + if let Ok(get_plugin) = get_plugin { + let plugins = get_plugin(); + for plugin in plugins { + match plugin { + Rule::Text(p) => { + let plugin = unsafe { Box::from_raw(p) }; + self.textrules.push(plugin); + }, + Rule::Syntax(p) => { + let plugin = unsafe { Box::from_raw(p) }; + self.ctl_enabled.insert(plugin.name(), true); + self.syntaxrules.push(plugin); + }, } } } + + Ok(()) } pub fn textrules_check(&mut self, line: &str, path: &Path, beg: &usize) -> Vec { diff --git a/src/main.rs b/src/main.rs index 6797dde4..72c13ba6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -202,7 +202,7 @@ pub fn run_opt_config(printer: &mut Printer, opt: &Opt, config: Config) -> Resul let mut linter = Linter::new(config); for plugin in &opt.plugins { - linter.load(&plugin); + linter.load(&plugin)?; } let mut defines = HashMap::new(); From 3a2a5ab2ba643f1b147702d9eac458e7f7998242 Mon Sep 17 00:00:00 2001 From: damc Date: Tue, 20 Jun 2023 20:43:22 +0200 Subject: [PATCH 6/8] api Default trait implementation to cleanup plugin macro usage. Thanks @skjdbg (https://github.com/dalance/svlint/issues/253#issuecomment-1598737867) --- src/linter.rs | 64 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/src/linter.rs b/src/linter.rs index 0f4b38ab..a243aadc 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -5,6 +5,33 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; use sv_parser::{unwrap_locate, Locate, NodeEvent, RefNode, SyntaxTree}; +// Rule enum is for use by plugins. +#[derive(Clone, Copy)] +pub enum Rule { + Text(*mut dyn TextRule), + Syntax(*mut dyn SyntaxRule), +} + +// Macro for use within plugins. +// Example usage in a plugin's `get_plugin` function: +// pluginrules!( +// SamplePlugin, +// AnotherPlugin, +// ) +#[macro_export] +macro_rules! pluginrules { + ( $( $x:ty ),* $(,)? ) => { + { + let mut vec: Vec = Vec::new(); + $( + let rule = <$x>::default(); + vec.push(rule.into_rule()); + )* + vec + } + }; +} + #[derive(Clone, Copy)] pub enum TextRuleResult { Pass, @@ -23,6 +50,14 @@ pub trait TextRule: Sync + Send { fn name(&self) -> String; fn hint(&self, config: &ConfigOption) -> String; fn reason(&self) -> String; + + fn into_rule(self) -> Rule + where + Self: Sized + 'static, + { + let temp = Box::new(self); + Rule::Text(Box::into_raw(temp)) + } } #[derive(Clone, Copy)] @@ -43,6 +78,14 @@ pub trait SyntaxRule: Sync + Send { fn name(&self) -> String; fn hint(&self, config: &ConfigOption) -> String; fn reason(&self) -> String; + + fn into_rule(self) -> Rule + where + Self: Sized + 'static, + { + let temp = Box::new(self); + Rule::Syntax(Box::into_raw(temp)) + } } pub struct Linter { @@ -251,27 +294,6 @@ impl Linter { } } -// Rule enum is for use by plugins. -#[derive(Clone, Copy)] -pub enum Rule { - Text(*mut dyn TextRule), - Syntax(*mut dyn SyntaxRule), -} - -// Macro for use within plugins. -// Example usage within a plugin's `get_plugin` function: -// let mut ret: Vec = Vec::new(); -// ret.push(pluginrule!(Syntax, SamplePlugin)); -#[macro_export] -macro_rules! pluginrule { - ( $e:ident,$t:ty ) => { - { - let boxed = Box::<$t>::default(); - Rule::$e(Box::into_raw(boxed)) - } - } -} - // Utility function used by syntaxrules `re_(required|forbidden)_*`. pub fn check_regex( required_not_forbidden: bool, From 44e6f4d37a279cd42d186b010c9a9d23c2906c25 Mon Sep 17 00:00:00 2001 From: damc Date: Wed, 21 Jun 2023 11:38:50 +0200 Subject: [PATCH 7/8] api Whitespace-only --- src/linter.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/linter.rs b/src/linter.rs index a243aadc..c4f3d377 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -51,13 +51,13 @@ pub trait TextRule: Sync + Send { fn hint(&self, config: &ConfigOption) -> String; fn reason(&self) -> String; - fn into_rule(self) -> Rule - where - Self: Sized + 'static, - { - let temp = Box::new(self); - Rule::Text(Box::into_raw(temp)) - } + fn into_rule(self) -> Rule + where + Self: Sized + 'static, + { + let temp = Box::new(self); + Rule::Text(Box::into_raw(temp)) + } } #[derive(Clone, Copy)] @@ -79,13 +79,13 @@ pub trait SyntaxRule: Sync + Send { fn hint(&self, config: &ConfigOption) -> String; fn reason(&self) -> String; - fn into_rule(self) -> Rule - where - Self: Sized + 'static, - { - let temp = Box::new(self); - Rule::Syntax(Box::into_raw(temp)) - } + fn into_rule(self) -> Rule + where + Self: Sized + 'static, + { + let temp = Box::new(self); + Rule::Syntax(Box::into_raw(temp)) + } } pub struct Linter { From 420845b714b05f760e8e4530698c01d4aba59e5a Mon Sep 17 00:00:00 2001 From: damc Date: Thu, 22 Jun 2023 18:43:16 +0200 Subject: [PATCH 8/8] api Fix #256. --- src/main.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index 72c13ba6..9e1c9c38 100644 --- a/src/main.rs +++ b/src/main.rs @@ -271,17 +271,16 @@ pub fn run_opt_config(printer: &mut Printer, opt: &Opt, config: Config) -> Resul let text: String = read_to_string(&path)?; let mut beg: usize = 0; - for line in text.lines() { - for failed in linter.textrules_check(&line, &path, &beg) { + for line in text.split_inclusive('\n') { + let line_stripped = line.trim_end_matches(&['\n', '\r']); + + for failed in linter.textrules_check(&line_stripped, &path, &beg) { pass = false; if !opt.silent { printer.print_failed(&failed, opt.single, opt.github_actions)?; } } - - // Newlines are not included in each line and `text` does not - // contain CRLF because `read_to_string` convents CRLF to LF. - beg += line.len() + 1; // Track the beginning byte index. + beg += line.len(); } match parse_sv_str(text.as_str(), &path, &defines, &includes, opt.ignore_include, false) {