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
;
41 public static InspectionGadgetsFix
buildFix(PsiField field
) {
42 if (field
.hasModifierProperty(PsiModifier
.STATIC
)) {
43 if (!canStaticFieldBeFinal(field
)) {
46 } else if (!canInstanceFieldBeFinal(field
)) {
49 final String name
= field
.getName();
50 return new MakeFieldFinalFix(name
);
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
);
63 if (initializedInOneStaticInitializer
) {
67 if (!initializedInOneStaticInitializer
) {
71 final Query
<PsiReference
> query
= ReferencesSearch
.search(field
);
72 for (PsiReference reference
: query
) {
73 final PsiElement element
= reference
.getElement();
74 if (!(element
instanceof PsiExpression
)) {
77 final PsiExpression expression
= (PsiExpression
) element
;
78 if (!PsiUtil
.isOnAssignmentLeftHand(expression
)) {
81 final PsiMethod method
= PsiTreeUtil
.getParentOfType(
82 expression
, PsiMethod
.class);
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
);
97 if (initializedInOneInitializer
) {
100 if (initializedInConstructors
) {
103 } else if (initializedInOneInitializer
) {
104 if (initializedInConstructors
) {
107 } else if (!initializedInConstructors
) {
110 final Query
<PsiReference
> query
= ReferencesSearch
.search(field
);
111 for (PsiReference reference
: query
) {
112 final PsiElement element
= reference
.getElement();
113 if (!(element
instanceof PsiExpression
)) {
116 final PsiExpression expression
= (PsiExpression
) element
;
117 if (!PsiUtil
.isOnAssignmentLeftHand(expression
)) {
120 final PsiMethod method
= PsiTreeUtil
.getParentOfType(
121 expression
, PsiMethod
.class);
122 if (method
!= null && !method
.isConstructor()) {
130 public String
getName() {
131 return InspectionGadgetsBundle
.message("make.field.final.quickfix",
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
)) {
147 field
= (PsiField
)target
;
149 final PsiElement parent
= element
.getParent();
150 if (!(parent
instanceof PsiField
)) {
153 field
= (PsiField
)parent
;
155 final PsiModifierList modifierList
= field
.getModifierList();
156 if (modifierList
== null) {
159 modifierList
.setModifierProperty(PsiModifier
.FINAL
, true);
162 private static boolean isInitializedInOneInitializer(
163 @NotNull PsiField field
){
164 final PsiClass aClass
= field
.getContainingClass();
168 boolean initializedInOneInitializer
= false;
169 final PsiClassInitializer
[] initializers
= aClass
.getInitializers();
170 for(final PsiClassInitializer initializer
: initializers
){
171 if (initializer
.hasModifierProperty(PsiModifier
.STATIC
)) {
174 final PsiCodeBlock body
= initializer
.getBody();
175 if(InitializationUtils
.blockAssignsVariableOrFails(body
, field
)) {
176 if (initializedInOneInitializer
) {
179 initializedInOneInitializer
= true;
185 private static boolean isInitializedInOneStaticInitializer(
186 @NotNull PsiField field
){
187 final PsiClass aClass
= field
.getContainingClass();
191 final PsiClassInitializer
[] initializers
= aClass
.getInitializers();
192 boolean initializedInOneStaticInitializer
= false;
193 for(final PsiClassInitializer initializer
: initializers
){
194 if (!initializer
.hasModifierProperty(PsiModifier
.STATIC
)) {
197 final PsiCodeBlock body
= initializer
.getBody();
198 if(InitializationUtils
.blockAssignsVariableOrFails(body
, field
)) {
199 if (initializedInOneStaticInitializer
) {
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) {
215 for (PsiMethod constructor
: constructors
) {
216 if (!InitializationUtils
.methodAssignsVariableOrFails(
217 constructor
, field
)) {