diff --git a/example_files/example_lint_cfg.json b/example_files/example_lint_cfg.json index d4c0427..7892d4c 100644 --- a/example_files/example_lint_cfg.json +++ b/example_files/example_lint_cfg.json @@ -12,5 +12,6 @@ "indent_closing_brace": {}, "indent_paren_expr": {}, "indent_switch_case": {}, - "indent_empty_loop": {} + "indent_empty_loop": {}, + "indent_continuation_line": {} } diff --git a/src/analysis/parsing/expression.rs b/src/analysis/parsing/expression.rs index 383e4f3..3537abf 100644 --- a/src/analysis/parsing/expression.rs +++ b/src/analysis/parsing/expression.rs @@ -24,7 +24,7 @@ use crate::lint::{DMLStyleError, SpPunctArgs}, CurrentRules}, AuxParams}; -use crate::lint::rules::indentation::{IndentParenExprArgs}; +use crate::lint::rules::indentation::IndentParenExprArgs; #[derive(Debug, Clone, PartialEq)] pub struct UnaryExpressionContent { diff --git a/src/analysis/parsing/statement.rs b/src/analysis/parsing/statement.rs index fed3b27..0f66d70 100644 --- a/src/analysis/parsing/statement.rs +++ b/src/analysis/parsing/statement.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 and MIT use log::error; -use crate::lint::rules::indentation::IndentEmptyLoopArgs; +use crate::lint::rules::indentation::{IndentContinuationLineArgs, IndentEmptyLoopArgs}; use crate::span::Range; use crate::analysis::parsing::lexer::TokenKind; use crate::analysis::parsing::statement; @@ -1839,6 +1839,9 @@ impl TreeElement for StatementContent { Self::Return(content) => create_subs![content], } } + fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { + rules.indent_continuation_line.check(acc, IndentContinuationLineArgs::from_statement_content(self, aux.depth)); + } } pub type Statement = AstObject; diff --git a/src/analysis/parsing/structure.rs b/src/analysis/parsing/structure.rs index 4d4a293..db1ed6b 100644 --- a/src/analysis/parsing/structure.rs +++ b/src/analysis/parsing/structure.rs @@ -20,7 +20,7 @@ use crate::lint::rules::spacing::{SpBracesArgs, NspInparenArgs, NspFunparArgs, SpPunctArgs}; -use crate::lint::rules::indentation::{IndentCodeBlockArgs, IndentClosingBraceArgs, IndentParenExprArgs}; +use crate::lint::rules::indentation::{IndentCodeBlockArgs, IndentClosingBraceArgs, IndentParenExprArgs, IndentContinuationLineArgs}; use crate::lint::{rules::CurrentRules, AuxParams, DMLStyleError}; use crate::analysis::reference::{Reference, ReferenceKind}; use crate::analysis::FileSpec; @@ -1905,6 +1905,9 @@ impl TreeElement for DMLObjectContent { Self::Template(content) => create_subs![content], } } + 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)); + } } pub type DMLObject = AstObject; diff --git a/src/lint/mod.rs b/src/lint/mod.rs index 1ad9ed2..d2e54f6 100644 --- a/src/lint/mod.rs +++ b/src/lint/mod.rs @@ -7,7 +7,7 @@ use rules::{instantiate_rules, CurrentRules, RuleType}; use rules::{spacing::{SpBraceOptions, SpPunctOptions, NspFunparOptions, NspInparenOptions, NspUnaryOptions, NspTrailingOptions}, indentation::{LongLineOptions, IndentSizeOptions, IndentCodeBlockOptions, - IndentNoTabOptions, IndentClosingBraceOptions, IndentParenExprOptions, IndentSwitchCaseOptions, IndentEmptyLoopOptions}, + IndentNoTabOptions, IndentClosingBraceOptions, IndentParenExprOptions, IndentSwitchCaseOptions, IndentEmptyLoopOptions, IndentContinuationLineOptions}, }; use crate::analysis::{DMLError, IsolatedAnalysis, LocalDMLError}; use crate::analysis::parsing::tree::TreeElement; @@ -73,6 +73,8 @@ pub struct LintCfg { pub indent_switch_case: Option, #[serde(default)] pub indent_empty_loop: Option, + #[serde(default)] + pub indent_continuation_line: Option, } impl Default for LintCfg { @@ -92,6 +94,7 @@ impl Default for LintCfg { indent_paren_expr: Some(IndentParenExprOptions{}), indent_switch_case: Some(IndentSwitchCaseOptions{indentation_spaces: INDENTATION_LEVEL_DEFAULT}), indent_empty_loop: Some(IndentEmptyLoopOptions{indentation_spaces: INDENTATION_LEVEL_DEFAULT}), + indent_continuation_line: Some(IndentContinuationLineOptions{indentation_spaces: INDENTATION_LEVEL_DEFAULT}), } } } diff --git a/src/lint/rules/indentation.rs b/src/lint/rules/indentation.rs index 62450e1..7b56be3 100644 --- a/src/lint/rules/indentation.rs +++ b/src/lint/rules/indentation.rs @@ -1,12 +1,6 @@ use std::convert::TryInto; -use crate::analysis::parsing::{expression::{CastContent, FunctionCallContent, ParenExpressionContent}, - lexer::TokenKind, - statement::{self, CompoundContent, DoContent, ForContent, ForeachContent, - IfContent, SwitchCase, SwitchContent, WhileContent}, - structure::{MethodContent, ObjectStatementsContent}, - tree::TreeElementTokenIterator, - types::{BitfieldsContent, LayoutContent, StructTypeContent}}; +use crate::analysis::parsing::{expression::{CastContent, FunctionCallContent, ParenExpressionContent}, lexer::TokenKind, parser::Token, statement::{self, CompoundContent, DoContent, ForContent, ForeachContent, IfContent, StatementContent, SwitchCase, SwitchContent, WhileContent}, structure::{DMLObjectContent, MethodContent, ObjectStatementsContent}, tree::TreeElementTokenIterator, types::{BitfieldsContent, LayoutContent, StructTypeContent}}; use crate::span::{Range, ZeroIndexed}; use crate::analysis::parsing::tree::{ZeroRange, Content, TreeElement}; use serde::{Deserialize, Serialize}; @@ -35,6 +29,9 @@ pub fn setup_indentation_size(cfg: &mut LintCfg) { if let Some(indent_empty_loop) = &mut cfg.indent_empty_loop { indent_empty_loop.indentation_spaces = indentation_spaces; } + if let Some(indent_continuation_line) = &mut cfg.indent_continuation_line { + indent_continuation_line.indentation_spaces = indentation_spaces; + } } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct LongLineOptions { @@ -377,8 +374,8 @@ pub struct IndentParenExprArgs { } impl IndentParenExprArgs { - fn filter_out_parenthesized_ranges(expression_tokens: TreeElementTokenIterator) -> Vec { - let mut token_ranges: Vec = vec![]; + pub fn filter_out_parenthesized_tokens(expression_tokens: TreeElementTokenIterator) -> Vec { + let mut token_list: Vec = vec![]; let mut paren_depth = 0; // paren_depth is used to identify nested // parenthesized expressions within other expressions @@ -387,25 +384,32 @@ impl IndentParenExprArgs { for token in expression_tokens { match token.kind { TokenKind::LParen => { + if paren_depth == 0 { token_list.push(token); } paren_depth += 1; - token_ranges.push(token.range); }, - TokenKind::RParen => paren_depth-=1, - _ => { if paren_depth == 0 { token_ranges.push(token.range); } + TokenKind::RParen => { + paren_depth-=1; + if paren_depth == 0 { token_list.push(token); } + }, + TokenKind::LBrace => { + break; + }, + _ => { + if paren_depth == 0 { token_list.push(token); } } } } - token_ranges + token_list } pub fn from_for(node: &ForContent) -> Option { // For loop has three parts within parentheses: pre, cond, and post let mut filtered_member_ranges: Vec = vec![]; - filtered_member_ranges.append(&mut Self::filter_out_parenthesized_ranges(node.pre.tokens())); + filtered_member_ranges.extend(&mut Self::filter_out_parenthesized_tokens(node.pre.tokens()).iter().filter(|t| t.kind != TokenKind::RParen).map(|t| t.range)); filtered_member_ranges.push(node.lsemi.range()); - filtered_member_ranges.append(&mut Self::filter_out_parenthesized_ranges(node.cond.tokens())); + filtered_member_ranges.extend(&mut Self::filter_out_parenthesized_tokens(node.cond.tokens()).iter().filter(|t| t.kind != TokenKind::RParen).map(|t| t.range)); filtered_member_ranges.push(node.rsemi.range()); - filtered_member_ranges.append(&mut Self::filter_out_parenthesized_ranges(node.post.tokens())); + filtered_member_ranges.extend(&mut Self::filter_out_parenthesized_tokens(node.post.tokens()).iter().filter(|t| t.kind != TokenKind::RParen).map(|t| t.range)); Some(IndentParenExprArgs { members_ranges: filtered_member_ranges, @@ -415,7 +419,7 @@ impl IndentParenExprArgs { pub fn from_foreach(node: &ForeachContent) -> Option { Some(IndentParenExprArgs { - members_ranges: Self::filter_out_parenthesized_ranges(node.expression.tokens()), + members_ranges: Self::filter_out_parenthesized_tokens(node.expression.tokens()).iter().filter(|t| t.kind != TokenKind::RParen).map(|t| t.range).collect(), lparen: node.lparen.range(), }) } @@ -423,7 +427,7 @@ impl IndentParenExprArgs { pub fn from_function_call(node: &FunctionCallContent) -> Option { let mut filtered_member_ranges: Vec = vec![]; for (arg, _comma) in node.arguments.iter() { - filtered_member_ranges.append(&mut Self::filter_out_parenthesized_ranges(arg.tokens())); + filtered_member_ranges.extend(Self::filter_out_parenthesized_tokens(arg.tokens()).iter().filter(|t| t.kind != TokenKind::RParen).map(|t| t.range)); } Some(IndentParenExprArgs { members_ranges: filtered_member_ranges, @@ -434,7 +438,7 @@ impl IndentParenExprArgs { pub fn from_paren_expression(node: &ParenExpressionContent) -> Option { Some(IndentParenExprArgs { - members_ranges: Self::filter_out_parenthesized_ranges(node.expr.tokens()), + members_ranges: Self::filter_out_parenthesized_tokens(node.expr.tokens()).iter().filter(|t| t.kind != TokenKind::RParen).map(|t| t.range).collect(), lparen: node.lparen.range(), }) } @@ -442,7 +446,7 @@ impl IndentParenExprArgs { pub fn from_method(node: &MethodContent) -> Option { let mut filtered_member_ranges: Vec = vec![]; for (arg, _comma) in node.arguments.iter() { - filtered_member_ranges.append(&mut Self::filter_out_parenthesized_ranges(arg.tokens())); + filtered_member_ranges.extend(Self::filter_out_parenthesized_tokens(arg.tokens()).iter().filter(|t| t.kind != TokenKind::RParen).map(|t| t.range)); } Some(IndentParenExprArgs { members_ranges: filtered_member_ranges, @@ -452,21 +456,21 @@ impl IndentParenExprArgs { pub fn from_while(node: &WhileContent) -> Option { Some(IndentParenExprArgs { - members_ranges: Self::filter_out_parenthesized_ranges(node.cond.tokens()), + members_ranges: Self::filter_out_parenthesized_tokens(node.cond.tokens()).iter().filter(|t| t.kind != TokenKind::RParen).map(|t| t.range).collect(), lparen: node.lparen.range(), }) } pub fn from_do_while(node: &DoContent) -> Option { Some(IndentParenExprArgs { - members_ranges: Self::filter_out_parenthesized_ranges(node.cond.tokens()), + members_ranges: Self::filter_out_parenthesized_tokens(node.cond.tokens()).iter().filter(|t| t.kind != TokenKind::RParen).map(|t| t.range).collect(), lparen: node.lparen.range(), }) } pub fn from_if(node: &IfContent) -> Option { Some(IndentParenExprArgs { - members_ranges: Self::filter_out_parenthesized_ranges(node.cond.tokens()), + members_ranges: Self::filter_out_parenthesized_tokens(node.cond.tokens()).iter().filter(|t| t.kind != TokenKind::RParen).map(|t| t.range).collect(), lparen: node.lparen.range(), }) } @@ -475,14 +479,14 @@ impl IndentParenExprArgs { let mut cast_member_tokens = node.from.tokens(); cast_member_tokens.append(&mut node.to.tokens()); Some(IndentParenExprArgs { - members_ranges: Self::filter_out_parenthesized_ranges(cast_member_tokens), + members_ranges: Self::filter_out_parenthesized_tokens(cast_member_tokens).iter().filter(|t| t.kind != TokenKind::RParen).map(|t| t.range).collect(), lparen: node.lparen.range(), }) } pub fn from_switch(node: &SwitchContent) -> Option { Some(IndentParenExprArgs { - members_ranges: Self::filter_out_parenthesized_ranges(node.expr.tokens()), + members_ranges: Self::filter_out_parenthesized_tokens(node.expr.tokens()).iter().filter(|t| t.kind != TokenKind::RParen).map(|t| t.range).collect(), lparen: node.lparen.range(), }) } @@ -689,3 +693,122 @@ impl Rule for IndentEmptyLoopRule { RuleType::IN10 } } + +// in6 +pub struct IndentContinuationLineRule { + pub enabled: bool, + indentation_spaces: u32 +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct IndentContinuationLineOptions { + #[serde(default = "default_indentation_spaces")] + pub indentation_spaces: u32, +} + +pub struct IndentContinuationLineArgs { + token_list: Vec, + expected_depth: u32, +} + +impl IndentContinuationLineArgs { + pub fn filter_out_last_semi_ranges(expression_tokens: &mut TreeElementTokenIterator) { + // This function filters out the last semicolon in a list of tokens + // as it is not part of the continuation line check. + expression_tokens.pop_if(|token| token.kind == TokenKind::SemiColon); + } + + pub fn from_statement_content(node: &StatementContent, depth: u32) -> Option { + match node { + StatementContent::Compound(_) | + StatementContent::If(_) | + StatementContent::While(_) | + StatementContent::Do(_) | + StatementContent::For(_) | + StatementContent::Try(_) | + StatementContent::Foreach(_) | + StatementContent::Throw(_) | + StatementContent::Switch(_) => return None, + _ => {} + }; + let mut tokens = node.tokens(); + Self::filter_out_last_semi_ranges(&mut tokens); + + Some(IndentContinuationLineArgs { + token_list: IndentParenExprArgs::filter_out_parenthesized_tokens(tokens), + expected_depth: depth, + }) + } + + pub fn from_dml_object_content(node: &DMLObjectContent, depth: u32) -> Option { + match node { + DMLObjectContent::Parameter(_) | + DMLObjectContent::Hook(_) | + DMLObjectContent::Import(_) | + DMLObjectContent::InEach(_) | + DMLObjectContent::Session(_) | + DMLObjectContent::Typedef(_) => { + let mut tokens = node.tokens(); + Self::filter_out_last_semi_ranges(&mut tokens); + return Some(IndentContinuationLineArgs { + token_list: IndentParenExprArgs::filter_out_parenthesized_tokens(tokens), + expected_depth: depth, + })}, + _ => return None, + } + } +} + +impl IndentContinuationLineRule { + pub fn from_options(options: &Option) -> IndentContinuationLineRule { + match options { + Some(options) => IndentContinuationLineRule { + enabled: true, + indentation_spaces: options.indentation_spaces + }, + None => IndentContinuationLineRule { + enabled: false, + indentation_spaces: 0 + } + } + } + + pub fn check<'a> (&self, acc: &mut Vec, + args: Option) { + if !self.enabled { return; } + let Some(args) = args else { return; }; + if args.token_list.is_empty() { return; } + let expected_line_start = self.indentation_spaces * (args.expected_depth + 1); + let mut last_row = args.token_list.first().unwrap().range.row_start.0; + + for token in args.token_list { + match token.kind { + TokenKind::RParen => { + if token.range.row_start.0 != last_row { + last_row = token.range.row_start.0; + } + } + _ => { + if token.range.row_start.0 != last_row { + last_row = token.range.row_start.0; + if token.range.col_start.0 != expected_line_start { + acc.push(self.create_err(token.range)) + } + } + } + } + } + } +} + +impl Rule for IndentContinuationLineRule { + fn name() -> &'static str { + "INDENT_CONTINUATION_LINE" + } + fn description() -> &'static str { + "A continuation line not broken inside a parenthesized expression is indented one level." + } + fn get_rule_type() -> RuleType { + RuleType::IN6 + } +} diff --git a/src/lint/rules/mod.rs b/src/lint/rules/mod.rs index 2b679e9..3340c4c 100644 --- a/src/lint/rules/mod.rs +++ b/src/lint/rules/mod.rs @@ -7,7 +7,7 @@ pub mod tests; use spacing::{SpBracesRule, SpPunctRule, NspFunparRule, NspInparenRule, NspUnaryRule, NspTrailingRule}; -use indentation::{LongLinesRule, IndentNoTabRule, IndentCodeBlockRule, IndentClosingBraceRule, IndentParenExprRule, IndentSwitchCaseRule, IndentEmptyLoopRule}; +use indentation::{LongLinesRule, IndentNoTabRule, IndentCodeBlockRule, IndentClosingBraceRule, IndentParenExprRule, IndentSwitchCaseRule, IndentEmptyLoopRule, IndentContinuationLineRule}; use crate::lint::{LintCfg, DMLStyleError}; use crate::analysis::{LocalDMLError, parsing::tree::ZeroRange}; @@ -24,7 +24,8 @@ pub struct CurrentRules { pub indent_closing_brace: IndentClosingBraceRule, pub indent_paren_expr: IndentParenExprRule, pub indent_switch_case: IndentSwitchCaseRule, - pub indent_empty_loop: IndentEmptyLoopRule + pub indent_empty_loop: IndentEmptyLoopRule, + pub indent_continuation_line: IndentContinuationLineRule, } pub fn instantiate_rules(cfg: &LintCfg) -> CurrentRules { @@ -41,7 +42,8 @@ pub fn instantiate_rules(cfg: &LintCfg) -> CurrentRules { indent_closing_brace: IndentClosingBraceRule::from_options(&cfg.indent_closing_brace), indent_paren_expr: IndentParenExprRule { enabled: cfg.indent_paren_expr.is_some() }, indent_switch_case: IndentSwitchCaseRule::from_options(&cfg.indent_switch_case), - indent_empty_loop: IndentEmptyLoopRule::from_options(&cfg.indent_empty_loop) + indent_empty_loop: IndentEmptyLoopRule::from_options(&cfg.indent_empty_loop), + indent_continuation_line: IndentContinuationLineRule::from_options(&cfg.indent_continuation_line), } } diff --git a/src/lint/rules/tests/indentation/continuation_line.rs b/src/lint/rules/tests/indentation/continuation_line.rs new file mode 100644 index 0000000..94af322 --- /dev/null +++ b/src/lint/rules/tests/indentation/continuation_line.rs @@ -0,0 +1,193 @@ +use crate::lint::rules::tests::common::{set_up, robust_assert_snippet as assert_snippet}; +use crate::lint::rules::RuleType; + +static CONTINUATION_LINE_CORRECT: &str = " +method set_irq() { + interrupt_enabled = + irq_enabled(interrupt_device); +} +"; +#[test] +fn continuation_line_correct() { + let rules = set_up(); + assert_snippet(CONTINUATION_LINE_CORRECT, vec![], &rules); +} + +static CONTINUATION_LINE_RETURN_CORRECT: &str = " +method calculate_sum(uint64 a, uint64 b) -> (uint64) { + return (a + b) * (a - b) + + (a * b); +} +"; +#[test] +fn continuation_line_return_correct() { + let rules = set_up(); + assert_snippet(CONTINUATION_LINE_RETURN_CORRECT, vec![], &rules); +} + +static CONTINUATION_LINE_LOCAL_DECLA_CORRECT: &str = " +bank regs { + register example_register size 4 @ 0x00 { + method read() -> (uint64) { + local uint64 value = (this.val + 10) * + (this.val - 5); + return value; + } + } +} +"; +#[test] +fn continuation_line_local_decla_correct() { + let rules = set_up(); + assert_snippet(CONTINUATION_LINE_LOCAL_DECLA_CORRECT, vec![], &rules); +} + +pub static CONTINUATION_LINE_FUNC_CALL_CORRECT: &str = " +method check_hashes(uint64 key, x_range *range) -> (int) { + local const uint8 *digest = get_key(key); + local bool same_hash = memcmp(range->hash_bytes, + digest, SIZE) == 0; + return (same_hash) ? CORRECT : INCORRECT; +} +"; +#[test] +fn continuation_line_func_call_correct() { + let rules = set_up(); + assert_snippet(CONTINUATION_LINE_FUNC_CALL_CORRECT, vec![], &rules); +} + +pub static CONTINUATION_LINE_IN_EACH_CORRECT: &str =" +in each reg_read_write { + param y_val_reg = CONST_X; + is ip_disable; +} +"; +#[test] +fn continuation_line_in_each_correct() { + let rules = set_up(); + assert_snippet(CONTINUATION_LINE_IN_EACH_CORRECT, vec![], &rules); +} + +static CONTINUATION_LINE_INCORRECT: &str = " +method set_irq() { + interrupt_enabled = +irq_enabled(interrupt_device); +} +"; +#[test] +fn continuation_line_incorrect() { + let rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::IN6, + (3, 3, 0, 11), + ); + assert_snippet(CONTINUATION_LINE_INCORRECT, expected_errors, &rules); +} + +pub static CONTINUATION_LINE_BITWISE_INCORRECT: &str = " +method write(uint64 value) { + local uint64 a = value; + local uint64 result = a << + 2; + log info: 'Writing to register, result after left shift = %x', result; +} +"; +#[test] +fn continuation_line_bitwise_incorrect() { + let rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::IN6, + (4, 4, 31, 32), + ); + assert_snippet(CONTINUATION_LINE_BITWISE_INCORRECT, expected_errors, &rules); +} + +pub static CONTINUATION_LINE_PARAM_INCORRECT: &str = " +bank regs { + register control size 4 @ 0x00 { + field status @ [31:3] { + param init_val = 1 << 2 | + 1 << 1; + } + } +} +"; +#[test] +fn continuation_line_param_incorrect() { + let rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::IN6, + (5, 5, 44, 45), + ); + assert_snippet(CONTINUATION_LINE_PARAM_INCORRECT, expected_errors, &rules); +} + +pub static CONTINUATION_LINE_HOOK_INCORRECT: &str = " +hook(int *, bool) +h3; + +template hooktest { + hook() + h2; +} +"; +#[test] +fn continuation_line_hook_incorrect() { + let rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::IN6, + (2, 2, 0, 2), + (6, 6, 16, 18), + ); + assert_snippet(CONTINUATION_LINE_HOOK_INCORRECT, expected_errors, &rules); +} + +pub static CONTINUATION_LINE_IN_EACH_INCORRECT: &str =" +in each +reg_read_write { + param y_val_reg = CONST_X; + is ip_disable; +} +"; +#[test] +fn continuation_line_in_each_incorrect() { + let rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::IN6, + (2, 2, 0, 14), + ); + assert_snippet(CONTINUATION_LINE_IN_EACH_INCORRECT, expected_errors, &rules); +} + +pub static CONTINUATION_LINE_SESSION_INCORRECT: &str =" +session + int max_buffer_index = 1; +session +int last_index_sent = 0; +"; +#[test] +fn continuation_line_session_incorrect() { + let rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::IN6, + (4, 4, 0, 3), + ); + assert_snippet(CONTINUATION_LINE_SESSION_INCORRECT, expected_errors, &rules); +} + +pub static CONTINUATION_LINE_TYPEDEF_INCORRECT: &str =" +typedef + struct { + uint32 data; + uint32 address; +}entry; +"; +#[test] +fn continuation_line_typedef_incorrect() { + let rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::IN6, + (2, 2, 8, 14), + ); + assert_snippet(CONTINUATION_LINE_TYPEDEF_INCORRECT, expected_errors, &rules); +} \ No newline at end of file diff --git a/src/lint/rules/tests/indentation/mod.rs b/src/lint/rules/tests/indentation/mod.rs index ab00ce8..a48b402 100644 --- a/src/lint/rules/tests/indentation/mod.rs +++ b/src/lint/rules/tests/indentation/mod.rs @@ -4,6 +4,7 @@ mod closing_brace; mod paren_expr; mod switch_case; mod empty_loop; +mod continuation_line; use crate::lint::rules::tests::common::assert_snippet; use crate::lint::LintCfg;