Bug fixes in DefUseInspection

IDEA-187758 Variable initializer is redundant false-negative with chained constructors
IDEA-187756 Variable initializer is redundant false-positive when the value is read before write
This commit is contained in:
Tagir Valeev
2018-03-06 11:42:15 +07:00
parent d6120cc97e
commit e3fb3c143c
4 changed files with 58 additions and 12 deletions
@@ -1,11 +1,16 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection.defUse;
import com.intellij.codeInsight.ExpressionUtil;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil;
import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
import com.intellij.codeInsight.daemon.impl.quickfix.RemoveUnusedVariableUtil;
import com.intellij.codeInspection.*;
import com.intellij.psi.*;
import com.intellij.psi.controlFlow.AnalysisCanceledException;
import com.intellij.psi.controlFlow.ControlFlow;
import com.intellij.psi.controlFlow.ControlFlowUtil;
import com.intellij.psi.controlFlow.DefUseUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ObjectUtils;
@@ -16,10 +21,8 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.*;
import java.util.List;
import java.util.Set;
public class DefUseInspectionBase extends AbstractBaseJavaLocalInspectionTool {
public boolean REPORT_PREFIX_EXPRESSIONS;
@@ -66,15 +69,7 @@ public class DefUseInspectionBase extends AbstractBaseJavaLocalInspectionTool {
List<DefUseUtil.Info> unusedDefs = DefUseUtil.getUnusedDefs(body, usedVariables);
if (unusedDefs != null && !unusedDefs.isEmpty()) {
Collections.sort(unusedDefs, (o1, o2) -> {
int offset1 = o1.getContext().getTextOffset();
int offset2 = o2.getContext().getTextOffset();
if (offset1 == offset2) return 0;
if (offset1 < offset2) return -1;
return 1;
});
unusedDefs.sort(Comparator.comparingInt(o -> o.getContext().getTextOffset()));
for (DefUseUtil.Info info : unusedDefs) {
PsiElement context = info.getContext();
@@ -179,10 +174,21 @@ public class DefUseInspectionBase extends AbstractBaseJavaLocalInspectionTool {
return false;
}
for (PsiMethod constructor : constructors) {
if (JavaHighlightUtil.getChainedConstructors(constructor) != null) continue;
final PsiCodeBlock body = constructor.getBody();
if (body == null || !HighlightControlFlowUtil.variableDefinitelyAssignedIn(field, body)) {
return false;
}
try {
ControlFlow flow = HighlightControlFlowUtil.getControlFlowNoConstantEvaluate(body);
if (ControlFlowUtil.getReadBeforeWrite(flow).stream()
.anyMatch(read -> ExpressionUtil.isEffectivelyUnqualified(read) && read.isReferenceTo(field))) {
return false;
}
}
catch (AnalysisCanceledException e) {
return false;
}
}
return true;
}
@@ -0,0 +1,15 @@
class Foo {
String s = <warning descr="Variable 's' initializer '\"foo\"' is redundant">"foo"</warning>;
Foo(String _s) {
s = _s;
}
Foo() {
this("foo");
}
public static void main(String[] args) {
new Foo();
}
}
@@ -0,0 +1,15 @@
import java.util.function.Supplier;
class Foo {
String s = "foo";
Foo() {
Supplier<String> fn = s::trim;
s = "bar";
System.out.println(fn.get());
}
public static void main(String[] args) {
new Foo();
}
}
@@ -17,7 +17,9 @@ package com.intellij.java.codeInspection;
import com.intellij.JavaTestUtil;
import com.intellij.codeInspection.defUse.DefUseInspection;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
public class DefUseTest extends LightCodeInsightFixtureTestCase {
@Override
@@ -63,6 +65,14 @@ public class DefUseTest extends LightCodeInsightFixtureTestCase {
myFixture.enableInspections(inspection);
myFixture.testHighlighting(getTestName(false) + ".java");
}
public void testFieldInitializerUsedInMethodReference() { doTest(); }
public void testFieldInitializerChainedConstructor() { doTest(); }
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_10;
}
private void doTest() {
myFixture.enableInspections(new DefUseInspection());