Apply elm-upgrade

This commit is contained in:
Jeroen Engels 2018-11-05 14:44:22 +01:00
parent 5c56965101
commit 48e3296fc3
16 changed files with 347 additions and 188 deletions

View File

@ -1,11 +1,9 @@
{ {
"version": "2.0.1", "type": "package",
"name": "jfmengels/elm-lint",
"summary": "A linter for Elm. Get your code from correct to better.", "summary": "A linter for Elm. Get your code from correct to better.",
"repository": "https://github.com/jfmengels/elm-lint.git", "license": "BSD-3-Clause",
"license": "BSD3", "version": "2.0.1",
"source-directories": [
"src"
],
"exposed-modules": [ "exposed-modules": [
"Lint", "Lint",
"Lint.Types", "Lint.Types",
@ -25,12 +23,12 @@
"Lint.Rules.SimplifyPropertyAccess", "Lint.Rules.SimplifyPropertyAccess",
"Lint.Rules.ElmTest.NoDuplicateTestBodies" "Lint.Rules.ElmTest.NoDuplicateTestBodies"
], ],
"elm-version": "0.19.0 <= v < 0.20.0",
"dependencies": { "dependencies": {
"Bogdanp/elm-ast": "8.0.3 <= v < 9.0.0", "elm/core": "1.0.0 <= v < 2.0.0",
"elm-community/list-extra": "5.0.1 <= v < 6.0.0", "elm/html": "1.0.0 <= v < 2.0.0",
"elm-community/parser-combinators": "1.1.0 <= v < 2.0.0", "elm/regex": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "5.0.0 <= v < 6.0.0", "elm-community/list-extra": "8.1.0 <= v < 9.0.0"
"elm-lang/html": "2.0.0 <= v < 3.0.0"
}, },
"elm-version": "0.18.0 <= v < 0.19.0" "test-dependencies": {}
} }

View File

@ -1,8 +1,10 @@
module Lint.Rules.DefaultPatternPosition exposing (rule, Configuration, PatternPosition(..)) module Lint.Rules.DefaultPatternPosition exposing (rule, Configuration, PatternPosition(..))
{-| {-|
@docs rule, Configuration, PatternPosition @docs rule, Configuration, PatternPosition
# Fail # Fail
rules = rules =
@ -25,6 +27,7 @@ module Lint.Rules.DefaultPatternPosition exposing (rule, Configuration, PatternP
-- LintError, this pattern should appear first -- LintError, this pattern should appear first
_ -> result _ -> result
# Success # Success
rules = rules =
@ -49,11 +52,12 @@ module Lint.Rules.DefaultPatternPosition exposing (rule, Configuration, PatternP
case value of case value of
_ -> result _ -> result
Foo -> bar Foo -> bar
-} -}
import Ast.Expression exposing (..) import Ast.Expression exposing (..)
import Lint exposing (doNothing, lint) import Lint exposing (doNothing, lint)
import Lint.Types exposing (LintRule, Direction(..), LintError, LintRuleImplementation) import Lint.Types exposing (Direction(..), LintError, LintRule, LintRuleImplementation)
import List.Extra exposing (findIndex) import List.Extra exposing (findIndex)
import Regex import Regex
@ -88,7 +92,7 @@ implementation configuration =
{ statementFn = doNothing { statementFn = doNothing
, typeFn = doNothing , typeFn = doNothing
, expressionFn = expressionFn configuration , expressionFn = expressionFn configuration
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = \ctx -> ( [], ctx )
, initialContext = Context , initialContext = Context
} }
@ -113,6 +117,7 @@ isDefaultPattern pattern =
Variable names -> Variable names ->
if isVariable (String.join "." names) then if isVariable (String.join "." names) then
True True
else else
False False
@ -138,12 +143,14 @@ expressionFn config ctx node =
First -> First ->
if index /= 0 then if index /= 0 then
( [ error "Expected default pattern to appear first in the list of patterns" ], ctx ) ( [ error "Expected default pattern to appear first in the list of patterns" ], ctx )
else else
( [], ctx ) ( [], ctx )
Last -> Last ->
if index /= (List.length patterns) - 1 then if index /= List.length patterns - 1 then
( [ error "Expected default pattern to appear last in the list of patterns" ], ctx ) ( [ error "Expected default pattern to appear last in the list of patterns" ], ctx )
else else
( [], ctx ) ( [], ctx )

View File

@ -1,44 +1,52 @@
module Lint.Rules.ElmTest.NoDuplicateTestBodies exposing (rule) module Lint.Rules.ElmTest.NoDuplicateTestBodies exposing (rule)
{-| {-|
@docs rule @docs rule
# Fail # Fail
module Addition exposing (..)
import Test exposing (test) import Test exposing (test)
tests = tests =
[ test "foo" <| [ test "foo" <|
\() -> 1 + 1 \() ->
|> Expect.equal 2 1
+ 1
|> Expect.equal 2
, test "bar" <| , test "bar" <|
\() -> 1 + 1 \() ->
|> Expect.equal 2 1
+ 1
|> Expect.equal 2
] ]
# Success # Success
module Addition exposing (..)
import Test exposing (test) import Test exposing (test)
tests = tests =
[ test "foo" <| [ test "foo" <|
\() -> 1 + 1 \() ->
|> Expect.equal 2 1
+ 1
|> Expect.equal 2
, test "bar" <| , test "bar" <|
\() -> 1 + 2 \() ->
|> Expect.equal 3 1
+ 2
|> Expect.equal 3
] ]
-} -}
import Ast.Expression exposing (..) import Ast.Expression exposing (..)
import Ast.Statement exposing (..) import Ast.Statement exposing (..)
import Lint exposing (lint, doNothing)
import Lint.Types exposing (LintRule, LintRuleImplementation, LintError, Direction(..))
import Dict exposing (Dict) import Dict exposing (Dict)
import Lint exposing (doNothing, lint)
import Lint.Types exposing (Direction(..), LintError, LintRule, LintRuleImplementation)
type alias Context = type alias Context =
@ -53,6 +61,7 @@ This may result in specifications that are thought to be implemented but are not
rules = rules =
[ ElmTest.NoDuplicateTestBodies.rule [ ElmTest.NoDuplicateTestBodies.rule
] ]
-} -}
rule : LintRule rule : LintRule
rule input = rule input =
@ -64,7 +73,7 @@ implementation =
{ statementFn = statementFn { statementFn = statementFn
, typeFn = doNothing , typeFn = doNothing
, expressionFn = expressionFn , expressionFn = expressionFn
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = \ctx -> ( [], ctx )
, initialContext = Context [] , initialContext = Context []
} }
@ -97,6 +106,7 @@ filterTests availableTestAliases listItems =
BinOp (Variable [ "<|" ]) (Application fn (String title)) testBody -> BinOp (Variable [ "<|" ]) (Application fn (String title)) testBody ->
if isTestFunctionCall availableTestAliases fn then if isTestFunctionCall availableTestAliases fn then
[ ( title, testBody ) ] [ ( title, testBody ) ]
else else
[] []
@ -124,17 +134,17 @@ expressionFn ctx node =
existingTest = existingTest =
Dict.get testBodyAsString dict Dict.get testBodyAsString dict
in in
case existingTest of case existingTest of
Nothing -> Nothing ->
{ dict = Dict.insert testBodyAsString title dict, redundant = redundant } { dict = Dict.insert testBodyAsString title dict, redundant = redundant }
Just existingTestTitle -> Just existingTestTitle ->
{ dict = dict, redundant = redundant ++ [ ( title, existingTestTitle ) ] } { dict = dict, redundant = redundant ++ [ ( title, existingTestTitle ) ] }
) )
{ dict = Dict.empty, redundant = [] } { dict = Dict.empty, redundant = [] }
tests tests
in in
( List.map error redundantTests.redundant, ctx ) ( List.map error redundantTests.redundant, ctx )
_ -> _ ->
( [], ctx ) ( [], ctx )
@ -152,6 +162,7 @@ extractImported exportSet =
FunctionExport name -> FunctionExport name ->
if name == "test" then if name == "test" then
[ name ] [ name ]
else else
[] []
@ -172,12 +183,12 @@ statementFn ctx node =
moduleFnAccess = moduleFnAccess =
computeAlias testAlias ++ ".test" computeAlias testAlias ++ ".test"
in in
case exportSet of case exportSet of
Nothing -> Nothing ->
( [], { availableTestAliases = [ moduleFnAccess ] } ) ( [], { availableTestAliases = [ moduleFnAccess ] } )
Just subExportSet -> Just subExportSet ->
( [], { availableTestAliases = [ moduleFnAccess ] ++ extractImported subExportSet } ) ( [], { availableTestAliases = [ moduleFnAccess ] ++ extractImported subExportSet } )
_ -> _ ->
( [], ctx ) ( [], ctx )

