
O lintpack é um utilitário para a construção de linter (analisadores estáticos), escritos usando a API fornecida. Com base nisso, o analisador estático go- critical, familiar para alguns, agora está sendo reescrito.
Hoje vamos lintpack
com mais detalhes o que lintpack
o lintpack
do ponto de vista do usuário.
No começo era crítico ...
O go-critic começou como um projeto piloto que era uma caixa de areia para prototipar quase todas as idéias de análise estática para o Go.
Uma surpresa agradável foi que algumas pessoas enviaram implementações de detectores de vários problemas no código. Tudo estava sob controle até que uma dívida técnica começou a se acumular, que praticamente não havia ninguém a eliminar. As pessoas entraram, adicionaram a verificação e desapareceram. Quem então precisa corrigir os erros e modificar a implementação?
Um evento significativo foi a proposta de adicionar verificações que requerem configuração adicional, ou seja, aquelas que dependem de arranjos locais para o projeto. Um exemplo é revelar a presença de um cabeçalho de direitos autorais em um arquivo (cabeçalho da licença) usando um modelo especial ou proibir a importação de alguns pacotes com a proposta de uma determinada alternativa.
Outra dificuldade foi a extensibilidade. Não é conveniente que todos enviem seu código ao repositório de outra pessoa. Alguns queriam conectar dinamicamente suas verificações para que não precisassem modificar os códigos go-critic
fonte go-critic
.
Resumindo, eis os problemas que impediram o desenvolvimento go-critic
:
- Uma carga de complexidade. Muito suporte, a presença de um código sem dono.
- Baixa qualidade média.
experimental
significava "quase pronto para usar" e "melhor não funcionar". - Às vezes, é difícil decidir se deve incluir a verificação no
go-critic
e rejeitá-la contradiz a filosofia de design original. - Pessoas diferentes viram o
go-critic
diferente. A maioria queria tê-lo como um linter de CI, que vem com o gometalinter
.
Para limitar de alguma forma o número de discrepâncias e interpretações inconsistentes do projeto, um manifesto foi escrito.
Se você deseja um contexto histórico adicional e ainda mais reflexão sobre a categorização de analisadores estáticos, pode ouvir a gravação GoCritic, um novo analisador estático para o Go . Naquele momento, o lintpack ainda não existia, mas algumas das idéias nasceram naquele dia, após o relatório.
Mas e se não precisássemos armazenar todas as verificações em um repositório?

go-critic
consiste em dois componentes principais:
- Implementação das próprias verificações.
- Um programa que baixa pacotes validados por Go e executa validações neles.
Nosso objetivo: poder armazenar verificações para o linter em diferentes repositórios e coletá-las quando necessário.
O lintpack faz exatamente isso. Ele define funções que permitem descrever suas verificações de forma que você possa executá-las no linter gerado.
Os pacotes implementados usando o lintpack
como estrutura serão chamados de lintpack
compatíveis com lintpack
ou compatíveis com lintpack
.
Se o próprio go-critic
lintpack
foi implementado com base no lintpack
, todas as verificações poderiam ser divididas em vários repositórios. Uma das opções de separação pode ser a seguinte:
- O conjunto principal onde todas as verificações estáveis e suportadas são obtidas.
- contrib repositório onde está o código que é muito experimental ou sem um mantenedor.
- Verificações personalizáveis para um projeto específico.
O primeiro ponto é de particular importância em relação à integração do crítico em golangci-lint .
Se você permanecer no nível go-critic
, então para os usuários quase nada mudou. lintpack
cria um linter quase idêntico, enquanto o golangci-lint
encapsula todos os diferentes detalhes de implementação.
Mas algo mudou. Se novos lintpack
forem criados com base no lintpack
, você terá uma seleção mais rica de diagnósticos prontos para gerar um linter. Imagine por um momento que seja assim, e existem mais de 10 conjuntos diferentes de verificações no mundo.
Início rápido

