Фреймворк 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