View File

@ -1,22 +1,44 @@
module Lint.Rules.NoConstantCondition exposing (rule) module Lint.Rules.NoConstantCondition exposing (rule)
{-| {-|
@docs rule @docs rule
# Fail # Fail
if True then a else b if True then
if False then a else b a
if foo == foo then a else b
else
b
if False then
a
else
b
if foo == foo then
a
else
b
# Success # Success
if foo == bar then a else b if foo == bar then
a
else
b
-} -}
import Ast.Expression exposing (..) import Ast.Expression exposing (..)
import Lint exposing (lint, doNothing) import Lint exposing (doNothing, lint)
import Lint.Types exposing (LintRule, LintRuleImplementation, LintError, Direction(..)) import Lint.Types exposing (Direction(..), LintError, LintRule, LintRuleImplementation)
import Set exposing (Set) import Set exposing (Set)
@ -29,6 +51,7 @@ type alias Context =
rules = rules =
[ NoConstantCondition.rule [ NoConstantCondition.rule
] ]
-} -}
rule : LintRule rule : LintRule
rule input = rule input =
@ -40,7 +63,7 @@ implementation =
{ statementFn = doNothing { statementFn = doNothing
, typeFn = doNothing , typeFn = doNothing
, expressionFn = expressionFn , expressionFn = expressionFn
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = \ctx -> ( [], ctx )
, initialContext = Context , initialContext = Context
} }
@ -74,6 +97,7 @@ isStatic expr =
Variable value -> Variable value ->
if isStaticVariable value then if isStaticVariable value then
True True
else else
False False
@ -87,7 +111,7 @@ isStatic expr =
True True
BinOp (Variable op) left right -> BinOp (Variable op) left right ->
(Set.member op comparisonOperators) Set.member op comparisonOperators
&& (left == right || (isStatic left && isStatic right)) && (left == right || (isStatic left && isStatic right))
_ -> _ ->
@ -100,6 +124,7 @@ expressionFn ctx node =
Enter (If cond _ _) -> Enter (If cond _ _) ->
if isStatic cond then if isStatic cond then
( [ error ], ctx ) ( [ error ], ctx )
else else
( [], ctx ) ( [], ctx )

