Skip to content

feat(linters): add deferinloop analyzer — flags defer inside for-loop bodies#40679

Merged
pelikhan merged 5 commits into
mainfrom
copilot/linter-miner-add-deferinloop-analyzer
Jun 21, 2026
Merged

feat(linters): add deferinloop analyzer — flags defer inside for-loop bodies#40679
pelikhan merged 5 commits into
mainfrom
copilot/linter-miner-add-deferinloop-analyzer

Conversation

Copilot AI commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

defer inside a loop doesn't execute at end of each iteration — it runs when the enclosing function returns, causing resource leaks (file handles, connections) and unexpected LIFO cleanup ordering. gocritic covers this but is disabled due to golangci-lint v2 bugs; this custom analyzer fills the gap.

Changes

  • pkg/linters/deferinloop/deferinloop.go — Analyzer using inspector.Cursor.Enclosing to walk ancestors from each DeferStmt, stopping at ForStmt/RangeStmt (flag) or FuncLit (exempt — new scope). Honors //nolint:deferinloop. Test files are exempt. Doc string accurately describes the ancestor-walk behavior and FuncLit boundary exemption.
  • pkg/linters/deferinloop/deferinloop_test.go + testdata/ — Covers range loops, classic for loops, infinite loops, nested loops (flagged), defers nested inside if/select within a loop (flagged), closures, goroutine func literals, explicit-close, and nolint (exempt).
  • cmd/linters/main.go — Registers deferinloop.Analyzer in the multichecker.
  • pkg/linters/README.md — Documents the new linter.
  • pkg/linters/doc.go — Updated analyzer count (29→30) and added deferinloop to the active analyzer list.
  • pkg/linters/spec_test.go — Added deferinloop to documentedAnalyzers() to keep the spec consistent.

Example

// BAD — flagged: defer runs when function returns, not each iteration
for _, p := range paths {
    f, _ := os.Open(p)
    defer f.Close() // deferinloop: defer inside a loop does not execute at the end of each iteration
}

// BAD — also flagged: defer nested inside if/select within a loop
for _, p := range paths {
    if cond {
        f, _ := os.Open(p)
        defer f.Close() // flagged
    }
}

// GOOD — exempt: function literal between defer and loop forms a new scope boundary
for _, p := range paths {
    func() {
        f, _ := os.Open(p)
        defer f.Close()
    }()
}

… bodies

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Add deferinloop analyzer for loop bodies feat(linters): add deferinloop analyzer — flags defer inside for-loop bodies Jun 21, 2026
Copilot AI requested a review from pelikhan June 21, 2026 19:40
@pelikhan pelikhan marked this pull request as ready for review June 21, 2026 19:42
Copilot AI review requested due to automatic review settings June 21, 2026 19:42
@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new custom go/analysis analyzer (deferinloop) to the gh-aw linter suite to detect defer statements inside for/range loop bodies (a common source of resource leaks and unintended cleanup timing), along with analysistest coverage, registration in the multichecker entrypoint, and README documentation.

Changes:

  • Added pkg/linters/deferinloop analyzer implementation that walks DeferStmt nodes and detects enclosing for/range loops while treating function literals as a scope boundary.
  • Added analysistest-based tests and testdata/ cases covering loop forms, nesting, closure exemptions, and //nolint:deferinloop.
  • Registered the analyzer in cmd/linters/main.go and documented it in pkg/linters/README.md.
Show a summary per file
File Description
pkg/linters/deferinloop/deferinloop.go New analyzer that reports defer in loop bodies and honors nolint + FuncLit scope boundaries
pkg/linters/deferinloop/deferinloop_test.go analysistest runner for the new analyzer
pkg/linters/deferinloop/testdata/src/deferinloop/deferinloop.go Positive/negative test cases for loop usage, closures, and nolint
cmd/linters/main.go Registers deferinloop.Analyzer in the multichecker
pkg/linters/README.md Documents the new linter in the package overview + table

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 5/6 changed files
  • Comments generated: 2

