IDEADEV-31824 (Incorrect "manual array copy" warning)
[fedora-idea.git] / plugins / InspectionGadgets / src / com / siyeh / ig / fixes / MakeFieldFinalFix.java
blobdbf6070944fe3db6a283c99f7fd0bbe8beda5fd7
1 /*
2 * Copyright 2007-2008 Bas Leijdekkers
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.siyeh.ig.fixes;
18 import com.intellij.codeInspection.ProblemDescriptor;
19 import com.intellij.openapi.project.Project;
20 import com.intellij.psi.*;
21 import com.intellij.psi.search.searches.ReferencesSearch;
22 import com.intellij.psi.util.PsiTreeUtil;
23 import com.intellij.psi.util.PsiUtil;
24 import com.intellij.util.IncorrectOperationException;
25 import com.intellij.util.Query;
26 import com.siyeh.InspectionGadgetsBundle;
27 import com.siyeh.ig.InspectionGadgetsFix;
28 import com.siyeh.ig.psiutils.InitializationUtils;
29 import org.jetbrains.annotations.NotNull;
30 import org.jetbrains.annotations.Nullable;
32 public class MakeFieldFinalFix extends InspectionGadgetsFix {
34 private final String fieldName;
36 private MakeFieldFinalFix(String fieldName) {
37 this.fieldName = fieldName;
40 @Nullable
41 public static InspectionGadgetsFix buildFix(PsiField field) {
42 if (field.hasModifierProperty(PsiModifier.STATIC)) {
43 if (!canStaticFieldBeFinal(field)) {
44 return null;
46 } else if (!canInstanceFieldBeFinal(field)) {
47 return null;
49 final String name = field.getName();
50 return new MakeFieldFinalFix(name);
53 @NotNull
54 public static InspectionGadgetsFix buildFixUnconditional(PsiField field) {
55 return new MakeFieldFinalFix(field.getName());
58 private static boolean canStaticFieldBeFinal(PsiField field) {
59 final boolean hasInitializer = field.hasInitializer();
60 final boolean initializedInOneStaticInitializer =
61 isInitializedInOneStaticInitializer(field);
62 if (hasInitializer) {
63 if (initializedInOneStaticInitializer) {
64 return false;
66 } else {
67 if (!initializedInOneStaticInitializer) {
68 return false;
71 final Query<PsiReference> query = ReferencesSearch.search(field);
72 for (PsiReference reference : query) {
73 final PsiElement element = reference.getElement();
74 if (!(element instanceof PsiExpression)) {
75 continue;
77 final PsiExpression expression = (PsiExpression) element;
78 if (!PsiUtil.isOnAssignmentLeftHand(expression)) {
79 continue;
81 final PsiMethod method = PsiTreeUtil.getParentOfType(
82 expression, PsiMethod.class);
83 if (method != null) {
84 return false;
87 return true;
90 private static boolean canInstanceFieldBeFinal(PsiField field) {
91 final boolean hasInitializer = field.hasInitializer();
92 final boolean initializedInOneInitializer =
93 isInitializedInOneInitializer(field);
94 final boolean initializedInConstructors =
95 isInitializedInConstructors(field);
96 if (hasInitializer) {
97 if (initializedInOneInitializer) {
98 return false;
100 if (initializedInConstructors) {
101 return false;
103 } else if (initializedInOneInitializer) {
104 if (initializedInConstructors) {
105 return false;
107 } else if (!initializedInConstructors) {
108 return false;
110 final Query<PsiReference> query = ReferencesSearch.search(field);
111 for (PsiReference reference : query) {
112 final PsiElement element = reference.getElement();
113 if (!(element instanceof PsiExpression)) {
114 continue;
116 final PsiExpression expression = (PsiExpression) element;
117 if (!PsiUtil.isOnAssignmentLeftHand(expression)) {
118 continue;
120 final PsiMethod method = PsiTreeUtil.getParentOfType(
121 expression, PsiMethod.class);
122 if (method != null && !method.isConstructor()) {
123 return false;
126 return true;
129 @NotNull
130 public String getName() {
131 return InspectionGadgetsBundle.message("make.field.final.quickfix",
132 fieldName);
135 @Override
136 protected void doFix(Project project, ProblemDescriptor descriptor)
137 throws IncorrectOperationException {
138 final PsiElement element = descriptor.getPsiElement();
139 final PsiField field;
140 if (element instanceof PsiReferenceExpression) {
141 final PsiReferenceExpression referenceExpression =
142 (PsiReferenceExpression)element;
143 final PsiElement target = referenceExpression.resolve();
144 if (!(target instanceof PsiField)) {
145 return;
147 field = (PsiField)target;
148 } else {
149 final PsiElement parent = element.getParent();
150 if (!(parent instanceof PsiField)) {
151 return;
153 field = (PsiField)parent;
155 final PsiModifierList modifierList = field.getModifierList();
156 if (modifierList == null) {
157 return;
159 modifierList.setModifierProperty(PsiModifier.FINAL, true);
162 private static boolean isInitializedInOneInitializer(
163 @NotNull PsiField field){
164 final PsiClass aClass = field.getContainingClass();
165 if(aClass == null){
166 return false;
168 boolean initializedInOneInitializer = false;
169 final PsiClassInitializer[] initializers = aClass.getInitializers();
170 for(final PsiClassInitializer initializer : initializers){
171 if (initializer.hasModifierProperty(PsiModifier.STATIC)) {
172 continue;
174 final PsiCodeBlock body = initializer.getBody();
175 if(InitializationUtils.blockAssignsVariableOrFails(body, field)) {
176 if (initializedInOneInitializer) {
177 return false;
179 initializedInOneInitializer = true;
182 return true;
185 private static boolean isInitializedInOneStaticInitializer(
186 @NotNull PsiField field){
187 final PsiClass aClass = field.getContainingClass();
188 if(aClass == null){
189 return false;
191 final PsiClassInitializer[] initializers = aClass.getInitializers();
192 boolean initializedInOneStaticInitializer = false;
193 for(final PsiClassInitializer initializer : initializers){
194 if (!initializer.hasModifierProperty(PsiModifier.STATIC)) {
195 continue;
197 final PsiCodeBlock body = initializer.getBody();
198 if(InitializationUtils.blockAssignsVariableOrFails(body, field)) {
199 if (initializedInOneStaticInitializer) {
200 return false;
202 initializedInOneStaticInitializer = true;
205 return initializedInOneStaticInitializer;
208 private static boolean isInitializedInConstructors(
209 @NotNull PsiField field) {
210 final PsiClass containingClass = field.getContainingClass();
211 final PsiMethod[] constructors = containingClass.getConstructors();
212 if (constructors.length == 0) {
213 return false;
215 for (PsiMethod constructor : constructors) {
216 if (!InitializationUtils.methodAssignsVariableOrFails(
217 constructor, field)) {
218 return false;
221 return true;