View File

@ -1,27 +1,38 @@
module Lint.Rules.NoDebug exposing (rule) module Lint.Rules.NoDebug exposing (rule)
{-| {-|
@docs rule @docs rule
# Fail # Fail
if Debug.log "condition" condition then a else b if Debug.log "condition" condition then
a
else
b
if condition then if condition then
Debug.crash "Nooo!" Debug.crash "Nooo!"
else else
value value
# Success # Success
if condition then if condition then
a a
else else
b b
-} -}
import Ast.Expression exposing (..) import Ast.Expression exposing (..)
import Lint exposing (lint, doNothing) import Lint exposing (doNothing, lint)
import Lint.Types exposing (LintRule, LintRuleImplementation, LintError, Direction(..)) import Lint.Types exposing (Direction(..), LintError, LintRule, LintRuleImplementation)
type alias Context = type alias Context =
@ -33,6 +44,7 @@ type alias Context =
rules = rules =
[ NoDebug.rule [ NoDebug.rule
] ]
-} -}
rule : LintRule rule : LintRule
rule input = rule input =
@ -44,7 +56,7 @@ implementation =
{ statementFn = doNothing { statementFn = doNothing
, typeFn = doNothing , typeFn = doNothing
, expressionFn = expressionFn , expressionFn = expressionFn
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = \ctx -> ( [], ctx )
, initialContext = Context , initialContext = Context
} }
@ -60,6 +72,7 @@ expressionFn ctx node =
Enter (Variable vars) -> Enter (Variable vars) ->
if List.member "Debug" vars then if List.member "Debug" vars then
( [ error ], ctx ) ( [ error ], ctx )
else else
( [], ctx ) ( [], ctx )

View File

@ -1,21 +1,25 @@
module Lint.Rules.NoDuplicateImports exposing (rule) module Lint.Rules.NoDuplicateImports exposing (rule)
{-| {-|
@docs rule @docs rule
# Fail # Fail
import Set import Set
import Set exposing (Set) import Set exposing (Set)
# Success # Success
import Set exposing (Set) import Set exposing (Set)
-} -}
import Ast.Statement exposing (..) import Ast.Statement exposing (..)
import Lint exposing (lint, doNothing) import Lint exposing (doNothing, lint)
import Lint.Types exposing (LintRule, LintRuleImplementation, LintError, Direction(..)) import Lint.Types exposing (Direction(..), LintError, LintRule, LintRuleImplementation)
import Set exposing (Set) import Set exposing (Set)
@ -30,6 +34,7 @@ type alias Context =
rules = rules =
[ NoDuplicateImports.rule [ NoDuplicateImports.rule
] ]
-} -}
rule : LintRule rule : LintRule
rule input = rule input =
@ -59,10 +64,11 @@ statementFn ctx node =
name = name =
String.join "." names String.join "." names
in in
if Set.member name ctx.imports then if Set.member name ctx.imports then
( [], { ctx | duplicates = Set.insert name ctx.duplicates } ) ( [], { ctx | duplicates = Set.insert name ctx.duplicates } )
else
( [], { ctx | imports = Set.insert name ctx.imports } ) else
( [], { ctx | imports = Set.insert name ctx.imports } )
_ -> _ ->
( [], ctx ) ( [], ctx )
@ -75,4 +81,4 @@ moduleEndFn ctx =
Set.toList ctx.duplicates Set.toList ctx.duplicates
|> List.map error |> List.map error
in in
( errors, ctx ) ( errors, ctx )

View File

@ -1,21 +1,25 @@
module Lint.Rules.NoImportingEverything exposing (rule, Configuration) module Lint.Rules.NoImportingEverything exposing (rule, Configuration)
{-| {-|
@docs rule, Configuration @docs rule, Configuration
# Fail # Fail
import Html exposing (..) import Html exposing (..)
# Success # Success
import Html exposing (div, p, textarea) import Html exposing (div, p, textarea)
-} -}
import Set exposing (Set)
import Ast.Statement exposing (..) import Ast.Statement exposing (..)
import Lint exposing (lint, doNothing) import Lint exposing (doNothing, lint)
import Lint.Types exposing (LintRule, LintRuleImplementation, LintError, Direction(..)) import Lint.Types exposing (Direction(..), LintError, LintRule, LintRuleImplementation)
import Set exposing (Set)
type alias Context = type alias Context =
@ -32,8 +36,9 @@ type alias Configuration =
functions and types are unknown to them. functions and types are unknown to them.
rules = rules =
[ NoImportingEverything.rule { exceptions = ["Html"]} [ NoImportingEverything.rule { exceptions = [ "Html" ] }
] ]
-} -}
rule : Configuration -> LintRule rule : Configuration -> LintRule
rule exceptions input = rule exceptions input =
@ -45,7 +50,7 @@ implementation config =
{ statementFn = statementFn { statementFn = statementFn
, typeFn = doNothing , typeFn = doNothing
, expressionFn = doNothing , expressionFn = doNothing
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = \ctx -> ( [], ctx )
, initialContext = Context (Set.fromList config.exceptions) , initialContext = Context (Set.fromList config.exceptions)
} }
@ -63,10 +68,11 @@ statementFn ctx node =
name = name =
String.join "." names String.join "." names
in in
if Set.member name ctx.exceptions then if Set.member name ctx.exceptions then
( [], ctx ) ( [], ctx )
else
( [ error name ], ctx ) else
( [ error name ], ctx )
_ -> _ ->
( [], ctx ) ( [], ctx )

