Merge pull request #1324 from ngzhian/679

Understand array variable declaration in read (fixes #679)
This commit is contained in:
Vidar Holen 2018-09-15 12:33:58 -07:00 committed by GitHub
commit a06d7c1841
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 25 additions and 4 deletions

View File

@ -710,6 +710,7 @@ prop_checkArrayWithoutIndex5 = verifyTree checkArrayWithoutIndex "a[0]=foo; echo
prop_checkArrayWithoutIndex6 = verifyTree checkArrayWithoutIndex "echo $PIPESTATUS" prop_checkArrayWithoutIndex6 = verifyTree checkArrayWithoutIndex "echo $PIPESTATUS"
prop_checkArrayWithoutIndex7 = verifyTree checkArrayWithoutIndex "a=(a b); a+=c" prop_checkArrayWithoutIndex7 = verifyTree checkArrayWithoutIndex "a=(a b); a+=c"
prop_checkArrayWithoutIndex8 = verifyTree checkArrayWithoutIndex "declare -a foo; foo=bar;" prop_checkArrayWithoutIndex8 = verifyTree checkArrayWithoutIndex "declare -a foo; foo=bar;"
prop_checkArrayWithoutIndex9 = verifyTree checkArrayWithoutIndex "read -r -a arr <<< 'foo bar'; echo \"$arr\""
checkArrayWithoutIndex params _ = checkArrayWithoutIndex params _ =
doVariableFlowAnalysis readF writeF defaultMap (variableFlow params) doVariableFlowAnalysis readF writeF defaultMap (variableFlow params)
where where
@ -1880,6 +1881,7 @@ prop_checkUnassignedReferences32= verifyNotTree checkUnassignedReferences "if [[
prop_checkUnassignedReferences33= verifyNotTree checkUnassignedReferences "f() { local -A foo; echo \"${foo[@]}\"; }" prop_checkUnassignedReferences33= verifyNotTree checkUnassignedReferences "f() { local -A foo; echo \"${foo[@]}\"; }"
prop_checkUnassignedReferences34= verifyNotTree checkUnassignedReferences "declare -A foo; (( foo[bar] ))" prop_checkUnassignedReferences34= verifyNotTree checkUnassignedReferences "declare -A foo; (( foo[bar] ))"
prop_checkUnassignedReferences35= verifyNotTree checkUnassignedReferences "echo ${arr[foo-bar]:?fail}" prop_checkUnassignedReferences35= verifyNotTree checkUnassignedReferences "echo ${arr[foo-bar]:?fail}"
prop_checkUnassignedReferences36= verifyNotTree checkUnassignedReferences "read -a foo -r <<<\"foo bar\"; echo \"$foo\""
checkUnassignedReferences params t = warnings checkUnassignedReferences params t = warnings
where where
(readMap, writeMap) = execState (mapM tally $ variableFlow params) (Map.empty, Map.empty) (readMap, writeMap) = execState (mapM tally $ variableFlow params) (Map.empty, Map.empty)

View File

@ -525,12 +525,22 @@ getReferencedVariableCommand base@(T_SimpleCommand _ _ (T_NormalWord _ (T_Litera
getReferencedVariableCommand _ = [] getReferencedVariableCommand _ = []
-- The function returns a tuple consisting of four items describing an assignment.
-- Given e.g. declare foo=bar
-- (
-- BaseCommand :: Token, -- The command/structure assigning the variable, i.e. declare foo=bar
-- AssignmentToken :: Token, -- The specific part that assigns this variable, i.e. foo=bar
-- VariableName :: String, -- The variable name, i.e. foo
-- VariableValue :: DataType -- A description of the value being assigned, i.e. "Literal string with value foo"
-- )
getModifiedVariableCommand base@(T_SimpleCommand _ _ (T_NormalWord _ (T_Literal _ x:_):rest)) = getModifiedVariableCommand base@(T_SimpleCommand _ _ (T_NormalWord _ (T_Literal _ x:_):rest)) =
filter (\(_,_,s,_) -> not ("-" `isPrefixOf` s)) $ filter (\(_,_,s,_) -> not ("-" `isPrefixOf` s)) $
case x of case x of
"read" -> "read" ->
let params = map getLiteral rest in let params = map getLiteral rest
catMaybes . takeWhile isJust . reverse $ params readArrayVars = getReadArrayVariables rest
in
catMaybes . (++ readArrayVars) . takeWhile isJust . reverse $ params
"getopts" -> "getopts" ->
case rest of case rest of
opts:var:_ -> maybeToList $ getLiteral var opts:var:_ -> maybeToList $ getLiteral var
@ -573,10 +583,14 @@ getModifiedVariableCommand base@(T_SimpleCommand _ _ (T_NormalWord _ (T_Literal
where where
defaultType = if any (`elem` flags) ["a", "A"] then DataArray else DataString defaultType = if any (`elem` flags) ["a", "A"] then DataArray else DataString
getLiteral t = do getLiteralOfDataType t d = do
s <- getLiteralString t s <- getLiteralString t
when ("-" `isPrefixOf` s) $ fail "argument" when ("-" `isPrefixOf` s) $ fail "argument"
return (base, t, s, DataString SourceExternal) return (base, t, s, d)
getLiteral t = getLiteralOfDataType t (DataString SourceExternal)
getLiteralArray t = getLiteralOfDataType t (DataArray SourceExternal)
getModifierParamString = getModifierParam DataString getModifierParamString = getModifierParam DataString
@ -618,6 +632,11 @@ getModifiedVariableCommand base@(T_SimpleCommand _ _ (T_NormalWord _ (T_Literal
guard $ isVariableName name guard $ isVariableName name
return (base, lastArg, name, DataArray SourceExternal) return (base, lastArg, name, DataArray SourceExternal)
-- get all the array variables used in read, e.g. read -a arr
getReadArrayVariables args = do
map (getLiteralArray . snd)
(filter (\(x,_) -> getLiteralString x == Just "-a") (zip (args) (tail args)))
getModifiedVariableCommand _ = [] getModifiedVariableCommand _ = []
getIndexReferences s = fromMaybe [] $ do getIndexReferences s = fromMaybe [] $ do