diff --git a/ShellCheck/Analytics.hs b/ShellCheck/Analytics.hs index 119a4e0..c6da563 100644 --- a/ShellCheck/Analytics.hs +++ b/ShellCheck/Analytics.hs @@ -1585,6 +1585,7 @@ prop_checkSpacefulness30= verifyTree checkSpacefulness "file='foo bar'; echo foo prop_checkSpacefulness31= verifyNotTree checkSpacefulness "echo \"`echo \\\"$1\\\"`\"" prop_checkSpacefulness32= verifyNotTree checkSpacefulness "var=$1; [ -v var ]" prop_checkSpacefulness33= verifyTree checkSpacefulness "for file; do echo $file; done" +prop_checkSpacefulness34= verifyTree checkSpacefulness "declare foo$n=$1" checkSpacefulness params t = doVariableFlowAnalysis readF writeF (Map.fromList defaults) (variableFlow params) diff --git a/ShellCheck/AnalyzerLib.hs b/ShellCheck/AnalyzerLib.hs index ca357e2..38b8534 100644 --- a/ShellCheck/AnalyzerLib.hs +++ b/ShellCheck/AnalyzerLib.hs @@ -223,10 +223,7 @@ isQuoteFreeNode strict tree t = TA_Sequence {} -> return True T_Arithmetic {} -> return True T_Assignment {} -> return True - T_Redirecting {} -> return $ - if strict then False else - -- Not true, just a hack to prevent warning about non-expansion refs - any (isCommand t) ["local", "declare", "typeset", "export", "trap", "readonly"] + T_Redirecting {} -> return False T_DoubleQuoted _ _ -> return True T_DollarDoubleQuoted _ _ -> return True T_CaseExpression {} -> return True diff --git a/ShellCheck/Parser.hs b/ShellCheck/Parser.hs index eded0d8..3dea149 100644 --- a/ShellCheck/Parser.hs +++ b/ShellCheck/Parser.hs @@ -2328,7 +2328,7 @@ readCompoundListOrEmpty = do readCmdPrefix = many1 (readIoRedirect <|> readAssignmentWord) readCmdSuffix = many1 (readIoRedirect <|> readCmdWord) -readModifierSuffix = many1 (readIoRedirect <|> readAssignmentWord <|> readCmdWord) +readModifierSuffix = many1 (readIoRedirect <|> readWellFormedAssignment <|> readCmdWord) readTimeSuffix = do flags <- many readFlag pipeline <- readPipeline @@ -2394,12 +2394,16 @@ prop_readAssignmentWord9c= isOk readAssignmentWord "foo= #bar" prop_readAssignmentWord10= isWarning readAssignmentWord "foo$n=42" prop_readAssignmentWord11= isOk readAssignmentWord "foo=([a]=b [c] [d]= [e f )" prop_readAssignmentWord12= isOk readAssignmentWord "a[b <<= 3 + c]='thing'" -readAssignmentWord = try $ do +readAssignmentWord = readAssignmentWordExt True +readWellFormedAssignment = readAssignmentWordExt False +readAssignmentWordExt lenient = try $ do id <- getNextId pos <- getPosition - optional (char '$' >> parseNote ErrorC 1066 "Don't use $ on the left side of assignments.") + when lenient $ + optional (char '$' >> parseNote ErrorC 1066 "Don't use $ on the left side of assignments.") variable <- readVariableName - optional (readNormalDollar >> parseNoteAt pos ErrorC + when lenient $ + optional (readNormalDollar >> parseNoteAt pos ErrorC 1067 "For indirection, use (associative) arrays or 'read \"var$n\" <<< \"value\"'") indices <- many readArrayIndex hasLeftSpace <- liftM (not . null) spacing