mirror of
https://github.com/jfmengels/elm-review.git
synced 2024-09-11 08:05:46 +03:00
Backport rules from cognitive-complexity
This commit is contained in:
parent
cf2a955d40
commit
60a15216a9
@ -337,32 +337,7 @@ expressionEnterVisitorHelp : Node Expression -> ModuleContext -> ModuleContext
|
|||||||
expressionEnterVisitorHelp node context =
|
expressionEnterVisitorHelp node context =
|
||||||
case Node.value node of
|
case Node.value node of
|
||||||
Expression.IfBlock _ _ else_ ->
|
Expression.IfBlock _ _ else_ ->
|
||||||
if not (List.member (Node.range node) context.elseIfToIgnore) then
|
visitElseExpression (Node.range node) else_ context
|
||||||
{ context
|
|
||||||
| increases =
|
|
||||||
{ line = (Node.range node).start
|
|
||||||
, increase = context.nesting + 1
|
|
||||||
, nesting = context.nesting
|
|
||||||
, kind = If
|
|
||||||
}
|
|
||||||
:: context.increases
|
|
||||||
, nesting = context.nesting + 1
|
|
||||||
, elseIfToIgnore = Node.range else_ :: context.elseIfToIgnore
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
-- This if expression is an else if
|
|
||||||
-- We want to increase the complexity but keep the same nesting as the parent if
|
|
||||||
{ context
|
|
||||||
| increases =
|
|
||||||
{ line = (Node.range node).start
|
|
||||||
, increase = context.nesting
|
|
||||||
, nesting = context.nesting - 1
|
|
||||||
, kind = ElseIf
|
|
||||||
}
|
|
||||||
:: context.increases
|
|
||||||
, elseIfToIgnore = Node.range else_ :: context.elseIfToIgnore
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression.CaseExpression _ ->
|
Expression.CaseExpression _ ->
|
||||||
{ context
|
{ context
|
||||||
@ -408,21 +383,62 @@ expressionEnterVisitorHelp node context =
|
|||||||
{ context | nesting = context.nesting + 1 }
|
{ context | nesting = context.nesting + 1 }
|
||||||
|
|
||||||
Expression.FunctionOrValue [] name ->
|
Expression.FunctionOrValue [] name ->
|
||||||
{ context
|
if isFunctionReference name then
|
||||||
| references =
|
{ context
|
||||||
if Dict.member name context.references then
|
| references =
|
||||||
-- The reference already exists, and we want to keep the first reference
|
if Dict.member name context.references then
|
||||||
-- for a better presentation
|
-- The reference already exists, and we want to keep the first reference
|
||||||
context.references
|
-- for a better presentation
|
||||||
|
context.references
|
||||||
|
|
||||||
else
|
else
|
||||||
Dict.insert name (Node.range node).start context.references
|
Dict.insert name (Node.range node).start context.references
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
context
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
context
|
context
|
||||||
|
|
||||||
|
|
||||||
|
visitElseExpression : Range -> Node a -> ModuleContext -> ModuleContext
|
||||||
|
visitElseExpression ifExprRange else_ context =
|
||||||
|
if not (List.member ifExprRange context.elseIfToIgnore) then
|
||||||
|
{ context
|
||||||
|
| increases =
|
||||||
|
{ line = ifExprRange.start
|
||||||
|
, increase = context.nesting + 1
|
||||||
|
, nesting = context.nesting
|
||||||
|
, kind = If
|
||||||
|
}
|
||||||
|
:: context.increases
|
||||||
|
, nesting = context.nesting + 1
|
||||||
|
, elseIfToIgnore = Node.range else_ :: context.elseIfToIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
-- This if expression is an else if
|
||||||
|
-- We want to increase the complexity but keep the same nesting as the parent if
|
||||||
|
{ context
|
||||||
|
| increases =
|
||||||
|
{ line = ifExprRange.start
|
||||||
|
, increase = context.nesting
|
||||||
|
, nesting = context.nesting - 1
|
||||||
|
, kind = ElseIf
|
||||||
|
}
|
||||||
|
:: context.increases
|
||||||
|
, elseIfToIgnore = Node.range else_ :: context.elseIfToIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
isFunctionReference : String -> Bool
|
||||||
|
isFunctionReference name =
|
||||||
|
name
|
||||||
|
|> String.left 1
|
||||||
|
|> String.all Char.isLower
|
||||||
|
|
||||||
|
|
||||||
computeRangesForLetDeclarations : List (Node Expression.LetDeclaration) -> List Range
|
computeRangesForLetDeclarations : List (Node Expression.LetDeclaration) -> List Range
|
||||||
computeRangesForLetDeclarations declarations =
|
computeRangesForLetDeclarations declarations =
|
||||||
List.filterMap
|
List.filterMap
|
||||||
@ -704,19 +720,18 @@ findRecursiveCalls : Dict String (Dict String a) -> RecursiveCalls
|
|||||||
findRecursiveCalls graph =
|
findRecursiveCalls graph =
|
||||||
graph
|
graph
|
||||||
|> Dict.foldl
|
|> Dict.foldl
|
||||||
(\vertice _ ( recursiveCalls, visited ) ->
|
(\vertice _ recursiveCalls ->
|
||||||
let
|
let
|
||||||
res : { recursiveCalls : RecursiveCalls, visited : Visited, stack : List String }
|
res : { recursiveCalls : RecursiveCalls, visited : Visited, stack : List String }
|
||||||
res =
|
res =
|
||||||
processDFSTree
|
processDFSTree
|
||||||
graph
|
graph
|
||||||
[ vertice ]
|
[ vertice ]
|
||||||
(Dict.insert vertice InStack visited)
|
(Dict.singleton vertice InStack)
|
||||||
in
|
in
|
||||||
( mergeRecursiveCallsDict res.recursiveCalls recursiveCalls, res.visited )
|
mergeRecursiveCallsDict res.recursiveCalls recursiveCalls
|
||||||
)
|
)
|
||||||
( Dict.empty, Dict.empty )
|
Dict.empty
|
||||||
|> Tuple.first
|
|
||||||
|
|
||||||
|
|
||||||
mergeRecursiveCallsDict : RecursiveCalls -> RecursiveCalls -> RecursiveCalls
|
mergeRecursiveCallsDict : RecursiveCalls -> RecursiveCalls -> RecursiveCalls
|
||||||
@ -732,45 +747,53 @@ mergeRecursiveCallsDict left right =
|
|||||||
|
|
||||||
processDFSTree : Dict String (Dict String a) -> List String -> Visited -> { recursiveCalls : RecursiveCalls, visited : Visited, stack : List String }
|
processDFSTree : Dict String (Dict String a) -> List String -> Visited -> { recursiveCalls : RecursiveCalls, visited : Visited, stack : List String }
|
||||||
processDFSTree graph stack visited =
|
processDFSTree graph stack visited =
|
||||||
let
|
case stack of
|
||||||
vertices : List String
|
[] ->
|
||||||
vertices =
|
{ recursiveCalls = Dict.empty, visited = visited, stack = [] }
|
||||||
List.head stack
|
|
||||||
|> Maybe.andThen (\v -> Dict.get v graph)
|
|
||||||
|> Maybe.withDefault Dict.empty
|
|
||||||
|> Dict.keys
|
|
||||||
in
|
|
||||||
List.foldl
|
|
||||||
(\vertice acc ->
|
|
||||||
case Dict.get vertice visited of
|
|
||||||
Just InStack ->
|
|
||||||
{ acc | recursiveCalls = insertCycle stack vertice acc.recursiveCalls }
|
|
||||||
|
|
||||||
Just Done ->
|
head :: restOfStack ->
|
||||||
acc
|
let
|
||||||
|
vertices : List String
|
||||||
|
vertices =
|
||||||
|
Dict.get head graph
|
||||||
|
|> Maybe.withDefault Dict.empty
|
||||||
|
|> Dict.keys
|
||||||
|
in
|
||||||
|
List.foldl
|
||||||
|
(\vertice acc ->
|
||||||
|
case Dict.get vertice visited of
|
||||||
|
Just InStack ->
|
||||||
|
{ acc | recursiveCalls = insertCycle stack vertice acc.recursiveCalls }
|
||||||
|
|
||||||
Nothing ->
|
Just Done ->
|
||||||
let
|
acc
|
||||||
res : { recursiveCalls : RecursiveCalls, visited : Visited, stack : List String }
|
|
||||||
res =
|
Nothing ->
|
||||||
processDFSTree
|
let
|
||||||
graph
|
res : { recursiveCalls : RecursiveCalls, visited : Visited, stack : List String }
|
||||||
(vertice :: stack)
|
res =
|
||||||
(Dict.insert vertice InStack visited)
|
processDFSTree
|
||||||
in
|
graph
|
||||||
{ recursiveCalls = mergeRecursiveCallsDict res.recursiveCalls acc.recursiveCalls, visited = res.visited }
|
(vertice :: stack)
|
||||||
)
|
(Dict.insert vertice InStack visited)
|
||||||
{ recursiveCalls = Dict.empty, visited = visited }
|
in
|
||||||
vertices
|
{ recursiveCalls = mergeRecursiveCallsDict res.recursiveCalls acc.recursiveCalls, visited = res.visited }
|
||||||
|> (\res ->
|
)
|
||||||
{ recursiveCalls = res.recursiveCalls
|
{ recursiveCalls = Dict.empty, visited = visited }
|
||||||
, visited =
|
vertices
|
||||||
List.head stack
|
|> updateStack head restOfStack
|
||||||
|> Maybe.map (\v -> Dict.insert v Done res.visited)
|
|
||||||
|> Maybe.withDefault res.visited
|
|
||||||
, stack = List.drop 1 stack
|
updateStack :
|
||||||
}
|
String
|
||||||
)
|
-> List String
|
||||||
|
-> { recursiveCalls : RecursiveCalls, visited : Visited }
|
||||||
|
-> { recursiveCalls : RecursiveCalls, visited : Visited, stack : List String }
|
||||||
|
updateStack head stack res =
|
||||||
|
{ recursiveCalls = res.recursiveCalls
|
||||||
|
, visited = Dict.insert head Done res.visited
|
||||||
|
, stack = stack
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
dataExtractor : ProjectContext -> Encode.Value
|
dataExtractor : ProjectContext -> Encode.Value
|
||||||
|
@ -611,6 +611,41 @@ fun5 n =
|
|||||||
"fun5": 1
|
"fun5": 1
|
||||||
}
|
}
|
||||||
}"""
|
}"""
|
||||||
|
, test "recursive call complexity should not depend on alphabetical order" <|
|
||||||
|
\() ->
|
||||||
|
"""module A exposing (..)
|
||||||
|
|
||||||
|
b () = b ()
|
||||||
|
|
||||||
|
a = b ()
|
||||||
|
|
||||||
|
c = b ()
|
||||||
|
"""
|
||||||
|
|> expectAtExactly
|
||||||
|
[ { name = "a"
|
||||||
|
, complexity = 1
|
||||||
|
, atExactly = { start = { row = 5, column = 1 }, end = { row = 5, column = 2 } }
|
||||||
|
, details = [ "Line 5: +1 for the indirect recursive call to b" ]
|
||||||
|
}
|
||||||
|
, { name = "b"
|
||||||
|
, complexity = 1
|
||||||
|
, atExactly = { start = { row = 3, column = 1 }, end = { row = 3, column = 2 } }
|
||||||
|
, details = [ "Line 3: +1 for the recursive call" ]
|
||||||
|
}
|
||||||
|
, { name = "c"
|
||||||
|
, complexity = 1
|
||||||
|
, atExactly = { start = { row = 7, column = 1 }, end = { row = 7, column = 2 } }
|
||||||
|
, details = [ "Line 7: +1 for the indirect recursive call to b" ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"A": {
|
||||||
|
"a": 1,
|
||||||
|
"b": 1,
|
||||||
|
"c": 1
|
||||||
|
}
|
||||||
|
}"""
|
||||||
, test "the complexity of a function should not affect another function's computed complexity" <|
|
, test "the complexity of a function should not affect another function's computed complexity" <|
|
||||||
\() ->
|
\() ->
|
||||||
"""module A exposing (..)
|
"""module A exposing (..)
|
||||||
|
Loading…
Reference in New Issue
Block a user