From ae12b77ab7d503baeb4b16d51476009216b8787e Mon Sep 17 00:00:00 2001 From: Peter Paul Bakker Date: Tue, 12 Mar 2024 13:46:27 +0100 Subject: [PATCH 1/3] added AvoidRecompilingPatterns including test (Convert applicable rules to Kotlin #185) --- src/main/resources/category/kotlin/common.xml | 57 +++++++++- .../common/AvoidRecompilingPatternsTest.java | 6 ++ .../common/xml/AvoidRecompilingPatterns.xml | 100 ++++++++++++++++++ 3 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/jpinpoint/perf/lang/kotlin/ruleset/common/AvoidRecompilingPatternsTest.java create mode 100644 src/test/resources/com/jpinpoint/perf/lang/kotlin/ruleset/common/xml/AvoidRecompilingPatterns.xml diff --git a/src/main/resources/category/kotlin/common.xml b/src/main/resources/category/kotlin/common.xml index 9b2eb4f9..7a2cbc50 100644 --- a/src/main/resources/category/kotlin/common.xml +++ b/src/main/resources/category/kotlin/common.xml @@ -105,7 +105,7 @@ class AvoidStringBuffer { (: filter matches in functions :) //ClassDeclaration//PrimaryExpression//SimpleIdentifier//T-Identifier[ (@Text="DecimalFormat" or @Text="ChoiceFormat") - and not(ancestor::FunctionDeclaration) + and not(ancestor::FunctionBody) ] ]]> @@ -133,4 +133,59 @@ class Foo { + + A regular expression is compiled on every invocation. Problem: this can be expensive, depending on the length of the regular expression. + Solution: Usually a pattern is a literal, not dynamic and can be compiled only once. Assign it to a private constant or instance field. + java.util.Pattern objects are thread-safe so they can be shared among threads. (jpinpoint-rules) + 2 + + + + + + + + + + + + + diff --git a/src/test/java/com/jpinpoint/perf/lang/kotlin/ruleset/common/AvoidRecompilingPatternsTest.java b/src/test/java/com/jpinpoint/perf/lang/kotlin/ruleset/common/AvoidRecompilingPatternsTest.java new file mode 100644 index 00000000..d9718fb3 --- /dev/null +++ b/src/test/java/com/jpinpoint/perf/lang/kotlin/ruleset/common/AvoidRecompilingPatternsTest.java @@ -0,0 +1,6 @@ +package com.jpinpoint.perf.lang.kotlin.ruleset.common; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class AvoidRecompilingPatternsTest extends PmdRuleTst { +} diff --git a/src/test/resources/com/jpinpoint/perf/lang/kotlin/ruleset/common/xml/AvoidRecompilingPatterns.xml b/src/test/resources/com/jpinpoint/perf/lang/kotlin/ruleset/common/xml/AvoidRecompilingPatterns.xml new file mode 100644 index 00000000..5acb4dd0 --- /dev/null +++ b/src/test/resources/com/jpinpoint/perf/lang/kotlin/ruleset/common/xml/AvoidRecompilingPatterns.xml @@ -0,0 +1,100 @@ + + + + violation: Avoid recompiling patterns + 3 + 5,12,13 + + + + no violation: Avoid recompiling patterns + 0 + { + val q1 = Pattern.compile("($action?=\\p{Lu})") // ok, dynamic -- TODO make function for this? + val q2 = Pattern.compile("(" + action + "?=\\p{Lu})") // ok, dynamic + val q3 = Pattern.compile("(${action}?=\\p{Lu})") // ok, dynamic + val r = Pattern.compile(String.format(PATTERN, action)) // ok, dynamic + val t = Pattern.compile(action) // dynamic, so ok (fix for JPCC-63) + + val actionSplit = q.split(action) // ok + val list: MutableList> = ArrayList() + list.add(actionSplit) + return list + } +} + ]]> + + + + no violation: Avoid recompiling patterns, other compile + 0 + + + + + violation: Avoid recompiling patterns, with chained operations, issue #180 + 2 + 5,10 + Pattern.compile(SEP).matcher(amount).replaceAll("").length() // bad + } + + private val isAmountAllowed2: Boolean + get() { + val bla: String = Pattern.compile("[.|,]").matcher("5.000,00").replaceAll("") // bad + val b = (11 > bla.length) + return b + } + + companion object { + private const val LIMIT = 11 + private const val SEP = "[.|,]" + } +} + ]]> + + + From c221ab7dc9a47fd52347769efb165631c3476358 Mon Sep 17 00:00:00 2001 From: Peter Paul Bakker Date: Tue, 12 Mar 2024 13:46:27 +0100 Subject: [PATCH 2/3] added AvoidRecompilingPatterns including test (Convert applicable rules to Kotlin #185) --- src/main/resources/category/kotlin/common.xml | 57 +++++++++- .../common/AvoidRecompilingPatternsTest.java | 6 ++ .../common/xml/AvoidRecompilingPatterns.xml | 100 ++++++++++++++++++ 3 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/jpinpoint/perf/lang/kotlin/ruleset/common/AvoidRecompilingPatternsTest.java create mode 100644 src/test/resources/com/jpinpoint/perf/lang/kotlin/ruleset/common/xml/AvoidRecompilingPatterns.xml diff --git a/src/main/resources/category/kotlin/common.xml b/src/main/resources/category/kotlin/common.xml index 18e3b7d5..f562b706 100644 --- a/src/main/resources/category/kotlin/common.xml +++ b/src/main/resources/category/kotlin/common.xml @@ -102,7 +102,7 @@ class AvoidStringBuffer { (: filter matches in functions :) //ClassDeclaration//PrimaryExpression//SimpleIdentifier//T-Identifier[ (@Text="DecimalFormat" or @Text="ChoiceFormat") - and not(ancestor::FunctionDeclaration) + and not(ancestor::FunctionBody) ] ]]> @@ -130,6 +130,61 @@ class Foo { + + A regular expression is compiled on every invocation. Problem: this can be expensive, depending on the length of the regular expression. + Solution: Usually a pattern is a literal, not dynamic and can be compiled only once. Assign it to a private constant or instance field. + java.util.Pattern objects are thread-safe so they can be shared among threads. (jpinpoint-rules) + 2 + + + + + + + + + + + + + + + + violation: Avoid recompiling patterns + 3 + 5,12,13 + + + + no violation: Avoid recompiling patterns + 0 + { + val q1 = Pattern.compile("($action?=\\p{Lu})") // ok, dynamic -- TODO make function for this? + val q2 = Pattern.compile("(" + action + "?=\\p{Lu})") // ok, dynamic + val q3 = Pattern.compile("(${action}?=\\p{Lu})") // ok, dynamic + val r = Pattern.compile(String.format(PATTERN, action)) // ok, dynamic + val t = Pattern.compile(action) // dynamic, so ok (fix for JPCC-63) + + val actionSplit = q.split(action) // ok + val list: MutableList> = ArrayList() + list.add(actionSplit) + return list + } +} + ]]> + + + + no violation: Avoid recompiling patterns, other compile + 0 + + + + + violation: Avoid recompiling patterns, with chained operations, issue #180 + 2 + 5,10 + Pattern.compile(SEP).matcher(amount).replaceAll("").length() // bad + } + + private val isAmountAllowed2: Boolean + get() { + val bla: String = Pattern.compile("[.|,]").matcher("5.000,00").replaceAll("") // bad + val b = (11 > bla.length) + return b + } + + companion object { + private const val LIMIT = 11 + private const val SEP = "[.|,]" + } +} + ]]> + + + From 25bc9289fdba3c7c7832d320897c10f6a8bc092c Mon Sep 17 00:00:00 2001 From: Peter Paul Bakker Date: Fri, 15 Mar 2024 11:44:50 +0100 Subject: [PATCH 3/3] remove deprecated version tags --- rulesets/kotlin/jpinpoint-kotlin-rules.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rulesets/kotlin/jpinpoint-kotlin-rules.xml b/rulesets/kotlin/jpinpoint-kotlin-rules.xml index 4922536e..6be7b067 100644 --- a/rulesets/kotlin/jpinpoint-kotlin-rules.xml +++ b/rulesets/kotlin/jpinpoint-kotlin-rules.xml @@ -78,7 +78,6 @@ class Foo { 2 - 3 - 3 - 2 -