diff --git a/.github/violation-baseline.txt b/.github/violation-baseline.txt index ea2c95be..64288802 100644 --- a/.github/violation-baseline.txt +++ b/.github/violation-baseline.txt @@ -1248,7 +1248,7 @@ zinit/zinit-autoload.zsh ZC1049 1 zinit/zinit-autoload.zsh ZC1053 1 zinit/zinit-autoload.zsh ZC1064 1 zinit/zinit-autoload.zsh ZC1073 3 -zinit/zinit-autoload.zsh ZC1075 41 +zinit/zinit-autoload.zsh ZC1075 40 zinit/zinit-autoload.zsh ZC1083 2 zinit/zinit-autoload.zsh ZC1091 32 zinit/zinit-autoload.zsh ZC1098 3 diff --git a/pkg/katas/katatests/fp_round7_test.go b/pkg/katas/katatests/fp_round7_test.go new file mode 100644 index 00000000..1d7ed83a --- /dev/null +++ b/pkg/katas/katatests/fp_round7_test.go @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +// Copyright the ZShellCheck contributors. +package katas + +import ( + "testing" + + "github.com/afadesigns/zshellcheck/pkg/testutil" +) + +// TestZC1075FlagLedExpansionNotFlagged pins the flag-led-expansion false +// positive. A `${(%):-default}` / `${(P)…}` carries a parameter flag and a +// default the parser cannot fully model; it never produces an empty word, +// so the elision warning does not apply. +func TestZC1075FlagLedExpansionNotFlagged(t *testing.T) { + for _, src := range []string{ + "echo ${(%):-default}", + "echo ${(P):-x}", + `read -q ${(%):-"?prompt "}`, + } { + if n := len(testutil.Check(src, "ZC1075")); n != 0 { + t.Errorf("ZC1075 should not flag a flag-led expansion: %q (got %d)", src, n) + } + } + // Ordinary unquoted scalars and array elements still elide and fire. + for _, src := range []string{"echo $plain", "echo ${arr[1]}"} { + if n := len(testutil.Check(src, "ZC1075")); n == 0 { + t.Errorf("ZC1075 should still fire on %q", src) + } + } +} diff --git a/pkg/katas/zc1000s.go b/pkg/katas/zc1000s.go index ab3c2217..f26ec626 100644 --- a/pkg/katas/zc1000s.go +++ b/pkg/katas/zc1000s.go @@ -5486,6 +5486,14 @@ func checkZC1075(node ast.Node) []Violation { }) } } else if aa, ok := arg.(*ast.ArrayAccess); ok { + // A flag-led expansion the parser cannot resolve to a subject + // (`${(%):-default}`, `${(P)…}`, `${(l:n:)…}`) leaves Left nil. + // Without the subject the elision behaviour is unknowable, and + // these forms commonly carry a `:-` default or a width modifier + // that never produces an empty word, so do not flag them. + if aa.Left == nil { + continue + } // A `:-word` / `:=word` / `:+word` default-value expansion // always yields a value, so it never elides — flagging it // warns against the canonical `: ${VAR:=default}` idiom.