TL; DR
- 廃止予定(deprecated) の関数、変数を同じパッケージ内から参照しても
staticcheck
は警告しない - この挙動は意図的(
staticcheck
は廃止予定の要素が「外部から参照される」ことを禁止している)
// DeprecatedFunc shows some messages.
//
// Deprecated: should not be used.
func DeprecatedFunc() {
fmt.Println("hoge")
}
// NewFunc shows some messages.
func NewFunc() {
DeprecatedFunc() // ここはstaticcheckで警告されない!!
}
はじめに
staticcheckは、廃止予定の関数、変数を参照している箇所を警告してくれます。golangci-lintに標準で入っているので使っている方も多いと思います。
Goでは廃止予定の要素には // Deprecated: ...
というコメントを書く決まりがあるため、この行を検知しています。
package foo
import "fmt"
// DeprecatedFunc shows some messages.
//
// Deprecated: should not be used.
func DeprecatedFunc() {
fmt.Println("hoge")
}
package main
import "example.com/foo"
func main() {
foo.DeprecatedFunc()
}
$ staticcheck
main.go:6:2: foo.DeprecatedFunc is deprecated: should not be used. (SA1019)
一方、冒頭のように同じパッケージ内であれば廃止予定の要素を参照しても警告されません。
最初はバグかと思いましたが、この仕様は意図的なものでした。
パッケージ内の参照を無視しない理由
廃止予定API利用のチェックは、同じパッケージからの廃止予定のものの利用を明示的に許可しています。つまり、新しい、廃止予定ではないAPIを内部的に廃止予定APIの上に構築することができます。何かが廃止予定であるということは、別のパッケージやサードパーティーの利用者にしか影響しません。廃止予定の方の(埋め込み)フィールドを持つことも問題ない場合もあります。
The check for use of deprecated APIs explicitly allows the use of deprecated things from the same package. After all, a new, not deprecated API can internally be built upon a deprecated API. That something is deprecated only affects other packages, 3rd party users. Even having (embedded) fields of deprecated types can be fine sometimes.
確かに、新APIへの過渡期には旧APIの実装を参照することがあると思います。「レガシーコード改善ガイド」に登場した「スプラウトメソッド」の話を思い出しました。
おわりに
以上、staticcheckのdeprecatedチェックの仕様についてでした。内部でさえ使いたくないものについては、レビューで確認するしかなさそうです。