Comment thread pkg/linters/deferinloop/deferinloop.go Outdated
// Analyzer is the defer-in-loop analysis pass.
var Analyzer = &analysis.Analyzer{
Name: "deferinloop",
Doc: "reports defer statements placed directly inside for or range loop bodies; defers inside function literals are exempt because they form a new function scope",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. The Doc string now reads: "reports defer statements enclosed anywhere within a for or range loop body; a function literal between a defer and an enclosing loop is treated as a new scope boundary, making the defer exempt; test files are not checked" — no longer implies all defers inside function literals are exempt.

Comment thread pkg/linters/README.md
Comment on lines 9 to 12
- `contextcancelnotdeferred` — reports context cancel functions that are called directly instead of deferred.
- `ctxbackground` — reports `context.Background()` calls inside functions that already receive a `context.Context` parameter.
- `deferinloop` — reports `defer` statements placed directly inside `for`/`range` loop bodies, which execute when the enclosing function returns rather than each iteration and can cause resource leaks.
- `errorfwrapv` — reports `fmt.Errorf` calls that format error arguments with `%v` instead of `%w`.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — pkg/linters/doc.go updated (count 29→30, deferinloop added alphabetically) and pkg/linters/spec_test.go updated with the import and entry in documentedAnalyzers().

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 100/100 — Excellent

Analyzed 1 test(s): 1 design, 0 implementation, 0 guideline violation(s).

📊 Metrics & Test Classification (1 test analyzed)
Metric Value
New/modified tests analyzed 1
✅ Design tests (behavioral contracts) 1 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 1 (100%)
Duplicate test clusters 0
Test inflation detected No (ratio 0.20:1)
🚨 Coding-guideline violations 0
Test File Classification Issues Detected
TestAnalyzer pkg/linters/deferinloop/deferinloop_test.go:13 ✅ Design

Go: 1 (*_test.go); JavaScript: 0 (*.test.cjs, *.test.js). Other languages detected but not scored.

Note: TestAnalyzer uses analysistest.Run — the standard Go analysis testing framework. Behavioral assertions are driven by // want directive comments in the testdata source file (testdata/src/deferinloop/deferinloop.go), which the framework verifies automatically. This is the idiomatic and correct testing pattern for go/analysis linters.

The testdata file covers 9 scenarios across 4 bad-case categories (range loop, classic for, infinite loop, nested loops) and 5 good-case categories (explicit close, func literal inside loop, defer outside loop, //nolint same line, //nolint previous line). The func-literal boundary exemption and nolint suppression paths are both exercised.

Verdict

Check passed. 0% implementation tests (threshold: 30%). All new tests verify observable behavioral contracts — the analyzer correctly flags and exempts the right code patterns, including key edge cases (func literal scope boundary, nolint directives, nested loops).

🧪 Test quality analysis by Test Quality Sentinel · 49.4 AIC · ⌖ 13.3 AIC · ⊞ 8.3K ·

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 100/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /tdd and /grill-with-docs — commenting on doc-string accuracy and test coverage gaps. No blocking logic bugs found.

📋 Key Themes & Highlights

Key Themes

  • Doc inaccuracy (/grill-with-docs): Both Analyzer.Doc (line 23) and the isInsideLoop comment (line 61) use the word "directly" — implying the linter only catches defer as an immediate child of a loop body. The implementation correctly catches defer at any depth (inside if/switch/select within a loop), so the docs should say so.

  • Test coverage gaps (/tdd): The testdata covers the six core cases well, but is missing the most prevalent real-world patterns:

    • defer inside a select case inside a for loop (ubiquitous in channel-consuming goroutines)
    • defer inside an if block inside a loop
    • go func() { defer ... }() inside a loop (goroutine FuncLit — should be exempt)
      Compare with timeafterleak's testdata (163 lines, 13 functions) for a fuller reference.
  • // want regex precision (/tdd): Backtick-quoted strings in analysistest are Go regexps; the unescaped . chars are wildcards. Harmless in practice but imprecise.

Positive Highlights

  • ✅ Core isInsideLoop logic is correct: inspector.Cursor.Enclosing with innermost-first ordering plus FuncLit short-circuit is the right approach
  • ✅ Shared nolint package wired up consistently with same-line and previous-line directives
  • ✅ Registration in cmd/linters/main.go is clean and follows existing alphabetical order
  • ✅ PR description clearly motivates why a custom analyzer is needed (gocritic disabled under golangci-lint v2)

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 86.8 AIC · ⌖ 7.89 AIC · ⊞ 6.9K

Comment thread pkg/linters/deferinloop/deferinloop.go Outdated
// Analyzer is the defer-in-loop analysis pass.
var Analyzer = &analysis.Analyzer{
Name: "deferinloop",
Doc: "reports defer statements placed directly inside for or range loop bodies; defers inside function literals are exempt because they form a new function scope",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/grill-with-docs] The Doc string says "placed directly inside for or range loop bodies" — but the linter catches defer at any depth within a loop body (e.g. inside a nested if, switch, or select).\n\n

\n💡 Suggested fix\n\nThe word "directly" implies only immediate children of the loop body, which is inaccurate. A user who writes defer inside an if within a loop would rightfully expect it to be flagged — and it is — but the doc implies otherwise:\n\ngo\nDoc: "reports defer statements appearing anywhere inside for or range loop bodies, except inside function literals which form a new scope",\n\n\nSame inaccuracy appears in the isInsideLoop doc comment on line 61.\n

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — Analyzer.Doc now reads "enclosed anywhere within a for or range loop body" rather than "placed directly inside".

}

// isInsideLoop reports whether cur (a DeferStmt) is directly enclosed by a
// for or range loop body, without crossing a function literal boundary.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/grill-with-docs] "Directly enclosed by a for or range loop body" is inaccurate — the function actually flags defer at any ancestor depth before a FuncLit boundary (e.g. a defer inside if { switch { defer } } inside a for is still caught). The word "directly" implies only immediate children.\n\n

\n💡 Suggested fix\n\ngo\n// isInsideLoop reports whether cur (a DeferStmt) has a for or range loop\n// anywhere in its ancestor chain before crossing a function literal boundary.\n// Defers inside func literals are exempt because they form a new function scope\n// and execute when the literal returns, not the outer function.\n\n

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — isInsideLoop comment updated to "enclosed anywhere within a for or range loop body, without crossing a function literal boundary".

//nolint:deferinloop
defer f.Close()
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] Missing test cases for defer inside control-flow structures nested within a loop. The most common real-world form is for { select { case <-ch: defer cleanup() } }, but if and switch inside a loop are equally unexercised. Compare with timeafterleak's testdata (163 lines, 13 functions) which is more exhaustive.\n\n

