Go lintpack:コンポーザブルリンターマネージャー


lintpackは、提供されているAPIを使用して作成されたlinter (静的アナライザー)を構築するためのユーティリティです。 それに基づいて、一部の人にはおなじみの批判的な静的アナライザーが書き換えられています。


今日は、ユーザーの観点から、 lintpack何かをより詳細にlintpackします。


最初は批判的だった...


go-criticは、Goの静的解析のアイデアをプロトタイピングするためのサンドボックスであるパイロットプロジェクトとして始まりました。


嬉しい驚きは、コードのさまざまな問題の検出器の実装を送信した人がいたことです。 技術的な負債が蓄積し始めるまで、すべてが制御下にありましたが、実質的には誰も排除できませんでした。 人々が入り、検証を追加してから姿を消しました。 誰がエラーを修正し、実装を変更する必要がありますか?


重要なイベントは、追加の構成が必要なチェック、つまりプロジェクトのローカルな配置に依存するチェックを追加する提案でした。 例としては、特別なテンプレートを使用してファイル内の著作権ヘッダー(ライセンスヘッダー)の存在を明らかにしたり、特定の代替案を提案して一部のパッケージのインポートを禁止したりします。


もう1つの困難は拡張性でした。 誰もが他の誰かのリポジトリにコードを送信するのは便利ではありません。 go-criticソースコードを変更する必要がないように、チェックを動的に接続したい人もいました。


要約すると、 go-critic開発の妨げとなった問題は次のとおりです。



少なくとも何らかの形でプロジェクトの相違点と相違する解釈の数を制限するために、 マニフェストが作成されました。


追加の履歴コンテキストと、静的アナライザーの分類に関するより多くの反映が必要な場合は、Goの新しい静的アナライザーであるGoCritic記録を聴くことができます。 その時点では、lintpackはまだ存在していませんでしたが、アイデアの一部はレポート後のその日に生まれました。

しかし、すべてのチェックを1つのリポジトリに保存する必要がない場合はどうでしょうか?


会う-lintpack




go-criticは、2つの主要コンポーネントで構成されています。


  1. チェック自体の実装。
  2. Goでテストされたパッケージをダウンロードし、チェックを実行するプログラム。

私たちの目標:リンターのチェックを異なるリポジトリに保存し、必要に応じてそれらを一緒に収集できるようにすること。


lintpackはまさにそれを行います。 生成されたリンターを介して実行できるように、チェックを記述することができる関数を定義します。


lintpackをフレームワークとして使用して実装されるパッケージは、 lintpack compatibleまたはlintpack lintpack compatibleパッケージと呼ばれます。

go-criticlintpackに基づいて実装されているlintpack 、すべてのチェックをいくつかのリポジトリに分割できます。 分離のオプションの1つは次のとおりです。


  1. すべての安定したサポートされているチェックが該当する基本セット。
  2. コードが存在するcontribリポジトリ。実験的すぎるか、メンテナーが不足しています。
  3. 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()は、 panicnil引数で呼び出されたか、まったくパニックがなかったかを判断できません。


パニックを伴う例(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)) 。 この動作をオーバーライドするには、 skipNilEfaceLittrueに設定しtrue 。 コマンドラインからこれを行うことができます:


 $mylinter check -@panicNil.skipNilEfaceLit=true ./panicNil/ ./panicNil/positive_tests.go:5:3: panicNil: panic(nil) calls are discouraged 

cmd / lintpackおよび生成されたlinterの使用法


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


リストの一部を次に示します。



このリストは定期的に更新され、追加要求のために開いています。 これらのパッケージのいずれかを使用してリンターを作成できます。


以下のコマンドは、上のリストのすべてのチェックを含むリンターを作成します。


 #   ,      #   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を追加したいが、最初のコンパイル中に使用されたすべてのソースからそれを再構築できないと仮定します。


  1. linterPlugin.go作成します。

 package main //         , //    import'. import ( _ "github.com/go-lintpack/lintpack/checkers" ) 

  1. 動的ライブラリを作成します。

 go build -buildmode=plugin -o linterPlugin.so linterPlugin.go 

  1. -pluginPathパラメーターを指定してリンターを実行します。

 ./linter check -pluginPath=linterPlugin.so bytes 

警告:動的モジュールのサポートは、Windowsでは機能しないプラグインパッケージを通じて実装されます。

-verboseフラグは、どのチェックがオンまたはオフになっているかを判断するのに役立ちます。最も重要なことは、どのフィルターがチェックをオフにしたかを示すことです。


-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との比較


混乱を避けるために、プロジェクト間の主な違いを説明する価値があります。


gometalintergolangci-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の新しいチェックに対する欲求があることを願っています。 静的解析がどれだけ多くなりすぎたかを教えてください。この問題をすぐに解決します。



Source: https://habr.com/ru/post/J430196/


All Articles