Skip to content

Commit b34ea26

Browse files
committed
Implement rule LL2 for breaking before binary ops
1 parent 55c70e9 commit b34ea26

File tree

7 files changed

+81
-5
lines changed

7 files changed

+81
-5
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,
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)