Go lintpack: pengelola linter yang dapat dikompilasi


lintpack adalah utilitas untuk membangun linter (penganalisa statis), yang ditulis menggunakan API yang disediakan. Berdasarkan itu, penganalisa statis go-kritik , akrab bagi sebagian orang, sekarang sedang ditulis ulang.


Hari ini kami akan lintpack secara lebih rinci apa lintpack dari sudut pandang pengguna.


Pada awalnya adalah go-critic ...


Go-kritikus dimulai sebagai proyek percontohan yang merupakan kotak pasir untuk prototyping hampir semua ide analisis statis untuk Go.


Kejutan yang menyenangkan adalah bahwa beberapa orang memang mengirim implementasi detektor berbagai masalah dalam kode. Semuanya terkendali sampai utang teknis mulai menumpuk, yang praktis tidak ada yang bisa dihilangkan. Orang-orang masuk, menambahkan verifikasi, dan kemudian menghilang. Siapa yang kemudian harus memperbaiki kesalahan dan memodifikasi implementasi?


Peristiwa penting adalah proposal untuk menambahkan pemeriksaan yang memerlukan konfigurasi tambahan, yaitu, yang bergantung pada pengaturan lokal untuk proyek. Contohnya adalah mengungkapkan keberadaan header hak cipta dalam file (header lisensi) menggunakan template khusus atau melarang impor beberapa paket dengan proposal dari alternatif yang diberikan.


Kesulitan lain adalah diperpanjang. Tidak nyaman bagi semua orang untuk mengirim kode mereka ke repositori orang lain. Beberapa ingin menghubungkan cek mereka secara dinamis sehingga mereka tidak perlu memodifikasi kode sumber go-critic .


Kesimpulannya, berikut adalah masalah yang menghalangi pengembangan go-critic :


  • Banyak kerumitan. Terlalu banyak dukungan, keberadaan kode tanpa pemilik.
  • Kualitas rata-rata rendah. experimental berarti "hampir siap digunakan" dan "lebih baik tidak berjalan sama sekali."
  • Terkadang sulit untuk memutuskan apakah akan memasukkan verifikasi dalam go-critic , dan menolaknya bertentangan dengan filosofi desain asli.
  • Orang yang berbeda melihat go-critic berbeda. Kebanyakan ingin memilikinya sebagai CI linter, yang dilengkapi dengan gometalinter .

Untuk membatasi jumlah ketidaksesuaian dan interpretasi proyek yang tidak konsisten, sebuah manifesto ditulis.


Jika Anda ingin konteks historis tambahan dan bahkan lebih banyak berpikir tentang kategorisasi alat analisis statis, Anda dapat mendengarkan rekaman GoCritic, alat analisis statis baru untuk Go . Pada saat itu, lintpack belum ada, tetapi beberapa ide lahir pada hari itu, setelah laporan.

Tetapi bagaimana jika kita tidak perlu menyimpan semua cek dalam satu repositori?


Bertemu - lintpack




go-critic terdiri dari dua komponen utama:


  1. Pelaksanaan pemeriksaan sendiri.
  2. Program yang mengunduh paket yang divalidasi Go dan menjalankan validasinya.

Tujuan kami: untuk dapat menyimpan cek untuk linter di repositori yang berbeda dan mengumpulkannya ketika diperlukan.


lintpack melakukan hal itu. Ini mendefinisikan fungsi yang memungkinkan Anda untuk menggambarkan cek Anda sedemikian rupa sehingga Anda dapat menjalankannya melalui linter yang dihasilkan.


Paket yang diimplementasikan menggunakan lintpack sebagai kerangka kerja akan disebut lintpack kompatibel dengan lintpack atau lintpack .

Jika go-critic diimplementasikan berdasarkan lintpack , semua cek dapat dibagi menjadi beberapa repositori. Salah satu opsi untuk pemisahan mungkin sebagai berikut:


  1. Set utama di mana semua cek stabil dan didukung mendapatkan.
  2. contrib repository di mana kodenya terletak yang terlalu eksperimental atau tidak memiliki pengelola.
  3. Pemeriksaan yang dapat disesuaikan untuk proyek tertentu.

