Skip to content

Commit 9823490

Browse files
authored
Merge pull request #686 from jborgers/pmd7-issue-651
Pmd7 issue 651: false positive on AvoidMultipleConcatStatements
2 parents 82ab13f + 3c3aaca commit 9823490

File tree

2 files changed

+121
-14
lines changed

2 files changed

+121
-14
lines changed

src/main/resources/category/kotlin/common.xml

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -398,21 +398,31 @@ class Foo {
398398
<property name="tag" value="jpinpoint-rule" type="String" description="for-sonar"/>
399399
<property name="xpath">
400400
<value><![CDATA[
401-
//FunctionBody[count(.//Assignment[.//(AssignmentAndOperator/T-ADD_ASSIGNMENT|AdditiveOperator/T-ADD)]/(AssignableExpression|DirectlyAssignableExpression)//T-Identifier[@Text=
402-
(: property a string literal :)
403-
ancestor::FunctionBody//PropertyDeclaration[(
404-
Expression[not(.//Expression)]//StringLiteral or
405-
(: or explicit type String:)
406-
VariableDeclaration/Type//T-Identifier[@Text='String'] or
407-
(: or assigned parameter of type String :)
408-
Expression[.//T-Identifier[@Text = ancestor::FunctionDeclaration/FunctionValueParameters/FunctionValueParameter[Parameter/Type//T-Identifier[@Text='String']]//T-Identifier/@Text]] or
409-
(: or assigned non-nested function of explicit type String :) (: known issue: ignores parameters, may give false positives with overloaded methods :)
410-
Expression[.//T-Identifier[not(ancestor::CallSuffix)][@Text = ancestor::ClassMemberDeclarations//FunctionDeclaration[Type//T-Identifier[@Text='String']]//T-Identifier/@Text]]
411-
)]
412-
/VariableDeclaration//T-Identifier/@Text]) > 1]
401+
//FunctionBody[
402+
count(
403+
.//Assignment[
404+
.//(AssignmentAndOperator/T-ADD_ASSIGNMENT|AdditiveOperator/T-ADD)
405+
and
406+
(AssignableExpression|DirectlyAssignableExpression)//T-Identifier[
407+
(: property a string literal :)
408+
@Text = ancestor::FunctionBody//PropertyDeclaration[
409+
(
410+
Expression[not(.//Expression)]//StringLiteral
411+
(: explicit type String:)
412+
or VariableDeclaration/Type//T-Identifier[@Text='String']
413+
(: assigned parameter of type String :)
414+
or Expression[.//T-Identifier[@Text = ancestor::FunctionDeclaration/FunctionValueParameters/FunctionValueParameter[Parameter/Type//T-Identifier[@Text='String']]//T-Identifier/@Text]]
415+
(: assigned non-nested function of explicit type String :) (: known issue: ignores parameters, may give false positives with overloaded methods :)
416+
or Expression[.//T-Identifier[not(ancestor::CallSuffix)][@Text = ancestor::ClassMemberDeclarations//FunctionDeclaration[Type//T-Identifier[@Text='String']]//T-Identifier/@Text]]
417+
)
418+
and not(Expression//T-Identifier[@Text='toMutableList'])
419+
]/VariableDeclaration//T-Identifier/@Text
420+
]
421+
]
422+
) > 1
423+
]
413424
//Statement[Assignment//(T-ADD_ASSIGNMENT|T-ADD)][position()=last()]
414-
415-
]]></value>
425+
]]></value>
416426
</property>
417427
</properties>
418428
<example>

src/test/resources/com/jpinpoint/perf/lang/kotlin/ruleset/common/xml/AvoidMultipleConcatStatements.xml

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,101 @@ class AvoidMultipleConcatStatementsKt {
203203
]]></code>
204204
</test-code>
205205

206+
<test-code>
207+
<description>Fix Request: Kotlin AvoidMultipleConcatStatements false positive on MutableList #651</description>
208+
<expected-problems>0</expected-problems>
209+
<code><![CDATA[
210+
class Foo(private val isActive: Boolean, private val canCreate: Boolean) {
211+
212+
private fun calculate(myList: List<String>): List<String> {
213+
214+
val mutableList = myList.toMutableList()
215+
216+
if (isActive) {
217+
mutableList += "one" // false positive, not two lines with += are needed to trigger this rule
218+
if (canCreate) {
219+
mutableList += listOf("two", "three") // false positive
220+
}
221+
} else {
222+
mutableList.removeAll(listOf("one", "two"))
223+
}
224+
return myList
225+
}
226+
}
227+
]]></code>
228+
</test-code>
229+
230+
<test-code>
231+
<description>Kotlin non-String plus operator usages should not trigger AvoidMultipleConcatStatements</description>
232+
<expected-problems>0</expected-problems>
233+
<code><![CDATA[
234+
import java.math.BigDecimal
235+
236+
data class Vec2(val x: Int, val y: Int) {
237+
operator fun plus(other: Vec2): Vec2 = Vec2(this.x + other.x, this.y + other.y)
238+
}
239+
240+
class NonStringPlusUsages {
241+
242+
fun numericPlus(): Int {
243+
var a = 10
244+
a += 5
245+
a = a + 2
246+
val b = 3 + 4
247+
return a + b
248+
}
249+
250+
fun bigDecimalPlus(): BigDecimal {
251+
var total = BigDecimal.ZERO
252+
total += BigDecimal("1.5")
253+
total = total + BigDecimal("2.25")
254+
return total + BigDecimal("3.0")
255+
}
256+
257+
fun listPlus(x: List<Int>, y: List<Int>): List<Int> {
258+
var base = listOf(1, 2)
259+
base = base + 3
260+
base += listOf(4, 5)
261+
val more = base + listOf(6)
262+
val evenMore = x + y
263+
return more
264+
}
265+
266+
fun mutableListPlusAssign(): MutableList<Int> {
267+
val ml = mutableListOf(1)
268+
ml += 2
269+
ml += listOf(3, 4)
270+
return ml
271+
}
272+
273+
fun setUnion(): Set<Int> {
274+
val s1 = setOf(1, 2)
275+
val s2 = setOf(2, 3)
276+
val s3 = s1 + s2
277+
return s3 + 4
278+
}
279+
280+
fun mapPlus(): Map<String, Int> {
281+
val m1 = mapOf("a" to 1)
282+
val m2 = m1 + ("b" to 2)
283+
val m3 = m2 + mapOf("c" to 3)
284+
return m3
285+
}
286+
287+
fun arrayPlus(): IntArray {
288+
val arr = intArrayOf(1, 2)
289+
val extended = arr + 3
290+
return extended + intArrayOf(4, 5)
291+
}
292+
293+
fun customOperatorPlus(): Vec2 {
294+
var v = Vec2(1, 2)
295+
v += Vec2(3, 4)
296+
v = v + Vec2(5, 6)
297+
return v + Vec2(7, 8)
298+
}
299+
}
300+
]]></code>
301+
</test-code>
302+
206303
</test-data>

0 commit comments

Comments
 (0)