brew install peripheryapp/periphery/periphery
mint install peripheryapp/periphery
scan
Perintah pemindaian adalah fungsi utama Periferal. Untuk memulai penyiapan terpandu, cukup ubah ke direktori proyek Anda dan jalankan:
periphery scan --setup
Penyiapan terpandu hanya berfungsi untuk proyek Xcode dan SwiftPM, untuk menggunakan Periphery dengan sistem build non-Apple seperti Bazel, lihat Sistem Build.
Setelah menjawab beberapa pertanyaan, Periphery akan mencetak perintah pemindaian lengkap dan menjalankannya.
Penyiapan terpandu hanya dimaksudkan untuk tujuan perkenalan, setelah Anda terbiasa dengan Periphery, Anda dapat mencoba beberapa opsi lebih lanjut, yang semuanya dapat dilihat dengan periphery help scan
.
Untuk mendapatkan hasil yang koheren dari Periphery, penting untuk memahami implikasi target pembangunan yang Anda pilih untuk dianalisis. Misalnya, bayangkan sebuah proyek yang terdiri dari tiga target: Aplikasi, Lib, dan Tes. Target Aplikasi mengimpor Lib, dan target Pengujian mengimpor Aplikasi dan Lib. Jika Anda memberikan ketiganya pada opsi --targets
maka Periphery akan dapat menganalisis proyek Anda secara keseluruhan. Namun, jika Anda hanya memilih untuk menganalisis Aplikasi dan Lib, tetapi bukan Pengujian, Periphery mungkin melaporkan beberapa contoh kode yang tidak digunakan yang hanya direferensikan oleh Pengujian. Oleh karena itu, ketika Anda mencurigai Periphery memberikan hasil yang salah, penting untuk mempertimbangkan target yang Anda pilih untuk dianalisis.
Jika proyek Anda terdiri dari satu atau lebih kerangka kerja mandiri yang tidak juga berisi beberapa jenis aplikasi yang menggunakan antarmukanya, Anda harus memberi tahu Periphery untuk berasumsi bahwa semua deklarasi publik sebenarnya digunakan dengan menyertakan --retain-public
pilihan.
Untuk proyek yang merupakan campuran Objective-C & Swift, sangat disarankan agar Anda membaca tentang implikasinya terhadap hasil Anda.
Setelah Anda menentukan opsi yang sesuai untuk proyek Anda, Anda mungkin ingin menyimpannya dalam file konfigurasi YAML. Cara paling sederhana untuk mencapai hal ini adalah dengan menjalankan Periphery dengan opsi --verbose
. Di dekat awal keluaran, Anda akan melihat bagian [configuration:begin]
dengan konfigurasi Anda diformat sebagai YAML di bawah. Salin & tempel konfigurasi ke .periphery.yml
di root folder proyek Anda. Anda sekarang dapat menjalankan periphery scan
dan konfigurasi YAML akan digunakan.
Periphery pertama-tama membangun proyek Anda. Untuk proyek Xcode, skema yang disediakan melalui opsi --schemes
dibuat menggunakan xcodebuild
. Untuk proyek Swift Package Manager, target individual yang disediakan melalui opsi --targets
dibuat menggunakan swift build
. Kompiler Swift menggunakan teknik yang disebut indeks-sementara-pembangunan untuk mengisi penyimpanan indeks yang berisi informasi tentang struktur kode sumber proyek Anda.
Setelah proyek Anda dibangun, Periphery melakukan fase pengindeksan. Untuk setiap file sumber yang merupakan anggota target yang disediakan melalui opsi --targets
, Periphery memperoleh informasi strukturalnya dari penyimpanan indeks dan membuat representasi grafik internal proyek Anda sendiri. Periphery juga menganalisis pohon sintaksis abstrak (AST) setiap file untuk mengisi beberapa detail yang tidak disediakan oleh penyimpanan indeks.
Setelah pengindeksan selesai, Periphery menganalisis grafik untuk mengidentifikasi kode yang tidak digunakan. Fase ini terdiri dari sejumlah langkah yang mengubah grafik agar lebih mudah mengidentifikasi skenario spesifik dari kode yang tidak digunakan. Langkah terakhir menelusuri grafik dari akarnya untuk mengidentifikasi deklarasi yang tidak lagi direferensikan.
Tujuan Periphery adalah melaporkan contoh deklarasi yang tidak digunakan. Deklarasi adalah class
, struct
, protocol
, function
, property
, constructor
, enum
, typealias
, associatedtype
, dll. Seperti yang Anda harapkan, Periphery dapat mengidentifikasi deklarasi sederhana yang tidak direferensikan, misalnya class
yang tidak lagi digunakan di mana pun di komputer Anda. basis kode.
Periferal juga dapat mengidentifikasi contoh lebih lanjut dari kode yang tidak digunakan. Bagian berikut menjelaskan hal ini secara rinci.
Pinggiran dapat mengidentifikasi parameter fungsi yang tidak digunakan. Contoh parameter yang tidak digunakan juga dapat diidentifikasi dalam protokol dan deklarasi yang sesuai, serta parameter dalam metode yang diganti. Kedua skenario ini dijelaskan lebih lanjut di bawah.
Parameter fungsi protokol yang tidak digunakan hanya akan dilaporkan sebagai tidak digunakan jika parameter tersebut juga tidak digunakan di semua implementasi.
protocol Greeter {
func greet ( name : String )
func farewell ( name : String ) // 'name' is unused
}
class InformalGreeter : Greeter {
func greet ( name : String ) {
print ( " Sup " + name + " . " )
}
func farewell ( name : String ) { // 'name' is unused
print ( " Cya. " )
}
}
Tip
Anda dapat mengabaikan semua parameter yang tidak digunakan dari protokol dan fungsi yang sesuai dengan opsi
--retain-unused-protocol-func-params
.
Mirip dengan protokol, parameter fungsi yang diganti hanya dilaporkan sebagai tidak digunakan jika parameter tersebut juga tidak digunakan dalam fungsi dasar dan semua fungsi pengganti.
class BaseGreeter {
func greet ( name : String ) {
print ( " Hello. " )
}
func farewell ( name : String ) { // 'name' is unused
print ( " Goodbye. " )
}
}
class InformalGreeter : BaseGreeter {
override func greet ( name : String ) {
print ( " Sup " + name + " . " )
}
override func farewell ( name : String ) { // 'name' is unused
print ( " Cya. " )
}
}
Parameter protokol atau kelas yang tidak digunakan yang ditentukan dalam modul asing (misalnya Foundation) selalu diabaikan, karena Anda tidak memiliki akses untuk mengubah deklarasi fungsi dasar.
Parameter fungsi yang tidak digunakan yang hanya memanggil fatalError
juga diabaikan. Fungsi-fungsi seperti itu sering kali tidak diimplementasikan sebagai inisialisasi yang diperlukan dalam subkelas.
class Base {
let param : String
required init ( param : String ) {
self . param = param
}
}
class Subclass : Base {
init ( custom : String ) {
super . init ( param : custom )
}
required init ( param : String ) {
fatalError ( " init(param:) has not been implemented " )
}
}
Protokol yang disesuaikan dengan suatu objek tidak benar-benar digunakan kecuali jika itu juga digunakan sebagai tipe eksistensial, atau untuk mengkhususkan metode/kelas generik. Periferal mampu mengidentifikasi protokol-protokol redundan tersebut apakah protokol-protokol tersebut dipatuhi oleh satu, atau bahkan beberapa objek.
protocol MyProtocol { // 'MyProtocol' is redundant
func someMethod ( )
}
class MyClass1 : MyProtocol { // 'MyProtocol' conformance is redundant
func someMethod ( ) {
print ( " Hello from MyClass1! " )
}
}
class MyClass2 : MyProtocol { // 'MyProtocol' conformance is redundant
func someMethod ( ) {
print ( " Hello from MyClass2! " )
}
}
let myClass1 = MyClass1 ( )
myClass1 . someMethod ( )
let myClass2 = MyClass2 ( )
myClass2 . someMethod ( )
Di sini kita dapat melihat bahwa meskipun kedua implementasi someMethod
dipanggil, suatu objek tidak akan mengambil tipe MyProtocol
. Oleh karena itu, protokol itu sendiri berlebihan, dan tidak ada manfaatnya jika MyClass1
atau MyClass2
menyesuaikannya. Kita dapat menghapus MyProtocol
bersama dengan setiap kesesuaian yang berlebihan, dan hanya menyimpan someMethod
di setiap kelas.
Sama seperti metode normal atau properti suatu objek, properti dan metode individual yang dideklarasikan oleh protokol Anda juga dapat diidentifikasi sebagai tidak digunakan.
protocol MyProtocol {
var usedProperty : String { get }
var unusedProperty : String { get } // 'unusedProperty' is unused
}
class MyConformingClass : MyProtocol {
var usedProperty : String = " used "
var unusedProperty : String = " unused " // 'unusedProperty' is unused
}
class MyClass {
let conformingClass : MyProtocol
init ( ) {
conformingClass = MyConformingClass ( )
}
func perform ( ) {
print ( conformingClass . usedProperty )
}
}
let myClass = MyClass ( )
myClass . perform ( )
Di sini kita dapat melihat bahwa MyProtocol
digunakan sendiri, dan tidak dapat dihapus. Namun, karena unusedProperty
tidak pernah dipanggil pada MyConformingClass
, Periphery dapat mengidentifikasi bahwa deklarasi unusedProperty
di MyProtocol
juga tidak digunakan dan dapat dihapus bersama dengan implementasi unusedProperty
yang tidak digunakan.
Selain dapat mengidentifikasi enumerasi yang tidak digunakan, Periphery juga dapat mengidentifikasi kasus enum individual yang tidak digunakan. Enum biasa yang tidak dapat direpresentasikan secara mentah, yaitu yang tidak memiliki tipe nilai String
, Character
, Int
atau floating-point dapat diidentifikasi dengan andal. Namun, pencacahan yang memiliki tipe nilai mentah dapat bersifat dinamis, dan oleh karena itu harus diasumsikan digunakan.
Mari kita perjelas dengan contoh singkat:
enum MyEnum : String {
case myCase
}
func someFunction ( value : String ) {
if let myEnum = MyEnum ( rawValue : value ) {
somethingImportant ( myEnum )
}
}
Tidak ada referensi langsung ke kasus myCase
, jadi masuk akal untuk memperkirakan bahwa kasus tersebut mungkin tidak diperlukan lagi, namun jika kasus tersebut dihapus, kita dapat melihat bahwa somethingImportant
tidak akan pernah dipanggil jika someFunction
diberi nilai "myCase"
.
Properti yang ditugaskan tetapi tidak pernah digunakan diidentifikasi sebagai berikut, misalnya:
class MyClass {
var assignOnlyProperty : String // 'assignOnlyProperty' is assigned, but never used
init ( value : String ) {
self . assignOnlyProperty = value
}
}
Dalam beberapa kasus, ini mungkin merupakan perilaku yang diinginkan, oleh karena itu Anda memiliki beberapa opsi yang tersedia untuk membungkam hasil tersebut:
--retain-assign-only-property-types
. Jenis yang diberikan harus sesuai dengan penggunaannya dalam deklarasi properti (tanpa tanda tanya opsional), misalnya String
, [String]
, Set
. Periphery tidak dapat menyelesaikan tipe properti yang disimpulkan, oleh karena itu dalam beberapa kasus Anda mungkin perlu menambahkan anotasi tipe eksplisit ke properti Anda.--retain-assign-only-properties
. Deklarasi yang ditandai public
namun tidak dirujuk dari luar modul asalnya, diidentifikasi memiliki aksesibilitas publik yang berlebihan. Dalam skenario ini, anotasi public
dapat dihapus dari deklarasi. Menghapus aksesibilitas publik yang berlebihan mempunyai beberapa manfaat:
final
dengan secara otomatis menemukan semua deklarasi yang berpotensi mengesampingkan. kelas final
dioptimalkan lebih baik oleh kompiler. Analisis ini dapat dinonaktifkan dengan --disable-redundant-public-analysis
.
Periphery dapat mendeteksi impor target yang belum terpakai yang telah dipindai, yaitu target yang ditentukan dengan argumen --targets
. Itu tidak dapat mendeteksi impor target lain yang tidak digunakan karena file sumber Swift tidak tersedia dan penggunaan @_exported
tidak dapat diamati. @_exported
bermasalah karena mengubah antarmuka publik suatu target sehingga deklarasi yang diekspor oleh target tidak lagi harus dideklarasikan oleh target yang diimpor. Misalnya, Foundation
menargetkan Dispatch
ekspor, di antara target lainnya. Jika ada file sumber tertentu yang mengimpor Foundation
dan mereferensikan DispatchQueue
tetapi tidak ada deklarasi lain dari Foundation
, maka impor Foundation
tidak dapat dihapus karena juga akan membuat jenis DispatchQueue
tidak tersedia. Oleh karena itu, untuk menghindari kesalahan positif, Periphery hanya mendeteksi impor target yang belum terpakai yang telah dipindai.
Periphery kemungkinan akan menghasilkan kesalahan positif untuk target dengan campuran Swift dan Objective-C, karena Periphery tidak dapat memindai file Objective-C. Oleh karena itu disarankan untuk menonaktifkan deteksi impor yang tidak digunakan untuk proyek dengan jumlah Objective-C yang signifikan, atau secara manual mengecualikan target bahasa campuran dari hasil.
Periferal tidak dapat menganalisis kode Objective-C karena tipe dapat diketik secara dinamis.
Secara default, Periphery tidak berasumsi bahwa deklarasi yang dapat diakses oleh runtime Objective-C sedang digunakan. Jika proyek Anda merupakan campuran dari Swift & Objective-C, Anda dapat mengaktifkan perilaku ini dengan opsi --retain-objc-accessible
. Deklarasi Swift yang dapat diakses oleh runtime Objective-C adalah deklarasi yang secara eksplisit dianotasi dengan @objc
atau @objcMembers
, dan kelas yang mewarisi NSObject
baik secara langsung atau tidak langsung melalui kelas lain.
Alternatifnya, --retain-objc-annotated
hanya dapat digunakan untuk mempertahankan deklarasi yang dianotasi secara eksplisit dengan @objc
atau @objcMembers
. Tipe yang mewarisi NSObject
tidak dipertahankan kecuali tipe tersebut memiliki anotasi eksplisit. Opsi ini mungkin mengungkap lebih banyak kode yang tidak digunakan, namun dengan peringatan bahwa beberapa hasil mungkin salah jika deklarasi tersebut sebenarnya digunakan dalam kode Objective-C. Untuk mengatasi hasil yang salah ini, Anda harus menambahkan anotasi @objc
ke deklarasi.
Swift mensintesis kode tambahan untuk tipe Codable
yang tidak terlihat oleh Periphery, dan dapat menghasilkan kesalahan positif untuk properti yang tidak direferensikan secara langsung dari kode yang tidak disintesis. Jika proyek Anda berisi banyak tipe seperti itu, Anda dapat mempertahankan semua properti pada tipe Codable
dengan --retain-codable-properties
. Alternatifnya, Anda dapat mempertahankan properti hanya pada tipe Encodable
dengan --retain-encodable-properties
.
Jika kesesuaian Codable
dideklarasikan oleh protokol dalam modul eksternal yang tidak dipindai oleh Periphery, Anda dapat menginstruksikan Periphery untuk mengidentifikasi protokol sebagai Codable
dengan --external-codable-protocols "ExternalProtocol"
.
Kelas apa pun yang mewarisi XCTestCase
secara otomatis dipertahankan bersama dengan metode pengujiannya. Namun, ketika suatu kelas mewarisi XCTestCase
secara tidak langsung melalui kelas lain, misalnya UnitTestCase
, dan kelas tersebut berada di target yang tidak dipindai oleh Periphery, Anda perlu menggunakan opsi --external-test-case-classes UnitTestCase
untuk menginstruksikan Periphery untuk perlakukan UnitTestCase
sebagai subkelas XCTestCase
.
Jika proyek Anda berisi file Pembuat Antarmuka (seperti storyboard dan XIB), Periphery akan mempertimbangkannya saat mengidentifikasi deklarasi yang tidak digunakan. Namun, Periphery saat ini hanya mengidentifikasi kelas yang tidak digunakan. Keterbatasan ini terjadi karena Periphery belum sepenuhnya mengurai file Interface Builder (lihat edisi #212). Karena prinsip desain Periphery yang menghindari positif palsu, diasumsikan bahwa jika suatu kelas direferensikan dalam file Pembuat Antarmuka, semua IBOutlets
dan IBActions
-nya akan digunakan, meskipun mungkin tidak ada dalam kenyataan. Pendekatan ini akan direvisi untuk secara akurat mengidentifikasi IBActions
dan IBOutlets
yang tidak digunakan setelah Periphery memperoleh kemampuan untuk mengurai file Interface Builder.
Untuk alasan apa pun, Anda mungkin ingin menyimpan beberapa kode yang tidak digunakan. Perintah komentar kode sumber dapat digunakan untuk mengabaikan deklarasi tertentu, dan mengecualikannya dari hasil.
Perintah abaikan komentar dapat ditempatkan langsung pada baris di atas deklarasi apa pun untuk mengabaikannya, dan semua deklarasi turunan:
// periphery:ignore
class MyClass { }
Anda juga dapat mengabaikan parameter fungsi tertentu yang tidak digunakan:
// periphery:ignore:parameters unusedOne,unusedTwo
func someFunc ( used : String , unusedOne : String , unusedTwo : String ) {
print ( used )
}
// periphery:ignore:all
dapat ditempatkan di bagian atas file sumber untuk mengabaikan seluruh isi file. Perhatikan bahwa komentar harus ditempatkan di atas kode apa pun, termasuk pernyataan import.
Perintah komentar juga mendukung komentar tambahan setelah tanda hubung sehingga Anda bisa menyertakan penjelasan pada baris yang sama:
// periphery:ignore - explanation of why this is necessary
class MyClass { }
Sebelum menyiapkan integrasi Xcode, kami sangat menyarankan Anda terlebih dahulu mengaktifkan Periphery di terminal, karena Anda akan menggunakan perintah yang sama persis melalui Xcode.
Pilih proyek Anda di Project Navigator dan klik tombol + di kiri bawah bagian Target. Pilih Lintas platform dan pilih Agregat . Tekan Berikutnya.
Periphery adalah proyek gairah yang membutuhkan banyak upaya untuk mempertahankan dan mengembangkannya. Jika menurut Anda Periphery berguna, harap pertimbangkan untuk mensponsori melalui GitHub Sponsors.
Terima kasih khusus ditujukan kepada para sponsor yang murah hati berikut ini:
SaGa Corp mengembangkan teknologi unik untuk pelaku keuangan dan pelanggannya.
Emerge Tools adalah rangkaian produk revolusioner yang dirancang untuk meningkatkan aplikasi seluler dan tim yang membangunnya.