go-analyzers

module
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 17, 2026 License: MIT

README

go-analyzers

Custom Go static analyzers for modern Go 1.25+ idioms. These analyzers detect patterns that can be simplified using newer standard library functions.

Usable standalone via go vet or with Bazel's nogo for build-time analysis.

Analyzers

Analyzer Detects Suggests
makecopy make([]T, len(s)); copy(dst, s) (including subslice variants) slices.Clone(s)
searchmigrate sort.Search(n, func(i int) bool { ... }) slices.BinarySearch(s, v)
clampcheck if-else-if clamp chains and consecutive if-return clamp patterns min(max(x, lo), hi)
sortmigrate sort.Strings, sort.Ints, sort.Slice, etc. slices.Sort, slices.SortFunc, etc.

Why these analyzers?

The official modernize suite and revive's use-slices-sort rule cover most Go 1.21+ modernization patterns. These analyzers fill the remaining gaps:

  • makecopy: modernize's appendclipped only catches append-based clones, not make+copy. Also detects subslice variants like make([]T, len(s)-idx); copy(dst, s[idx:]).
  • searchmigrate: No existing linter detects sort.Searchslices.BinarySearch.
  • clampcheck: modernize's minmax handles simple if/elsemin/max but deliberately excludes nested if-elseif-else clamp patterns. Also detects consecutive if-return clamp patterns.
  • sortmigrate: Detects deprecated sort.Strings, sort.Ints, sort.Float64s, sort.Slice, sort.SliceStable, sort.SliceIsSorted, and their AreSorted variants, suggesting slices.Sort, slices.SortFunc, slices.IsSorted, etc.

Installation

Standalone
go install github.com/albertocavalcante/go-analyzers/cmd/go-analyzers@latest
go vet -vettool=$(which go-analyzers) ./...
golangci-lint v2 module plugin

For golangci-lint integration, see go-analyzers-gcl.

Bazel nogo (build-time analysis)

nogo runs go/analysis analyzers as part of bazel build, failing the build on any diagnostic. Each of our analyzer packages exports a var Analyzer compatible with nogo's requirements.

  1. Add this module as a dependency in your MODULE.bazel:
bazel_dep(name = "go-analyzers", version = "0.1.0")

go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//:go.mod")
# If not using go.mod, add the module directly:
# go_deps.module(
#     path = "github.com/albertocavalcante/go-analyzers",
#     version = "v0.1.0",
# )
  1. Define a nogo() target in your root BUILD.bazel:
load("@rules_go//go:def.bzl", "nogo", "TOOLS_NOGO")

nogo(
    name = "my_nogo",
    deps = TOOLS_NOGO + [
        "@com_github_albertocavalcante_go_analyzers//makecopy",
        "@com_github_albertocavalcante_go_analyzers//searchmigrate",
        "@com_github_albertocavalcante_go_analyzers//clampcheck",
        "@com_github_albertocavalcante_go_analyzers//sortmigrate",
    ],
    config = ":nogo_config.json",
    vet = True,
    visibility = ["//visibility:public"],
)
  1. Register nogo with the Go SDK in MODULE.bazel:
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
go_sdk.nogo(nogo = "//:my_nogo")
WORKSPACE (legacy)
  1. Add this module via go_repository (typically managed by Gazelle):
load("@bazel_gazelle//:deps.bzl", "go_repository")

go_repository(
    name = "com_github_albertocavalcante_go_analyzers",
    importpath = "github.com/albertocavalcante/go-analyzers",
    sum = "h1:...",
    version = "v0.1.0",
)
  1. Define the nogo() target in your root BUILD file (same as Bzlmod above).

  2. Register nogo in your WORKSPACE:

load("@io_bazel_rules_go//go:deps.bzl", "go_register_nogo")
go_register_nogo(nogo = "@//:my_nogo")
nogo config JSON

Create nogo_config.json in your repository root to control analyzer behavior:

{
  "_base": {
    "exclude_files": {
      "external/": "skip external dependencies",
      "third_party/": "skip vendored code"
    }
  },
  "makecopy": {},
  "searchmigrate": {},
  "clampcheck": {},
  "sortmigrate": {}
}

See the nogo documentation for the full config format (only_files, exclude_files, analyzer_flags).

Notes
  • nogo runs automatically on every bazel build -- no separate lint step needed.
  • Diagnostics are build failures. Use exclude_files to suppress false positives rather than //nolint comments (which nogo does not support).
  • Add tags = ["no-nogo"] to any target where analysis should be skipped.
  • Use --norun_validations to temporarily skip nogo during a build.

License

MIT

Directories

Path Synopsis
Package clampcheck defines an analyzer that detects clamp patterns that can be replaced with min(max(x, lo), hi).
Package clampcheck defines an analyzer that detects clamp patterns that can be replaced with min(max(x, lo), hi).
cmd
go-analyzers command
Command go-analyzers runs all custom analyzers as a standalone tool.
Command go-analyzers runs all custom analyzers as a standalone tool.
internal
importutil
Package importutil provides shared helpers for adding import TextEdits in go/analysis SuggestedFixes.
Package importutil provides shared helpers for adding import TextEdits in go/analysis SuggestedFixes.
Package makecopy defines an analyzer that detects make+copy patterns that can be replaced with slices.Clone.
Package makecopy defines an analyzer that detects make+copy patterns that can be replaced with slices.Clone.
Package searchmigrate defines an analyzer that detects sort.Search calls that could potentially be replaced with slices.BinarySearch or slices.BinarySearchFunc.
Package searchmigrate defines an analyzer that detects sort.Search calls that could potentially be replaced with slices.BinarySearch or slices.BinarySearchFunc.
Package sortmigrate defines an analyzer that detects deprecated sort package function calls that can be replaced with slices package equivalents.
Package sortmigrate defines an analyzer that detects deprecated sort package function calls that can be replaced with slices package equivalents.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL