diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md
index 5848d4a8a3..cceb97f6e4 100644
--- a/docs/pages/release_notes.md
+++ b/docs/pages/release_notes.md
@@ -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
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPass.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPass.java
index a088cc4207..94f75d64d9 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPass.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPass.java
@@ -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
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedAssignment.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedAssignment.xml
index d9aad8af15..161433fd1a 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedAssignment.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedAssignment.xml
@@ -3543,4 +3543,43 @@ public class UnusedAssignmentUnusedVariableFP {
}
]]>
+
+
+ [java] UnusedAssignment false positive in record compact constructor #4603
+ 0
+
+
+
+
+ [java] Verify explicit canonical record constructor #4603
+ 0
+
+