Backport rules from cognitive-complexity

This commit is contained in:
Jeroen Engels 2023-09-03 11:45:53 +02:00
parent cf2a955d40
commit 60a15216a9
2 changed files with 135 additions and 77 deletions

View File

@ -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,6 +383,7 @@ expressionEnterVisitorHelp node context =
{ context | nesting = context.nesting + 1 } { context | nesting = context.nesting + 1 }
Expression.FunctionOrValue [] name -> Expression.FunctionOrValue [] name ->
if isFunctionReference name then
{ context { context
| references = | references =
if Dict.member name context.references then if Dict.member name context.references then
@ -419,10 +395,50 @@ expressionEnterVisitorHelp node context =
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,11 +747,15 @@ 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 =
case stack of
[] ->
{ recursiveCalls = Dict.empty, visited = visited, stack = [] }
head :: restOfStack ->
let let
vertices : List String vertices : List String
vertices = vertices =
List.head stack Dict.get head graph
|> Maybe.andThen (\v -> Dict.get v graph)
|> Maybe.withDefault Dict.empty |> Maybe.withDefault Dict.empty
|> Dict.keys |> Dict.keys
in in
@ -762,15 +781,19 @@ processDFSTree graph stack visited =
) )
{ recursiveCalls = Dict.empty, visited = visited } { recursiveCalls = Dict.empty, visited = visited }
vertices vertices
|> (\res -> |> updateStack head restOfStack
updateStack :
String
-> List String
-> { recursiveCalls : RecursiveCalls, visited : Visited }
-> { recursiveCalls : RecursiveCalls, visited : Visited, stack : List String }
updateStack head stack res =
{ recursiveCalls = res.recursiveCalls { recursiveCalls = res.recursiveCalls
, visited = , visited = Dict.insert head Done res.visited
List.head stack , stack = stack
|> Maybe.map (\v -> Dict.insert v Done res.visited)
|> Maybe.withDefault res.visited
, stack = List.drop 1 stack
} }
)
dataExtractor : ProjectContext -> Encode.Value dataExtractor : ProjectContext -> Encode.Value

View File

@ -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 (..)