Poin pertama adalah sangat penting sehubungan dengan integrasi go-kritik ke golangci-lint .


Jika Anda tetap pada level go-critic , maka bagi pengguna hampir tidak ada yang berubah. lintpack membuat linter yang hampir identik, sementara golangci-lint merangkum semua detail implementasi yang berbeda.


Tetapi sesuatu telah berubah. Jika lintpack baru dibuat berdasarkan lintpack , Anda akan memiliki pilihan diagnostik siap pakai yang lebih kaya untuk menghasilkan linter. Bayangkan sejenak bahwa ini benar, dan ada lebih dari 10 set cek berbeda di dunia.


Mulai cepat



Untuk memulai, Anda perlu menginstal lintpack sendiri:


 # lintpack    `$(go env GOPATH)/bin`. go get -v github.com/go-lintpack/lintpack/... 

Buat linter menggunakan paket tes dari lintpack :


 lintpack build -o mylinter github.com/go-lintpack/lintpack/checkers 

Set termasuk panicNil , yang menemukan panic(nil) dalam kode dan meminta untuk menggantinya dengan sesuatu yang dapat dibedakan, karena jika tidak recover() tidak akan dapat mengatakan apakah panic dipanggil dengan argumen nil , atau tidak ada kepanikan sama sekali.


Contoh dengan panik (nihil)


Kode di bawah ini mencoba menjelaskan nilai yang diperoleh dari recover() :


 r := recover() fmt.Printf("%T, %v\n", r, r) 

Hasilnya akan sama untuk panic(nil) dan untuk program yang tidak panic(nil) .


Contoh penerapan perilaku yang dijelaskan .




Anda dapat memulai linter pada file yang terpisah, dengan argumen tipe ./... atau paket (berdasarkan jalur impornya).


 ./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 

Secara default, pemeriksaan ini juga merespons panic(interface{}(nil)) . Untuk mengganti perilaku ini, setel skipNilEfaceLit menjadi true . Anda dapat melakukan ini melalui baris perintah:


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

penggunaan untuk cmd / lintpack dan linter yang dihasilkan


Baik lintpack dan linter yang dihasilkan menggunakan argumen pertama untuk memilih sub-perintah. Daftar sub-perintah yang tersedia dan contoh peluncurannya dapat diperoleh dengan memanggil utilitas tanpa argumen.


 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 

Misalkan kita menamai linter yang dibuat dengan nama 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 

Bendera -help tersedia untuk beberapa sub-perintah, yang menyediakan informasi tambahan (Saya memotong beberapa baris terlalu lebar):


 ./gocritic check -help #     . 



Dokumentasi cek yang diinstal


Jawaban untuk pertanyaan "bagaimana mencari tahu tentang parameter sangat skipNilEfaceLit?" - baca manual mewah (RTFM)!


Semua dokumentasi tentang cek yang diinstal ada di dalam mylinter . Dokumentasi ini tersedia melalui sub-perintah 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) 

Seperti dukungan untuk templat dalam go list -f , Anda dapat meneruskan dalam baris templat yang bertanggung jawab atas format output dokumentasi, yang dapat berguna saat menulis dokumen penurunan harga.


Di mana mencari cek untuk instalasi?


Untuk menyederhanakan pencarian suite lintpack berguna, ada daftar terpusat paket yang kompatibel dengan lintpack : https://go-lintpack.imtqy.com/ .


Berikut beberapa daftarnya:



Daftar ini diperbarui secara berkala dan terbuka untuk permintaan tambahan. Paket-paket ini dapat digunakan untuk membuat linter.


Perintah di bawah ini membuat linter yang berisi semua cek dari daftar di atas:


 #   ,      #   Go . go get -v github.com/go-critic/go-critic/checkers go get -v github.com/go-critic/checkers-contrib # build   . lintpack build \ github.com/go-critic/go-critic/checkers \ github.com/go-critic/checkers-contrib 

