Backport changes from review dependencies

This commit is contained in:
Jeroen Engels 2020-06-20 20:09:03 +02:00
parent 97179db534
commit c9e8f9680d
11 changed files with 478 additions and 159 deletions

View File

@ -42,4 +42,5 @@ config =
--, NoTodoComment.rule
-- |> Rule.ignoreErrorsForFiles [ "NoTodoComment" ]
]
|> List.map (Rule.ignoreErrorsForDirectories [ "src/Vendor/" ])
|> List.map (Rule.ignoreErrorsForDirectories [ "src/Vendor/"])
|> List.map (Rule.ignoreErrorsForFiles [ "tests/NoUnused/Patterns/NameVisitor.elm"])

View File

@ -218,14 +218,14 @@ moduleRule =
moduleVisitor : Rule.ModuleRuleSchema schemaState ModuleContext -> Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } ModuleContext
moduleVisitor schema =
schema
|> Rule.withExpressionEnterVisitor expressionVisitor
|> Rule.withExpressionVisitor expressionVisitor
|> Rule.withFinalModuleEvaluation finalEvaluation
expressionVisitor : Node Expression -> ModuleContext -> ( List nothing, ModuleContext )
expressionVisitor node context =
case Node.value node of
Expression.FunctionOrValue moduleName name ->
expressionVisitor : Node Expression -> Rule.Direction -> ModuleContext -> ( List nothing, ModuleContext )
expressionVisitor node direction context =
case ( direction, Node.value node ) of
( Rule.OnEnter, Expression.FunctionOrValue moduleName name ) ->
let
nameInCode : String
nameInCode =

View File

@ -70,8 +70,8 @@ rule =
moduleVisitor : Rule.ModuleRuleSchema schemaState ModuleContext -> Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } ModuleContext
moduleVisitor schema =
schema
|> Rule.withDeclarationVisitor declarationVisitor
|> Rule.withExpressionVisitor expressionVisitor
|> Rule.withDeclarationEnterVisitor declarationVisitor
|> Rule.withExpressionEnterVisitor expressionVisitor
|> Rule.withFinalModuleEvaluation finalEvaluation
@ -134,41 +134,10 @@ foldProjectContexts newContext previousContext =
}
expressionVisitor : Node Expression -> Rule.Direction -> ModuleContext -> ( List (Error {}), ModuleContext )
expressionVisitor node direction moduleContext =
case ( direction, Node.value node ) of
( Rule.OnEnter, Expression.FunctionOrValue moduleName "update" ) ->
let
realModuleName : List String
realModuleName =
Scope.moduleNameForValue moduleContext.scope "update" moduleName
in
if Set.member realModuleName moduleContext.modulesThatExposeSubscriptionsAndUpdate then
( [], { moduleContext | usesUpdateOfModule = Dict.insert realModuleName (Node.range node) moduleContext.usesUpdateOfModule } )
else
( [], moduleContext )
( Rule.OnEnter, Expression.FunctionOrValue moduleName "subscriptions" ) ->
let
realModuleName : List String
realModuleName =
Scope.moduleNameForValue moduleContext.scope "subscriptions" moduleName
in
if Set.member realModuleName moduleContext.modulesThatExposeSubscriptionsAndUpdate then
( [], { moduleContext | usesSubscriptionsOfModule = Set.insert realModuleName moduleContext.usesSubscriptionsOfModule } )
else
( [], moduleContext )
_ ->
( [], moduleContext )
declarationVisitor : Node Declaration -> Rule.Direction -> ModuleContext -> ( List (Error nothing), ModuleContext )
declarationVisitor declaration direction moduleContext =
case ( direction, Node.value declaration ) of
( Rule.OnEnter, Declaration.FunctionDeclaration function ) ->
declarationVisitor : Node Declaration -> ModuleContext -> ( List (Error nothing), ModuleContext )
declarationVisitor node moduleContext =
case Node.value node of
Declaration.FunctionDeclaration function ->
case
function.declaration
|> Node.value
@ -188,6 +157,37 @@ declarationVisitor declaration direction moduleContext =
( [], moduleContext )
expressionVisitor : Node Expression -> ModuleContext -> ( List (Error {}), ModuleContext )
expressionVisitor node moduleContext =
case Node.value node of
Expression.FunctionOrValue moduleName "update" ->
let
realModuleName : List String
realModuleName =
Scope.moduleNameForValue moduleContext.scope "update" moduleName
in
if Set.member realModuleName moduleContext.modulesThatExposeSubscriptionsAndUpdate then
( [], { moduleContext | usesUpdateOfModule = Dict.insert realModuleName (Node.range node) moduleContext.usesUpdateOfModule } )
else
( [], moduleContext )
Expression.FunctionOrValue moduleName "subscriptions" ->
let
realModuleName : List String
realModuleName =
Scope.moduleNameForValue moduleContext.scope "subscriptions" moduleName
in
if Set.member realModuleName moduleContext.modulesThatExposeSubscriptionsAndUpdate then
( [], { moduleContext | usesSubscriptionsOfModule = Set.insert realModuleName moduleContext.usesSubscriptionsOfModule } )
else
( [], moduleContext )
_ ->
( [], moduleContext )
finalEvaluation : ModuleContext -> List (Error {})
finalEvaluation moduleContext =
moduleContext.usesUpdateOfModule

