55import com .intellij .codeInspection .util .IntentionName ;
66import com .intellij .openapi .editor .Editor ;
77import com .intellij .openapi .project .Project ;
8+ import com .intellij .psi .PsiAssignmentExpression ;
9+ import com .intellij .psi .PsiClass ;
810import com .intellij .psi .PsiCodeBlock ;
911import com .intellij .psi .PsiElement ;
12+ import com .intellij .psi .PsiExpression ;
1013import com .intellij .psi .PsiField ;
1114import com .intellij .psi .PsiFile ;
1215import com .intellij .psi .PsiJavaFile ;
1720import com .intellij .psi .PsiModifierListOwner ;
1821import com .intellij .psi .PsiParameter ;
1922import com .intellij .psi .PsiParameterList ;
23+ import com .intellij .psi .PsiReferenceExpression ;
2024import com .intellij .psi .PsiVariable ;
2125import com .intellij .psi .util .PsiTreeUtil ;
2226import com .intellij .psi .util .PsiUtil ;
@@ -48,13 +52,20 @@ public boolean isAvailable(@NotNull final Project project, final Editor editor,
4852 if (element == null ) {
4953 return false ;
5054 }
55+
5156 final PsiField field = PsiTreeUtil .getParentOfType (element , PsiField .class , false );
5257 if (field != null ) {
5358 return true ;
5459 }
5560 if (element instanceof PsiVariable ) {
5661 return true ;
5762 }
63+
64+ // 检查是否在类名标识符上
65+ final PsiClass psiClass = PsiTreeUtil .getParentOfType (element , PsiClass .class , false );
66+ if (psiClass != null && isCaretOnClassIdentifier (element , psiClass )) {
67+ return true ;
68+ }
5869
5970 return PsiTreeUtil .getParentOfType (element , PsiMethod .class ) != null ;
6071 }
@@ -66,40 +77,167 @@ public void invoke(@NotNull final Project project, final Editor editor, final Ps
6677 return ;
6778 }
6879
80+ // 优先检查是否直接在变量上
6981 final PsiVariable specificVariable = PsiTreeUtil .getParentOfType (element , PsiVariable .class , false );
7082 if (specificVariable != null ) {
7183 addFinalModifierIfNotPresent (specificVariable );
7284 return ;
7385 }
7486
87+ // 检查是否在类名标识符上(而不是在类体内的其他地方)
88+ final PsiClass psiClass = PsiTreeUtil .getParentOfType (element , PsiClass .class , false );
89+ if (psiClass != null && isCaretOnClassIdentifier (element , psiClass )) {
90+ processClass (psiClass );
91+ return ;
92+ }
93+
7594 final PsiMethod containingMethod = PsiTreeUtil .getParentOfType (element , PsiMethod .class );
7695 if (containingMethod != null ) {
77- // Add final to parameters
78- final PsiParameterList parameterList = containingMethod .getParameterList ();
79- for (final PsiParameter parameter : parameterList .getParameters ()) {
80- addFinalModifierIfNotPresent (parameter );
81- }
96+ processMethod (containingMethod );
97+ }
98+ }
8299
83- // Add final to local variables
84- final PsiCodeBlock methodBody = containingMethod .getBody ();
85- if (methodBody != null ) {
86- final Collection <PsiLocalVariable > localVariables = PsiTreeUtil .collectElementsOfType (methodBody , PsiLocalVariable .class );
87- for (final PsiLocalVariable localVariable : localVariables ) {
88- addFinalModifierIfNotPresent (localVariable );
89- }
100+ /**
101+ * 处理整个类
102+ */
103+ private void processClass (final PsiClass psiClass ) {
104+ // 处理类字段
105+ for (final PsiField field : psiClass .getFields ()) {
106+ addFinalModifierIfNotPresent (field );
107+ }
108+
109+ // 处理类中所有方法
110+ for (final PsiMethod method : psiClass .getMethods ()) {
111+ processMethod (method );
112+ }
113+ }
114+
115+ /**
116+ * 处理单个方法
117+ */
118+ private void processMethod (final PsiMethod method ) {
119+ // 给方法参数添加 final
120+ final PsiParameterList parameterList = method .getParameterList ();
121+ for (final PsiParameter parameter : parameterList .getParameters ()) {
122+ addFinalModifierIfNotPresent (parameter );
123+ }
124+
125+ // 给方法内局部变量添加 final
126+ final PsiCodeBlock methodBody = method .getBody ();
127+ if (methodBody != null ) {
128+ final Collection <PsiLocalVariable > localVariables = PsiTreeUtil .collectElementsOfType (methodBody , PsiLocalVariable .class );
129+ for (final PsiLocalVariable localVariable : localVariables ) {
130+ addFinalModifierIfNotPresent (localVariable );
90131 }
91132 }
92133 }
93134
94135 private void addFinalModifierIfNotPresent (final PsiModifierListOwner element ) {
95136 if (element != null ) {
96137 final PsiModifierList modifierList = element .getModifierList ();
97- if (modifierList != null && !modifierList .hasExplicitModifier (PsiModifier .FINAL )) {
138+ if (modifierList != null && !modifierList .hasExplicitModifier (PsiModifier .FINAL ) && canAddFinal ( element ) ) {
98139 PsiUtil .setModifierProperty (element , PsiModifier .FINAL , true );
99140 }
100141 }
101142 }
102143
144+ /**
145+ * 判断是否可以添加 final 修饰符
146+ */
147+ private boolean canAddFinal (final PsiModifierListOwner element ) {
148+ final PsiModifierList modifierList = element .getModifierList ();
149+ if (modifierList == null ) {
150+ return false ;
151+ }
152+
153+ // 对于字段,需要更严格的检查
154+ if (element instanceof PsiField ) {
155+ final PsiField field = (PsiField ) element ;
156+ // 如果字段没有初始化器,需要检查是否在构造器中被初始化
157+ if (field .getInitializer () == null ) {
158+ // 如果是静态字段但没有初始化器,不能添加 final
159+ if (modifierList .hasExplicitModifier (PsiModifier .STATIC )) {
160+ return false ;
161+ }
162+ // 对于实例字段,检查是否在构造器中被初始化
163+ if (!isFieldInitializedInConstructor (field )) {
164+ return false ;
165+ }
166+ }
167+ }
168+
169+ // 抽象方法的参数不能添加 final(虽然抽象方法本身没有方法体,但为了安全起见)
170+ if (element instanceof PsiParameter ) {
171+ final PsiParameter parameter = (PsiParameter ) element ;
172+ final PsiElement parent = parameter .getParent ();
173+ if (parent instanceof PsiParameterList ) {
174+ final PsiElement grandParent = parent .getParent ();
175+ if (grandParent instanceof PsiMethod ) {
176+ final PsiMethod method = (PsiMethod ) grandParent ;
177+ return !method .hasModifierProperty (PsiModifier .ABSTRACT );
178+ }
179+ }
180+ }
181+
182+ return true ;
183+ }
184+
185+ /**
186+ * 检查字段是否在构造器中被初始化
187+ */
188+ private boolean isFieldInitializedInConstructor (final PsiField field ) {
189+ final PsiClass containingClass = field .getContainingClass ();
190+ if (containingClass == null ) {
191+ return false ;
192+ }
193+
194+ final PsiMethod [] constructors = containingClass .getConstructors ();
195+ if (constructors .length == 0 ) {
196+ // 没有显式构造器,Java会提供默认构造器,字段不会被初始化
197+ return false ;
198+ }
199+
200+ // 检查所有构造器是否都初始化了该字段
201+ for (final PsiMethod constructor : constructors ) {
202+ if (!isFieldInitializedInMethod (field , constructor )) {
203+ return false ;
204+ }
205+ }
206+
207+ return true ;
208+ }
209+
210+ /**
211+ * 检查字段是否在指定方法中被初始化
212+ */
213+ private boolean isFieldInitializedInMethod (final PsiField field , final PsiMethod method ) {
214+ final PsiCodeBlock body = method .getBody ();
215+ if (body == null ) {
216+ return false ;
217+ }
218+
219+ final Collection <PsiAssignmentExpression > assignments = PsiTreeUtil .collectElementsOfType (body , PsiAssignmentExpression .class );
220+ for (final PsiAssignmentExpression assignment : assignments ) {
221+ final PsiExpression lhs = assignment .getLExpression ();
222+ if (lhs instanceof PsiReferenceExpression ) {
223+ final PsiReferenceExpression ref = (PsiReferenceExpression ) lhs ;
224+ if (field .equals (ref .resolve ())) {
225+ return true ;
226+ }
227+ }
228+ }
229+
230+ return false ;
231+ }
232+
233+ /**
234+ * 检查光标是否在类名标识符上
235+ */
236+ private boolean isCaretOnClassIdentifier (final PsiElement element , final PsiClass psiClass ) {
237+ // 检查光标所在元素是否是类名标识符
238+ return element .getParent () == psiClass .getNameIdentifier () || element == psiClass .getNameIdentifier ();
239+ }
240+
103241 @ Override
104242 public boolean startInWriteAction () {
105243 return true ;
0 commit comments