Skip to content

Commit 6b44a59

Browse files
committed
Implement rule LL2 for breaking before binary ops
1 parent e0b60f9 commit 6b44a59

File tree

10 files changed

+105
-38
lines changed

10 files changed

+105
-38
lines changed

example_files/example_lint_cfg.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@
2222
"func_call_break_on_open_paren": {},
2323
"method_output_break": {},
2424
"conditional_expression_break_before_op": {},
25+
"break_before_binary_op": {},
2526
"annotate_lints": true
2627
}

src/analysis/parsing/expression.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ use crate::lint::{DMLStyleError,
2727
CurrentRules},
2828
AuxParams};
2929
use crate::lint::rules::indentation::IndentParenExprArgs;
30-
use crate::lint::rules::linebreaking::{ConditionalExpressionBreakBeforeOperatorArgs, FuncCallBreakOnOpenParenArgs};
30+
use crate::lint::rules::linebreaking::{BreakBeforeBinaryOpArgs,
31+
ConditionalExpressionBreakBeforeOperatorArgs,
32+
FuncCallBreakOnOpenParenArgs};
3133

3234
#[derive(Debug, Clone, PartialEq)]
3335
pub struct UnaryExpressionContent {
@@ -97,6 +99,7 @@ impl TreeElement for BinaryExpressionContent {
9799
}
98100
fn evaluate_rules(&self, acc: &mut Vec<DMLStyleError>, rules: &CurrentRules, _aux: AuxParams) {
99101
rules.sp_binop.check(SpBinopArgs::from_binary_expression_content(self), acc);
102+
rules.break_before_binary_op.check(BreakBeforeBinaryOpArgs::from_binary_expression(self), acc);
100103
}
101104
}
102105

src/lint/features.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ Below are listed the currently supported rules for linting:
4747