View File

@ -1,23 +1,27 @@
module Lint.Rules.NoUnannotatedFunction exposing (rule) module Lint.Rules.NoUnannotatedFunction exposing (rule)
{-| {-|
@docs rule @docs rule
# Fail # Fail
a n = a n =
n + 1 n + 1
# Success # Success
a : Int -> Int a : Int -> Int
a n = a n =
n + 1 n + 1
-} -}
import Ast.Statement exposing (..) import Ast.Statement exposing (..)
import Lint exposing (lint, doNothing) import Lint exposing (doNothing, lint)
import Lint.Types exposing (LintRule, LintRuleImplementation, LintError, Direction(..)) import Lint.Types exposing (Direction(..), LintError, LintRule, LintRuleImplementation)
import Set exposing (Set) import Set exposing (Set)
@ -31,6 +35,7 @@ type alias Context =
rules = rules =
[ NoUnannotatedFunction.rule [ NoUnannotatedFunction.rule
] ]
-} -}
rule : LintRule rule : LintRule
rule input = rule input =
@ -42,7 +47,7 @@ implementation =
{ statementFn = statementFn { statementFn = statementFn
, typeFn = doNothing , typeFn = doNothing
, expressionFn = doNothing , expressionFn = doNothing
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = \ctx -> ( [], ctx )
, initialContext = Context Set.empty , initialContext = Context Set.empty
} }
@ -61,6 +66,7 @@ statementFn ctx node =
Enter (FunctionDeclaration name params body) -> Enter (FunctionDeclaration name params body) ->
if Set.member name ctx.annotatedFunctions then if Set.member name ctx.annotatedFunctions then
( [], ctx ) ( [], ctx )
else else
( [ createError name ], ctx ) ( [ createError name ], ctx )

View File

@ -1,26 +1,32 @@
module Lint.Rules.NoUnusedVariables exposing (rule) module Lint.Rules.NoUnusedVariables exposing (rule)
{-| {-|
@docs rule @docs rule
# Fail # Fail
module Main exposing (a)
a n = a n =
n + 1 n + 1
b = a 2
b =
a 2
# Success # Success
module Main exposing (a)
a n = a n =
n + 1 n + 1
-} -}
import Ast.Expression exposing (..) import Ast.Expression exposing (..)
import Ast.Statement exposing (..) import Ast.Statement exposing (..)
import Lint exposing (doNothing, lint) import Lint exposing (doNothing, lint)
import Lint.Types exposing (LintRule, Direction(..), LintError, LintRuleImplementation) import Lint.Types exposing (Direction(..), LintError, LintRule, LintRuleImplementation)
import Set exposing (Set) import Set exposing (Set)
@ -46,6 +52,7 @@ emptyScope =
rules = rules =
[ NoUnusedVariables.rule [ NoUnusedVariables.rule
] ]
-} -}
rule : LintRule rule : LintRule
rule input = rule input =
@ -78,7 +85,7 @@ addUsedToStack scopes variables =
Just scope -> Just scope ->
{ scope | used = Set.union scope.used (Set.fromList variables) } { scope | used = Set.union scope.used (Set.fromList variables) }
in in
lastScope :: (List.drop 1 scopes) lastScope :: List.drop 1 scopes
addFoundToStack : List Scope -> List String -> List Scope addFoundToStack : List Scope -> List String -> List Scope
@ -92,7 +99,7 @@ addFoundToStack scopes variables =
Just scope -> Just scope ->
{ scope | declared = Set.union scope.declared (Set.fromList variables) } { scope | declared = Set.union scope.declared (Set.fromList variables) }
in in
lastScope :: (List.drop 1 scopes) lastScope :: List.drop 1 scopes
makeReport : Maybe Scope -> ( List LintError, Set String ) makeReport : Maybe Scope -> ( List LintError, Set String )
@ -115,7 +122,7 @@ makeReport scope =
|> List.sort |> List.sort
|> List.map createError |> List.map createError
in in
( errors, variablesUsedButNotFromThisScope ) ( errors, variablesUsedButNotFromThisScope )
variableName : Expression -> Maybe (List String) variableName : Expression -> Maybe (List String)
@ -153,7 +160,7 @@ expressionFn ctx node =
newScope = newScope =
Scope variables Set.empty Scope variables Set.empty
in in
( [], { ctx | scopes = newScope :: ctx.scopes } ) ( [], { ctx | scopes = newScope :: ctx.scopes } )
Exit (Let _ _) -> Exit (Let _ _) ->
let let
@ -165,7 +172,7 @@ expressionFn ctx node =
newScopes = newScopes =
List.drop 1 ctx.scopes List.drop 1 ctx.scopes
in in
( errors, { ctx | scopes = addUsedToStack newScopes (Set.toList variablesUsedButNotFromThisScope) } ) ( errors, { ctx | scopes = addUsedToStack newScopes (Set.toList variablesUsedButNotFromThisScope) } )
_ -> _ ->
( [], ctx ) ( [], ctx )
@ -226,7 +233,7 @@ statementFn ctx node =
[] []
imported imported
in in
( [], { ctx | scopes = addFoundToStack ctx.scopes variables } ) ( [], { ctx | scopes = addFoundToStack ctx.scopes variables } )
Enter (ModuleDeclaration names exportType) -> Enter (ModuleDeclaration names exportType) ->
( [], addExposedVariables ctx exportType ) ( [], addExposedVariables ctx exportType )
@ -244,9 +251,10 @@ moduleEndFn ctx =
( errors, _ ) = ( errors, _ ) =
if ctx.exportsEverything then if ctx.exportsEverything then
( [], Set.empty ) ( [], Set.empty )
else else
ctx.scopes ctx.scopes
|> List.head |> List.head
|> makeReport |> makeReport
in in
( errors, ctx ) ( errors, ctx )

