chainlint: recognize multi-line quoted strings more robustly

chainlint.sed recognizes multi-line quoted strings within subshells:

    echo "abc
        def" >out &&

so it can avoid incorrectly classifying lines internal to the string as
breaking the &&-chain. To identify the first line of a multi-line
string, it checks if the line contains a single quote. However, this is
fragile and can be easily fooled by a line containing multiple strings:

    echo "xyz" "abc
        def" >out &&

Make detection more robust by checking for an odd number of quotes
rather than only a single one.

(Escaped quotes are not handled, but support may be added later.)

The original multi-line string recognizer rather cavalierly threw away
all but the final quote, whereas the new one is careful to retain all
quotes, so the "expected" output of a couple existing chainlint tests is
updated to account for this new behavior.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Eric Sunshine 2018-08-13 04:47:38 -04:00 committed by Junio C Hamano
parent d93871143f
commit 22e3e0241a
4 changed files with 43 additions and 13 deletions

View file

@ -151,10 +151,10 @@ s/.*\n//
:slurp
# incomplete line "...\"
/\\$/bincomplete
# multi-line quoted string "...\n..."
/^[^"]*"[^"]*$/bdqstring
# multi-line quoted string '...\n...' (but not contraction in string "it's so")
/^[^']*'[^']*$/{
# multi-line quoted string "...\n..."?
/"/bdqstring
# multi-line quoted string '...\n...'? (but not contraction in string "it's")
/'/{
/"[^'"]*'[^'"]*"/!bsqstring
}
:folded
@ -250,20 +250,32 @@ N
s/\\\n//
bslurp
# found multi-line double-quoted string "...\n..." -- slurp until end of string
# check for multi-line double-quoted string "...\n..." -- fold to one line
:dqstring
s/"//g
# remove all quote pairs
s/"\([^"]*\)"/@!\1@!/g
# done if no dangling quote
/"/!bdqdone
# otherwise, slurp next line and try again
N
s/\n//
/"/!bdqstring
bdqstring
:dqdone
s/@!/"/g
bfolded
# found multi-line single-quoted string '...\n...' -- slurp until end of string
# check for multi-line single-quoted string '...\n...' -- fold to one line
:sqstring
s/'//g
# remove all quote pairs
s/'\([^']*\)'/@!\1@!/g
# done if no dangling quote
/'/!bsqdone
# otherwise, slurp next line and try again
N
s/\n//
/'/!bsqstring
bsqstring
:sqdone
s/@!/'/g
bfolded
# found here-doc -- swallow it to avoid false hits within its body (but keep

View file

@ -1,4 +1,4 @@
(
?!AMP?! cat && echo multi-line string"
?!AMP?! cat && echo "multi-line string"
bap
>)

View file

@ -1,9 +1,15 @@
(
x=line 1 line 2 line 3" &&
?!AMP?! y=line 1 line2'
x="line 1 line 2 line 3" &&
?!AMP?! y='line 1 line2'
foobar
>) &&
(
echo "there's nothing to see here" &&
exit
>) &&
(
echo "xyz" "abc def ghi" &&
echo 'xyz' 'abc def ghi' &&
echo 'xyz' "abc def ghi" &&
barfoo
>)

View file

@ -12,4 +12,16 @@
# LINT: starting multi-line single-quoted string
echo "there's nothing to see here" &&
exit
) &&
(
echo "xyz" "abc
def
ghi" &&
echo 'xyz' 'abc
def
ghi' &&
echo 'xyz' "abc
def
ghi" &&
barfoo
)