diff --git a/java/java-impl/src/com/intellij/codeInspection/classCanBeRecord/ConvertToRecordFix.java b/java/java-impl/src/com/intellij/codeInspection/classCanBeRecord/ConvertToRecordFix.java index 209aa046cdc4..91ba05009580 100644 --- a/java/java-impl/src/com/intellij/codeInspection/classCanBeRecord/ConvertToRecordFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/classCanBeRecord/ConvertToRecordFix.java @@ -4,6 +4,7 @@ package com.intellij.codeInspection.classCanBeRecord; import com.intellij.codeInsight.AnnotationTargetUtil; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.ExceptionUtil; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.util.IntentionFamilyName; @@ -240,20 +241,23 @@ public class ConvertToRecordFix extends InspectionGadgetsFix { myCanonical = false; return; } - PsiParameter[] ctorParams = myConstructor.getParameterList().getParameters(); Set instanceFieldNames = instanceFields.stream().map(PsiField::getName).collect(Collectors.toSet()); - for (PsiParameter param : ctorParams) { - if (!instanceFieldNames.contains(param.getName())) { - myCanonical = false; - return; - } - } - Map ctorParamsWithType = Arrays.stream(ctorParams) - .collect(Collectors.toMap(param -> param.getName(), param -> param.getType(), (first, second) -> first)); - if (ctorParams.length != ctorParamsWithType.size()) { + if (instanceFieldNames.size() != instanceFields.size()) { myCanonical = false; return; } + PsiParameter[] ctorParams = myConstructor.getParameterList().getParameters(); + if (instanceFields.size() != ctorParams.length) { + myCanonical = false; + return; + } + PsiCodeBlock ctorBody = myConstructor.getBody(); + if (ctorBody == null) { + myCanonical = false; + return; + } + Map ctorParamsWithType = Arrays.stream(ctorParams) + .collect(Collectors.toMap(param -> param.getName(), param -> param.getType(), (first, second) -> first)); for (PsiField instanceField : instanceFields) { PsiType ctorParamType = ObjectUtils.tryCast(ctorParamsWithType.get(instanceField.getName()), PsiType.class); if (ctorParamType instanceof PsiEllipsisType) { @@ -263,6 +267,10 @@ public class ConvertToRecordFix extends InspectionGadgetsFix { myCanonical = false; return; } + if (!HighlightControlFlowUtil.variableDefinitelyAssignedIn(instanceField, ctorBody)) { + myCanonical = false; + return; + } } myCanonical = true; } diff --git a/java/java-tests/testData/inspection/classCanBeRecord/beforeFieldNotInitializedInCtor.java b/java/java-tests/testData/inspection/classCanBeRecord/beforeFieldNotInitializedInCtor.java new file mode 100644 index 000000000000..45bdeada506f --- /dev/null +++ b/java/java-tests/testData/inspection/classCanBeRecord/beforeFieldNotInitializedInCtor.java @@ -0,0 +1,9 @@ +// "Convert to a record" "false" +class R { + final int first; + final int second; + + R(int first, int second) { + this.first = first; + } +} diff --git a/java/java-tests/testData/inspection/classCanBeRecord/beforeFieldsHaveEqualNames.java b/java/java-tests/testData/inspection/classCanBeRecord/beforeFieldsHaveEqualNames.java new file mode 100644 index 000000000000..f595fc5bced4 --- /dev/null +++ b/java/java-tests/testData/inspection/classCanBeRecord/beforeFieldsHaveEqualNames.java @@ -0,0 +1,9 @@ +// "Convert to a record" "false" +class R { + final int first; + final int first; + + R(int first) { + this.first = first; + } +} \ No newline at end of file