View File

@ -1,26 +1,32 @@
module Lint.Rules.NoUselessIf exposing (rule) module Lint.Rules.NoUselessIf exposing (rule)
{-| {-|
@docs rule @docs rule
# Fail # Fail
if condition then if condition then
value value
else else
value value
# Success # Success
if condition then if condition then
value1 value1
else else
value2 value2
-} -}
import Ast.Expression exposing (..) import Ast.Expression exposing (..)
import Lint exposing (lint, doNothing) import Lint exposing (doNothing, lint)
import Lint.Types exposing (LintRule, LintRuleImplementation, LintError, Direction(..)) import Lint.Types exposing (Direction(..), LintError, LintRule, LintRuleImplementation)
type alias Context = type alias Context =
@ -32,6 +38,7 @@ type alias Context =
rules = rules =
[ NoUselessIf.rule [ NoUselessIf.rule
] ]
-} -}
rule : LintRule rule : LintRule
rule input = rule input =
@ -43,7 +50,7 @@ implementation =
{ statementFn = doNothing { statementFn = doNothing
, typeFn = doNothing , typeFn = doNothing
, expressionFn = expressionFn , expressionFn = expressionFn
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = \ctx -> ( [], ctx )
, initialContext = Context , initialContext = Context
} }
@ -59,6 +66,7 @@ expressionFn ctx node =
Enter (If cond then_ else_) -> Enter (If cond then_ else_) ->
if then_ == else_ then if then_ == else_ then
( [ error ], ctx ) ( [ error ], ctx )
else else
( [], ctx ) ( [], ctx )

View File

@ -1,37 +1,59 @@
module Lint.Rules.NoUselessPatternMatching exposing (rule) module Lint.Rules.NoUselessPatternMatching exposing (rule)
{-| {-|
@docs rule @docs rule
# Fail # Fail
-- Useless pattern matching -- Useless pattern matching
case value of case value of
Foo -> 1 Foo ->
Bar -> 1 1
_ -> 1
Bar ->
1
_ ->
1
-- Useless pattern `Bar`, it's the same as the default pattern -- Useless pattern `Bar`, it's the same as the default pattern
case value of case value of
Foo -> 2 Foo ->
Bar -> 1 2
_ -> 1
Bar ->
1
_ ->
1
# Success # Success
case value of case value of
Foo -> 1 Foo ->
Bar -> 2 1
_ -> 3
Bar ->
2
_ ->
3
case value of case value of
Foo n -> n Foo n ->
Bar n -> n n
Bar n ->
n
-} -}
import Ast.Expression exposing (..) import Ast.Expression exposing (..)
import Lint exposing (lint, visitExpression, doNothing) import Lint exposing (doNothing, lint, visitExpression)
import Lint.Types exposing (LintRule, LintRuleImplementation, LintError, Direction(..)) import Lint.Types exposing (Direction(..), LintError, LintRule, LintRuleImplementation)
import Regex import Regex
import Set exposing (Set) import Set exposing (Set)
@ -46,6 +68,7 @@ pattern will lead to the same value as the default pattern.
rules = rules =
[ NoUselessPatternMatching.rule [ NoUselessPatternMatching.rule
] ]
-} -}
rule : LintRule rule : LintRule
rule input = rule input =
@ -57,7 +80,7 @@ implementation =
{ statementFn = doNothing { statementFn = doNothing
, typeFn = doNothing , typeFn = doNothing
, expressionFn = expressionFn , expressionFn = expressionFn
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = \ctx -> ( [], ctx )
, initialContext = Context , initialContext = Context
} }
@ -67,7 +90,7 @@ variableFinder =
{ statementFn = doNothing { statementFn = doNothing
, typeFn = doNothing , typeFn = doNothing
, expressionFn = findVariable , expressionFn = findVariable
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = \ctx -> ( [], ctx )
, initialContext = Set.empty , initialContext = Set.empty
} }
@ -104,7 +127,7 @@ subPatternMatchingVariables pattern =
[ String.join "." a ] [ String.join "." a ]
Application object variable -> Application object variable ->
(subPatternMatchingVariables object) ++ (subPatternMatchingVariables variable) subPatternMatchingVariables object ++ subPatternMatchingVariables variable
_ -> _ ->
[] []
@ -145,7 +168,7 @@ patternsAreAllTheSame patterns =
|> Set.fromList |> Set.fromList
|> (\set -> Set.size set == 1) |> (\set -> Set.size set == 1)
in in
(not anyUseVariables) && bodiesAreIdentical not anyUseVariables && bodiesAreIdentical
defaultPattern : List ( Expression, Expression, Set String, Set String ) -> Maybe ( Expression, Expression, Set String, Set String ) defaultPattern : List ( Expression, Expression, Set String, Set String ) -> Maybe ( Expression, Expression, Set String, Set String )
@ -161,6 +184,7 @@ defaultPattern patterns =
Variable names -> Variable names ->
if isVariable (String.join "." names) then if isVariable (String.join "." names) then
Just ( pattern, body, used, declared ) Just ( pattern, body, used, declared )
else else
Nothing Nothing
@ -193,18 +217,17 @@ thereAreUselessPatterns patterns =
justDefault = justDefault =
Maybe.withDefault ( Integer 1, Integer 1, Set.empty, Set.empty ) default Maybe.withDefault ( Integer 1, Integer 1, Set.empty, Set.empty ) default
in in
hasDefault hasDefault
&& (List.foldl && List.foldl
(\pattern res -> (\pattern res ->
res res
|| ((pattern /= justDefault) || ((pattern /= justDefault)
&& (patternBody pattern == patternBody justDefault) && (patternBody pattern == patternBody justDefault)
&& not (usesIntroducedVariable pattern) && not (usesIntroducedVariable pattern)
) )
) )
False False
patterns patterns
)
expressionFn : Context -> Direction Expression -> ( List LintError, Context ) expressionFn : Context -> Direction Expression -> ( List LintError, Context )
@ -219,12 +242,14 @@ expressionFn ctx node =
( pattern, body, Tuple.second <| visitExpression variableFinder body, patternMatchingVariables pattern ) ( pattern, body, Tuple.second <| visitExpression variableFinder body, patternMatchingVariables pattern )
) )
in in
if patternsAreAllTheSame analyzedPatterns then if patternsAreAllTheSame analyzedPatterns then
( [ uselessPatternMatchingError ], ctx ) ( [ uselessPatternMatchingError ], ctx )
else if thereAreUselessPatterns analyzedPatterns then
( [ uselessPatternError ], ctx ) else if thereAreUselessPatterns analyzedPatterns then
else ( [ uselessPatternError ], ctx )
( [], ctx )
else
( [], ctx )
_ -> _ ->
( [], ctx ) ( [], ctx )