\n💡 Suggested additions\n\nAdd these exempt/flagged cases to verify the ancestor-walk is correct regardless of intermediate AST nodes:\n\ngo\n// BadSelectInLoop flags defer inside a select inside a for loop.\nfunc BadSelectInLoop(ch <-chan string) {\n\tfor {\n\t\tselect {\n\t\tcase p := <-ch:\n\t\t\tf, _ := os.Open(p)\n\t\t\tdefer f.Close() // want `defer inside a loop...`\n\t\t}\n\t}\n}\n\n// BadIfInLoop flags defer inside an if block inside a for loop.\nfunc BadIfInLoop(paths []string, cond bool) {\n\tfor _, p := range paths {\n\t\tif cond {\n\t\t\tf, _ := os.Open(p)\n\t\t\tdefer f.Close() // want `defer inside a loop...`\n\t\t}\n\t}\n}\n\n// GoodGoFuncLitInsideLoop is fine — goroutine func literal forms a new scope.\nfunc GoodGoFuncLitInsideLoop(paths []string) {\n\tfor _, p := range paths {\n\t\tgo func() {\n\t\t\tf, _ := os.Open(p)\n\t\t\tdefer f.Close()\n\t\t}()\n\t}\n}\n\n\nThe implementation should handle all these correctly (the ancestor walk skips non-filter nodes), but without tests a future refactor has no safety net.\n

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added BadIfInLoop, BadSelectInLoop, and GoodGoFuncLitInsideLoop test cases covering those patterns.