4848
## Line Length
4949
- **LL1**, `long_lines`: Lines should be kept shorter than 80 characters. This limit can be set to a custom value
50+
- **LL2**, `break_before_binary_op`: Break long lines before binary operators, not after
51+
```
52+
x = (a_very_long_expression
53+
+ another_very_long_expression)
54+
* a_third_long_expression;
55+
```
5056
- **LL3**, `conditional_expression_break`: Break conditional expressions before the ?, or both before the ? and before the :.
5157
- **LL5**, `method_output_break`: Break long method declarations with output parameters before the arrow.
5258
```

src/lint/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ use std::path::{Path, PathBuf};
55
use std::str::FromStr;
66
use lazy_static::lazy_static;
77
use log::{debug, error, trace};
8-
use rules::linebreaking::{FuncCallBreakOnOpenParenOptions, MethodOutputBreakOptions, ConditionalExpressionBreakBeforeOperatorOptions};
8+
use rules::linebreaking::{BreakBeforeBinaryOpOptions,
9+
FuncCallBreakOnOpenParenOptions,
10+
MethodOutputBreakOptions,
11+
ConditionalExpressionBreakBeforeOperatorOptions};
912
use serde::{Deserialize, Serialize};
1013
use regex::Regex;
1114
use rules::{instantiate_rules, CurrentRules, RuleType};
@@ -120,6 +123,8 @@ pub struct LintCfg {
120123
pub conditional_expression_break_before_op: Option<ConditionalExpressionBreakBeforeOperatorOptions>,
121124
#[serde(default)]
122125
pub method_output_break: Option<MethodOutputBreakOptions>,
126+
#[serde(default)]
127+
pub break_before_binary_op: Option<BreakBeforeBinaryOpOptions>,
123128
#[serde(default = "get_true")]
124129
pub annotate_lints: bool,
125130
}
@@ -169,6 +174,7 @@ impl Default for LintCfg {
169174
func_call_break_on_open_paren: Some(FuncCallBreakOnOpenParenOptions{indentation_spaces: INDENTATION_LEVEL_DEFAULT}),
170175
method_output_break: Some(MethodOutputBreakOptions{}),
171176
conditional_expression_break_before_op: Some(ConditionalExpressionBreakBeforeOperatorOptions{}),
177+
break_before_binary_op: Some(BreakBeforeBinaryOpOptions{}),
172178
annotate_lints: true,
173179
}
174180
}

src/lint/rules/linebreaking.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::analysis::parsing::parser::Token;
44
use crate::analysis::parsing::structure::MethodContent;
55
use crate::analysis::parsing::tree::{ZeroRange, TreeElementTokenIterator, TreeElement};
66
use crate::analysis::parsing::expression::{CastContent, FunctionCallContent,
7+
BinaryExpressionContent,
78
ParenExpressionContent, TertiaryExpressionContent};
89
use crate::lint::{DMLStyleError, RuleType};
910
use super::indentation::IndentParenExprArgs;
@@ -216,6 +217,60 @@ impl FuncCallBreakOnOpenParenRule {
216217
}
217218
}
218219

220+
pub struct BreakBeforeBinaryOpRule {
221+
pub enabled: bool,
222+
}
223+
224+
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
225+
pub struct BreakBeforeBinaryOpOptions {}
226+
227+
pub struct BreakBeforeBinaryOpArgs {
228+
pub left: ZeroRange,
229+
pub operation: ZeroRange,
230+
pub right: ZeroRange
231+
}
232+
233+
impl BreakBeforeBinaryOpArgs {
234+
pub fn from_binary_expression(node: &BinaryExpressionContent)
235+
-> Option<BreakBeforeBinaryOpArgs> {
236+
Some(BreakBeforeBinaryOpArgs {
237+
left: node.left.range(),
238+
operation: node.operation.range(),
239+
right: node.right.range(),
240+
})
241+
}
242+
}
243+
244+
impl BreakBeforeBinaryOpRule {
245+
pub fn from_options(options: &Option<BreakBeforeBinaryOpOptions>) -> BreakBeforeBinaryOpRule {
246+
BreakBeforeBinaryOpRule {
247+
enabled: options.is_some(),
248+
}
249+
}
250+
251+
pub fn check(&self, args: Option<BreakBeforeBinaryOpArgs>, acc: &mut Vec<DMLStyleError>) {
252+
if !self.enabled { return; }
253+
let Some(args) = args else { return; };
254+
let binop_is_broken = args.left.row_start.0 != args.right.row_end.0;
255+
let has_break_after_operator = args.operation.row_end.0 != args.right.row_start.0;
256+
if binop_is_broken && has_break_after_operator {
257+
acc.push(self.create_err(args.operation));
258+
}
259+
}
260+
}
261+
262+
impl Rule for BreakBeforeBinaryOpRule {
263+
fn name() -> &'static str {
264+
"break_before_binary_op"
265+
}
266+
fn description() -> &'static str {
267+
"Break binary expressions before the operator, not after."
268+
}
269+
fn get_rule_type() -> RuleType {
270+
RuleType::LL2
271+
}
272+
}
273+
219274
pub struct ConditionalExpressionBreakBeforeOperatorRule {
220275
pub enabled: bool,
221276
}

src/lint/rules/mod.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ use indentation::{LongLinesRule,
2424
IndentSwitchCaseRule,
2525
IndentEmptyLoopRule,
2626
IndentContinuationLineRule};
27-
use linebreaking::{FuncCallBreakOnOpenParenRule,
28-
MethodOutputBreakRule,
29-
ConditionalExpressionBreakBeforeOperatorRule};
27+
use linebreaking::{BreakBeforeBinaryOpRule,
28+
FuncCallBreakOnOpenParenRule,
29+
ConditionalExpressionBreakBeforeOperatorRule,
30+
MethodOutputBreakRule};
3031
use crate::lint::{LintCfg, DMLStyleError};
3132
use crate::analysis::{LocalDMLError, parsing::tree::ZeroRange};
3233

@@ -53,6 +54,7 @@ pub struct CurrentRules {
5354
pub func_call_break_on_open_paren: FuncCallBreakOnOpenParenRule,
5455
pub method_output_break: MethodOutputBreakRule,
5556
pub conditional_expression_break_before_op: ConditionalExpressionBreakBeforeOperatorRule,
57+
pub break_before_binary_op: BreakBeforeBinaryOpRule, // Placeholder for future rule
5658
}
5759

5860
pub fn instantiate_rules(cfg: &LintCfg) -> CurrentRules {
@@ -79,6 +81,7 @@ pub fn instantiate_rules(cfg: &LintCfg) -> CurrentRules {
7981
func_call_break_on_open_paren: FuncCallBreakOnOpenParenRule::from_options(&cfg.func_call_break_on_open_paren),
8082
method_output_break: MethodOutputBreakRule { enabled: cfg.method_output_break.is_some() },
8183
conditional_expression_break_before_op: ConditionalExpressionBreakBeforeOperatorRule::from_options(&cfg.conditional_expression_break_before_op),
84+
break_before_binary_op: BreakBeforeBinaryOpRule { enabled: cfg.break_before_binary_op.is_some() },
8285
}
8386
}
8487

@@ -113,6 +116,7 @@ pub enum RuleType {
113116
NspUnary,
114117
NspTrailing,
115118
LL1,
119+
LL2,
116120
LL3,
117121
LL5,
118122
LL6,

src/lint/rules/tests/indentation/continuation_line.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ fn continuation_line_correct() {
1515

1616
static CONTINUATION_LINE_RETURN_CORRECT: &str = "
1717
method calculate_sum(uint64 a, uint64 b) -> (uint64) {
18-
return (a + b) * (a - b) +
19-
(a * b);
18+
return (a + b) * (a - b)
19+
+ (a * b);
2020
}
2121
";
2222
#[test]
@@ -29,8 +29,8 @@ static CONTINUATION_LINE_LOCAL_DECLA_CORRECT: &str = "
2929
bank regs {
3030
register example_register size 4 @ 0x00 {
3131
method read() -> (uint64) {
32-
local uint64 value = (this.val + 10) *
33-
(this.val - 5);
32+
local uint64 value = (this.val + 10)
33+
* (this.val - 5);
3434
return value;
3535
}
3636
}
@@ -87,8 +87,8 @@ fn continuation_line_incorrect() {
8787
pub static CONTINUATION_LINE_BITWISE_INCORRECT: &str = "
8888
method write(uint64 value) {
8989
local uint64 a = value;
90-
local uint64 result = a <<
91-
2;
90+
local uint64 result = a
91+
<< 2;
9292
log info: 'Writing to register, result after left shift = %x', result;
9393
}
9494
";
@@ -97,7 +97,7 @@ fn continuation_line_bitwise_incorrect() {
9797
let rules = set_up();
9898
let expected_errors = define_expected_errors!(
9999
RuleType::IN6,
100-
(4, 4, 31, 32),
100+
(4, 4, 31, 33),
101101
);
102102
assert_snippet(CONTINUATION_LINE_BITWISE_INCORRECT, expected_errors, &rules);
103103
}
@@ -106,8 +106,8 @@ pub static CONTINUATION_LINE_PARAM_INCORRECT: &str = "
106106
bank regs {
107107
register control size 4 @ 0x00 {
108108
field status @ [31:3] {
109-
param init_val = 1 << 2 |
110-
1 << 1;
109+
param init_val = 1 << 2
110+
| 1 << 1;
111111
}
112112
}
113113
}

src/lint/rules/tests/indentation/paren_expr.rs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ fn funcall_nested_paren_incorrect() {
130130

131131
static IF_PAREN_CORRECT: &str = "
132132
method callback() {
133-
if (conditionX &&
134-
conditionY) {
133+
if (conditionX
134+
&& conditionY) {
135135
return;
136136
}
137137
}
@@ -144,8 +144,8 @@ fn if_paren_correct() {
144144

145145
static IF_PAREN_INCORRECT: &str = "
146146
method callback() {
147-
if (conditionX &&
148-
conditionY) {
147+
if (conditionX
148+
&& conditionY) {
149149
return;
150150
}
151151
}
@@ -155,7 +155,7 @@ fn if_paren_incorrect() {
155155
let rules = set_up();
156156
let expected_errors = define_expected_errors!(
157157
RuleType::IN5,
158-
(3, 3, 10, 20),
158+
(3, 3, 10, 12),
159159
);
160160
assert_snippet(IF_PAREN_INCORRECT, expected_errors, &rules);
161161
}
@@ -348,10 +348,8 @@ fn switch_paren_incorrect() {
348348
static NESTED_PAREN_EXPR_CORRECT: &str = "
349349
param result = ((reg0.val
350350
* reg1.enable.val)
351-
&
352-
mask_reg
353-
+
354-
1);
351+
& mask_reg
352+
+ 1);
355353
";
356354

357355
#[test]
@@ -363,18 +361,16 @@ fn nested_paren_expr_correct(){
363361
static NESTED_PAREN_EXPR_INCORRECT: &str = "
364362
param result = ((reg0.val
365363
* reg1.enable.val)
366-
&
367-
mask_reg
368-
+
369-
1);
364+
& mask_reg
365+
+ 1);
370366
";
371367
#[test]
372368
fn nested_paren_expr_incorrect(){
373369
let rules = set_up();
374370
let expected_errors = define_expected_errors!(
375371
RuleType::IN5,
376372
(2, 2, 5, 6),
377-
(4, 4, 17, 25),
373+
(3, 3, 17, 18),
378374
);
379375
assert_snippet(NESTED_PAREN_EXPR_INCORRECT, expected_errors, &rules);
380376
}

src/lint/rules/tests/line_length_breaking/func_call_break_open_paren.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,8 @@ static PAREN_NESTED_CORRECT: &str = "
5959
param result = (
6060
(reg0.val
6161
* reg1.enable.val)
62-
&
63-
mask_reg
64-
+
65-
1);
62+
& mask_reg
63+
+ 1);
6664
";
6765

6866
#[test]
@@ -75,10 +73,8 @@ static PAREN_NESTED_INCORRECT: &str = "
7573
param result = (
7674
(reg0.val
7775
* reg1.enable.val)
78-
&
79-
mask_reg
80-
+
81-
1);
76+
& mask_reg
77+
+ 1);
8278
";
8379

8480
#[test]
@@ -87,8 +83,7 @@ fn paren_nested_incorrect(){
8783
let expected_errors = define_expected_errors!(
8884
RuleType::LL6,
8985
(4, 4, 16, 17),
90-
(6, 6, 16, 17),
91-
(7, 7, 16, 17),
86+
(5, 5, 16, 17),
9287
);
9388
assert_snippet(PAREN_NESTED_INCORRECT, expected_errors, &rules);
9489
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
mod func_call_break_open_paren;
22
mod method_output_break;
33
mod conditional_expression_break;
4+
mod break_before_binary_op;

0 commit comments

Comments
 (0)