Jeroen Engels
@jfmengels
Elm Radio
// linter-disable rule
// linter-disable rule
// linter-disable rule
// linter-disable rule
// linter-disable rule
// linter-disable rule
// linter-disable rule
// linter-disable rule
False positive | False negative | |
---|---|---|
Linter / compiler | Unnecessary blocking | Missed problem |
False positive | False negative | |
---|---|---|
Linter / compiler | Unnecessary blocking | Missed problem |
Code optimizer | Optimization bug, potential crash | Missed opportunity |
False positive | |
---|---|
Linter / compiler | Unnecessary blocking |
array.map(function(item) {
console.log(item);
});
const array = new NotReallyAnArray();
(array-callback-return) Array.prototype.map() expects a return value from function
FpJmybnS3yy8Ny#1kF4D6X?zgoN&TCN5H5CrM9kr
MrAfxo5L6F?KQ583fFcpp$n5z$3T#!g6e6tsjGEr
gNix&i69gQneYe#8Go@gkHSfaDd!@&XY@qHG!kL$
BftTcRJC88z!3Szqq&NChsx7D9C4LJLE&hftKksA
EoTFoxJ$nSis79zbEQGM?5ff7QCsnjoxj7pspGBo
rN6rXdxngDeDm@tlGQasFAC@g5JQ?jBHAEqK9&g!
#5?GiBXhSrfYXX@jC8SGooamhdn&Ag5Cm8$nFGj4
(a + b) / 2
Integer 2
Binary expression
using "+"
Reference to "a"
Binary expression
using "/"
Reference to "b"
Parenthesized
a / 0
Integer 0
Reference to "a"
Binary expression
using "/"
Rule: No division by 0
If I see a binary expression using "/" where on the right side there's an integer 0 , then report a problem.
someVariable + 1
const a = 1; const a = 2;
fn(tooFewOrTooManyArguments)
import "unknown-module"
*But ignorable
92% (56/61) of the recommended rules
87% (228/263) of all the rules
someVariable + 1
array.map(function(item) {
console.log(item);
});
Array.map (\item -> {- ... -}) array
Explicit call to the target function
Guaranteed to be an Array
someFunction argument =
let
a = func1(argument)
b = func2(argument)
c = func3(a, b)
in
func4(c)
someFunction argument =
let
a = func1(argument)
b = func2(argument)
c = func3(a, b)
in
func4(c)
func1 argument =
func5(
GLOBAL_VAR++,
argument
)
func2 argument =
GLOBAL_VAR + argument
???
???
References indicate explicit dependencies on values
Side-effects create hidden dependencies on operations
someFunction n =
if needToCompute(n) then
+ let
+ value =
+ expensiveComputation(n)
+ in
use(value)
else
0
someFunction n =
- let
- value =
- expensiveComputation(n)
- in
if needToCompute(n) then
use(value)
else
0
someFunction n =
let
value =
expensiveComputation(n)
in
if needToCompute(n) then
use(value)
else
0
someFunction n =
if f(n) == f(n) then
1
else
0
someFunction n =
if True then
1
else
0
someFunction n =
1
sayHello name =
let
neverUsed = toUpperCase(name)
in
"Hello " ++ format(name)
sayHello name =
let
- neverUsed = toUpperCase(name)
+ toUpperCase(name)
in
"Hello " ++ format(name)
sayHello name =
- let
- neverUsed = toUpperCase(name)
- in
"Hello " ++ format(name)
sayHello name =
let
- neverUsed = toUpperCase(name)
+ toUpperCase(name)
in
"Hello " ++ format(name)
Dynamic references
fnName = "unusedFn"
global[fnName](10)
unusedFn n =
n + 1
Post-analysis
code manipulation
-- Injected at
-- compilation time
unusedFn(10)
Arbitrary code execution
eval("unusedFn(10)")
https://slides.com/jfmengels/static-analysis-tools-love-pure-fp
Jeroen Engels
@jfmengels
Elm Radio
someFunction arg =
let
array = []
if someCondition(arg) then
array.push(arg)
else if otherCond(arg) then
array.push(0)
else
array.push(1)
in
array
someFunction arg =
if someCondition(arg) then
[ arg ]
else if otherCond(arg) then
[ 0 ]
else
[ 1 ]