Skip to main content

normalize_languages/
verilog.rs

1//! Verilog/SystemVerilog support.
2
3use crate::external_packages::ResolvedPackage;
4use crate::{Export, Import, Language, Symbol, SymbolKind, Visibility, VisibilityMechanism};
5use std::path::{Path, PathBuf};
6use tree_sitter::Node;
7
8/// Verilog language support.
9pub struct Verilog;
10
11impl Language for Verilog {
12    fn name(&self) -> &'static str {
13        "Verilog"
14    }
15    fn extensions(&self) -> &'static [&'static str] {
16        &["v", "sv", "svh"]
17    }
18    fn grammar_name(&self) -> &'static str {
19        "verilog"
20    }
21
22    fn has_symbols(&self) -> bool {
23        true
24    }
25
26    fn container_kinds(&self) -> &'static [&'static str] {
27        &["module_declaration"]
28    }
29
30    fn function_kinds(&self) -> &'static [&'static str] {
31        &["function_declaration", "task_declaration"]
32    }
33
34    fn type_kinds(&self) -> &'static [&'static str] {
35        &[]
36    }
37
38    fn import_kinds(&self) -> &'static [&'static str] {
39        &["package_import_declaration"]
40    }
41
42    fn public_symbol_kinds(&self) -> &'static [&'static str] {
43        &["module_declaration"]
44    }
45
46    fn visibility_mechanism(&self) -> VisibilityMechanism {
47        VisibilityMechanism::AllPublic
48    }
49
50    fn extract_public_symbols(&self, node: &Node, content: &str) -> Vec<Export> {
51        if node.kind() != "module_declaration" {
52            return Vec::new();
53        }
54
55        if let Some(name) = self.node_name(node, content) {
56            return vec![Export {
57                name: name.to_string(),
58                kind: SymbolKind::Module,
59                line: node.start_position().row + 1,
60            }];
61        }
62        Vec::new()
63    }
64
65    fn scope_creating_kinds(&self) -> &'static [&'static str] {
66        &[
67            "module_declaration",
68            "function_declaration",
69            "task_declaration",
70        ]
71    }
72
73    fn control_flow_kinds(&self) -> &'static [&'static str] {
74        &[
75            "if_generate_construct",
76            "case_generate_construct",
77            "conditional_statement",
78            "case_statement",
79        ]
80    }
81
82    fn complexity_nodes(&self) -> &'static [&'static str] {
83        &["conditional_statement", "case_statement", "loop_statement"]
84    }
85
86    fn nesting_nodes(&self) -> &'static [&'static str] {
87        &["module_declaration"]
88    }
89
90    fn signature_suffix(&self) -> &'static str {
91        ""
92    }
93
94    fn extract_function(&self, node: &Node, content: &str, _in_container: bool) -> Option<Symbol> {
95        if node.kind() != "function_declaration" && node.kind() != "task_declaration" {
96            return None;
97        }
98
99        let name = self.node_name(node, content)?;
100        let text = &content[node.byte_range()];
101        let first_line = text.lines().next().unwrap_or(text);
102
103        Some(Symbol {
104            name: name.to_string(),
105            kind: SymbolKind::Function,
106            signature: first_line.trim().to_string(),
107            docstring: None,
108            attributes: Vec::new(),
109            start_line: node.start_position().row + 1,
110            end_line: node.end_position().row + 1,
111            visibility: Visibility::Public,
112            children: Vec::new(),
113            is_interface_impl: false,
114            implements: Vec::new(),
115        })
116    }
117
118    fn extract_container(&self, node: &Node, content: &str) -> Option<Symbol> {
119        if node.kind() != "module_declaration" {
120            return None;
121        }
122
123        let name = self.node_name(node, content)?;
124        let text = &content[node.byte_range()];
125        let first_line = text.lines().next().unwrap_or(text);
126
127        Some(Symbol {
128            name: name.to_string(),
129            kind: SymbolKind::Module,
130            signature: first_line.trim().to_string(),
131            docstring: None,
132            attributes: Vec::new(),
133            start_line: node.start_position().row + 1,
134            end_line: node.end_position().row + 1,
135            visibility: Visibility::Public,
136            children: Vec::new(),
137            is_interface_impl: false,
138            implements: Vec::new(),
139        })
140    }
141
142    fn extract_type(&self, _node: &Node, _content: &str) -> Option<Symbol> {
143        None
144    }
145    fn extract_docstring(&self, _node: &Node, _content: &str) -> Option<String> {
146        None
147    }
148
149    fn extract_attributes(&self, _node: &Node, _content: &str) -> Vec<String> {
150        Vec::new()
151    }
152
153    fn extract_imports(&self, node: &Node, content: &str) -> Vec<Import> {
154        if node.kind() != "package_import_declaration" {
155            return Vec::new();
156        }
157
158        let text = &content[node.byte_range()];
159        vec![Import {
160            module: text.trim().to_string(),
161            names: Vec::new(),
162            alias: None,
163            is_wildcard: false,
164            is_relative: false,
165            line: node.start_position().row + 1,
166        }]
167    }
168
169    fn format_import(&self, import: &Import, names: Option<&[&str]>) -> String {
170        // Verilog: import package::*; or import package::item;
171        let names_to_use: Vec<&str> = names
172            .map(|n| n.to_vec())
173            .unwrap_or_else(|| import.names.iter().map(|s| s.as_str()).collect());
174        if names_to_use.is_empty() {
175            format!("import {}::*;", import.module)
176        } else if names_to_use.len() == 1 {
177            format!("import {}::{};", import.module, names_to_use[0])
178        } else {
179            // Multiple items need separate import statements
180            names_to_use
181                .iter()
182                .map(|n| format!("import {}::{};", import.module, n))
183                .collect::<Vec<_>>()
184                .join("\n")
185        }
186    }
187
188    fn is_public(&self, _node: &Node, _content: &str) -> bool {
189        true
190    }
191    fn get_visibility(&self, _node: &Node, _content: &str) -> Visibility {
192        Visibility::Public
193    }
194
195    fn is_test_symbol(&self, _symbol: &crate::Symbol) -> bool {
196        false
197    }
198
199    fn embedded_content(&self, _node: &Node, _content: &str) -> Option<crate::EmbeddedBlock> {
200        None
201    }
202
203    fn container_body<'a>(&self, node: &'a Node<'a>) -> Option<Node<'a>> {
204        node.child_by_field_name("body")
205    }
206
207    fn body_has_docstring(&self, _body: &Node, _content: &str) -> bool {
208        false
209    }
210
211    fn node_name<'a>(&self, node: &Node, content: &'a str) -> Option<&'a str> {
212        node.child_by_field_name("name")
213            .map(|n| &content[n.byte_range()])
214    }
215
216    fn file_path_to_module_name(&self, path: &Path) -> Option<String> {
217        let ext = path.extension()?.to_str()?;
218        if !["v", "sv", "svh"].contains(&ext) {
219            return None;
220        }
221        let stem = path.file_stem()?.to_str()?;
222        Some(stem.to_string())
223    }
224
225    fn module_name_to_paths(&self, module: &str) -> Vec<String> {
226        vec![format!("{}.v", module), format!("{}.sv", module)]
227    }
228
229    fn lang_key(&self) -> &'static str {
230        "verilog"
231    }
232
233    fn is_stdlib_import(&self, _: &str, _: &Path) -> bool {
234        false
235    }
236    fn find_stdlib(&self, _: &Path) -> Option<PathBuf> {
237        None
238    }
239    fn resolve_local_import(&self, _: &str, _: &Path, _: &Path) -> Option<PathBuf> {
240        None
241    }
242    fn resolve_external_import(&self, _: &str, _: &Path) -> Option<ResolvedPackage> {
243        None
244    }
245    fn get_version(&self, _: &Path) -> Option<String> {
246        None
247    }
248    fn find_package_cache(&self, _: &Path) -> Option<PathBuf> {
249        None
250    }
251    fn indexable_extensions(&self) -> &'static [&'static str] {
252        &["v", "sv", "svh"]
253    }
254    fn package_sources(&self, _: &Path) -> Vec<crate::PackageSource> {
255        Vec::new()
256    }
257
258    fn should_skip_package_entry(&self, name: &str, is_dir: bool) -> bool {
259        use crate::traits::{has_extension, skip_dotfiles};
260        if skip_dotfiles(name) {
261            return true;
262        }
263        !is_dir && !has_extension(name, self.indexable_extensions())
264    }
265
266    fn discover_packages(&self, _: &crate::PackageSource) -> Vec<(String, PathBuf)> {
267        Vec::new()
268    }
269
270    fn package_module_name(&self, entry_name: &str) -> String {
271        entry_name
272            .strip_suffix(".v")
273            .or_else(|| entry_name.strip_suffix(".sv"))
274            .or_else(|| entry_name.strip_suffix(".svh"))
275            .unwrap_or(entry_name)
276            .to_string()
277    }
278
279    fn find_package_entry(&self, path: &Path) -> Option<PathBuf> {
280        if path.is_file() {
281            Some(path.to_path_buf())
282        } else {
283            None
284        }
285    }
286}
287
288#[cfg(test)]
289mod tests {
290    use super::*;
291    use crate::validate_unused_kinds_audit;
292
293    #[test]
294    fn unused_node_kinds_audit() {
295        #[rustfmt::skip]
296        let documented_unused: &[&str] = &[
297            // Declarations
298            "class_declaration", "interface_declaration", "checker_declaration",
299            "udp_declaration", "clocking_declaration", "property_declaration",
300            "net_declaration", "data_declaration", "parameter_declaration",
301            "specparam_declaration", "type_declaration", "genvar_declaration",
302            "modport_declaration", "constraint_declaration", "covergroup_declaration",
303            "sequence_declaration", "let_declaration", "local_parameter_declaration",
304            "overload_declaration", "interface_class_declaration", "anonymous_program",
305            "package_declaration",
306            // Module/interface headers
307            "module_ansi_header", "module_nonansi_header", "module_header",
308            "interface_ansi_header", "interface_nonansi_header",
309            // Items
310            "module_or_generate_item", "interface_or_generate_item", "class_item",
311            "interface_class_item", "checker_or_generate_item_declaration",
312            "tf_item_declaration", "block_item_declaration", "anonymous_program_item",
313            // Identifiers
314            "simple_identifier", "function_identifier", "task_identifier",
315            "interface_identifier", "class_identifier", "package_identifier",
316            "property_identifier", "checker_identifier",
317            "covergroup_identifier", "cover_point_identifier", "constraint_identifier",
318            "clocking_identifier", "modport_identifier", "generate_block_identifier",
319            "specparam_identifier", "terminal_identifier", "port_identifier",
320            "input_identifier", "output_port_identifier", "index_variable_identifier",
321            "interface_instance_identifier", "hierarchical_btf_identifier",
322            "ps_identifier", "system_tf_identifier",
323            "genvar_identifier",
324            "instance_identifier", "output_identifier", "tf_identifier",
325            "enum_identifier", "member_identifier", "parameter_identifier",
326            "dynamic_array_variable_identifier", "inout_port_identifier",
327            "input_port_identifier", "program_identifier", "cross_identifier",
328            "method_identifier", "formal_port_identifier", "const_identifier",
329            "c_identifier", "escaped_identifier", "text_macro_identifier",
330            // Expressions
331            "expression", "conditional_expression", "inside_expression",
332            "let_expression", "range_expression", "array_range_expression",
333            "case_expression", "expression_or_dist", "data_source_expression",
334            "constant_expression", "constant_mintypmax_expression", "constant_param_expression",
335            "mintypmax_expression", "module_path_expression", "module_path_mintypmax_expression",
336            "clockvar_expression", "inc_or_dec_expression", "assignment_pattern_expression",
337            "event_expression", "param_expression", "select_expression", "bins_expression",
338            "tagged_union_expression", "cycle_delay_const_range_expression",
339            // Statements
340            "statement_or_null", "seq_block", "wait_statement", "jump_statement",
341            "randcase_statement", "action_block", "statement_item", "par_block",
342            "procedural_timing_control_statement", "statement", "disable_statement",
343            "function_statement", "function_statement_or_null",
344            // Assertions
345            "assert_property_statement", "assume_property_statement",
346            "restrict_property_statement", "expect_property_statement",
347            "deferred_immediate_assert_statement", "deferred_immediate_assume_statement",
348            "deferred_immediate_cover_statement", "simple_immediate_assert_statement",
349            "simple_immediate_assume_statement", "simple_immediate_cover_statement",
350            "cover_property_statement", "cover_sequence_statement",
351            "assertion_variable_declaration", "concurrent_assertion_item",
352            "deferred_immediate_assertion_item",
353            // Case
354            "case_item", "case_keyword", "case_pattern_item", "case_inside_item",
355            "case_generate_item", "case_item_expression", "property_case_item",
356            // Generate constructs
357            "loop_generate_construct", "generate_block", "generate_region",
358            "genvar_iteration", "genvar_initialization",
359            // Types
360            "class_type", "integer_vector_type", "struct_union", "struct_union_member",
361            "casting_type", "data_type_or_implicit1", "implicit_data_type1",
362            "integer_atom_type", "type_reference", "net_type", "net_type_declaration",
363            "data_type", "non_integer_type", "data_type_or_void", "enum_base_type",
364            "net_port_type1", "interface_class_type",
365            // Class/method
366            "class_method", "class_property", "class_item_qualifier",
367            "class_constructor_prototype", "method_qualifier", "method_call",
368            "method_call_body", "sequence_method_call", "array_method_name",
369            "class_scope", "class_constructor_declaration", "interface_class_method",
370            "class_qualifier", "class_new", "implicit_class_handle", "random_qualifier",
371            // Functions/tasks
372            "function_body_declaration", "function_prototype", "task_prototype",
373            "tf_port_declaration", "extern_tf_declaration", "function_subroutine_call",
374            "dpi_function_proto", "task_body_declaration", "function_data_type_or_implicit1",
375            "dpi_function_import_property", "dpi_task_proto", "tf_call", "tf_port_list",
376            "tf_port_item1", "tf_port_direction",
377            // Ports
378            "input_declaration", "output_declaration", "inout_declaration",
379            "interface_port_declaration", "interface_port_header", "port_direction",
380            "port_declaration", "list_of_port_declarations", "ansi_port_declaration",
381            // Parameters and lists
382            "parameter_port_declaration", "list_of_tf_variable_identifiers",
383            "list_of_variable_identifiers", "list_of_port_identifiers",
384            "list_of_variable_port_identifiers", "list_of_interface_identifiers",
385            "list_of_type_assignments", "list_of_formal_arguments",
386            "list_of_path_delay_expressions", "identifier_list", "list_of_genvar_identifiers",
387            "list_of_arguments", "list_of_arguments_parent", "list_of_port_connections",
388            "list_of_parameter_assignments", "list_of_clocking_decl_assign",
389            "list_of_cross_items", "list_of_defparam_assignments", "list_of_net_assignments",
390            "list_of_net_decl_assignments", "list_of_param_assignments",
391            "list_of_specparam_assignments", "list_of_udp_port_identifiers",
392            "list_of_variable_assignments", "list_of_variable_decl_assignments",
393            "list_of_path_inputs", "list_of_path_outputs", "variable_identifier_list",
394            // UDP
395            "udp_ansi_declaration", "udp_reg_declaration", "udp_input_declaration",
396            "sequential_entry", "combinational_entry", "combinational_body",
397            "udp_initial_statement", "udp_declaration_port_list", "udp_output_declaration",
398            "udp_nonansi_declaration", "udp_port_declaration", "sequential_body",
399            "udp_port_list", "udp_instance", "udp_instantiation",
400            // Constraints
401            "constraint_expression", "constraint_prototype_qualifier",
402            "extern_constraint_declaration", "solve_before_list", "constraint_block_item",
403            "constraint_block", "constraint_prototype", "constraint_primary",
404            "constraint_set", "uniqueness_constraint", "dist_list", "dist_item", "dist_weight",
405            // Specify
406            "simple_path_declaration", "edge_sensitive_path_declaration",
407            "state_dependent_path_declaration", "specify_input_terminal_descriptor",
408            "specify_output_terminal_descriptor", "showcancelled_declaration",
409            "edge_control_specifier", "edge_identifier", "specify_block",
410            "pulsestyle_declaration", "path_delay_expression", "path_declaration",
411            "parallel_path_description", "full_path_description",
412            "parallel_edge_sensitive_path_description", "full_edge_sensitive_path_description",
413            "path_delay_value",
414            // Operators
415            "stream_operator", "assignment_operator", "operator_assignment",
416            "inc_or_dec_operator", "polarity_operator", "overload_operator",
417            "overload_proto_formals", "unary_operator",
418            // DPI
419            "dpi_import_export", "dpi_task_import_property", "import_export", "dpi_spec_string",
420            // Assignments
421            "nonblocking_assignment", "for_step", "for_variable_declaration",
422            "loop_variables1", "ref_declaration", "blocking_assignment",
423            "for_initialization", "variable_assignment", "net_assignment",
424            "net_decl_assignment", "variable_decl_assignment", "param_assignment",
425            "specparam_assignment", "defparam_assignment", "type_assignment",
426            "assignment_pattern", "assignment_pattern_key",
427            "assignment_pattern_net_lvalue", "assignment_pattern_variable_lvalue",
428            "clocking_decl_assign",
429            // Concatenations
430            "module_path_concatenation", "module_path_multiple_concatenation",
431            "concatenation", "constant_concatenation", "constant_multiple_concatenation",
432            "multiple_concatenation", "streaming_concatenation", "stream_concatenation",
433            "stream_expression", "slice_size", "empty_unpacked_array_concatenation",
434            // Interface/modport
435            "interface_item", "interface_instantiation", "modport_clocking_declaration",
436            "modport_item", "modport_ports_declaration", "modport_simple_ports_declaration",
437            "modport_simple_port", "modport_tf_ports_declaration",
438            // Module instantiation
439            "module_instantiation", "module_keyword", "hierarchical_instance",
440            "name_of_instance", "parameter_value_assignment",
441            "ordered_parameter_assignment", "named_parameter_assignment",
442            "ordered_port_connection", "named_port_connection",
443            "program_instantiation", "checker_instantiation",
444            // Lifetime
445            "lifetime",
446            // Block
447            "block_event_expression", "join_keyword",
448            // Program
449            "program_declaration",
450            // Coverage
451            "cross_body", "cross_body_item", "cover_cross", "cover_point",
452            "coverage_event", "coverage_option", "coverage_spec_or_option",
453            "bins_or_empty", "bins_or_options", "bins_keyword",
454            "bins_selection", "bins_selection_or_option", "select_condition",
455            "covergroup_range_list", "covergroup_value_range",
456            "trans_list", "trans_set", "trans_range_list", "trans_item", "repeat_range",
457            // Cycle delay
458            "cycle_delay", "cycle_delay_range",
459            // Gate types
460            "n_input_gatetype", "n_output_gatetype", "enable_gatetype", "cmos_switchtype",
461            "gate_instantiation", "cmos_switch_instance", "enable_gate_instance",
462            "mos_switch_instance", "n_input_gate_instance", "n_output_gate_instance",
463            "pass_switch_instance", "pass_enable_switch_instance", "pull_gate_instance",
464            "pulldown_strength", "pullup_strength", "enable_terminal", "inout_terminal",
465            "input_terminal", "output_terminal", "ncontrol_terminal", "pcontrol_terminal",
466            // Compiler directives
467            "default_nettype_compiler_directive", "timeunits_declaration",
468            "text_macro_definition",
469            // Clocking
470            "clocking_event", "clocking_item", "clocking_direction",
471            "default_skew", "clocking_skew", "clocking_drive", "clockvar",
472            // Delay/timing
473            "delay3", "delay2", "delay_value", "delay_control", "delay_or_event_control",
474            "event_control", "event_trigger",
475            // Strength
476            "drive_strength", "strength0", "strength1", "charge_strength",
477            // Dimensions
478            "unpacked_dimension", "packed_dimension", "associative_dimension",
479            "queue_dimension", "unsized_dimension",
480            // Selects and ranges
481            "constant_range", "constant_indexed_range", "indexed_range",
482            "constant_primary", "module_path_primary", "primary", "primary_literal",
483            "bit_select1", "select1", "nonrange_select1", "constant_bit_select1",
484            "constant_select1",
485            // Randcase
486            "randcase_item",
487            // Always/initial
488            "always_construct", "always_keyword", "initial_construct", "final_construct",
489            // Continuous assign
490            "continuous_assign", "net_alias", "procedural_continuous_assignment",
491            // Loop
492            "loop_variables1", "open_range_list", "open_value_range",
493            // Pattern
494            "pattern", "cond_pattern", "cond_predicate", "unique_priority",
495            // Enum
496            "enum_name_declaration",
497            // Formal/args
498            "formal_argument", "let_port_list", "let_port_item", "let_list_of_arguments",
499            "let_actual_arg",
500            // Property/sequence
501            "property_port_list", "property_port_item", "property_lvar_port_direction",
502            "property_spec", "property_expr", "sequence_port_list", "sequence_port_item",
503            "sequence_lvar_port_direction", "sequence_expr", "sequence_instance",
504            "sequence_list_of_arguments", "sequence_abbrev",
505            "consecutive_repetition", "non_consecutive_repetition", "goto_repetition",
506            // Lvalues
507            "net_lvalue", "variable_lvalue", "nonrange_variable_lvalue",
508            // Subroutines
509            "subroutine_call", "system_tf_call", "array_manipulation_call", "randomize_call",
510            // Literals
511            "time_literal", "time_unit", "string_literal", "integral_number",
512            "decimal_number", "real_number", "unbased_unsized_literal",
513            // Cast
514            "cast", "dynamic_array_new",
515            // Package
516            "package_export_declaration", "package_scope", "package_import_item",
517            // Attributes
518            "attribute_instance", "attr_spec",
519            // Specparam
520            "pulse_control_specparam", "error_limit_value", "reject_limit_value", "limit_value",
521            // Timing checks
522            "timing_check_event", "timing_check_event_control", "timing_check_condition",
523            "timing_check_limit", "controlled_reference_event", "data_event",
524            "delayed_data", "delayed_reference", "end_edge_offset", "event_based_flag",
525            "reference_event", "remain_active_flag", "timestamp_condition",
526            "start_edge_offset", "threshold", "scalar_timing_check_condition",
527            "scalar_constant", "timecheck_condition", "edge_descriptor",
528            // System timing checks
529            "$setup_timing_check", "$hold_timing_check", "$setuphold_timing_check",
530            "$recovery_timing_check", "$removal_timing_check", "$recrem_timing_check",
531            "$skew_timing_check", "$timeskew_timing_check", "$fullskew_timing_check",
532            "$period_timing_check", "$width_timing_check", "$nochange_timing_check",
533            // Level/edge
534            "level_input_list", "edge_input_list", "edge_indicator", "next_state", "init_val",
535            // Others
536            "pass_switchtype", "pass_en_switchtype", "mos_switchtype",
537            "default_nettype_value",
538            "property_formal_type1", "sequence_formal_type1", "let_formal_type1",
539            "package_or_generate_item_declaration", "notifier",
540            "ps_or_hierarchical_array_identifier", "value_range",
541        ];
542        validate_unused_kinds_audit(&Verilog, documented_unused)
543            .expect("Verilog unused node kinds audit failed");
544    }
545}