View File

@ -1,22 +1,30 @@
module Lint.Rules.NoWarningComments exposing (rule) module Lint.Rules.NoWarningComments exposing (rule)
{-| {-|
@docs rule @docs rule
# Fail # Fail
-- TODO Refactor this part of the code -- TODO Refactor this part of the code
-- FIXME Broken because of... -- FIXME Broken because of...
-- XXX This should not be done like this -- XXX This should not be done like this
# Success # Success
-- Regular comment -- Regular comment
-} -}
import Ast.Statement exposing (..) import Ast.Statement exposing (..)
import Lint exposing (doNothing, lint) import Lint exposing (doNothing, lint)
import Lint.Types exposing (LintRule, Direction(..), LintError, LintRuleImplementation) import Lint.Types exposing (Direction(..), LintError, LintRule, LintRuleImplementation)
type alias Context = type alias Context =
@ -28,6 +36,7 @@ type alias Context =
rules = rules =
[ NoWarningComments.rule [ NoWarningComments.rule
] ]
-} -}
rule : LintRule rule : LintRule
rule input = rule input =
@ -39,7 +48,7 @@ implementation =
{ statementFn = statementFn { statementFn = statementFn
, typeFn = doNothing , typeFn = doNothing
, expressionFn = doNothing , expressionFn = doNothing
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = \ctx -> ( [], ctx )
, initialContext = Context , initialContext = Context
} }
@ -53,16 +62,22 @@ findWarning : String -> Maybe LintError
findWarning text = findWarning text =
if String.contains "TODO" text then if String.contains "TODO" text then
Just <| error "TODO" Just <| error "TODO"
else if String.contains "todo" text then else if String.contains "todo" text then
Just <| error "todo" Just <| error "todo"
else if String.contains "FIXME" text then else if String.contains "FIXME" text then
Just <| error "FIXME" Just <| error "FIXME"
else if String.contains "fixme" text then else if String.contains "fixme" text then
Just <| error "fixme" Just <| error "fixme"
else if String.contains "XXX" text then else if String.contains "XXX" text then
Just <| error "XXX" Just <| error "XXX"
else if String.contains "xxx" text then else if String.contains "xxx" text then
Just <| error "xxx" Just <| error "xxx"
else else
Nothing Nothing
@ -75,12 +90,12 @@ statementFn ctx node =
warning = warning =
findWarning text findWarning text
in in
case warning of case warning of
Just err -> Just err ->
( [ err ], ctx ) ( [ err ], ctx )
Nothing -> Nothing ->
( [], ctx ) ( [], ctx )
_ -> _ ->
( [], ctx ) ( [], ctx )

View File

