[java] UnusedAssignment false positive in record compact constructor

Fixes #4603
This commit is contained in:
Andreas Dangel committed 2024-02-29 10:06:27 +01:00
1 parent 3b0dd7a82b
commit f0cbbddcfc
3 files changed
+60 -1

No files matched your search

+3 -1
View File
@@ -275,7 +275,8 @@ The rules have been moved into categories with PMD 6.
* [#3751](https://github.com/pmd/pmd/issues/3751): \[java] Rename some node types
* [#4628](https://github.com/pmd/pmd/pull/4628): \[java] Support loading classes from java runtime images
* [#4753](https://github.com/pmd/pmd/issues/4753): \[java] PMD crashes while using generics and wildcards
* java-bestpractives
* java-bestpractices
* [#4603](https://github.com/pmd/pmd/issues/4603): \[java] UnusedAssignment false positive in record compact constructor
* [#4625](https://github.com/pmd/pmd/issues/4625): \[java] UnusedPrivateMethod false positive: Autoboxing into Number
* java-codestyle
* [#2847](https://github.com/pmd/pmd/issues/2847): \[java] New Rule: Use Explicit Types
@@ -1406,6 +1407,7 @@ Language specific fixes:
* [#4516](https://github.com/pmd/pmd/issues/4516): \[java] UnusedLocalVariable: false-negative with try-with-resources
* [#4517](https://github.com/pmd/pmd/issues/4517): \[java] UnusedLocalVariable: false-negative with compound assignments
* [#4518](https://github.com/pmd/pmd/issues/4518): \[java] UnusedLocalVariable: false-positive with multiple for-loop indices
* [#4603](https://github.com/pmd/pmd/issues/4603): \[java] UnusedAssignment false positive in record compact constructor
* [#4625](https://github.com/pmd/pmd/issues/4625): \[java] UnusedPrivateMethod false positive: Autoboxing into Number
* [#4634](https://github.com/pmd/pmd/issues/4634): \[java] JUnit4TestShouldUseTestAnnotation false positive with TestNG
* java-codestyle
@@ -54,6 +54,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTLoopStatement;
import net.sourceforge.pmd.lang.java.ast.ASTMethodCall;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTRecordComponent;
import net.sourceforge.pmd.lang.java.ast.ASTResourceList;
import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
import net.sourceforge.pmd.lang.java.ast.ASTStatement;
@@ -818,6 +819,23 @@ public final class DataflowPass {
return data;
}
@Override
public SpanInfo visit(ASTCompactConstructorDeclaration node, SpanInfo data) {
super.visit(node, data);
// mark any write to a variable that is named like a record component as usage
// record compact constructors do an implicit assignment at the end.
for (ASTRecordComponent component : node.getEnclosingType().getRecordComponents()) {
node.descendants(ASTAssignmentExpression.class)
.descendants(ASTVariableAccess.class)
.filter(v -> v.getAccessType() == AccessType.WRITE)
.filter(v -> v.getName().equals(component.getVarId().getName()))
.forEach(varAccess -> data.use(varAccess.getReferencedSym(), null));
}
return data;
}
/**
* Whether the variable has an implicit initializer, that is not
* an expression. For instance, formal parameters have a value
@@ -3543,4 +3543,43 @@ public class UnusedAssignmentUnusedVariableFP {
}
]]></code>
</test-code>
<test-code>
<description>[java] UnusedAssignment false positive in record compact constructor #4603</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Main {
public static void main(String[] args) {
System.out.println(new TestRecord(2).foo());
}
}
record TestRecord(int foo) {
TestRecord {
// src/Main.java:10: UnusedAssignment: The value assigned to variable 'foo' is never used
foo = Math.min(foo, 1); // <!--- violation here
// implicit this.foo = foo;
}
}
]]></code>
</test-code>
<test-code>
<description>[java] Verify explicit canonical record constructor #4603</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Main {
public static void main(String[] args) {
System.out.println(new TestRecord(2).foo());
}
}
record TestRecord(int foo) {
TestRecord(int foo) {
foo = Math.min(foo, 1);
this.foo = foo; // explicit
}
}
]]></code>
</test-code>
</test-data>