Correctly handle empty variables for SC2086 (fixes #1722)

This commit is contained in:
Vidar Holen 2019-11-03 12:45:13 -08:00
parent 4dfd7eb1cf
commit 5962b01816
2 changed files with 40 additions and 21 deletions

View File

@ -1,6 +1,7 @@
## v0.7.1 - soon
### Fixed
- `-f diff` no longer claims that it found more issues when it didn't
- Known empty variables now correctly trigger SC2086
### Added
- SC2254: Suggest quoting expansions in case statements

View File

@ -1807,6 +1807,21 @@ prop_checkSpacefulness35= verifyNotTree checkSpacefulness "echo ${1+\"$1\"}"
prop_checkSpacefulness36= verifyNotTree checkSpacefulness "arg=$#; echo $arg"
prop_checkSpacefulness37= verifyNotTree checkSpacefulness "@test 'status' {\n [ $status -eq 0 ]\n}"
prop_checkSpacefulness37v = verifyTree checkVerboseSpacefulness "@test 'status' {\n [ $status -eq 0 ]\n}"
prop_checkSpacefulness38= verifyTree checkSpacefulness "a=; echo $a"
prop_checkSpacefulness39= verifyNotTree checkSpacefulness "a=''\"\"''; b=x$a; echo $b"
prop_checkSpacefulness40= verifyNotTree checkSpacefulness "a=$((x+1)); echo $a"
data SpaceStatus = SpaceSome | SpaceNone | SpaceEmpty deriving (Eq)
instance Semigroup SpaceStatus where
(<>) x y =
case (x,y) of
(SpaceNone, SpaceNone) -> SpaceNone
(SpaceSome, _) -> SpaceSome
(_, SpaceSome) -> SpaceSome
(SpaceEmpty, x) -> x
(x, SpaceEmpty) -> x
instance Monoid SpaceStatus where
mempty = SpaceEmpty
-- This is slightly awkward because we want to support structured
-- optional checks based on nearly the same logic
@ -1814,7 +1829,7 @@ checkSpacefulness params = checkSpacefulness' onFind params
where
emit x = tell [x]
onFind spaces token _ =
when spaces $
when (spaces /= SpaceNone) $
if isDefaultAssignment (parentMap params) token
then
emit $ makeComment InfoC (getId token) 2223
@ -1829,7 +1844,6 @@ checkSpacefulness params = checkSpacefulness' onFind params
any (`isPrefixOf` modifier) ["=", ":="]
&& isParamTo parents ":" token
prop_checkSpacefulness4v= verifyTree checkVerboseSpacefulness "foo=3; foo=$(echo $foo)"
prop_checkSpacefulness8v= verifyTree checkVerboseSpacefulness "a=foo\\ bar; a=foo; rm $a"
prop_checkSpacefulness28v = verifyTree checkVerboseSpacefulness "exec {n}>&1; echo $n"
@ -1837,24 +1851,24 @@ prop_checkSpacefulness36v = verifyTree checkVerboseSpacefulness "arg=$#; echo $a
checkVerboseSpacefulness params = checkSpacefulness' onFind params
where
onFind spaces token name =
when (not spaces && name `notElem` specialVariablesWithoutSpaces) $
when (spaces == SpaceNone && name `notElem` specialVariablesWithoutSpaces) $
tell [makeCommentWithFix StyleC (getId token) 2248
"Prefer double quoting even when variables don't contain special characters."
(addDoubleQuotesAround params token)]
addDoubleQuotesAround params token = (surroundWidth (getId token) params "\"")
checkSpacefulness'
:: (Bool -> Token -> String -> Writer [TokenComment] ()) ->
:: (SpaceStatus -> Token -> String -> Writer [TokenComment] ()) ->
Parameters -> Token -> [TokenComment]
checkSpacefulness' onFind params t =
doVariableFlowAnalysis readF writeF (Map.fromList defaults) (variableFlow params)
where
defaults = zip variablesWithoutSpaces (repeat False)
defaults = zip variablesWithoutSpaces (repeat SpaceNone)
hasSpaces name = gets (Map.findWithDefault True name)
hasSpaces name = gets (Map.findWithDefault SpaceSome name)
setSpaces name bool =
modify $ Map.insert name bool
setSpaces name status =
modify $ Map.insert name status
readF _ token name = do
spaces <- hasSpaces name
@ -1871,13 +1885,13 @@ checkSpacefulness' onFind params t =
where
emit x = tell [x]
writeF _ _ name (DataString SourceExternal) = setSpaces name True >> return []
writeF _ _ name (DataString SourceInteger) = setSpaces name False >> return []
writeF _ _ name (DataString SourceExternal) = setSpaces name SpaceSome >> return []
writeF _ _ name (DataString SourceInteger) = setSpaces name SpaceNone >> return []
writeF _ _ name (DataString (SourceFrom vals)) = do
map <- get
setSpaces name
(isSpacefulWord (\x -> Map.findWithDefault True x map) vals)
(isSpacefulWord (\x -> Map.findWithDefault SpaceSome x map) vals)
return []
writeF _ _ _ _ = return []
@ -1889,24 +1903,28 @@ checkSpacefulness' onFind params t =
(T_DollarBraced _ _ _ ) -> True
_ -> False
isSpacefulWord :: (String -> Bool) -> [Token] -> Bool
isSpacefulWord f = any (isSpaceful f)
isSpaceful :: (String -> Bool) -> Token -> Bool
isSpacefulWord :: (String -> SpaceStatus) -> [Token] -> SpaceStatus
isSpacefulWord f = mconcat . map (isSpaceful f)
isSpaceful :: (String -> SpaceStatus) -> Token -> SpaceStatus
isSpaceful spacefulF x =
case x of
T_DollarExpansion _ _ -> True
T_Backticked _ _ -> True
T_Glob _ _ -> True
T_Extglob {} -> True
T_Literal _ s -> s `containsAny` globspace
T_SingleQuoted _ s -> s `containsAny` globspace
T_DollarExpansion _ _ -> SpaceSome
T_Backticked _ _ -> SpaceSome
T_Glob _ _ -> SpaceSome
T_Extglob {} -> SpaceSome
T_DollarArithmetic _ _ -> SpaceNone
T_Literal _ s -> fromLiteral s
T_SingleQuoted _ s -> fromLiteral s
T_DollarBraced _ _ _ -> spacefulF $ getBracedReference $ bracedString x
T_NormalWord _ w -> isSpacefulWord spacefulF w
T_DoubleQuoted _ w -> isSpacefulWord spacefulF w
_ -> False
_ -> SpaceEmpty
where
globspace = "*?[] \t\n"
containsAny s = any (`elem` s)
fromLiteral "" = SpaceEmpty
fromLiteral s | s `containsAny` globspace = SpaceSome
fromLiteral _ = SpaceNone
prop_CheckVariableBraces1 = verify checkVariableBraces "a='123'; echo $a"
prop_CheckVariableBraces2 = verifyNot checkVariableBraces "a='123'; echo ${a}"