View File

@ -55,8 +55,8 @@ To add the rule to your configuration:
rule : Rule
rule =
Rule.newModuleRuleSchema "NoRecursiveUpdate" { isInUpdateFunction = False }
|> Rule.withDeclarationVisitor declarationVisitor
|> Rule.withExpressionVisitor expressionVisitor
|> Rule.withDeclarationEnterVisitor declarationVisitor
|> Rule.withExpressionEnterVisitor expressionVisitor
|> Rule.fromModuleRuleSchema
@ -65,10 +65,10 @@ type alias Context =
}
declarationVisitor : Node Declaration -> Rule.Direction -> Context -> ( List nothing, Context )
declarationVisitor declaration direction _ =
case ( direction, Node.value declaration ) of
( Rule.OnEnter, Declaration.FunctionDeclaration function ) ->
declarationVisitor : Node Declaration -> Context -> ( List nothing, Context )
declarationVisitor node _ =
case Node.value node of
Declaration.FunctionDeclaration function ->
( []
, { isInUpdateFunction =
(function.declaration
@ -84,11 +84,11 @@ declarationVisitor declaration direction _ =
( [], { isInUpdateFunction = False } )
expressionVisitor : Node Expression -> Rule.Direction -> Context -> ( List (Error {}), Context )
expressionVisitor node direction context =
expressionVisitor : Node Expression -> Context -> ( List (Error {}), Context )
expressionVisitor node context =
if context.isInUpdateFunction then
case ( direction, Node.value node ) of
( Rule.OnEnter, Expression.FunctionOrValue [] "update" ) ->
case Node.value node of
Expression.FunctionOrValue [] "update" ->
( [ Rule.error
{ message = "`update` shouldn't call itself"
, details = [ "If you wish to have the same behavior for different messages, move that behavior into a new function and call have it called in the handling of both messages." ]

View File

@ -20,7 +20,7 @@ import Elm.Syntax.ModuleName exposing (ModuleName)
import Elm.Syntax.Node as Node exposing (Node)
import Elm.Syntax.Signature exposing (Signature)
import Elm.Syntax.TypeAnnotation as TypeAnnotation exposing (TypeAnnotation)
import Review.Rule as Rule exposing (Direction, Error, Rule)
import Review.Rule as Rule exposing (Error, Rule)
import Scope
import Set exposing (Set)
@ -129,8 +129,8 @@ moduleVisitor schema =
schema
|> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor
|> Rule.withDeclarationListVisitor declarationListVisitor
|> Rule.withDeclarationVisitor declarationVisitor
|> Rule.withExpressionVisitor expressionVisitor
|> Rule.withDeclarationEnterVisitor declarationVisitor
|> Rule.withExpressionEnterVisitor expressionVisitor
@ -385,10 +385,10 @@ register node context =
-- DECLARATION VISITOR
declarationVisitor : Node Declaration -> Direction -> ModuleContext -> ( List nothing, ModuleContext )
declarationVisitor node direction context =
case ( direction, Node.value node ) of
( Rule.OnEnter, Declaration.CustomTypeDeclaration { name, constructors } ) ->
declarationVisitor : Node Declaration -> ModuleContext -> ( List nothing, ModuleContext )
declarationVisitor node context =
case Node.value node of
Declaration.CustomTypeDeclaration { name, constructors } ->
let
constructorsForCustomType : Dict String (Node String)
constructorsForCustomType =
@ -417,7 +417,7 @@ declarationVisitor node direction context =
}
)
( Rule.OnEnter, Declaration.FunctionDeclaration function ) ->
Declaration.FunctionDeclaration function ->
( [], markPhantomTypesFromTypeSignatureAsUsed function.signature context )
_ ->
@ -428,13 +428,13 @@ declarationVisitor node direction context =
-- EXPRESSION VISITOR
expressionVisitor : Node Expression -> Direction -> ModuleContext -> ( List nothing, ModuleContext )
expressionVisitor node direction moduleContext =
case ( direction, Node.value node ) of
( Rule.OnEnter, Expression.FunctionOrValue moduleName name ) ->
expressionVisitor : Node Expression -> ModuleContext -> ( List nothing, ModuleContext )
expressionVisitor node moduleContext =
case Node.value node of
Expression.FunctionOrValue moduleName name ->
( [], registerUsedFunctionOrValue moduleName name moduleContext )
( Rule.OnEnter, Expression.LetExpression { declarations } ) ->
Expression.LetExpression { declarations } ->
( []
, declarations
|> List.filterMap

View File

@ -63,7 +63,7 @@ moduleVisitor schema =
|> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor
|> Rule.withImportVisitor importVisitor
|> Rule.withDeclarationListVisitor declarationListVisitor
|> Rule.withExpressionVisitor expressionVisitor
|> Rule.withExpressionEnterVisitor expressionVisitor
@ -609,10 +609,10 @@ collectTypesFromTypeAnnotation scope node =
-- EXPRESSION VISITOR
expressionVisitor : Node Expression -> Rule.Direction -> ModuleContext -> ( List nothing, ModuleContext )
expressionVisitor node direction moduleContext =
case ( direction, Node.value node ) of
( Rule.OnEnter, Expression.FunctionOrValue moduleName name ) ->
expressionVisitor : Node Expression -> ModuleContext -> ( List nothing, ModuleContext )
expressionVisitor node moduleContext =
case Node.value node of
Expression.FunctionOrValue moduleName name ->
( []
, registerAsUsed
( Scope.moduleNameForValue moduleContext.scope name moduleName, name )

View File

@ -53,38 +53,54 @@ Value `something` is not used:
rule : Rule
rule =
Rule.newModuleRuleSchema "NoUnused.Parameters" initialContext
|> Rule.withDeclarationVisitor declarationVisitor
|> Rule.withExpressionVisitor expressionVisitor
|> Rule.withDeclarationEnterVisitor declarationEnterVisitor
|> Rule.withDeclarationExitVisitor declarationExitVisitor
|> Rule.withExpressionEnterVisitor expressionEnterVisitor
|> Rule.withExpressionExitVisitor expressionExitVisitor
|> NameVisitor.withValueVisitor valueVisitor
|> Rule.fromModuleRuleSchema
declarationVisitor : Node Declaration -> Rule.Direction -> Context -> ( List (Rule.Error {}), Context )
declarationVisitor node direction context =
case ( direction, Node.value node ) of
( Rule.OnEnter, Declaration.FunctionDeclaration { declaration } ) ->
declarationEnterVisitor : Node Declaration -> Context -> ( List (Rule.Error {}), Context )
declarationEnterVisitor node context =
case Node.value node of
Declaration.FunctionDeclaration { declaration } ->
( [], rememberFunctionImplementation declaration context )
( Rule.OnExit, Declaration.FunctionDeclaration { declaration } ) ->
_ ->
( [], context )
declarationExitVisitor : Node Declaration -> Context -> ( List (Rule.Error {}), Context )
declarationExitVisitor node context =
case Node.value node of
Declaration.FunctionDeclaration { declaration } ->
errorsForFunctionImplementation declaration context
_ ->
( [], context )
expressionVisitor : Node Expression -> Rule.Direction -> Context -> ( List (Rule.Error {}), Context )
expressionVisitor (Node _ expression) direction context =
case ( direction, expression ) of
( Rule.OnEnter, Expression.LambdaExpression { args } ) ->
expressionEnterVisitor : Node Expression -> Context -> ( List (Rule.Error {}), Context )
expressionEnterVisitor node context =
case Node.value node of
Expression.LambdaExpression { args } ->
( [], rememberPatternList args context )
( Rule.OnExit, Expression.LambdaExpression { args } ) ->
errorsForPatternList Lambda args context
( Rule.OnEnter, Expression.LetExpression { declarations } ) ->
Expression.LetExpression { declarations } ->
( [], rememberLetDeclarationList declarations context )
( Rule.OnExit, Expression.LetExpression { declarations } ) ->
_ ->
( [], context )
expressionExitVisitor : Node Expression -> Context -> ( List (Rule.Error {}), Context )
expressionExitVisitor node context =
case Node.value node of
Expression.LambdaExpression { args } ->
errorsForPatternList Lambda args context
Expression.LetExpression { declarations } ->
errorsForLetDeclarationList declarations context
_ ->

View File

@ -55,24 +55,32 @@ Value `something` is not used:
rule : Rule
rule =
Rule.newModuleRuleSchema "NoUnused.Patterns" initialContext
|> Rule.withExpressionVisitor expressionVisitor
|> Rule.withExpressionEnterVisitor expressionEnterVisitor
|> Rule.withExpressionExitVisitor expressionExitVisitor
|> NameVisitor.withValueVisitor valueVisitor
|> Rule.fromModuleRuleSchema
expressionVisitor : Node Expression -> Rule.Direction -> Context -> ( List (Rule.Error {}), Context )
expressionVisitor (Node _ expression) direction context =
case ( direction, expression ) of
( Rule.OnEnter, Expression.LetExpression { declarations } ) ->
expressionEnterVisitor : Node Expression -> Context -> ( List (Rule.Error {}), Context )
expressionEnterVisitor node context =
case Node.value node of
Expression.LetExpression { declarations } ->
( [], rememberLetDeclarationList declarations context )
( Rule.OnExit, Expression.LetExpression { declarations } ) ->
errorsForLetDeclarationList declarations context
( Rule.OnEnter, Expression.CaseExpression { cases } ) ->
Expression.CaseExpression { cases } ->
( [], rememberCaseList cases context )
( Rule.OnExit, Expression.CaseExpression { cases } ) ->
_ ->
( [], context )
expressionExitVisitor : Node Expression -> Context -> ( List (Rule.Error {}), Context )
expressionExitVisitor node context =
case Node.value node of
Expression.LetExpression { declarations } ->
errorsForLetDeclarationList declarations context
Expression.CaseExpression { cases } ->
errorsForCaseList cases context
_ ->

View File

@ -2,14 +2,16 @@ module NoUnused.Patterns.NameVisitor exposing (withValueVisitor)
{-| Visit each name in the module.
A "name" is a `Node ( ModuleName, String )` and represents a value or type reference. Here are some value examples:
A "name" is a `Node ( ModuleName, String )` and represents a value or type reference. Here are some examples:
- `Json.Encode.Value` -> `( [ "Json", "Encode" ], "Value" )`
- `Html.Attributes.class` -> `( [ "Html", "Attributes" ], "class" )`
- `Page` -> `( [], "Page" )`
- `view` -> `( [], "view" )`
These can appear in many places throughout declarations and expressions, and picking them out each time is a lot of work. Instead of writing 1000 lines of code and tests each time, you can write one `nameVisitor` and plug it straight into your module schema, or separate `valueVisitor` and `typeVisitor`s.
@docs withValueVisitor
@docs withNameVisitor, withValueVisitor, withTypeVisitor, withValueAndTypeVisitors
## Scope
@ -18,6 +20,11 @@ This makes no attempt to resolve module names from imports, it just returns what
[elm-review-scope]: http://github.com/jfmengels/elm-review-scope/
## Version
Version: 0.2.0
-}
import Elm.Syntax.Declaration as Declaration exposing (Declaration)
@ -25,25 +32,148 @@ import Elm.Syntax.Expression as Expression exposing (Expression)
import Elm.Syntax.ModuleName exposing (ModuleName)
import Elm.Syntax.Node as Node exposing (Node(..))
import Elm.Syntax.Pattern as Pattern exposing (Pattern)
import Elm.Syntax.Signature exposing (Signature)
import Elm.Syntax.Type as Type
import Elm.Syntax.TypeAnnotation as TypeAnnotation exposing (TypeAnnotation)
import Review.Rule as Rule exposing (Error)
type Visitor context
= NameVisitor (VisitorFunction context)
| ValueVisitor (VisitorFunction context)
| TypeVisitor (VisitorFunction context)
| ValueAndTypeVisitor (VisitorFunction context) (VisitorFunction context)
type alias VisitorFunction context =
Node ( ModuleName, String ) -> context -> ( List (Error {}), context )
type Name
= Value (Node ( ModuleName, String ))
| Type (Node ( ModuleName, String ))
{-| This will apply the `nameVisitor` to every value and type in the module, you will get no information about whether the name is a value or type.
rule : Rule
rule =
Rule.newModuleRuleSchema "NoInconsistentAliases" initialContext
|> NameVisitor.withNameVisitor nameVisitor
|> Rule.fromModuleRuleSchema
nameVisitor : Node ( ModuleName, String ) -> context -> ( List (Error {}), context )
nameVisitor node context =
-- Do what you want with the name
( [], context )
-}
withNameVisitor :
(Node ( ModuleName, String ) -> context -> ( List (Error {}), context ))
-> Rule.ModuleRuleSchema state context
-> Rule.ModuleRuleSchema { state | hasAtLeastOneVisitor : () } context
withNameVisitor nameVisitor rule =
let
visitor =
NameVisitor nameVisitor
in
rule
|> Rule.withDeclarationListVisitor (declarationListVisitor visitor)
|> Rule.withExpressionEnterVisitor (expressionVisitor visitor)
{-| This will apply the `valueVisitor` to every value in the module, and ignore any types.
rule : Rule
rule =
Rule.newModuleRuleSchema "NoInconsistentAliases" initialContext
|> NameVisitor.withValueVisitor valueVisitor
|> Rule.fromModuleRuleSchema
valueVisitor : Node ( ModuleName, String ) -> context -> ( List (Error {}), context )
valueVisitor node context =
-- Do what you want with the value
( [], context )
-}
withValueVisitor :
(Node ( ModuleName, String ) -> context -> ( List (Error {}), context ))
-> Rule.ModuleRuleSchema state context
-> Rule.ModuleRuleSchema { state | hasAtLeastOneVisitor : () } context
withValueVisitor valueVisitor rule =
let
visitor =
ValueVisitor valueVisitor
in
rule
|> Rule.withDeclarationListVisitor (declarationListVisitor valueVisitor)
|> Rule.withExpressionVisitor (expressionVisitor valueVisitor)
|> Rule.withDeclarationListVisitor (declarationListVisitor visitor)
|> Rule.withExpressionEnterVisitor (expressionVisitor visitor)
{-| This will apply the `typeVisitor` to every type in the module, and ignore any values.
rule : Rule
rule =
Rule.newModuleRuleSchema "NoInconsistentAliases" initialContext
|> NameVisitor.withTypeVisitor typeVisitor
|> Rule.fromModuleRuleSchema
typeVisitor : Node ( ModuleName, String ) -> context -> ( List (Error {}), context )
typeVisitor node context =
-- Do what you want with the type
( [], context )
-}
withTypeVisitor :
(Node ( ModuleName, String ) -> context -> ( List (Error {}), context ))
-> Rule.ModuleRuleSchema state context
-> Rule.ModuleRuleSchema { state | hasAtLeastOneVisitor : () } context
withTypeVisitor typeVisitor rule =
let
visitor =
TypeVisitor typeVisitor
in
rule
|> Rule.withDeclarationListVisitor (declarationListVisitor visitor)
|> Rule.withExpressionEnterVisitor (expressionVisitor visitor)
{-| This will apply the `valueVisitor` to every value and the `typeVisitor` to every type in the module.
rule : Rule
rule =
Rule.newModuleRuleSchema "NoInconsistentAliases" initialContext
|> NameVisitor.withValueAndTypeVisitors
{ valueVisitor = valueVisitor
, typeVisitor = typeVisitor
}
|> Rule.fromModuleRuleSchema
valueVisitor : Node ( ModuleName, String ) -> context -> ( List (Error {}), context )
valueVisitor node context =
-- Do what you want with the value
( [], context )
typeVisitor : Node ( ModuleName, String ) -> context -> ( List (Error {}), context )
typeVisitor node context =
-- Do what you want with the type
( [], context )
-}
withValueAndTypeVisitors :
{ valueVisitor : Node ( ModuleName, String ) -> context -> ( List (Error {}), context )
, typeVisitor : Node ( ModuleName, String ) -> context -> ( List (Error {}), context )
}
-> Rule.ModuleRuleSchema state context
-> Rule.ModuleRuleSchema { state | hasAtLeastOneVisitor : () } context
withValueAndTypeVisitors { valueVisitor, typeVisitor } rule =
let
visitor =
ValueAndTypeVisitor valueVisitor typeVisitor
in
rule
|> Rule.withDeclarationListVisitor (declarationListVisitor visitor)
|> Rule.withExpressionEnterVisitor (expressionVisitor visitor)
@ -51,24 +181,17 @@ withValueVisitor valueVisitor rule =
declarationListVisitor :
VisitorFunction context
Visitor context
-> (List (Node Declaration) -> context -> ( List (Error {}), context ))
declarationListVisitor visitor list context =
visitDeclarationList list
|> folder visitor context
expressionVisitor :
VisitorFunction context
-> (Node Expression -> Rule.Direction -> context -> ( List (Error {}), context ))
expressionVisitor visitor node direction context =
case direction of
Rule.OnEnter ->
visitExpression node
|> folder visitor context
Rule.OnExit ->
( [], context )
expressionVisitor : Visitor context -> (Node Expression -> context -> ( List (Error {}), context ))
expressionVisitor visitor node context =
visitExpression node
|> folder visitor context
@ -76,7 +199,7 @@ expressionVisitor visitor node direction context =
folder :
VisitorFunction context
Visitor context
-> context
-> List Name
-> ( List (Error {}), context )
@ -85,7 +208,7 @@ folder visitor context list =
folderHelper :
VisitorFunction context
Visitor context
-> Name
-> ( List (Error {}), context )
-> ( List (Error {}), context )
@ -97,9 +220,51 @@ folderHelper visitor name ( errors, context ) =
( newErrors ++ errors, newContext )
applyVisitor : VisitorFunction context -> Name -> context -> ( List (Error {}), context )
applyVisitor visitor (Value node) context =
visitor node context
applyVisitor : Visitor context -> Name -> context -> ( List (Error {}), context )
applyVisitor visitor name context =
case name of
Value node ->
applyValueVisitor visitor node context
Type node ->
applyTypeVisitor visitor node context
applyValueVisitor : Visitor context -> VisitorFunction context
applyValueVisitor visitor =
case visitor of
NameVisitor function ->
function
ValueVisitor function ->
function
TypeVisitor _ ->
noopVisitor
ValueAndTypeVisitor function _ ->
function
applyTypeVisitor : Visitor context -> VisitorFunction context
applyTypeVisitor visitor =
case visitor of
NameVisitor function ->
function
ValueVisitor _ ->
noopVisitor
TypeVisitor function ->
function
ValueAndTypeVisitor _ function ->
function
noopVisitor : VisitorFunction context
noopVisitor _ context =
( [], context )
@ -108,24 +273,101 @@ applyVisitor visitor (Value node) context =
visitDeclarationList : List (Node Declaration) -> List Name
visitDeclarationList nodes =
List.concatMap visitDeclaration nodes
fastConcatMap visitDeclaration nodes
visitDeclaration : Node Declaration -> List Name
visitDeclaration node =
case Node.value node of
Declaration.FunctionDeclaration { declaration } ->
visitFunctionImplementation declaration
Declaration.FunctionDeclaration { signature, declaration } ->
visitMaybeSignature signature
++ visitFunctionImplementation declaration
Declaration.AliasDeclaration { typeAnnotation } ->
visitTypeAnnotation typeAnnotation
Declaration.CustomTypeDeclaration { constructors } ->
visitValueConstructorList constructors
Declaration.PortDeclaration { typeAnnotation } ->
visitTypeAnnotation typeAnnotation
_ ->
[]
visitMaybeSignature : Maybe (Node Signature) -> List Name
visitMaybeSignature maybeNode =
case maybeNode of
Just node ->
visitSignature node
Nothing ->
[]
visitSignature : Node Signature -> List Name
visitSignature node =
visitTypeAnnotation (node |> Node.value |> .typeAnnotation)
visitFunctionImplementation : Node Expression.FunctionImplementation -> List Name
visitFunctionImplementation node =
visitPatternList (node |> Node.value |> .arguments)
visitValueConstructorList : List (Node Type.ValueConstructor) -> List Name
visitValueConstructorList list =
fastConcatMap visitValueConstructor list
visitValueConstructor : Node Type.ValueConstructor -> List Name
visitValueConstructor node =
visitTypeAnnotationList (node |> Node.value |> .arguments)
visitTypeAnnotationList : List (Node TypeAnnotation) -> List Name
visitTypeAnnotationList list =
fastConcatMap visitTypeAnnotation list
visitTypeAnnotation : Node TypeAnnotation -> List Name
visitTypeAnnotation node =
case Node.value node of
TypeAnnotation.GenericType _ ->
[]
TypeAnnotation.Typed call types ->
visitType call
++ visitTypeAnnotationList types
TypeAnnotation.Unit ->
[]
TypeAnnotation.Tupled list ->
visitTypeAnnotationList list
TypeAnnotation.Record list ->
visitRecordFieldList list
TypeAnnotation.GenericRecord _ list ->
visitRecordFieldList (Node.value list)
TypeAnnotation.FunctionTypeAnnotation argument return ->
visitTypeAnnotation argument
++ visitTypeAnnotation return
visitRecordFieldList : List (Node TypeAnnotation.RecordField) -> List Name
visitRecordFieldList list =
fastConcatMap visitRecordField list
visitRecordField : Node TypeAnnotation.RecordField -> List Name
visitRecordField node =
visitTypeAnnotation (node |> Node.value |> Tuple.second)
visitExpression : Node Expression -> List Name
visitExpression (Node range expression) =
case expression of
@ -150,14 +392,15 @@ visitExpression (Node range expression) =
visitLetDeclarationList : List (Node Expression.LetDeclaration) -> List Name
visitLetDeclarationList list =
List.concatMap visitLetDeclaration list
fastConcatMap visitLetDeclaration list
visitLetDeclaration : Node Expression.LetDeclaration -> List Name
visitLetDeclaration node =
case Node.value node of
Expression.LetFunction { declaration } ->
visitFunctionImplementation declaration
Expression.LetFunction { signature, declaration } ->
visitMaybeSignature signature
++ visitFunctionImplementation declaration
Expression.LetDestructuring pattern _ ->
visitPattern pattern
@ -165,7 +408,7 @@ visitLetDeclaration node =
visitCaseList : List Expression.Case -> List Name
visitCaseList list =
List.concatMap visitCase list
fastConcatMap visitCase list
visitCase : Expression.Case -> List Name
@ -175,7 +418,7 @@ visitCase ( pattern, _ ) =
visitPatternList : List (Node Pattern) -> List Name
visitPatternList list =
List.concatMap visitPattern list
fastConcatMap visitPattern list
visitPattern : Node Pattern -> List Name
@ -216,3 +459,17 @@ visitPattern node =
visitValue : Node ( ModuleName, String ) -> List Name
visitValue node =
[ Value node ]
visitType : Node ( ModuleName, String ) -> List Name
visitType node =
[ Type node ]
--- High Performance List
fastConcatMap : (a -> List b) -> List a -> List b
fastConcatMap fn =
List.foldr (fn >> (++)) []

View File

@ -57,8 +57,8 @@ rule =
|> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor
|> Rule.withImportVisitor importVisitor
|> Rule.withDeclarationEnterVisitor declarationVisitor
|> Rule.withExpressionEnterVisitor expressionVisitorOnEnter
|> Rule.withExpressionExitVisitor expressionVisitorOnExit
|> Rule.withExpressionEnterVisitor expressionEnterVisitor
|> Rule.withExpressionExitVisitor expressionExitVisitor
|> Rule.withFinalModuleEvaluation finalEvaluation
|> Rule.fromModuleRuleSchema
@ -338,8 +338,8 @@ moduleAliasRange (Node _ { moduleName }) range =
{ range | start = (Node.range moduleName).end }
expressionVisitorOnEnter : Node Expression -> Context -> ( List (Error {}), Context )
expressionVisitorOnEnter (Node range value) context =
expressionEnterVisitor : Node Expression -> Context -> ( List (Error {}), Context )
expressionEnterVisitor (Node range value) context =
case value of
Expression.FunctionOrValue [] name ->
( [], markAsUsed name context )
@ -404,9 +404,9 @@ expressionVisitorOnEnter (Node range value) context =
( [], context )
expressionVisitorOnExit : Node Expression -> Context -> ( List (Error {}), Context )
expressionVisitorOnExit (Node _ value) context =
case value of
expressionExitVisitor : Node Expression -> Context -> ( List (Error {}), Context )
expressionExitVisitor node context =
case Node.value node of
Expression.RecordUpdateExpression expr _ ->
( [], markAsUsed (Node.value expr) context )

View File

@ -27,7 +27,7 @@ module Scope exposing
{- Copied over from https://github.com/jfmengels/elm-review-scope
Version: 0.2.2
Version: 0.3.0
Copyright (c) 2020, Jeroen Engels
All rights reserved.
@ -397,26 +397,49 @@ internalAddModuleVisitors schema =
(mapInnerModuleContext importVisitor |> pairWithNoErrors)
|> Rule.withDeclarationListVisitor
(mapInnerModuleContext declarationListVisitor |> pairWithNoErrors)
|> Rule.withDeclarationVisitor
(\visitedElement direction outerContext ->
|> Rule.withDeclarationEnterVisitor
(\visitedElement outerContext ->
let
innerContext : InnerModuleContext
innerContext =
outerContext.scope
|> unboxModule
|> declarationVisitor visitedElement direction
|> declarationEnterVisitor visitedElement
in
( [], { outerContext | scope = ModuleContext innerContext } )
)
|> Rule.withExpressionVisitor
(\visitedElement direction outerContext ->
|> Rule.withDeclarationExitVisitor
(\visitedElement outerContext ->
let
innerContext : InnerModuleContext
innerContext =
outerContext.scope
|> unboxModule
|> popScope visitedElement direction
|> expressionVisitor visitedElement direction
|> declarationExitVisitor visitedElement
in
( [], { outerContext | scope = ModuleContext innerContext } )
)
|> Rule.withExpressionEnterVisitor
(\visitedElement outerContext ->
let
innerContext : InnerModuleContext
innerContext =
outerContext.scope
|> unboxModule
|> popScope visitedElement Rule.OnEnter
|> expressionEnterVisitor visitedElement
in
( [], { outerContext | scope = ModuleContext innerContext } )
)
|> Rule.withExpressionExitVisitor
(\visitedElement outerContext ->
let
innerContext : InnerModuleContext
innerContext =
outerContext.scope
|> unboxModule
|> popScope visitedElement Rule.OnExit
|> expressionExitVisitor visitedElement
in
( [], { outerContext | scope = ModuleContext innerContext } )
)
@ -1021,10 +1044,10 @@ type VariableType
| Port
declarationVisitor : Node Declaration -> Rule.Direction -> InnerModuleContext -> InnerModuleContext
declarationVisitor declaration direction context =
case ( direction, Node.value declaration ) of
( Rule.OnEnter, Declaration.FunctionDeclaration function ) ->
declarationEnterVisitor : Node Declaration -> InnerModuleContext -> InnerModuleContext
declarationEnterVisitor node context =
case Node.value node of
Declaration.FunctionDeclaration function ->
let
newScope : Scope
newScope =
@ -1034,7 +1057,14 @@ declarationVisitor declaration direction context =
|> nonemptyList_cons newScope
|> updateScope context
( Rule.OnExit, Declaration.FunctionDeclaration function ) ->
_ ->
context
declarationExitVisitor : Node Declaration -> InnerModuleContext -> InnerModuleContext
declarationExitVisitor node context =
case Node.value node of
Declaration.FunctionDeclaration _ ->
{ context | scopes = nonemptyList_pop context.scopes }
_ ->
@ -1133,10 +1163,10 @@ popScope node direction context =
context
expressionVisitor : Node Expression -> Direction -> InnerModuleContext -> InnerModuleContext
expressionVisitor (Node _ value) direction context =
case ( direction, value ) of
( Rule.OnEnter, Expression.LetExpression { declarations, expression } ) ->
expressionEnterVisitor : Node Expression -> InnerModuleContext -> InnerModuleContext
expressionEnterVisitor node context =
case Node.value node of
Expression.LetExpression { declarations, expression } ->
List.foldl
(\declaration scopes ->
case Node.value declaration of
@ -1161,10 +1191,7 @@ expressionVisitor (Node _ value) direction context =
declarations
|> updateScope context
( Rule.OnExit, Expression.LetExpression _ ) ->
{ context | scopes = nonemptyList_pop context.scopes }
( Rule.OnEnter, Expression.CaseExpression caseBlock ) ->
Expression.CaseExpression caseBlock ->
let
cases : List ( Node Expression, Dict String VariableInfo )
cases =
@ -1187,7 +1214,17 @@ expressionVisitor (Node _ value) direction context =
in
{ context | scopes = nonemptyList_mapHead (\scope -> { scope | cases = cases }) context.scopes }
( Rule.OnExit, Expression.CaseExpression caseBlock ) ->
_ ->
context
expressionExitVisitor : Node Expression -> InnerModuleContext -> InnerModuleContext
expressionExitVisitor node context =
case Node.value node of
Expression.LetExpression _ ->
{ context | scopes = nonemptyList_pop context.scopes }
Expression.CaseExpression _ ->
{ context | scopes = nonemptyList_mapHead (\scope -> { scope | cases = [] }) context.scopes }
_ ->
@ -1220,10 +1257,10 @@ A value can be either a function, a constant, a custom type constructor or a typ
If the element was defined in the current module, then the result will be `[]`.
expressionVisitor : Node Expression -> Direction -> Context -> ( List (Error {}), Context )
expressionVisitor node direction context =
case ( direction, Node.value node ) of
( Rule.OnEnter, Expression.FunctionOrValue moduleName "button" ) ->
expressionVisitor : Node Expression -> Context -> ( List (Error {}), Context )
expressionVisitor node context =
case Node.value node of
Expression.FunctionOrValue moduleName "button" ->
if Scope.moduleNameForValue context.scope "button" moduleName == [ "Html" ] then
( [ createError node ], context )