lintpack build mencakup semua pemeriksaan pada tahap kompilasi, linter yang dihasilkan dapat ditempatkan di lingkungan di mana tidak ada kode sumber untuk implementasi diagnostik yang dipasang, semuanya seperti biasa dengan penghubung statis.


Lampiran Paket Dinamis


Selain rakitan statis, dimungkinkan untuk memuat plugin yang menyediakan pemeriksaan tambahan.


Kekhasannya adalah bahwa implementasi pemeriksa tidak tahu apakah itu akan digunakan untuk kompilasi statis atau akan dimuat sebagai plug-in. Tidak diperlukan perubahan pada kode.


Misalkan kita ingin menambahkan panicNil ke linter, tetapi kita tidak dapat membangunnya kembali dari semua sumber yang digunakan selama kompilasi pertama.


  1. Buat linterPlugin.go :

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

  1. Bangun perpustakaan dinamis:

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

  1. Jalankan linter dengan parameter -pluginPath :

 ./linter check -pluginPath=linterPlugin.so bytes 

Peringatan: Dukungan untuk modul dinamis diimplementasikan melalui paket plugin yang tidak berfungsi pada Windows.

Bendera -verbose dapat membantu Anda mengetahui cek mana yang aktif atau tidak, dan yang paling penting, itu akan menunjukkan filter mana yang telah menonaktifkan pemeriksaan.


Contoh dengan -verbose


Perhatikan bahwa panicNil ditampilkan dalam daftar cek yang disertakan. Jika kita menghapus argumen -pluginPath, itu tidak akan benar lagi.


 ./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 # ...   . 



Perbandingan dengan gometalinter dan golangci-lint


Untuk menghindari kebingungan, ada baiknya menggambarkan perbedaan utama antara proyek.


gometalinter dan golangci-lint utamanya mengintegrasikan linters yang lain, seringkali sangat berbeda, menyediakan akses yang mudah untuk mereka. Mereka menargetkan pengguna akhir yang akan menggunakan analisis statis.


lintpack menyederhanakan pembuatan linter baru, menyediakan kerangka kerja yang membuat berbagai paket, diimplementasikan berdasarkan basisnya, kompatibel dalam file yang dapat dieksekusi yang sama. Pemeriksaan ini (untuk golangci-lint) atau file yang dapat dieksekusi (untuk gometalinter) kemudian dapat disematkan dalam meta-linters tersebut.


Misalkan salah satu cek yang kompatibel dengan lintpack adalah bagian dari golangci-lint . Jika ada masalah terkait dengan kegunaannya, ini mungkin menjadi tanggung jawab golangci-lint , tetapi jika itu adalah kesalahan dalam melaksanakan verifikasi itu sendiri, maka ini adalah masalah penulis verifikasi, ekosistem lintpack.


Dengan kata lain, proyek-proyek ini menyelesaikan berbagai masalah.


Bagaimana dengan kritikus?


Proses porting go-critic ke lintpack telah selesai, checker dapat ditemukan di repositori go-kritik / checker .


 #  go-critic : go get -v github.com/go-critic/go-critic/... #  go-critic : lintpack -o gocritic github.com/go-critic/go-critic/checkers 

Tidak masuk akal untuk menggunakan go-critic luar golangci-lint , tetapi lintpack dapat memungkinkan Anda untuk menginstal cek yang tidak termasuk dalam go-critic . Misalnya, ini mungkin diagnosa yang ditulis oleh Anda.


Untuk dilanjutkan


Anda akan belajar cara membuat cek yang kompatibel dengan lintpack Anda sendiri di artikel berikutnya.


Di sana kami akan menganalisis keuntungan apa yang Anda dapatkan ketika menerapkan lintpack berbasis lintpack Anda dibandingkan dengan implementasi dari awal.


Saya harap Anda memiliki selera untuk cek baru untuk Go. Biarkan saya tahu berapa banyak analisis statis menjadi terlalu banyak, kami akan segera menyelesaikan masalah ini bersama-sama.

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


All Articles