EnglishРусский Map

Фреймворк go/analysis

title
Фреймворк go/analysis
type
concept
summary
Стандартный Go-фреймворк для создания статических анализаторов, совместимых с go vet и golangci-lint
tags
golang, static-analysis, tooling
created
2026-04-15
updated
2026-04-15
lang
ru
translation_of
go-analysis-framework
source_updated
2026-04-15
translated
2026-09-01
translator
lllm/antigravity/gemini-3.7-flash-medium

Пакет golang.org/x/tools/go/analysis - это стандартный фреймворк Go для написания статических анализаторов. Любой созданный на его базе анализатор можно запускать отдельно, встраивать в go vet или подключать к golangci-lint.

Структура

Анализатор представляет собой структуру следующего вида:

var Analyzer = &analysis.Analyzer{
    Name:     "mycheck",
    Doc:      "checks for X",
    Requires: []*analysis.Analyzer{inspect.Analyzer},
    Run:      run,
}

Поле Requires объявляет зависимости от других анализаторов. Почти всегда требуется inspect.Analyzer - он обеспечивает оптимизированный обход AST.

Функция Run принимает analysis.Pass, содержащий:

  • Fset - набор файлов для информации о позициях в коде
  • Files - распарсенное AST пакета
  • TypesInfo - результаты проверки типов
  • ResultOf - результаты анализаторов, указанных в зависимостях
  • Report - функцию для вывода диагностических сообщений

Обход AST

Вместо обхода каждого узла используется инспектор из inspect.Analyzer:

inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{(*ast.CallExpr)(nil)}
inspect.Preorder(nodeFilter, func(n ast.Node) {
    call := n.(*ast.CallExpr)
    // analyze the call
})

Фильтр делает обход эффективным - вы посещаете только интересующие типы узлов.

Информация о типах

Поле pass.TypesInfo даёт доступ к результатам проверки типов Go:

  • TypesInfo.Types[expr] - тип любого выражения
  • TypesInfo.Uses[ident] - к чему обращается идентификатор
  • TypesInfo.Defs[ident] - что объявляет идентификатор
  • TypesInfo.ObjectOf(ident) - объект types.Object для идентификатора

Объект types.Object играет ключевую роль в отслеживании переменных. Два идентификатора, указывающие на одну и ту же переменную, ссылаются на один и тот же объект, поэтому проверка равенства указателей работает даже при затенении имён.

Тестирование

Пакет analysistest предельно упрощает тестирование:

func TestMyCheck(t *testing.T) {
    testdata := analysistest.TestData()
    analysistest.Run(t, testdata, mycheck.Analyzer, "mypackage")
}

В тестовых файлах ожидаемые сообщения задаются комментариями // want:

x := badThing() // want "badThing is deprecated"

Запуск

Отдельный запуск:

func main() {
    singlechecker.Main(mycheck.Analyzer)
}

С go vet (требуется регистрация в тулчейне Go).

С golangci-lint: добавление в .golangci.yml в секцию linters-settings.

Примеры

  • transactioncheck - находит операции с базой данных, выходящие за пределы транзакций
  • errcheck - находит необработанные ошибки
  • staticcheck - комплексный набор статических анализаторов
  • nilness - находит избыточные проверки на nil и гарантированные разыменования nil