summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2021-12-22 22:48:11 -0800
committerJunio C Hamano <gitster@pobox.com>2021-12-22 22:48:11 -0800
commitd52da628013ad333e056432057da8b61042c6cfc (patch)
tree3697116d393edc66304d0e3bf7e73b0262e9d960
parent62a3a27b915c5f2a70796af15678cce1079d200a (diff)
parentd73f5cfa89ae9fcc76b1b1528f4daf944ce2a931 (diff)
Merge branch 'es/chainlint'
The chainlint test script linter in the test suite has been updated. * es/chainlint: chainlint.sed: stop splitting "(..." into separate lines "(" and "..." chainlint.sed: swallow comments consistently chainlint.sed: stop throwing away here-doc tags chainlint.sed: don't mistake `<< word` in string as here-doc operator chainlint.sed: make here-doc "<<-" operator recognition more POSIX-like chainlint.sed: drop subshell-closing ">" annotation chainlint.sed: drop unnecessary distinction between ?!AMP?! and ?!SEMI?! chainlint.sed: tolerate harmless ";" at end of last line in block chainlint.sed: improve ?!SEMI?! placement accuracy chainlint.sed: improve ?!AMP?! placement accuracy t/Makefile: optimize chainlint self-test t/chainlint/one-liner: avoid overly intimate chainlint.sed knowledge t/chainlint/*.test: generalize self-test commentary t/chainlint/*.test: fix invalid test cases due to mixing quote types t/chainlint/*.test: don't use invalid shell syntax
-rw-r--r--t/Makefile10
-rw-r--r--t/chainlint.sed124
-rw-r--r--t/chainlint/arithmetic-expansion.expect6
-rw-r--r--t/chainlint/bash-array.expect4
-rw-r--r--t/chainlint/blank-line.expect2
-rw-r--r--t/chainlint/blank-line.test2
-rw-r--r--t/chainlint/block-comment.expect6
-rw-r--r--t/chainlint/block-comment.test8
-rw-r--r--t/chainlint/block.expect4
-rw-r--r--t/chainlint/block.test3
-rw-r--r--t/chainlint/broken-chain.expect4
-rw-r--r--t/chainlint/broken-chain.test2
-rw-r--r--t/chainlint/case-comment.expect8
-rw-r--r--t/chainlint/case-comment.test11
-rw-r--r--t/chainlint/case.expect10
-rw-r--r--t/chainlint/case.test6
-rw-r--r--t/chainlint/close-nested-and-parent-together.expect5
-rw-r--r--t/chainlint/close-subshell.expect16
-rw-r--r--t/chainlint/command-substitution.expect6
-rw-r--r--t/chainlint/comment.expect2
-rw-r--r--t/chainlint/complex-if-in-cuddled-loop.expect5
-rw-r--r--t/chainlint/complex-if-in-cuddled-loop.test2
-rw-r--r--t/chainlint/cuddled-if-then-else.expect5
-rw-r--r--t/chainlint/cuddled-if-then-else.test2
-rw-r--r--t/chainlint/cuddled-loop.expect5
-rw-r--r--t/chainlint/cuddled-loop.test2
-rw-r--r--t/chainlint/cuddled.expect22
-rw-r--r--t/chainlint/cuddled.test3
-rw-r--r--t/chainlint/exit-loop.expect6
-rw-r--r--t/chainlint/exit-subshell.expect2
-rw-r--r--t/chainlint/for-loop.expect8
-rw-r--r--t/chainlint/for-loop.test8
-rw-r--r--t/chainlint/here-doc-close-subshell.expect2
-rw-r--r--t/chainlint/here-doc-multi-line-command-subst.expect6
-rw-r--r--t/chainlint/here-doc-multi-line-string.expect4
-rw-r--r--t/chainlint/here-doc.expect10
-rw-r--r--t/chainlint/here-doc.test7
-rw-r--r--t/chainlint/if-in-loop.expect8
-rw-r--r--t/chainlint/if-in-loop.test6
-rw-r--r--t/chainlint/if-then-else.expect15
-rw-r--r--t/chainlint/if-then-else.test17
-rw-r--r--t/chainlint/incomplete-line.expect2
-rw-r--r--t/chainlint/inline-comment.expect9
-rw-r--r--t/chainlint/loop-in-if.expect8
-rw-r--r--t/chainlint/loop-in-if.test6
-rw-r--r--t/chainlint/multi-line-nested-command-substitution.expect10
-rw-r--r--t/chainlint/multi-line-string.expect12
-rw-r--r--t/chainlint/multi-line-string.test16
-rw-r--r--t/chainlint/negated-one-liner.expect4
-rw-r--r--t/chainlint/nested-cuddled-subshell.expect14
-rw-r--r--t/chainlint/nested-here-doc.expect8
-rw-r--r--t/chainlint/nested-subshell-comment.expect6
-rw-r--r--t/chainlint/nested-subshell-comment.test2
-rw-r--r--t/chainlint/nested-subshell.expect6
-rw-r--r--t/chainlint/nested-subshell.test1
-rw-r--r--t/chainlint/not-heredoc.expect14
-rw-r--r--t/chainlint/not-heredoc.test16
-rw-r--r--t/chainlint/one-liner.expect6
-rw-r--r--t/chainlint/one-liner.test4
-rw-r--r--t/chainlint/p4-filespec.expect2
-rw-r--r--t/chainlint/pipe.expect4
-rw-r--r--t/chainlint/pipe.test2
-rw-r--r--t/chainlint/semicolon.expect27
-rw-r--r--t/chainlint/semicolon.test4
-rw-r--r--t/chainlint/subshell-here-doc.expect15
-rw-r--r--t/chainlint/subshell-here-doc.test8
-rw-r--r--t/chainlint/subshell-one-liner.expect12
-rw-r--r--t/chainlint/t7900-subtree.expect10
-rw-r--r--t/chainlint/t7900-subtree.test4
-rw-r--r--t/chainlint/while-loop.expect8
-rw-r--r--t/chainlint/while-loop.test8
71 files changed, 339 insertions, 293 deletions
diff --git a/t/Makefile b/t/Makefile
index 882d26eee3..46cd5fc527 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -71,12 +71,10 @@ clean-chainlint:
check-chainlint:
@mkdir -p '$(CHAINLINTTMP_SQ)' && \
- err=0 && \
- for i in $(CHAINLINTTESTS); do \
- $(CHAINLINT) <chainlint/$$i.test | \
- sed -e '/^# LINT: /d' >'$(CHAINLINTTMP_SQ)'/$$i.actual && \
- diff -u chainlint/$$i.expect '$(CHAINLINTTMP_SQ)'/$$i.actual || err=1; \
- done && exit $$err
+ sed -e '/^# LINT: /d' $(patsubst %,chainlint/%.test,$(CHAINLINTTESTS)) >'$(CHAINLINTTMP_SQ)'/tests && \
+ sed -e '/^[ ]*$$/d' $(patsubst %,chainlint/%.expect,$(CHAINLINTTESTS)) >'$(CHAINLINTTMP_SQ)'/expect && \
+ $(CHAINLINT) '$(CHAINLINTTMP_SQ)'/tests | grep -v '^[ ]*$$' >'$(CHAINLINTTMP_SQ)'/actual && \
+ diff -u '$(CHAINLINTTMP_SQ)'/expect '$(CHAINLINTTMP_SQ)'/actual
test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \
test-lint-filenames
diff --git a/t/chainlint.sed b/t/chainlint.sed
index 8a25c5b855..dc4ce37cb5 100644
--- a/t/chainlint.sed
+++ b/t/chainlint.sed
@@ -24,9 +24,9 @@
# in order to avoid misinterpreting the ")" in constructs such as "x=$(...)"
# and "case $x in *)" as ending the subshell.
#
-# Lines missing a final "&&" are flagged with "?!AMP?!", and lines which chain
-# commands with ";" internally rather than "&&" are flagged "?!SEMI?!". A line
-# may be flagged for both violations.
+# Lines missing a final "&&" are flagged with "?!AMP?!", as are lines which
+# chain commands with ";" internally rather than "&&". A line may be flagged
+# for both violations.
#
# Detection of a missing &&-link in a multi-line subshell is complicated by the
# fact that the last statement before the closing ")" must not end with "&&".
@@ -47,8 +47,8 @@
# "?!AMP?!" violation is removed from the "bar" line (retrieved from the "hold"
# area) since the final statement of a subshell must not end with "&&". The
# final line of a subshell may still break the &&-chain by using ";" internally
-# to chain commands together rather than "&&", so "?!SEMI?!" is never removed
-# from a line (even though "?!AMP?!" might be).
+# to chain commands together rather than "&&", but an internal "?!AMP?!" is
+# never removed from a line even though a line-ending "?!AMP?!" might be.
#
# Care is taken to recognize the last _statement_ of a multi-line subshell, not
# necessarily the last textual _line_ within the subshell, since &&-chaining
@@ -62,26 +62,20 @@
# receives similar treatment.
#
# Swallowing here-docs with arbitrary tags requires a bit of finesse. When a
-# line such as "cat <<EOF >out" is seen, the here-doc tag is moved to the front
-# of the line enclosed in angle brackets as a sentinel, giving "<EOF>cat >out".
+# line such as "cat <<EOF" is seen, the here-doc tag is copied to the front of
+# the line enclosed in angle brackets as a sentinel, giving "<EOF>cat <<EOF".
# As each subsequent line is read, it is appended to the target line and a
# (whitespace-loose) back-reference match /^<(.*)>\n\1$/ is attempted to see if
# the content inside "<...>" matches the entirety of the newly-read line. For
# instance, if the next line read is "some data", when concatenated with the
-# target line, it becomes "<EOF>cat >out\nsome data", and a match is attempted
+# target line, it becomes "<EOF>cat <<EOF\nsome data", and a match is attempted
# to see if "EOF" matches "some data". Since it doesn't, the next line is
# attempted. When a line consisting of only "EOF" (and possible whitespace) is
-# encountered, it is appended to the target line giving "<EOF>cat >out\nEOF",
+# encountered, it is appended to the target line giving "<EOF>cat <<EOF\nEOF",
# in which case the "EOF" inside "<...>" does match the text following the
# newline, thus the closing here-doc tag has been found. The closing tag line
# and the "<...>" prefix on the target line are then discarded, leaving just
-# the target line "cat >out".
-#
-# To facilitate regression testing (and manual debugging), a ">" annotation is
-# applied to the line containing ")" which closes a subshell, ">>" to a line
-# closing a nested subshell, and ">>>" to a line closing both at once. This
-# makes it easy to detect whether the heuristics correctly identify
-# end-of-subshell.
+# the target line "cat <<EOF".
#------------------------------------------------------------------------------
# incomplete line -- slurp up next line
@@ -94,9 +88,9 @@
# here-doc -- swallow it to avoid false hits within its body (but keep the
# command to which it was attached)
-/<<[ ]*[-\\'"]*[A-Za-z0-9_]/ {
- s/^\(.*\)<<[ ]*[-\\'"]*\([A-Za-z0-9_][A-Za-z0-9_]*\)['"]*/<\2>\1<</
- s/[ ]*<<//
+/<<-*[ ]*[\\'"]*[A-Za-z0-9_]/ {
+ /"[^"]*<<[^"]*"/bnotdoc
+ s/^\(.*<<-*[ ]*\)[\\'"]*\([A-Za-z0-9_][A-Za-z0-9_]*\)['"]*/<\2>\1\2/
:hered
N
/^<\([^>]*\)>.*\n[ ]*\1[ ]*$/!{
@@ -106,6 +100,7 @@
s/^<[^>]*>//
s/\n.*$//
}
+:notdoc
# one-liner "(...) &&"
/^[ ]*!*[ ]*(..*)[ ]*&&[ ]*$/boneline
@@ -126,7 +121,7 @@ b
# "&&" (but not ";" in a string)
:oneline
/;/{
- /"[^"]*;[^"]*"/!s/^/?!SEMI?!/
+ /"[^"]*;[^"]*"/!s/;/; ?!AMP?!/
}
b
@@ -136,11 +131,15 @@ b
h
bnextln
}
-# "(..." line -- split off and stash "(", then process "..." as its own line
+# "(..." line -- "(" opening subshell cuddled with command; temporarily replace
+# "(" with sentinel "^" and process the line as if "(" had been seen solo on
+# the preceding line; this temporary replacement prevents several rules from
+# accidentally thinking "(" introduces a nested subshell; "^" is changed back
+# to "(" at output time
x
-s/.*/(/
+s/.*//
x
-s/(//
+s/(/^/
bslurp
:nextln
@@ -157,8 +156,10 @@ s/.*\n//
/"[^'"]*'[^'"]*"/!bsqstr
}
:folded
-# here-doc -- swallow it
-/<<[ ]*[-\\'"]*[A-Za-z0-9_]/bheredoc
+# here-doc -- swallow it (but not "<<" in a string)
+/<<-*[ ]*[\\'"]*[A-Za-z0-9_]/{
+ /"[^"]*<<[^"]*"/!bheredoc
+}
# comment or empty line -- discard since final non-comment, non-empty line
# before closing ")", "done", "elsif", "else", or "fi" will need to be
# re-visited to drop "suspect" marking since final line of those constructs
@@ -171,12 +172,12 @@ s/.*\n//
/"[^"]*#[^"]*"/!s/[ ]#.*$//
}
# one-liner "case ... esac"
-/^[ ]*case[ ]*..*esac/bchkchn
+/^[ ^]*case[ ]*..*esac/bchkchn
# multi-line "case ... esac"
-/^[ ]*case[ ]..*[ ]in/bcase
+/^[ ^]*case[ ]..*[ ]in/bcase
# multi-line "for ... done" or "while ... done"
-/^[ ]*for[ ]..*[ ]in/bcont
-/^[ ]*while[ ]/bcont
+/^[ ^]*for[ ]..*[ ]in/bcont
+/^[ ^]*while[ ]/bcont
/^[ ]*do[ ]/bcont
/^[ ]*do[ ]*$/bcont
/;[ ]*do/bcont
@@ -187,7 +188,7 @@ s/.*\n//
/||[ ]*exit[ ]/bcont
/||[ ]*exit[ ]*$/bcont
# multi-line "if...elsif...else...fi"
-/^[ ]*if[ ]/bcont
+/^[ ^]*if[ ]/bcont
/^[ ]*then[ ]/bcont
/^[ ]*then[ ]*$/bcont
/;[ ]*then/bcont
@@ -200,15 +201,15 @@ s/.*\n//
/^[ ]*fi[ ]*[<>|]/bdone
/^[ ]*fi[ ]*)/bdone
# nested one-liner "(...) &&"
-/^[ ]*(.*)[ ]*&&[ ]*$/bchkchn
+/^[ ^]*(.*)[ ]*&&[ ]*$/bchkchn
# nested one-liner "(...)"
-/^[ ]*(.*)[ ]*$/bchkchn
+/^[ ^]*(.*)[ ]*$/bchkchn
# nested one-liner "(...) >x" (or "2>x" or "<x" or "|x")
-/^[ ]*(.*)[ ]*[0-9]*[<>|]/bchkchn
+/^[ ^]*(.*)[ ]*[0-9]*[<>|]/bchkchn
# nested multi-line "(...\n...)"
-/^[ ]*(/bnest
+/^[ ^]*(/bnest
# multi-line "{...\n...}"
-/^[ ]*{/bblock
+/^[ ^]*{/bblock
# closing ")" on own line -- exit subshell
/^[ ]*)/bclssolo
# "$((...))" -- arithmetic expansion; not closing ")"
@@ -230,16 +231,18 @@ s/.*\n//
# string and not ";;" in one-liner "case...esac")
/;/{
/;;/!{
- /"[^"]*;[^"]*"/!s/^/?!SEMI?!/
+ /"[^"]*;[^"]*"/!s/;/; ?!AMP?!/
}
}
# line ends with pipe "...|" -- valid; not missing "&&"
/|[ ]*$/bcont
# missing end-of-line "&&" -- mark suspect
-/&&[ ]*$/!s/^/?!AMP?!/
+/&&[ ]*$/!s/$/ ?!AMP?!/
:cont
# retrieve and print previous line
x
+s/^\([ ]*\)^/\1(/
+s/?!HERE?!/<</g
n
bslurp
@@ -280,8 +283,7 @@ bfolded
# found here-doc -- swallow it to avoid false hits within its body (but keep
# the command to which it was attached)
:heredoc
-s/^\(.*\)<<[ ]*[-\\'"]*\([A-Za-z0-9_][A-Za-z0-9_]*\)['"]*/<\2>\1<</
-s/[ ]*<<//
+s/^\(.*\)<<\(-*[ ]*\)[\\'"]*\([A-Za-z0-9_][A-Za-z0-9_]*\)['"]*/<\3>\1?!HERE?!\2\3/
:hdocsub
N
/^<\([^>]*\)>.*\n[ ]*\1[ ]*$/!{
@@ -295,7 +297,15 @@ bfolded
# found "case ... in" -- pass through untouched
:case
x
+s/^\([ ]*\)^/\1(/
+s/?!HERE?!/<</g
n
+:cascom
+/^[ ]*#/{
+ N
+ s/.*\n//
+ bcascom
+}
/^[ ]*esac/bslurp
bcase
@@ -303,7 +313,7 @@ bcase
# that line legitimately lacks "&&"
:else
x
-s/?!AMP?!//
+s/\( ?!AMP?!\)* ?!AMP?!$//
x
bcont
@@ -311,7 +321,7 @@ bcont
# "suspect" from final contained line since that line legitimately lacks "&&"
:done
x
-s/?!AMP?!//
+s/\( ?!AMP?!\)* ?!AMP?!$//
x
# is 'done' or 'fi' cuddled with ")" to close subshell?
/done.*)/bclose
@@ -322,11 +332,18 @@ bchkchn
:nest
x
:nstslrp
+s/^\([ ]*\)^/\1(/
+s/?!HERE?!/<</g
n
+:nstcom
+# comment -- not closing ")" if in comment
+/^[ ]*#/{
+ N
+ s/.*\n//
+ bnstcom
+}
# closing ")" on own line -- stop nested slurp
/^[ ]*)/bnstcl
-# comment -- not closing ")" if in comment
-/^[ ]*#/bnstcnt
# "$((...))" -- arithmetic expansion; not closing ")"
/\$(([^)][^)]*))[^)]*$/bnstcnt
# "$(...)" -- command substitution; not closing ")"
@@ -337,7 +354,6 @@ n
x
bnstslrp
:nstcl
-s/^/>>/
# is it "))" which closes nested and parent subshells?
/)[ ]*)/bslurp
bchkchn
@@ -345,7 +361,15 @@ bchkchn
# found multi-line "{...\n...}" block -- pass through untouched
:block
x
+s/^\([ ]*\)^/\1(/
+s/?!HERE?!/<</g
n
+:blkcom
+/^[ ]*#/{
+ N
+ s/.*\n//
+ bblkcom
+}
# closing "}" -- stop block slurp
/}/bchkchn
bblock
@@ -354,16 +378,22 @@ bblock
# since that line legitimately lacks "&&" and exit subshell loop
:clssolo
x
-s/?!AMP?!//
+s/\( ?!AMP?!\)* ?!AMP?!$//
+s/^\([ ]*\)^/\1(/
+s/?!HERE?!/<</g
p
x
-s/^/>/
+s/^\([ ]*\)^/\1(/
+s/?!HERE?!/<</g
b
# found closing "...)" -- exit subshell loop
:close
x
+s/^\([ ]*\)^/\1(/
+s/?!HERE?!/<</g
p
x
-s/^/>/
+s/^\([ ]*\)^/\1(/
+s/?!HERE?!/<</g
b
diff --git a/t/chainlint/arithmetic-expansion.expect b/t/chainlint/arithmetic-expansion.expect
index 09457d3196..46ee1046af 100644
--- a/t/chainlint/arithmetic-expansion.expect
+++ b/t/chainlint/arithmetic-expansion.expect
@@ -2,8 +2,8 @@
foo &&
bar=$((42 + 1)) &&
baz
->) &&
+) &&
(
-?!AMP?! bar=$((42 + 1))
+ bar=$((42 + 1)) ?!AMP?!
baz
->)
+)
diff --git a/t/chainlint/bash-array.expect b/t/chainlint/bash-array.expect
index c4a830d1c1..4c34eaee45 100644
--- a/t/chainlint/bash-array.expect
+++ b/t/chainlint/bash-array.expect
@@ -2,9 +2,9 @@
foo &&
bar=(gumbo stumbo wumbo) &&
baz
->) &&
+) &&
(
foo &&
bar=${#bar[@]} &&
baz
->)
+)
diff --git a/t/chainlint/blank-line.expect b/t/chainlint/blank-line.expect
index 3be939ed38..f76fde1ffb 100644
--- a/t/chainlint/blank-line.expect
+++ b/t/chainlint/blank-line.expect
@@ -1,4 +1,4 @@
(
nothing &&
something
->)
+)
diff --git a/t/chainlint/blank-line.test b/t/chainlint/blank-line.test
index f6dd14302b..0fdf15b3e1 100644
--- a/t/chainlint/blank-line.test
+++ b/t/chainlint/blank-line.test
@@ -3,7 +3,7 @@
nothing &&
something
-# LINT: swallow blank lines since final _statement_ before subshell end is
+# LINT: ignore blank lines since final _statement_ before subshell end is
# LINT: significant to "&&"-check, not final _line_ (which might be blank)
diff --git a/t/chainlint/block-comment.expect b/t/chainlint/block-comment.expect
new file mode 100644
index 0000000000..d10b2eeaf2
--- /dev/null
+++ b/t/chainlint/block-comment.expect
@@ -0,0 +1,6 @@
+(
+ {
+ echo a &&
+ echo b
+ }
+)
diff --git a/t/chainlint/block-comment.test b/t/chainlint/block-comment.test
new file mode 100644
index 0000000000..df2beea888
--- /dev/null
+++ b/t/chainlint/block-comment.test
@@ -0,0 +1,8 @@
+(
+ {
+ # show a
+ echo a &&
+ # show b
+ echo b
+ }
+)
diff --git a/t/chainlint/block.expect b/t/chainlint/block.expect
index fed7e89ae8..da60257ebc 100644
--- a/t/chainlint/block.expect
+++ b/t/chainlint/block.expect
@@ -7,6 +7,6 @@
bar &&
{
echo c
-?!AMP?! }
+ } ?!AMP?!
baz
->)
+)
diff --git a/t/chainlint/block.test b/t/chainlint/block.test
index d859151af1..0a82fd579f 100644
--- a/t/chainlint/block.test
+++ b/t/chainlint/block.test
@@ -1,6 +1,5 @@
(
-# LINT: missing "&&" in block not currently detected (for consistency with
-# LINT: --chain-lint at top level and to provide escape hatch if needed)
+# LINT: missing "&&" after first "echo"
foo &&
{
echo a
diff --git a/t/chainlint/broken-chain.expect b/t/chainlint/broken-chain.expect
index 55b0f42a53..cfb58fb6b9 100644
--- a/t/chainlint/broken-chain.expect
+++ b/t/chainlint/broken-chain.expect
@@ -1,6 +1,6 @@
(
foo &&
-?!AMP?! bar
+ bar ?!AMP?!
baz &&
wop
->)
+)
diff --git a/t/chainlint/broken-chain.test b/t/chainlint/broken-chain.test
index 3cc67b65d0..2a44aa73b7 100644
--- a/t/chainlint/broken-chain.test
+++ b/t/chainlint/broken-chain.test
@@ -1,6 +1,6 @@
(
foo &&
-# LINT: missing "&&" from 'bar'
+# LINT: missing "&&" from "bar"
bar
baz &&
# LINT: final statement before closing ")" legitimately lacks "&&"
diff --git a/t/chainlint/case-comment.expect b/t/chainlint/case-comment.expect
new file mode 100644
index 0000000000..1e4b054bda
--- /dev/null
+++ b/t/chainlint/case-comment.expect
@@ -0,0 +1,8 @@
+(
+ case "$x" in
+ x) foo ;;
+ *)
+ bar
+ ;;
+ esac
+)
diff --git a/t/chainlint/case-comment.test b/t/chainlint/case-comment.test
new file mode 100644
index 0000000000..641c157b98
--- /dev/null
+++ b/t/chainlint/case-comment.test
@@ -0,0 +1,11 @@
+(
+ case "$x" in
+ # found foo
+ x) foo ;;
+ # found other
+ *)
+ # treat it as bar
+ bar
+ ;;
+ esac
+)
diff --git a/t/chainlint/case.expect b/t/chainlint/case.expect
index 41f121fbbf..31f280d8ce 100644
--- a/t/chainlint/case.expect
+++ b/t/chainlint/case.expect
@@ -4,16 +4,16 @@
*) bar ;;
esac &&
foobar
->) &&
+) &&
(
case "$x" in
x) foo ;;
*) bar ;;
-?!AMP?! esac
+ esac ?!AMP?!
foobar
->) &&
+) &&
(
case "$x" in 1) true;; esac &&
-?!AMP?! case "$y" in 2) false;; esac
+ case "$y" in 2) false;; esac ?!AMP?!
foobar
->)
+)
diff --git a/t/chainlint/case.test b/t/chainlint/case.test
index 5ef6ff7db5..4cb086bf87 100644
--- a/t/chainlint/case.test
+++ b/t/chainlint/case.test
@@ -1,5 +1,5 @@
(
-# LINT: "...)" arms in 'case' not misinterpreted as subshell-closing ")"
+# LINT: "...)" arms in "case" not misinterpreted as subshell-closing ")"
case "$x" in
x) foo ;;
*) bar ;;
@@ -7,7 +7,7 @@
foobar
) &&
(
-# LINT: missing "&&" on 'esac'
+# LINT: missing "&&" on "esac"
case "$x" in
x) foo ;;
*) bar ;;
@@ -15,7 +15,7 @@
foobar
) &&
(
-# LINT: "...)" arm in one-liner 'case' not misinterpreted as closing ")"
+# LINT: "...)" arm in one-liner "case" not misinterpreted as closing ")"
case "$x" in 1) true;; esac &&
# LINT: same but missing "&&"
case "$y" in 2) false;; esac
diff --git a/t/chainlint/close-nested-and-parent-together.expect b/t/chainlint/close-nested-and-parent-together.expect
index 2a910f9d66..72d482f76d 100644
--- a/t/chainlint/close-nested-and-parent-together.expect
+++ b/t/chainlint/close-nested-and-parent-together.expect
@@ -1,4 +1,3 @@
-(
-cd foo &&
+(cd foo &&
(bar &&
->>> baz))
+ baz))
diff --git a/t/chainlint/close-subshell.expect b/t/chainlint/close-subshell.expect
index 184688718a..0f87db9ae6 100644
--- a/t/chainlint/close-subshell.expect
+++ b/t/chainlint/close-subshell.expect
@@ -1,25 +1,25 @@
(
foo
->) &&
+) &&
(
bar
->) >out &&
+) >out &&
(
baz
->) 2>err &&
+) 2>err &&
(
boo
->) <input &&
+) <input &&
(
bip
->) | wuzzle &&
+) | wuzzle &&
(
bop
->) | fazz fozz &&
+) | fazz fozz &&
(
bup
->) |
+) |
fuzzle &&
(
yop
->)
+)
diff --git a/t/chainlint/command-substitution.expect b/t/chainlint/command-substitution.expect
index ad4118e537..c72e4df9e7 100644
--- a/t/chainlint/command-substitution.expect
+++ b/t/chainlint/command-substitution.expect
@@ -2,8 +2,8 @@
foo &&
bar=$(gobble) &&
baz
->) &&
+) &&
(
-?!AMP?! bar=$(gobble blocks)
+ bar=$(gobble blocks) ?!AMP?!
baz
->)
+)
diff --git a/t/chainlint/comment.expect b/t/chainlint/comment.expect
index 3be939ed38..f76fde1ffb 100644
--- a/t/chainlint/comment.expect
+++ b/t/chainlint/comment.expect
@@ -1,4 +1,4 @@
(
nothing &&
something
->)
+)
diff --git a/t/chainlint/complex-if-in-cuddled-loop.expect b/t/chainlint/complex-if-in-cuddled-loop.expect
index 9674b88cf2..2fca183409 100644
--- a/t/chainlint/complex-if-in-cuddled-loop.expect
+++ b/t/chainlint/complex-if-in-cuddled-loop.expect
@@ -1,10 +1,9 @@
-(
-for i in a b c; do
+(for i in a b c; do
if test "$(echo $(waffle bat))" = "eleventeen" &&
test "$x" = "$y"; then
:
else
echo >file
fi
-> done) &&
+ done) &&
test ! -f file
diff --git a/t/chainlint/complex-if-in-cuddled-loop.test b/t/chainlint/complex-if-in-cuddled-loop.test
index 571bbd85cd..5efeda58b2 100644
--- a/t/chainlint/complex-if-in-cuddled-loop.test
+++ b/t/chainlint/complex-if-in-cuddled-loop.test
@@ -1,4 +1,4 @@
-# LINT: 'for' loop cuddled with "(" and ")" and nested 'if' with complex
+# LINT: "for" loop cuddled with "(" and ")" and nested "if" with complex
# LINT: multi-line condition; indented with spaces, not tabs
(for i in a b c; do
if test "$(echo $(waffle bat))" = "eleventeen" &&
diff --git a/t/chainlint/cuddled-if-then-else.expect b/t/chainlint/cuddled-if-then-else.expect
index ab2a026fbc..1d8ed58c49 100644
--- a/t/chainlint/cuddled-if-then-else.expect
+++ b/t/chainlint/cuddled-if-then-else.expect
@@ -1,7 +1,6 @@
-(
-if test -z ""; then
+(if test -z ""; then
echo empty
else
echo bizzy
-> fi) &&
+ fi) &&
echo foobar
diff --git a/t/chainlint/cuddled-if-then-else.test b/t/chainlint/cuddled-if-then-else.test
index eed774a9d6..7c53f4efe3 100644
--- a/t/chainlint/cuddled-if-then-else.test
+++ b/t/chainlint/cuddled-if-then-else.test
@@ -1,4 +1,4 @@
-# LINT: 'if' cuddled with "(" and ")"; indented with spaces, not tabs
+# LINT: "if" cuddled with "(" and ")"; indented with spaces, not tabs
(if test -z ""; then
echo empty
else
diff --git a/t/chainlint/cuddled-loop.expect b/t/chainlint/cuddled-loop.expect
index 8c0260d7f1..9cf260708e 100644
--- a/t/chainlint/cuddled-loop.expect
+++ b/t/chainlint/cuddled-loop.expect
@@ -1,5 +1,4 @@
-(
- while read x
+( while read x
do foobar bop || exit 1
-> done <file ) &&
+ done <file ) &&
outside subshell
diff --git a/t/chainlint/cuddled-loop.test b/t/chainlint/cuddled-loop.test
index a841d781f0..3c2a62f751 100644
--- a/t/chainlint/cuddled-loop.test
+++ b/t/chainlint/cuddled-loop.test
@@ -1,4 +1,4 @@
-# LINT: 'while' loop cuddled with "(" and ")", with embedded (allowed)
+# LINT: "while" loop cuddled with "(" and ")", with embedded (allowed)
# LINT: "|| exit {n}" to exit loop early, and using redirection "<" to feed
# LINT: loop; indented with spaces, not tabs
( while read x
diff --git a/t/chainlint/cuddled.expect b/t/chainlint/cuddled.expect
index b506d46221..c3e0be4047 100644
--- a/t/chainlint/cuddled.expect
+++ b/t/chainlint/cuddled.expect
@@ -1,21 +1,17 @@
-(
-cd foo &&
+(cd foo &&
bar
->) &&
+) &&
-(
-?!AMP?!cd foo
+(cd foo ?!AMP?!
bar
->) &&
+) &&
(
cd foo &&
-> bar) &&
+ bar) &&
-(
-cd foo &&
-> bar) &&
+(cd foo &&
+ bar) &&
-(
-?!AMP?!cd foo
-> bar)
+(cd foo ?!AMP?!
+ bar)
diff --git a/t/chainlint/cuddled.test b/t/chainlint/cuddled.test
index 0499fa4180..257b5b5eed 100644
--- a/t/chainlint/cuddled.test
+++ b/t/chainlint/cuddled.test
@@ -1,5 +1,4 @@
-# LINT: first subshell statement cuddled with opening "("; for implementation
-# LINT: simplicity, "(..." is split into two lines, "(" and "..."
+# LINT: first subshell statement cuddled with opening "("
(cd foo &&
bar
) &&
diff --git a/t/chainlint/exit-loop.expect b/t/chainlint/exit-loop.expect
index 84d8bdebc0..f76aa60466 100644
--- a/t/chainlint/exit-loop.expect
+++ b/t/chainlint/exit-loop.expect
@@ -5,7 +5,7 @@
bar &&
baz
done
->) &&
+) &&
(
while true
do
@@ -13,7 +13,7 @@
bar &&
baz
done
->) &&
+) &&
(
i=0 &&
while test $i -lt 10
@@ -21,4 +21,4 @@
echo $i || exit
i=$(($i + 1))
done
->)
+)
diff --git a/t/chainlint/exit-subshell.expect b/t/chainlint/exit-subshell.expect
index bf78454f74..da80339f78 100644
--- a/t/chainlint/exit-subshell.expect
+++ b/t/chainlint/exit-subshell.expect
@@ -2,4 +2,4 @@
foo || exit 1
bar &&
baz
->)
+)
diff --git a/t/chainlint/for-loop.expect b/t/chainlint/for-loop.expect
index c33cf56ee7..6671b8cd84 100644
--- a/t/chainlint/for-loop.expect
+++ b/t/chainlint/for-loop.expect
@@ -1,11 +1,11 @@
(
for i in a b c
do
-?!AMP?! echo $i
- cat
-?!AMP?! done
+ echo $i ?!AMP?!
+ cat <<-EOF
+ done ?!AMP?!
for i in a b c; do
echo $i &&
cat $i
done
->)
+)
diff --git a/t/chainlint/for-loop.test b/t/chainlint/for-loop.test
index 7db76262bc..6cb3428158 100644
--- a/t/chainlint/for-loop.test
+++ b/t/chainlint/for-loop.test
@@ -1,17 +1,17 @@
(
-# LINT: 'for', 'do', 'done' do not need "&&"
+# LINT: "for", "do", "done" do not need "&&"
for i in a b c
do
-# LINT: missing "&&" on 'echo'
+# LINT: missing "&&" on "echo"
echo $i
# LINT: last statement of while does not need "&&"
cat <<-\EOF
bar
EOF
-# LINT: missing "&&" on 'done'
+# LINT: missing "&&" on "done"
done
-# LINT: 'do' on same line as 'for'
+# LINT: "do" on same line as "for"
for i in a b c; do
echo $i &&
cat $i
diff --git a/t/chainlint/here-doc-close-subshell.expect b/t/chainlint/here-doc-close-subshell.expect
index f011e335e5..2af9ced71c 100644
--- a/t/chainlint/here-doc-close-subshell.expect
+++ b/t/chainlint/here-doc-close-subshell.expect
@@ -1,2 +1,2 @@
(
-> cat)
+ cat <<-INPUT)
diff --git a/t/chainlint/here-doc-multi-line-command-subst.expect b/t/chainlint/here-doc-multi-line-command-subst.expect
index e5fb752d2f..f8b3aa73c4 100644
--- a/t/chainlint/here-doc-multi-line-command-subst.expect
+++ b/t/chainlint/here-doc-multi-line-command-subst.expect
@@ -1,5 +1,5 @@
(
- x=$(bobble &&
-?!AMP?!>> wiffle)
+ x=$(bobble <<-END &&
+ wiffle) ?!AMP?!
echo $x
->)
+)
diff --git a/t/chainlint/here-doc-multi-line-string.expect b/t/chainlint/here-doc-multi-line-string.expect
index 32038a070c..2578191ca8 100644
--- a/t/chainlint/here-doc-multi-line-string.expect
+++ b/t/chainlint/here-doc-multi-line-string.expect
@@ -1,4 +1,4 @@
(
-?!AMP?! cat && echo "multi-line string"
+ cat <<-TXT && echo "multi-line string" ?!AMP?!
bap
->)
+)
diff --git a/t/chainlint/here-doc.expect b/t/chainlint/here-doc.expect
index 534b065e38..110059ba58 100644
--- a/t/chainlint/here-doc.expect
+++ b/t/chainlint/here-doc.expect
@@ -1,9 +1,7 @@
-boodle wobba gorgo snoot wafta snurb &&
+boodle wobba gorgo snoot wafta snurb <<EOF &&
-cat >foo &&
+cat <<-Arbitrary_Tag_42 >foo &&
-cat >bar &&
+cat <<zump >boo &&
-cat >boo &&
-
-horticulture
+horticulture <<EOF
diff --git a/t/chainlint/here-doc.test b/t/chainlint/here-doc.test
index ad4ce8afd9..3f5f92cad3 100644
--- a/t/chainlint/here-doc.test
+++ b/t/chainlint/here-doc.test
@@ -14,13 +14,6 @@ boz
woz
Arbitrary_Tag_42
-# LINT: swallow 'quoted' here-doc
-cat <<'FUMP' >bar &&
-snoz
-boz
-woz
-FUMP
-
# LINT: swallow "quoted" here-doc
cat <<"zump" >boo &&
snoz
diff --git a/t/chainlint/if-in-loop.expect b/t/chainlint/if-in-loop.expect
index 03d3ceb22d..03b82a3e58 100644
--- a/t/chainlint/if-in-loop.expect
+++ b/t/chainlint/if-in-loop.expect
@@ -3,10 +3,10 @@
do
if false
then
-?!AMP?! echo "err"
+ echo "err" ?!AMP?!
exit 1
-?!AMP?! fi
+ fi ?!AMP?!
foo
-?!AMP?! done
+ done ?!AMP?!
bar
->)
+)
diff --git a/t/chainlint/if-in-loop.test b/t/chainlint/if-in-loop.test
index daf22da164..f0cf19cfad 100644
--- a/t/chainlint/if-in-loop.test
+++ b/t/chainlint/if-in-loop.test
@@ -3,13 +3,13 @@
do
if false
then
-# LINT: missing "&&" on 'echo'
+# LINT: missing "&&" on "echo"
echo "err"
exit 1
-# LINT: missing "&&" on 'fi'
+# LINT: missing "&&" on "fi"
fi
foo
-# LINT: missing "&&" on 'done'
+# LINT: missing "&&" on "done"
done
bar
)
diff --git a/t/chainlint/if-then-else.expect b/t/chainlint/if-then-else.expect
index 5953c7bfbc..44d86c3597 100644
--- a/t/chainlint/if-then-else.expect
+++ b/t/chainlint/if-then-else.expect
@@ -1,19 +1,20 @@
(
if test -n ""
then
-?!AMP?! echo very
+ echo very ?!AMP?!
echo empty
elif test -z ""
+ then
echo foo
else
echo foo &&
- cat
-?!AMP?! fi
+ cat <<-EOF
+ fi ?!AMP?!
echo poodle
->) &&
+) &&
(
if test -n ""; then
echo very &&
-?!AMP?! echo empty
- if
->)
+ echo empty
+ fi
+)
diff --git a/t/chainlint/if-then-else.test b/t/chainlint/if-then-else.test
index 9bd8e9a4c6..2055336c2b 100644
--- a/t/chainlint/if-then-else.test
+++ b/t/chainlint/if-then-else.test
@@ -1,28 +1,29 @@
(
-# LINT: 'if', 'then', 'elif', 'else', 'fi' do not need "&&"
+# LINT: "if", "then", "elif", "else", "fi" do not need "&&"
if test -n ""
then
-# LINT: missing "&&" on 'echo'
+# LINT: missing "&&" on "echo"
echo very
-# LINT: last statement before 'elif' does not need "&&"
+# LINT: last statement before "elif" does not need "&&"
echo empty
elif test -z ""
-# LINT: last statement before 'else' does not need "&&"
+ then
+# LINT: last statement before "else" does not need "&&"
echo foo
else
echo foo &&
-# LINT: last statement before 'fi' does not need "&&"
+# LINT: last statement before "fi" does not need "&&"
cat <<-\EOF
bar
EOF
-# LINT: missing "&&" on 'fi'
+# LINT: missing "&&" on "fi"
fi
echo poodle
) &&
(
-# LINT: 'then' on same line as 'if'
+# LINT: "then" on same line as "if"
if test -n ""; then
echo very &&
echo empty
- if
+ fi
)
diff --git a/t/chainlint/incomplete-line.expect b/t/chainlint/incomplete-line.expect
index 2f3ebabdc2..ffac8f9018 100644
--- a/t/chainlint/incomplete-line.expect
+++ b/t/chainlint/incomplete-line.expect
@@ -1,4 +1,4 @@
line 1 line 2 line 3 line 4 &&
(
line 5 line 6 line 7 line 8
->)
+)
diff --git a/t/chainlint/inline-comment.expect b/t/chainlint/inline-comment.expect
index fc9f250ac4..dd0dace077 100644
--- a/t/chainlint/inline-comment.expect
+++ b/t/chainlint/inline-comment.expect
@@ -1,9 +1,8 @@
(
foobar &&
-?!AMP?! barfoo
+ barfoo ?!AMP?!
flibble "not a # comment"
->) &&
+) &&
-(
-cd foo &&
-> flibble "not a # comment")
+(cd foo &&
+ flibble "not a # comment")
diff --git a/t/chainlint/loop-in-if.expect b/t/chainlint/loop-in-if.expect
index 088e622c31..e1be42376c 100644
--- a/t/chainlint/loop-in-if.expect
+++ b/t/chainlint/loop-in-if.expect
@@ -3,10 +3,10 @@
then
while true
do
-?!AMP?! echo "pop"
+ echo "pop" ?!AMP?!
echo "glup"
-?!AMP?! done
+ done ?!AMP?!
foo
-?!AMP?! fi
+ fi ?!AMP?!
bar
->)
+)
diff --git a/t/chainlint/loop-in-if.test b/t/chainlint/loop-in-if.test
index 93e8ba8e4d..dfcc3f98fb 100644
--- a/t/chainlint/loop-in-if.test
+++ b/t/chainlint/loop-in-if.test
@@ -3,13 +3,13 @@
then
while true
do
-# LINT: missing "&&" on 'echo'
+# LINT: missing "&&" on "echo"
echo "pop"
echo "glup"
-# LINT: missing "&&" on 'done'
+# LINT: missing "&&" on "done"
done
foo
-# LINT: missing "&&" on 'fi'
+# LINT: missing "&&" on "fi"
fi
bar
)
diff --git a/t/chainlint/multi-line-nested-command-substitution.expect b/t/chainlint/multi-line-nested-command-substitution.expect
index 59b6c8b850..300058341b 100644
--- a/t/chainlint/multi-line-nested-command-substitution.expect
+++ b/t/chainlint/multi-line-nested-command-substitution.expect
@@ -3,16 +3,16 @@
x=$(
echo bar |
cat
->> ) &&
+ ) &&
echo ok
->) |
+) |
sort &&
(
bar &&
x=$(echo bar |
cat
->> ) &&
+ ) &&
y=$(echo baz |
->> fip) &&
+ fip) &&
echo fail
->)
+)
diff --git a/t/chainlint/multi-line-string.expect b/t/chainlint/multi-line-string.expect
index 170cb59993..ab0dadf748 100644
--- a/t/chainlint/multi-line-string.expect
+++ b/t/chainlint/multi-line-string.expect
@@ -1,15 +1,9 @@
(
x="line 1 line 2 line 3" &&
-?!AMP?! y='line 1 line2'
+ y="line 1 line2" ?!AMP?!
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
->)
+)
diff --git a/t/chainlint/multi-line-string.test b/t/chainlint/multi-line-string.test
index 287ab89705..4a0af2107d 100644
--- a/t/chainlint/multi-line-string.test
+++ b/t/chainlint/multi-line-string.test
@@ -3,25 +3,13 @@
line 2
line 3" &&
# LINT: missing "&&" on assignment
- y='line 1
- line2'
+ y="line 1
+ line2"
foobar
) &&
(
-# LINT: apostrophe (in a contraction) within string not misinterpreted as
-# 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
)
diff --git a/t/chainlint/negated-one-liner.expect b/t/chainlint/negated-one-liner.expect
index cf18429d03..ad4c2d949e 100644
--- a/t/chainlint/negated-one-liner.expect
+++ b/t/chainlint/negated-one-liner.expect
@@ -1,5 +1,5 @@
! (foo && bar) &&
! (foo && bar) >baz &&
-?!SEMI?!! (foo; bar) &&
-?!SEMI?!! (foo; bar) >baz
+! (foo; ?!AMP?! bar) &&
+! (foo; ?!AMP?! bar) >baz
diff --git a/t/chainlint/nested-cuddled-subshell.expect b/t/chainlint/nested-cuddled-subshell.expect
index c2a59ffc33..2a86885ee6 100644
--- a/t/chainlint/nested-cuddled-subshell.expect
+++ b/t/chainlint/nested-cuddled-subshell.expect
@@ -1,19 +1,19 @@
(
(cd foo &&
bar
->> ) &&
+ ) &&
(cd foo &&
bar
-?!AMP?!>> )
+ ) ?!AMP?!
(
cd foo &&
->> bar) &&
+ bar) &&
(
cd foo &&
-?!AMP?!>> bar)
+ bar) ?!AMP?!
(cd foo &&
->> bar) &&
+ bar) &&
(cd foo &&
-?!AMP?!>> bar)
+ bar) ?!AMP?!
foobar
->)
+)
diff --git a/t/chainlint/nested-here-doc.expect b/t/chainlint/nested-here-doc.expect
index 0c9ef1cfc6..e3bef63f75 100644
--- a/t/chainlint/nested-here-doc.expect
+++ b/t/chainlint/nested-here-doc.expect
@@ -1,7 +1,7 @@
-cat >foop &&
+cat <<ARBITRARY >foop &&
(
- cat &&
-?!AMP?! cat
+ cat <<-INPUT_END &&
+ cat <<-EOT ?!AMP?!
foobar
->)
+)
diff --git a/t/chainlint/nested-subshell-comment.expect b/t/chainlint/nested-subshell-comment.expect
index 15b68d4373..be4b27a305 100644
--- a/t/chainlint/nested-subshell-comment.expect
+++ b/t/chainlint/nested-subshell-comment.expect
@@ -2,10 +2,8 @@
foo &&
(
bar &&
- # bottles wobble while fiddles gobble
- # minor numbers of cows (or do they?)
baz &&
snaff
-?!AMP?!>> )
+ ) ?!AMP?!
fuzzy
->)
+)
diff --git a/t/chainlint/nested-subshell-comment.test b/t/chainlint/nested-subshell-comment.test
index 0ff136ab3c..0215cdb192 100644
--- a/t/chainlint/nested-subshell-comment.test
+++ b/t/chainlint/nested-subshell-comment.test
@@ -7,7 +7,7 @@
# minor numbers of cows (or do they?)
baz &&
snaff
-# LINT: missing "&&" on ')'
+# LINT: missing "&&" on ")"
)
fuzzy
)
diff --git a/t/chainlint/nested-subshell.expect b/t/chainlint/nested-subshell.expect
index c8165ad19e..41a48adaa2 100644
--- a/t/chainlint/nested-subshell.expect
+++ b/t/chainlint/nested-subshell.expect
@@ -3,10 +3,10 @@
(
echo a &&
echo b
->> ) >file &&
+ ) >file &&
cd foo &&
(
echo a
echo b
->> ) >file
->)
+ ) >file
+)
diff --git a/t/chainlint/nested-subshell.test b/t/chainlint/nested-subshell.test
index 998b05a47d..440ee9992d 100644
--- a/t/chainlint/nested-subshell.test
+++ b/t/chainlint/nested-subshell.test
@@ -7,7 +7,6 @@
cd foo &&
(
-# LINT: nested multi-line subshell not presently checked for missing "&&"
echo a
echo b
) >file
diff --git a/t/chainlint/not-heredoc.expect b/t/chainlint/not-heredoc.expect
new file mode 100644
index 0000000000..2e9bb135fe
--- /dev/null
+++ b/t/chainlint/not-heredoc.expect
@@ -0,0 +1,14 @@
+echo "<<<<<<< ours" &&
+echo ourside &&
+echo "=======" &&
+echo theirside &&
+echo ">>>>>>> theirs" &&
+
+(
+ echo "<<<<<<< ours" &&
+ echo ourside &&
+ echo "=======" &&
+ echo theirside &&
+ echo ">>>>>>> theirs" ?!AMP?!
+ poodle
+) >merged
diff --git a/t/chainlint/not-heredoc.test b/t/chainlint/not-heredoc.test
new file mode 100644
index 0000000000..9aa57346cd
--- /dev/null
+++ b/t/chainlint/not-heredoc.test
@@ -0,0 +1,16 @@
+# LINT: "<< ours" inside string is not here-doc
+echo "<<<<<<< ours" &&
+echo ourside &&
+echo "=======" &&
+echo theirside &&
+echo ">>>>>>> theirs" &&
+
+(
+# LINT: "<< ours" inside string is not here-doc
+ echo "<<<<<<< ours" &&
+ echo ourside &&
+ echo "=======" &&
+ echo theirside &&
+ echo ">>>>>>> theirs"
+ poodle
+) >merged
diff --git a/t/chainlint/one-liner.expect b/t/chainlint/one-liner.expect
index 237f227349..57a7a444c1 100644
--- a/t/chainlint/one-liner.expect
+++ b/t/chainlint/one-liner.expect
@@ -2,8 +2,8 @@
(foo && bar) |
(foo && bar) >baz &&
-?!SEMI?!(foo; bar) &&
-?!SEMI?!(foo; bar) |
-?!SEMI?!(foo; bar) >baz
+(foo; ?!AMP?! bar) &&
+(foo; ?!AMP?! bar) |
+(foo; ?!AMP?! bar) >baz &&
(foo "bar; baz")
diff --git a/t/chainlint/one-liner.test b/t/chainlint/one-liner.test
index ec9acb9825..be9858fa29 100644
--- a/t/chainlint/one-liner.test
+++ b/t/chainlint/one-liner.test
@@ -3,10 +3,10 @@
(foo && bar) |
(foo && bar) >baz &&
-# LINT: top-level one-liner subshell missing internal "&&"
+# LINT: top-level one-liner subshell missing internal "&&" and broken &&-chain
(foo; bar) &&
(foo; bar) |
-(foo; bar) >baz
+(foo; bar) >baz &&
# LINT: ";" in string not misinterpreted as broken &&-chain
(foo "bar; baz")
diff --git a/t/chainlint/p4-filespec.expect b/t/chainlint/p4-filespec.expect
index 98b3d881fd..1290fd1ff2 100644
--- a/t/chainlint/p4-filespec.expect
+++ b/t/chainlint/p4-filespec.expect
@@ -1,4 +1,4 @@
(
p4 print -1 //depot/fiddle#42 >file &&
foobar
->)
+)
diff --git a/t/chainlint/pipe.expect b/t/chainlint/pipe.expect
index 211b901dbc..2cfc028297 100644
--- a/t/chainlint/pipe.expect
+++ b/t/chainlint/pipe.expect
@@ -3,6 +3,6 @@
bar |
baz &&
fish |
-?!AMP?! cow
+ cow ?!AMP?!
sunder
->)
+)
diff --git a/t/chainlint/pipe.test b/t/chainlint/pipe.test
index e6af4de916..dd82534c66 100644
--- a/t/chainlint/pipe.test
+++ b/t/chainlint/pipe.test
@@ -4,7 +4,7 @@
bar |
baz &&
-# LINT: final line of pipe sequence ('cow') lacking "&&"
+# LINT: final line of pipe sequence ("cow") lacking "&&"
fish |
cow
diff --git a/t/chainlint/semicolon.expect b/t/chainlint/semicolon.expect
index 1d79384606..ed0b3707ae 100644
--- a/t/chainlint/semicolon.expect
+++ b/t/chainlint/semicolon.expect
@@ -1,20 +1,19 @@
(
-?!AMP?!?!SEMI?! cat foo ; echo bar
-?!SEMI?! cat foo ; echo bar
->) &&
+ cat foo ; ?!AMP?! echo bar ?!AMP?!
+ cat foo ; ?!AMP?! echo bar
+) &&
(
-?!SEMI?! cat foo ; echo bar &&
-?!SEMI?! cat foo ; echo bar
->) &&
+ cat foo ; ?!AMP?! echo bar &&
+ cat foo ; ?!AMP?! echo bar
+) &&
(
echo "foo; bar" &&
-?!SEMI?! cat foo; echo bar
->) &&
+ cat foo; ?!AMP?! echo bar
+) &&
(
-?!SEMI?! foo;
->) &&
-(
-cd foo &&
+ foo;
+) &&
+(cd foo &&
for i in a b c; do
-?!SEMI?! echo;
-> done)
+ echo;
+ done)
diff --git a/t/chainlint/semicolon.test b/t/chainlint/semicolon.test
index d82c8ebbc0..67e1192c50 100644
--- a/t/chainlint/semicolon.test
+++ b/t/chainlint/semicolon.test
@@ -15,11 +15,11 @@
cat foo; echo bar
) &&
(
-# LINT: unnecessary terminating semicolon
+# LINT: semicolon unnecessary but legitimate
foo;
) &&
(cd foo &&
for i in a b c; do
-# LINT: unnecessary terminating semicolon
+# LINT: semicolon unnecessary but legitimate
echo;
done)
diff --git a/t/chainlint/subshell-here-doc.expect b/t/chainlint/subshell-here-doc.expect
index 74723e7340..029d129299 100644
--- a/t/chainlint/subshell-here-doc.expect
+++ b/t/chainlint/subshell-here-doc.expect
@@ -1,11 +1,10 @@
(
- echo wobba gorgo snoot wafta snurb &&
-?!AMP?! cat >bip
- echo >bop
->) &&
+ echo wobba gorgo snoot wafta snurb <<-EOF &&
+ cat <<EOF >bip ?!AMP?!
+ echo <<-EOF >bop
+) &&
(
- cat >bup &&
- cat >bup2 &&
- cat >bup3 &&
+ cat <<-ARBITRARY >bup &&
+ cat <<-ARBITRARY3 >bup3 &&
meep
->)
+)
diff --git a/t/chainlint/subshell-here-doc.test b/t/chainlint/subshell-here-doc.test
index f6b3ba4214..d40eb65583 100644
--- a/t/chainlint/subshell-here-doc.test
+++ b/t/chainlint/subshell-here-doc.test
@@ -8,10 +8,10 @@
nevermore...
EOF
-# LINT: missing "&&" on 'cat'
+# LINT: missing "&&" on "cat"
cat <<EOF >bip
fish fly high
- EOF
+EOF
# LINT: swallow here-doc (EOF is last line of subshell)
echo <<-\EOF >bop
@@ -27,10 +27,6 @@
glink
FIZZ
ARBITRARY
- cat <<-'ARBITRARY2' >bup2 &&
- glink
- FIZZ
- ARBITRARY2
cat <<-"ARBITRARY3" >bup3 &&
glink
FIZZ
diff --git a/t/chainlint/subshell-one-liner.expect b/t/chainlint/subshell-one-liner.expect
index 51162821d7..b7015361bf 100644
--- a/t/chainlint/subshell-one-liner.expect
+++ b/t/chainlint/subshell-one-liner.expect
@@ -2,13 +2,13 @@
(foo && bar) &&
(foo && bar) |
(foo && bar) >baz &&
-?!SEMI?! (foo; bar) &&
-?!SEMI?! (foo; bar) |
-?!SEMI?! (foo; bar) >baz &&
+ (foo; ?!AMP?! bar) &&
+ (foo; ?!AMP?! bar) |
+ (foo; ?!AMP?! bar) >baz &&
(foo || exit 1) &&
(foo || exit 1) |
(foo || exit 1) >baz &&
-?!AMP?! (foo && bar)
-?!AMP?!?!SEMI?! (foo && bar; baz)
+ (foo && bar) ?!AMP?!
+ (foo && bar; ?!AMP?! baz) ?!AMP?!
foobar
->)
+)
diff --git a/t/chainlint/t7900-subtree.expect b/t/chainlint/t7900-subtree.expect
index c9913429e6..1cccc7bf7e 100644
--- a/t/chainlint/t7900-subtree.expect
+++ b/t/chainlint/t7900-subtree.expect
@@ -1,10 +1,10 @@
(
chks="sub1sub2sub3sub4" &&
- chks_sub=$(cat | sed 's,^,sub dir/,'
->>) &&
+ chks_sub=$(cat <<TXT | sed "s,^,sub dir/,"
+) &&
chkms="main-sub1main-sub2main-sub3main-sub4" &&
- chkms_sub=$(cat | sed 's,^,sub dir/,'
->>) &&
+ chkms_sub=$(cat <<TXT | sed "s,^,sub dir/,"
+) &&
subfiles=$(git ls-files) &&
check_equal "$subfiles" "$chkms$chks"
->)
+)
diff --git a/t/chainlint/t7900-subtree.test b/t/chainlint/t7900-subtree.test
index 277d8358df..02f3129232 100644
--- a/t/chainlint/t7900-subtree.test
+++ b/t/chainlint/t7900-subtree.test
@@ -3,7 +3,7 @@
sub2
sub3
sub4" &&
- chks_sub=$(cat <<TXT | sed 's,^,sub dir/,'
+ chks_sub=$(cat <<TXT | sed "s,^,sub dir/,"
$chks
TXT
) &&
@@ -11,7 +11,7 @@ TXT
main-sub2
main-sub3
main-sub4" &&
- chkms_sub=$(cat <<TXT | sed 's,^,sub dir/,'
+ chkms_sub=$(cat <<TXT | sed "s,^,sub dir/,"
$chkms
TXT
) &&
diff --git a/t/chainlint/while-loop.expect b/t/chainlint/while-loop.expect
index 13cff2c0a5..0d3a9b3d12 100644
--- a/t/chainlint/while-loop.expect
+++ b/t/chainlint/while-loop.expect
@@ -1,11 +1,11 @@
(
while true
do
-?!AMP?! echo foo
- cat
-?!AMP?! done
+ echo foo ?!AMP?!
+ cat <<-EOF
+ done ?!AMP?!
while true; do
echo foo &&
cat bar
done
->)
+)
diff --git a/t/chainlint/while-loop.test b/t/chainlint/while-loop.test
index f1df085bf0..d09fb016e4 100644
--- a/t/chainlint/while-loop.test
+++ b/t/chainlint/while-loop.test
@@ -1,17 +1,17 @@
(
-# LINT: 'while, 'do', 'done' do not need "&&"
+# LINT: "while", "do", "done" do not need "&&"
while true
do
-# LINT: missing "&&" on 'echo'
+# LINT: missing "&&" on "echo"
echo foo
# LINT: last statement of while does not need "&&"
cat <<-\EOF
bar
EOF
-# LINT: missing "&&" on 'done'
+# LINT: missing "&&" on "done"
done
-# LINT: 'do' on same line as 'while'
+# LINT: "do" on same line as "while"
while true; do
echo foo &&
cat bar