fmt: proper infix operator detection in wrapping logic (#9824)

pull/9830/head
Lukas Neubert 2021-04-20 14:20:11 +02:00 committed by GitHub
parent 254d247e80
commit f5e6cadf63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 12 deletions

View File

@ -1888,14 +1888,15 @@ pub fn (mut f Fmt) infix_expr(node ast.InfixExpr) {
if !buffering_save && f.buffering {
f.buffering = false
if !f.single_line_if && f.line_len > fmt.max_len.last() {
f.wrap_infix(start_pos, start_len)
is_cond := node.op in [.and, .logical_or]
f.wrap_infix(start_pos, start_len, is_cond)
}
}
f.is_assign = is_assign_save
f.or_expr(node.or_block)
}
pub fn (mut f Fmt) wrap_infix(start_pos int, start_len int) {
pub fn (mut f Fmt) wrap_infix(start_pos int, start_len int, is_cond bool) {
cut_span := f.out.len - start_pos
infix_str := f.out.cut_last(cut_span)
if !infix_str.contains_any_substr(['&&', '||', '+']) {
@ -1906,14 +1907,13 @@ pub fn (mut f Fmt) wrap_infix(start_pos int, start_len int) {
if start_len == 0 {
f.empty_line = true
}
conditions, penalties := split_up_infix(infix_str, false)
f.write_splitted_infix(conditions, penalties, false)
conditions, penalties := split_up_infix(infix_str, false, is_cond)
f.write_splitted_infix(conditions, penalties, false, is_cond)
}
fn split_up_infix(infix_str string, ignore_paren bool) ([]string, []int) {
fn split_up_infix(infix_str string, ignore_paren bool, is_cond_infix bool) ([]string, []int) {
mut conditions := ['']
mut penalties := [5]
is_cond_infix := infix_str.contains_any_substr(['&&', '||'])
or_pen := if infix_str.contains('&&') { 3 } else { 5 }
parts := infix_str.split(' ')
mut inside_paren := false
@ -1948,12 +1948,9 @@ fn split_up_infix(infix_str string, ignore_paren bool) ([]string, []int) {
return conditions, penalties
}
fn (mut f Fmt) write_splitted_infix(conditions []string, penalties []int, ignore_paren bool) {
fn (mut f Fmt) write_splitted_infix(conditions []string, penalties []int, ignore_paren bool, is_cond bool) {
for i, cnd in conditions {
c := cnd.trim_space()
if c.len == 0 {
continue
}
if f.line_len + c.len < fmt.max_len[penalties[i]] {
if (i > 0 && i < conditions.len) || (ignore_paren && i == 0 && c.len > 5 && c[3] == `(`) {
f.write(' ')
@ -1963,8 +1960,8 @@ fn (mut f Fmt) write_splitted_infix(conditions []string, penalties []int, ignore
is_paren_expr := (c[0] == `(` || (c.len > 5 && c[3] == `(`)) && c.ends_with(')')
final_len := ((f.indent + 1) * 4) + c.len
if final_len > fmt.max_len.last() && is_paren_expr {
conds, pens := split_up_infix(c, true)
f.write_splitted_infix(conds, pens, true)
conds, pens := split_up_infix(c, true, is_cond)
f.write_splitted_infix(conds, pens, true, is_cond)
continue
}
if i == 0 {

View File

@ -2,3 +2,14 @@ fn infix_in_multi_assign() {
child_width, child_height = child.adj_width + child.margin(.left) + child.margin(.right),
child.adj_height + child.margin(.top) + child.margin(.bottom)
}
fn impostor_infix() {
/*
String concatiation is an InfixExpr. The second part is so long
that it overflows a single line. Therefore the wrapping logic is run.
The problem was that `&&` and `||` inside the string were detected as infix operators.
Thus causing a totally wrong wrapping and sometimes runtime panics.
*/
x := 'foo' +
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa || (eeeeeeeeeeeeeeeeee && ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) && bbbbbbbbbbbbbbbbbbbbbbbbbbbb'
}