Gopls: Диагностика

Gopls непрерывно аннотирует все ваши открытые файлы исходного кода различными диагностическими сообщениями. Каждый раз, когда вы редактируете файл или вносите изменения в конфигурацию, gopls асинхронно пересчитывает эти диагностики и отправляет их клиенту с использованием уведомления LSP publishDiagnostics, обеспечивая вам обратную связь в реальном времени, что снижает стоимость распространённых ошибок.

Диагностики поступают из двух основных источников: ошибки компиляции и результаты анализа.

  • Ошибки компиляции — это те, которые вы получали бы при запуске go build. Gopls не запускает компилятор напрямую; это было бы слишком медленно. Вместо этого он запускает go list (при необходимости), чтобы вычислить метаданные компиляции, а затем обрабатывает пакеты аналогично фронтенду компилятора: читает, сканирует и разбирает исходные файлы, а затем проверяет их типы. Каждый из этих этапов может породить ошибки, которые gopls отобразит как диагностику.

    Поле source записи Diagnostic в LSP указывает, откуда поступила диагностика: диагностики с источником "go list" поступают из команды go list, а диагностики с источником "compiler" — из фаз разбора или проверки типов в gopls, которые аналогичны тем, что используются в компиляторе Go.

    A diagnostic due to a type error

    Приведённый выше пример показывает сложение string + int, вызывающее проверку типов, чтобы сообщить об ошибке MismatchedTypes. Диагностика содержит ссылку на документацию по этому типу ошибок.

  • Результаты анализа поступают из фреймворка Go analysis, системы, используемой go vet для применения различных дополнительных статических проверок вашего кода на Go. Наиболее известным примером является printf анализатор, который сообщает о вызовах fmt.Printf, где «verb» формата не соответствует аргументу, например fmt.Printf("%d", "three").

    Gopls предоставляет десятки анализаторов, собранных из различных наборов; см. Анализаторы для полного списка. Поле source каждой диагностики, выдаваемой анализатором, содержит имя анализатора, который её создал.

    A diagnostic due to an analysis finding

    Приведённый выше пример показывает ошибку форматирования printf. Диагностика содержит ссылку на документацию по анализатору printf.

Существует дополнительный третий источник диагностических данных:

Пересчёт диагностических данных

По умолчанию диагностические данные автоматически пересчитываются каждый раз при редактировании исходных файлов.

Ошибки компиляции в открытых файлах обновляются через очень короткую задержку (десятки миллисекунд) после каждого изменения файла, возможно, после каждой нажатой клавиши. Это обеспечивает быструю обратную связь по синтаксическим и типовым ошибкам во время редактирования.

Компиляция и анализ диагностических данных для всего рабочего пространства требуют гораздо больше ресурсов для вычисления, поэтому они обычно пересчитываются после короткого периода бездействия (примерно 1 секунда) после редактирования.

Настройка diagnosticsDelay определяет этот период. В качестве альтернативы, диагностика может быть запущена только после сохранения отредактированного файла, используя настройку diagnosticsTrigger.

Когда инициализировано с "pullDiagnostics": true, gopls также поддерживает «pull diagnostics», альтернативный механизм пересчёта диагностических данных, при котором клиент явно запрашивает диагностику у gopls с использованием запроса textDocument/diagnostic. Эта функция отключена по умолчанию, пока производительность pull-диагностики не будет сопоставима с push-диагностикой.

Быстрые исправления

Каждая диагностическая инструкция анализатора может предлагать одно или несколько альтернативных способов исправления проблемы путём редактирования кода. Например, когда оператор return имеет недостаточное количество операндов, анализатор fillreturns предлагает исправление, которое эвристически заполняет недостающие значения подходящими значениями. Применение такого исправления устраняет ошибку компиляции.

An analyzer diagnostic with two alternative fixes