Para começar, você precisa instalar o próprio lintpack
:
Crie um linter usando o pacote de teste do lintpack
:
lintpack build -o mylinter github.com/go-lintpack/lintpack/checkers
O conjunto inclui panicNil
, que encontra panic(nil)
no código e panicNil
uma substituição por algo distinguível, porque caso contrário o recover()
não será capaz de dizer se o panic
foi chamado com argumento nil
ou se não houve pânico.
Exemplo com pânico (nulo)
O código abaixo tenta descrever o valor obtido de recover()
:
r := recover() fmt.Printf("%T, %v\n", r, r)
O resultado será idêntico para panic(nil)
e para um programa que não entre em panic(nil)
.
Um exemplo de execução do comportamento descrito .
Você pode iniciar o linter em arquivos separados, com argumentos do tipo ./...
ou pacotes (pelo caminho de importação).
./mylinter check bytes $GOROOT/src/bytes/buffer_test.go:276:3: panicNil: panic(nil) calls are discouraged
Por padrão, essa verificação também responde ao panic(interface{}(nil))
. Para substituir esse comportamento, defina skipNilEfaceLit
como true
. Você pode fazer isso através da linha de comando:
$mylinter check -@panicNil.skipNilEfaceLit=true ./panicNil/ ./panicNil/positive_tests.go:5:3: panicNil: panic(nil) calls are discouraged
uso para cmd / lintpack e linter gerado
O lintpack
e o linter gerado usam o primeiro argumento para selecionar um subcomando. A lista de subcomandos disponíveis e exemplos de seu lançamento podem ser obtidos chamando o utilitário sem argumentos.
lintpack not enough arguments, expected sub-command name Supported sub-commands: build - build linter from made of lintpack-compatible packages $ lintpack build -help $ lintpack build -o gocritic github.com/go-critic/checkers $ lintpack build -linter.version=v1.0.0 . version - print lintpack version $ lintpack version
Suponha que gocritic
o linter criado com o nome gocritic
:
./gocritic not enough arguments, expected sub-command name Supported sub-commands: check - run linter over specified targets $ linter check -help $ linter check -disableTags=none strings bytes $ linter check -enableTags=diagnostic ./... version - print linter version $ linter version doc - get installed checkers documentation $ linter doc -help $ linter doc $ linter doc checkerName
O sinalizador -help
está disponível para alguns subcomandos, o que fornece informações adicionais (cortei algumas linhas muito largas):
./gocritic check -help
Documentação de verificações instaladas
A resposta para a pergunta "como descobrir o próprio parâmetro skipNilEfaceLit?" - leia o manual chique (RTFM)!
Toda a documentação sobre as verificações instaladas está dentro do mylinter
. Esta documentação está disponível através do subcomando doc
:
Assim como o suporte a modelos na go list -f
, você pode passar uma linha de modelo responsável pelo formato de saída da documentação, que pode ser útil ao gravar documentos de remarcação.
Onde procurar verificações para instalação?
Para simplificar a busca por suítes de lintpack
úteis, existe uma lista centralizada de pacotes compatíveis com o lintpack
: https://go-lintpack.imtqy.com/ .
Aqui estão algumas da lista:
Esta lista é atualizada periodicamente e está aberta para solicitações de adição. Qualquer um desses pacotes pode ser usado para criar um linter.
O comando abaixo cria um linter que contém todas as verificações da lista acima:
lintpack build
inclui todas as verificações no estágio de compilação, o linter resultante pode ser colocado em um ambiente em que não há códigos-fonte para a implementação dos diagnósticos instalados; tudo é como de costume com o link estático.
Anexo de pacote dinâmico
Além da montagem estática, é possível carregar plug-ins que fornecem verificações adicionais.
A peculiaridade é que a implementação do verificador não sabe se será usada para compilação estática ou se será carregada como um plug-in. Nenhuma alteração no código é necessária.
Suponha que desejemos adicionar panicNil
ao linter, mas não podemos reconstruí-lo a partir de todas as fontes usadas durante a primeira compilação.
- Crie
linterPlugin.go
:
package main
- Crie uma biblioteca dinâmica:
go build -buildmode=plugin -o linterPlugin.so linterPlugin.go
- Execute o linter com o parâmetro
-pluginPath
:
./linter check -pluginPath=linterPlugin.so bytes
Aviso: O suporte para módulos dinâmicos é implementado por meio de um pacote de plugins que não funciona no Windows.
O sinalizador -verbose
pode ajudá-lo a descobrir qual verificação está ativada ou desativada e, o mais importante, mostrará qual filtro desativou a verificação.
Exemplo com -verbose
Observe que panicNil
exibido na lista de verificações incluídas. Se removermos o argumento -pluginPath, ele deixará de ser verdadeiro.
./linter check -verbose -pluginPath=./linterPlugin.so bytes debug: appendCombine: disabled by tags (-disableTags) debug: boolExprSimplify: disabled by tags (-disableTags) debug: builtinShadow: disabled by tags (-disableTags) debug: commentedOutCode: disabled by tags (-disableTags) debug: deprecatedComment: disabled by tags (-disableTags) debug: docStub: disabled by tags (-disableTags) debug: emptyFallthrough: disabled by tags (-disableTags) debug: hugeParam: disabled by tags (-disableTags) debug: importShadow: disabled by tags (-disableTags) debug: indexAlloc: disabled by tags (-disableTags) debug: methodExprCall: disabled by tags (-disableTags) debug: nilValReturn: disabled by tags (-disableTags) debug: paramTypeCombine: disabled by tags (-disableTags) debug: rangeExprCopy: disabled by tags (-disableTags) debug: rangeValCopy: disabled by tags (-disableTags) debug: sloppyReassign: disabled by tags (-disableTags) debug: typeUnparen: disabled by tags (-disableTags) debug: unlabelStmt: disabled by tags (-disableTags) debug: wrapperFunc: disabled by tags (-disableTags) debug: appendAssign is enabled debug: assignOp is enabled debug: captLocal is enabled debug: caseOrder is enabled debug: defaultCaseOrder is enabled debug: dupArg is enabled debug: dupBranchBody is enabled debug: dupCase is enabled debug: dupSubExpr is enabled debug: elseif is enabled debug: flagDeref is enabled debug: ifElseChain is enabled debug: panicNil is enabled debug: regexpMust is enabled debug: singleCaseSwitch is enabled debug: sloppyLen is enabled debug: switchTrue is enabled debug: typeSwitchVar is enabled debug: underef is enabled debug: unlambda is enabled debug: unslice is enabled
Para evitar confusão, vale a pena descrever as principais diferenças entre os projetos.
O gometalinter e o golangci-lint integram principalmente outros linters , geralmente implementados de maneira muito diferente, proporcionando acesso conveniente a eles. Eles têm como alvo usuários finais que usarão analisadores estáticos.
O lintpack simplifica a criação de novos linters, fornece uma estrutura que torna diferentes pacotes, implementados em sua base, compatíveis dentro do mesmo arquivo executável. Essas verificações (para golangci-lint) ou o arquivo executável (para gometalinter) podem ser incorporadas nos meta-linters mencionados acima.
Suponha que uma das verificações compatíveis com o lintpack
parte do golangci-lint
. Se houver algum problema relacionado à sua usabilidade, isso pode ser de responsabilidade do golangci-lint
, mas se houver um erro na implementação da verificação em si, esse é o problema dos autores do ecossistema de verificação, lintpack.
Em outras palavras, esses projetos resolvem vários problemas.
E o crítico?
O processo de portar o go-critic
para o lintpack
já foi concluído; os verificadores podem ser encontrados no repositório do go-critic / checkers .
Não faz sentido usar o go-critic
fora do golangci-lint
, mas o lintpack
pode permitir que você instale as verificações que não estão incluídas no go-critic
. Por exemplo, esses podem ser diagnósticos escritos por você.
Para ser continuado
Você aprenderá como criar suas próprias verificações compatíveis com o lintpack
no próximo artigo.
Lá, analisaremos quais vantagens você obtém ao implementar seu lintpack
baseado em lintpack em comparação com a implementação do zero.
Espero que você tenha um apetite por novos cheques para o Go. Deixe-me saber o quanto a análise estática se torna demais, resolveremos rapidamente esse problema juntos.