From 1a5296659b304575fb71c54c33b5eb14fcb9c3f9 Mon Sep 17 00:00:00 2001
From: Vidar Holen <spam@vidarholen.net>
Date: Sun, 1 Nov 2015 12:30:33 -0800
Subject: [PATCH] Properly handle escaped double quotes in quoted backtick
 expressions.

---
 ShellCheck/Analytics.hs |  1 +
 ShellCheck/Parser.hs    | 22 +++++++++++++---------
 2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/ShellCheck/Analytics.hs b/ShellCheck/Analytics.hs
index be9ce25..95ae6ac 100644
--- a/ShellCheck/Analytics.hs
+++ b/ShellCheck/Analytics.hs
@@ -2565,6 +2565,7 @@ prop_checkSpacefulness27= verifyNotTree checkSpacefulness "echo ${a:+'foo'}"
 prop_checkSpacefulness28= verifyNotTree checkSpacefulness "exec {n}>&1; echo $n"
 prop_checkSpacefulness29= verifyNotTree checkSpacefulness "n=$(stuff); exec {n}>&-;"
 prop_checkSpacefulness30= verifyTree checkSpacefulness "file='foo bar'; echo foo > $file;"
+prop_checkSpacefulness31= verifyNotTree checkSpacefulness "echo \"`echo \\\"$1\\\"`\""
 
 checkSpacefulness params t =
     doVariableFlowAnalysis readF writeF (Map.fromList defaults) (variableFlow params)
diff --git a/ShellCheck/Parser.hs b/ShellCheck/Parser.hs
index 34c8c40..8c499ce 100644
--- a/ShellCheck/Parser.hs
+++ b/ShellCheck/Parser.hs
@@ -623,7 +623,7 @@ readArithmeticContents =
             readDoubleQuoted,
             readNormalDollar,
             readBraced,
-            readBackTicked,
+            readUnquotedBackTicked,
             readNormalLiteral "+-*/=%^,]?:"
             ]
         spacing
@@ -833,7 +833,7 @@ readNormalWordPart end = do
         readGlob,
         readNormalDollar,
         readBraced,
-        readBackTicked,
+        readUnquotedBackTicked,
         readProcSub,
         readNormalLiteral end,
         readLiteralCurlyBraces
@@ -869,7 +869,7 @@ readDollarBracedWord = do
     list <- many readDollarBracedPart
     return $ T_NormalWord id list
 
-readDollarBracedPart = readSingleQuoted <|> readDoubleQuoted <|> readExtglob <|> readNormalDollar <|> readBackTicked <|> readDollarBracedLiteral
+readDollarBracedPart = readSingleQuoted <|> readDoubleQuoted <|> readExtglob <|> readNormalDollar <|> readUnquotedBackTicked <|> readDollarBracedLiteral
 
 readDollarBracedLiteral = do
     id <- getNextId
@@ -927,15 +927,18 @@ readSingleQuotedPart =
     readSingleEscaped
     <|> many1 (noneOf "'\\\x2018\x2019")
 
-prop_readBackTicked = isOk readBackTicked "`ls *.mp3`"
-prop_readBackTicked2 = isOk readBackTicked "`grep \"\\\"\"`"
-prop_readBackTicked3 = isWarning readBackTicked "´grep \"\\\"\"´"
-prop_readBackTicked4 = isOk readBackTicked "`echo foo\necho bar`"
+
+prop_readBackTicked = isOk (readBackTicked False) "`ls *.mp3`"
+prop_readBackTicked2 = isOk (readBackTicked False) "`grep \"\\\"\"`"
+prop_readBackTicked3 = isWarning (readBackTicked False) "´grep \"\\\"\"´"
+prop_readBackTicked4 = isOk readSimpleCommand "`echo foo\necho bar`"
 prop_readBackTicked5 = isOk readSimpleCommand "echo `foo`bar"
 prop_readBackTicked6 = isWarning readSimpleCommand "echo `foo\necho `bar"
 prop_readBackTicked7 = isOk readSimpleCommand "`#inline comment`"
 prop_readBackTicked8 = isOk readSimpleCommand "echo `#comment` \\\nbar baz"
-readBackTicked = called "backtick expansion" $ do
+readQuotedBackTicked = readBackTicked True
+readUnquotedBackTicked = readBackTicked False
+readBackTicked quoted = called "backtick expansion" $ do
     id <- getNextId
     startPos <- getPosition
     backtick
@@ -954,6 +957,7 @@ readBackTicked = called "backtick expansion" $ do
     return $ T_Backticked id result
   where
     unEscape [] = []
+    unEscape ('\\':'"':rest) | quoted = '"' : unEscape rest
     unEscape ('\\':x:rest) | x `elem` "$`\\" = x : unEscape rest
     unEscape ('\\':'\n':rest) = unEscape rest
     unEscape (c:rest) = c : unEscape rest
@@ -1021,7 +1025,7 @@ suggestForgotClosingQuote startPos endPos name = do
     parseProblemAt endPos InfoC 1079
         "This is actually an end quote, but due to next char it looks suspect."
 
-doubleQuotedPart = readDoubleLiteral <|> readDoubleQuotedDollar <|> readBackTicked
+doubleQuotedPart = readDoubleLiteral <|> readDoubleQuotedDollar <|> readQuotedBackTicked
 
 readDoubleQuotedLiteral = do
     doubleQuote