From 41b6e3d5eb81b18998dae6476901cfe60dbf6c7e Mon Sep 17 00:00:00 2001 From: Vidar Holen Date: Sat, 8 Apr 2017 14:37:58 -0700 Subject: [PATCH] Don't warn about [ -v foo ] being unassigned. --- ShellCheck/Analytics.hs | 18 +++++++++++++++--- ShellCheck/AnalyzerLib.hs | 25 ++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/ShellCheck/Analytics.hs b/ShellCheck/Analytics.hs index b28fecc..7bb86d4 100644 --- a/ShellCheck/Analytics.hs +++ b/ShellCheck/Analytics.hs @@ -1795,6 +1795,7 @@ prop_checkUnused32= verifyTree checkUnusedAssignments "let a=b=c; echo $a" prop_checkUnused33= verifyNotTree checkUnusedAssignments "a=foo; [[ foo =~ ^{$a}$ ]]" prop_checkUnused34= verifyNotTree checkUnusedAssignments "foo=1; (( t = foo )); echo $t" prop_checkUnused35= verifyNotTree checkUnusedAssignments "a=foo; b=2; echo ${a:b}" +prop_checkUnused36= verifyNotTree checkUnusedAssignments "if [[ -v foo ]]; then true; fi" checkUnusedAssignments params t = execWriter (mapM_ warnFor unused) where flow = variableFlow params @@ -1845,6 +1846,10 @@ prop_checkUnassignedReferences25= verifyNotTree checkUnassignedReferences "decla prop_checkUnassignedReferences26= verifyNotTree checkUnassignedReferences "a::b() { foo; }; readonly -f a::b" prop_checkUnassignedReferences27= verifyNotTree checkUnassignedReferences ": ${foo:=bar}" prop_checkUnassignedReferences28= verifyNotTree checkUnassignedReferences "#!/bin/ksh\necho \"${.sh.version}\"\n" +prop_checkUnassignedReferences29= verifyNotTree checkUnassignedReferences "if [[ -v foo ]]; then echo $foo; fi" +prop_checkUnassignedReferences30= verifyNotTree checkUnassignedReferences "if [[ -v foo[3] ]]; then echo ${foo[3]}; fi" +prop_checkUnassignedReferences31= verifyNotTree checkUnassignedReferences "X=1; if [[ -v foo[$X+42] ]]; then echo ${foo[$X+42]}; fi" +prop_checkUnassignedReferences32= verifyNotTree checkUnassignedReferences "if [[ -v \"foo[1]\" ]]; then echo ${foo[@]}; fi" checkUnassignedReferences params t = warnings where (readMap, writeMap) = execState (mapM tally $ variableFlow params) (Map.empty, Map.empty) @@ -2415,12 +2420,19 @@ prop_checkTestArgumentSplitting12 = verify checkTestArgumentSplitting "[ *.png ] prop_checkTestArgumentSplitting13 = verify checkTestArgumentSplitting "[ \"$@\" == \"\" ]" prop_checkTestArgumentSplitting14 = verify checkTestArgumentSplitting "[[ \"$@\" == \"\" ]]" prop_checkTestArgumentSplitting15 = verifyNot checkTestArgumentSplitting "[[ \"$*\" == \"\" ]]" +prop_checkTestArgumentSplitting16 = verifyNot checkTestArgumentSplitting "[[ -v foo[123] ]]" checkTestArgumentSplitting :: Parameters -> Token -> Writer [TokenComment] () checkTestArgumentSplitting _ t = case t of - (TC_Unary _ _ op token) | isGlob token -> - err (getId token) 2144 $ - op ++ " doesn't work with globs. Use a for loop." + (TC_Unary _ typ op token) | isGlob token -> + if op == "-v" + then + when (typ == SingleBracket) $ + err (getId token) 2208 $ + "Use [[ ]] or quote arguments to -v to avoid glob expansion." + else + err (getId token) 2144 $ + op ++ " doesn't work with globs. Use a for loop." (TC_Nullary _ typ token) -> do checkBraces typ token diff --git a/ShellCheck/AnalyzerLib.hs b/ShellCheck/AnalyzerLib.hs index d73d3da..dc7a02c 100644 --- a/ShellCheck/AnalyzerLib.hs +++ b/ShellCheck/AnalyzerLib.hs @@ -94,7 +94,12 @@ data StackData = data DataType = DataString DataSource | DataArray DataSource deriving (Show) -data DataSource = SourceFrom [Token] | SourceExternal | SourceDeclaration | SourceInteger +data DataSource = + SourceFrom [Token] + | SourceExternal + | SourceDeclaration + | SourceInteger + | SourceChecked deriving (Show) data VariableState = Dead Token String | Alive deriving (Show) @@ -388,6 +393,18 @@ getModifiedVariables t = name <- getLiteralString lhs return (t, t, name, DataString $ SourceFrom [rhs]) + -- Count [[ -v foo ]] as an "assignment". + -- This is to prevent [ -v foo ] being unassigned or unused. + TC_Unary id _ "-v" token -> maybeToList $ do + str <- fmap (takeWhile (/= '[')) $ -- Quoted index + flip getLiteralStringExt token $ \x -> + case x of + T_Glob _ s -> return s -- Unquoted index + _ -> Nothing + + guard . not . null $ str + return (t, token, str, DataString $ SourceChecked) + T_DollarBraced _ l -> maybeToList $ do let string = bracedString t let modifier = getBracedModifier string @@ -584,8 +601,10 @@ getReferencedVariables parents t = getVariablesFromLiteralToken word else [] - literalizer TA_Index {} = return "" -- x[0] becomes a reference of x - literalizer _ = Nothing + literalizer t = case t of + TA_Index {} -> return "" -- x[0] becomes a reference of x + T_Glob _ s -> return s -- Also when parsed as globs + _ -> Nothing getIfReference context token = maybeToList $ do str <- getLiteralStringExt literalizer token