diff --git a/CHANGELOG.md b/CHANGELOG.md index 43d48a9..96f5b92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Unknown fields in the lint configuration file are now detected and reported as errors, helping users identify and correct typos or unsupported configuration options. - CLI tool DFA now uses default one-indexed line count for reporting warnings on analyzed files. `--zero-indexed` flag can be set to `true` when executing DFA for using zero-indexed counting if required. +- Added support for spacing linting rules SpReserved, SpBinop, SpTernary, SpPtrDecl and NspPtrDecl. ## 0.9.12 - Added 'simics\_util\_vect' as a known provisional (with no DLS semantics) diff --git a/example_files/example_lint_cfg.json b/example_files/example_lint_cfg.json index b9072af..e1aa021 100644 --- a/example_files/example_lint_cfg.json +++ b/example_files/example_lint_cfg.json @@ -1,10 +1,15 @@ { + "sp_reserved": {}, "sp_brace": {}, "sp_punct": {}, + "sp_binop": {}, + "sp_ternary" : {}, + "sp_ptrdecl": {}, "nsp_funpar": {}, "nsp_inparen": {}, "nsp_unary": {}, "nsp_trailing": {}, + "nsp_ptrdecl": {}, "long_lines": { "max_length": 80 }, "indent_size": { "indentation_spaces": 4 }, "indent_no_tabs": {}, diff --git a/src/analysis/parsing/expression.rs b/src/analysis/parsing/expression.rs index 383e4f3..6450807 100644 --- a/src/analysis/parsing/expression.rs +++ b/src/analysis/parsing/expression.rs @@ -21,6 +21,8 @@ use crate::lint::{DMLStyleError, rules::{spacing::{NspFunparArgs, NspInparenArgs, NspUnaryArgs, + SpBinopArgs, + SpTernaryArgs, SpPunctArgs}, CurrentRules}, AuxParams}; @@ -40,7 +42,7 @@ impl TreeElement for UnaryExpressionContent { create_subs!(&self.operation, &self.expr) } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { - rules.nsp_unary.check(acc, NspUnaryArgs::from_unary_expr(self)); + rules.nsp_unary.check(NspUnaryArgs::from_unary_expr(self), acc); } } @@ -74,7 +76,7 @@ impl TreeElement for PostUnaryExpressionContent { create_subs!(&self.expr, &self.operation) } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { - rules.nsp_unary.check(acc, NspUnaryArgs::from_postunary_expr(self)); + rules.nsp_unary.check(NspUnaryArgs::from_postunary_expr(self), acc); } } @@ -92,6 +94,9 @@ impl TreeElement for BinaryExpressionContent { fn subs(&self) -> TreeElements<'_> { create_subs!(&self.left, &self.operation, &self.right) } + fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { + rules.sp_binop.check(SpBinopArgs::from_binary_expression_content(self), acc); + } } #[derive(Debug, Clone, PartialEq)] @@ -151,6 +156,9 @@ impl TreeElement for TertiaryExpressionContent { create_subs!(&self.left, &self.left_operation, &self.middle, &self.right_operation, &self.right) } + fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { + rules.sp_ternary.check(SpTernaryArgs::from_tertiary_expression_content(self), acc); + } } #[derive(Debug, Clone, PartialEq)] @@ -168,7 +176,7 @@ impl TreeElement for ParenExpressionContent { create_subs!(&self.lparen, &self.expr, &self.rparen) } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { - rules.indent_paren_expr.check(acc, IndentParenExprArgs::from_paren_expression(self)); + rules.indent_paren_expr.check(IndentParenExprArgs::from_paren_expression(self), acc); } } @@ -215,10 +223,10 @@ impl TreeElement for FunctionCallContent { } } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { - rules.nsp_funpar.check(acc, NspFunparArgs::from_function_call(self)); - rules.nsp_inparen.check(acc, NspInparenArgs::from_function_call(self)); - rules.sp_punct.check(acc, SpPunctArgs::from_function_call(self)); - rules.indent_paren_expr.check(acc, IndentParenExprArgs::from_function_call(self)); + rules.nsp_funpar.check(NspFunparArgs::from_function_call(self), acc); + rules.nsp_inparen.check(NspInparenArgs::from_function_call(self), acc); + rules.sp_punct.check(SpPunctArgs::from_function_call(self), acc); + rules.indent_paren_expr.check(IndentParenExprArgs::from_function_call(self), acc); } } @@ -333,7 +341,7 @@ impl TreeElement for CastContent { &self.comma, &self.to, &self.rparen) } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { - rules.indent_paren_expr.check(acc, IndentParenExprArgs::from_cast(self)); + rules.indent_paren_expr.check(IndentParenExprArgs::from_cast(self), acc); } } @@ -430,7 +438,7 @@ impl TreeElement for IndexContent { create_subs!(&self.array, &self.lbracket, &self.index, &self.rbracket) } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { - rules.nsp_inparen.check(acc, NspInparenArgs::from_index(self)); + rules.nsp_inparen.check(NspInparenArgs::from_index(self), acc); } } diff --git a/src/analysis/parsing/misc.rs b/src/analysis/parsing/misc.rs index 1599d9b..2207338 100644 --- a/src/analysis/parsing/misc.rs +++ b/src/analysis/parsing/misc.rs @@ -1,3 +1,5 @@ +use crate::lint::rules::spacing::{NspPtrDeclArgs, SpPtrDeclArgs}; +use crate::lint::{rules::CurrentRules, AuxParams, DMLStyleError}; // © 2024 Intel Corporation // SPDX-License-Identifier: Apache-2.0 and MIT use crate::span::Range; @@ -591,6 +593,10 @@ impl TreeElement for CDeclContent { create_subs!(&self.consttok, &self.base, &self.modifiers, &self.decl) } + fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { + rules.sp_ptrdecl.check(SpPtrDeclArgs::from_cdecl(self), acc); + rules.nsp_ptrdecl.check(NspPtrDeclArgs::from_cdecl(self), acc); + } } // corresponds to cdecl in grammar diff --git a/src/analysis/parsing/statement.rs b/src/analysis/parsing/statement.rs index a02401e..fb44fe3 100644 --- a/src/analysis/parsing/statement.rs +++ b/src/analysis/parsing/statement.rs @@ -3,6 +3,7 @@ use log::error; use crate::lint::rules::indentation::IndentEmptyLoopArgs; +use crate::lint::rules::spacing::SpReservedArgs; use crate::span::Range; use crate::analysis::parsing::lexer::TokenKind; use crate::analysis::parsing::statement; @@ -145,9 +146,9 @@ impl TreeElement for CompoundContent { create_subs!(&self.lbrace, &self.statements, &self.rbrace) } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { - rules.sp_brace.check(acc, SpBracesArgs::from_compound(self)); - rules.indent_code_block.check(acc, IndentCodeBlockArgs::from_compound_content(self, aux.depth)); - rules.indent_closing_brace.check(acc, IndentClosingBraceArgs::from_compound_content(self, aux.depth)); + 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); } fn should_increment_depth(&self) -> bool { true @@ -203,7 +204,7 @@ impl TreeElement for VariableDeclContent { self.decls.ensure_named() } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { - rules.sp_punct.check(acc, SpPunctArgs::from_variable_decl(self)); + rules.sp_punct.check(SpPunctArgs::from_variable_decl(self), acc); } } @@ -435,8 +436,9 @@ impl TreeElement for IfContent { &self.elsebranch) } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { - rules.nsp_inparen.check(acc, NspInparenArgs::from_if(self)); - rules.indent_paren_expr.check(acc, IndentParenExprArgs::from_if(self)); + rules.nsp_inparen.check(NspInparenArgs::from_if(self), acc); + rules.indent_paren_expr.check(IndentParenExprArgs::from_if(self), acc); + rules.sp_reserved.check(SpReservedArgs::from_if(self), acc); } } @@ -548,8 +550,9 @@ impl TreeElement for WhileContent { &self.statement) } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { - rules.indent_paren_expr.check(acc, IndentParenExprArgs::from_while(self)); - rules.indent_empty_loop.check(acc, IndentEmptyLoopArgs::from_while_content(self, aux.depth)); + rules.indent_paren_expr.check(IndentParenExprArgs::from_while(self), acc); + rules.indent_empty_loop.check(IndentEmptyLoopArgs::from_while_content(self, aux.depth), acc); + rules.sp_reserved.check(SpReservedArgs::from_while(self), acc); } } @@ -599,7 +602,7 @@ impl TreeElement for DoContent { &self.semi) } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { - rules.indent_paren_expr.check(acc, IndentParenExprArgs::from_do_while(self)); + rules.indent_paren_expr.check(IndentParenExprArgs::from_do_while(self), acc); } } @@ -864,8 +867,9 @@ impl TreeElement for ForContent { &self.statement) } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { - rules.indent_paren_expr.check(acc, IndentParenExprArgs::from_for(self)); - rules.indent_empty_loop.check(acc, IndentEmptyLoopArgs::from_for_content(self, aux.depth)); + rules.indent_paren_expr.check(IndentParenExprArgs::from_for(self), acc); + rules.indent_empty_loop.check(IndentEmptyLoopArgs::from_for_content(self, aux.depth), acc); + rules.sp_reserved.check(SpReservedArgs::from_for(self), acc); } } @@ -1024,7 +1028,7 @@ impl TreeElement for SwitchCase { } } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { - rules.indent_switch_case.check(acc, IndentSwitchCaseArgs::from_switch_case(self, aux.depth)); + rules.indent_switch_case.check(IndentSwitchCaseArgs::from_switch_case(self, aux.depth), acc); } fn should_increment_depth(&self) -> bool { matches!(self, SwitchCase::Statement(statement) @@ -1114,8 +1118,8 @@ impl TreeElement for SwitchContent { fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { - rules.indent_closing_brace.check(acc, IndentClosingBraceArgs::from_switch_content(self, aux.depth)); - rules.indent_paren_expr.check(acc, IndentParenExprArgs::from_switch(self)); + rules.indent_closing_brace.check(IndentClosingBraceArgs::from_switch_content(self, aux.depth), acc); + rules.indent_paren_expr.check(IndentParenExprArgs::from_switch(self), acc); } } @@ -1285,6 +1289,9 @@ impl TreeElement for AfterContent { &self.callexpression, &self.semi) } + fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { + rules.sp_reserved.check(SpReservedArgs::from_after_content(self), acc); + } } impl Parse for AfterContent { @@ -1611,7 +1618,7 @@ impl TreeElement for ForeachContent { &self.statement) } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { - rules.indent_paren_expr.check(acc, IndentParenExprArgs::from_foreach(self)); + rules.indent_paren_expr.check(IndentParenExprArgs::from_foreach(self), acc); } } @@ -1750,7 +1757,7 @@ impl TreeElement for ExpressionStmtContent { create_subs!(&self.expression, &self.semi) } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { - rules.sp_punct.check(acc, SpPunctArgs::from_expression_stmt(self)); + rules.sp_punct.check(SpPunctArgs::from_expression_stmt(self), acc); } } diff --git a/src/analysis/parsing/structure.rs b/src/analysis/parsing/structure.rs index bda2960..8954007 100644 --- a/src/analysis/parsing/structure.rs +++ b/src/analysis/parsing/structure.rs @@ -16,10 +16,7 @@ use crate::analysis::parsing::parser::{doesnt_understand_tokens, FileParser, Parse, ParseContext, FileInfo}; use crate::analysis::LocalDMLError; -use crate::lint::rules::spacing::{SpBracesArgs, - NspInparenArgs, - NspFunparArgs, - SpPunctArgs}; +use crate::lint::rules::spacing::{NspFunparArgs, NspInparenArgs, SpBracesArgs, SpPunctArgs}; use crate::lint::rules::indentation::{IndentCodeBlockArgs, IndentClosingBraceArgs, IndentParenExprArgs}; use crate::lint::{rules::CurrentRules, AuxParams, DMLStyleError}; use crate::analysis::reference::{Reference, ReferenceKind}; @@ -236,10 +233,10 @@ impl TreeElement for MethodContent { errors } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { - rules.nsp_funpar.check(acc, NspFunparArgs::from_method(self)); - rules.nsp_inparen.check(acc, NspInparenArgs::from_method(self)); - rules.sp_punct.check(acc, SpPunctArgs::from_method(self)); - rules.indent_paren_expr.check(acc, IndentParenExprArgs::from_method(self)); + rules.nsp_funpar.check(NspFunparArgs::from_method(self), acc); + rules.nsp_inparen.check(NspInparenArgs::from_method(self), acc); + rules.sp_punct.check(SpPunctArgs::from_method(self), acc); + rules.indent_paren_expr.check(IndentParenExprArgs::from_method(self), acc); } } @@ -723,9 +720,9 @@ impl TreeElement for ObjectStatementsContent { } } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { - rules.sp_brace.check(acc, SpBracesArgs::from_obj_stmts(self)); - rules.indent_code_block.check(acc, IndentCodeBlockArgs::from_obj_stmts_content(self, aux.depth)); - rules.indent_closing_brace.check(acc, IndentClosingBraceArgs::from_obj_stmts_content(self, aux.depth)); + 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); } fn should_increment_depth(&self) -> bool { matches!(self, ObjectStatementsContent::List(lbrace, list, rbrace) diff --git a/src/analysis/parsing/types.rs b/src/analysis/parsing/types.rs index 18ed84b..7335632 100644 --- a/src/analysis/parsing/types.rs +++ b/src/analysis/parsing/types.rs @@ -55,9 +55,9 @@ impl TreeElement for StructTypeContent { errors } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { - rules.indent_code_block.check(acc, IndentCodeBlockArgs::from_struct_type_content(self, aux.depth)); - rules.indent_closing_brace.check(acc, IndentClosingBraceArgs::from_struct_type_content(self, aux.depth)); - rules.sp_brace.check(acc, SpBracesArgs::from_struct_type_content(self)); + 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.sp_brace.check(SpBracesArgs::from_struct_type_content(self), acc); } fn should_increment_depth(&self) -> bool { true @@ -138,9 +138,9 @@ impl TreeElement for LayoutContent { errors } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { - rules.indent_code_block.check(acc, IndentCodeBlockArgs::from_layout_content(self, aux.depth)); - rules.indent_closing_brace.check(acc, IndentClosingBraceArgs::from_layout_content(self, aux.depth)); - rules.sp_brace.check(acc, SpBracesArgs::from_layout_content(self)); + 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.sp_brace.check(SpBracesArgs::from_layout_content(self), acc); } fn should_increment_depth(&self) -> bool { true @@ -315,9 +315,9 @@ impl TreeElement for BitfieldsContent { errors } fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, aux: AuxParams) { - rules.sp_brace.check(acc, SpBracesArgs::from_bitfields_content(self)); - rules.indent_code_block.check(acc, IndentCodeBlockArgs::from_bitfields_content(self, aux.depth)); - rules.indent_closing_brace.check(acc, IndentClosingBraceArgs::from_bitfields_content(self, aux.depth)); + 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); } fn should_increment_depth(&self) -> bool { true diff --git a/src/lint/features.md b/src/lint/features.md index 665457d..030d884 100644 --- a/src/lint/features.md +++ b/src/lint/features.md @@ -3,12 +3,17 @@ Below are listed the currently supported rules for linting: ## Spacing -- SpBraces, `sp_brace`: spaces around braces (`{` and `}`) -- SpPunct, `sp_punct`: spaces after but not before colon, semicolon and comma -- NspFunpar, `nsp_funpar`: no spaces between a function/method name and its opening parenthesis -- NspInparen, `nsp_inparen`: no spaces immediately inside parentheses or brackets -- NspUnary, `nsp_unary`: no spaces between a unary operator and its operand -- NspTrailing, `nsp_trailing`: no spaces between the last token in a line and the corresponding newline `\n` +- **SpReserved**, `sp_reserved`: spaces around reserved words, such as `if`, `else`, `default`, `size`, `const` and `in`, except when a reserved word is used as an identifier (e.g., `local uint8 *data;`). Currently supported reserved words: `if`, `for` and `while`. +- **SpBinop**, `sp_binop`: spaces around binary operators except for derefencing operators (dot `a.b` and arrow `a->b` ) +- **SpTernary**, `sp_ternary`: spaces around `?` and `:` in ternary conditional expressions +- **SpBraces**, `sp_brace`: spaces around braces (`{` and `}`) +- **SpPunct**, `sp_punct`: spaces after but not before colon, semicolon and comma +- **SpPtrDecl**, `sp_ptrdecl`: spaces between a type and the `*` marking a pointer +- **NspFunpar**, `nsp_funpar`: no spaces between a function/method name and its opening parenthesis +- **NspInparen**, `nsp_inparen`: no spaces immediately inside parentheses or brackets +- **NspUnary**, `nsp_unary`: no spaces between a unary operator and its operand +- **NspPtrDecl**, `nsp_ptrdecl`: no spaces after the `*` marking a pointer in a declaration +- **NspTrailing**, `nsp_trailing`: no spaces between the last token in a line and the corresponding newline `\n` ## Indentation - **IN1**, `indent_size`: Lines are indented a fixed amount of spaces for each indentation level. Defaults to 4, can be set to a custom value by defining field "indentation_spaces" lint configuration [json file](../../example_files/example_lint_cfg.README) diff --git a/src/lint/mod.rs b/src/lint/mod.rs index 96b237d..9229216 100644 --- a/src/lint/mod.rs +++ b/src/lint/mod.rs @@ -8,10 +8,20 @@ use log::{debug, error, trace}; use serde::{Deserialize, Serialize}; use regex::Regex; use rules::{instantiate_rules, CurrentRules, RuleType}; -use rules::{spacing::{SpBraceOptions, SpPunctOptions, NspFunparOptions, - NspInparenOptions, NspUnaryOptions, NspTrailingOptions}, - indentation::{LongLineOptions, IndentSizeOptions, IndentCodeBlockOptions, - IndentNoTabOptions, IndentClosingBraceOptions, IndentParenExprOptions, IndentSwitchCaseOptions, IndentEmptyLoopOptions}, +use rules::{spacing::{SpReservedOptions, + SpBraceOptions, + SpPunctOptions, + SpBinopOptions, + NspFunparOptions, + SpTernaryOptions, + SpPtrDeclOptions, + NspPtrDeclOptions, + NspInparenOptions, + NspUnaryOptions, + NspTrailingOptions}, + indentation::{LongLineOptions, IndentSizeOptions, IndentCodeBlockOptions, + IndentNoTabOptions, IndentClosingBraceOptions, IndentParenExprOptions, + IndentSwitchCaseOptions, IndentEmptyLoopOptions}, }; use crate::analysis::{DMLError, IsolatedAnalysis, LocalDMLError, ZeroRange}; use crate::analysis::parsing::tree::TreeElement; @@ -58,11 +68,21 @@ pub fn maybe_parse_lint_cfg(path: PathBuf, out: &O) -> Option, #[serde(default)] pub sp_brace: Option, #[serde(default)] pub sp_punct: Option, #[serde(default)] + pub sp_binop: Option, + #[serde(default)] + pub sp_ternary: Option, + #[serde(default)] + pub sp_ptrdecl: Option, + #[serde(default)] + pub nsp_ptrdecl: Option, + #[serde(default)] pub nsp_funpar: Option, #[serde(default)] pub nsp_inparen: Option, @@ -112,8 +132,13 @@ fn get_true() -> bool { impl Default for LintCfg { fn default() -> LintCfg { LintCfg { + sp_reserved: Some(SpReservedOptions{}), sp_brace: Some(SpBraceOptions{}), sp_punct: Some(SpPunctOptions{}), + sp_binop: Some(SpBinopOptions{}), + sp_ternary: Some(SpTernaryOptions{}), + sp_ptrdecl: Some(SpPtrDeclOptions{}), + nsp_ptrdecl: Some(NspPtrDeclOptions{}), nsp_funpar: Some(NspFunparOptions{}), nsp_inparen: Some(NspInparenOptions{}), nsp_unary: Some(NspUnaryOptions{}), @@ -189,9 +214,9 @@ pub fn begin_style_check(ast: TopAst, file: &str, rules: &CurrentRules) -> Resul // Per line checks let lines: Vec<&str> = file.lines().collect(); for (row, line) in lines.iter().enumerate() { - rules.indent_no_tabs.check(&mut linting_errors, row, line); - rules.long_lines.check(&mut linting_errors, row, line); - rules.nsp_trailing.check(&mut linting_errors, row, line); + rules.indent_no_tabs.check(row, line, &mut linting_errors); + rules.long_lines.check(row, line, &mut linting_errors); + rules.nsp_trailing.check(row, line, &mut linting_errors); } // Do this _before_ post-process, since post-process may incorrectly @@ -386,41 +411,6 @@ pub mod tests { use std::str::FromStr; use crate::{analysis::{parsing::{parser::FileInfo, structure::{self, TopAst}}, FileSpec}, vfs::TextFile}; - pub static SOURCE: &str = " - dml 1.4; - - bank sb_cr { - group monitor { - - register MKTME_KEYID_MASK { - method get() -> (uint64) { - local uint64 physical_address_mask = mse.srv10nm_mse_mktme.get_key_addr_mask(); - this.Mask.set(physical_address_mask); - this.function_with_args('some_string', - integer, - floater); - return this.val; - } - } - - register TDX_KEYID_MASK { - method get() -> (uint64) { - local uint64 tdx_keyid_mask = mse.srv10nm_mse_tdx.get_key_addr_mask(); - local uint64 some_uint = (is_this_real) ? then_you_might_like_this_value : or_this_one; - this.Mask.set(tdx_keyid_mask); - return this.val; - } - } - } - } - - /* - This is ONEEEE VEEEEEERY LLOOOOOOONG COOOMMMEENTT ON A SINGLEEEE LINEEEEEEEEEEEEEE - and ANOTHEEEER VEEEEEERY LLOOOOOOONG COOOMMMEENTT ON A SINGLEEEE LINEEEEEEEEEEEEEE - */ - - "; - pub fn create_ast_from_snippet(source: &str) -> TopAst { use logos::Logos; use crate::analysis::parsing::lexer::TokenKind; @@ -488,18 +478,6 @@ pub mod tests { assert!(expected_unknowns.is_empty()); // No unknown fields in the expected config } - #[test] - fn test_main() { - use crate::lint::{begin_style_check, LintCfg}; - use crate::lint::rules:: instantiate_rules; - let ast = create_ast_from_snippet(SOURCE); - let cfg = LintCfg::default(); - let rules = instantiate_rules(&cfg); - let lint_errors = begin_style_check(ast, SOURCE, &rules); - assert!(lint_errors.is_ok()); - assert!(!lint_errors.unwrap().is_empty()); - } - #[test] fn test_annotation_parse() { use super::*; @@ -566,7 +544,7 @@ pub mod tests { use crate::lint::rules::indentation::*; use crate::lint::rules::tests::common::{ ExpectedDMLStyleError, - set_up, robust_assert_snippet as assert_snippet + set_up, assert_snippet }; use crate::lint::rules::Rule; use crate::analysis::ZeroRange; diff --git a/src/lint/rules/indentation.rs b/src/lint/rules/indentation.rs index bb6d040..1408cc9 100644 --- a/src/lint/rules/indentation.rs +++ b/src/lint/rules/indentation.rs @@ -59,7 +59,7 @@ impl LongLinesRule { }, } } - pub fn check(&self, acc: &mut Vec, row: usize, line: &str) { + pub fn check(&self, row: usize, line: &str, acc: &mut Vec) { if !self.enabled { return; } let len = line.len().try_into().unwrap(); if len > self.max_length { @@ -95,7 +95,7 @@ pub struct IndentNoTabRule { } impl IndentNoTabRule { - pub fn check(&self, acc: &mut Vec, row: usize, line: &str) { + pub fn check(&self, row: usize, line: &str, acc: &mut Vec) { if !self.enabled { return; } let rowu32 = row.try_into().unwrap(); @@ -197,9 +197,9 @@ impl IndentCodeBlockRule { } } } - pub fn check(&self, acc: &mut Vec, - args: Option) - { + pub fn check(&self, + args: Option, + acc: &mut Vec) { if !self.enabled { return; } let Some(args) = args else { return; }; if args.members_ranges.is_empty() { return; } @@ -340,7 +340,9 @@ impl IndentClosingBraceRule { } } - pub fn check(&self, acc: &mut Vec, args: Option) { + pub fn check(&self, + args: Option, + acc: &mut Vec) { if !self.enabled { return; } let Some(args) = args else { return; }; @@ -489,8 +491,9 @@ impl IndentParenExprArgs { } impl IndentParenExprRule { - pub fn check(&self, acc: &mut Vec, - args: Option) { + pub fn check(&self, + args: Option, + acc: &mut Vec) { if !self.enabled { return; } let Some(args) = args else { return; }; let expected_line_start = args.lparen.col_start.0 + 1; @@ -573,9 +576,9 @@ impl IndentSwitchCaseRule { } } } - pub fn check(&self, acc: &mut Vec, - args: Option) - { + pub fn check(&self, + args: Option, + acc: &mut Vec) { if !self.enabled { return; } let Some(args) = args else { return; }; if self.indentation_is_not_aligned(args.case_range, args.expected_depth) { @@ -659,9 +662,9 @@ impl IndentEmptyLoopRule { } } } - pub fn check(&self, acc: &mut Vec, - args: Option) - { + pub fn check(&self, + args: Option, + acc: &mut Vec) { if !self.enabled { return; } let Some(args) = args else { return; }; if self.indentation_is_not_aligned(args.semicolon_range, args.expected_depth) || diff --git a/src/lint/rules/mod.rs b/src/lint/rules/mod.rs index b1c234f..aec8549 100644 --- a/src/lint/rules/mod.rs +++ b/src/lint/rules/mod.rs @@ -4,16 +4,29 @@ pub mod indentation; #[cfg(test)] pub mod tests; -use spacing::{SpBracesRule, - SpPunctRule, NspFunparRule, NspInparenRule, - NspUnaryRule, NspTrailingRule}; +use spacing::{NspFunparRule, + NspInparenRule, + NspTrailingRule, + NspUnaryRule, + SpBracesRule, + SpBinopRule, + SpTernaryRule, + SpPtrDeclRule, + NspPtrDeclRule, + SpPunctRule, + SpReservedRule}; use indentation::{LongLinesRule, IndentNoTabRule, IndentCodeBlockRule, IndentClosingBraceRule, IndentParenExprRule, IndentSwitchCaseRule, IndentEmptyLoopRule}; use crate::lint::{LintCfg, DMLStyleError}; use crate::analysis::{LocalDMLError, parsing::tree::ZeroRange}; pub struct CurrentRules { + pub sp_reserved: SpReservedRule, pub sp_brace: SpBracesRule, pub sp_punct: SpPunctRule, + pub sp_binop: SpBinopRule, + pub sp_ternary: SpTernaryRule, + pub sp_ptrdecl: SpPtrDeclRule, + pub nsp_ptrdecl: NspPtrDeclRule, pub nsp_funpar: NspFunparRule, pub nsp_inparen: NspInparenRule, pub nsp_unary: NspUnaryRule, @@ -29,8 +42,13 @@ pub struct CurrentRules { pub fn instantiate_rules(cfg: &LintCfg) -> CurrentRules { CurrentRules { + sp_reserved: SpReservedRule { enabled: cfg.sp_reserved.is_some() }, sp_brace: SpBracesRule { enabled: cfg.sp_brace.is_some() }, sp_punct: SpPunctRule { enabled: cfg.sp_punct.is_some() }, + sp_binop: SpBinopRule { enabled: cfg.sp_binop.is_some() }, + sp_ternary: SpTernaryRule { enabled: cfg.sp_ternary.is_some() }, + sp_ptrdecl: SpPtrDeclRule { enabled: cfg.sp_ptrdecl.is_some() }, + nsp_ptrdecl: NspPtrDeclRule { enabled: cfg.nsp_ptrdecl.is_some() }, nsp_funpar: NspFunparRule { enabled: cfg.nsp_funpar.is_some() }, nsp_inparen: NspInparenRule { enabled: cfg.nsp_inparen.is_some() }, nsp_unary: NspUnaryRule { enabled: cfg.nsp_unary.is_some() }, @@ -64,8 +82,13 @@ pub trait Rule { #[derive(Copy, PartialEq, Debug, Clone, Eq, Hash)] pub enum RuleType { + SpReserved, SpBraces, SpPunct, + SpBinop, + SpTernary, + SpPtrDecl, + NspPtrDecl, NspFunpar, NspInparen, NspUnary, diff --git a/src/lint/rules/spacing.rs b/src/lint/rules/spacing.rs index fcdb57d..a87ba73 100644 --- a/src/lint/rules/spacing.rs +++ b/src/lint/rules/spacing.rs @@ -1,34 +1,146 @@ use itertools::izip; use std::convert::TryInto; use serde::{Deserialize, Serialize}; +use crate::analysis::parsing::lexer::TokenKind; +use crate::analysis::parsing::misc::CDeclContent; use crate::analysis::parsing::types::{BitfieldsContent, LayoutContent, StructTypeContent}; use crate::lint::{rules::{Rule, RuleType}, DMLStyleError}; -use crate::analysis::parsing::tree::{TreeElement, ZeroRange}; -use crate::analysis::parsing::expression::{FunctionCallContent, IndexContent, +use crate::analysis::parsing::tree::{LeafToken, TreeElement, ZeroRange}; +use crate::analysis::parsing::expression::{BinaryExpressionContent, + FunctionCallContent, IndexContent, PostUnaryExpressionContent, + TertiaryExpressionContent, UnaryExpressionContent}; -use crate::analysis::parsing::statement::{CompoundContent, - ExpressionStmtContent, - IfContent, VariableDeclContent}; +use crate::analysis::parsing::statement::{AfterContent, CompoundContent, ExpressionStmtContent, + ForContent, IfContent, VariableDeclContent, + WhileContent}; use crate::analysis::parsing::structure::{MethodContent, ObjectStatementsContent}; use crate::span::{ZeroIndexed, Range}; +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct SpReservedOptions {} + +pub struct SpReservedRule { + pub enabled: bool, +} + +pub struct SpReservedArgs { + before_range: Option, + token_range: ZeroRange, + after_range: ZeroRange, +} + +impl SpReservedArgs { + pub fn from_after_content(node: &AfterContent) -> Vec { + let mut args_list = vec![]; + if let Some(timer) = &node.timer { + args_list.push(SpReservedArgs { + before_range: None, + token_range: node.after.range(), + after_range: timer.range(), + }); + } + args_list + } + pub fn from_if(node: &IfContent) -> Vec { + let mut args_list = vec![]; + + args_list.push(SpReservedArgs { + before_range: None, + token_range: node.iftok.range(), + after_range: node.lparen.range(), + }); + + if let Some((else_tok, elsebranch)) = &node.elsebranch { + args_list.push(SpReservedArgs { + before_range: Some(node.truebranch.range()), + token_range: else_tok.range(), + after_range: elsebranch.range(), + }); + } + + args_list + } + pub fn from_for(node: &ForContent) -> Vec { + let args_list = vec![ + SpReservedArgs { + before_range: None, + token_range: node.fortok.range(), + after_range: node.lparen.range(), + } + ]; + args_list + } + pub fn from_while(node: &WhileContent) -> Vec { + let args_list = vec![ + SpReservedArgs { + before_range: None, + token_range: node.whiletok.range(), + after_range: node.lparen.range(), + } + ]; + args_list + } +} + +impl SpReservedRule { + pub fn check(&self, + args: Vec, + acc: &mut Vec) { + if !self.enabled { return; } + for arg in args { + if let Some(before_range) = &arg.before_range { + if (before_range.row_end == arg.token_range.row_start) + && (before_range.col_end == arg.token_range.col_start) { + acc.push( + self.create_err(Range::combine( + *before_range, arg.token_range + )) + ); + } + } + if (arg.token_range.row_end == arg.after_range.row_start) + && (arg.token_range.col_end == arg.after_range.col_start) { + acc.push( + self.create_err(Range::combine( + arg.token_range, arg.after_range + )) + ); + } + } + } +} + +impl Rule for SpReservedRule { + fn name() -> &'static str { + "sp_reserved" + } + fn description() -> &'static str { + "Missing space around reserved words" + } + fn get_rule_type() -> RuleType { + RuleType::SpReserved + } +} + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct SpBraceOptions {} pub struct SpBracesRule { pub enabled: bool, } + pub struct SpBracesArgs { body_start: ZeroRange, body_end: ZeroRange, lbrace: ZeroRange, rbrace: ZeroRange, } + impl SpBracesArgs { pub fn from_compound(node: &CompoundContent) -> Option { if node.statements.is_empty() { @@ -97,8 +209,9 @@ impl SpBracesArgs { } impl SpBracesRule { - pub fn check(&self, acc: &mut Vec, - ranges: Option) { + pub fn check(&self, + ranges: Option, + acc: &mut Vec) { if !self.enabled { return; } if let Some(location) = ranges { if (location.lbrace.row_end == location.body_start.row_start) @@ -125,17 +238,147 @@ impl Rule for SpBracesRule { } } +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct SpBinopOptions {} + +pub struct SpBinopRule { + pub enabled: bool, +} + +pub struct SpBinopArgs { + left: ZeroRange, + operator: ZeroRange, + right: ZeroRange, +} + +impl SpBinopArgs { + pub fn from_binary_expression_content(node: &BinaryExpressionContent) -> Option { + Some(SpBinopArgs { + left: node.left.range(), + operator: node.operation.range(), + right: node.right.range(), + }) + } +} + +impl SpBinopRule { + pub fn check(&self, + ranges: Option, + acc: &mut Vec) { + if !self.enabled { return; } + if let Some(location) = ranges { + if (location.left.row_end == location.operator.row_start) + && (location.left.col_end == location.operator.col_start) { + acc.push(self.create_err(location.left)); + } + if (location.right.row_start == location.operator.row_end) + && (location.operator.col_end == location.right.col_start) { + + acc.push(self.create_err(location.right)); + } + } + } +} + +impl Rule for SpBinopRule { + fn name() -> &'static str { + "sp_binop" + } + fn description() -> &'static str { + "Missing space around binary operator" + } + fn get_rule_type() -> RuleType { + RuleType::SpBinop + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct SpTernaryOptions {} + +pub struct SpTernaryRule { + pub enabled: bool, +} + +pub struct SpTernaryArgs { + left: ZeroRange, + left_op: ZeroRange, + middle: ZeroRange, + right_op: ZeroRange, + right: ZeroRange, +} + +impl SpTernaryArgs { + pub fn from_tertiary_expression_content(node: &TertiaryExpressionContent) -> Option { + Some(SpTernaryArgs { + left: node.left.range(), + left_op: node.left_operation.range(), + middle: node.middle.range(), + right_op: node.right_operation.range(), + right: node.right.range(), + }) + } +} + +fn no_gap(left: ZeroRange, right: ZeroRange) -> bool { + left.row_end == right.row_start + && left.col_end == right.col_start +} + +impl SpTernaryRule { + pub fn check(&self, + ranges: Option, + acc: &mut Vec) { + if !self.enabled { return; } + if let Some(SpTernaryArgs { left, left_op, middle, right_op, right }) = ranges { + if no_gap(left, left_op) { + acc.push(self.create_err( + ZeroRange::combine(left, left_op) + )); + } + if no_gap(left_op, middle) { + acc.push(self.create_err( + ZeroRange::combine(left_op, middle) + )); + } + if no_gap(middle, right_op) { + acc.push(self.create_err( + ZeroRange::combine(middle, right_op) + )); + } + if no_gap(right_op, right) { + acc.push(self.create_err( + ZeroRange::combine(right_op, right) + )); + } + } + } +} + +impl Rule for SpTernaryRule { + fn name() -> &'static str { + "sp_ternary" + } + fn description() -> &'static str { + "Missing space around ? or : in conditional expression" + } + fn get_rule_type() -> RuleType { + RuleType::SpTernary + } +} + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct SpPunctOptions {} pub struct SpPunctRule { pub enabled: bool, } + pub struct SpPunctArgs { before_range_list: Vec>, punct_range_list: Vec>, after_range_list: Vec>>, } + impl SpPunctArgs { pub fn from_method(node: &MethodContent) -> Option { let mut before_range_list = vec![]; @@ -225,8 +468,9 @@ impl SpPunctArgs { } impl SpPunctRule { - pub fn check(&self, acc: &mut Vec, - ranges: Option) { + pub fn check(&self, + ranges: Option, + acc: &mut Vec) { if !self.enabled { return; } if let Some(args) = ranges { for (before_range, punct_range, after_range) in @@ -268,14 +512,17 @@ impl Rule for SpPunctRule { RuleType::SpPunct } } + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct NspFunparOptions {} pub struct NspFunparRule { pub enabled: bool, } - // Single ZeroRange required as input for this rule + +// Single ZeroRange required as input for this rule pub type NspFunparArgs = ZeroRange; + impl NspFunparArgs { fn found_gap(fn_name: &ZeroRange, lparen: &ZeroRange) -> Option { @@ -297,16 +544,18 @@ impl NspFunparArgs { Self::found_gap(&node.fun.range(), &node.lparen.range()) } } + impl NspFunparRule { pub fn check(&self, - acc: &mut Vec, - range: Option) { + range: Option, + acc: &mut Vec) { if !self.enabled { return; } if let Some(gap) = range { acc.push(self.create_err(gap)); } } } + impl Rule for NspFunparRule { fn name() -> &'static str { "nsp_funpar" @@ -319,19 +568,20 @@ impl Rule for NspFunparRule { } } - #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct NspInparenOptions {} pub struct NspInparenRule { pub enabled: bool, } + pub struct NspInparenArgs { opening: ZeroRange, content_start: ZeroRange, content_end: ZeroRange, closing: ZeroRange, } + impl NspInparenArgs { pub fn from_method(node: &MethodContent) -> Option { let content_start_range; @@ -385,10 +635,11 @@ impl NspInparenArgs { }) } } + impl NspInparenRule { pub fn check(&self, - acc: &mut Vec, - ranges: Option) { + ranges: Option, + acc: &mut Vec) { if !self.enabled { return; } if let Some(location) = ranges { if (location.opening.row_end == location.content_start.row_start) @@ -408,6 +659,7 @@ impl NspInparenRule { } } } + impl Rule for NspInparenRule { fn name() -> &'static str { "nsp_inparen" @@ -426,8 +678,10 @@ pub struct NspUnaryOptions {} pub struct NspUnaryRule { pub enabled: bool, } + // Single ZeroRange required as input for this rule pub type NspUnaryArgs = ZeroRange; + impl NspUnaryArgs { pub fn from_unary_expr(node: &UnaryExpressionContent) -> Option { @@ -448,16 +702,18 @@ impl NspUnaryArgs { } else { None } } } + impl NspUnaryRule { pub fn check(&self, - acc: &mut Vec, - range: Option) { + range: Option, + acc: &mut Vec) { if !self.enabled { return; } if let Some(gap) = range { acc.push(self.create_err(gap)); } } } + impl Rule for NspUnaryRule { fn name() -> &'static str { "nsp_unary" @@ -476,8 +732,9 @@ pub struct NspTrailingOptions {} pub struct NspTrailingRule { pub enabled: bool, } + impl NspTrailingRule { - pub fn check(&self, acc: &mut Vec, row: usize, line: &str) { + pub fn check(&self, row: usize, line: &str, acc: &mut Vec) { if !self.enabled { return; } let len = line.len().try_into().unwrap(); let row_u32 = row.try_into().unwrap(); @@ -490,6 +747,7 @@ impl NspTrailingRule { } } } + impl Rule for NspTrailingRule { fn name() -> &'static str { "nsp_trailing" @@ -501,3 +759,122 @@ impl Rule for NspTrailingRule { RuleType::NspTrailing } } + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct SpPtrDeclOptions {} + +pub struct SpPtrDeclRule { + pub enabled: bool, +} + +pub struct SpPtrDeclArgs { + type_name_range: ZeroRange, + operator_ranges: Vec +} + +fn extract_operator_ranges_from_cdecl(node: &CDeclContent) -> Vec { + node.modifiers.iter() + .filter_map(|m| { + if let LeafToken::Actual(token) = m { + if token.kind == TokenKind::Multiply { + return Some(m.range()); + } + } + None + }).collect() +} + +impl SpPtrDeclArgs { + pub fn from_cdecl(node: &CDeclContent) -> Option { + // Check if node has a multiply token inside its modifiers + let operator_ranges: Vec = extract_operator_ranges_from_cdecl(node); + Some(SpPtrDeclArgs { + type_name_range: node.base.range(), + operator_ranges, + }) + } +} + +fn has_space_between(range_left: &ZeroRange, + range_right: &ZeroRange) -> bool { + !((range_left.row_end == range_right.row_start) + && (range_left.col_end == range_right.col_start)) +} + +impl SpPtrDeclRule { + pub fn check(&self, + ranges: Option, + acc: &mut Vec) { + if !self.enabled { return; } + if let Some(ranges) = ranges { + if ranges.operator_ranges.iter().any(|op_range| { + !has_space_between(&ranges.type_name_range, op_range) + }) { + acc.push(self.create_err(ranges.type_name_range)); + } + } + } +} + +impl Rule for SpPtrDeclRule { + fn name() -> &'static str { + "sp_ptrdecl" + } + fn description() -> &'static str { + "There should be a space between type and * marking a pointer" + } + fn get_rule_type() -> RuleType { + RuleType::SpPtrDecl + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct NspPtrDeclOptions {} + +pub struct NspPtrDeclRule { + pub enabled: bool, +} + +pub struct NspPtrDeclArgs { + rightmost_multiply: Option, + identifier_range: ZeroRange +} + +impl NspPtrDeclArgs { + pub fn from_cdecl(node: &CDeclContent) -> Option { + // Check if node has a multiply token inside its modifiers + let operator_ranges: Vec = extract_operator_ranges_from_cdecl(node); + let rightmost_multiply: Option = operator_ranges.last().cloned(); + Some(NspPtrDeclArgs { + rightmost_multiply, + identifier_range: node.decl.range() + }) + } +} + +impl NspPtrDeclRule { + pub fn check(&self, + ranges: Option, + acc: &mut Vec) { + if !self.enabled { return; } + if let Some(ranges) = ranges { + if let Some(op_range) = ranges.rightmost_multiply { + if has_space_between(&op_range, &ranges.identifier_range) { + acc.push(self.create_err(ranges.identifier_range)); + } + } + } + } +} + +impl Rule for NspPtrDeclRule { + fn name() -> &'static str { + "nsp_ptrdecl" + } + fn description() -> &'static str { + "There should be no space after the * marking a pointer in a declaration" + } + fn get_rule_type() -> RuleType { + RuleType::NspPtrDecl + } +} diff --git a/src/lint/rules/tests/common.rs b/src/lint/rules/tests/common.rs index eace602..812aab5 100644 --- a/src/lint/rules/tests/common.rs +++ b/src/lint/rules/tests/common.rs @@ -37,14 +37,7 @@ pub fn run_linter(source_code: &str, rules: &CurrentRules) begin_style_check(ast, source_code, rules) } -pub fn assert_snippet(source_code: &str, expected_errors: usize, rules: &CurrentRules) { - let lint_errors = run_linter(source_code, rules); - assert!(lint_errors.is_ok()); - assert_eq!(lint_errors.clone().unwrap().len(), expected_errors, - "{:#?}", lint_errors); -} - -pub fn robust_assert_snippet(source_code: &str, expected_errors: Vec, rules: &CurrentRules) { +pub fn assert_snippet(source_code: &str, expected_errors: Vec, rules: &CurrentRules) { let lint_errors = run_linter(source_code, rules).unwrap(); assert_eq!(lint_errors.len(), expected_errors.len(), "{:#?}", lint_errors); diff --git a/src/lint/rules/tests/indentation/closing_brace.rs b/src/lint/rules/tests/indentation/closing_brace.rs index 0ca5f27..45116ee 100644 --- a/src/lint/rules/tests/indentation/closing_brace.rs +++ b/src/lint/rules/tests/indentation/closing_brace.rs @@ -1,4 +1,4 @@ -use crate::lint::rules::tests::common::{set_up, robust_assert_snippet as assert_snippet}; +use crate::lint::rules::tests::common::{set_up, assert_snippet}; use crate::lint::rules::RuleType; static BASIC_COMPOUND_CORRECT: &str = " @@ -8,8 +8,6 @@ method my_method() { } } "; - - #[test] fn basic_compound_correct() { let rules = set_up(); @@ -22,7 +20,6 @@ method my_method() { return; } } "; - #[test] fn closing_brace_not_first_in_line_incorrect() { let rules = set_up(); @@ -38,7 +35,6 @@ method my_method() { if (true) { return; } } "; - #[test] fn closing_and_open_brace_on_same_line_correct() { let rules = set_up(); @@ -51,7 +47,6 @@ method my_method() { return; } }"; - #[test] fn closing_brace_not_deindented_incorrect() { let rules = set_up(); @@ -69,7 +64,6 @@ method my_method() { } } "; - #[test] fn closing_brace_overindented_incorrect() { let rules = set_up(); @@ -90,7 +84,6 @@ method my_method() { return; break; } }"; - #[test] fn closing_brace_not_first_switch_incorrect() { let rules = set_up(); @@ -105,7 +98,6 @@ static CLOSING_BRACE_NOT_FIRST_STRUCT_INCORRECT: &str = " typedef struct { int x; } mystruct_t; "; - #[test] fn closing_brace_not_first_struct_incorrect() { let rules = set_up(); @@ -120,7 +112,6 @@ static CLOSING_BRACE_NOT_FIRST_LAYOUT_INCORRECT: &str = " typedef layout \"little-endian\" { uint8 cmd_code; } mylayout_t; "; - #[test] fn closing_brace_not_first_layout_incorrect() { let rules = set_up(); @@ -138,7 +129,6 @@ typedef layout \"little-endian\" { uint1 always_zero @ [0:0]; } dst_slave; } mylayout_t; "; - #[test] fn closing_brace_not_first_bitfield_incorrect() { let rules = set_up(); @@ -156,7 +146,6 @@ method my_method() { case 2: { return; } } }"; - #[test] fn switch_case_same_line_correct() { let rules = set_up(); diff --git a/src/lint/rules/tests/indentation/code_block.rs b/src/lint/rules/tests/indentation/code_block.rs index b298c90..d2a027c 100644 --- a/src/lint/rules/tests/indentation/code_block.rs +++ b/src/lint/rules/tests/indentation/code_block.rs @@ -1,4 +1,4 @@ -use crate::lint::rules::tests::common::{set_up, robust_assert_snippet as assert_snippet}; +use crate::lint::rules::tests::common::{set_up, assert_snippet}; use crate::lint::rules::RuleType; static FUNCTION_CONTENTS_INDENT_CORRECT: &str = " @@ -187,7 +187,6 @@ method control_device() { } } "; - #[test] fn cond_structure_indent_incorrect() { let rules = set_up(); diff --git a/src/lint/rules/tests/indentation/empty_loop.rs b/src/lint/rules/tests/indentation/empty_loop.rs index a2df0ad..3665abd 100644 --- a/src/lint/rules/tests/indentation/empty_loop.rs +++ b/src/lint/rules/tests/indentation/empty_loop.rs @@ -1,4 +1,4 @@ -use crate::lint::rules::tests::common::{set_up, robust_assert_snippet as assert_snippet}; +use crate::lint::rules::tests::common::{set_up, assert_snippet}; use crate::lint::rules::RuleType; static EMPTY_LOOP_INCORRECT: &str = " diff --git a/src/lint/rules/tests/indentation/mod.rs b/src/lint/rules/tests/indentation/mod.rs index ab00ce8..4eb63c9 100644 --- a/src/lint/rules/tests/indentation/mod.rs +++ b/src/lint/rules/tests/indentation/mod.rs @@ -6,6 +6,7 @@ mod switch_case; mod empty_loop; use crate::lint::rules::tests::common::assert_snippet; +use crate::lint::rules::RuleType; use crate::lint::LintCfg; use crate::lint::LongLineOptions; use crate::lint::rules::instantiate_rules; @@ -20,15 +21,23 @@ param some_parameter_name_in_this_device = some_long_name_bank.some_long_name_gr fn line_length_incorrect() { let mut cfg = LintCfg::default(); let mut rules = instantiate_rules(&cfg); - assert_snippet(LINE_LENGTH_INCORRECT, 1, &rules); + let expected_errors = define_expected_errors!( + RuleType::LL1, + (1, 1, 80, 103), + ); + assert_snippet(LINE_LENGTH_INCORRECT, expected_errors, &rules); // Test rule disable cfg.long_lines = None; rules = instantiate_rules(&cfg); - assert_snippet(LINE_LENGTH_INCORRECT, 0, &rules); + assert_snippet(LINE_LENGTH_INCORRECT, vec![], &rules); // Test lower max_length cfg.long_lines = Some(LongLineOptions{ max_length: (LINE_LENGTH_INCORRECT.len()-3).try_into().unwrap() }); rules = instantiate_rules(&cfg); - assert_snippet(LINE_LENGTH_INCORRECT, 1, &rules); + let expected_errors = define_expected_errors!( + RuleType::LL1, + (1, 1, 102, 103), + ); + assert_snippet(LINE_LENGTH_INCORRECT, expected_errors, &rules); } diff --git a/src/lint/rules/tests/indentation/no_tabs.rs b/src/lint/rules/tests/indentation/no_tabs.rs index d75255a..8e01034 100644 --- a/src/lint/rules/tests/indentation/no_tabs.rs +++ b/src/lint/rules/tests/indentation/no_tabs.rs @@ -1,4 +1,4 @@ -use crate::lint::rules::tests::common::{set_up, robust_assert_snippet as assert_snippet}; +use crate::lint::rules::tests::common::{set_up, assert_snippet}; use crate::lint::rules::RuleType; static USING_TAB_INDENT_INCORRECT: &str = " diff --git a/src/lint/rules/tests/indentation/paren_expr.rs b/src/lint/rules/tests/indentation/paren_expr.rs index 85440a8..762b6dc 100644 --- a/src/lint/rules/tests/indentation/paren_expr.rs +++ b/src/lint/rules/tests/indentation/paren_expr.rs @@ -1,4 +1,4 @@ -use crate::lint::rules::tests::common::{set_up, robust_assert_snippet as assert_snippet}; +use crate::lint::rules::tests::common::{set_up, assert_snippet}; use crate::lint::rules::RuleType; // A continuation line that is broken inside a parenthesized expression @@ -136,7 +136,6 @@ method callback() { } } "; - #[test] fn if_paren_correct() { let rules = set_up(); @@ -371,7 +370,6 @@ param result = ( + 1); "; - #[test] fn nested_paren_expr_incorrect(){ let rules = set_up(); diff --git a/src/lint/rules/tests/indentation/switch_case.rs b/src/lint/rules/tests/indentation/switch_case.rs index 4345045..f095923 100644 --- a/src/lint/rules/tests/indentation/switch_case.rs +++ b/src/lint/rules/tests/indentation/switch_case.rs @@ -1,4 +1,4 @@ -use crate::lint::rules::tests::common::{set_up, robust_assert_snippet as assert_snippet}; +use crate::lint::rules::tests::common::{set_up, assert_snippet}; use crate::lint::rules::RuleType; static SWITCH_CASE_INDENT_CORRECT: &str = " diff --git a/src/lint/rules/tests/spacing/mod.rs b/src/lint/rules/tests/spacing/mod.rs index 302e0a8..e3cdc14 100644 --- a/src/lint/rules/tests/spacing/mod.rs +++ b/src/lint/rules/tests/spacing/mod.rs @@ -1,113 +1,15 @@ -use crate::lint::rules::tests::common::assert_snippet; -use crate::lint::rules::instantiate_rules; -use crate::lint::LintCfg; +mod nsp_funpar; +mod nsp_inparen; +mod nsp_ptrdecl; +mod nsp_trailing; +mod nsp_unary; +mod sp_braces; +mod sp_ptrdecl; +mod sp_punct; +mod sp_reserved; +mod sp_binop; +mod sp_ternary; -// Put whitespace (space or newline): -// SP.reserved around reserved words, such as if, else, default, -// size, const and in, except when a reserved word is used as an identifier -// (e.g., local uint8 *data;) -#[allow(dead_code)] -static SP_RESERVED: &str = " -method this_is_some_method() { -local int this_some_integer = 0x666; -if(this_some_integer == 0x666) - return; -} -"; - -// SP.braces around braces ({ and }) -static SP_BRACES: &str = " -method this_is_some_method() {return 0;} - -method this_is_empty_method() { } - -bank pcie_config {register command {field mem { - method pcie_write(uint64 value) { - if (value != 0) {value = value + 1;} - default(value); - map_memory_alt(); - } -} -} -} -"; -#[test] -fn style_check_sp_braces() { - let mut cfg = LintCfg::default(); - let mut rules = instantiate_rules(&cfg); - assert_snippet(SP_BRACES, 6, &rules); - // Test rule disable - cfg.sp_brace = None; - rules = instantiate_rules(&cfg); - assert_snippet(SP_BRACES, 0, &rules); - -} - -static SP_BRACES_02: &str = " -typedef struct {uint16 idx;} hqm_cq_list_release_ctx_t; - -typedef layout \"little-endian\" {bitfields 1 {uint1 cq @ [0:0];} byte;} q_t; -"; -#[test] -fn style_check_sp_braces_02() { - let mut cfg = LintCfg::default(); - let mut rules = instantiate_rules(&cfg); - assert_snippet(SP_BRACES_02, 6, &rules); - // Test rule disable - cfg.sp_brace = None; - rules = instantiate_rules(&cfg); - assert_snippet(SP_BRACES_02, 0, &rules); - -} - -// SP.binop around binary operators except the dereferencing operators dot -// (a.b) and arrow (a->b) -#[allow(dead_code)] -static SP_BINOP: &str = " -method this_is_some_method() { -local int this_some_integer = 5+6; -if (this_some_integer == 0x666) - this_some_integer = this.val; -} -"; - -// SP.ternary around ? and : in the ternary ?: operator -#[allow(dead_code)] -static SP_TERNARY: &str = " -method this_is_some_method(bool flag) { -local int this_some_integer = (flag?5:7)); -} -"; - -// SP.punct after but not before colon, semicolon and comma -#[allow(dead_code)] -static SP_PUNCT: &str = " -method this_is_some_method(bool flag ,int8 var) { - local int this_some_integer = 0x666 ; - if(this_some_integer == 0x666) - return; - some_func(arg1 ,arg2 ,arg3 ,arg4); -} -"; -#[test] -fn style_check_sp_punct_rule() { - let mut cfg = LintCfg::default(); - let mut rules = instantiate_rules(&cfg); - assert_snippet(SP_PUNCT, 9, &rules); - // Test rule disable - cfg.sp_punct = None; - rules = instantiate_rules(&cfg); - assert_snippet(SP_PUNCT, 0, &rules); -} - -// SP.ptrdecl between a type and the * marking a pointer -#[allow(dead_code)] -static SP_PTRDECL: &str = " -method this_is_some_method(conf_object_t* dummy_obj) { -if(!dummy_obj) - return; -} -"; // SP.comment around the comment delimiters //, /* and **/ #[allow(dead_code)] @@ -115,96 +17,8 @@ static SP_COMMENT: &str = " /*Function documentation*/ method this_is_some_method(conf_object_t *dummy_obj) { -if(!dummy_obj)//Not null - return; -} -"; - -// There should be no space: -// NSP.funpar between a function/method name and its opening parenthesis -static NSP_FUNPAR: &str = " -method this_is_some_method (conf_object_t *dummy_obj) { - if(!dummy_obj) - other_method_called (); -} -"; -#[test] -fn style_check_nsp_funpar() { - let mut cfg = LintCfg::default(); - let mut rules = instantiate_rules(&cfg); - assert_snippet(NSP_FUNPAR, 2, &rules); - // Test rule disable - cfg.nsp_funpar = None; - rules = instantiate_rules(&cfg); - assert_snippet(NSP_FUNPAR, 0, &rules); -} - -// NSP.inparen immediately inside parentheses or brackets -static NSP_INPAREN: &str = " -method this_is_some_method( conf_object_t *dummy_obj ) { - if( !dummy_obj[ 0 ] ) - return; -} -"; -#[test] -fn style_check_nsp_inparen() { - let mut cfg = LintCfg::default(); - let mut rules = instantiate_rules(&cfg); - assert_snippet(NSP_INPAREN, 6, &rules); - // Test rule disable - cfg.nsp_inparen = None; - rules = instantiate_rules(&cfg); - assert_snippet(NSP_INPAREN, 0, &rules); -} - -// NSP.unary between a unary operator and its operand -static NSP_UNARY: &str = " -method this_is_some_method(conf_object_t *dummy_obj) { - if(! dummy_obj) - return; - local uint64 p = & dummy_obj; - p ++; - -- p; - local int64 neg = - 1; -} -"; -#[test] -fn style_check_nsp_unary() { - let mut cfg = LintCfg::default(); - let mut rules = instantiate_rules(&cfg); - assert_snippet(NSP_UNARY, 5, &rules); - // Test rule disable - cfg.nsp_unary = None; - rules = instantiate_rules(&cfg); - assert_snippet(NSP_UNARY, 0, &rules); -} - -// NSP.ptrdecl after the * marking a pointer in a declaration -#[allow(dead_code)] -static NSP_PTRDECL: &str = " -method this_is_some_method(conf_object_t * dummy_obj) { -if(!dummy_obj) +if (!dummy_obj)//Not null return; } "; -// Adding trailing whitespace removal to spacing rules: -// no whitespaces should be left at the end of a line between the last token -// and the newline \n -static NSP_TRAILING: &str = " -method this_is_some_method(int64 num) { - local int this_some_integer = 0x666; - if (this_some_integer == 0x666) - return; -} -"; -#[test] -fn style_check_nsp_trailing() { - let mut cfg = LintCfg::default(); - let mut rules = instantiate_rules(&cfg); - assert_snippet(NSP_TRAILING, 4, &rules); - // Test rule disable - cfg.nsp_trailing = None; - rules = instantiate_rules(&cfg); - assert_snippet(NSP_TRAILING, 0, &rules); -} diff --git a/src/lint/rules/tests/spacing/nsp_funpar.rs b/src/lint/rules/tests/spacing/nsp_funpar.rs new file mode 100644 index 0000000..25e5f92 --- /dev/null +++ b/src/lint/rules/tests/spacing/nsp_funpar.rs @@ -0,0 +1,36 @@ +use crate::lint::rules::tests::common::{set_up, assert_snippet}; +use crate::lint::rules::RuleType; + +// There should be no space: +// NSP.funpar between a function/method name and its opening parenthesis +static NO_SPACE_METHOD_FUNC_INCORRECT: &str = " +method this_is_some_method (conf_object_t *dummy_obj) { + if (!dummy_obj) + other_method_called (); +} +"; +#[test] +fn no_space_method_func_incorrect() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::NspFunpar, + (1, 1, 26, 27), + (3, 3, 27, 28), + ); + assert_snippet(NO_SPACE_METHOD_FUNC_INCORRECT, expected_errors, &rules); + // Test rule disable + rules.nsp_funpar.enabled = false; + assert_snippet(NO_SPACE_METHOD_FUNC_INCORRECT, vec![], &rules); +} + +static NO_SPACE_METHOD_FUNC_CORRECT: &str = " +method this_is_some_method(conf_object_t *dummy_obj) { + if (!dummy_obj) + other_method_called(); +} +"; +#[test] +fn no_space_method_func_correct() { + let rules = set_up(); + assert_snippet(NO_SPACE_METHOD_FUNC_CORRECT, vec![], &rules); +} \ No newline at end of file diff --git a/src/lint/rules/tests/spacing/nsp_inparen.rs b/src/lint/rules/tests/spacing/nsp_inparen.rs new file mode 100644 index 0000000..a5160c4 --- /dev/null +++ b/src/lint/rules/tests/spacing/nsp_inparen.rs @@ -0,0 +1,40 @@ +use crate::lint::rules::tests::common::{set_up, assert_snippet}; +use crate::lint::rules::RuleType; + +// NSP.inparen immediately inside parentheses or brackets +static NO_SPACE_INPAREN_METHOD_FUNC_INDEX_INCORRECT: &str = " +method this_is_some_method( conf_object_t *dummy_obj ) { + if ( !dummy_obj[ 0 ] ) + return; +} +"; +#[test] +fn no_space_inparen_method_func_index_incorrect() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::NspInparen, + (1, 1, 27, 28), + (1, 1, 52, 53), + (2, 2, 8, 9), + (2, 2, 24, 25), + (2, 2, 20, 21), + (2, 2, 22, 23), + ); + assert_snippet(NO_SPACE_INPAREN_METHOD_FUNC_INDEX_INCORRECT, expected_errors, &rules); + // Test rule disable + rules.nsp_inparen.enabled = false; + assert_snippet(NO_SPACE_INPAREN_METHOD_FUNC_INDEX_INCORRECT, vec![], &rules); +} + +// NSP.inparen immediately inside parentheses or brackets +static NO_SPACE_INPAREN_METHOD_FUNC_INDEX_CORRECT: &str = " +method this_is_some_method(conf_object_t *dummy_obj) { + if (!dummy_obj[0]) + return; +} +"; +#[test] +fn no_space_inparen_method_func_index_correct() { + let rules = set_up(); + assert_snippet(NO_SPACE_INPAREN_METHOD_FUNC_INDEX_CORRECT, vec![], &rules); +} \ No newline at end of file diff --git a/src/lint/rules/tests/spacing/nsp_ptrdecl.rs b/src/lint/rules/tests/spacing/nsp_ptrdecl.rs new file mode 100644 index 0000000..ca81cc8 --- /dev/null +++ b/src/lint/rules/tests/spacing/nsp_ptrdecl.rs @@ -0,0 +1,76 @@ +use crate::lint::rules::tests::common::{set_up, assert_snippet}; +use crate::lint::rules::RuleType; + +static NSP_PTRDECL_CORRECT: &str = " +method this_is_some_method(conf_object_t *dummy_obj) { + if (!dummy_obj) { + return; + } +}"; +#[test] +fn nsp_ptrdecl_correct() { + let mut rules = set_up(); + assert_snippet(NSP_PTRDECL_CORRECT, vec![], &rules); + // Test rule disable + rules.nsp_ptrdecl.enabled = false; + assert_snippet(NSP_PTRDECL_CORRECT, vec![], &rules); +} + +static NSP_PTRDECL_INCORRECT_PARAM: &str = " +method this_is_some_method(conf_object_t * dummy_obj) { + if (!dummy_obj) { + return; + } +}"; +#[test] +fn nsp_ptrdcl_incorrect_param() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::NspPtrDecl, + (1, 1, 43, 52), + ); + assert_snippet(NSP_PTRDECL_INCORRECT_PARAM, expected_errors, &rules); + // Test rule disable + rules.nsp_ptrdecl.enabled = false; + assert_snippet(NSP_PTRDECL_INCORRECT_PARAM, vec![], &rules); +} + +static NSP_PTRDECL_INCORRECT_STATEMENT: &str = " +method this_is_some_method(conf_object_t *dummy_obj) { + local conf_object_t * conf = dummy_obj; + if (!conf) { + return; + } +}"; +#[test] +fn nsp_ptrdecl_incorrect_statement() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::NspPtrDecl, + (2, 2, 26, 30), + ); + assert_snippet(NSP_PTRDECL_INCORRECT_STATEMENT, expected_errors, &rules); + // Test rule disable + rules.nsp_ptrdecl.enabled = false; + assert_snippet(NSP_PTRDECL_INCORRECT_STATEMENT, vec![], &rules); +} + +static NSP_PTRDECL_MULTIPLE_POINTER_SYMBOLS: &str = " +method this_is_some_method(conf_object_t **dummy_obj) { + local conf_object_t ** conf = dummy_obj; + if (!conf) { + return; + } +}"; +#[test] +fn nsp_ptrdecl_multiple_symbols() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::NspPtrDecl, + (2, 2, 27, 31), + ); + assert_snippet(NSP_PTRDECL_MULTIPLE_POINTER_SYMBOLS, expected_errors, &rules); + // Test rule disable + rules.nsp_ptrdecl.enabled = false; + assert_snippet(NSP_PTRDECL_MULTIPLE_POINTER_SYMBOLS, vec![], &rules); +} \ No newline at end of file diff --git a/src/lint/rules/tests/spacing/nsp_trailing.rs b/src/lint/rules/tests/spacing/nsp_trailing.rs new file mode 100644 index 0000000..83981fe --- /dev/null +++ b/src/lint/rules/tests/spacing/nsp_trailing.rs @@ -0,0 +1,28 @@ +use crate::lint::rules::tests::common::{set_up, assert_snippet}; +use crate::lint::rules::RuleType; + +// Adding trailing whitespace removal to spacing rules: +// no whitespaces should be left at the end of a line between the last token +// and the newline \n +static TRAILING_WHITESPACE_INCORRECT: &str = " +method this_is_some_method(int64 num) { + local int this_some_integer = 0x666; + if (this_some_integer == 0x666) + return; +} +"; +#[test] +fn trailing_whitespace_incorrect() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::NspTrailing, + (2, 2, 40, 51), + (3, 3, 35, 42), + (4, 4, 15, 17), + (5, 5, 1, 4), + ); + assert_snippet(TRAILING_WHITESPACE_INCORRECT, expected_errors, &rules); + // Test rule disable + rules.nsp_trailing.enabled = false; + assert_snippet(TRAILING_WHITESPACE_INCORRECT, vec![], &rules); +} \ No newline at end of file diff --git a/src/lint/rules/tests/spacing/nsp_unary.rs b/src/lint/rules/tests/spacing/nsp_unary.rs new file mode 100644 index 0000000..0a8b8cc --- /dev/null +++ b/src/lint/rules/tests/spacing/nsp_unary.rs @@ -0,0 +1,46 @@ +use crate::lint::rules::tests::common::{set_up, assert_snippet}; +use crate::lint::rules::RuleType; + +// NSP.unary between a unary operator and its operand +static NO_SPACE_UNARY_INCORRECT: &str = " +method this_is_some_method(conf_object_t *dummy_obj) { + if (! dummy_obj) + return; + local uint64 p = & dummy_obj; + p ++; + -- p; + local int64 neg = - 1; +} +"; +#[test] +fn no_space_unary_incorrect() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::NspUnary, + (2, 2, 9, 10), + (4, 4, 22, 23), + (5, 5, 5, 6), + (6, 6, 6, 7), + (7, 7, 23, 24), + ); + assert_snippet(NO_SPACE_UNARY_INCORRECT, expected_errors, &rules); + // Test rule disable + rules.nsp_unary.enabled = false; + assert_snippet(NO_SPACE_UNARY_INCORRECT, vec![], &rules); +} + +static NO_SPACE_UNARY_CORRECT: &str = " +method this_is_some_method(conf_object_t *dummy_obj) { + if (!dummy_obj) + return; + local uint64 p = &dummy_obj; + p++; + --p; + local int64 neg = -1; +} +"; +#[test] +fn no_space_unary_correct() { + let rules = set_up(); + assert_snippet(NO_SPACE_UNARY_CORRECT, vec![], &rules); +} \ No newline at end of file diff --git a/src/lint/rules/tests/spacing/sp_binop.rs b/src/lint/rules/tests/spacing/sp_binop.rs new file mode 100644 index 0000000..3c24028 --- /dev/null +++ b/src/lint/rules/tests/spacing/sp_binop.rs @@ -0,0 +1,77 @@ +use crate::lint::rules::tests::common::{set_up, assert_snippet}; +use crate::lint::rules::RuleType; + +// SP.binop around binary operators except the dereferencing operators dot +// (a.b) and arrow (a->b) +static ARTITHMETIC_OPERATOR_CORRECT: &str = " +method this_is_some_method() { + local int this_some_integer = 5 + 6; + if (this_some_integer == 0x666) { + this_some_integer = this.val; + } +} +"; +#[test] +fn arithmetic_operator_correct() { + let rules = set_up(); + assert_snippet(ARTITHMETIC_OPERATOR_CORRECT, vec![], &rules); +} + +static ARTITHMETIC_OPERATOR_INCORRECT: &str = " +method this_is_some_method() { + local int this_some_integer = 5+6; + if (this_some_integer == 0x666) { + this_some_integer = this.val; + } +} +"; +#[test] +fn arithmetic_operator_incorrect() { + let rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpBinop, + (2, 2, 34, 35), + (2, 2, 36, 37), + ); + assert_snippet(ARTITHMETIC_OPERATOR_INCORRECT, expected_errors, &rules); +} + +static CONDITIONAL_OPERATOR_INCORRECT: &str = " +method this_is_some_method() { + local int this_some_integer = 5 + 6; + if (this_some_integer==0x666) { + this_some_integer = this.val; + } +} +"; +#[test] +fn conditional_operator_incorrect() { + let rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpBinop, + (3, 3, 8, 25), + (3, 3, 27, 32), + ); + assert_snippet(CONDITIONAL_OPERATOR_INCORRECT, expected_errors, &rules); +} + +static SP_BINOP: &str = " +method this_is_some_method() { + local int this_some_integer = 5+6; + if (this_some_integer == 0x666) { + this_some_integer = this.val; + } +} +"; +#[test] +fn rule_disable() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpBinop, + (2, 2, 34, 35), + (2, 2, 36, 37), + ); + assert_snippet(SP_BINOP, expected_errors, &rules); + rules.sp_binop.enabled = false; + assert_snippet(SP_BINOP, vec![], &rules); +} diff --git a/src/lint/rules/tests/spacing/sp_braces.rs b/src/lint/rules/tests/spacing/sp_braces.rs new file mode 100644 index 0000000..c8424f9 --- /dev/null +++ b/src/lint/rules/tests/spacing/sp_braces.rs @@ -0,0 +1,94 @@ +use crate::lint::rules::tests::common::{set_up, assert_snippet}; +use crate::lint::rules::RuleType; + +// SP.braces around braces ({ and }) +static SPACE_BRACES_METHOD_BANK_REGISTER_FIELD_INCORRECT: &str = " +method this_is_some_method() {return 0;} + +method this_is_empty_method() { } + +bank pcie_config {register command {field mem { + method pcie_write(uint64 value) { + if (value != 0) {value = value + 1;} + default(value); + map_memory_alt(); + } +} +} +} +"; +#[test] +fn space_braces_method_bank_register_field_incorrect() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpBraces, + (1, 1, 29, 30), + (1, 1, 39, 40), + (5, 5, 17, 18), + (5, 5, 35, 36), + (7, 7, 24, 25), + (7, 7, 43, 44), + ); + assert_snippet(SPACE_BRACES_METHOD_BANK_REGISTER_FIELD_INCORRECT, expected_errors, &rules); + // Test rule disable + rules.sp_brace.enabled = false; + assert_snippet(SPACE_BRACES_METHOD_BANK_REGISTER_FIELD_INCORRECT, vec![], &rules); +} + +static SPACE_BRACES_METHOD_BANK_REGISTER_FIELD_CORRECT: &str = " +method this_is_some_method() { return 0; } + +method this_is_empty_method() { } + +bank pcie_config { register command { field mem { + method pcie_write(uint64 value) { + if (value != 0) { value = value + 1; } + default(value); + map_memory_alt(); + } +} +} +} +"; +#[test] +fn space_braces_method_bank_register_field_correct() { + let rules = set_up(); + assert_snippet(SPACE_BRACES_METHOD_BANK_REGISTER_FIELD_CORRECT, vec![], &rules); +} + +static SPACE_BRACES_STRUCT_LAYOUT_BITF_INCORRECT: &str = " +typedef struct {uint16 idx;} hqm_cq_list_release_ctx_t; + +typedef layout \"little-endian\" {bitfields 1 {uint1 cq @ [0:0];} byte;} q_t; +"; +#[test] +fn space_braces_struct_layout_bitf_incorrect() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpBraces, + (1, 1, 15, 16), + (1, 1, 27, 28), + (3, 3, 31, 32), + (3, 3, 69, 70), + (3, 3, 44, 45), + (3, 3, 62, 63), + ); + assert_snippet(SPACE_BRACES_STRUCT_LAYOUT_BITF_INCORRECT, expected_errors, &rules); + // Test rule disable + rules.sp_brace.enabled = false; + assert_snippet(SPACE_BRACES_STRUCT_LAYOUT_BITF_INCORRECT, vec![], &rules); +} + +static SPACE_BRACES_STRUCT_LAYOUT_BITF_CORRECT: &str = " +typedef struct { uint16 idx; } hqm_cq_list_release_ctx_t; + +typedef layout \"little-endian\" { bitfields 1 { uint1 cq @ [0:0]; } byte; } q_t; +"; +#[test] +fn space_braces_struct_layout_bitf_correct() { + let mut rules = set_up(); + assert_snippet(SPACE_BRACES_STRUCT_LAYOUT_BITF_CORRECT, vec![], &rules); + // Test rule disable + rules.sp_brace.enabled = false; + assert_snippet(SPACE_BRACES_STRUCT_LAYOUT_BITF_CORRECT, vec![], &rules); +} diff --git a/src/lint/rules/tests/spacing/sp_ptrdecl.rs b/src/lint/rules/tests/spacing/sp_ptrdecl.rs new file mode 100644 index 0000000..ee42504 --- /dev/null +++ b/src/lint/rules/tests/spacing/sp_ptrdecl.rs @@ -0,0 +1,65 @@ +use crate::lint::rules::tests::common::{set_up, assert_snippet}; +use crate::lint::rules::RuleType; + +static SP_PTRDECL_CORRECT: &str = " +method this_is_some_method(conf_object_t *dummy_obj) { + if (!dummy_obj) { + return; + } +}"; +#[test] +fn sp_ptrdecl_correct() { + let mut rules = set_up(); + assert_snippet(SP_PTRDECL_CORRECT, vec![], &rules); + // Test rule disable + rules.sp_ptrdecl.enabled = false; + assert_snippet(SP_PTRDECL_CORRECT, vec![], &rules); +} + +static SP_PTRDECL_INCORRECT_PARAM: &str = " +method this_is_some_method(conf_object_t*dummy_obj) { + if (!dummy_obj) { + return; + } +}"; +#[test] +fn sp_ptrdecl_incorrect_param() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpPtrDecl, + (1, 1, 27, 40), + ); + assert_snippet(SP_PTRDECL_INCORRECT_PARAM, expected_errors, &rules); + // Test rule disable + rules.sp_ptrdecl.enabled = false; + assert_snippet(SP_PTRDECL_INCORRECT_PARAM, vec![], &rules); +} + +static SP_PTRDECL_INCORRECT_STATEMENT: &str = " +method this_is_some_method(conf_object_t *dummy_obj) { + local conf_object_t*conf = dummy_obj; + if (!conf) { + return; + } +}"; +#[test] +fn sp_ptrdecl_incorrect_statement() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpPtrDecl, + (2, 2, 10, 23), + ); + assert_snippet(SP_PTRDECL_INCORRECT_STATEMENT, expected_errors, &rules); + // Test rule disable + rules.sp_ptrdecl.enabled = false; + assert_snippet(SP_PTRDECL_INCORRECT_STATEMENT, vec![], &rules); +} + +static SP_MULTIPLE_POINTER_SYMBOLS: &str = " +method this_is_some_method(conf_object_t **dummy_obj) { +}"; +#[test] +fn sp_ptrdecl_multiple_symbols() { + let rules = set_up(); + assert_snippet(SP_MULTIPLE_POINTER_SYMBOLS, vec![], &rules); +} \ No newline at end of file diff --git a/src/lint/rules/tests/spacing/sp_punct.rs b/src/lint/rules/tests/spacing/sp_punct.rs new file mode 100644 index 0000000..46e2b69 --- /dev/null +++ b/src/lint/rules/tests/spacing/sp_punct.rs @@ -0,0 +1,46 @@ +use crate::lint::rules::tests::common::{set_up, assert_snippet}; +use crate::lint::rules::RuleType; + +// SP.punct after but not before colon, semicolon and comma +static SP_PUNCT_INCORRECT: &str = " +method this_is_some_method(bool flag ,int8 var) { + local int this_some_integer = 0x666 ; + if (this_some_integer == 0x666) + return; + some_func(arg1 ,arg2 ,arg3 ,arg4); +} +"; +#[test] +fn sp_punct_incorrect() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpPunct, + (1, 1, 36, 37), + (1, 1, 37, 46), + (2, 2, 39, 40), + (5, 5, 18, 19), + (5, 5, 19, 24), + (5, 5, 24, 25), + (5, 5, 25, 30), + (5, 5, 30, 31), + (5, 5, 31, 36), + ); + assert_snippet(SP_PUNCT_INCORRECT, expected_errors, &rules); + // Test rule disable + rules.sp_punct.enabled = false; + assert_snippet(SP_PUNCT_INCORRECT, vec![], &rules); +} + +static SP_PUNCT_CORRECT: &str = " +method this_is_some_method(bool flag, int8 var) { + local int this_some_integer = 0x666; + if (this_some_integer == 0x666) + return; + some_func(arg1, arg2, arg3, arg4); +} +"; +#[test] +fn sp_punct_correct() { + let rules = set_up(); + assert_snippet(SP_PUNCT_CORRECT, vec![], &rules); +} \ No newline at end of file diff --git a/src/lint/rules/tests/spacing/sp_reserved.rs b/src/lint/rules/tests/spacing/sp_reserved.rs new file mode 100644 index 0000000..332cd32 --- /dev/null +++ b/src/lint/rules/tests/spacing/sp_reserved.rs @@ -0,0 +1,153 @@ +use crate::lint::rules::tests::common::{set_up, assert_snippet}; +use crate::lint::rules::RuleType; + +static SP_RESERVED_IF_INCORRECT: &str = " +method this_is_some_method(bool flag) { + local int this_some_integer = 0x666; + if(this_some_integer == 0x666) + return; + + if(this_some_integer == 0x667) { + if(flag) { + some_cal(); + }else{ + return; + } + } +} +"; +#[test] +fn sp_reserved_if_incorrect() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpReserved, + (3, 3, 4, 7), + (6, 6, 4, 7), + (7, 7, 8, 11), + (7, 9, 17, 13), + (9, 11, 9, 9), + ); + assert_snippet(SP_RESERVED_IF_INCORRECT, expected_errors, &rules); + // Test rule disable + rules.sp_reserved.enabled = false; + assert_snippet(SP_RESERVED_IF_INCORRECT, vec![], &rules); +} + +static SP_RESERVED_IF_CORRECT: &str = " +method this_is_some_method(bool flag) { + local int this_some_integer = 0x666; + if (this_some_integer == 0x666) + return; + + if (this_some_integer == 0x667) { + if (flag) { + some_cal(); + } else { + return; + } + } +} +"; +#[test] +fn sp_reserved_if_correct() { + let rules = set_up(); + assert_snippet(SP_RESERVED_IF_CORRECT, vec![], &rules); +} + +static SP_RESERVED_FOR_INCORRECT: &str = " +method this_is_some_method() { + for(local uint16 i = 0; i < SOME_CONST; i++) { + local uint16 j; + for(j = 0; j < OTHER_CONST; j++) { + local uint64 offset = some_var[i][j]; + write(offset, 4, val); + } + } +} +"; +#[test] +fn sp_reserved_for_incorrect() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpReserved, + (2, 2, 4, 8), + (4, 4, 8, 12), + ); + assert_snippet(SP_RESERVED_FOR_INCORRECT, expected_errors, &rules); + // Test rule disable + rules.sp_reserved.enabled = false; + assert_snippet(SP_RESERVED_FOR_INCORRECT, vec![], &rules); +} + +static SP_RESERVED_FOR_CORRECT: &str = " +method this_is_some_method() { + for (local uint16 i = 0; i < SOME_CONST; i++) { + local uint16 j; + for (j = 0; j < OTHER_CONST; j++) { + local uint64 offset = some_var[i][j]; + write(offset, 4, val); + } + } +} +"; +#[test] +fn sp_reserved_for_correct() { + let rules = set_up(); + assert_snippet(SP_RESERVED_FOR_CORRECT, vec![], &rules); +} + +static SP_RESERVED_WHILE_INCORRECT: &str = " +method this_is_some_method() { + local uint16 i = 0; + while(i < SOMETHING) { + some_fun(); + if (some_expression) { + local uint16 j = 0; + while(j < SOMETHING) { + some_other_fun(); + j++; + } + } else { + break; + } + i++; + } +} +"; +#[test] +fn sp_reserved_while_incorrect() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpReserved, + (3, 3, 4, 10), + (7, 7, 12, 18), + ); + assert_snippet(SP_RESERVED_WHILE_INCORRECT, expected_errors, &rules); + // Test rule disable + rules.sp_reserved.enabled = false; + assert_snippet(SP_RESERVED_WHILE_INCORRECT, vec![], &rules); +} + +static SP_RESERVED_WHILE_CORRECT: &str = " +method this_is_some_method() { + local uint16 i = 0; + while (i < SOMETHING) { + some_fun(); + if (some_expression) { + local uint16 j = 0; + while (j < SOMETHING) { + some_other_fun(); + j++; + } + } else { + break; + } + i++; + } +} +"; +#[test] +fn sp_reserved_while_correct() { + let rules = set_up(); + assert_snippet(SP_RESERVED_WHILE_CORRECT, vec![], &rules); +} diff --git a/src/lint/rules/tests/spacing/sp_ternary.rs b/src/lint/rules/tests/spacing/sp_ternary.rs new file mode 100644 index 0000000..63fef50 --- /dev/null +++ b/src/lint/rules/tests/spacing/sp_ternary.rs @@ -0,0 +1,69 @@ +use crate::lint::rules::tests::common::{set_up, assert_snippet}; +use crate::lint::rules::RuleType; + + +// SP.ternary around ? and : in the ternary ?: operator +static VARIABLE_CONDITIONAL_CORRECT: &str = " +method this_is_some_method(bool flag) { + local int this_some_integer = (flag ? 5 : 7); +} +"; +#[test] +fn variable_conditional_correct() { + let rules = set_up(); + assert_snippet(VARIABLE_CONDITIONAL_CORRECT, vec![], &rules); +} + +static VARIABLE_CONDITIONAL_INCORRECT: &str = " +method this_is_some_method(bool flag) { + local int this_some_integer = (flag?5:7); +} +"; +#[test] +fn variable_conditional_incorrect() { + let rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpTernary, + (2, 2, 35, 40), + (2, 2, 39, 41), + (2, 2, 40, 42), + (2, 2, 41, 43), + ); + assert_snippet(VARIABLE_CONDITIONAL_INCORRECT, expected_errors, &rules); +} + +static PARAM_CONDITIONAL_CORRECT: &str = " +param even_or_odd = odd_flag ? 'odd' : 'even'; +"; +#[test] +fn param_conditional_correct() { + let rules = set_up(); + assert_snippet(PARAM_CONDITIONAL_CORRECT, vec![], &rules); +} + +static PARAM_CONDITIONAL_INCORRECT: &str = " +param even_or_odd = odd_flag ?'odd' :'even'; +"; +#[test] +fn param_conditional_incorrect() { + let rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpTernary, + (1, 1, 29, 35), + (1, 1, 36, 43), + ); + assert_snippet(PARAM_CONDITIONAL_INCORRECT, expected_errors, &rules); +} + +#[test] +fn rule_disable() { + let mut rules = set_up(); + let expected_errors = define_expected_errors!( + RuleType::SpTernary, + (1, 1, 29, 35), + (1, 1, 36, 43), + ); + assert_snippet(PARAM_CONDITIONAL_INCORRECT, expected_errors, &rules); + rules.sp_ternary.enabled = false; + assert_snippet(PARAM_CONDITIONAL_INCORRECT, vec![], &rules); +}