Снимок экрана выше показывает меню быстрых исправлений VS Code для диагностического сообщения анализа «unused parameter» (неиспользуемый параметр) с двумя альтернативными исправлениями. (См. Remove unused parameter для получения дополнительных сведений.)

Предлагаемые исправления, которые являются неоспоримо безопасными, представляют собой code actions с типом "source.fixAll". Многие клиентские редакторы имеют ярлык для применения всех таких исправлений.

TODO(adonovan): провести аудит всех анализаторов, чтобы убедиться, что их документация актуальна по отношению к предлагаемым исправлениям.

Настройки:

Поддержка клиентов:

stubMissingInterfaceMethods: Объявить отсутствующие методы интерфейса I

Когда значение конкретного типа присваивается переменной типа интерфейса, но конкретный тип не обладает всеми необходимыми методами, проверяющий типы выдаст ошибку «отсутствующий метод».

В такой ситуации gopls предлагает быстрое исправление для добавления заглушечных объявлений всех отсутствующих методов к конкретному типу, чтобы он реализовывал интерфейс.

Например, эта функция не будет компилироваться, потому что значение NegativeErr{} не реализует интерфейс «error»:

<code class="language-go">func sqrt(x float64) (float64, error) {
  if x < 0 {
    return 0, NegativeErr{} // error: missing method
  }
  ...
}
type NegativeErr struct{}
</code>

Gopls предложит быстрое исправление для объявления этого метода:

<code class="language-go">
// Error implements error.Error.
func (NegativeErr) Error() string {
  panic("unimplemented")
}
</code>

Обратите внимание, что новые объявления появляются рядом с конкретным типом, который может находиться в другом файле или даже пакете по отношению к позиции курсора. (Возможно, gopls должен отправлять запрос showDocument для перехода клиента туда, или уведомление о ходе выполнения, указывающее, что что-то произошло.)

StubMissingCalledFunction: Объявить отсутствующий метод T.f

Когда вы пытаетесь вызвать метод у типа, который не имеет этого метода, компилятор выдаст ошибку вроде «type X has no field or method Y». В этой ситуации gopls теперь предлагает быстрое исправление для генерации заглушки объявления отсутствующего метода, выведя его тип из вызова.

Рассмотрим следующий код, где Foo не имеет метода bar:

<code class="language-go">type Foo struct{}
func main() {
  var s string
  f := Foo{}
  s = f.bar("str", 42) // error: f.bar undefined (type Foo has no field or method bar)
}
</code>

Gopls предложит быстрое исправление «Declare missing method Foo.bar». При его применении будет создана следующая декларация:

<code class="language-go">func (f Foo) bar(s string, i int) string {
  panic("unimplemented")
}
</code>

CreateUndeclared: Создать отсутствующее объявление для «undeclared name: X»

Ошибка компилятора Go «undeclared name: X» означает, что переменная или функция используется до того, как была объявлена в текущей области видимости. В этой ситуации gopls предлагает быстрое исправление для создания объявления.

Объявить новую переменную

Когда вы ссылаетесь на переменную, которая ещё не объявлена:

<code class="language-go">func main() {
  x := 42
  min(x, y) // error: undefined: y
}
</code>

Быстрое исправление вставит объявление со значением по умолчанию, выведя его тип из контекста:

<code class="language-go">func main() {
  x := 42
  y := 0
  min(x, y)
}
</code>

Объявить новую функцию

Аналогично, если вы вызываете функцию, которая ещё не объявлена:

<code class="language-go">func main() {
  var s string
  s = doSomething(42) // error: undefined: doSomething
}
</code>

Gopls вставит новое объявление функции ниже, выведя её тип из вызова:

<code class="language-go">func main() {
  var s string
  s = doSomething(42)
}
func doSomething(i int) string {
  panic("unimplemented")
}
</code>

Исходные файлы для этой документации можно найти ниже golang.org/x/tools/gopls/doc.

GoRu.dev Golang на русском

На сайте представлена адаптированная под русский язык документация языка программирования Golang