src/rules/suspicious/concat.bend checks
raw source on the hub · import 0xd96f2ab40f5df4925c42e96d0ba857ff/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
Let@name:String -> @onto:Maybe<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/lex.Tok> -> Let
Definitions
def lone.name source · line 24 · raw
@nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> Maybe<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> Maybe<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node> -> Maybe<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @kids:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> Maybe<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/lex.Tok>
a leaf, then a group: the call's append
def onto.next source · line 54 · raw
@+hh:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @h2:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> Maybe<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/lex.Tok>
a first cell, then the second: a name then ++, or a call
def onto source · line 65 · raw
@aa:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> Maybe<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/lex.Tok> -> @+lets:List<&2, Let> -> Maybe<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/lex.Tok>
what the let of a lone name appends onto
def via source · line 96 · raw
@aa:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @+lets:List<&2, Let> -> Maybe<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/lex.Tok> -> @bb:Maybe<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/lex.Tok> -> Maybe<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/lex.Tok>
the first maybe when it holds a token, else the second
def seen source · line 108 · raw
@+aa:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @+lets:List<&2, Let> -> Maybe<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/lex.Tok>
the name an argument appends onto, in place or through a let
def bound.eq source · line 112 · raw
@kk:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/lex.TokKind -> Bool
an =
def bound.of source · line 120 · raw
@mm:Maybe<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/lex.Tok> -> @+h2:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @rhs:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> Maybe<&2, Let>
a name, then =, then the right side: the let
def bound.named source · line 128 · raw
@+hh:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @+h2:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @rhs:0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @+h2:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @rest:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> Maybe<&2, Let>
+, then a plain name, = and the right side: the let
def bound source · line 142 · raw
@kids:0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/lex.Tok> -> @+slot:String -> @+path:String -> @+acc:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Finding> -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node> -> @+params:List<&2, String> -> @+lets:List<&2, Let> -> @+path:String -> @acc:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Finding> -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.StmtKind -> @+kids:0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @+name:String -> @+params:List<&2, String> -> @+lets:List<&2, Let> -> @+path:String -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Finding>
every self-call's arguments, with the lets in scope
def check.go source · line 222 · raw
@ds:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/rules/calls.Def> -> @+path:String -> @acc:List<&2, List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Finding>> -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Finding>
def check source · line 232 · raw
@ss:0xd96f2ab40f5df4925c42e96d0ba857ff/src/src.Src -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Finding>
the rule