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 --, NoTodoComment.rule
-- |> Rule.ignoreErrorsForFiles [ "NoTodoComment" ] -- |> 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 : Rule.ModuleRuleSchema schemaState ModuleContext -> Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } ModuleContext
moduleVisitor schema = moduleVisitor schema =
schema schema
|> Rule.withExpressionEnterVisitor expressionVisitor |> Rule.withExpressionVisitor expressionVisitor
|> Rule.withFinalModuleEvaluation finalEvaluation |> Rule.withFinalModuleEvaluation finalEvaluation
expressionVisitor : Node Expression -> ModuleContext -> ( List nothing, ModuleContext ) expressionVisitor : Node Expression -> Rule.Direction -> ModuleContext -> ( List nothing, ModuleContext )
expressionVisitor node context = expressionVisitor node direction context =
case Node.value node of case ( direction, Node.value node ) of
Expression.FunctionOrValue moduleName name -> ( Rule.OnEnter, Expression.FunctionOrValue moduleName name ) ->
let let
nameInCode : String nameInCode : String
nameInCode = nameInCode =

View File

@ -70,8 +70,8 @@ rule =
moduleVisitor : Rule.ModuleRuleSchema schemaState ModuleContext -> Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } ModuleContext moduleVisitor : Rule.ModuleRuleSchema schemaState ModuleContext -> Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } ModuleContext
moduleVisitor schema = moduleVisitor schema =
schema schema
|> Rule.withDeclarationVisitor declarationVisitor |> Rule.withDeclarationEnterVisitor declarationVisitor
|> Rule.withExpressionVisitor expressionVisitor |> Rule.withExpressionEnterVisitor expressionVisitor
|> Rule.withFinalModuleEvaluation finalEvaluation |> Rule.withFinalModuleEvaluation finalEvaluation
@ -134,41 +134,10 @@ foldProjectContexts newContext previousContext =
} }
expressionVisitor : Node Expression -> Rule.Direction -> ModuleContext -> ( List (Error {}), ModuleContext ) declarationVisitor : Node Declaration -> ModuleContext -> ( List (Error nothing), ModuleContext )
expressionVisitor node direction moduleContext = declarationVisitor node moduleContext =
case ( direction, Node.value node ) of case Node.value node of
( Rule.OnEnter, Expression.FunctionOrValue moduleName "update" ) -> Declaration.FunctionDeclaration function ->
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 ) ->
case case
function.declaration function.declaration
|> Node.value |> Node.value
@ -188,6 +157,37 @@ declarationVisitor declaration direction moduleContext =
( [], 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 -> List (Error {})
finalEvaluation moduleContext = finalEvaluation moduleContext =
moduleContext.usesUpdateOfModule moduleContext.usesUpdateOfModule

View File

@ -55,8 +55,8 @@ To add the rule to your configuration:
rule : Rule rule : Rule
rule = rule =
Rule.newModuleRuleSchema "NoRecursiveUpdate" { isInUpdateFunction = False } Rule.newModuleRuleSchema "NoRecursiveUpdate" { isInUpdateFunction = False }
|> Rule.withDeclarationVisitor declarationVisitor |> Rule.withDeclarationEnterVisitor declarationVisitor
|> Rule.withExpressionVisitor expressionVisitor |> Rule.withExpressionEnterVisitor expressionVisitor
|> Rule.fromModuleRuleSchema |> Rule.fromModuleRuleSchema
@ -65,10 +65,10 @@ type alias Context =
} }
declarationVisitor : Node Declaration -> Rule.Direction -> Context -> ( List nothing, Context ) declarationVisitor : Node Declaration -> Context -> ( List nothing, Context )
declarationVisitor declaration direction _ = declarationVisitor node _ =
case ( direction, Node.value declaration ) of case Node.value node of
( Rule.OnEnter, Declaration.FunctionDeclaration function ) -> Declaration.FunctionDeclaration function ->
( [] ( []
, { isInUpdateFunction = , { isInUpdateFunction =
(function.declaration (function.declaration
@ -84,11 +84,11 @@ declarationVisitor declaration direction _ =
( [], { isInUpdateFunction = False } ) ( [], { isInUpdateFunction = False } )
expressionVisitor : Node Expression -> Rule.Direction -> Context -> ( List (Error {}), Context ) expressionVisitor : Node Expression -> Context -> ( List (Error {}), Context )
expressionVisitor node direction context = expressionVisitor node context =
if context.isInUpdateFunction then if context.isInUpdateFunction then
case ( direction, Node.value node ) of case Node.value node of
( Rule.OnEnter, Expression.FunctionOrValue [] "update" ) -> Expression.FunctionOrValue [] "update" ->
( [ Rule.error ( [ Rule.error
{ message = "`update` shouldn't call itself" { 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." ] , 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.Node as Node exposing (Node)
import Elm.Syntax.Signature exposing (Signature) import Elm.Syntax.Signature exposing (Signature)
import Elm.Syntax.TypeAnnotation as TypeAnnotation exposing (TypeAnnotation) 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 Scope
import Set exposing (Set) import Set exposing (Set)
@ -129,8 +129,8 @@ moduleVisitor schema =
schema schema
|> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor |> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor
|> Rule.withDeclarationListVisitor declarationListVisitor |> Rule.withDeclarationListVisitor declarationListVisitor
|> Rule.withDeclarationVisitor declarationVisitor |> Rule.withDeclarationEnterVisitor declarationVisitor
|> Rule.withExpressionVisitor expressionVisitor |> Rule.withExpressionEnterVisitor expressionVisitor
@ -385,10 +385,10 @@ register node context =
-- DECLARATION VISITOR -- DECLARATION VISITOR
declarationVisitor : Node Declaration -> Direction -> ModuleContext -> ( List nothing, ModuleContext ) declarationVisitor : Node Declaration -> ModuleContext -> ( List nothing, ModuleContext )
declarationVisitor node direction context = declarationVisitor node context =
case ( direction, Node.value node ) of case Node.value node of
( Rule.OnEnter, Declaration.CustomTypeDeclaration { name, constructors } ) -> Declaration.CustomTypeDeclaration { name, constructors } ->
let let
constructorsForCustomType : Dict String (Node String) constructorsForCustomType : Dict String (Node String)
constructorsForCustomType = constructorsForCustomType =
@ -417,7 +417,7 @@ declarationVisitor node direction context =
} }
) )
( Rule.OnEnter, Declaration.FunctionDeclaration function ) -> Declaration.FunctionDeclaration function ->
( [], markPhantomTypesFromTypeSignatureAsUsed function.signature context ) ( [], markPhantomTypesFromTypeSignatureAsUsed function.signature context )
_ -> _ ->
@ -428,13 +428,13 @@ declarationVisitor node direction context =
-- EXPRESSION VISITOR -- EXPRESSION VISITOR
expressionVisitor : Node Expression -> Direction -> ModuleContext -> ( List nothing, ModuleContext ) expressionVisitor : Node Expression -> ModuleContext -> ( List nothing, ModuleContext )
expressionVisitor node direction moduleContext = expressionVisitor node moduleContext =
case ( direction, Node.value node ) of case Node.value node of
( Rule.OnEnter, Expression.FunctionOrValue moduleName name ) -> Expression.FunctionOrValue moduleName name ->
( [], registerUsedFunctionOrValue moduleName name moduleContext ) ( [], registerUsedFunctionOrValue moduleName name moduleContext )
( Rule.OnEnter, Expression.LetExpression { declarations } ) -> Expression.LetExpression { declarations } ->
( [] ( []
, declarations , declarations
|> List.filterMap |> List.filterMap

View File

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

View File

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

View File

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

View File

@ -2,14 +2,16 @@ module NoUnused.Patterns.NameVisitor exposing (withValueVisitor)
{-| Visit each name in the module. {-| 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" )` - `Html.Attributes.class` -> `( [ "Html", "Attributes" ], "class" )`
- `Page` -> `( [], "Page" )`
- `view` -> `( [], "view" )` - `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. 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 ## 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/ [elm-review-scope]: http://github.com/jfmengels/elm-review-scope/
## Version
Version: 0.2.0
-} -}
import Elm.Syntax.Declaration as Declaration exposing (Declaration) 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.ModuleName exposing (ModuleName)
import Elm.Syntax.Node as Node exposing (Node(..)) import Elm.Syntax.Node as Node exposing (Node(..))
import Elm.Syntax.Pattern as Pattern exposing (Pattern) 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) 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 = type alias VisitorFunction context =
Node ( ModuleName, String ) -> context -> ( List (Error {}), context ) Node ( ModuleName, String ) -> context -> ( List (Error {}), context )
type Name type Name
= Value (Node ( ModuleName, String )) = 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 : withValueVisitor :
(Node ( ModuleName, String ) -> context -> ( List (Error {}), context )) (Node ( ModuleName, String ) -> context -> ( List (Error {}), context ))
-> Rule.ModuleRuleSchema state context -> Rule.ModuleRuleSchema state context
-> Rule.ModuleRuleSchema { state | hasAtLeastOneVisitor : () } context -> Rule.ModuleRuleSchema { state | hasAtLeastOneVisitor : () } context
withValueVisitor valueVisitor rule = withValueVisitor valueVisitor rule =
let
visitor =
ValueVisitor valueVisitor
in
rule rule
|> Rule.withDeclarationListVisitor (declarationListVisitor valueVisitor) |> Rule.withDeclarationListVisitor (declarationListVisitor visitor)
|> Rule.withExpressionVisitor (expressionVisitor valueVisitor) |> 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 : declarationListVisitor :
VisitorFunction context Visitor context
-> (List (Node Declaration) -> context -> ( List (Error {}), context )) -> (List (Node Declaration) -> context -> ( List (Error {}), context ))
declarationListVisitor visitor list context = declarationListVisitor visitor list context =
visitDeclarationList list visitDeclarationList list
|> folder visitor context |> folder visitor context
expressionVisitor : expressionVisitor : Visitor context -> (Node Expression -> context -> ( List (Error {}), context ))
VisitorFunction context expressionVisitor visitor node context =
-> (Node Expression -> Rule.Direction -> context -> ( List (Error {}), context )) visitExpression node
expressionVisitor visitor node direction context = |> folder visitor context
case direction of
Rule.OnEnter ->
visitExpression node
|> folder visitor context
Rule.OnExit ->
( [], context )
@ -76,7 +199,7 @@ expressionVisitor visitor node direction context =
folder : folder :
VisitorFunction context Visitor context
-> context -> context
-> List Name -> List Name
-> ( List (Error {}), context ) -> ( List (Error {}), context )
@ -85,7 +208,7 @@ folder visitor context list =
folderHelper : folderHelper :
VisitorFunction context Visitor context
-> Name -> Name
-> ( List (Error {}), context ) -> ( List (Error {}), context )
-> ( List (Error {}), context ) -> ( List (Error {}), context )
@ -97,9 +220,51 @@ folderHelper visitor name ( errors, context ) =
( newErrors ++ errors, newContext ) ( newErrors ++ errors, newContext )
applyVisitor : VisitorFunction context -> Name -> context -> ( List (Error {}), context ) applyVisitor : Visitor context -> Name -> context -> ( List (Error {}), context )
applyVisitor visitor (Value node) context = applyVisitor visitor name context =
visitor node 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 : List (Node Declaration) -> List Name
visitDeclarationList nodes = visitDeclarationList nodes =
List.concatMap visitDeclaration nodes fastConcatMap visitDeclaration nodes
visitDeclaration : Node Declaration -> List Name visitDeclaration : Node Declaration -> List Name
visitDeclaration node = visitDeclaration node =
case Node.value node of case Node.value node of
Declaration.FunctionDeclaration { declaration } -> Declaration.FunctionDeclaration { signature, declaration } ->
visitFunctionImplementation 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 Expression.FunctionImplementation -> List Name
visitFunctionImplementation node = visitFunctionImplementation node =
visitPatternList (node |> Node.value |> .arguments) 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 Expression -> List Name
visitExpression (Node range expression) = visitExpression (Node range expression) =
case expression of case expression of
@ -150,14 +392,15 @@ visitExpression (Node range expression) =
visitLetDeclarationList : List (Node Expression.LetDeclaration) -> List Name visitLetDeclarationList : List (Node Expression.LetDeclaration) -> List Name
visitLetDeclarationList list = visitLetDeclarationList list =
List.concatMap visitLetDeclaration list fastConcatMap visitLetDeclaration list
visitLetDeclaration : Node Expression.LetDeclaration -> List Name visitLetDeclaration : Node Expression.LetDeclaration -> List Name
visitLetDeclaration node = visitLetDeclaration node =
case Node.value node of case Node.value node of
Expression.LetFunction { declaration } -> Expression.LetFunction { signature, declaration } ->
visitFunctionImplementation declaration visitMaybeSignature signature
++ visitFunctionImplementation declaration
Expression.LetDestructuring pattern _ -> Expression.LetDestructuring pattern _ ->
visitPattern pattern visitPattern pattern
@ -165,7 +408,7 @@ visitLetDeclaration node =
visitCaseList : List Expression.Case -> List Name visitCaseList : List Expression.Case -> List Name
visitCaseList list = visitCaseList list =
List.concatMap visitCase list fastConcatMap visitCase list
visitCase : Expression.Case -> List Name visitCase : Expression.Case -> List Name
@ -175,7 +418,7 @@ visitCase ( pattern, _ ) =
visitPatternList : List (Node Pattern) -> List Name visitPatternList : List (Node Pattern) -> List Name
visitPatternList list = visitPatternList list =
List.concatMap visitPattern list fastConcatMap visitPattern list
visitPattern : Node Pattern -> List Name visitPattern : Node Pattern -> List Name
@ -216,3 +459,17 @@ visitPattern node =
visitValue : Node ( ModuleName, String ) -> List Name visitValue : Node ( ModuleName, String ) -> List Name
visitValue node = visitValue node =
[ Value 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.withModuleDefinitionVisitor moduleDefinitionVisitor
|> Rule.withImportVisitor importVisitor |> Rule.withImportVisitor importVisitor
|> Rule.withDeclarationEnterVisitor declarationVisitor |> Rule.withDeclarationEnterVisitor declarationVisitor
|> Rule.withExpressionEnterVisitor expressionVisitorOnEnter |> Rule.withExpressionEnterVisitor expressionEnterVisitor
|> Rule.withExpressionExitVisitor expressionVisitorOnExit |> Rule.withExpressionExitVisitor expressionExitVisitor
|> Rule.withFinalModuleEvaluation finalEvaluation |> Rule.withFinalModuleEvaluation finalEvaluation
|> Rule.fromModuleRuleSchema |> Rule.fromModuleRuleSchema
@ -338,8 +338,8 @@ moduleAliasRange (Node _ { moduleName }) range =
{ range | start = (Node.range moduleName).end } { range | start = (Node.range moduleName).end }
expressionVisitorOnEnter : Node Expression -> Context -> ( List (Error {}), Context ) expressionEnterVisitor : Node Expression -> Context -> ( List (Error {}), Context )
expressionVisitorOnEnter (Node range value) context = expressionEnterVisitor (Node range value) context =
case value of case value of
Expression.FunctionOrValue [] name -> Expression.FunctionOrValue [] name ->
( [], markAsUsed name context ) ( [], markAsUsed name context )
@ -404,9 +404,9 @@ expressionVisitorOnEnter (Node range value) context =
( [], context ) ( [], context )
expressionVisitorOnExit : Node Expression -> Context -> ( List (Error {}), Context ) expressionExitVisitor : Node Expression -> Context -> ( List (Error {}), Context )
expressionVisitorOnExit (Node _ value) context = expressionExitVisitor node context =
case value of case Node.value node of
Expression.RecordUpdateExpression expr _ -> Expression.RecordUpdateExpression expr _ ->
( [], markAsUsed (Node.value expr) context ) ( [], markAsUsed (Node.value expr) context )

View File

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