~/bend-docscommunity

src/rules/suspicious/concat.bend checks

raw source on the hub · import 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/rules/suspicious/concat.bend as Concat

rule concat: a def passes itself a parameter grown at the end, p ++ x or List.append(.., p, ys) (String.append(p, ..) too), as the argument in p's own position, the slot it carries; p grown into another slot is not a finding. The argument is that append written in place, inside any number of parentheses ((p ++ x)), or a lone name read from a let: the nearest q = .. or +q = .. of that name before the call in its block or an enclosing one, whose right side is such an append (a later let of the name shadows it; other binders, a typed or destructuring let and a do-bind do not count). A String and a List are cons lists, so appending copies all of p: the loop is quadratic, with right output (night-train's text step cost three times the render; rootagi's JSON stringify). Prepend (x <> acc) and reverse once at the end, build with h <> go(t), or gather pieces and join them once.

7 imports
import Base
import ../../src.bend as Src
import ../../finding.bend as F
import ../../syntax/lex.bend as Lex
import ../../syntax/tree.bend as Tree
import ../calls.bend as Calls
import ../../lazy/lazy.bend as Lazy

Types

type Let source · line 76 · raw

Data

a let of one plain name in scope: the name, and what its right side appends onto

Definitions

def lone.name source · line 24 · raw

@nn:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok>

a leaf that is a lowercase name: its token. The rule matches a leaf's kind here and in bound.is_eq only; the rest reads kinds through these

def lone source · line 32 · raw

@nn:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok>

a chain that is exactly one lowercase name: its token

def appended source · line 40 · raw

@+tt:String -> @as:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node> -> Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok>

the list a call appends onto: List.append's first list, String.append's first

def onto.call source · line 46 · raw

@hh:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> @kids:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok>

a leaf, then a group: the call's append

def onto.next source · line 54 · raw

@+hh:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> @h2:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok>

a first cell, then the second: a name then ++, or a call

def onto source · line 65 · raw

@aa:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok>

the name an argument appends onto, p ++ .. or an append call, inside any number of parentheses

def find source · line 80 · raw

@lets:List<&2, Let> -> @+name:String -> Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok>

what the nearest let of the name appends onto; nothing when no let binds it

def via.of source · line 88 · raw

@mm:Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok> -> @+lets:List<&2, Let> -> Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok>

what the let of a lone name appends onto

def via source · line 96 · raw

@aa:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> @+lets:List<&2, Let> -> Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok>

the name an argument appends onto, when it is a lone name read from a let

def either source · line 100 · raw

@aa:Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok> -> @bb:Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok> -> Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok>

the first maybe when it holds a token, else the second

def seen source · line 108 · raw

@+aa:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> @+lets:List<&2, Let> -> Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok>

the name an argument appends onto, in place or through a let

def bound.eq source · line 112 · raw

@kk:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.TokKind -> Bool

an =

def bound.of source · line 120 · raw

@mm:Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok> -> @+h2:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> @rhs:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> Maybe<&2, Let>

a name, then =, then the right side: the let

def bound.named source · line 128 · raw

@+hh:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> @+h2:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> @rhs:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> Maybe<&2, Let>

a plain name, then =, then the right side: the let

def bound.plus source · line 132 · raw

@+h1:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> @+h2:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> @rest:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> Maybe<&2, Let>

+, then a plain name, = and the right side: the let

def bound source · line 142 · raw

@kids:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> Maybe<&2, Let>

the let a statement's own tokens make, when it binds one plain name with =, bare or +

def push source · line 151 · raw

@mm:Maybe<&2, Let> -> @+lets:List<&2, Let> -> List<&2, Let>

the lets in scope after one more, when there is one

def hit source · line 159 · raw

@mm:Maybe<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.Tok> -> @+slot:String -> @+path:String -> @+acc:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding> -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>

a finding when the name is the parameter of the argument's own slot

def hits source · line 176 · raw

@as:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node> -> @+params:List<&2, String> -> @+lets:List<&2, Let> -> @+path:String -> @acc:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding> -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>

the findings on a self-call's arguments, each against the parameter in its position (params, from the argument's own slot on)

def after source · line 191 · raw

@kind:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.StmtKind -> @+kids:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> @+lets:List<&2, Let> -> List<&2, Let>

the lets a statement leaves in scope for the statements after it

def walk source · line 199 · raw

@nn:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> @+name:String -> @+params:List<&2, String> -> @+lets:List<&2, Let> -> @+path:String -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>

every self-call's arguments, with the lets in scope

def check.go source · line 222 · raw

@ds:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/rules/calls.Def> -> @+path:String -> @acc:List<&2, List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>> -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>

def check source · line 232 · raw

@ss:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/src.Src -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>

the rule