From cb229d5d9d993986171a384b38c4d6ea3b6f8ffc Mon Sep 17 00:00:00 2001 From: "Vasquez Alfaro, Juan J" Date: Fri, 22 Aug 2025 15:27:49 -0600 Subject: [PATCH 1/3] Compensate depth for compound blocks inside HashIf content --- src/analysis/parsing/structure.rs | 13 +++++ src/analysis/parsing/tree.rs | 2 +- .../rules/tests/indentation/code_block.rs | 56 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/analysis/parsing/structure.rs b/src/analysis/parsing/structure.rs index ee9e647b..0902aec9 100644 --- a/src/analysis/parsing/structure.rs +++ b/src/analysis/parsing/structure.rs @@ -1384,6 +1384,19 @@ impl TreeElement for HashIfContent { } errors } + fn style_check(&self, acc: &mut Vec, rules: &CurrentRules, mut aux: AuxParams) { + self.evaluate_rules(acc, rules, aux); + self.cond.style_check(acc, rules, aux); + // if depth=0 for this HashIf statement + // then pass 0xffff_ffff interpreted as -1 + // to child block, so no indentation is applied + if aux.depth == 0 { + aux.depth = 0xffff_ffff; + } + + self.truestatements.style_check(acc, rules, aux); + self.elsebranch.style_check(acc, rules, aux); + } } impl Parse for HashIfContent { diff --git a/src/analysis/parsing/tree.rs b/src/analysis/parsing/tree.rs index 102f18ee..3542f562 100644 --- a/src/analysis/parsing/tree.rs +++ b/src/analysis/parsing/tree.rs @@ -108,7 +108,7 @@ pub trait TreeElement { fn style_check(&self, acc: &mut Vec, rules: &CurrentRules, mut aux: AuxParams) { if self.should_increment_depth() { - aux.depth += 1; + aux.depth = aux.depth.wrapping_add(1); } self.evaluate_rules(acc, rules, aux); for sub in self.subs() { diff --git a/src/lint/rules/tests/indentation/code_block.rs b/src/lint/rules/tests/indentation/code_block.rs index b358567c..f3593c03 100644 --- a/src/lint/rules/tests/indentation/code_block.rs +++ b/src/lint/rules/tests/indentation/code_block.rs @@ -298,3 +298,59 @@ fn template_incorrect() { ); assert_snippet(TEMPLATE_INCORRECT, expected_errors, &rules); } + +static TOPLEVEL_HASHIF_CORRECT: &str = " +constant FEATURE_SUPPORTED = false; + +#if (!FEATURE_SUPPORTED) { +attribute target_sb_port is uint64_attr {} +} #else { +attribute target_sb_fid is uint64_attr {} +} + +#if (!FEATURE_SUPPORTED) { +method signal_feature() { + return 1; +} +} #else { +method signal_feature() { return 0; } +} +"; + +#[test] +fn toplevel_hashif_correct() { + let rules = set_up(); + assert_snippet(TOPLEVEL_HASHIF_CORRECT, vec![], &rules); +} + +static TOPLEVEL_HASHIF_INCORRECT: &str = " +constant FEATURE_SUPPORTED = false; + +#if (!FEATURE_SUPPORTED) { + attribute target_sb_port is uint64_attr {} +} #else { + attribute target_sb_fid is uint64_attr {} +} + +#if (!FEATURE_SUPPORTED) { + method signal_feature() { + return 1; + } +} #else { + method signal_feature() { return 0; } +} +"; + +#[test] +fn toplevel_hashif_incorrect() { + let rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::IN3, + (4, 4, 4, 46), + (6, 6, 4, 45), + (10, 12, 4, 5), + (11, 11, 8, 17), + (14, 14, 4, 41), + ); + assert_snippet(TOPLEVEL_HASHIF_INCORRECT, expected_errors, &rules); +} \ No newline at end of file From 0452e3035d8b879ab3a0c1b6188e2b169802ee8e Mon Sep 17 00:00:00 2001 From: Juan Vasquez Date: Thu, 18 Dec 2025 16:08:28 -0800 Subject: [PATCH 2/3] Add test for nested HashIf code blocks --- .../rules/tests/indentation/code_block.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/lint/rules/tests/indentation/code_block.rs b/src/lint/rules/tests/indentation/code_block.rs index f3593c03..b1c4214c 100644 --- a/src/lint/rules/tests/indentation/code_block.rs +++ b/src/lint/rules/tests/indentation/code_block.rs @@ -353,4 +353,45 @@ fn toplevel_hashif_incorrect() { (14, 14, 4, 41), ); assert_snippet(TOPLEVEL_HASHIF_INCORRECT, expected_errors, &rules); +} + +static NESTED_HASHIF_CORRECT: &str = " +constant FEATURE_SUPPORTED = false; + +method signal_feature() { + #if (!FEATURE_SUPPORTED) { + return 1; + } #else { + return 0; + } +} +"; + +#[test] +fn nested_hashif_correct() { + let rules = set_up(); + assert_snippet(NESTED_HASHIF_CORRECT, vec![], &rules); +} + +static NESTED_HASHIF_INCORRECT: &str = " +constant FEATURE_SUPPORTED = false; + +method signal_feature() { + #if (!FEATURE_SUPPORTED) { +return 1; + } #else { + return 0; + } +} +"; + +#[test] +fn nested_hashif_incorrect() { + let rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::IN3, + (5, 5, 0, 9), + (7, 7, 12, 21), + ); + assert_snippet(NESTED_HASHIF_INCORRECT, expected_errors, &rules); } \ No newline at end of file From e708286bea8cb1b83dca0a5855acc9207bffc8fe Mon Sep 17 00:00:00 2001 From: "Vasquez Alfaro, Juan J" Date: Thu, 8 Jan 2026 18:41:23 -0600 Subject: [PATCH 3/3] Pass parent_start_col through AuxParams for required cases --- src/analysis/parsing/statement.rs | 7 +++++-- src/analysis/parsing/structure.rs | 21 ++++++++++++++++++++- src/analysis/parsing/tree.rs | 10 +++++++++- src/analysis/parsing/types.rs | 9 ++++++--- src/lint/mod.rs | 4 +++- src/lint/rules/indentation.rs | 16 ++++++++-------- 6 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/analysis/parsing/statement.rs b/src/analysis/parsing/statement.rs index 5d3da738..204741b4 100644 --- a/src/analysis/parsing/statement.rs +++ b/src/analysis/parsing/statement.rs @@ -152,7 +152,7 @@ impl TreeElement for CompoundContent { fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { rules.sp_brace.check(SpBracesArgs::from_compound(self), acc); rules.indent_code_block.check(IndentCodeBlockArgs::from_compound_content(self, aux.depth), acc); - rules.indent_closing_brace.check(IndentClosingBraceArgs::from_compound_content(self, aux.depth), acc); + rules.indent_closing_brace.check(IndentClosingBraceArgs::from_compound_content(self, aux.parent_statement_start_col), acc); } fn should_increment_depth(&self) -> bool { true @@ -439,6 +439,9 @@ impl TreeElement for IfContent { &self.truebranch, &self.elsebranch) } + fn should_save_outer_start_col(&self) -> bool { + true + } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { rules.nsp_inparen.check(NspInparenArgs::from_if(self), acc); rules.indent_paren_expr.check(IndentParenExprArgs::from_if(self), acc); @@ -1122,7 +1125,7 @@ impl TreeElement for SwitchContent { fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { - rules.indent_closing_brace.check(IndentClosingBraceArgs::from_switch_content(self, aux.depth), acc); + rules.indent_closing_brace.check(IndentClosingBraceArgs::from_switch_content(self, self.switchtok.range().col_start.0), acc); rules.indent_paren_expr.check(IndentParenExprArgs::from_switch(self), acc); } } diff --git a/src/analysis/parsing/structure.rs b/src/analysis/parsing/structure.rs index 0902aec9..8db32257 100644 --- a/src/analysis/parsing/structure.rs +++ b/src/analysis/parsing/structure.rs @@ -31,6 +31,8 @@ use crate::analysis::FileSpec; use crate::span::Range; use crate::vfs::TextFile; +use super::parser::Token; + fn object_contexts(context: &ParseContext) -> (ParseContext, ParseContext) { fn understands_semi(token: TokenKind) -> bool { @@ -239,6 +241,9 @@ impl TreeElement for MethodContent { } errors } + fn should_save_outer_start_col(&self) -> bool { + true + } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { rules.nsp_funpar.check(NspFunparArgs::from_method(self), acc); rules.nsp_inparen.check(NspInparenArgs::from_method(self), acc); @@ -731,7 +736,7 @@ impl TreeElement for ObjectStatementsContent { fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { rules.sp_brace.check(SpBracesArgs::from_obj_stmts(self), acc); rules.indent_code_block.check(IndentCodeBlockArgs::from_obj_stmts_content(self, aux.depth), acc); - rules.indent_closing_brace.check(IndentClosingBraceArgs::from_obj_stmts_content(self, aux.depth), acc); + rules.indent_closing_brace.check(IndentClosingBraceArgs::from_obj_stmts_content(self, aux.parent_statement_start_col), acc); } fn should_increment_depth(&self) -> bool { matches!(self, ObjectStatementsContent::List(lbrace, list, rbrace) @@ -1061,6 +1066,9 @@ impl TreeElement for RegisterContent { } } fn references<'a>(&self, _accumulator: &mut Vec, _file: FileSpec<'a>) {} + fn should_save_outer_start_col(&self) -> bool { + true + } } impl Parse for RegisterContent { @@ -1130,6 +1138,9 @@ impl TreeElement for FieldContent { } } fn references<'a>(&self, _accumulator: &mut Vec, _file: FileSpec<'a>) {} + fn should_save_outer_start_col(&self) -> bool { + true + } } impl Parse for FieldContent { @@ -1615,6 +1626,9 @@ impl TreeElement for TypedefContent { fn post_parse_sanity(&self, _file: &TextFile) -> Vec { self.decl.ensure_named() } + fn should_save_outer_start_col(&self) -> bool { + true + } } // Special case, to distinguish between extern cdecl and extern typedef, the @@ -1953,6 +1967,11 @@ impl TreeElement for DMLObjectContent { fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { rules.indent_continuation_line.check(acc, IndentContinuationLineArgs::from_dml_object_content(self, aux.depth)); } + fn save_outer_start_col(&self, aux: &mut AuxParams) { + if let Some(token) = self.tokens().first() { + aux.parent_statement_start_col = token.range.col_start.0; + } + } } pub type DMLObject = AstObject; diff --git a/src/analysis/parsing/tree.rs b/src/analysis/parsing/tree.rs index 3542f562..05871d5e 100644 --- a/src/analysis/parsing/tree.rs +++ b/src/analysis/parsing/tree.rs @@ -107,6 +107,9 @@ pub trait TreeElement { } fn style_check(&self, acc: &mut Vec, rules: &CurrentRules, mut aux: AuxParams) { + if self.should_save_outer_start_col() { + self.save_outer_start_col(&mut aux); + } if self.should_increment_depth() { aux.depth = aux.depth.wrapping_add(1); } @@ -116,8 +119,13 @@ pub trait TreeElement { } } fn should_increment_depth(&self) -> bool {false} // default don't increment + fn should_save_outer_start_col(&self) -> bool {false} // default don't save fn evaluate_rules(&self, _acc: &mut Vec, _rules: &CurrentRules, _aux: AuxParams) {} // default NOOP -} + fn save_outer_start_col(&self, aux: &mut AuxParams) { + if let Some(token) = self.tokens().first() { + aux.parent_statement_start_col = token.range.col_start.0; + } + }} impl ReferenceContainer for T { fn collect_references<'a>(&self, diff --git a/src/analysis/parsing/types.rs b/src/analysis/parsing/types.rs index 7335632d..86d1c2a6 100644 --- a/src/analysis/parsing/types.rs +++ b/src/analysis/parsing/types.rs @@ -56,7 +56,7 @@ impl TreeElement for StructTypeContent { } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { rules.indent_code_block.check(IndentCodeBlockArgs::from_struct_type_content(self, aux.depth), acc); - rules.indent_closing_brace.check(IndentClosingBraceArgs::from_struct_type_content(self, aux.depth), acc); + rules.indent_closing_brace.check(IndentClosingBraceArgs::from_struct_type_content(self, self.structtok.range().col_start.0), acc); rules.sp_brace.check(SpBracesArgs::from_struct_type_content(self), acc); } fn should_increment_depth(&self) -> bool { @@ -139,7 +139,7 @@ impl TreeElement for LayoutContent { } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { rules.indent_code_block.check(IndentCodeBlockArgs::from_layout_content(self, aux.depth), acc); - rules.indent_closing_brace.check(IndentClosingBraceArgs::from_layout_content(self, aux.depth), acc); + rules.indent_closing_brace.check(IndentClosingBraceArgs::from_layout_content(self, self.layout.range().col_start.0), acc); rules.sp_brace.check(SpBracesArgs::from_layout_content(self), acc); } fn should_increment_depth(&self) -> bool { @@ -317,11 +317,14 @@ impl TreeElement for BitfieldsContent { fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { rules.sp_brace.check(SpBracesArgs::from_bitfields_content(self), acc); rules.indent_code_block.check(IndentCodeBlockArgs::from_bitfields_content(self, aux.depth), acc); - rules.indent_closing_brace.check(IndentClosingBraceArgs::from_bitfields_content(self, aux.depth), acc); + rules.indent_closing_brace.check(IndentClosingBraceArgs::from_bitfields_content(self, self.bitfields.range().col_start.0), acc); } fn should_increment_depth(&self) -> bool { true } + fn should_save_outer_start_col(&self) -> bool { + true + } } impl Parse for BitfieldsContent { diff --git a/src/lint/mod.rs b/src/lint/mod.rs index f5d2210f..41a14451 100644 --- a/src/lint/mod.rs +++ b/src/lint/mod.rs @@ -245,7 +245,7 @@ impl LinterAnalysis { fn begin_style_check(ast: TopAst, file: &str, rules: &CurrentRules) -> Result, Error> { let (mut invalid_lint_annot, lint_annot) = obtain_lint_annotations(file); let mut linting_errors: Vec = vec![]; - ast.style_check(&mut linting_errors, rules, AuxParams { depth: 0 }); + ast.style_check(&mut linting_errors, rules, AuxParams { depth: 0, parent_statement_start_col: 0 }); // Per line checks let lines: Vec<&str> = file.lines().collect(); @@ -438,6 +438,8 @@ pub struct AuxParams { // Individual nodes update depth to affect level of their // nested TreeElements. See more in src/lint/README.md pub depth: u32, + pub parent_statement_start_col: u32, + // pub get_parent_start_col: fn(T: dyn TreeElement) -> u32, } pub mod rules; diff --git a/src/lint/rules/indentation.rs b/src/lint/rules/indentation.rs index 499a00e2..ae3331ba 100644 --- a/src/lint/rules/indentation.rs +++ b/src/lint/rules/indentation.rs @@ -286,7 +286,7 @@ pub struct IndentClosingBraceArgs { impl IndentClosingBraceArgs { pub fn from_compound_content(node: &CompoundContent, depth: u32) -> Option { Some(IndentClosingBraceArgs { - expected_depth: depth.saturating_sub(1), + expected_depth: depth, lbrace: node.lbrace.range(), last_member: node.statements.last()?.range(), rbrace: node.rbrace.range(), @@ -296,7 +296,7 @@ impl IndentClosingBraceArgs { pub fn from_obj_stmts_content(node: &ObjectStatementsContent, depth: u32) -> Option { if let ObjectStatementsContent::List(lbrace, stmnts, rbrace) = node { Some(IndentClosingBraceArgs { - expected_depth: depth.saturating_sub(1), + expected_depth: depth, lbrace: lbrace.range(), last_member: stmnts.last()?.range(), rbrace: rbrace.range(), @@ -319,7 +319,7 @@ impl IndentClosingBraceArgs { pub fn from_struct_type_content(node: &StructTypeContent, depth: u32) -> Option { Some(IndentClosingBraceArgs { - expected_depth: depth.saturating_sub(1), + expected_depth: depth, lbrace: node.lbrace.range(), last_member: node.members.last()?.range(), rbrace: node.rbrace.range(), @@ -328,7 +328,7 @@ impl IndentClosingBraceArgs { pub fn from_layout_content(node: &LayoutContent, depth: u32) -> Option { Some(IndentClosingBraceArgs { - expected_depth: depth.saturating_sub(1), + expected_depth: depth, lbrace: node.lbrace.range(), last_member: node.fields.last()?.range(), rbrace: node.rbrace.range(), @@ -337,7 +337,7 @@ impl IndentClosingBraceArgs { pub fn from_bitfields_content(node: &BitfieldsContent, depth: u32) -> Option { Some(IndentClosingBraceArgs { - expected_depth: depth.saturating_sub(1), + expected_depth: depth, lbrace: node.lbrace.range(), last_member: node.fields.last()?.range(), rbrace: node.rbrace.range(), @@ -377,9 +377,9 @@ impl IndentClosingBraceRule { return; } - let rbrace_on_same_ind_level_than_switchtok:bool = args.rbrace.col_start.0 - == args.expected_depth * self.indentation_spaces; - if !rbrace_on_same_ind_level_than_switchtok { + let rbrace_on_same_col_as_outer_statement_start:bool = args.rbrace.col_start.0 + == args.expected_depth; + if !rbrace_on_same_col_as_outer_statement_start { acc.push(self.create_err(args.rbrace)); } }