PMD

Zpracoval: Hung Duong Manh
Vedoucí projektu, korektury, závěrečná revize: Pavel Herout
Datum poslední modifikace: 31.10.2011



Obsah:

Úvod - co je to PMD?

PMD je opensource program, který slouží k analýze zdrojových souborů napsaných v jazyce Java. Na ZČU se používá především jako nástroj pro kontrolu ve výuce základních programovacích praktik, ale je možno ho použít i pro jiné účely, např. odhalování bugů (prázdné try/catch příkazy) nebo hledání duplicitního kódu. Chyby odhalené pomocí PMD nejsou chyby v pravém slova smyslu, ale spíše chyby v kvalitě zdrojového kódu.

Instalace (Windows)

Instalace PMD je poměrně jednoduchá. Stačí pouze ze stránek PMD stáhnout archiv pmd-bin-X.X.X.zip a někam ho rozbalit. (X.X.X je číslo verze)

Stránky PMD - http://pmd.sourceforge.net

Spuštění

V příkazové řádce se přesuneme na místo, kam jsme rozbalili PMD a pak do složky bin.

pmd [zdrojovySoubor] [vystup] [pravidla]

kde

Příklad použití:

1) pmd Vlakna.java text mojepravidla.xml > vystup.txt
2) pmd c:\data\pmd\pmd\test-data\Unused1.java xml rulesets/unusedcode.xml

Poznámka k příkladům:
V prvním případě bude analyzován soubor Vlakna.java (nachází se ve stejné složce jako pmd.bat), výstup bude textový a použije se soubor s pravidly nazvanými mojepravidla.xml, který byl předtím nakopírován do složky bin. Soubor mojepravidla.xml je námi připravený soubor pravidel, který není přibalen s PMD. Poslední část "> vystup.txt" přesměruje text, který by se jinak vypsal do konzole, do souboru vystup.txt.
V druhém příkladě bude výstup do xml formátu a bude použit přibalené soubor pravidel unusedcode.xml, které se nachází v souboru \lib\pmd-X.X.X.jar\rulesets

V případě, že bychom chtěli nějaké konkrétní pravidlo poupravit, tak si překopírujeme ze souboru pmd-X.X.X.jar daný soubor s pravidly a upravíme. Upravený soubor pravidel pak použijeme tak, že k němu uvedeme cestu v 3. parametru (viz první příklad).

Příklad:
Soubor pravidel /rulesets/naming.xml obsahuje pravidlo LongVariable. Toto pravidlo hledá deklarace názvy proměnných a pokud název proměnné je delší než určitá hodnota, tak oznámí porušení pravidla. Standardně je mezní hodnota nastavena jako 17, my bychom ale chtěli hodnotu navýšit. Skopírujeme si tedy z jaru soubor naming.xml do svého adresáře. Soubor naming.xml pak otevřeme v editoru a najdeme pravidlo LongVariable. XPath výraz vypadá takto:

//VariableDeclaratorId[string-length(@Image) > $minimum]

O pár řádků výše je pak tato řádka:

<property name="minimum" description="The variable length reporting threshold" value="17"/>

Přepíšeme tedy value="17" na value="20" a soubor uložíme. Upravený soubor pravidel pak použijeme takto:

pmd Soubor.java text cestaKUpravenémuSouboru/naming.xml

Princip fungování

PMD ze zdrojového souboru vytvoří Abstract Syntax Tree a ten pak každé pravidlo prochází a hledá chyby.

Vytvoření vlastního pravidla

Vlastní pravidlo lze vytvořit dvěma způsoby – buď jako Java třídu nebo pomocí XPath výrazu . Osobně si myslím, že definice pomoci XPath výrazu je jednodušší a praktičtější.

Jak napsat pravidlo pomoci Java třídy je podrobně popsáno zde http://pmd.sourceforge.net/howtowritearule.html

Stručný popis jak napsat pravidlo jako XPath výraz.
Nejdřív potřebujeme vědět s čím budeme pracovat v AST. K tomu slouží malá utilitka [PMD]/bin/designer.bat. Kde [PMD] je cesta, kam jsme rozbalili PMD.
Designer má 4 okénka - Source code, XPath Query, Abstract Syntax Tree a Okénko pro výsledky XPath dotazu.