func BadForRange(paths []string) {
for _, p := range paths {
f, _ := os.Open(p)
defer f.Close() // want `defer inside a loop does not execute at the end of each iteration; it runs when the enclosing function returns, which can cause resource leaks`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The // want backtick-quoted string is treated as a Go regexp by analysistest. The ." characters in "iteration" and "leaks" are wildcard metacharacters (match any byte), so the regex is slightly more permissive than intended.\n\n<details>\n<summary>💡 Suggested fix</summary>\n\nEscape literal dots with \.":\n\ngo\ndefer f.Close() // want `defer inside a loop does not execute at the end of each iteration; it runs when the enclosing function returns, which can cause resource leaks`\n// becomes:\ndefer f.Close() // want `defer inside a loop does not execute at the end of each iteration; it runs when the enclosing function returns, which can cause resource leaks`\n\n\nIn practice this is harmless (the actual message always matches), but precise regexps make the test intent clearer. This pattern repeats on lines 17, 25, and 35.\n

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diagnostic message contains no literal dots, so there is nothing to escape. The // want patterns are already exact matches for the message text.

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot Run pr-finisher skill

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR adds 176 new lines in business-logic directories (a new custom go/analysis linter, deferinloop) but does not have a linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/40679-add-deferinloop-linter.md — review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR committed to your branch — it was generated from the PR diff and follows the precedent set by docs/adr/40490-add-sprintferrorsnew-linter.md.
  2. Complete / refine the sections — confirm the gocritic-disabled rationale, the FuncLit exemption decision, and the listed consequences match your intent.
  3. Commit the finalized ADR to docs/adr/ on your branch.
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-40679: Add deferinloop linter

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

❓ Why ADRs Matter

ADRs create a searchable, permanent record of why the codebase looks the way it does. A future contributor reading deferinloop will want to know why a local analyzer exists instead of gocritic, and why function-literal defers are exempt. Future contributors (and your future self) will thank you.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 40679-add-deferinloop-linter.md for PR #40679).

🔒 This PR cannot merge until an ADR is linked in the PR body.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · 85.3 AIC · ⌖ 10.5 AIC · ⊞ 6.9K ·

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation is correct and well-structured. isInsideLoop properly uses cur.Enclosing(...) to stop at FuncLit boundaries, the nolint handling is sound, and the test coverage is reasonable for the documented patterns.

Two non-blocking observations
  1. Analyzer.Doc omits the test-file exemption_test.go files are silently skipped (consistent with other linters in this package), but the doc string doesn't say so. gocritic's equivalent check doesn't skip test files, so users may be surprised.

  2. Missing testdata case for defer inside a conditional within a loopif cond { defer f.Close() } inside a for loop is the most common real-world trigger for this warning. The logic handles it correctly, but there's no test to prevent a future regression if isInsideLoop is refactored.

🔎 Code quality review by PR Code Quality Reviewer · 163.7 AIC · ⌖ 7.51 AIC · ⊞ 5.1K

Comment thread pkg/linters/deferinloop/deferinloop.go Outdated
// Analyzer is the defer-in-loop analysis pass.
var Analyzer = &analysis.Analyzer{
Name: "deferinloop",
Doc: "reports defer statements placed directly inside for or range loop bodies; defers inside function literals are exempt because they form a new function scope",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Analyzer.Doc omits the test-file exemption, which will surprise users when _test.go defers-in-loops are silently not flagged.

💡 Suggested fix

Extend the doc string to document the exemption:

Doc: "reports defer statements placed directly inside for/range loop bodies; defers inside function literals and _test.go files are exempt",

gocritic's equivalent check (deferInLoop) flags test files. This analyzer silently diverges from that behavior. A user who wonders why their benchmark or test helper isn't flagged has no indication from the doc string that test files are excluded.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added "test files are not checked" to the Analyzer.Doc string to document this exemption.

//nolint:deferinloop
defer f.Close()
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No test case for defer nested inside a conditional (if/switch/select) within a loop — the most common real-world pattern that triggers this lint warning.

💡 Suggested addition
// BadDeferInIfInsideLoop flags defer inside an if block within a loop.
func BadDeferInIfInsideLoop(paths []string, cond bool) {
	for _, p := range paths {
		if cond {
			f, _ := os.Open(p)
			defer f.Close() // want `defer inside a loop does not execute at the end of each iteration; it runs when the enclosing function returns, which can cause resource leaks`
		}
	}
}

The current implementation is correct — cur.Enclosing(...) traverses all ancestors, so the ForStmt/RangeStmt is found regardless of how many IfStmt/SwitchStmt/SelectStmt nodes are between the defer and the loop. However, without an explicit test for this pattern, a future refactor that naively checks only the direct parent would regress silently. Adding this case closes that gap.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added BadIfInLoop (defer inside if inside loop) and BadSelectInLoop (defer inside select inside loop) test cases.

Comment thread pkg/linters/deferinloop/deferinloop.go Outdated
// Analyzer is the defer-in-loop analysis pass.
var Analyzer = &analysis.Analyzer{
Name: "deferinloop",
Doc: "reports defer statements placed directly inside for or range loop bodies; defers inside function literals are exempt because they form a new function scope",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Analyzer.Doc says "directly inside" but the linter flags defers at any nesting depth within the loop — this is a meaningful documentation inaccuracy.

💡 Suggested fix

The current doc reads:

"reports defer statements placed directly inside for or range loop bodies"

isInsideLoop uses cur.Enclosing(...) which skips all intermediate nodes (IfStmt, SwitchStmt, SelectStmt, BlockStmt). A defer inside for { if cond { defer f() } } is flagged even though it is not a direct child of the loop body.

Change to:

Doc: "reports defer statements enclosed anywhere within a for or range loop body without a function literal boundary; defers inside function literals are exempt because they form a new function scope",

Users who read "directly inside" and wonder why their for { switch { case: defer } } is flagged will be confused. The behavior is correct; the description is not.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — Analyzer.Doc now reads "enclosed anywhere within" instead of "placed directly inside".

// isInsideLoop reports whether cur (a DeferStmt) is directly enclosed by a
// for or range loop body, without crossing a function literal boundary.
// Defers inside func literals are exempt because they form a new function scope
// and execute when the literal returns, not the outer function.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isInsideLoop doc comment says "directly enclosed by" — same imprecision as Analyzer.Doc, misleading for future maintainers.

💡 Suggested fix

Current comment:

isInsideLoop reports whether cur (a DeferStmt) is **directly enclosed by** a for or range loop body

A maintainer who reads "directly enclosed" might refactor Enclosing(...) to only check the immediate parent node, breaking detection of defers nested inside if/switch/select inside loops — and the comment would look like justification for that regression.

Suggested:

// isInsideLoop reports whether cur (a DeferStmt) is enclosed anywhere within a
// for or range loop body, without crossing a function literal boundary.
// Defers inside func literals are exempt because they form a new function scope
// and execute when the literal returns, not the outer function.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — isInsideLoop comment updated to "enclosed anywhere within a for or range loop body" to avoid implying only immediate children are checked.

Copilot AI and others added 2 commits June 21, 2026 20:09
…test.go

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…/goroutine test cases

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan pelikhan merged commit 7cdcb8b into main Jun 21, 2026
36 checks passed
@pelikhan pelikhan deleted the copilot/linter-miner-add-deferinloop-analyzer branch June 21, 2026 20:28
github-actions Bot added a commit that referenced this pull request Jun 22, 2026
Weekly update covering the week of June 15–22, 2026:
- Compiler +320% performance regression fix (#40662)
- New deferinloop Go linter (#40679)
- gh-aw-detection rollout to 50% of workflows (#40698)
- JSON-RPC error handling fix (#40715)
- Skillet sparse checkout path fix (#40684)
- FNV-1a heredoc delimiter generation (#40696)
- Agent of the Week: delight ✨

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants