From 7ea2d6d175c9379d39b4aca2566dfdb741a6dc6f Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 1 Jul 2015 22:21:31 +0200 Subject: [PATCH] IG: check fields with initializers correctly in "Field may be final" inspection --- .../src/com/siyeh/ig/psiutils/FinalUtils.java | 6 ++++- .../ig/psiutils/VariableAccessUtils.java | 27 +++++++++++++++++++ .../style/field_final/FieldMayBeFinal.java | 12 +++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/FinalUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/FinalUtils.java index 1155a1083906..e320e35b1c2f 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/FinalUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/FinalUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2013 Bas Leijdekkers + * Copyright 2009-2015 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,10 @@ public class FinalUtils { private FinalUtils() {} public static boolean canBeFinal(@NotNull PsiVariable variable) { + if (variable.getInitializer() != null || variable instanceof PsiParameter) { + // parameters hava implicit initializer + return !VariableAccessUtils.variableIsAssigned(variable); + } final FinalDefiniteAssignment definiteAssignment = new FinalDefiniteAssignment(variable); DefiniteAssignmentUtil.checkVariable(variable, definiteAssignment); return definiteAssignment.isDefinitelyAssigned() && diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java index 03bf5937d44f..a6639f51d1e8 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java @@ -16,7 +16,10 @@ package com.siyeh.ig.psiutils; import com.intellij.psi.*; +import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -79,6 +82,30 @@ public class VariableAccessUtils { return visitor.isPassed(); } + public static boolean variableIsAssigned(@NotNull PsiVariable variable) { + if (variable instanceof PsiField) { + if (variable.hasModifierProperty(PsiModifier.PRIVATE)) { + final PsiClass aClass = PsiUtil.getTopLevelClass(variable); + return variableIsAssigned(variable, aClass); + } + return !ReferencesSearch.search(variable, variable.getUseScope()).forEach(new Processor() { + @Override + public boolean process(PsiReference reference) { + final PsiElement element = reference.getElement(); + if (!(element instanceof PsiExpression)) { + return true; + } + final PsiExpression expression = (PsiExpression)element; + return !PsiUtil.isAccessedForWriting(expression); + } + }); + } + final PsiElement context = + PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class, PsiMethod.class, PsiLambdaExpression.class, + PsiCatchSection.class, PsiForStatement.class, PsiForeachStatement.class); + return variableIsAssigned(variable, context); + } + public static boolean variableIsAssigned( @NotNull PsiVariable variable, @Nullable PsiElement context) { if (context == null) { diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/field_final/FieldMayBeFinal.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/field_final/FieldMayBeFinal.java index e532626bfd39..299549b239ed 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/field_final/FieldMayBeFinal.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/field_final/FieldMayBeFinal.java @@ -886,6 +886,18 @@ class T58 { x = 3; } } +class T59 { + private int i = 0; + { + assert true : i++; + } +} +class T60 { + private int i = 1; + { + if (false) i = 2; + } +} class Foo { public interface Accessor {