[SwiftLint] no_empty_bodyルールについて
概要
SwiftLintに新しく実装された no_empty_body
ルールの紹介をする。
SwiftLintとは
SwiftLintとは、Swiftのコード静的解析ツールである。
Linterのルールを設定できるため、複数の開発者がいるプロジェクトでも、コードベース内で一貫したコーディングルールを適用させることができる。
最初から有効になっているDefaultRuleと、必要に応じて有効にすることのできるOpt-In Ruleを合わせて、240のルールが実装されている。(2024/7/22現在)
丁寧にSwiftLintの解説をしてくれている記事
no_empty_body
Rule
どんなルール?
CodeBlockに、コードもコメントもない場合にwarningを出す。
func sampleFunc() {} //<- warning
No Empty Block Violation: Code blocks should contain at least one statement or comment (no_empty_block)
(日本語訳)コードブロックは、少なくとも一行 コードかコメントを含んでいるべきである。
CodeBlockは、SwiftSyntaxの定義にもとづいて、以下のものが該当する。
-
AccessorDeclSyntax
(didSet
などの中身) -
CatchClauseSyntax
(do-catchのcatch
の中身) -
DeferStmtSyntax
(defer
の中身) -
DeinitializerDeclSyntax
(deinit
の中身) -
DoStmtSyntax
(do-catchのdo
の中身) -
ForStmtSyntax
(for
-loopの中身) -
FunctionDeclSyntax
(関数の中身) -
GuardStmtSyntax
(guard
の中身) -
IfExprSyntax
(if
やelse
の中身) -
InitializerDeclSyntax
(init
の中身) -
RepeatStmtSyntax
(repeat
の中身) -
WhileStmtSyntax
(while
の中身)
guard
のコードブロックが空の場合は、コンパイルエラーになるため、空のguard
ブロックにはwarningを出さない。
ルールを実装したモチベーション
他のLinterには同様のルールが実装されている。(e.g. eslint)
Swiftでも、SonarqubeのLinter(SonarLint)では、そのルールがすでに実装されている。
Sonarqubeはコードの静的解析ツールだが、Xcodeの上で動かすことができない。
CI上などで使用されることが多いが、手元では動作させることができないので、CIを走らせたときにはじめてcode-smellに気付くことが多かった。
Xcode上で動作させるLinterとして有名なSwiftlintに同様のルールが実装されれば、code-smellにより早く気付けるようになるので嬉しい。
そのため、no_empty_body
ルールを実装した。(PRを出した)
ルールの目的
中身が空のコードブロックからは、それが意図的に空なのか実装し忘れなのかを判断できない。
そのため、読者の混乱を生み、可読性を害し、メンテナンスしにくいという問題を生じる可能性がある。
もしそれが実装のし忘れなら、warningを出すことでそれに気付くことができる。
もしそれがoverrideされることを予想して意図的に空なら、コメントでそれを説明するべきである。
OKな例
OKな例
//関数
func f() {
/* do something */
}
// Accessor(e.g willSet)
var flag = true {
willSet { /* do something */ }
}
// initとdeinit
class Apple {
init() { /* do something */ }
deinit { /* do something */ }
}
// For文
for _ in 0..<10 { /* do something */ }
// do-catch文
do {
/* do something */
} catch {
/* do something */
}
// defer
func f() {
defer {
/* do something */
}
print("other code")
}
// if-else文
if flag {
/* do something */
} else {
/* do something */
}
// repeat-while文
repeat { /* do something */ } while (flag)
// while文
while i < 10 { /* do something */ }
NGな例
NGな例
//関数
func f() {}
// Accessor(e.g willSet)
var flag = true {
willSet {}
}
// initとdeinit
class Apple {
init() {}
deinit {}
}
// For文
for _ in 0..<10 {}
// do-catch文
do {
} catch {
}
// defer
func f() {
defer {}
print("other code")
}
// if-else文
if flag {
} else {
}
// repeat-while文
repeat { } while (flag)
// while文
while i < 10 {}
設定の方法(Configuration)
有効にする
.swiftlint.yml
に以下を記述する。
opt_in_rules: # some rules are turned off by default, so you need to opt-in
- no_empty_block
一部のルールを無効にする
.swiftlint.yml
に以下を記述する。
opt_in_rules: # some rules are turned off by default, so you need to opt-in
- no_empty_block
no_empty_block:
severity: error # warningの代りに errorを出す。
disabled: ["function_bodies", "initializer_bodies", "statement_blocks"] # list内で記述したルールを無効にする。
Discussion