diff --git a/example_files/example_lint_cfg.json b/example_files/example_lint_cfg.json index b9072af..be46493 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" : {}, "nsp_funpar": {}, "nsp_inparen": {}, "nsp_unary": {}, "nsp_trailing": {}, + "nsp_ptrdecl": {}, + "sp_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..5411e17 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}; @@ -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(acc, SpBinopArgs::from_binary_expression_content(self)); + } } #[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(acc, SpTernaryArgs::from_tertiary_expression_content(self)); + } } #[derive(Debug, Clone, PartialEq)] diff --git a/src/analysis/parsing/misc.rs b/src/analysis/parsing/misc.rs index 1599d9b..4d193a8 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(acc, SpPtrDeclArgs::from_cdecl(self)); + rules.nsp_ptrdecl.check(acc, NspPtrDeclArgs::from_cdecl(self)); + } } // corresponds to cdecl in grammar diff --git a/src/analysis/parsing/statement.rs b/src/analysis/parsing/statement.rs index fed3b27..ef03f01 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; @@ -437,6 +438,7 @@ impl TreeElement for IfContent { 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.sp_reserved.check(acc, SpReservedArgs::from_if(self)); } } @@ -550,6 +552,7 @@ impl TreeElement for WhileContent { 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.sp_reserved.check(acc, SpReservedArgs::from_while(self)); } } @@ -865,6 +868,7 @@ impl TreeElement for ForContent { 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.sp_reserved.check(acc, SpReservedArgs::from_for(self)); } } @@ -1284,6 +1288,9 @@ impl TreeElement for AfterContent { &self.callexpression, &self.semi) } + fn evaluate_rules(&self, acc: &mut Vec, rules: &CurrentRules, _aux: AuxParams) { + rules.sp_reserved.check(acc, SpReservedArgs::from_after_content(self)); + } } impl Parse for AfterContent { diff --git a/src/analysis/parsing/structure.rs b/src/analysis/parsing/structure.rs index 4d4a293..25fee12 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}; diff --git a/src/lint/features.md b/src/lint/features.md index 665457d..682dd8c 100644 --- a/src/lint/features.md +++ b/src/lint/features.md @@ -3,6 +3,9 @@ Below are listed the currently supported rules for linting: ## Spacing +- SpReserved, `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;`). 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 - NspFunpar, `nsp_funpar`: no spaces between a function/method name and its opening parenthesis diff --git a/src/lint/mod.rs b/src/lint/mod.rs index 4171e14..dc207db 100644 --- a/src/lint/mod.rs +++ b/src/lint/mod.rs @@ -4,10 +4,20 @@ use std::path::{Path, PathBuf}; use log::{debug, error, trace}; use serde::{Deserialize, Serialize}; 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}; use crate::analysis::parsing::tree::TreeElement; @@ -45,11 +55,21 @@ pub fn maybe_parse_lint_cfg(path: PathBuf) -> Option { #[serde(default)] #[serde(deny_unknown_fields)] pub struct LintCfg { + #[serde(default)] + pub sp_reserved: 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, @@ -84,8 +104,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{}), @@ -204,41 +229,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; @@ -264,19 +254,8 @@ pub mod tests { env!("CARGO_MANIFEST_DIR"), EXAMPLE_CFG); let example_cfg = parse_lint_cfg(example_path.into()).unwrap(); + println!("Example LintCfg: {:#?}", example_cfg); + println!("LintCfg::default(): {:#?}", LintCfg::default()); assert_eq!(example_cfg, LintCfg::default()); } - - #[test] - #[ignore] - 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.to_string(), &rules); - assert!(_lint_errors.is_ok()); - assert!(!_lint_errors.unwrap().is_empty()); - } } diff --git a/src/lint/rules/mod.rs b/src/lint/rules/mod.rs index 062efeb..d318c3f 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(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 53b68a0..d98ff46 100644 --- a/src/lint/rules/spacing.rs +++ b/src/lint/rules/spacing.rs @@ -1,22 +1,129 @@ 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: Option, +} +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: Some(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: Some(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: Some(elsebranch.range()), + }); + } + + args_list + } + pub fn from_for(node: &ForContent) -> Vec { + let mut args_list = vec![]; + args_list.push(SpReservedArgs { + before_range: None, + token_range: node.fortok.range(), + after_range: Some(node.lparen.range()), + }); + args_list + } + pub fn from_while(node: &WhileContent) -> Vec { + let mut args_list = vec![]; + args_list.push(SpReservedArgs { + before_range: None, + token_range: node.whiletok.range(), + after_range: Some(node.lparen.range()), + }); + args_list + } +} + +impl SpReservedRule { + pub fn check(&self, acc: &mut Vec, + args: 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 let Some(after_range) = &arg.after_range { + if (arg.token_range.row_end == after_range.row_start) + && (arg.token_range.col_end == after_range.col_start) { + acc.push( + self.create_err(Range::combine( + arg.token_range, *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 {} @@ -125,6 +232,114 @@ 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, acc: &mut Vec, + ranges: Option) { + 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, acc: &mut Vec, + ranges: Option) { + 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(left)); + } + if no_gap(left_op, middle) { + acc.push(self.create_err(middle)); + } + if no_gap(middle, right_op) { + acc.push(self.create_err(middle)); + } + if no_gap(right_op, right) { + acc.push(self.create_err(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 {} @@ -501,3 +716,132 @@ impl Rule for NspTrailingRule { RuleType::NspTrailing } } +pub struct SpPtrDeclRule { + pub enabled: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct SpPtrDeclOptions {} + +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 + } +} + +fn has_space_between(range_left: &ZeroRange, + range_right: &ZeroRange) -> bool { + return !((range_left.row_end == range_right.row_start) + && (range_left.col_end == range_right.col_start)) +} +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| { + match m { + LeafToken::Actual(token) => { + match token.kind { + TokenKind::Multiply => Some(m.range()), + _ => None + } + } + LeafToken::Missing(_) => 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: operator_ranges, + }) + } +} + +impl SpPtrDeclRule { + pub fn check(&self, acc: &mut Vec, + ranges: Option) { + if !self.enabled { return; } + match ranges { + None => return, + Some(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)); + } + } + } + + } +} + +pub struct NspPtrDeclRule { + pub enabled: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct NspPtrDeclOptions {} + +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: rightmost_multiply, + identifier_range: node.decl.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 + } +} + +impl NspPtrDeclRule { + pub fn check(&self, acc: &mut Vec, + ranges: Option) { + if !self.enabled { return; } + match ranges { + None => return, + Some(ranges) => { + match ranges.rightmost_multiply{ + None => return, + Some(op_range) => { + if has_space_between(&op_range, &ranges.identifier_range) { + acc.push(self.create_err(ranges.identifier_range)); + } + } + } + } + } + + } +} \ No newline at end of file diff --git a/src/lint/rules/tests/common.rs b/src/lint/rules/tests/common.rs index 988c1ee..e198083 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.to_string(), 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..bd13810 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 = " diff --git a/src/lint/rules/tests/indentation/code_block.rs b/src/lint/rules/tests/indentation/code_block.rs index b298c90..fd30d24 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 = " 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..f446093 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 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..4f03690 --- /dev/null +++ b/src/lint/rules/tests/spacing/nsp_ptrdecl.rs @@ -0,0 +1,80 @@ +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..bdd23fb --- /dev/null +++ b/src/lint/rules/tests/spacing/sp_binop.rs @@ -0,0 +1,79 @@ +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..cce04a5 --- /dev/null +++ b/src/lint/rules/tests/spacing/sp_ptrdecl.rs @@ -0,0 +1,69 @@ +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..f08b740 --- /dev/null +++ b/src/lint/rules/tests/spacing/sp_ternary.rs @@ -0,0 +1,76 @@ +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, 39), + (2, 2, 40, 41), + (2, 2, 40, 41), + (2, 2, 42, 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, 30, 35), + (1, 1, 37, 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, 30, 35), + (1, 1, 37, 43), + ); + assert_snippet(PARAM_CONDITIONAL_INCORRECT, expected_errors, &rules); + rules.sp_ternary.enabled = false; + assert_snippet(PARAM_CONDITIONAL_INCORRECT, vec![], &rules); +}