@@ -5053,6 +5053,8 @@ prop_checkCommandIsUnreachable6 = verifyNot checkCommandIsUnreachable "return ||
50535053prop_checkCommandIsUnreachable7 = verifyNot checkCommandIsUnreachable " return 2>/dev/null ||:"
50545054prop_checkCommandIsUnreachable8 = verifyNot checkCommandIsUnreachable " return; echo 'reachable when not in function'"
50555055prop_checkCommandIsUnreachable9 = verify checkCommandIsUnreachable " f() { return; echo unreachable; }"
5056+ prop_checkCommandIsUnreachable10 = verifyNot checkCommandIsUnreachable " f; f() { :; }; exit $?"
5057+ prop_checkCommandIsUnreachable11 = verifyNot checkCommandIsUnreachable " PS4func; PS4func() { echo test; }; exit $?"
50565058checkCommandIsUnreachable params t =
50575059 case t of
50585060 T_Pipeline {} -> sequence_ $ do
@@ -5062,10 +5064,11 @@ checkCommandIsUnreachable params t =
50625064 guard . not $ isSourced params t
50635065 guard . not $ any (\ t -> isUnreachable t || isUnreachableFunction t) $ NE. drop 1 $ getPath (parentMap params) t
50645066 return $ info (getId t) 2317 " Command appears to be unreachable. Check usage (or ignore if invoked indirectly)."
5065- T_Function id _ _ _ _ ->
5067+ T_Function id _ _ name _ ->
50665068 when (isUnreachableFunction t
50675069 && (not . any isUnreachableFunction . NE. drop 1 $ getPath (parentMap params) t)
5068- && (not $ isSourced params t)) $
5070+ && (not $ isSourced params t)
5071+ && (not $ isFunctionInvokedInReachableCode name)) $
50695072 info id 2329 " This function is never invoked. Check usage (or ignored if invoked indirectly)."
50705073 _ -> return ()
50715074 where
@@ -5078,6 +5081,18 @@ checkCommandIsUnreachable params t =
50785081 cfga <- cfgAnalysis params
50795082 state <- CF. getIncomingState cfga (getId t)
50805083 return . not $ CF. stateIsReachable state
5084+
5085+ -- Check if a function is invoked anywhere in reachable code
5086+ isFunctionInvokedInReachableCode :: String -> Bool
5087+ isFunctionInvokedInReachableCode name =
5088+ any isFunctionCall $ analyse findCalls (rootNode params)
5089+ where
5090+ findCalls token = when (isFunctionCall token) $ modify (token: )
5091+ isFunctionCall token =
5092+ case token of
5093+ T_SimpleCommand _ _ (cmd: _) ->
5094+ getUnquotedLiteral cmd == Just name && not (isUnreachable token)
5095+ _ -> False
50815096
50825097
50835098prop_checkOverwrittenExitCode1 = verify checkOverwrittenExitCode " x; [ $? -eq 1 ] || [ $? -eq 2 ]"
0 commit comments