lintpackは、提供されているAPIを使用して作成されたlinter (静的アナライザー)を構築するためのユーティリティです。 それに基づいて、一部の人にはおなじみの批判的な静的アナライザーが書き換えられています。
今日は、ユーザーの観点から、 lintpack
何かをより詳細にlintpack
します。
最初は批判的だった...
go-criticは、Goの静的解析のアイデアをプロトタイピングするためのサンドボックスであるパイロットプロジェクトとして始まりました。
嬉しい驚きは、コードのさまざまな問題の検出器の実装を送信した人がいたことです。 技術的な負債が蓄積し始めるまで、すべてが制御下にありましたが、実質的には誰も排除できませんでした。 人々が入り、検証を追加してから姿を消しました。 誰がエラーを修正し、実装を変更する必要がありますか?
重要なイベントは、追加の構成が必要なチェック、つまりプロジェクトのローカルな配置に依存するチェックを追加する提案でした。 例としては、特別なテンプレートを使用してファイル内の著作権ヘッダー(ライセンスヘッダー)の存在を明らかにしたり、特定の代替案を提案して一部のパッケージのインポートを禁止したりします。
もう1つの困難は拡張性でした。 誰もが他の誰かのリポジトリにコードを送信するのは便利ではありません。 go-critic
ソースコードを変更する必要がないように、チェックを動的に接続したい人もいました。
要約すると、 go-critic
開発の妨げとなった問題は次のとおりです。
- 複雑さの負荷。 サポートが多すぎる、所有者のないコードの存在。
- 低平均品質。
experimental
は、「ほぼすぐに使用できる」と「まったく実行しない方がよい」の両方を意味します。 -
go-critic
に検証を含めるかどうかを決定するのは難しい場合があり、それらを拒否することは元の設計哲学に反しています。 -
go-critic
見方は人によって異なります。 ほとんどは、gometalinter
付属するCIリンターとして使用することを望んでいgometalinter
。
少なくとも何らかの形でプロジェクトの相違点と相違する解釈の数を制限するために、 マニフェストが作成されました。
追加の履歴コンテキストと、静的アナライザーの分類に関するより多くの反映が必要な場合は、Goの新しい静的アナライザーであるGoCritic記録を聴くことができます。 その時点では、lintpackはまだ存在していませんでしたが、アイデアの一部はレポート後のその日に生まれました。
しかし、すべてのチェックを1つのリポジトリに保存する必要がない場合はどうでしょうか?
会う-lintpack
go-critic
は、2つの主要コンポーネントで構成されています。
- チェック自体の実装。
- Goでテストされたパッケージをダウンロードし、チェックを実行するプログラム。
私たちの目標:リンターのチェックを異なるリポジトリに保存し、必要に応じてそれらを一緒に収集できるようにすること。
lintpackはまさにそれを行います。 生成されたリンターを介して実行できるように、チェックを記述することができる関数を定義します。
lintpack
をフレームワークとして使用して実装されるパッケージは、lintpack
compatibleまたはlintpack
lintpack
compatibleパッケージと呼ばれます。
go-critic
がlintpack
に基づいて実装されているlintpack
、すべてのチェックをいくつかのリポジトリに分割できます。 分離のオプションの1つは次のとおりです。
- すべての安定したサポートされているチェックが該当する基本セット。
- コードが存在するcontribリポジトリ。実験的すぎるか、メンテナーが不足しています。
- go-policeのようなもので、同じカスタマイズ可能なチェックを見つけることができます。
最初のポイントはgo-criticをgolangci-lintに統合することに関連して特に重要です。
go-critic
レベルにとどまる場合、ユーザーにとってはほとんど何も変わりません。 lintpack
はほぼ同一のリンターを作成しますが、 golangci-lint
はすべての異なる実装の詳細をカプセル化します。
しかし、何かが変わった。 lintpack
に基づいて新しいlintpack
が作成された場合、リンターを生成するための既製の診断の選択肢が豊富になります。 これがそうであることをちょっと想像してみてください。世界には10種類以上の異なるチェックセットがあります。
クイックスタート
開始するには、 lintpack
自体をインストールする必要があります。
# lintpack `$(go env GOPATH)/bin`. go get -v github.com/go-lintpack/lintpack/...
lintpack
のテストパッケージを使用してリンターを作成します。
lintpack build -o mylinter github.com/go-lintpack/lintpack/checkers
このセットには、コード内でpanic(nil)
を検出し、識別可能な何かで置き換えるように要求するpanicNil
含まれています。そうでない場合、 recover()
は、 panic
がnil
引数で呼び出されたか、まったくパニックがなかったかを判断できません。
以下のコードは、 recover()
から取得した値の説明を試みます。
r := recover() fmt.Printf("%T, %v\n", r, r)
panic(nil)
とpanic(nil)
を起こさないプログラムの結果は同じです。
タイプ./ ./...
またはパッケージ(インポートパスによる)の引数を使用して、別のファイルでリンターを実行できます。
./mylinter check bytes $GOROOT/src/bytes/buffer_test.go:276:3: panicNil: panic(nil) calls are discouraged
# , go-lintpack $GOPATH. mylinter=$(pwd)/mylinter cd $(go env GOPATH)/src/github.com/go-lintpack/lintpack/checkers/testdata $mylinter check ./panicNil/ ./panicNil/positive_tests.go:5:3: panicNil: panic(nil) calls are discouraged ./panicNil/positive_tests.go:9:3: panicNil: panic(interface{}(nil)) calls are discouraged
デフォルトでは、このチェックはpanic(interface{}(nil))
も応答しpanic(interface{}(nil))
。 この動作をオーバーライドするには、 skipNilEfaceLit
をtrue
に設定しtrue
。 コマンドラインからこれを行うことができます:
$mylinter check -@panicNil.skipNilEfaceLit=true ./panicNil/ ./panicNil/positive_tests.go:5:3: panicNil: panic(nil) calls are discouraged
lintpack
と生成されたlintpack
は、最初の引数を使用してサブコマンドを選択します。 利用可能なサブコマンドのリストとそれらの起動の例は、引数なしでユーティリティを呼び出すことで取得できます。
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
作成したリンターにgocritic
という名前を付けたと仮定し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
-help
フラグは、追加情報を提供する一部のサブコマンドで使用できます(幅が広すぎる行を切り取りました)。
./gocritic check -help # .
インストール済みチェックのドキュメント
「同じskipNilEfaceLitパラメーターについて調べる方法」という質問に対する答え。 -ファンシーマニュアル(RTFM)を読んでください!
インストールされたチェックに関するすべてのドキュメントはmylinter
内にmylinter
ます。 このドキュメントは、 doc
サブコマンドから入手できます。
# : $mylinter doc panicNil [diagnostic] # : $mylinter doc panicNil panicNil checker documentation URL: github.com/go-lintpack/lintpack Tags: [diagnostic] Detects panic(nil) calls. Such panic calls are hard to handle during recover. Non-compliant code: panic(nil) Compliant code: panic("something meaningful") Checker parameters: -@panicNil.skipNilEfaceLit bool whether to ignore interface{}(nil) arguments (default false)
go list -f
でのテンプレートのサポートと同様に、ドキュメントの出力形式を担当するテンプレート文字列を渡すことができます。これは、マークダウンドキュメントを書くときに役立ちます。
インストールのチェックを探す場所
便利なlintpack
スイートの検索を簡素化するために、 lintpack
互換パッケージの集中リストがあります: https : lintpack
。
リストの一部を次に示します。
- https://github.com/go-critic/go-critic/checkers
- https://github.com/go-critic/checkers-contrib
- https://github.com/Quasilyte/go-police
このリストは定期的に更新され、追加要求のために開いています。 これらのパッケージのいずれかを使用してリンターを作成できます。
以下のコマンドは、上のリストのすべてのチェックを含むリンターを作成します。
# , # Go . go get -v github.com/go-critic/go-critic/checkers go get -v github.com/go-critic/checkers-contrib go get -v github.com/Quasilyte/go-police # build . lintpack build \ github.com/go-critic/go-critic/checkers \ github.com/go-critic/checkers-contrib \ github.com/Quasilyte/go-police
lintpack build
は、コンパイル段階でのすべてのチェックが含まれます。結果のリンターは、インストール済み診断の実装用のソースコードがない環境に配置できます。すべてが静的リンクで通常どおりです。
パッケージの動的接続
静的アセンブリに加えて、追加のチェックを提供するプラグインをロードすることができます。
特徴は、チェッカー実装が静的コンパイルに使用されるのか、プラグインとしてロードされるのかを知らないことです。 コードの変更は必要ありません。
panicNil
を追加したいが、最初のコンパイル中に使用されたすべてのソースからそれを再構築できないと仮定します。
-
linterPlugin.go
作成します。
package main // , // import'. import ( _ "github.com/go-lintpack/lintpack/checkers" )
- 動的ライブラリを作成します。
go build -buildmode=plugin -o linterPlugin.so linterPlugin.go
-
-pluginPath
パラメーターを指定してリンターを実行します。
./linter check -pluginPath=linterPlugin.so bytes
警告:動的モジュールのサポートは、Windowsでは機能しないプラグインパッケージを通じて実装されます。
-verbose
フラグは、どのチェックがオンまたはオフになっているかを判断するのに役立ちます。最も重要なことは、どのフィルターがチェックをオフにしたかを示すことです。
含まれるチェックのリストにpanicNil
表示されることに注意してください。 -pluginPath引数を削除すると、trueではなくなります。
./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 # ... .
gometalinterおよびgolangci-lintとの比較
混乱を避けるために、プロジェクト間の主な違いを説明する価値があります。
gometalinterとgolangci-lintは、主に他の、しばしば非常に異なって実装されているlintersを主に統合し、それらへの便利なアクセスを提供します。 静的アナライザーを使用するエンドユーザーを対象としています。
lintpackは、新しいリンターの作成を簡素化し、同じ実行可能ファイル内で互換性のある異なるパッケージを作成するフレームワークを提供します。 これらのチェック(golangci-lint用)または実行可能ファイル(gometalinter用)は、前述のメタリンターに埋め込むことができます。
lintpack
互換のチェックの1つがgolangci-lint
一部でgolangci-lint
。 その使いやすさに関連する問題がある場合、これはgolangci-lint
責任である可能性がありますが、検証自体の実装に誤りがある場合、これは検証、lintpackエコシステムの作成者の問題です。
つまり、これらのプロジェクトはさまざまな問題を解決します。
批評家はどうですか?
lintpack
go-critic
の移植はほぼ完了しています。 進行中の作業はgo-critic / checkersリポジトリにあります。 移行が完了すると、チェックはgo-critic/go-critic/checkers
ます。
# go-critic : go get -v github.com/go-critic/go-critic/... # go-critic : lintpack -o gocritic github.com/go-critic/go-critic/checkers
golangci-lint
外部でgo-critic
を使用することはほとんど意味がありませんが、 lintpack
ではgo-critic
含まれていないチェックをインストールできます。 たとえば、これらはあなたによって書かれた診断かもしれません。
続く
次の記事で、独自のlintpack
互換チェックを作成する方法を学習します。
そこで、ゼロからの実装と比較して、lintpackベースのlintpack
実装する場合にどのような利点が得られるかを分析します。
Goの新しいチェックに対する欲求があることを願っています。 静的解析がどれだけ多くなりすぎたかを教えてください。この問題をすぐに解決します。