go/analysis : o framework modular de análise estática da equipe Go, em pequenos blocos reutilizáveis

Dev & Code Jul 26, 2026Adicionar aos favoritos

go/analysis : o framework modular de análise estática da equipe Go, em pequenos blocos reutilizáveis
Ilustração : Momiji Shirogane

Sob o capô de `go vet`, `staticcheck` e afins: a equipe Go mantém um *framework* oficial que permite escrever um *linter* em poucas dezenas de linhas.

O Cas Concreto

Você herda um projeto Go de 200.000 linhas. A revisão de código deixa passar, há seis meses, um pattern que provoca goroutine leaks: um context.WithTimeout criado sem defer cancel(). Ninguém o vê na leitura. O go vet não o sinaliza. Adicionar uma regra no linter caseiro levaria, em outra linguagem, uma pequena semana.

Em Go, você escreve um Analyzer em uma noite. Porque a equipe da linguagem mantém há muito tempo um pacote quase discreto e, ainda assim, fundamental: golang.org/x/tools/go/analysis.

Por Que Isso É Importante

O pacote go/analysisGo Analysis Framework ») não é novo — está publicado e documentado em pkg.go.dev/golang.org/x/tools/go/analysis — mas volta regularmente ao Hacker News (última aparição em 2026-07-26) porque muitos desenvolvedores Go ainda o desconhecem. Só que é a infraestrutura sobre a qual gira todo o ecossistema de análise estática da linguagem: o go vet se apoia nele, o staticcheck (Dominik Honnef) o usa, o gopls (o language server oficial) conecta seus diagnósticos a ele, e a imensa maioria dos linters modernos na CI — com o golangci-lint à frente — são apenas coleções de Analyzer empilhados.

A aposta do framework é simples: um analisador = uma struct. Essa struct declara seu nome, sua documentação, suas dependências em relação a outros analisadores, e uma função Run que recebe um objeto *analysis.Pass (o código parsed, o type-checker, os arquivos, os comentários) e sinaliza seus diagnósticos via pass.Report. Só isso.

Como Funciona Por Baixo do Capô

Três ideias sustentam a arquitetura:

  1. Modularidade por composição. Um analisador pode declarar Requires: []*analysis.Analyzer{inspect.Analyzer}: o framework resolve o grafo de dependências e injeta o resultado dos analisadores pré-requisitos no Pass.ResultOf. Resultado: seu analisador de negócio não re-parse os arquivos, ele consome o resultado do inspect (que, por sua vez, faz o walk no AST tipado uma única vez para toda a cadeia).

  2. Um único « driver », múltiplos bootstrappings. Você escreve seu Analyzer. singlechecker.Main(myAnalyzer) o transforma em um binário CLI autônomo, multichecker.Main(a1, a2, a3) o transforma em um binário multi-checks, unitchecker.Main(...) o conecta ao go vet -vettool=.... Sem glue code: o mesmo código do Analyzer roda localmente, na CI, na IDE via gopls, e no golangci-lint.

  3. Correção automática tipada. Um diagnóstico pode conter SuggestedFix: substituições textuais ancoradas em posições token.Pos. O gopls as aplica com um clique no editor. É isso que permite, por exemplo, ao staticcheck propor « substituir errors.Is(err, sql.ErrNoRows) por uma verificação mais idiomática » e à IDE fazer a substituição corretamente.

Para dar uma noção de proporção: singlechecker — a função que transforma um *Analyzer em um binário completo — cabe em um único arquivo. O esqueleto mínimo de um linter Go publicável é mais ou menos 40 linhas, incluindo documentação e testes. Compare com escrever um plugin ESLint do zero: não é a mesma escala.

O Que Isso Muda na Prática

Três usos que vemos em projetos reais:

  • Regras internas da empresa. « Proibido importar diretamente net/http, deve-se passar pelo nosso wrapper de tracing. » Trinta linhas, um Analyzer que inspeciona os *ast.ImportSpec, um teste com analysistest.Run em um arquivo de fixture, e a regra é conectada na CI no dia seguinte.
  • Migração massiva de código. Refatoração em larga escala (renomear uma API deprecated em 500 arquivos): um Analyzer com SuggestedFix transforma a operação em go vet -vettool=./meufix -fix ./.... Sem intervenção humana na cadeia.
  • Análise de dataflow customizada. O framework fornece pacotes companheiros — ctrlflow (control flow graph), buildssa (representação SSA do código Go) — nos quais é possível conectar análises de dataflow não triviais. Detectar leaks de sql.Rows não fechados, por exemplo, é feito de forma séria a partir da SSA, não do AST bruto.

As Limitações Que Devemos Conhecer

Dois pontos cegos para manter em mente:

  • Análise intra-package. Por padrão, um Analyzer vê um package de cada vez. As análises inter-packages (whole-program) exigem trabalho adicional — é possível com « facts » (analysis.Fact), que permitem a um analisador exportar facts sobre os símbolos de um package para que esses facts sejam reutilizados quando outro package o importa, mas é um degrau mais complexo de se escrever.
  • Sem ecossistema de plugins dinâmicos. Não se « conecta » um Analyzer ao go vet por configuração em tempo de execução: ele é compilado em um binário. É uma escolha (Go não gosta de plugins dinâmicos), não uma omissão.

Para Guardar

  • go/analysis é a API oficial para tudo o que diz respeito à análise estática em Go, do linter caseiro à migração automática de código.
  • Um analisador = uma struct com um Run(*Pass). O resto (CLI, integração com go vet, integração com gopls, CI) é oferecido a você.
  • Se você ainda escreve suas regras de qualidade de código em shell ou com sed, essa noite de estudo é bem investida.
Resources

Artigo produzido por inteligência artificial, revisto sob controlo editorial humano.

A nossa redação
Este artigo foi-lhe útil?

3 pessoas gostaram deste artigo

Gosto
K
Kaito KuroganeSenior Dev Writer
Senior polyvalent developer, backend Go + frontend TS, open source contributor.
Partilhar:
LIVERadio Geek Kitsune
Toca para ouvir, o mesmo som para todos
0··
// Programa
// all stations
// partilhar uma faixa →
Secções
Explorar
Informações