From 39d02a1fa5b8ec44fc083f907ca1bf775c7e4461 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 6 May 2026 04:43:35 +0000 Subject: [PATCH 1/2] Initial plan From 23675b3f07d37cfb0f7144406b50df9f18ccf4b9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 6 May 2026 05:11:26 +0000 Subject: [PATCH 2/2] test(codemod): pin direct-assignment accumulator pattern for AssertDiffSetsNeedsReplaceForForceNew Agent-Logs-Url: https://github.com/GoCodeAlone/workflow/sessions/e6d4a1f2-66be-48b7-8e17-964af164c028 Co-authored-by: intel352 <77607+intel352@users.noreply.github.com> --- cmd/iac-codemod/lint_test.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/cmd/iac-codemod/lint_test.go b/cmd/iac-codemod/lint_test.go index 3c95421a..b6bfe0fc 100644 --- a/cmd/iac-codemod/lint_test.go +++ b/cmd/iac-codemod/lint_test.go @@ -525,6 +525,37 @@ func TestAssertDiffSetsNeedsReplaceForForceNew_StructLiteralFalseStillFlags(t *t } } +// TestAssertDiffSetsNeedsReplaceForForceNew_DirectAccumulatorAssignIsClean pins +// the direct-assignment accumulator form described in the issue: the driver +// initializes a local `needsReplace` bool, sets it to true inside a ForceNew +// branch, then assigns `r.NeedsReplace = needsReplace` (an *ast.AssignStmt +// with a selector LHS and a local-variable RHS). This is distinct from the +// struct-literal KeyValueExpr form (workflow#539) but must equally NOT produce +// a false-positive diagnostic. +const diffDirectAccumulatorSrc = driverScaffold + ` +func (d *FooDriver) Diff(ctx context.Context, desired ResourceSpec, current *ResourceOutput) (*DiffResult, error) { + if current == nil { + return &DiffResult{}, nil + } + r := &DiffResult{} + needsReplace := false + for _, c := range r.Changes { + if c.ForceNew { + needsReplace = true + } + } + r.NeedsReplace = needsReplace + return r, nil +} +` + +func TestAssertDiffSetsNeedsReplaceForForceNew_DirectAccumulatorAssignIsClean(t *testing.T) { + diags := runAnalyzerOnSource(t, diffDirectAccumulatorSrc, AssertDiffSetsNeedsReplaceForForceNew) + if len(diags) != 0 { + t.Errorf("direct-assignment accumulator `r.NeedsReplace = needsReplace` is a valid W-3 expression; should NOT flag; got %d:\n%s", len(diags), diagSummary(diags)) + } +} + // TestAssertDiffSetsNeedsReplaceForForceNew_NonDriverNotFlagged pins // review finding #3: the analyzer must NOT fire on types that have a // method named Diff but are not resource drivers (no Read / Create /