@ -1,23 +1,29 @@
module Lint.Rules.SimplifyPiping exposing (rule) module Lint.Rules.SimplifyPiping exposing (rule)
{-| {-|
@docs rule @docs rule
# Fail # Fail
a = values a =
|> List.map foo values
|> List.map bar |> List.map foo
|> List.map bar
# Success # Success
a = values a =
|> List.map (foo >> bar) values
|> List.map (foo >> bar)
-} -}
import Ast.Expression exposing (..) import Ast.Expression exposing (..)
import Lint exposing (lint, doNothing) import Lint exposing (doNothing, lint)
import Lint.Types exposing (LintRule, LintRuleImplementation, LintError, Direction(..)) import Lint.Types exposing (Direction(..), LintError, LintRule, LintRuleImplementation)
import Set exposing (Set) import Set exposing (Set)
@ -30,6 +36,7 @@ type alias Context =
rules = rules =
[ SimplifyPiping.rule [ SimplifyPiping.rule
] ]
-} -}
rule : LintRule rule : LintRule
rule input = rule input =
@ -41,7 +48,7 @@ implementation =
{ statementFn = doNothing { statementFn = doNothing
, typeFn = doNothing , typeFn = doNothing
, expressionFn = expressionFn , expressionFn = expressionFn
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = \ctx -> ( [], ctx )
, initialContext = Context , initialContext = Context
} }
@ -76,6 +83,7 @@ reportIfSimplifiableMethod op left right =
[ Application (Access (Variable names1) fns1) _, Application (Access (Variable names2) fns2) _ ] -> [ Application (Access (Variable names1) fns1) _, Application (Access (Variable names2) fns2) _ ] ->
if [ names1, fns1 ] == [ names2, fns2 ] && Set.member (nameOfMethod [ names1, fns1 ]) simplifiableFns then if [ names1, fns1 ] == [ names2, fns2 ] && Set.member (nameOfMethod [ names1, fns1 ]) simplifiableFns then
[ error op <| nameOfMethod [ names1, fns1 ] ] [ error op <| nameOfMethod [ names1, fns1 ] ]
else else
[] []

View File

@ -1,21 +1,27 @@
module Lint.Rules.SimplifyPropertyAccess exposing (rule) module Lint.Rules.SimplifyPropertyAccess exposing (rule)
{-| {-|
@docs rule @docs rule
# Fail # Fail
a = List.map (\x -> x.foo) values a =
List.map (\x -> x.foo) values
# Success # Success
a = List.map .foo values a =
List.map .foo values
-} -}
import Ast.Statement exposing (..)
import Ast.Expression exposing (..) import Ast.Expression exposing (..)
import Lint exposing (lint, doNothing) import Ast.Statement exposing (..)
import Lint.Types exposing (LintRule, LintRuleImplementation, LintError, Direction(..)) import Lint exposing (doNothing, lint)
import Lint.Types exposing (Direction(..), LintError, LintRule, LintRuleImplementation)
type alias Context = type alias Context =
@ -27,6 +33,7 @@ type alias Context =
rules = rules =
[ SimplifyPropertyAccess.rule [ SimplifyPropertyAccess.rule
] ]
-} -}
rule : LintRule rule : LintRule
rule input = rule input =
@ -38,7 +45,7 @@ implementation =
{ statementFn = statementFn { statementFn = statementFn
, typeFn = doNothing , typeFn = doNothing
, expressionFn = expressionFn , expressionFn = expressionFn
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = \ctx -> ( [], ctx )
, initialContext = Context , initialContext = Context
} }
@ -54,6 +61,7 @@ expressionFn ctx node =
Enter (Lambda [ Variable paramNames ] (Access (Variable varName) properties)) -> Enter (Lambda [ Variable paramNames ] (Access (Variable varName) properties)) ->
if List.length properties == 1 && varName == paramNames then if List.length properties == 1 && varName == paramNames then
( [ String.join "" properties |> error ], ctx ) ( [ String.join "" properties |> error ], ctx )
else else
( [], ctx ) ( [], ctx )
@ -67,6 +75,7 @@ statementFn ctx node =
Enter (FunctionDeclaration _ [ Variable paramNames ] (Access (Variable varName) properties)) -> Enter (FunctionDeclaration _ [ Variable paramNames ] (Access (Variable varName) properties)) ->
if List.length properties == 1 && varName == paramNames then if List.length properties == 1 && varName == paramNames then
( [ String.join "" properties |> error ], ctx ) ( [ String.join "" properties |> error ], ctx )
else else
( [], ctx ) ( [], ctx )

View File

