From 5e5356c87f754ecf5a0b7da8ed698a1589accff8 Mon Sep 17 00:00:00 2001 From: Peter Tripp Date: Tue, 24 Mar 2026 13:41:09 -0400 Subject: [PATCH 1/2] Avoid SC2164 on trailing cd in functions --- src/ShellCheck/Analytics.hs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/ShellCheck/Analytics.hs b/src/ShellCheck/Analytics.hs index a4e2186a4..81277246e 100644 --- a/src/ShellCheck/Analytics.hs +++ b/src/ShellCheck/Analytics.hs @@ -3294,6 +3294,7 @@ prop_checkUncheckedPopd10 = verifyNotTree checkUncheckedCdPushdPopd "cd ../.." prop_checkUncheckedPopd11 = verifyNotTree checkUncheckedCdPushdPopd "cd ../.././.." prop_checkUncheckedPopd12 = verifyNotTree checkUncheckedCdPushdPopd "cd /" prop_checkUncheckedPopd13 = verifyTree checkUncheckedCdPushdPopd "cd ../../.../.." +prop_checkUncheckedCdInFunction1 = verifyNotTree checkUncheckedCdPushdPopd "#!/bin/bash\nfoo() {\n cd /abc\n}" checkUncheckedCdPushdPopd params root = if hasSetE params then @@ -3304,6 +3305,7 @@ checkUncheckedCdPushdPopd params root = | name `elem` ["cd", "pushd", "popd"] && not (isSafeDir t) && not (name `elem` ["pushd", "popd"] && ("n" `elem` map snd (getAllFlags t))) + && not (isLastCommandInFunction t) && not (isCondition $ getPath (parentMap params) t) = warnWithFix (getId t) 2164 ("Use '" ++ name ++ " ... || exit' or '" ++ name ++ " ... || return' in case " ++ name ++ " fails.") @@ -3311,6 +3313,15 @@ checkUncheckedCdPushdPopd params root = where name = getName t checkElement _ = return () getName t = fromMaybe "" $ getCommandName t + isLastCommandInFunction t = + case getPath (parentMap params) t of + _ NE.:| T_BraceGroup _ commands:T_Function {}:_ -> t `isLastOf` commands + _ -> False + isLastOf t commands = + case commands of + [x] -> x == t + _:rest -> isLastOf t rest + [] -> False isSafeDir t = case oversimplify t of [_, str] -> str `matches` regex _ -> False From 0648d5dc46c780644c33bc66b06cf70c2c21b132 Mon Sep 17 00:00:00 2001 From: Peter Tripp Date: Wed, 8 Apr 2026 11:18:01 -0400 Subject: [PATCH 2/2] Fix --- src/ShellCheck/Analytics.hs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/ShellCheck/Analytics.hs b/src/ShellCheck/Analytics.hs index 81277246e..afdb8fc11 100644 --- a/src/ShellCheck/Analytics.hs +++ b/src/ShellCheck/Analytics.hs @@ -3314,14 +3314,12 @@ checkUncheckedCdPushdPopd params root = checkElement _ = return () getName t = fromMaybe "" $ getCommandName t isLastCommandInFunction t = - case getPath (parentMap params) t of - _ NE.:| T_BraceGroup _ commands:T_Function {}:_ -> t `isLastOf` commands - _ -> False - isLastOf t commands = - case commands of - [x] -> x == t - _:rest -> isLastOf t rest - [] -> False + go $ NE.tail $ getPath (parentMap params) t + where + go (child:T_BraceGroup _ commands:T_Function {}:_) = + not (null commands) && getId (last commands) == getId child + go (_:rest) = go rest + go [] = False isSafeDir t = case oversimplify t of [_, str] -> str `matches` regex _ -> False