Correctly handle empty variables for SC2086 (fixes #1722)
This commit is contained in:
parent
4dfd7eb1cf
commit
5962b01816
|
@ -1,6 +1,7 @@
|
||||||
## v0.7.1 - soon
|
## v0.7.1 - soon
|
||||||
### Fixed
|
### Fixed
|
||||||
- `-f diff` no longer claims that it found more issues when it didn't
|
- `-f diff` no longer claims that it found more issues when it didn't
|
||||||
|
- Known empty variables now correctly trigger SC2086
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- SC2254: Suggest quoting expansions in case statements
|
- SC2254: Suggest quoting expansions in case statements
|
||||||
|
|
|
@ -1807,6 +1807,21 @@ prop_checkSpacefulness35= verifyNotTree checkSpacefulness "echo ${1+\"$1\"}"
|
||||||
prop_checkSpacefulness36= verifyNotTree checkSpacefulness "arg=$#; echo $arg"
|
prop_checkSpacefulness36= verifyNotTree checkSpacefulness "arg=$#; echo $arg"
|
||||||
prop_checkSpacefulness37= verifyNotTree checkSpacefulness "@test 'status' {\n [ $status -eq 0 ]\n}"
|
prop_checkSpacefulness37= verifyNotTree checkSpacefulness "@test 'status' {\n [ $status -eq 0 ]\n}"
|
||||||
prop_checkSpacefulness37v = verifyTree checkVerboseSpacefulness "@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
|
-- This is slightly awkward because we want to support structured
|
||||||
-- optional checks based on nearly the same logic
|
-- optional checks based on nearly the same logic
|
||||||
|
@ -1814,7 +1829,7 @@ checkSpacefulness params = checkSpacefulness' onFind params
|
||||||
where
|
where
|
||||||
emit x = tell [x]
|
emit x = tell [x]
|
||||||
onFind spaces token _ =
|
onFind spaces token _ =
|
||||||
when spaces $
|
when (spaces /= SpaceNone) $
|
||||||
if isDefaultAssignment (parentMap params) token
|
if isDefaultAssignment (parentMap params) token
|
||||||
then
|
then
|
||||||
emit $ makeComment InfoC (getId token) 2223
|
emit $ makeComment InfoC (getId token) 2223
|
||||||
|
@ -1829,7 +1844,6 @@ checkSpacefulness params = checkSpacefulness' onFind params
|
||||||
any (`isPrefixOf` modifier) ["=", ":="]
|
any (`isPrefixOf` modifier) ["=", ":="]
|
||||||
&& isParamTo parents ":" token
|
&& isParamTo parents ":" token
|
||||||
|
|
||||||
|
|
||||||
prop_checkSpacefulness4v= verifyTree checkVerboseSpacefulness "foo=3; foo=$(echo $foo)"
|
prop_checkSpacefulness4v= verifyTree checkVerboseSpacefulness "foo=3; foo=$(echo $foo)"
|
||||||
prop_checkSpacefulness8v= verifyTree checkVerboseSpacefulness "a=foo\\ bar; a=foo; rm $a"
|
prop_checkSpacefulness8v= verifyTree checkVerboseSpacefulness "a=foo\\ bar; a=foo; rm $a"
|
||||||
prop_checkSpacefulness28v = verifyTree checkVerboseSpacefulness "exec {n}>&1; echo $n"
|
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
|
checkVerboseSpacefulness params = checkSpacefulness' onFind params
|
||||||
where
|
where
|
||||||
onFind spaces token name =
|
onFind spaces token name =
|
||||||
when (not spaces && name `notElem` specialVariablesWithoutSpaces) $
|
when (spaces == SpaceNone && name `notElem` specialVariablesWithoutSpaces) $
|
||||||
tell [makeCommentWithFix StyleC (getId token) 2248
|
tell [makeCommentWithFix StyleC (getId token) 2248
|
||||||
"Prefer double quoting even when variables don't contain special characters."
|
"Prefer double quoting even when variables don't contain special characters."
|
||||||
(addDoubleQuotesAround params token)]
|
(addDoubleQuotesAround params token)]
|
||||||
|
|
||||||
addDoubleQuotesAround params token = (surroundWidth (getId token) params "\"")
|
addDoubleQuotesAround params token = (surroundWidth (getId token) params "\"")
|
||||||
checkSpacefulness'
|
checkSpacefulness'
|
||||||
:: (Bool -> Token -> String -> Writer [TokenComment] ()) ->
|
:: (SpaceStatus -> Token -> String -> Writer [TokenComment] ()) ->
|
||||||
Parameters -> Token -> [TokenComment]
|
Parameters -> Token -> [TokenComment]
|
||||||
checkSpacefulness' onFind params t =
|
checkSpacefulness' onFind params t =
|
||||||
doVariableFlowAnalysis readF writeF (Map.fromList defaults) (variableFlow params)
|
doVariableFlowAnalysis readF writeF (Map.fromList defaults) (variableFlow params)
|
||||||
where
|
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 =
|
setSpaces name status =
|
||||||
modify $ Map.insert name bool
|
modify $ Map.insert name status
|
||||||
|
|
||||||
readF _ token name = do
|
readF _ token name = do
|
||||||
spaces <- hasSpaces name
|
spaces <- hasSpaces name
|
||||||
|
@ -1871,13 +1885,13 @@ checkSpacefulness' onFind params t =
|
||||||
where
|
where
|
||||||
emit x = tell [x]
|
emit x = tell [x]
|
||||||
|
|
||||||
writeF _ _ name (DataString SourceExternal) = setSpaces name True >> return []
|
writeF _ _ name (DataString SourceExternal) = setSpaces name SpaceSome >> return []
|
||||||
writeF _ _ name (DataString SourceInteger) = setSpaces name False >> return []
|
writeF _ _ name (DataString SourceInteger) = setSpaces name SpaceNone >> return []
|
||||||
|
|
||||||
writeF _ _ name (DataString (SourceFrom vals)) = do
|
writeF _ _ name (DataString (SourceFrom vals)) = do
|
||||||
map <- get
|
map <- get
|
||||||
setSpaces name
|
setSpaces name
|
||||||
(isSpacefulWord (\x -> Map.findWithDefault True x map) vals)
|
(isSpacefulWord (\x -> Map.findWithDefault SpaceSome x map) vals)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
writeF _ _ _ _ = return []
|
writeF _ _ _ _ = return []
|
||||||
|
@ -1889,24 +1903,28 @@ checkSpacefulness' onFind params t =
|
||||||
(T_DollarBraced _ _ _ ) -> True
|
(T_DollarBraced _ _ _ ) -> True
|
||||||
_ -> False
|
_ -> False
|
||||||
|
|
||||||
isSpacefulWord :: (String -> Bool) -> [Token] -> Bool
|
isSpacefulWord :: (String -> SpaceStatus) -> [Token] -> SpaceStatus
|
||||||
isSpacefulWord f = any (isSpaceful f)
|
isSpacefulWord f = mconcat . map (isSpaceful f)
|
||||||
isSpaceful :: (String -> Bool) -> Token -> Bool
|
isSpaceful :: (String -> SpaceStatus) -> Token -> SpaceStatus
|
||||||
isSpaceful spacefulF x =
|
isSpaceful spacefulF x =
|
||||||
case x of
|
case x of
|
||||||
T_DollarExpansion _ _ -> True
|
T_DollarExpansion _ _ -> SpaceSome
|
||||||
T_Backticked _ _ -> True
|
T_Backticked _ _ -> SpaceSome
|
||||||
T_Glob _ _ -> True
|
T_Glob _ _ -> SpaceSome
|
||||||
T_Extglob {} -> True
|
T_Extglob {} -> SpaceSome
|
||||||
T_Literal _ s -> s `containsAny` globspace
|
T_DollarArithmetic _ _ -> SpaceNone
|
||||||
T_SingleQuoted _ s -> s `containsAny` globspace
|
T_Literal _ s -> fromLiteral s
|
||||||
|
T_SingleQuoted _ s -> fromLiteral s
|
||||||
T_DollarBraced _ _ _ -> spacefulF $ getBracedReference $ bracedString x
|
T_DollarBraced _ _ _ -> spacefulF $ getBracedReference $ bracedString x
|
||||||
T_NormalWord _ w -> isSpacefulWord spacefulF w
|
T_NormalWord _ w -> isSpacefulWord spacefulF w
|
||||||
T_DoubleQuoted _ w -> isSpacefulWord spacefulF w
|
T_DoubleQuoted _ w -> isSpacefulWord spacefulF w
|
||||||
_ -> False
|
_ -> SpaceEmpty
|
||||||
where
|
where
|
||||||
globspace = "*?[] \t\n"
|
globspace = "*?[] \t\n"
|
||||||
containsAny s = any (`elem` s)
|
containsAny s = any (`elem` s)
|
||||||
|
fromLiteral "" = SpaceEmpty
|
||||||
|
fromLiteral s | s `containsAny` globspace = SpaceSome
|
||||||
|
fromLiteral _ = SpaceNone
|
||||||
|
|
||||||
prop_CheckVariableBraces1 = verify checkVariableBraces "a='123'; echo $a"
|
prop_CheckVariableBraces1 = verify checkVariableBraces "a='123'; echo $a"
|
||||||
prop_CheckVariableBraces2 = verifyNot checkVariableBraces "a='123'; echo ${a}"
|
prop_CheckVariableBraces2 = verifyNot checkVariableBraces "a='123'; echo ${a}"
|
||||||
|
|
Loading…
Reference in New Issue