Skip to content

Commit

Permalink
Add SC2317 warning about unreachable commands
Browse files Browse the repository at this point in the history
  • Loading branch information
koalaman committed Jul 20, 2022
1 parent f77a545 commit 642ad86
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## Git
### Added
- SC2316: Warn about 'local readonly foo' and similar (thanks, patrickxia!)
- SC2317: Warn about unreachable commands

### Fixed

Expand Down
32 changes: 24 additions & 8 deletions src/ShellCheck/Analytics.hs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ nodeChecks = [
,checkCommandWithTrailingSymbol
,checkUnquotedParameterExpansionPattern
,checkBatsTestDoesNotUseNegation
,checkCommandIsUnreachable
]

optionalChecks = map fst optionalTreeChecks
Expand Down Expand Up @@ -4129,13 +4130,6 @@ checkAliasUsedInSameParsingUnit params root =
checkUnit :: [Token] -> Writer [TokenComment] ()
checkUnit unit = evalStateT (mapM_ (doAnalysis findCommands) unit) (Map.empty)

isSourced t =
let
f (T_SourceCommand {}) = True
f _ = False
in
any f $ getPath (parentMap params) t

findCommands :: Token -> StateT (Map.Map String Token) (Writer [TokenComment]) ()
findCommands t = case t of
T_SimpleCommand _ _ (cmd:args) ->
Expand All @@ -4146,7 +4140,7 @@ checkAliasUsedInSameParsingUnit params root =
cmd <- gets (Map.lookup name)
case cmd of
Just alias ->
unless (isSourced t || shouldIgnoreCode params 2262 alias) $ do
unless (isSourced params t || shouldIgnoreCode params 2262 alias) $ do
warn (getId alias) 2262 "This alias can't be defined and used in the same parsing unit. Use a function instead."
info (getId t) 2263 "Since they're in the same parsing unit, this command will not refer to the previously mentioned alias."
_ -> return ()
Expand All @@ -4157,6 +4151,14 @@ checkAliasUsedInSameParsingUnit params root =
when (isVariableName name && not (null value)) $
modify (Map.insertWith (\new old -> old) name arg)

isSourced params t =
let
f (T_SourceCommand {}) = True
f _ = False
in
any f $ getPath (parentMap params) t


-- Like groupBy, but compares pairs of adjacent elements, rather than against the first of the span
prop_groupByLink1 = groupByLink (\a b -> a+1 == b) [1,2,3,2,3,7,8,9] == [[1,2,3], [2,3], [7,8,9]]
prop_groupByLink2 = groupByLink (==) ([] :: [()]) == []
Expand Down Expand Up @@ -4910,5 +4912,19 @@ checkBatsTestDoesNotUseNegation params t =
x:rest -> isLastOf t rest
[] -> False


prop_checkCommandIsUnreachable1 = verify checkCommandIsUnreachable "foo; bar; exit; baz"
prop_checkCommandIsUnreachable2 = verify checkCommandIsUnreachable "die() { exit; }; foo; bar; die; baz"
prop_checkCommandIsUnreachable3 = verifyNot checkCommandIsUnreachable "foo; bar || exit; baz"
checkCommandIsUnreachable params t =
case t of
T_Pipeline {} -> sequence_ $ do
state <- CF.getIncomingState (cfgAnalysis params) id
guard . not $ CF.stateIsReachable state
guard . not $ isSourced params t
return $ info id 2317 "Command appears to be unreachable. Check usage (or ignore if invoked indirectly)."
_ -> return ()
where id = getId t

return []
runTests = $( [| $(forAllProperties) (quickCheckWithResult (stdArgs { maxSuccess = 1 }) ) |])

0 comments on commit 642ad86

Please sign in to comment.