Do okénka Source code napíšeme jednoduchý zdrojový kód problému, na který chceme reagovat. Po stisknutí tlačítka "Go" se nám vygeneruje příslušný AST, kde můžeme vidět, jaká je struktura našeho kódu.
Např. příkaz int a; bude v AST jako VariableDeclaratorId: a. Uzel je VariableDeclaratorId a "a" je jeho atribut, neboli VariableDeclaratorId[@Image="a"].

Příklad (kód v Source code):

public class A { 
    int a, b;
}
           

Když bychom do okénka XPath Query zapsali "//VariableDeclaratorId", vypsal by nám Designer, že našel proměnnou "a" i "b". //VariableDeclaratorId[@Image="a"] by nám našlo pouze proměnnou "a". //VariableDeclaratorId[@Image="c"] by nám nevypsalo nic, protože taková proměnná tam není.

Dejme tomu, že bychom chtěli hlídat minimální délku názvu proměnných, tedy VariableDeclaratorId. Nyní když víme, na co chceme reagovat, tak můžeme definovat vlastni pravidlo.
Náš soubor s pravidly nazveme například pridane-pravidlo.xml a bude v něm:

<?xml version="1.0"?>
<ruleset name="Moje pravidla"
    xmlns="http://pmd.sf.net/ruleset/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
    xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
    <rule name="ShortVariable"
    message="Promenna musi mit alespon 3 znaky"
    class="net.sourceforge.pmd.rules.XPathRule">
                
    <description>
            Detects when a field, formal or local variable is declared with a short name.
    </description>
                
    <priority>3</priority>
    <properties>
        <property name="minimum" description="The variable length reporting threshold" value="3"/>
        <property name="xpath" pluginname="true">
        <value>
            <![CDATA[
//VariableDeclaratorId[string-length(@Image) < $minimum]
            ]]>
        </value>
        </property>
    </properties>
    <example>
    <![CDATA[
public class Something {
  int reallyLongIntName = -3;  // VIOLATION - Field
  public static void main( String argumentsList[] ) { // VIOLATION - Formal
    int otherReallyLongName = -5; // VIOLATION - Local
    for (int interestingIntIndex = 0;  // VIOLATION - For
             interestingIntIndex < 10;
             interestingIntIndex ++ ) {
    }
}
]]>
    </example>
    </rule>
</ruleset>
            

rule name - název pravidla
messsage - zpráva, která se vypíše při nalezení chyby
class - pokud chceme pouzivat XPath výrazy, tak musí byt uvedeno "net.sourceforge.pmd.rules.XPathRule", pokud bychom použili Java třídu, byl by zde název třídy bez jakékoliv přípony
property - definice XPath promenných
<value></value> - zde je umístěn samotný XPath vyraz v CDATA bloku
//VariableDeclaratorId[string-length(@Image) > $minimum
Najde všechny deklarace názvu proměnných, jejichž délka je menší nez minimum (3). string-length(x) je funkce na spočítání délky řetězce
<example></example> Příklad této chyby v kódu, který se uživateli zobrazuje při případném chybovém hlášení.

Vlastní pravidla v PMD rozšíření pro BlueJ:

PMD rozšíření (je myšlen standardní PMDExtension.jar stažený z webu PMD) bere v základu pouze pravidla uvedená v souboru PMDExtension.jar\rulesets\favorites.xml. Pokud chceme definovat své vlastní pravidlo, musíme napsat definici do .xml souboru. Buď si můžeme vytvořit nový .xml soubor, který bude obsahovat pouze naše nové pravidlo nebo ho můžeme připsat do nějakého .xml souboru se základními pravidly (např. basic.xml) a potom na něj uvést odkaz ze souboru favorites.xml.

Pokud bychom chtěli pouze použit nějaké již definované pravidlo, stačí do favorites.xml připsat odkaz, např:

<rule ref="rulesets/basic.xml/EmptyCatchBlock" message="Nepouzivejte prazdne bloky 'catch'"> </rule>