svlint/opt/rustwide/workdir/src/syntaxrules/
re_forbidden_port_ref.rs

1use crate::config::ConfigOption;
2use crate::linter::{check_regex, SyntaxRule, SyntaxRuleResult};
3use regex::Regex;
4use sv_parser::{unwrap_node, NodeEvent, RefNode, SyntaxTree, PortDirection};
5
6#[derive(Default)]
7pub struct ReForbiddenPortRef {
8    re: Option<Regex>,
9    under_ref_declaration: bool,
10    under_ansi_port_declaration: bool,
11    previous_port_direction_ref: bool,
12}
13
14impl SyntaxRule for ReForbiddenPortRef {
15    fn check(
16        &mut self,
17        syntax_tree: &SyntaxTree,
18        event: &NodeEvent,
19        option: &ConfigOption,
20    ) -> SyntaxRuleResult {
21        if self.re.is_none() {
22            self.re = Some(Regex::new(&option.re_forbidden_port_ref).unwrap());
23        }
24
25        let node = match event {
26            NodeEvent::Enter(x) => {
27                match x {
28                    RefNode::RefDeclaration(_) => {
29                        self.under_ref_declaration = true;
30                    }
31                    RefNode::AnsiPortDeclaration(_) => {
32                        self.under_ansi_port_declaration = true;
33                    }
34                    RefNode::PortDirection(PortDirection::Ref(_)) => {
35                        self.previous_port_direction_ref = true;
36                    }
37                    RefNode::ModuleAnsiHeader(_) |
38                    RefNode::PortDirection(PortDirection::Inout(_)) |
39                    RefNode::PortDirection(PortDirection::Input(_)) |
40                    RefNode::PortDirection(PortDirection::Output(_)) => {
41                        self.previous_port_direction_ref = false;
42                    }
43                    _ => ()
44                }
45                x
46            }
47            NodeEvent::Leave(x) => {
48                match x {
49                    RefNode::RefDeclaration(_) => {
50                        self.under_ref_declaration = false;
51                    }
52                    RefNode::AnsiPortDeclaration(_) => {
53                        self.under_ansi_port_declaration = false;
54                    }
55                    _ => ()
56                }
57                return SyntaxRuleResult::Pass;
58            }
59        };
60
61        let c: bool = self.under_ref_declaration ||
62            (self.under_ansi_port_declaration && self.previous_port_direction_ref);
63
64        match (c, node) {
65            (true, RefNode::PortIdentifier(x)) => {
66                check_regex(false, unwrap_node!(*x, Identifier),
67                            &syntax_tree, &self.re.as_ref().unwrap())
68            }
69            _ => SyntaxRuleResult::Pass
70        }
71    }
72
73    fn name(&self) -> String {
74        String::from("re_forbidden_port_ref")
75    }
76
77    fn hint(&self, option: &ConfigOption) -> String {
78        String::from(format!(
79            "Use a port identifier not matching regex `{}`.",
80            &option.re_forbidden_port_ref
81        ))
82    }
83
84    fn reason(&self) -> String {
85        String::from("Identifiers must conform to the naming scheme.")
86    }
87}