Rules which enforce generally accepted best practices.
Table of Contents

FunctionNameTooShort

Since: PMD 7.0.0

Priority: Medium (3)

Function names should be easy to understand and describe the intention. Makes developers happy.

This rule is defined by the following XPath expression:

//FunctionDeclaration/SimpleIdentifier/T-Identifier[string-length(@Text) < 3]

Example(s):

fun cl() {} // violation, no unavailable attribute added to the function declaration

fun calculateLayout() // no violation

Use this rule by referencing it:

<rule ref="category/kotlin/bestpractices.xml/FunctionNameTooShort" />

LocalVariableShadowsParameter

Since: PMD 7.26.0

Priority: Medium (3)

A local variable declaration uses the same name as a parameter of the enclosing function. This shadows the parameter and may lead to confusion about which value is used.

This rule is defined by the following Java class: net.sourceforge.pmd.lang.kotlin.rule.bestpractices.LocalVariableShadowsParameterRule

Example(s):

fun compute(result: Int): Int {
    val result = 42  // violation - shadows parameter 'result'
    return result
}

fun compute2(input: Int): Int {
    val result = input + 1  // no violation - different name
    return result
}

Use this rule by referencing it:

<rule ref="category/kotlin/bestpractices.xml/LocalVariableShadowsParameter" />

LooseCoupling

Since: PMD 7.29.0

Priority: Medium (3)

Excessive coupling to implementation types (e.g., HashMap) limits your ability to use alternate implementations in the future as requirements change. Whenever available, declare properties, parameters, and return types using a more general type (e.g., Map).

Note that Kotlin’s List / Map / Set are read-only interfaces, distinct from the mutable MutableList / MutableMap / MutableSet. Prefer the read-only interface by default; only fall back to the Mutable* variant when the value genuinely needs to be mutated after declaration (e.g. put, add, remove).

This rule reports uses of concrete collection/map types. It currently checks a fixed list of common JDK implementation types (e.g. ArrayList, HashMap, TreeSet); unlike the Java version of this rule, it does not yet generically detect any concrete Collection/Map implementation, since that would require a dedicated type-introspection XPath function (see https://github.com/pmd/pmd/issues/7091). User-defined types that should be treated the same as interfaces can be configured with the property allowedTypes. Local variables are not reported, since their type is not part of the API surface.

This rule is defined by the following XPath expression:

(
                        //PropertyDeclaration[not(ancestor::FunctionBody or ancestor::AnonymousInitializer or ancestor::SecondaryConstructor)]
                        | //ClassParameter
                        | //FunctionValueParameter[ancestor::FunctionDeclaration]
                        | //FunctionDeclaration
                    )
                        [not(pmd-kotlin:modifiers() = 'override')]
                        [
                            pmd-kotlin:typeIs('java.util.ArrayList')
                            or pmd-kotlin:typeIs('java.util.LinkedList')
                            or pmd-kotlin:typeIs('java.util.Vector')
                            or pmd-kotlin:typeIs('java.util.Stack')
                            or pmd-kotlin:typeIs('java.util.HashMap')
                            or pmd-kotlin:typeIs('java.util.Hashtable')
                            or pmd-kotlin:typeIs('java.util.LinkedHashMap')
                            or pmd-kotlin:typeIs('java.util.TreeMap')
                            or pmd-kotlin:typeIs('java.util.HashSet')
                            or pmd-kotlin:typeIs('java.util.LinkedHashSet')
                            or pmd-kotlin:typeIs('java.util.TreeSet')
                        ]
                        [not(some $t in $allowedTypes satisfies pmd-kotlin:typeIsExactly($t))]

Example(s):

class Example {
    // violation - concrete type used for a property
    private val subscriptions: ArrayList<String> = ArrayList()

    // violation - concrete return type
    private fun sortedItems(): LinkedHashMap<String, Int> {
        return LinkedHashMap()
    }

    // preferred approach
    private val subscriptions2: MutableList<String> = mutableListOf()
    private fun sortedItems2(): Map<String, Int> {
        return linkedMapOf()
    }

    fun local() {
        val local: ArrayList<String> = ArrayList()  // no violation - local variable
    }
}

This rule has the following properties:

Name Default Value Description
allowedTypes java.util.Properties Exceptions to the rule: types that should be treated the same as interfaces even though they are concrete implementation types.

Use this rule with the default properties by just referencing it:

<rule ref="category/kotlin/bestpractices.xml/LooseCoupling" />

Use this rule and customize it:

<rule ref="category/kotlin/bestpractices.xml/LooseCoupling">
    <properties>
        <property name="allowedTypes" value="java.util.Properties" />
    </properties>
</rule>