From 10b86fbc300227f3bd784b15ab34b951cce464b4 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Thu, 9 Jan 2020 18:22:19 +0700 Subject: [PATCH] IDEA-230315 Control flow for record compact constructor should take into account implicit assignments GitOrigin-RevId: 31f268e2ffdb4a2d4d42288e5075e1eb52f4c137 --- .../psi/controlFlow/ControlFlowAnalyzer.java | 33 +++++++++++++++++++ .../unusedAssignment/afterRecordCompact2.java | 6 ++++ .../unusedAssignment/beforeRecordCompact.java | 6 ++++ .../beforeRecordCompact2.java | 7 ++++ 4 files changed, 52 insertions(+) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/afterRecordCompact2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/beforeRecordCompact.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/beforeRecordCompact2.java diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java index 306c63111a22..b58fca3ab6ee 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java @@ -9,6 +9,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.JavaPsiRecordUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.ObjectUtils; @@ -59,6 +60,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor { private final ControlFlowFactory myControlFlowFactory; private final Map mySubRanges = new THashMap<>(); private final PsiConstantEvaluationHelper myConstantEvaluationHelper; + private final Map myImplicitCompactConstructorAssignments; ControlFlowAnalyzer(@NotNull PsiElement codeFragment, @NotNull ControlFlowPolicy policy, @@ -80,6 +82,24 @@ class ControlFlowAnalyzer extends JavaElementVisitor { Project project = codeFragment.getProject(); myControlFlowFactory = ControlFlowFactory.getInstance(project); myConstantEvaluationHelper = JavaPsiFacade.getInstance(project).getConstantEvaluationHelper(); + myImplicitCompactConstructorAssignments = getImplicitCompactConstructorAssignmentsMap(); + } + + private Map getImplicitCompactConstructorAssignmentsMap() { + PsiMethod ctor = ObjectUtils.tryCast(myCodeFragment.getParent(), PsiMethod.class); + if (ctor == null || !JavaPsiRecordUtil.isCompactConstructor(ctor)) return Collections.emptyMap(); + PsiClass containingClass = ctor.getContainingClass(); + if (containingClass == null) return Collections.emptyMap(); + PsiParameter[] parameters = ctor.getParameterList().getParameters(); + PsiRecordComponent[] components = containingClass.getRecordComponents(); + Map map = new HashMap<>(); + for (int i = 0; i < Math.min(components.length, parameters.length); i++) { + PsiRecordComponent component = components[i]; + PsiField field = JavaPsiRecordUtil.getFieldForComponent(component); + PsiParameter parameter = parameters[i]; + map.put(field, parameter); + } + return map; } @NotNull @@ -105,6 +125,10 @@ class ControlFlowAnalyzer extends JavaElementVisitor { return myCurrentFlow; } + private void generateCompactConstructorAssignments() { + myImplicitCompactConstructorAssignments.values().stream().filter(myPolicy::isParameterAccepted).forEach(this::generateReadInstruction); + } + private static class StatementStack { private final Stack myStatements = new Stack<>(); private final TIntArrayList myAtStart = new TIntArrayList(); @@ -370,6 +394,9 @@ class ControlFlowAnalyzer extends JavaElementVisitor { if (!(block.getParent() instanceof PsiSwitchStatement) && prevOffset == nextOffset) { emitEmptyInstruction(); } + if (block == myCodeFragment) { + generateCompactConstructorAssignments(); + } finishElement(block); if (prevOffset != 0) { @@ -1370,6 +1397,12 @@ class ControlFlowAnalyzer extends JavaElementVisitor { boolean generatedWriteInstruction = false; PsiExpression lExpr = PsiUtil.skipParenthesizedExprDown(expression.getLExpression()); if (lExpr instanceof PsiReferenceExpression) { + if (!myImplicitCompactConstructorAssignments.isEmpty()) { + PsiElement target = ((PsiReferenceExpression)lExpr).resolve(); + if (target instanceof PsiField) { + myImplicitCompactConstructorAssignments.remove(target); + } + } PsiVariable variable = getUsedVariable((PsiReferenceExpression)lExpr); if (variable != null) { if (myAssignmentTargetsAreElements) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/afterRecordCompact2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/afterRecordCompact2.java new file mode 100644 index 000000000000..5ac539930abc --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/afterRecordCompact2.java @@ -0,0 +1,6 @@ +// "Remove redundant assignment" "true" +record R2(int y) { + public R2 { + this.y = y; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/beforeRecordCompact.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/beforeRecordCompact.java new file mode 100644 index 000000000000..da13763b9fc7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/beforeRecordCompact.java @@ -0,0 +1,6 @@ +// "Remove redundant assignment" "false" +record R(int x) { + R { + x = x + 1; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/beforeRecordCompact2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/beforeRecordCompact2.java new file mode 100644 index 000000000000..0a0380381d4e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unusedAssignment/beforeRecordCompact2.java @@ -0,0 +1,7 @@ +// "Remove redundant assignment" "true" +record R2(int y) { + public R2 { + this.y = y; + y = y + 1; + } +} \ No newline at end of file