~/bend-docscommunity

src/rules/suspicious/table.bend checks

raw source on the hub · import 0xd96f2ab40f5df4925c42e96d0ba857ff/src/rules/suspicious/table.bend as Table

rule table: List.get or List.set at a computed index inside a def that calls itself, when the list is a fixed table: a literal, an array, or List.replicate / Array.new / List.range with a constant count, written inline, defined beside the loop, or held by the let of that name in scope. The index walks that table on every step. Keep it in an Array. A let reaches the statements after it and the blocks under them, not a sibling case arm, and a later let of the name to anything else ends it. A literal index (a fixed slot, including 0 and 1), a growing or data-dependent list, a one-shot outside the recursion, and List.head / List.tail do not run. index leaves a table this rule owns, so one call is one finding. Laws and proofs do not run (a def with no type at all fills a law: it is a proof).

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

Definitions

def literal source · line 21 · raw

@nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> Bool

is the chain exactly one number?

def top_has source · line 29 · raw

@nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @+want:String -> Bool

a top-level token of this text, not one nested in a group

def array_sized source · line 42 · raw

@nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> Bool

[v : T*n] or [v : T^d], and the size is a number

def lone_num source · line 57 · raw

@nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> Bool

the chain is exactly one number

def range_count source · line 65 · raw

@as:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node> -> Bool

List.replicate / Array.new count at argument 2; List.range at the end

def built_call source · line 75 · raw

@+tt:String -> @kids:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> Bool

a constant-size constructor, not a length taken from the data

def built source · line 81 · raw

@nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> Bool

a list literal, a sized array, or a constant-size constructor

def call_name source · line 92 · raw

@nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> String

the chain is exactly this call's name, with no arguments that matter: name()

def lone_name source · line 101 · raw

@nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> String

the chain is exactly one lowercase name

def key source · line 109 · raw

@+tt:String -> @+line:U32 -> @+col:U32 -> String

one use of a name, told apart from its other uses by where it stands

def lone_key source · line 113 · raw

@nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> String

the chain is exactly one lowercase name: that use's key

def owns source · line 122 · raw

@+nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @+fixed:List<&2, String> -> Bool

the list argument is a fixed table: inline, a use of a let that holds one, or name() / name for a table def of the file

def bind_bad source · line 132 · raw

@+bad:Bool -> @+nm:String -> String

one plain name before =, when the pattern is not a destructure

def bind_at source · line 140 · raw

@+seen:Bool -> @+bad:Bool -> @+nm:String -> String

one plain name before =, when there is one

def bind_name source · line 148 · raw

@nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @+seen:Bool -> @+bad:Bool -> @+nm:String -> String

the one plain name a statement binds, or empty

def bind_rhs source · line 164 · raw

@nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> 0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node

the right-hand side: the chain after a statement's top-level =

def drop source · line 174 · raw

@live:List<&2, String> -> @+nm:String -> List<&2, String>

the names in scope without this one

def rebind source · line 183 · raw

@+nm:String -> @+tab:Bool -> @+live:List<&2, String> -> List<&2, String>

after a let of nm: it holds a table only when this binding is one

def use_at source · line 189 · raw

@+tt:String -> @+line:U32 -> @+col:U32 -> @+live:List<&2, String> -> @+acc:List<&2, String> -> List<&2, String>

a name use joins the keys when the let in scope for it holds a table

def lets source · line 195 · raw

@nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @+live:List<&2, String> -> @acc:List<&2, String> -> List<&2, String>

the keys of every name use under the node whose binding in scope is a table: a let reaches the statements after it and their bodies, not an enclosing block or a sibling arm, and a later let of the name replaces it

def mod_one source · line 210 · raw

@body:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @+name:String -> @+acc:List<&2, String> -> List<&2, String>

a def whose body is one fixed table

def modules source · line 218 · raw

@ds:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/rules/calls.Def> -> @acc:List<&2, String> -> List<&2, String>

defs of this file whose body is one fixed table

def scope source · line 227 · raw

@body:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @+mods:List<&2, String> -> List<&2, String>

fixed tables visible in this def: the file's table defs by name, and each use of a let whose binding in scope is a table, by its key

def cite source · line 231 · raw

@+get:Bool -> @+path:String -> @+line:U32 -> @+col:U32 -> @+len:U32 -> 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Finding

the finding for a get or a set

def hit source · line 241 · raw

@+open:Bool -> @+tt:String -> @kids:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @+fixed:List<&2, String> -> @+path:String -> @+line:U32 -> @+col:U32 -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Finding>

a get or a set of a fixed table at a computed index

def walk source · line 259 · raw

@nn:0xd96f2ab40f5df4925c42e96d0ba857ff/src/syntax/tree.Node -> @+path:String -> @+fixed:List<&2, String> -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Finding>

every fixed-table get or set

def check.go source · line 273 · raw

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

def check source · line 289 · raw

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

the rule