Skip to content

Add lookup table lint analyzer - #22

Merged
Peyton-Spencer merged 1 commit into
mainfrom
codex/lookuptablelint
Jul 9, 2026
Merged

Add lookup table lint analyzer#22
Peyton-Spencer merged 1 commit into
mainfrom
codex/lookuptablelint

Conversation

@Peyton-Spencer

@Peyton-Spencer Peyton-Spencer commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add lookuptablelint, a go/analysis analyzer for small static lookup maps
  • report map[k]bool / map[k]struct{} lookup tables that should be predicate helpers with single-case switches
  • ship a standalone lookuptablelint singlechecker command and analysistest coverage

Notes

  • no suggested fix is emitted because rewriting call sites from map lookups to predicate calls is intentionally more invasive
  • default reporting is capped at 64 entries via -max_entries; local benchmarks showed switches faster through thousands of same-length string cases, but 64 keeps the lint focused on obvious lookup tables

Validation

  • PATH=/opt/homebrew/bin:$PATH ./scripts/test-all.sh

Summary by CodeRabbit

  • New Features

    • Added a new Go analysis check that flags small static lookup maps and suggests using predicate-style helpers.
    • Added a command-line entrypoint so the analyzer can be run directly.
    • Added test coverage and sample cases for supported and unsupported lookup patterns.
  • Documentation

    • Added package documentation describing what the analyzer reports.
  • Chores

    • Updated the Go toolchain and related module dependencies.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new Go static analysis pass lookuptablelint that detects small compile-time lookup maps (bool or empty-struct valued) and suggests predicate helpers, including its CLI entrypoint, documentation, module configuration, tests, and testdata fixtures.

Changes

Lookup Table Lint Analyzer

Layer / File(s) Summary
Analyzer registration and configuration
lookuptablelint/analyzer.go
Declares Analyzer metadata, a configurable -max_entries flag, and internal candidate/kind data model for tracking bool vs struct lookup tables.
Candidate discovery and classification
lookuptablelint/analyzer.go
Implements the run control flow, walks var declarations to find map-literal candidates, and classifies them by switchable key type, bool/empty-struct element type, and entry-count bounds with compile-time constant checks.
Usage safety analysis
lookuptablelint/analyzer.go
Scans identifier usages via a parent-pointer AST map to distinguish safe read-only index lookups from writes/mutations, requiring two-value lookup shape for struct tables.
Type predicates, constant validation, naming, and generated-code detection
lookuptablelint/analyzer.go
Adds helpers for allowed key/value type checks, compile-time constant/value validation, predicate-name generation for diagnostic messages, and skipping generated files.
CLI entrypoint, package docs, and module config
lookuptablelint/cmd/lookuptablelint/main.go, lookuptablelint/doc.go, lookuptablelint/go.mod
Wires Analyzer into singlechecker.Main, adds a package doc comment, and sets Go/toolchain versions with x/tools, x/mod, x/sync dependencies.
Analyzer tests and testdata fixtures
lookuptablelint/analyzer_test.go, lookuptablelint/testdata/src/a/a.go
Adds TestAnalyzer using analysistest against testdata package "a", which defines bool/struct/int lookup tables, an exported map, and helper functions exercising read, mutate, range, and length usage patterns.

Estimated code review effort: 4 (Complex) | ~60 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a lookup table lint analyzer.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/lookuptablelint

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain modules listed in go.work or their selected dependencies"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Peyton-Spencer
Peyton-Spencer merged commit 6142078 into main Jul 9, 2026
2 of 3 checks passed
@Peyton-Spencer
Peyton-Spencer deleted the codex/lookuptablelint branch July 9, 2026 04:50

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
lookuptablelint/testdata/src/a/a.go (1)

56-126: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a boundary test for exactly 64 entries.

tooLarge has 65 entries (000–064), which correctly exceeds the default -max_entries=64. However, there's no positive test for a map with exactly 64 entries. If the boundary comparison accidentally changes from <= to <, no test would catch the regression.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lookuptablelint/testdata/src/a/a.go` around lines 56 - 126, Add a boundary
test in the lookuptablelint testdata around the tooLarge/tooSmall maps to cover
a map with exactly 64 entries and verify it is accepted; this will protect the
max_entries check from regressing from <= to <. Use the existing tooLarge
fixture in a.go as the location to derive a 64-entry case, and ensure the test
clearly exercises the lookup-table limit boundary.
lookuptablelint/analyzer.go (1)

302-313: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use ast.IsGenerated(file) here. The standard helper matches the generated-code convention directly and avoids the loose substring scan. Remove the now-unused strings import too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lookuptablelint/analyzer.go` around lines 302 - 313, Replace the custom
generated-code detection in generated(file *ast.File) with the standard
ast.IsGenerated(file) helper so the analyzer uses the official convention
instead of scanning comments manually. After switching, remove the now-unused
strings import from analyzer.go and make sure any remaining references to the
old substring check are eliminated.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@lookuptablelint/analyzer.go`:
- Around line 302-313: Replace the custom generated-code detection in
generated(file *ast.File) with the standard ast.IsGenerated(file) helper so the
analyzer uses the official convention instead of scanning comments manually.
After switching, remove the now-unused strings import from analyzer.go and make
sure any remaining references to the old substring check are eliminated.

In `@lookuptablelint/testdata/src/a/a.go`:
- Around line 56-126: Add a boundary test in the lookuptablelint testdata around
the tooLarge/tooSmall maps to cover a map with exactly 64 entries and verify it
is accepted; this will protect the max_entries check from regressing from <= to
<. Use the existing tooLarge fixture in a.go as the location to derive a
64-entry case, and ensure the test clearly exercises the lookup-table limit
boundary.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b737526b-b0ab-43f4-acc5-89cf155d0416

📥 Commits

Reviewing files that changed from the base of the PR and between 1e60c7c and 40e9af4.

⛔ Files ignored due to path filters (2)
  • go.work is excluded by !**/*.work
  • lookuptablelint/go.sum is excluded by !**/*.sum
📒 Files selected for processing (6)
  • lookuptablelint/analyzer.go
  • lookuptablelint/analyzer_test.go
  • lookuptablelint/cmd/lookuptablelint/main.go
  • lookuptablelint/doc.go
  • lookuptablelint/go.mod
  • lookuptablelint/testdata/src/a/a.go

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.

1 participant