Don't look at 'set' options after a non-literal.

This commit is contained in:
Vidar Holen 2019-02-08 22:36:22 -08:00
parent acef53be9c
commit d984f8cbe7
1 changed files with 17 additions and 12 deletions

View File

@ -170,6 +170,7 @@ prop_checkBashisms86 = verifyNot checkBashisms "#!/bin/dash\nset -o emacs"
prop_checkBashisms87 = verify checkBashisms "#!/bin/sh\nset -o emacs" prop_checkBashisms87 = verify checkBashisms "#!/bin/sh\nset -o emacs"
prop_checkBashisms88 = verifyNot checkBashisms "#!/bin/sh\nset -- wget -o foo 'https://some.url'" prop_checkBashisms88 = verifyNot checkBashisms "#!/bin/sh\nset -- wget -o foo 'https://some.url'"
prop_checkBashisms89 = verifyNot checkBashisms "#!/bin/sh\nopts=$-\nset -\"$opts\"" prop_checkBashisms89 = verifyNot checkBashisms "#!/bin/sh\nopts=$-\nset -\"$opts\""
prop_checkBashisms90 = verifyNot checkBashisms "#!/bin/sh\nset -o \"$opt\""
checkBashisms = ForShell [Sh, Dash] $ \t -> do checkBashisms = ForShell [Sh, Dash] $ \t -> do
params <- ask params <- ask
kludge params t kludge params t
@ -272,39 +273,43 @@ checkBashisms = ForShell [Sh, Dash] $ \t -> do
warnMsg (getId arg) "exec flags are" warnMsg (getId arg) "exec flags are"
bashism t@(T_SimpleCommand id _ _) bashism t@(T_SimpleCommand id _ _)
| t `isCommand` "let" = warnMsg id "'let' is" | t `isCommand` "let" = warnMsg id "'let' is"
bashism t@(T_SimpleCommand _ _ (cmd:arg:rest)) bashism t@(T_SimpleCommand _ _ (cmd:args))
| t `isCommand` "set" = unless isDash $ checkOptions (arg:rest) | t `isCommand` "set" = unless isDash $
checkOptions $ getLiteralArgs args
where where
-- Get the literal options from a list of arguments,
-- up until the first non-literal one
getLiteralArgs :: [Token] -> [(Id, String)]
getLiteralArgs (first:rest) = fromMaybe [] $ do
str <- getLiteralString first
return $ (getId first, str) : getLiteralArgs rest
getLiteralArgs [] = []
-- Check a flag-option pair (such as -o errexit) -- Check a flag-option pair (such as -o errexit)
checkOptions (flag:opt:rest) checkOptions (flag@(fid,flag') : opt@(oid,opt') : rest)
| flag' `matches` oFlagRegex = do | flag' `matches` oFlagRegex = do
when (opt' `notElem` longOptions) $ when (opt' `notElem` longOptions) $
warnMsg (getId opt) $ "set option " <> opt' <> " is" warnMsg oid $ "set option " <> opt' <> " is"
checkFlags (flag:rest) checkFlags (flag:rest)
| otherwise = checkFlags (flag:opt:rest) | otherwise = checkFlags (flag:opt:rest)
where
flag' = concat $ getLiteralString flag
opt' = concat $ getLiteralString opt
checkOptions (flag:rest) = checkFlags (flag:rest) checkOptions (flag:rest) = checkFlags (flag:rest)
checkOptions _ = return () checkOptions _ = return ()
-- Check that each option in a sequence of flags -- Check that each option in a sequence of flags
-- (such as -aveo) is valid -- (such as -aveo) is valid
checkFlags (flag:rest) checkFlags (flag@(fid, flag'):rest)
| startsOption flag' = do | startsOption flag' = do
unless (flag' `matches` validFlagsRegex) $ unless (flag' `matches` validFlagsRegex) $
forM_ (tail flag') $ \letter -> forM_ (tail flag') $ \letter ->
when (letter `notElem` optionsSet) $ when (letter `notElem` optionsSet) $
warnMsg (getId flag) $ "set flag " <> ('-':letter:" is") warnMsg fid $ "set flag " <> ('-':letter:" is")
checkOptions rest checkOptions rest
| beginsWithDoubleDash flag' = do | beginsWithDoubleDash flag' = do
warnMsg (getId flag) $ "set flag " <> flag' <> " is" warnMsg fid $ "set flag " <> flag' <> " is"
checkOptions rest checkOptions rest
-- Either a word that doesn't start with a dash, or simply '--', -- Either a word that doesn't start with a dash, or simply '--',
-- so stop checking. -- so stop checking.
| otherwise = return () | otherwise = return ()
where
flag' = concat $ getLiteralString flag
checkFlags [] = return () checkFlags [] = return ()
options = "abCefhmnuvxo" options = "abCefhmnuvxo"