353.PMD(3)
初回:2024/02/28
前回は、PMDのカスタマイズを行いました。とはいうものの、不要なルールを無効にするだけの簡単な作業でした。
P子「それだけでも結構有効よね」※1
私の個人的な意見としては、この手のルールは『かるーく』で良いと思っています。なので、quickstart.xml をベースに不要なルールを無効にするだけで良いと思いますが、もう少し細かい設定を行いたいという要望もあると思います。今回はそのようなカスタマイズの方法を書いてみたいと思います。
1.quickstart
前回、quickstart.xml から無効にするルールを、exclude で指定したと思います。
<?xml version="1.0" encoding="UTF-8"?> <ruleset name="customset" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> <description> Github Collect Rule Set https://docs.pmd-code.org/latest/pmd_rules_java.html </description> <rule ref="rulesets/java/quickstart.xml" > <exclude name="UnnecessaryImport"/> <exclude name="UnnecessaryConstructor"/> </rule> </ruleset>
私が個人的にお勧めするのは、このquickstart.xmlで既存のソースをチェックして一旦問題個所を洗い出したうえで、対応が難しい、数が多い、実態に合わないなどのルールを除外し、基本的に警告が 0件になるようにします。
P子「もちろん、対応できるものは対応してからという事ですよね」
その通りです。つまり、ソース修正都度、このチェックを行って、0件であれば問題なし、そうでなければ警告箇所は必ず直すというルールにすれば、新人でも社外発注であろうが、判りやすいと思います。
以前も書きましたが、PMD の Rule Reference → Java Rules → Index のページで『quickstart.xml』で検索すれば、quickstart で使われているルールが見えると思います。
《参考資料1》
https://docs.pmd-code.org/latest/pmd_rules_java.html
Rule Reference → Java Rules → Index のページ
例えば、今回はこのルールの中から、UnusedPrivateField をカスタマイズしてみます。
まず、quickstartのルールから『UnusedPrivateField』を見つけリンクをたどります。
https://docs.pmd-code.org/latest/pmd_rules_java_bestpractices.html#unusedprivatefield
このルールを読んでいくと、This rule has the following properties: という箇所が現れます。
Name | Default Value | Description |
---|---|---|
ignoredFieldNames | serialVersionUID , serialPersistentFields | 未使用チェックで無視されるフィールド名 |
reportForAnnotations | とにかく報告する必要がある注釈タイプの完全修飾名。 未使用のフィールドにこれらの注釈のいずれかがある場合、それが報告されます。 他の注釈が付いている場合でも、使用されているとみなされ、報告されません。 |
※ google翻訳しています。
さて、この中で、ignoredFieldNames をカスタマイズしてみます。私が作成するクラスには、serialVersionUID とは別に、VERSION というprivate static final の定数を使用して各クラスのバージョン情報を、javadoc で収集・管理しています。なので、この定数はシステムとしては未使用定数となり警告が発生しますが、未使用変数のチェックを除外するのも『なんだかなー』と思いますので、カスタマイズしてみます。
<rule ref="category/java/bestpractices.xml/UnusedPrivateField" > <properties> <property name="ignoredFieldNames" value="serialVersionUID,VERSION" /> </properties> </rule>
初期値の、serialVersionUID は残しておきます。独自設定した VERSION を追記します。これで、未使用の VERSION 変数はチェック対象から外されます。
2.もう少し複雑なカスタマイズ
変数名やメソッド名は独自のルールを定められている会社も多いかもしれません。私も少し独自ルールを作っていますので、逆にそれらのルールに合うようにチェックする方法を示します。
ローカル変数とfinal変数には、大文字とアンダーバーのみの変数名も許可しておきます。
<rule ref="category/java/codestyle.xml/LocalVariableNamingConventions" > <properties> <property name="localVarPattern" value="[a-z][a-zA-Z0-9]*|[A-Z0-9_]*" /> <property name="finalVarPattern" value="[a-z][a-zA-Z0-9]*|[A-Z0-9_]*" /> </properties> </rule>
初期設定は、小文字で始まり、アンダーバーは使用できません。
<property name="localVarPattern" value="[a-z][a-zA-Z0-9]*" /> <property name="finalVarPattern" value="[a-z][a-zA-Z0-9]*" /> <property name="catchParameterPattern" value="[a-z][a-zA-Z0-9]*" />
これらの正規表現での指定は、FormalParameterNamingConventions やClassNamingConventionsやFieldNamingConventions のルールでもカスタマイズできます。
3.さらに複雑なカスタマイズ
さて、LongVariable ですが、制限桁数が、minimum パラメータで初期値が 17 です。実は私のシステムの中に、すべてが大文字の定数が定義されていますが、これが 17 文字を超えます。かといって、17文字の制限を増やすというのも安直です。なので、桁数制限を変えずにすべてが大文字の場合だけ除外します。
さて、ドキュメントにはパラメータが書かれていませんが、This rule is defined by the following XPath expression: というのが書かれています。
翻訳すると、『このルールは、次の XPath 式によって定義されます。』と書かれています。
さて、どこに書かれているかというと、ルールの本当のXMLソースを確認してみましょう。LongVariable の横のリンクから飛びます。
https://github.com/pmd/pmd/blob/master/pmd-java/src/main/resources/category/java/codestyle.xml
これは、すべての codestyle.xml の定義なので、LongVariable の定義を検索します。
properties の property の name="xpath" の value の定義を確認します。
<properties> <property name="minimum" type="Integer" description="The variable length reporting threshold" min="1" max="100" value="17"/> <property name="xpath"> <value> <![CDATA[ //VariableId[string-length(@Name) > $minimum] ]]> </value> </property> </properties>
P子「ドキュメントに書かれていた定義と少し異なっているわね」
ドキュメントは余りあてにならないので、ソースをカスタマイズしましょう。
//VariableId[string-length(@Name) > $minimum]
↓
//VariableId[string-length(@Name) > $minimum and upper-case(@Name) != @Name]
upper-case(@Name) != @Name を追加しました。これで、すべてが大文字の定数は文字数チェックから除外できます。
ドキュメントに書かれていないルールのカスタマイズをもう一つ。
if文でのリテラルの使用の制限をチェックする AvoidLiteralsInIfCondition ですが、リテラルが何かを確認できるように、message を変更します。
message="Avoid using literals in if statements {0}"
オリジナルには、{0} が書かれていませんので、これで、チェック対象の変数を確認することができます。
4.まとめ
今回は、もう少し本格的なカスタマイズの方法を取り上げました。最初に書きましたように、細かいカスタマイズを行うのは、個人的にはお勧めしません。しかし、本格的に使用する場合には、カスタマイズを行って最適なルールを適用するのは有りだと思います。
そのあたりは会社や組織の都合が良いようにすればよいと思います。
ほな、さいなら
======= <<注釈>>=======
※1 P子「それだけでも結構有効よね」
P子とは、私があこがれているツンデレPythonの仮想女性の心の声です。