Java: Look for redundant assignment of a field in class and field initializers - check constructors (IDEA-149587)

This commit is contained in:
Pavel Dolgov
2017-06-27 12:36:11 +03:00
parent f4e44fadc8
commit b2a37da7e2
2 changed files with 52 additions and 4 deletions
@@ -142,10 +142,12 @@ public class DefUseInspectionBase extends BaseJavaBatchLocalInspectionTool {
final PsiClass psiClass = field.getContainingClass();
if (psiClass == null) return;
final PsiClassInitializer[] classInitializers = psiClass.getInitializers();
if (classInitializers.length == 0) return;
final boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC);
final PsiMethod[] constructors = !isStatic ? psiClass.getConstructors() : PsiMethod.EMPTY_ARRAY;
final boolean fieldHasInitializer = field.hasInitializer();
final int maxPossibleWritesCount = classInitializers.length + (constructors.length != 0 ? 1 : 0) + (fieldHasInitializer ? 1 : 0);
if (maxPossibleWritesCount <= 1) return;
final PsiClassInitializer initializerBeforeField = PsiTreeUtil.getPrevSiblingOfType(field, PsiClassInitializer.class);
final List<FieldWrite> fieldWrites = new ArrayList<>(); // class initializers and field initializer in the program order
@@ -166,7 +168,7 @@ public class DefUseInspectionBase extends BaseJavaBatchLocalInspectionTool {
}
Collections.reverse(fieldWrites);
boolean wasDefinitelyAssigned = false;
boolean wasDefinitelyAssigned = isAssignedInAllConstructors(field, constructors);
for (final FieldWrite fieldWrite : fieldWrites) {
if (wasDefinitelyAssigned) {
if (fieldWrite.isInitializer()) {
@@ -184,10 +186,23 @@ public class DefUseInspectionBase extends BaseJavaBatchLocalInspectionTool {
}
}
private static boolean isAssignedInAllConstructors(@NotNull PsiField field, @NotNull PsiMethod[] constructors) {
if (constructors.length == 0 || field.hasModifierProperty(PsiModifier.STATIC)) {
return false;
}
for (PsiMethod constructor : constructors) {
final PsiCodeBlock body = constructor.getBody();
if (body == null || !HighlightControlFlowUtil.variableDefinitelyAssignedIn(field, body)) {
return false;
}
}
return true;
}
@NotNull
private static List<PsiAssignmentExpression> collectAssignments(@NotNull PsiField field, @NotNull PsiClassInitializer classInitializer) {
final List<PsiAssignmentExpression> assignmentExpressions = new ArrayList<>();
classInitializer.accept(new JavaRecursiveElementVisitor() {
classInitializer.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitAssignmentExpression(PsiAssignmentExpression expression) {
final PsiExpression lExpression = expression.getLExpression();
@@ -42,6 +42,35 @@ class C {
}
{ s = "d"; }
}
static class C10 {
String s = <warning descr="Variable 's' initializer '\"a\"' is redundant">"a"</warning>;
C10() { s = "b"; }
}
static class C11 {
String s = "a";
C11() { s = "b"; }
C11(int i) { }
}
static class C12 {
String s = "a";
C12() { s = "b"; }
C12(int i) { if (i == 0) s = "c"; }
}
static class C13 {
String s = <warning descr="Variable 's' initializer '\"a\"' is redundant">"a"</warning>;
C13() { s = "b"; }
C13(int i) { if (i == 0) s = "c"; else s = "d"; }
}
static class C14 {
String s = <warning descr="Variable 's' initializer '\"a\"' is redundant">"a"</warning>;
{ <warning descr="The value \"b\" assigned to 's' is never used">s</warning> = "b"; }
C14() { s = "c"; }
}
static class C15 {
C15() { s = "c"; }
{ if (b) <warning descr="The value \"b\" assigned to 's' is never used">s</warning> = "b"; }
String s = <warning descr="Variable 's' initializer '\"a\"' is redundant">"a"</warning>;
}
static class S1 {
static { <warning descr="The value \"a\" assigned to 's' is never used">s</warning> = "a"; }
@@ -88,4 +117,8 @@ class C {
static String s = "a";
{ s = "b"; }
}
static class S11 {
static String s = "a";
S11() { s = "b"; }
}
}