@ -1,31 +1,32 @@
module Lint.Types module Lint.Types exposing
exposing ( LintError, Direction(..)
( Direction(..) , LintRule, Severity(..), Reporter
, File , LintRuleImplementation, LintImplementation
, LintError , Visitor, LintResult, File
, LintImplementation )
, LintResult
, LintRule
, LintRuleImplementation
, Reporter
, Severity
, Severity(..)
, Visitor
)
{-| This module contains types that are used for writing rules. {-| This module contains types that are used for writing rules.
# Elementary types # Elementary types
@docs LintError, Direction @docs LintError, Direction
# Configuration # Configuration
@docs LintRule, Severity, Reporter @docs LintRule, Severity, Reporter
# Writing rules # Writing rules
@docs LintRuleImplementation, LintImplementation @docs LintRuleImplementation, LintImplementation
# Internal types # Internal types
@docs Visitor, LintResult, File @docs Visitor, LintResult, File
-} -}
import Ast.Expression exposing (..) import Ast.Expression exposing (..)
@ -38,6 +39,7 @@ a description of the error.
error : LintError error : LintError
error = error =
LintError "NoDebug" "Forbidden use of Debug" LintError "NoDebug" "Forbidden use of Debug"
-} -}
type alias LintError = type alias LintError =
{ rule : String { rule : String
@ -63,31 +65,35 @@ enforce.
{ statementFn = doNothing { statementFn = doNothing
, typeFn = doNothing , typeFn = doNothing
, expressionFn = expressionFn , expressionFn = expressionFn
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = \ctx -> ( [], ctx )
, initialContext = Context , initialContext = Context
} }
-} -}
type alias LintImplementation nodeType context = type alias LintImplementation nodeType context =
context -> Direction nodeType -> ( List LintError, context ) context -> Direction nodeType -> ( List LintError, context )
{-| When visiting the AST, nodes are visited twice: {-| When visiting the AST, nodes are visited twice:
- on Enter, before the children of the node will be visited
- on Exit, after the children of the node have been visited - on Enter, before the children of the node will be visited
- on Exit, after the children of the node have been visited
expressionFn : Context -> Direction Expression -> ( List LintError, Context ) expressionFn : Context -> Direction Expression -> ( List LintError, Context )
expressionFn ctx node = expressionFn ctx node =
case node of case node of
Enter (Variable names) -> Enter (Variable names) ->
( [], markVariableAsUsed ctx names ) ( [], markVariableAsUsed ctx names )
-- Find variables declared in `let .. in ..` expression -- Find variables declared in `let .. in ..` expression
Enter (Let declarations body) -> Enter (Let declarations body) ->
( [], registerVariables ctx declarations ) ( [], registerVariables ctx declarations )
-- When exiting the `let .. in ..` expression, report the variables that were not used.
Exit (Let _ _) ->
( unusedVariables ctx |> List.map createError, ctx )
-- When exiting the `let .. in ..` expression, report the variables that were not used.
Exit (Let _ _) ->
( unusedVariables ctx |> List.map createError, ctx )
-} -}
type Direction node type Direction node
= Enter node = Enter node
@ -95,25 +101,31 @@ type Direction node
{-| A LintRuleImplementation is the implementation of a rule. It is a record that contains: {-| A LintRuleImplementation is the implementation of a rule. It is a record that contains:
- initialContext: An initial context
- statementFn: A LintImplementation for Statement nodes - initialContext: An initial context
- typeFn: A LintImplementation for Type nodes
- expressionFn: A LintImplementation for Expression nodes - statementFn: A LintImplementation for Statement nodes
- moduleEndFn: A function that takes a context and returns a list of error. Similar to a LintImplementation, but will
be called after visiting the whole AST. - typeFn: A LintImplementation for Type nodes
- expressionFn: A LintImplementation for Expression nodes
- moduleEndFn: A function that takes a context and returns a list of error. Similar to a LintImplementation, but will
be called after visiting the whole AST.
rule : LintRule rule : LintRule
rule input = rule input =
lint input implementation lint input implementation
implementation : LintRuleImplementation Context implementation : LintRuleImplementation Context
implementation = implementation =
{ statementFn = doNothing { statementFn = doNothing
, typeFn = doNothing , typeFn = doNothing
, expressionFn = expressionFn , expressionFn = expressionFn
, moduleEndFn = (\ctx -> ( [], ctx )) , moduleEndFn = (\\ctx -> ( [], ctx ))
, initialContext = Context , initialContext = Context
} }
-} -}
type alias LintRuleImplementation context = type alias LintRuleImplementation context =
{ statementFn : LintImplementation Statement context { statementFn : LintImplementation Statement context
@ -140,6 +152,7 @@ type alias LintRule =
A Visitor represents a node and calls the appropriate function for the given node type. A Visitor represents a node and calls the appropriate function for the given node type.
Note: this is internal API, and will be removed in a future version. Note: this is internal API, and will be removed in a future version.
-} -}
type alias Visitor context = type alias Visitor context =
LintRuleImplementation context -> context -> ( List LintError, context ) LintRuleImplementation context -> context -> ( List LintError, context )
@ -147,9 +160,10 @@ type alias Visitor context =
{-| Severity associated to a rule. {-| Severity associated to a rule.
- Critical: Transgressions reported by the rule will make the linting process fail. - Critical: Transgressions reported by the rule will make the linting process fail.
- Warning: Transgressions reported by the rule will not make the linting process fail. - Warning: Transgressions reported by the rule will not make the linting process fail.
- Disabled: Rule will not be enforced. - Disabled: Rule will not be enforced.
-} -}
type Severity type Severity
= Disabled = Disabled

View File

@ -1,8 +1,8 @@
module Lint.Visitor exposing (transformStatementsIntoVisitors, expressionToVisitors) module Lint.Visitor exposing (expressionToVisitors, transformStatementsIntoVisitors)
import Ast.Expression exposing (..) import Ast.Expression exposing (..)
import Ast.Statement exposing (..) import Ast.Statement exposing (..)
import Lint.Types exposing (LintRule, Direction(..), Visitor) import Lint.Types exposing (Direction(..), LintRule, Visitor)
createExitAndEnterWithChildren : (Direction nodeType -> Visitor context) -> nodeType -> List (Visitor context) -> List (Visitor context) createExitAndEnterWithChildren : (Direction nodeType -> Visitor context) -> nodeType -> List (Visitor context) -> List (Visitor context)
@ -92,7 +92,7 @@ expressionToVisitors node =
childrenVisitors = childrenVisitors =
List.concatMap expressionToVisitors children List.concatMap expressionToVisitors children
in in
createExitAndEnterWithChildren expressionVisitor node childrenVisitors createExitAndEnterWithChildren expressionVisitor node childrenVisitors
typeToVisitors : Type -> List (Visitor context) typeToVisitors : Type -> List (Visitor context)
@ -114,7 +114,7 @@ statementToVisitors node =
_ -> _ ->
[] []
in in
createExitAndEnterWithChildren statementVisitor node childrenVisitors createExitAndEnterWithChildren statementVisitor node childrenVisitors
transformStatementsIntoVisitors : List Statement -> List (Visitor context) transformStatementsIntoVisitors : List Statement -> List (Visitor context)