SwiftLintの記事はシリーズになっています。
記事を順番に読み進めると、SwiftLintを使いこなせるようになります。
- Swiftの静的解析ツール「SwiftLint」のセットアップ方法
- SwiftLintの全ルール一覧(Swift 4.2版)
- SwiftLintで追加・変更・廃止されたルールまとめ(Swift 4.2→5.1.2版)
- SwiftLintで追加・廃止されたルールまとめ(Swift 5.1.2→5.3.1版)
- SwiftLintのオレオレカスタムルール一覧
- SwiftLintのAnalyzeを使って高度な解析をする方法 ←イマココ
- SwiftLintの設定ファイルをサーバーに配置して共有する方法
- SwiftLintの「Currently running SwiftLint x.y.z but configuration specified version a.b.c.」エラーの解決法
はじめに
本記事は Swift/Kotlin愛好会 Advent Calendar 2020 の8日目の記事です。
SwiftLintのAnalyze機能を紹介します。
環境
- OS:macOS Big Sur 11.0.1
- Swift:5.3.1
- Xcode:12.2 (12B45b)
- SwiftLint:0.41.0
本記事で説明しないこと
- SwiftLintの概要やセットアップ方法
私が以前書いた記事を参考にしてください。
Swiftの静的解析ツール「SwiftLint」のセットアップ方法 - Qiita - SwiftのASTについて
そもそも私が理解できていないので説明できません。
詳しく学びたい人は以下の動画が参考になると思います。
try! Swift Tokyo 2018 - AST Meta-programming - YouTube
SwiftLintの「Analyze」とは?
かんたんにいうと「ビルドログのASTを使って解析する」機能です。
Analyzeは実験的な機能であり、いつでも変更される可能性があるとのことです。
Analyzeの使い方
Analyzeの使い方を紹介します。
設定ファイルの作成
Analyze用のルールを設定ファイルの analyzer_rules
に記述します。
analyzer_rules:
#- explicit_self # 関数は `self.` を付けずに呼び出したいため
- unused_declaration
- unused_import
公式ドキュメントで「Analyzer rule: Yes」となっているルールが対象で、私が見た限りでは以下の3つのみでした。
ルール | 説明 | 参考リンク |
---|---|---|
Explicit Self |
self. を明示的に書くべき |
https://qiita.com/uhooi/items/7f5d6cf2b240f60ba1ed#explicit-self |
Unused Declaration | 宣言した変数やクラスなどは使われるべき | https://qiita.com/uhooi/items/8e9767c2e746f4171ded#unused-declaration |
Unused Import | インポートされたモジュールは使われるべき | https://qiita.com/uhooi/items/7f5d6cf2b240f60ba1ed#unused-import |
私は同一クラス内の関数を self.
なしで呼び出したいため、下の2つのみ有効にしています。
Analyzeの実行
READMEに記載されている通り xcodebuild
コマンドでログをファイルに出力し、それを --compiler-log-path
オプションで渡します。
コマンドが長くなるので、私は Makefile
に定義して make analyze
で実行できるようにしました。
make build-debug
はCIでビルドが通るかの確認にも使っているため、 swiftlint analyze
に対して必要最小限にはなっていません。
PRODUCT_NAME := UhooiPicBook # 製品名を適宜変更する
PROJECT_NAME := ${PRODUCT_NAME}.xcodeproj
SCHEME_NAME := ${PRODUCT_NAME}
TEST_SDK := iphonesimulator
TEST_CONFIGURATION := Debug
TEST_PLATFORM := iOS Simulator
TEST_DEVICE ?= iPhone 12 Pro Max
TEST_OS ?= 14.2
TEST_DESTINATION := 'platform=${TEST_PLATFORM},name=${TEST_DEVICE},OS=${TEST_OS}'
XCODEBUILD_BUILD_LOG_NAME := xcodebuild_build.log
.PHONY: analyze
analyze: # Analyze with SwiftLint
$(MAKE) build-debug
mint run swiftlint swiftlint analyze --autocorrect --compiler-log-path ./${XCODEBUILD_BUILD_LOG_NAME}
.PHONY: build-debug
build-debug: # Xcode build for debug
set -o pipefail \
&& xcodebuild \
-sdk ${TEST_SDK} \
-configuration ${TEST_CONFIGURATION} \
-project ${PROJECT_NAME} \
-scheme ${SCHEME_NAME} \
-destination ${TEST_DESTINATION} \
build \
| tee ./${XCODEBUILD_BUILD_LOG_NAME} \
| bundle exec xcpretty --color
--autocorrect
オプションを付けると自動で修正されるのでオススメです。
make analyze
を実行します。
$ make analyze
# ...
# `make build-debug` のログは省略
# ...
mint run swiftlint swiftlint analyze --autocorrect --compiler-log-path ./xcodebuild_build.log
Loading configuration from '.swiftlint.yml'
Correcting Swift files at paths
Collecting 'Debug.swift' (1/23)
Collecting 'ActivityRouter.swift' (2/23)
# ...
Correcting 'MonsterListInteractor.swift' (15/23)
/Users/uhooi/Documents/Repos/GitHub/uhooi/UhooiPicBook/UhooiPicBook/Repository/Spotlight/SpotlightRepository.swift:10:1 Corrected Unused Import
Correcting 'MonsterListViewController.swift' (16/23)
# ...
Correcting 'MonsterDetailViewController.swift' (22/23)
Correcting 'SceneDelegate.swift' (23/23)
Done correcting 23 files!
.../SpotlightRepository.swift:10:1 Corrected Unused Import
のログからわかる通り、 SpotlightRepository.swift
の10行1列目に未使用のモジュールがインポートされているので自動で削除されました。
git diff
で確認します。
$ git diff
diff --git a/UhooiPicBook/Repository/Spotlight/SpotlightRepository.swift b/UhooiPicBook/Repository/Spotlight/SpotlightRepository.swift
index e435a9b..ba45ffb 100644
--- a/UhooiPicBook/Repository/Spotlight/SpotlightRepository.swift
+++ b/UhooiPicBook/Repository/Spotlight/SpotlightRepository.swift
@@ -7,7 +7,6 @@
import CoreGraphics.CGGeometry
import CoreSpotlight
-import MobileCoreServices
/// @mockable
protocol SpotlightRepository: AnyObject { // swiftlint:disable:this file_types_order
確かにインポート文が削除されています。
今回は一度実行済みなので1箇所のみ削除されましたが、初回は大量の import Foundation
と import UIKit
が削除されて気持ちいいです。
おまけ①: 使用しているインポートが削除される場合がある
先ほど削除された import MobileCoreServices
ですが、実はないとビルドエラーになります。
理由としては、iOS 13以前で kUTTypeData
の呼び出しに使っているためです。
private func createAttributeSet(title: String, contentDescription: String, thumbnailData: Data?) -> CSSearchableItemAttributeSet {
let attributeSet: CSSearchableItemAttributeSet
if #available(iOS 14.0, *) {
attributeSet = .init(contentType: .data)
} else {
attributeSet = .init(itemContentType: kUTTypeData as String) // !!!: ここでビルドエラーになる
}
// ...
// 中略
// ...
return attributeSet
}
xcodebuild
の -destination
オプションでiOS 14.2を指定しているためだと思われます。
仕方ないので手動でインポート文を戻しました。
このようなケースはまれですが、自動修正する場合はコミット前にビルドが通るか確認しましょう。
おまけ②: Analyzeの実行タイミング
READMEに記載されている通り、Analyzeには時間がかかります。
そのため、Xcodeのビルドフェイズで毎回実行するのを避けています。
現在は手動実行しているのですが、それだと漏れる可能性があるため、いい方法を考え中です。
おわりに
これで未使用のインポート文を大量に削除できます!
以上、 Swift/Kotlin愛好会 Advent Calendar 2020 の8日目の記事でした。
明日はまだ埋まっていません。ぜひ こちら から参加しましょう!
@Sho-heikun さんが参加してくださりました!
ありがとうございます
ウホーイさんを1人にさせるわけにはいかないので明日分入れときました! 1人で1週間埋めたいとかあったらキャンセルしますので教えてください!w
— ShoHeiKun (@ShoHeiKun3) December 8, 2020