From af8db317de4da9dc3f21bfb4381f34ad3a30ad43 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 17:27:49 +0100 Subject: [PATCH] Create rule S6524: Collection should be immutable if contents is not changed (#1637) --- rules/S6524/kotlin/metadata.json | 23 +++++++ rules/S6524/kotlin/rule.adoc | 100 +++++++++++++++++++++++++++++++ rules/S6524/metadata.json | 2 + 3 files changed, 125 insertions(+) create mode 100644 rules/S6524/kotlin/metadata.json create mode 100644 rules/S6524/kotlin/rule.adoc create mode 100644 rules/S6524/metadata.json diff --git a/rules/S6524/kotlin/metadata.json b/rules/S6524/kotlin/metadata.json new file mode 100644 index 00000000000..5a9f3924f5e --- /dev/null +++ b/rules/S6524/kotlin/metadata.json @@ -0,0 +1,23 @@ +{ + "title": "Collection should be immutable if contents is not changed", + "type": "CODE_SMELL", + "code": { + "impacts": { + "MAINTAINABILITY": "MEDIUM" + }, + "attribute": "CLEAR" + }, + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + ], + "defaultSeverity": "Minor", + "ruleSpecification": "RSPEC-6524", + "sqKey": "S6524", + "scope": "All", + "defaultQualityProfiles": ["Sonar way"], + "quickfix": "unknown" +} diff --git a/rules/S6524/kotlin/rule.adoc b/rules/S6524/kotlin/rule.adoc new file mode 100644 index 00000000000..041e50c64af --- /dev/null +++ b/rules/S6524/kotlin/rule.adoc @@ -0,0 +1,100 @@ +== Why is this an issue? + +If a mutable collection type is used but no mutating functions such as `add` or `remove` are ever called, +and the collection instance does not leave the scope of the function, +it can be replaced with the corresponding immutable collection type. + +This is similar to why `val` should be used instead of `var` for local variables that are never re-assigned. + +=== What is the potential impact? + +==== Readability and Understanding + +If an immutable collection type is used, it is evident to the readers that its content is never changed. +This makes it easier to understand the code because readers do not need to keep track of possible state changes of the collection. + +==== Performance + +In some cases, optimized implementation variants of collection classes can be used when the collection is immutable. + +==== Wrong code + +Developers might intend for a collection to remain unchanged and have their code relying on that constraint. +For example, a map could be expected to contain specific elements. +Changing the contents of a collection breaks that constraint. +Also, users of an API might otherwise downcast an immutable collection they got from a library +into a mutable collection, and so cause unforeseen side effects. + +Declare collections that remain unchanged as immutable to avoid these mistakes. + +== How to fix it + +Replace mutable collection type names such as `MutableList` or `MutableMap` +with their immutable equivalents, such as `List` or `map`. + +Replace builder functions that return mutable collection instances, +such as `mutableListOf` with their immutable counterparts, such as `listOf`. + +=== Code examples + +==== Noncompliant code example + +[source,kotlin,diff-id=1,diff-type=noncompliant] +---- +fun sum123(): Int { + val list = mutableListOf(1,2,3) // Noncompliant, can be immutable + return list.reduce { acc, it -> acc + it} +} +---- + +==== Compliant solution + +[source,kotlin,diff-id=1,diff-type=compliant] +---- +fun sum123(): Int { + val list = listOf(1,2,3) // Compliant + return list.reduce { acc, it -> acc + it} +} +---- + +==== Noncompliant code example + +[source,kotlin,diff-id=2,diff-type=noncompliant] +---- +fun sumList(list: MutableList): Int { // Noncompliant, can be immutable + return list.reduce { acc, it -> acc + it} +} +---- + +==== Compliant solution + +[source,kotlin,diff-id=2,diff-type=compliant] +---- +fun sumList(list: List): Int { // Compliant + return list.reduce { acc, it -> acc + it} +} +---- + +==== Noncompliant code example + +[source,kotlin,diff-id=3,diff-type=noncompliant] +---- +fun MutableList.sum(): Int { // Noncompliant, can be immutable + return reduce { acc, it -> acc + it} +} +---- + +==== Compliant solution + +[source,kotlin,diff-id=3,diff-type=compliant] +---- +fun List.sum(): Int { // Compliant + return reduce { acc, it -> acc + it} +} +---- + +== Resources + +=== Articles & blog posts + +* https://www.baeldung.com/kotlin/immutable-collections[Baeldung, Kotlin Immutable Collections] diff --git a/rules/S6524/metadata.json b/rules/S6524/metadata.json new file mode 100644 index 00000000000..2c63c085104 --- /dev/null +++ b/rules/S6524/metadata.json @@ -0,0 +1,2 @@ +{ +}