2 * Copyright 2000-2009 JetBrains s.r.o.
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.
18 * Created by IntelliJ IDEA.
22 package com
.intellij
.codeInsight
.daemon
.impl
.analysis
;
24 import com
.intellij
.codeInsight
.ExceptionUtil
;
25 import com
.intellij
.codeInsight
.daemon
.JavaErrorMessages
;
26 import com
.intellij
.codeInsight
.daemon
.impl
.HighlightInfo
;
27 import com
.intellij
.codeInsight
.daemon
.impl
.HighlightInfoType
;
28 import com
.intellij
.codeInsight
.daemon
.impl
.quickfix
.*;
29 import com
.intellij
.codeInsight
.highlighting
.HighlightUsagesDescriptionLocation
;
30 import com
.intellij
.codeInsight
.intention
.IntentionAction
;
31 import com
.intellij
.codeInsight
.intention
.QuickFixFactory
;
32 import com
.intellij
.codeInsight
.quickfix
.ChangeVariableTypeQuickFixProvider
;
33 import com
.intellij
.codeInsight
.quickfix
.UnresolvedReferenceQuickFixProvider
;
34 import com
.intellij
.lang
.StdLanguages
;
35 import com
.intellij
.lang
.findUsages
.LanguageFindUsages
;
36 import com
.intellij
.openapi
.diagnostic
.Logger
;
37 import com
.intellij
.openapi
.extensions
.Extensions
;
38 import com
.intellij
.openapi
.project
.Project
;
39 import com
.intellij
.openapi
.util
.Comparing
;
40 import com
.intellij
.openapi
.util
.Key
;
41 import com
.intellij
.openapi
.util
.Pair
;
42 import com
.intellij
.openapi
.util
.TextRange
;
43 import com
.intellij
.psi
.*;
44 import com
.intellij
.psi
.impl
.source
.jsp
.jspJava
.JspHolderMethod
;
45 import com
.intellij
.psi
.javadoc
.PsiDocComment
;
46 import com
.intellij
.psi
.jsp
.JspFile
;
47 import com
.intellij
.psi
.scope
.processor
.VariablesNotProcessor
;
48 import com
.intellij
.psi
.scope
.util
.PsiScopesUtil
;
49 import com
.intellij
.psi
.tree
.IElementType
;
50 import com
.intellij
.psi
.util
.*;
51 import com
.intellij
.util
.ArrayUtil
;
52 import com
.intellij
.util
.IncorrectOperationException
;
53 import com
.intellij
.xml
.util
.XmlStringUtil
;
54 import gnu
.trove
.THashMap
;
55 import gnu
.trove
.THashSet
;
56 import org
.jetbrains
.annotations
.NonNls
;
57 import org
.jetbrains
.annotations
.NotNull
;
58 import org
.jetbrains
.annotations
.Nullable
;
62 public class HighlightUtil
{
63 private static final Logger LOG
= Logger
.getInstance("#com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil");
64 private static final Map
<String
, Set
<String
>> ourInterfaceIncompatibleModifiers
;
65 private static final Map
<String
, Set
<String
>> ourMethodIncompatibleModifiers
;
66 private static final Map
<String
, Set
<String
>> ourFieldIncompatibleModifiers
;
67 private static final Map
<String
, Set
<String
>> ourClassIncompatibleModifiers
;
68 private static final Map
<String
, Set
<String
>> ourClassInitializerIncompatibleModifiers
;
69 private static final Set
<String
> ourConstructorNotAllowedModifiers
;
71 @NonNls private static final String SERIAL_VERSION_UID_FIELD_NAME
= "serialVersionUID";
72 @NonNls private static final String SERIAL_PERSISTENT_FIELDS_FIELD_NAME
= "serialPersistentFields";
73 private static final QuickFixFactory QUICK_FIX_FACTORY
= QuickFixFactory
.getInstance();
75 private HighlightUtil() {
79 ourClassIncompatibleModifiers
= new THashMap
<String
, Set
<String
>>(8);
80 Set
<String
> modifiers
= new THashSet
<String
>(1);
81 modifiers
.add(PsiModifier
.FINAL
);
82 ourClassIncompatibleModifiers
.put(PsiModifier
.ABSTRACT
, modifiers
);
83 modifiers
= new THashSet
<String
>(1);
84 modifiers
.add(PsiModifier
.ABSTRACT
);
85 ourClassIncompatibleModifiers
.put(PsiModifier
.FINAL
, modifiers
);
86 modifiers
= new THashSet
<String
>(3);
87 modifiers
.add(PsiModifier
.PRIVATE
);
88 modifiers
.add(PsiModifier
.PUBLIC
);
89 modifiers
.add(PsiModifier
.PROTECTED
);
90 ourClassIncompatibleModifiers
.put(PsiModifier
.PACKAGE_LOCAL
, modifiers
);
91 modifiers
= new THashSet
<String
>(3);
92 modifiers
.add(PsiModifier
.PACKAGE_LOCAL
);
93 modifiers
.add(PsiModifier
.PUBLIC
);
94 modifiers
.add(PsiModifier
.PROTECTED
);
95 ourClassIncompatibleModifiers
.put(PsiModifier
.PRIVATE
, modifiers
);
96 modifiers
= new THashSet
<String
>(3);
97 modifiers
.add(PsiModifier
.PACKAGE_LOCAL
);
98 modifiers
.add(PsiModifier
.PRIVATE
);
99 modifiers
.add(PsiModifier
.PROTECTED
);
100 ourClassIncompatibleModifiers
.put(PsiModifier
.PUBLIC
, modifiers
);
101 modifiers
= new THashSet
<String
>(3);
102 modifiers
.add(PsiModifier
.PACKAGE_LOCAL
);
103 modifiers
.add(PsiModifier
.PUBLIC
);
104 modifiers
.add(PsiModifier
.PRIVATE
);
105 ourClassIncompatibleModifiers
.put(PsiModifier
.PROTECTED
, modifiers
);
106 ourClassIncompatibleModifiers
.put(PsiModifier
.STRICTFP
, Collections
.<String
>emptySet());
107 ourClassIncompatibleModifiers
.put(PsiModifier
.STATIC
, Collections
.<String
>emptySet());
108 ourInterfaceIncompatibleModifiers
= new THashMap
<String
, Set
<String
>>(7);
109 ourInterfaceIncompatibleModifiers
.put(PsiModifier
.ABSTRACT
, Collections
.<String
>emptySet());
110 modifiers
= new THashSet
<String
>(3);
111 modifiers
.add(PsiModifier
.PRIVATE
);
112 modifiers
.add(PsiModifier
.PUBLIC
);
113 modifiers
.add(PsiModifier
.PROTECTED
);
114 ourInterfaceIncompatibleModifiers
.put(PsiModifier
.PACKAGE_LOCAL
, modifiers
);
115 modifiers
= new THashSet
<String
>(3);
116 modifiers
.add(PsiModifier
.PACKAGE_LOCAL
);
117 modifiers
.add(PsiModifier
.PUBLIC
);
118 modifiers
.add(PsiModifier
.PROTECTED
);
119 ourInterfaceIncompatibleModifiers
.put(PsiModifier
.PRIVATE
, modifiers
);
120 modifiers
= new THashSet
<String
>(3);
121 modifiers
.add(PsiModifier
.PRIVATE
);
122 modifiers
.add(PsiModifier
.PACKAGE_LOCAL
);
123 modifiers
.add(PsiModifier
.PROTECTED
);
124 ourInterfaceIncompatibleModifiers
.put(PsiModifier
.PUBLIC
, modifiers
);
125 modifiers
= new THashSet
<String
>(3);
126 modifiers
.add(PsiModifier
.PRIVATE
);
127 modifiers
.add(PsiModifier
.PUBLIC
);
128 modifiers
.add(PsiModifier
.PACKAGE_LOCAL
);
129 ourInterfaceIncompatibleModifiers
.put(PsiModifier
.PROTECTED
, modifiers
);
130 ourInterfaceIncompatibleModifiers
.put(PsiModifier
.STRICTFP
, Collections
.<String
>emptySet());
131 ourInterfaceIncompatibleModifiers
.put(PsiModifier
.STATIC
, Collections
.<String
>emptySet());
132 ourMethodIncompatibleModifiers
= new THashMap
<String
, Set
<String
>>(10);
133 modifiers
= new THashSet
<String
>(6);
134 modifiers
.addAll(Arrays
.asList(PsiModifier
.NATIVE
, PsiModifier
.STATIC
, PsiModifier
.FINAL
, PsiModifier
.PRIVATE
, PsiModifier
.STRICTFP
,
135 PsiModifier
.SYNCHRONIZED
));
136 ourMethodIncompatibleModifiers
.put(PsiModifier
.ABSTRACT
, modifiers
);
137 modifiers
= new THashSet
<String
>(2);
138 modifiers
.add(PsiModifier
.ABSTRACT
);
139 modifiers
.add(PsiModifier
.STRICTFP
);
140 ourMethodIncompatibleModifiers
.put(PsiModifier
.NATIVE
, modifiers
);
141 modifiers
= new THashSet
<String
>(3);
142 modifiers
.add(PsiModifier
.PRIVATE
);
143 modifiers
.add(PsiModifier
.PUBLIC
);
144 modifiers
.add(PsiModifier
.PROTECTED
);
145 ourMethodIncompatibleModifiers
.put(PsiModifier
.PACKAGE_LOCAL
, modifiers
);
146 modifiers
= new THashSet
<String
>(4);
147 modifiers
.add(PsiModifier
.ABSTRACT
);
148 modifiers
.add(PsiModifier
.PACKAGE_LOCAL
);
149 modifiers
.add(PsiModifier
.PUBLIC
);
150 modifiers
.add(PsiModifier
.PROTECTED
);
151 ourMethodIncompatibleModifiers
.put(PsiModifier
.PRIVATE
, modifiers
);
152 modifiers
= new THashSet
<String
>(3);
153 modifiers
.add(PsiModifier
.PACKAGE_LOCAL
);
154 modifiers
.add(PsiModifier
.PRIVATE
);
155 modifiers
.add(PsiModifier
.PROTECTED
);
156 ourMethodIncompatibleModifiers
.put(PsiModifier
.PUBLIC
, modifiers
);
157 modifiers
= new THashSet
<String
>(3);
158 modifiers
.add(PsiModifier
.PACKAGE_LOCAL
);
159 modifiers
.add(PsiModifier
.PUBLIC
);
160 modifiers
.add(PsiModifier
.PRIVATE
);
161 ourMethodIncompatibleModifiers
.put(PsiModifier
.PROTECTED
, modifiers
);
162 modifiers
= new THashSet
<String
>(1);
163 modifiers
.add(PsiModifier
.ABSTRACT
);
164 ourMethodIncompatibleModifiers
.put(PsiModifier
.STATIC
, modifiers
);
165 ourMethodIncompatibleModifiers
.put(PsiModifier
.SYNCHRONIZED
, modifiers
);
166 ourMethodIncompatibleModifiers
.put(PsiModifier
.STRICTFP
, modifiers
);
167 ourMethodIncompatibleModifiers
.put(PsiModifier
.FINAL
, modifiers
);
168 ourFieldIncompatibleModifiers
= new THashMap
<String
, Set
<String
>>(8);
169 modifiers
= new THashSet
<String
>(1);
170 modifiers
.add(PsiModifier
.VOLATILE
);
171 ourFieldIncompatibleModifiers
.put(PsiModifier
.FINAL
, modifiers
);
172 modifiers
= new THashSet
<String
>(3);
173 modifiers
.add(PsiModifier
.PRIVATE
);
174 modifiers
.add(PsiModifier
.PUBLIC
);
175 modifiers
.add(PsiModifier
.PROTECTED
);
176 ourFieldIncompatibleModifiers
.put(PsiModifier
.PACKAGE_LOCAL
, modifiers
);
177 modifiers
= new THashSet
<String
>(3);
178 modifiers
.add(PsiModifier
.PACKAGE_LOCAL
);
179 modifiers
.add(PsiModifier
.PUBLIC
);
180 modifiers
.add(PsiModifier
.PROTECTED
);
181 ourFieldIncompatibleModifiers
.put(PsiModifier
.PRIVATE
, modifiers
);
182 modifiers
= new THashSet
<String
>(3);
183 modifiers
.add(PsiModifier
.PACKAGE_LOCAL
);
184 modifiers
.add(PsiModifier
.PRIVATE
);
185 modifiers
.add(PsiModifier
.PROTECTED
);
186 ourFieldIncompatibleModifiers
.put(PsiModifier
.PUBLIC
, modifiers
);
187 modifiers
= new THashSet
<String
>(3);
188 modifiers
.add(PsiModifier
.PACKAGE_LOCAL
);
189 modifiers
.add(PsiModifier
.PRIVATE
);
190 modifiers
.add(PsiModifier
.PUBLIC
);
191 ourFieldIncompatibleModifiers
.put(PsiModifier
.PROTECTED
, modifiers
);
192 ourFieldIncompatibleModifiers
.put(PsiModifier
.STATIC
, Collections
.<String
>emptySet());
193 ourFieldIncompatibleModifiers
.put(PsiModifier
.TRANSIENT
, Collections
.<String
>emptySet());
194 modifiers
= new THashSet
<String
>(1);
195 modifiers
.add(PsiModifier
.FINAL
);
196 ourFieldIncompatibleModifiers
.put(PsiModifier
.VOLATILE
, modifiers
);
198 ourClassInitializerIncompatibleModifiers
= new THashMap
<String
, Set
<String
>>(1);
199 ourClassInitializerIncompatibleModifiers
.put(PsiModifier
.STATIC
, Collections
.<String
>emptySet());
201 ourConstructorNotAllowedModifiers
= new THashSet
<String
>(6);
202 ourConstructorNotAllowedModifiers
.add(PsiModifier
.ABSTRACT
);
203 ourConstructorNotAllowedModifiers
.add(PsiModifier
.STATIC
);
204 ourConstructorNotAllowedModifiers
.add(PsiModifier
.NATIVE
);
205 ourConstructorNotAllowedModifiers
.add(PsiModifier
.FINAL
);
206 ourConstructorNotAllowedModifiers
.add(PsiModifier
.STRICTFP
);
207 ourConstructorNotAllowedModifiers
.add(PsiModifier
.SYNCHRONIZED
);
211 public static String
getIncompatibleModifier(String modifier
,
212 PsiModifierList modifierList
,
213 Map
<String
, Set
<String
>> incompatibleModifiersHash
) {
214 if (modifierList
== null) return null;
215 // modifier is always incompatible with itself
216 PsiElement
[] modifiers
= modifierList
.getChildren();
217 int modifierCount
= 0;
218 for (PsiElement otherModifier
: modifiers
) {
219 if (Comparing
.equal(modifier
, otherModifier
.getText(), true)) modifierCount
++;
221 if (modifierCount
> 1) {
225 Set
<String
> incompatibles
= incompatibleModifiersHash
.get(modifier
);
226 if (incompatibles
== null) return null;
227 for (@Modifier String incompatible
: incompatibles
) {
228 if (modifierList
.hasModifierProperty(incompatible
)) {
236 * make element protected/package local/public suggestion
238 static void registerAccessQuickFixAction(PsiMember refElement
,
239 PsiJavaCodeReferenceElement place
,
240 HighlightInfo errorResult
,
241 final PsiElement fileResolveScope
) {
242 if (refElement
instanceof PsiCompiledElement
) return;
243 PsiModifierList modifierList
= refElement
.getModifierList();
244 if (modifierList
== null) return;
246 PsiClass packageLocalClassInTheMiddle
= getPackageLocalClassInTheMiddle(place
);
247 if (packageLocalClassInTheMiddle
!= null) {
248 IntentionAction fix
=
249 QUICK_FIX_FACTORY
.createModifierListFix(packageLocalClassInTheMiddle
, PsiModifier
.PUBLIC
, true, true);
250 QuickFixAction
.registerQuickFixAction(errorResult
, fix
);
255 Project project
= refElement
.getProject();
256 JavaPsiFacade facade
= JavaPsiFacade
.getInstance(project
);
257 PsiModifierList modifierListCopy
= facade
.getElementFactory().createFieldFromText("int a;", null).getModifierList();
258 modifierListCopy
.setModifierProperty(PsiModifier
.STATIC
, modifierList
.hasModifierProperty(PsiModifier
.STATIC
));
259 @Modifier String minModifier
= PsiModifier
.PACKAGE_LOCAL
;
260 if (refElement
.hasModifierProperty(PsiModifier
.PACKAGE_LOCAL
)) {
261 minModifier
= PsiModifier
.PROTECTED
;
263 if (refElement
.hasModifierProperty(PsiModifier
.PROTECTED
)) {
264 minModifier
= PsiModifier
.PUBLIC
;
266 String
[] modifiers
= {PsiModifier
.PACKAGE_LOCAL
, PsiModifier
.PROTECTED
, PsiModifier
.PUBLIC
,};
267 PsiClass accessObjectClass
= PsiTreeUtil
.getParentOfType(place
, PsiClass
.class, false);
269 for (int i
= ArrayUtil
.indexOf(modifiers
, minModifier
); i
< modifiers
.length
; i
++) {
270 @Modifier String modifier
= modifiers
[i
];
271 modifierListCopy
.setModifierProperty(modifier
, true);
272 if (facade
.getResolveHelper().isAccessible(refElement
, modifierListCopy
, place
, accessObjectClass
, fileResolveScope
)) {
273 IntentionAction fix
= QUICK_FIX_FACTORY
.createModifierListFix(refElement
, modifier
, true, true);
274 TextRange fixRange
= new TextRange(errorResult
.startOffset
, errorResult
.endOffset
);
275 PsiElement ref
= place
.getReferenceNameElement();
277 fixRange
= fixRange
.union(ref
.getTextRange());
279 QuickFixAction
.registerQuickFixAction(errorResult
, fixRange
, fix
, null);
283 catch (IncorrectOperationException e
) {
289 private static PsiClass
getPackageLocalClassInTheMiddle(PsiJavaCodeReferenceElement place
) {
290 if (place
instanceof PsiReferenceExpression
) {
291 // check for package local classes in the middle
292 PsiReferenceExpression expression
= (PsiReferenceExpression
)place
;
294 PsiElement resolved
= expression
.resolve();
295 if (resolved
instanceof PsiField
) {
296 PsiField field
= (PsiField
)resolved
;
297 PsiClass aClass
= field
.getContainingClass();
298 if (aClass
!= null && aClass
.hasModifierProperty(PsiModifier
.PACKAGE_LOCAL
) &&
299 !JavaPsiFacade
.getInstance(aClass
.getProject()).arePackagesTheSame(aClass
, place
)) {
304 PsiExpression qualifier
= expression
.getQualifierExpression();
305 if (!(qualifier
instanceof PsiReferenceExpression
)) break;
306 expression
= (PsiReferenceExpression
)qualifier
;
314 static HighlightInfo
checkInstanceOfApplicable(PsiInstanceOfExpression expression
) {
315 PsiExpression operand
= expression
.getOperand();
316 PsiTypeElement typeElement
= expression
.getCheckType();
317 if (typeElement
== null) return null;
318 PsiType checkType
= typeElement
.getType();
319 PsiType operandType
= operand
.getType();
320 if (operandType
== null) return null;
321 if (TypeConversionUtil
.isPrimitiveAndNotNull(operandType
)
322 || TypeConversionUtil
.isPrimitiveAndNotNull(checkType
)
323 || !TypeConversionUtil
.areTypesConvertible(operandType
, checkType
)) {
324 String message
= JavaErrorMessages
.message("inconvertible.type.cast", formatType(operandType
), formatType(checkType
));
325 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, expression
, message
);
332 static HighlightInfo
checkInconvertibleTypeCast(PsiTypeCastExpression expression
) {
333 PsiExpression operand
= expression
.getOperand();
334 PsiType castType
= expression
.getCastType().getType();
335 PsiType operandType
= operand
== null ?
null : operand
.getType();
336 if (operandType
!= null && !TypeConversionUtil
.areTypesConvertible(operandType
, castType
)) {
337 String message
= JavaErrorMessages
.message("inconvertible.type.cast", formatType(operandType
), formatType(castType
));
338 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, expression
, message
);
344 static HighlightInfo
checkVariableExpected(PsiExpression expression
) {
345 PsiExpression lValue
;
346 if (expression
instanceof PsiAssignmentExpression
) {
347 PsiAssignmentExpression assignment
= (PsiAssignmentExpression
)expression
;
348 lValue
= assignment
.getLExpression();
350 else if (PsiUtil
.isIncrementDecrementOperation(expression
)) {
351 lValue
= expression
instanceof PsiPostfixExpression
352 ?
((PsiPostfixExpression
)expression
).getOperand()
353 : ((PsiPrefixExpression
)expression
).getOperand();
358 HighlightInfo errorResult
= null;
359 if (lValue
!= null && !TypeConversionUtil
.isLValue(lValue
)) {
360 errorResult
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, lValue
, JavaErrorMessages
.message("variable.expected"));
368 static HighlightInfo
checkAssignmentOperatorApplicable(PsiAssignmentExpression assignment
) {
369 PsiJavaToken operationSign
= assignment
.getOperationSign();
370 IElementType eqOpSign
= operationSign
.getTokenType();
371 IElementType opSign
= TypeConversionUtil
.convertEQtoOperation(eqOpSign
);
372 if (opSign
== null) return null;
373 HighlightInfo errorResult
= null;
374 if (!TypeConversionUtil
.isBinaryOperatorApplicable(opSign
, assignment
.getLExpression(), assignment
.getRExpression(), true)) {
375 String operatorText
= operationSign
.getText().substring(0, operationSign
.getText().length() - 1);
376 String message
= JavaErrorMessages
.message("binary.operator.not.applicable", operatorText
,
377 formatType(assignment
.getLExpression().getType()),
378 formatType(assignment
.getRExpression().getType()));
380 errorResult
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, assignment
, message
);
387 static HighlightInfo
checkAssignmentCompatibleTypes(PsiAssignmentExpression assignment
) {
388 if (!"=".equals(assignment
.getOperationSign().getText())) return null;
389 PsiExpression lExpr
= assignment
.getLExpression();
390 PsiExpression rExpr
= assignment
.getRExpression();
391 if (rExpr
== null) return null;
392 PsiType lType
= lExpr
.getType();
393 PsiType rType
= rExpr
.getType();
394 if (rType
== null) return null;
396 HighlightInfo highlightInfo
= checkAssignability(lType
, rType
, rExpr
, assignment
);
397 if (highlightInfo
!= null) {
398 PsiVariable leftVar
= null;
399 if (lExpr
instanceof PsiReferenceExpression
) {
400 PsiElement element
= ((PsiReferenceExpression
)lExpr
).resolve();
401 if (element
instanceof PsiVariable
) {
402 leftVar
= (PsiVariable
)element
;
405 if (leftVar
!= null) {
406 registerChangeVariableTypeFixes(leftVar
, rType
, highlightInfo
);
409 return highlightInfo
;
412 private static boolean isCastIntentionApplicable(PsiExpression expression
, PsiType toType
) {
413 while (expression
instanceof PsiTypeCastExpression
|| expression
instanceof PsiParenthesizedExpression
) {
414 if (expression
instanceof PsiTypeCastExpression
) {
415 expression
= ((PsiTypeCastExpression
)expression
).getOperand();
417 if (expression
instanceof PsiParenthesizedExpression
) {
418 expression
= ((PsiParenthesizedExpression
)expression
).getExpression();
421 if (expression
== null) return false;
422 PsiType rType
= expression
.getType();
423 return rType
!= null && toType
!= null && TypeConversionUtil
.areTypesConvertible(rType
, toType
);
428 static HighlightInfo
checkVariableInitializerType(PsiVariable variable
) {
429 PsiExpression initializer
= variable
.getInitializer();
430 // array initalizer checked in checkArrayInitializerApplicable
431 if (initializer
== null || initializer
instanceof PsiArrayInitializerExpression
) return null;
432 PsiType lType
= variable
.getType();
433 PsiType rType
= initializer
.getType();
434 int start
= variable
.getTypeElement().getTextRange().getStartOffset();
435 int end
= variable
.getTextRange().getEndOffset();
436 HighlightInfo highlightInfo
= checkAssignability(lType
, rType
, initializer
, new TextRange(start
, end
));
437 if (highlightInfo
!= null) {
438 registerChangeVariableTypeFixes(variable
, rType
, highlightInfo
);
440 return highlightInfo
;
444 static HighlightInfo
checkAssignability(PsiType lType
, PsiType rType
, PsiExpression expression
, PsiElement elementToHighlight
) {
445 TextRange textRange
= elementToHighlight
.getTextRange();
446 return checkAssignability(lType
, rType
, expression
, textRange
);
450 public static HighlightInfo
checkAssignability(@Nullable PsiType lType
, @Nullable PsiType rType
, @Nullable PsiExpression expression
, TextRange textRange
) {
451 if (lType
== rType
) return null;
452 if (expression
== null) {
453 if (rType
== null || lType
== null || TypeConversionUtil
.isAssignable(lType
, rType
)) return null;
455 else if (TypeConversionUtil
.areTypesAssignmentCompatible(lType
, expression
)) {
456 if (lType
== null || rType
== null) return null;
457 return GenericsHighlightUtil
.checkRawToGenericAssignment(lType
, rType
, expression
);
460 rType
= expression
.getType();
462 HighlightInfo highlightInfo
= createIncompatibleTypeHighlightInfo(lType
, rType
, textRange
);
463 if (rType
!= null && expression
!= null && isCastIntentionApplicable(expression
, lType
)) {
464 QuickFixAction
.registerQuickFixAction(highlightInfo
, new AddTypeCastFix(lType
, expression
));
466 if (lType
instanceof PsiClassType
&& expression
!= null) {
467 QuickFixAction
.registerQuickFixAction(highlightInfo
, new WrapExpressionFix((PsiClassType
)lType
, expression
));
469 ChangeNewOperatorTypeFix
.register(highlightInfo
, expression
, lType
);
470 return highlightInfo
;
475 static HighlightInfo
checkReturnStatementType(PsiReturnStatement statement
) {
476 PsiMethod method
= null;
477 PsiElement parent
= statement
.getParent();
479 if (parent
instanceof PsiFile
) break;
480 if (parent
instanceof PsiClassInitializer
) break;
481 if (parent
instanceof PsiMethod
) {
482 method
= (PsiMethod
)parent
;
485 parent
= parent
.getParent();
488 int navigationShift
= 0;
489 HighlightInfo errorResult
= null;
490 if (method
== null && !(parent
instanceof JspFile
)) {
491 description
= JavaErrorMessages
.message("return.outside.method");
492 errorResult
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, statement
, description
);
495 PsiType returnType
= method
!= null ? method
.getReturnType() : null/*JSP page returns void*/;
496 boolean isMethodVoid
= returnType
== null || PsiType
.VOID
.equals(returnType
);
497 final PsiExpression returnValue
= statement
.getReturnValue();
498 if (returnValue
!= null) {
499 PsiType valueType
= returnValue
.getType();
501 description
= JavaErrorMessages
.message("return.from.void.method");
502 errorResult
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, statement
, description
);
503 if (valueType
!= null) {
504 IntentionAction fix
= QUICK_FIX_FACTORY
.createMethodReturnFix(method
, valueType
, true);
505 QuickFixAction
.registerQuickFixAction(errorResult
, fix
);
509 errorResult
= checkAssignability(returnType
, valueType
, returnValue
, statement
);
510 if (errorResult
!= null && valueType
!= null) {
511 IntentionAction fix
= QUICK_FIX_FACTORY
.createMethodReturnFix(method
, valueType
, true);
512 QuickFixAction
.registerQuickFixAction(errorResult
, fix
);
513 if (returnType
instanceof PsiArrayType
&& TypeConversionUtil
.isAssignable(((PsiArrayType
)returnType
).getComponentType(), valueType
)) {
514 QuickFixAction
.registerQuickFixAction(errorResult
, new SurroundWithArrayFix(null){
516 protected PsiExpression
getExpression(final PsiElement element
) {
517 return returnValue
.isValid() ? returnValue
: null;
523 navigationShift
= returnValue
.getStartOffsetInParent();
527 description
= JavaErrorMessages
.message("missing.return.value");
528 errorResult
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, statement
, description
);
529 IntentionAction fix
= QUICK_FIX_FACTORY
.createMethodReturnFix(method
, PsiType
.VOID
, true);
530 QuickFixAction
.registerQuickFixAction(errorResult
, fix
);
531 navigationShift
= PsiKeyword
.RETURN
.length();
535 if (errorResult
!= null) {
536 errorResult
.navigationShift
= navigationShift
;
541 public static String
getUnhandledExceptionsDescriptor(Collection
<PsiClassType
> unhandledExceptions
) {
542 StringBuilder exceptionsText
= new StringBuilder();
543 for (PsiClassType unhandledException
: unhandledExceptions
) {
544 if (exceptionsText
.length() != 0) exceptionsText
.append(", ");
545 exceptionsText
.append(formatType(unhandledException
));
548 return JavaErrorMessages
.message("unhandled.exceptions", exceptionsText
.toString(), unhandledExceptions
.size());
553 static HighlightInfo
checkVariableAlreadyDefined(PsiVariable variable
) {
554 boolean isIncorrect
= false;
555 PsiIdentifier identifier
= variable
.getNameIdentifier();
556 String name
= variable
.getName();
557 if (variable
instanceof PsiLocalVariable
||
558 variable
instanceof PsiParameter
&& ((PsiParameter
)variable
).getDeclarationScope() instanceof PsiCatchSection
||
559 variable
instanceof PsiParameter
&& ((PsiParameter
)variable
).getDeclarationScope() instanceof PsiForeachStatement
) {
560 PsiElement scope
= PsiTreeUtil
.getParentOfType(variable
, PsiFile
.class, PsiMethod
.class, PsiClassInitializer
.class);
561 VariablesNotProcessor proc
= new VariablesNotProcessor(variable
, false){
562 protected boolean check(final PsiVariable var
, final ResolveState state
) {
563 return (var
instanceof PsiLocalVariable
|| var
instanceof PsiParameter
) && super.check(var
, state
);
566 PsiScopesUtil
.treeWalkUp(proc
, identifier
, scope
);
567 if (proc
.size() > 0) {
571 else if (variable
instanceof PsiField
) {
572 PsiField field
= (PsiField
)variable
;
573 PsiClass aClass
= field
.getContainingClass();
574 if (aClass
== null) return null;
575 PsiField fieldByName
= aClass
.findFieldByName(name
, false);
576 if (fieldByName
!= null && fieldByName
!= field
) {
581 PsiElement scope
= variable
.getParent();
582 PsiElement
[] children
= scope
.getChildren();
583 for (PsiElement child
: children
) {
584 if (child
instanceof PsiVariable
) {
585 if (child
.equals(variable
)) continue;
586 if (name
.equals(((PsiVariable
)child
).getName())) {
595 String description
= JavaErrorMessages
.message("variable.already.defined", name
);
596 HighlightInfo highlightInfo
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, identifier
, description
);
597 QuickFixAction
.registerQuickFixAction(highlightInfo
, new ReuseVariableDeclarationFix(variable
, identifier
));
598 return highlightInfo
;
604 public static String
formatClass(@NotNull PsiClass aClass
) {
605 return formatClass(aClass
, true);
609 public static String
formatClass(@NotNull PsiClass aClass
, boolean fqn
) {
610 return PsiFormatUtil
.formatClass(aClass
, PsiFormatUtil
.SHOW_NAME
| PsiFormatUtil
.SHOW_ANONYMOUS_CLASS_VERBOSE
| (fqn ? PsiFormatUtil
.SHOW_FQ_NAME
: 0));
614 public static String
formatMethod(@NotNull PsiMethod method
) {
615 return PsiFormatUtil
.formatMethod(method
, PsiSubstitutor
.EMPTY
, PsiFormatUtil
.SHOW_NAME
| PsiFormatUtil
.SHOW_PARAMETERS
, PsiFormatUtil
.SHOW_TYPE
);
619 public static String
formatType(@Nullable PsiType type
) {
620 if (type
== null) return PsiKeyword
.NULL
;
621 String text
= type
.getInternalCanonicalText();
622 return text
== null ? PsiKeyword
.NULL
: text
;
626 public static HighlightInfo
checkUnhandledExceptions(PsiElement element
, TextRange fixRange
) {
627 List
<PsiClassType
> unhandledExceptions
= ExceptionUtil
.getUnhandledExceptions(element
);
628 HighlightInfo errorResult
= null;
629 if (!unhandledExceptions
.isEmpty()) {
630 if (fixRange
== null) {
631 fixRange
= element
.getTextRange();
633 HighlightInfoType highlightType
= getUnhandledExceptionHighlightType(element
);
634 if (highlightType
== null) return null;
635 errorResult
= HighlightInfo
.createHighlightInfo(highlightType
, fixRange
, getUnhandledExceptionsDescriptor(unhandledExceptions
));
636 QuickFixAction
.registerQuickFixAction(errorResult
, new AddExceptionToCatchFix());
637 QuickFixAction
.registerQuickFixAction(errorResult
, new AddExceptionToThrowsFix(element
));
638 QuickFixAction
.registerQuickFixAction(errorResult
, new SurroundWithTryCatchFix(element
));
639 if (unhandledExceptions
.size() == 1) {
640 QuickFixAction
.registerQuickFixAction(errorResult
, new GeneralizeCatchFix(element
, unhandledExceptions
.get(0)));
646 private static HighlightInfoType
getUnhandledExceptionHighlightType(final PsiElement element
) {
647 if (!JspPsiUtil
.isInJspFile(element
)) {
648 return HighlightInfoType
.UNHANDLED_EXCEPTION
;
650 PsiMethod targetMethod
= PsiTreeUtil
.getParentOfType(element
, PsiMethod
.class);
651 if (!(targetMethod
instanceof JspHolderMethod
)) return HighlightInfoType
.UNHANDLED_EXCEPTION
;
652 // ignore JSP top level errors - it handled by UnhandledExceptionInJSP inspection
658 static HighlightInfo
checkBreakOutsideLoop(PsiBreakStatement statement
) {
659 if (statement
.getLabelIdentifier() == null) {
660 if (new PsiMatcherImpl(statement
).ancestor(EnclosingLoopOrSwitchMatcherExpression
.INSTANCE
).getElement() == null) {
662 .createHighlightInfo(HighlightInfoType
.ERROR
, statement
, JavaErrorMessages
.message("break.outside.switch.or.loop"));
673 static HighlightInfo
checkContinueOutsideLoop(PsiContinueStatement statement
) {
674 if (statement
.getLabelIdentifier() == null) {
675 if (new PsiMatcherImpl(statement
).ancestor(EnclosingLoopMatcherExpression
.INSTANCE
).getElement() == null) {
676 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, statement
, JavaErrorMessages
.message("continue.outside.loop"));
680 PsiStatement exitedStatement
= statement
.findContinuedStatement();
681 if (exitedStatement
== null) return null;
682 if (!(exitedStatement
instanceof PsiForStatement
) && !(exitedStatement
instanceof PsiWhileStatement
) &&
683 !(exitedStatement
instanceof PsiDoWhileStatement
) && !(exitedStatement
instanceof PsiForeachStatement
)) {
684 String description
= JavaErrorMessages
.message("not.loop.label", statement
.getLabelIdentifier().getText());
685 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, statement
, description
);
692 static HighlightInfo
checkIllegalModifierCombination(PsiKeyword keyword
, PsiModifierList modifierList
) {
693 @Modifier String modifier
= keyword
.getText();
694 String incompatible
= getIncompatibleModifier(modifier
, modifierList
);
696 HighlightInfo highlightInfo
= null;
697 if (incompatible
!= null) {
698 String message
= JavaErrorMessages
.message("incompatible.modifiers", modifier
, incompatible
);
700 highlightInfo
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, keyword
, message
);
702 QuickFixAction
.registerQuickFixAction(highlightInfo
, QUICK_FIX_FACTORY
.createModifierListFix(modifierList
, modifier
, false, false));
704 return highlightInfo
;
708 private static Map
<String
, Set
<String
>> getIncompatibleModifierMap(PsiModifierList modifierList
) {
709 PsiElement parent
= modifierList
.getParent();
710 if (parent
== null || PsiUtilBase
.hasErrorElementChild(parent
)) return null;
711 return parent
instanceof PsiClass
712 ?
((PsiClass
)parent
).isInterface() ? ourInterfaceIncompatibleModifiers
: ourClassIncompatibleModifiers
713 : parent
instanceof PsiMethod
714 ? ourMethodIncompatibleModifiers
715 : parent
instanceof PsiVariable
716 ? ourFieldIncompatibleModifiers
717 : parent
instanceof PsiClassInitializer ? ourClassInitializerIncompatibleModifiers
: null;
721 public static String
getIncompatibleModifier(String modifier
, PsiModifierList modifierList
) {
722 PsiElement parent
= modifierList
.getParent();
723 if (parent
== null || PsiUtilBase
.hasErrorElementChild(parent
)) return null;
724 final Map
<String
, Set
<String
>> incompatibleModifierMap
= getIncompatibleModifierMap(modifierList
);
725 if (incompatibleModifierMap
== null) return null;
726 return getIncompatibleModifier(modifier
, modifierList
, incompatibleModifierMap
);
731 public static HighlightInfo
checkNotAllowedModifier(PsiKeyword keyword
, PsiModifierList modifierList
) {
732 PsiElement modifierOwner
= modifierList
.getParent();
733 if (modifierOwner
== null) return null;
734 if (PsiUtilBase
.hasErrorElementChild(modifierOwner
)) return null;
735 @Modifier String modifier
= keyword
.getText();
736 final Map
<String
, Set
<String
>> incompatibleModifierMap
= getIncompatibleModifierMap(modifierList
);
737 if (incompatibleModifierMap
== null) return null;
738 Set
<String
> incompatibles
= incompatibleModifierMap
.get(modifier
);
739 PsiElement modifierOwnerParent
= modifierOwner
instanceof PsiMember ?
((PsiMember
)modifierOwner
).getContainingClass() : modifierOwner
.getParent();
740 if (modifierOwnerParent
== null) modifierOwnerParent
= modifierOwner
.getParent();
741 boolean isAllowed
= true;
742 if (modifierOwner
instanceof PsiClass
) {
743 PsiClass aClass
= (PsiClass
)modifierOwner
;
744 if (aClass
.isInterface()) {
745 if (PsiModifier
.STATIC
.equals(modifier
) || PsiModifier
.PRIVATE
.equals(modifier
) || PsiModifier
.PROTECTED
.equals(modifier
) ||
746 PsiModifier
.PACKAGE_LOCAL
.equals(modifier
)) {
747 isAllowed
= modifierOwnerParent
instanceof PsiClass
;
751 if (PsiModifier
.PUBLIC
.equals(modifier
)) {
752 isAllowed
= modifierOwnerParent
instanceof PsiJavaFile
|| modifierOwnerParent
instanceof PsiClass
;
754 else if (PsiModifier
.STATIC
.equals(modifier
) || PsiModifier
.PRIVATE
.equals(modifier
) || PsiModifier
.PROTECTED
.equals(modifier
) ||
755 PsiModifier
.PACKAGE_LOCAL
.equals(modifier
)) {
756 isAllowed
= modifierOwnerParent
instanceof PsiClass
;
759 if (aClass
.isEnum()) {
760 isAllowed
&= !(PsiModifier
.FINAL
.equals(modifier
) || PsiModifier
.ABSTRACT
.equals(modifier
));
764 else if (modifierOwner
instanceof PsiMethod
) {
765 PsiMethod method
= (PsiMethod
)modifierOwner
;
766 isAllowed
= !(method
.isConstructor() && ourConstructorNotAllowedModifiers
.contains(modifier
));
767 if ((method
.hasModifierProperty(PsiModifier
.PUBLIC
) || method
.hasModifierProperty(PsiModifier
.PROTECTED
)) && method
.isConstructor() &&
768 method
.getContainingClass() != null && method
.getContainingClass().isEnum()) {
772 if (PsiModifier
.PRIVATE
.equals(modifier
) || PsiModifier
.PROTECTED
.equals(modifier
) || PsiModifier
.TRANSIENT
.equals(modifier
) ||
773 PsiModifier
.STRICTFP
.equals(modifier
) || PsiModifier
.SYNCHRONIZED
.equals(modifier
)) {
774 isAllowed
&= modifierOwnerParent
instanceof PsiClass
&& !((PsiClass
)modifierOwnerParent
).isInterface();
777 else if (modifierOwner
instanceof PsiField
) {
778 if (PsiModifier
.PRIVATE
.equals(modifier
) || PsiModifier
.PROTECTED
.equals(modifier
) || PsiModifier
.TRANSIENT
.equals(modifier
) ||
779 PsiModifier
.STRICTFP
.equals(modifier
) || PsiModifier
.SYNCHRONIZED
.equals(modifier
)) {
780 isAllowed
= modifierOwnerParent
instanceof PsiClass
&& !((PsiClass
)modifierOwnerParent
).isInterface();
783 else if (modifierOwner
instanceof PsiClassInitializer
) {
784 isAllowed
= PsiModifier
.STATIC
.equals(modifier
);
786 else if (modifierOwner
instanceof PsiLocalVariable
|| modifierOwner
instanceof PsiParameter
) {
787 isAllowed
= PsiModifier
.FINAL
.equals(modifier
);
790 isAllowed
&= incompatibles
!= null;
792 String message
= JavaErrorMessages
.message("modifier.not.allowed", modifier
);
794 HighlightInfo highlightInfo
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, keyword
, message
);
795 QuickFixAction
.registerQuickFixAction(highlightInfo
, QUICK_FIX_FACTORY
.createModifierListFix(modifierList
, modifier
, false, false));
796 return highlightInfo
;
803 static HighlightInfo
checkLiteralExpressionParsingError(PsiLiteralExpression expression
) {
804 String error
= expression
.getParsingError();
806 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, expression
, error
);
813 static HighlightInfo
checkMustBeBoolean(PsiExpression expr
) {
814 PsiElement parent
= expr
.getParent();
815 if (parent
instanceof PsiIfStatement
|| parent
instanceof PsiWhileStatement
||
816 parent
instanceof PsiForStatement
&& expr
.equals(((PsiForStatement
)parent
).getCondition()) ||
817 parent
instanceof PsiDoWhileStatement
&& expr
.equals(((PsiDoWhileStatement
)parent
).getCondition())) {
818 if (expr
.getNextSibling() instanceof PsiErrorElement
) return null;
820 PsiType type
= expr
.getType();
821 if (!TypeConversionUtil
.isBooleanType(type
)) {
822 final HighlightInfo info
= createIncompatibleTypeHighlightInfo(PsiType
.BOOLEAN
, type
, expr
.getTextRange());
823 if (expr
instanceof PsiMethodCallExpression
) {
824 final PsiMethodCallExpression methodCall
= (PsiMethodCallExpression
) expr
;
825 final PsiMethod method
= methodCall
.resolveMethod();
826 if (method
!= null && PsiType
.VOID
.equals(method
.getReturnType())) {
827 QuickFixAction
.registerQuickFixAction(info
, new MethodReturnBooleanFix(method
, PsiType
.BOOLEAN
));
838 static HighlightInfo
checkExceptionThrownInTry(PsiParameter parameter
) {
839 PsiElement declarationScope
= parameter
.getDeclarationScope();
840 if (!(declarationScope
instanceof PsiCatchSection
)) return null;
841 PsiTryStatement statement
= ((PsiCatchSection
)declarationScope
).getTryStatement();
842 Collection
<PsiClassType
> classes
= ExceptionUtil
.collectUnhandledExceptions(statement
.getTryBlock(), statement
.getTryBlock());
844 PsiType caughtType
= parameter
.getType();
845 if (!(caughtType
instanceof PsiClassType
)) return null;
846 if (ExceptionUtil
.isUncheckedExceptionOrSuperclass((PsiClassType
)caughtType
)) return null;
848 for (PsiClassType exceptionType
: classes
) {
849 if (exceptionType
.isAssignableFrom(caughtType
) || caughtType
.isAssignableFrom(exceptionType
)) return null;
852 String description
= JavaErrorMessages
.message("exception.never.thrown.try", formatType(caughtType
));
853 HighlightInfo errorResult
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, parameter
, description
);
855 QuickFixAction
.registerQuickFixAction(errorResult
, new DeleteCatchFix(parameter
));
861 static HighlightInfo
checkNotAStatement(PsiStatement statement
) {
862 if (!PsiUtil
.isStatement(statement
) && !PsiUtilBase
.hasErrorElementChild(statement
)) {
863 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, statement
, JavaErrorMessages
.message("not.a.statement"));
869 public static HighlightInfo
checkSwitchSelectorType(PsiSwitchStatement statement
) {
870 PsiExpression expression
= statement
.getExpression();
871 HighlightInfo errorResult
= null;
872 if (expression
!= null && expression
.getType() != null) {
873 PsiType type
= expression
.getType();
874 if (!isValidTypeForSwitchSelector(type
)) {
876 JavaErrorMessages
.message("incompatible.types", JavaErrorMessages
.message("valid.switch.selector.types"), formatType(type
));
877 errorResult
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, expression
, message
);
878 if (PsiType
.LONG
.equals(type
) || PsiType
.FLOAT
.equals(type
) || PsiType
.DOUBLE
.equals(type
)) {
879 QuickFixAction
.registerQuickFixAction(errorResult
, new AddTypeCastFix(PsiType
.INT
, expression
));
886 private static boolean isValidTypeForSwitchSelector(PsiType type
) {
887 if (TypeConversionUtil
.getTypeRank(type
) <= TypeConversionUtil
.INT_RANK
) return true;
888 if (type
instanceof PsiClassType
) {
889 PsiClass psiClass
= ((PsiClassType
)type
).resolve();
890 if (psiClass
== null) return false;
891 if (psiClass
.isEnum()) {
900 static HighlightInfo
checkBinaryOperatorApplicable(PsiBinaryExpression expression
) {
901 PsiExpression lOperand
= expression
.getLOperand();
902 PsiExpression rOperand
= expression
.getROperand();
903 PsiJavaToken operationSign
= expression
.getOperationSign();
904 if (!TypeConversionUtil
.isBinaryOperatorApplicable(operationSign
.getTokenType(), lOperand
, rOperand
, false)) {
905 String message
= JavaErrorMessages
906 .message("binary.operator.not.applicable", operationSign
.getText(), formatType(lOperand
.getType()), formatType(rOperand
.getType()));
907 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, expression
, message
);
914 public static HighlightInfo
checkUnaryOperatorApplicable(PsiJavaToken token
, PsiExpression expression
) {
915 if (token
!= null && expression
!= null && !TypeConversionUtil
.isUnaryOperatorApplicable(token
, expression
)) {
916 PsiType type
= expression
.getType();
917 if (type
== null) return null;
918 String message
= JavaErrorMessages
.message("unary.operator.not.applicable", token
.getText(), formatType(type
));
920 PsiElement parentExpr
= token
.getParent();
921 HighlightInfo highlightInfo
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, parentExpr
, message
);
922 if (parentExpr
instanceof PsiPrefixExpression
&& token
.getTokenType() == JavaTokenType
.EXCL
) {
923 QuickFixAction
.registerQuickFixAction(highlightInfo
, new NegationBroadScopeFix((PsiPrefixExpression
)parentExpr
));
925 return highlightInfo
;
931 public static HighlightInfo
checkThisOrSuperExpressionInIllegalContext(PsiExpression expr
, @Nullable PsiJavaCodeReferenceElement qualifier
) {
932 if (expr
instanceof PsiSuperExpression
&& !(expr
.getParent() instanceof PsiReferenceExpression
)) {
933 // like in 'Object o = super;'
934 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, expr
.getTextRange().getEndOffset(),
935 expr
.getTextRange().getEndOffset() + 1,
936 JavaErrorMessages
.message("dot.expected.after.super.or.this"));
938 PsiClass aClass
= qualifier
== null ? PsiTreeUtil
.getParentOfType(expr
, PsiClass
.class) : (PsiClass
)qualifier
.resolve();
939 if (aClass
== null) return null;
940 if (qualifier
!= null && aClass
.isInterface()) {
941 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, qualifier
, HighlightClassUtil
.CLASS_EXPECTED
);
943 if (!HighlightClassUtil
.hasEnclosingInstanceInScope(aClass
, expr
, false)) {
944 return HighlightClassUtil
.reportIllegalEnclosingUsage(expr
, null, aClass
, expr
);
951 static String
buildProblemWithStaticDescription(PsiElement refElement
) {
952 String type
= LanguageFindUsages
.INSTANCE
.forLanguage(StdLanguages
.JAVA
).getType(refElement
);
953 String name
= HighlightMessageUtil
.getSymbolName(refElement
, PsiSubstitutor
.EMPTY
);
954 return JavaErrorMessages
.message("non.static.symbol.referenced.from.static.context", type
, name
);
957 static void registerStaticProblemQuickFixAction(@NotNull PsiElement refElement
, HighlightInfo errorResult
, PsiJavaCodeReferenceElement place
) {
958 if (refElement
instanceof PsiModifierListOwner
) {
959 QuickFixAction
.registerQuickFixAction(errorResult
, QUICK_FIX_FACTORY
.createModifierListFix((PsiModifierListOwner
)refElement
, PsiModifier
.STATIC
, true, false));
961 // make context non static
962 PsiModifierListOwner staticParent
= PsiUtil
.getEnclosingStaticElement(place
, null);
963 if (staticParent
!= null && isInstanceReference(place
)) {
964 QuickFixAction
.registerQuickFixAction(errorResult
, QUICK_FIX_FACTORY
.createModifierListFix(staticParent
, PsiModifier
.STATIC
, false, false));
968 private static boolean isInstanceReference(PsiJavaCodeReferenceElement place
) {
969 PsiElement qualifier
= place
.getQualifier();
970 if (qualifier
== null) return true;
971 if (!(qualifier
instanceof PsiJavaCodeReferenceElement
)) return false;
972 PsiElement q
= ((PsiReference
)qualifier
).resolve();
973 if (q
instanceof PsiClass
) return false;
974 if (q
!= null) return true;
975 String qname
= ((PsiJavaCodeReferenceElement
)qualifier
).getQualifiedName();
976 return qname
== null || !Character
.isLowerCase(qname
.charAt(0));
979 static String
buildProblemWithAccessDescription(PsiJavaCodeReferenceElement reference
, JavaResolveResult result
) {
980 PsiModifierListOwner refElement
= (PsiModifierListOwner
)result
.getElement();
981 String symbolName
= HighlightMessageUtil
.getSymbolName(refElement
, result
.getSubstitutor());
983 if (refElement
.hasModifierProperty(PsiModifier
.PRIVATE
)) {
984 String containerName
= HighlightMessageUtil
.getSymbolName(refElement
.getParent(), result
.getSubstitutor());
985 return JavaErrorMessages
.message("private.symbol", symbolName
, containerName
);
988 if (refElement
.hasModifierProperty(PsiModifier
.PROTECTED
)) {
989 String containerName
= HighlightMessageUtil
.getSymbolName(refElement
.getParent(), result
.getSubstitutor());
990 return JavaErrorMessages
.message("protected.symbol", symbolName
, containerName
);
993 PsiClass packageLocalClass
= getPackageLocalClassInTheMiddle(reference
);
994 if (packageLocalClass
!= null) {
995 refElement
= packageLocalClass
;
996 symbolName
= HighlightMessageUtil
.getSymbolName(refElement
, result
.getSubstitutor());
998 if (refElement
.hasModifierProperty(PsiModifier
.PACKAGE_LOCAL
) || packageLocalClass
!= null) {
999 String containerName
= HighlightMessageUtil
.getSymbolName(refElement
.getParent(), result
.getSubstitutor());
1000 return JavaErrorMessages
.message("package.local.symbol", symbolName
, containerName
);
1003 String containerName
= HighlightMessageUtil
.getSymbolName(
1004 refElement
instanceof PsiTypeParameter ? refElement
.getParent().getParent() : refElement
.getParent(), result
.getSubstitutor());
1005 return JavaErrorMessages
.message("visibility.access.problem", symbolName
, containerName
);
1012 static HighlightInfo
checkValidArrayAccessExpression(PsiExpression arrayExpression
, PsiExpression indexExpression
) {
1013 PsiType arrayExpressionType
= arrayExpression
== null ?
null : arrayExpression
.getType();
1014 if (arrayExpressionType
!= null && !(arrayExpressionType
instanceof PsiArrayType
)) {
1015 String description
= JavaErrorMessages
.message("array.type.expected", formatType(arrayExpressionType
));
1016 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, arrayExpression
, description
);
1018 return checkAssignability(PsiType
.INT
, indexExpression
.getType(), indexExpression
, indexExpression
);
1023 public static HighlightInfo
checkCatchParameterIsThrowable(PsiParameter parameter
) {
1024 if (parameter
.getDeclarationScope() instanceof PsiCatchSection
) {
1025 PsiType type
= parameter
.getType();
1026 return checkMustBeThrowable(type
, parameter
, true);
1031 public static void checkArrayInitalizer(final PsiExpression initializer
, final HighlightInfoHolder holder
) {
1032 if (! (initializer
instanceof PsiArrayInitializerExpression
)) return;
1034 final PsiType arrayInitializerType
= initializer
.getType();
1035 if (! (arrayInitializerType
instanceof PsiArrayType
)) return;
1037 final PsiType componentType
= ((PsiArrayType
) arrayInitializerType
).getComponentType();
1038 final PsiArrayInitializerExpression arrayInitializer
= (PsiArrayInitializerExpression
) initializer
;
1040 boolean arrayTypeFixChecked
= false;
1041 VariableArrayTypeFix fix
= null;
1043 final PsiExpression
[] initializers
= arrayInitializer
.getInitializers();
1044 for (PsiExpression expression
: initializers
) {
1045 final HighlightInfo info
= checkArrayInitalizerCompatibleTypes(expression
, componentType
);
1049 if (!arrayTypeFixChecked
) {
1050 final PsiType checkResult
= sameType(initializers
);
1051 fix
= checkResult
!= null ?
new VariableArrayTypeFix(arrayInitializer
, checkResult
) : null;
1052 arrayTypeFixChecked
= true;
1055 QuickFixAction
.registerQuickFixAction(info
, fix
);
1062 private static PsiType
getArrayInitializerType(final PsiArrayInitializerExpression element
) {
1063 final PsiType typeCheckResult
= sameType(element
.getInitializers());
1064 if (typeCheckResult
!= null) {
1065 return typeCheckResult
.createArrayType();
1070 private static PsiType
sameType(PsiExpression
[] expressions
) {
1071 PsiType type
= null;
1072 for (PsiExpression expression
: expressions
) {
1073 final PsiType currentType
;
1074 if (expression
instanceof PsiArrayInitializerExpression
) {
1075 currentType
= getArrayInitializerType((PsiArrayInitializerExpression
)expression
);
1078 currentType
= expression
.getType();
1083 else if (!type
.equals(currentType
)) {
1091 private static HighlightInfo
checkArrayInitalizerCompatibleTypes(PsiExpression initializer
, final PsiType componentType
) {
1092 PsiType initializerType
= initializer
.getType();
1093 if (initializerType
== null) {
1094 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, initializer
,
1095 JavaErrorMessages
.message("illegal.initializer", formatType(componentType
)));
1097 PsiExpression expression
= initializer
instanceof PsiArrayInitializerExpression ?
null : initializer
;
1098 return checkAssignability(componentType
, initializerType
, expression
, initializer
);
1102 public static HighlightInfo
checkExpressionRequired(PsiReferenceExpression expression
) {
1103 if (expression
.getNextSibling() instanceof PsiErrorElement
) return null;
1104 PsiElement resolved
= expression
.advancedResolve(true).getElement();
1105 if (resolved
== null) return null;
1106 PsiElement parent
= expression
.getParent();
1107 // String.class or String() are both correct
1108 if (parent
instanceof PsiReferenceExpression
|| parent
instanceof PsiMethodCallExpression
) return null;
1109 if (resolved
instanceof PsiVariable
) return null;
1110 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, expression
, JavaErrorMessages
.message("expression.expected"));
1115 public static HighlightInfo
checkArrayInitializerApplicable(PsiArrayInitializerExpression expression
) {
1117 JLS 10.6 Array Initializers
1118 An array initializer may be specified in a declaration, or as part of an array creation expression
1120 PsiElement parent
= expression
.getParent();
1121 if (parent
instanceof PsiVariable
) {
1122 PsiVariable variable
= (PsiVariable
)parent
;
1123 if (variable
.getType() instanceof PsiArrayType
) return null;
1125 else if (parent
instanceof PsiNewExpression
) {
1128 else if (parent
instanceof PsiArrayInitializerExpression
) {
1131 HighlightInfo info
=
1132 HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, expression
, JavaErrorMessages
.message("expression.expected"));
1133 QuickFixAction
.registerQuickFixAction(info
, new AddNewArrayExpressionFix(expression
));
1140 public static HighlightInfo
checkCaseStatement(PsiSwitchLabelStatement statement
) {
1141 PsiSwitchStatement switchStatement
= statement
.getEnclosingSwitchStatement();
1142 if (switchStatement
== null) {
1143 return HighlightInfo
1144 .createHighlightInfo(HighlightInfoType
.ERROR
, statement
, JavaErrorMessages
.message("case.statement.outside.switch"));
1146 if (switchStatement
.getBody() == null) return null;
1147 PsiExpression switchExpression
= switchStatement
.getExpression();
1148 PsiType switchType
= switchExpression
== null ? PsiType
.INT
: switchExpression
.getType();
1149 // check constant expression
1150 PsiExpression caseValue
= statement
.getCaseValue();
1152 // Every case constant expression associated with a switch statement must be assignable ($5.2) to the type of the switch Expression.
1153 if (caseValue
!= null && switchExpression
!= null) {
1154 HighlightInfo highlightInfo
= checkAssignability(switchType
, caseValue
.getType(), caseValue
, caseValue
);
1155 if (highlightInfo
!= null) return highlightInfo
;
1157 Object value
= null;
1159 boolean isEnumSwitch
= false;
1160 if (!statement
.isDefaultCase() && caseValue
!= null) {
1161 if (caseValue
instanceof PsiReferenceExpression
) {
1162 PsiElement element
= ((PsiReferenceExpression
)caseValue
).resolve();
1163 if (element
instanceof PsiEnumConstant
) {
1164 isEnumSwitch
= true;
1165 value
= ((PsiEnumConstant
)element
).getName();
1166 if (!(((PsiReferenceExpression
)caseValue
).getQualifier() == null)) {
1167 String message
= JavaErrorMessages
.message("qualified.enum.constant.in.switch");
1168 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, caseValue
, message
);
1172 if (!isEnumSwitch
) {
1173 value
= ConstantExpressionUtil
.computeCastTo(caseValue
, switchType
);
1175 if (value
== null) {
1176 return HighlightInfo
1177 .createHighlightInfo(HighlightInfoType
.ERROR
, caseValue
, JavaErrorMessages
.message("constant.expression.required"));
1182 PsiStatement
[] statements
= switchStatement
.getBody().getStatements();
1183 for (PsiStatement st
: statements
) {
1184 if (st
== statement
) continue;
1185 if (!(st
instanceof PsiSwitchLabelStatement
)) continue;
1186 PsiSwitchLabelStatement labelStatement
= (PsiSwitchLabelStatement
)st
;
1187 if (labelStatement
.isDefaultCase() != statement
.isDefaultCase()) continue;
1188 PsiExpression caseExpr
= labelStatement
.getCaseValue();
1189 if (isEnumSwitch
&& caseExpr
instanceof PsiReferenceExpression
) {
1190 PsiElement element
= ((PsiReferenceExpression
)caseExpr
).resolve();
1191 if (!(element
instanceof PsiEnumConstant
&& Comparing
.equal(((PsiEnumConstant
)element
).getName(), value
))) continue;
1194 // not assignable error already caught
1195 if (!TypeConversionUtil
.areTypesAssignmentCompatible(switchType
, caseExpr
)) continue;
1196 if (!Comparing
.equal(ConstantExpressionUtil
.computeCastTo(caseExpr
, switchType
), value
)) continue;
1198 String description
= statement
.isDefaultCase()
1199 ? JavaErrorMessages
.message("duplicate.default.switch.label")
1200 : JavaErrorMessages
.message("duplicate.switch.label", value
);
1201 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, value
== null ? statement
: caseValue
, description
);
1204 // must be followed with colon
1205 PsiElement lastChild
= statement
.getLastChild();
1206 while (lastChild
instanceof PsiComment
|| lastChild
instanceof PsiWhiteSpace
) {
1207 lastChild
= lastChild
.getPrevSibling();
1209 if (!(lastChild
instanceof PsiJavaToken
&& ((PsiJavaToken
)lastChild
).getTokenType() == JavaTokenType
.COLON
)) {
1210 int start
= statement
.getTextRange().getEndOffset();
1211 int end
= statement
.getTextRange().getEndOffset() + 1;
1212 String description
= JavaErrorMessages
.message("switch.colon.expected.after.case.label");
1213 CharSequence chars
= statement
.getContainingFile().getViewProvider().getContents();
1214 boolean isAfterEndOfLine
= end
>= chars
.length() || chars
.charAt(start
) == '\n' || chars
.charAt(start
) == '\r';
1215 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, null,start
, end
, description
, description
,isAfterEndOfLine
, null);
1225 public static HighlightInfo
checkIllegalForwardReferenceToField(PsiReferenceExpression expression
, PsiField referencedField
) {
1226 PsiClass containingClass
= referencedField
.getContainingClass();
1227 if (containingClass
== null) return null;
1228 if (expression
.getContainingFile() != referencedField
.getContainingFile()) return null;
1229 if (expression
.getTextRange().getStartOffset() >= referencedField
.getTextRange().getEndOffset()) return null;
1230 // only simple reference can be illegal
1231 if (expression
.getQualifierExpression() != null) return null;
1232 PsiField initField
= findEnclosingFieldInitializer(expression
);
1233 PsiClassInitializer classInitializer
= findParentClassInitializer(expression
);
1234 if (initField
== null && classInitializer
== null) return null;
1235 // instance initializers may access static fields
1236 boolean isStaticClassInitializer
= classInitializer
!= null && classInitializer
.hasModifierProperty(PsiModifier
.STATIC
);
1237 boolean isStaticInitField
= initField
!= null && initField
.hasModifierProperty(PsiModifier
.STATIC
);
1238 boolean inStaticContext
= isStaticInitField
|| isStaticClassInitializer
;
1239 if (!inStaticContext
&& referencedField
.hasModifierProperty(PsiModifier
.STATIC
)) return null;
1240 if (PsiUtil
.isOnAssignmentLeftHand(expression
) && !PsiUtil
.isAccessedForReading(expression
)) return null;
1241 if (!containingClass
.getManager().areElementsEquivalent(containingClass
, PsiTreeUtil
.getParentOfType(expression
, PsiClass
.class))) {
1244 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, expression
, JavaErrorMessages
.message("illegal.forward.reference"));
1248 * @return field that has initializer with this element as subexpression or null if not found
1251 static PsiField
findEnclosingFieldInitializer(PsiElement element
) {
1252 while (element
!= null) {
1253 PsiElement parent
= element
.getParent();
1254 if (parent
instanceof PsiField
) {
1255 PsiField field
= (PsiField
)parent
;
1256 if (element
== field
.getInitializer()) return field
;
1257 if (field
instanceof PsiEnumConstant
&& element
== ((PsiEnumConstant
)field
).getArgumentList()) return field
;
1259 if (element
instanceof PsiClass
|| element
instanceof PsiMethod
) return null;
1266 private static PsiClassInitializer
findParentClassInitializer(PsiElement element
) {
1267 while (element
!= null) {
1268 if (element
instanceof PsiClassInitializer
) return (PsiClassInitializer
)element
;
1269 if (element
instanceof PsiClass
|| element
instanceof PsiMethod
) return null;
1270 element
= element
.getParent();
1277 public static HighlightInfo
checkIllegalType(PsiTypeElement typeElement
) {
1278 if (typeElement
== null || typeElement
.getParent() instanceof PsiTypeElement
) return null;
1280 if (PsiUtil
.isInsideJavadocComment(typeElement
)) return null;
1282 PsiType type
= typeElement
.getType();
1283 PsiType componentType
= type
.getDeepComponentType();
1284 if (componentType
instanceof PsiClassType
) {
1285 PsiClass aClass
= PsiUtil
.resolveClassInType(componentType
);
1286 if (aClass
== null) {
1287 String canonicalText
= type
.getCanonicalText();
1288 String description
= JavaErrorMessages
.message("unknown.class", canonicalText
);
1289 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, typeElement
, description
);
1297 public static HighlightInfo
checkIllegalVoidType(PsiKeyword type
) {
1298 if (!PsiKeyword
.VOID
.equals(type
.getText())) return null;
1300 PsiElement parent
= type
.getParent();
1301 if (parent
instanceof PsiTypeElement
) {
1302 PsiElement typeOwner
= parent
.getParent();
1303 if (typeOwner
instanceof PsiMethod
) {
1304 if (((PsiMethod
)typeOwner
).getReturnTypeElement() == parent
) return null;
1306 else if (typeOwner
instanceof PsiClassObjectAccessExpression
&&
1307 TypeConversionUtil
.isVoidType(((PsiClassObjectAccessExpression
)typeOwner
).getOperand().getType())) {
1308 // like in Class c = void.class;
1311 else if (typeOwner
!= null && PsiUtilBase
.hasErrorElementChild(typeOwner
)) {
1312 // do not highlight incomplete declarations
1315 else if (typeOwner
instanceof JavaCodeFragment
) {
1316 if (typeOwner
.getUserData(PsiUtil
.VALID_VOID_TYPE_IN_CODE_FRAGMENT
) != null) return null;
1320 String description
= JavaErrorMessages
.message("illegal.type.void");
1321 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, type
, description
);
1325 public static HighlightInfo
checkMemberReferencedBeforeConstructorCalled(PsiElement expression
) {
1326 PsiClass referencedClass
;
1327 @NonNls String resolvedName
;
1329 if (expression
instanceof PsiJavaCodeReferenceElement
) {
1330 PsiElement resolved
= ((PsiJavaCodeReferenceElement
)expression
).advancedResolve(true).getElement();
1332 if (PsiKeyword
.THIS
.equals(((PsiJavaCodeReferenceElement
)expression
).getReferenceName())
1333 && resolved
instanceof PsiMethod
1334 && ((PsiMethod
)resolved
).isConstructor()) return null;
1335 PsiElement qualifier
= ((PsiJavaCodeReferenceElement
)expression
).getQualifier();
1336 type
= qualifier
instanceof PsiExpression ?
((PsiExpression
)qualifier
).getType() : null;
1337 referencedClass
= PsiUtil
.resolveClassInType(type
);
1339 boolean isSuperCall
= isSuperMethodCall(expression
.getParent());
1340 if (resolved
== null && isSuperCall
) {
1341 if (qualifier
instanceof PsiReferenceExpression
) {
1342 resolved
= ((PsiReferenceExpression
)qualifier
).resolve();
1343 expression
= qualifier
;
1344 type
= ((PsiReferenceExpression
)qualifier
).getType();
1345 referencedClass
= PsiUtil
.resolveClassInType(type
);
1347 else if (qualifier
instanceof PsiThisExpression
|| qualifier
== null) {
1348 resolved
= PsiTreeUtil
.getParentOfType(expression
, PsiMethod
.class, true, PsiMember
.class);
1349 expression
= qualifier
== null ? expression
: qualifier
;
1350 if (resolved
instanceof PsiMethod
) {
1351 referencedClass
= ((PsiMethod
)resolved
).getContainingClass();
1355 if (resolved
instanceof PsiField
) {
1356 PsiField referencedField
= (PsiField
)resolved
;
1357 if (referencedField
.hasModifierProperty(PsiModifier
.STATIC
)) return null;
1358 resolvedName
= PsiFormatUtil
.formatVariable(referencedField
, PsiFormatUtil
.SHOW_CONTAINING_CLASS
| PsiFormatUtil
.SHOW_NAME
, PsiSubstitutor
.EMPTY
);
1359 referencedClass
= referencedField
.getContainingClass();
1361 else if (resolved
instanceof PsiMethod
) {
1362 PsiMethod method
= (PsiMethod
)resolved
;
1363 if (method
.hasModifierProperty(PsiModifier
.STATIC
)) return null;
1364 PsiElement nameElement
= expression
instanceof PsiThisExpression ? expression
: ((PsiJavaCodeReferenceElement
)expression
).getReferenceNameElement();
1365 String name
= nameElement
== null ?
null : nameElement
.getText();
1367 if (referencedClass
== null) return null;
1368 if (qualifier
== null) {
1369 PsiClass superClass
= referencedClass
.getSuperClass();
1370 if (superClass
!= null
1371 && PsiUtil
.isInnerClass(superClass
)
1372 && InheritanceUtil
.isInheritorOrSelf(referencedClass
, superClass
.getContainingClass(), true)) {
1373 // by default super() is considered this. - qualified
1374 resolvedName
= PsiKeyword
.THIS
;
1381 resolvedName
= qualifier
.getText();
1384 else if (PsiKeyword
.THIS
.equals(name
)) {
1385 resolvedName
= PsiKeyword
.THIS
;
1388 resolvedName
= PsiFormatUtil
.formatMethod(method
, PsiSubstitutor
.EMPTY
, PsiFormatUtil
.SHOW_CONTAINING_CLASS
| PsiFormatUtil
.SHOW_NAME
, 0);
1389 if (referencedClass
== null) referencedClass
= method
.getContainingClass();
1392 else if (resolved
instanceof PsiClass
) {
1393 PsiClass aClass
= (PsiClass
)resolved
;
1394 if (aClass
.hasModifierProperty(PsiModifier
.STATIC
)) return null;
1395 referencedClass
= aClass
.getContainingClass();
1396 if (referencedClass
== null) return null;
1397 resolvedName
= PsiFormatUtil
.formatClass(aClass
, PsiFormatUtil
.SHOW_NAME
);
1403 else if (expression
instanceof PsiThisExpression
) {
1404 PsiThisExpression thisExpression
= (PsiThisExpression
)expression
;
1405 type
= thisExpression
.getType();
1406 referencedClass
= PsiUtil
.resolveClassInType(type
);
1407 if (thisExpression
.getQualifier() != null) {
1408 resolvedName
= referencedClass
== null
1410 : PsiFormatUtil
.formatClass(referencedClass
, PsiFormatUtil
.SHOW_CONTAINING_CLASS
| PsiFormatUtil
.SHOW_NAME
) + ".this";
1413 resolvedName
= "this";
1419 if (referencedClass
== null) return null;
1420 return checkReferenceToOurInstanceInsideThisOrSuper(expression
, referencedClass
, resolvedName
);
1423 private static HighlightInfo
checkReferenceToOurInstanceInsideThisOrSuper(final PsiElement expression
,
1424 final PsiClass referencedClass
,
1425 final String resolvedName
) {
1426 if (PsiTreeUtil
.getParentOfType(expression
, PsiReferenceParameterList
.class) != null) return null;
1427 PsiElement element
= expression
.getParent();
1428 while (element
!= null) {
1429 // check if expression inside super()/this() call
1430 if (isSuperOrThisMethodCall(element
)) {
1431 PsiElement parentClass
= new PsiMatcherImpl(element
)
1432 .parent(PsiMatchers
.hasClass(PsiExpressionStatement
.class))
1433 .parent(PsiMatchers
.hasClass(PsiCodeBlock
.class))
1434 .parent(PsiMatchers
.hasClass(PsiMethod
.class))
1435 .dot(PsiMatchers
.isConstructor(true))
1436 .parent(PsiMatchers
.hasClass(PsiClass
.class))
1438 if (parentClass
== null) {
1442 // only this class/superclasses instance methods are not allowed to call
1443 PsiClass aClass
= (PsiClass
)parentClass
;
1444 if (PsiUtil
.isInnerClass(aClass
) && referencedClass
== aClass
.getContainingClass()) return null;
1445 // field or method should be declared in this class or super
1446 if (!InheritanceUtil
.isInheritorOrSelf(aClass
, referencedClass
, true)) return null;
1447 // and point to our instance
1448 if (expression
instanceof PsiReferenceExpression
&&
1449 !thisOrSuperReference(((PsiReferenceExpression
)expression
).getQualifierExpression(), aClass
)) {
1452 return createMemberReferencedError(resolvedName
, expression
.getTextRange());
1454 element
= element
.getParent();
1459 private static HighlightInfo
createMemberReferencedError(@NonNls final String resolvedName
, TextRange textRange
) {
1460 String description
= JavaErrorMessages
.message("member.referenced.before.constructor.called", resolvedName
);
1461 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, textRange
, description
);
1464 public static HighlightInfo
checkImplicitThisReferenceBeforeSuper(PsiClass aClass
) {
1465 if (aClass
instanceof PsiAnonymousClass
) return null;
1466 PsiClass superClass
= aClass
.getSuperClass();
1467 if (superClass
== null || !PsiUtil
.isInnerClass(superClass
)) return null;
1468 PsiClass outerClass
= superClass
.getContainingClass();
1469 if (!InheritanceUtil
.isInheritorOrSelf(aClass
, outerClass
, true)) {
1472 // 'this' can be used as an (implicit) super() qualifier
1473 PsiMethod
[] constructors
= aClass
.getConstructors();
1474 if (constructors
.length
== 0) {
1475 TextRange range
= HighlightNamesUtil
.getClassDeclarationTextRange(aClass
);
1476 return createMemberReferencedError(aClass
.getName()+".this", range
);
1478 for (PsiMethod constructor
: constructors
) {
1479 if (!isSuperCalledInConstructor(constructor
)) {
1480 return createMemberReferencedError(aClass
.getName()+".this", HighlightNamesUtil
.getMethodDeclarationTextRange(constructor
));
1486 private static boolean isSuperCalledInConstructor(final PsiMethod constructor
) {
1487 final PsiCodeBlock body
= constructor
.getBody();
1488 if (body
== null) return false;
1489 final PsiStatement
[] statements
= body
.getStatements();
1490 if (statements
.length
== 0) return false;
1491 final PsiStatement statement
= statements
[0];
1492 final PsiElement element
= new PsiMatcherImpl(statement
)
1493 .dot(PsiMatchers
.hasClass(PsiExpressionStatement
.class))
1494 .firstChild(PsiMatchers
.hasClass(PsiMethodCallExpression
.class))
1495 .firstChild(PsiMatchers
.hasClass(PsiReferenceExpression
.class))
1496 .firstChild(PsiMatchers
.hasClass(PsiKeyword
.class))
1497 .dot(PsiMatchers
.hasText(PsiKeyword
.SUPER
))
1499 return element
!= null;
1502 private static String
getMethodExpressionName(PsiElement element
) {
1503 if (!(element
instanceof PsiMethodCallExpression
)) return null;
1504 PsiReferenceExpression methodExpression
= ((PsiMethodCallExpression
)element
).getMethodExpression();
1505 return methodExpression
.getReferenceName();
1507 public static boolean isSuperOrThisMethodCall(PsiElement element
) {
1508 String name
= getMethodExpressionName(element
);
1509 return PsiKeyword
.SUPER
.equals(name
) || PsiKeyword
.THIS
.equals(name
);
1511 public static boolean isSuperMethodCall(PsiElement element
) {
1512 String name
= getMethodExpressionName(element
);
1513 return PsiKeyword
.SUPER
.equals(name
);
1516 private static boolean thisOrSuperReference(PsiExpression qualifierExpression
, PsiClass aClass
) {
1517 if (qualifierExpression
== null) return true;
1518 PsiJavaCodeReferenceElement qualifier
;
1519 if (qualifierExpression
instanceof PsiThisExpression
) {
1520 qualifier
= ((PsiThisExpression
)qualifierExpression
).getQualifier();
1522 else if (qualifierExpression
instanceof PsiSuperExpression
) {
1523 qualifier
= ((PsiSuperExpression
)qualifierExpression
).getQualifier();
1528 if (qualifier
== null) return true;
1529 PsiElement resolved
= qualifier
.resolve();
1530 return resolved
instanceof PsiClass
&& InheritanceUtil
.isInheritorOrSelf(aClass
, (PsiClass
)resolved
, true);
1535 public static HighlightInfo
checkLabelWithoutStatement(PsiLabeledStatement statement
) {
1536 if (statement
.getStatement() == null) {
1537 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, statement
, JavaErrorMessages
.message("label.without.statement"));
1544 public static HighlightInfo
checkLabelAlreadyInUse(PsiLabeledStatement statement
) {
1545 PsiIdentifier identifier
= statement
.getLabelIdentifier();
1546 String text
= identifier
.getText();
1547 PsiElement element
= statement
;
1548 while (element
!= null) {
1549 if (element
instanceof PsiMethod
|| element
instanceof PsiClass
) break;
1550 if (element
instanceof PsiLabeledStatement
&& element
!= statement
&&
1551 Comparing
.equal(((PsiLabeledStatement
)element
).getLabelIdentifier().getText(), text
)) {
1552 String description
= JavaErrorMessages
.message("duplicate.label", text
);
1553 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, identifier
, description
);
1555 element
= element
.getParent();
1562 public static HighlightInfo
checkUnclosedComment(PsiComment comment
) {
1563 if (!(comment
instanceof PsiDocComment
) && !(comment
.getTokenType() == JavaTokenType
.C_STYLE_COMMENT
)) return null;
1564 if (!comment
.getText().endsWith("*/")) {
1565 int start
= comment
.getTextRange().getEndOffset() - 1;
1566 int end
= start
+ 1;
1567 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, start
, end
, JavaErrorMessages
.message("nonterminated.comment"));
1574 public static HighlightInfo
checkExceptionAlreadyCaught(PsiJavaCodeReferenceElement element
, PsiElement resolved
) {
1575 if (!(resolved
instanceof PsiClass
)) return null;
1576 PsiClass catchClass
= (PsiClass
)resolved
;
1577 if (!(element
.getParent() instanceof PsiTypeElement
)) return null;
1578 PsiElement catchParameter
= element
.getParent().getParent();
1579 if (!(catchParameter
instanceof PsiParameter
) || !(((PsiParameter
)catchParameter
).getDeclarationScope() instanceof PsiCatchSection
)) {
1582 PsiCatchSection catchSection
= (PsiCatchSection
)((PsiParameter
)catchParameter
).getDeclarationScope();
1583 PsiTryStatement statement
= catchSection
.getTryStatement();
1584 PsiCatchSection
[] catchSections
= statement
.getCatchSections();
1585 int i
= ArrayUtil
.find(catchSections
, catchSection
);
1586 for (i
--; i
>= 0; i
--) {
1587 PsiCatchSection section
= catchSections
[i
];
1588 PsiType type
= section
.getCatchType();
1589 PsiClass upCatchClass
= PsiUtil
.resolveClassInType(type
);
1590 if (upCatchClass
== null) continue;
1591 if (InheritanceUtil
.isInheritorOrSelf(catchClass
, upCatchClass
, true)) {
1592 String description
= JavaErrorMessages
1593 .message("exception.already.caught", PsiFormatUtil
.formatClass(catchClass
, PsiFormatUtil
.SHOW_NAME
| PsiFormatUtil
.SHOW_FQ_NAME
));
1594 HighlightInfo highlightInfo
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, element
, description
);
1595 QuickFixAction
.registerQuickFixAction(highlightInfo
, new MoveCatchUpFix(catchSection
, section
));
1596 QuickFixAction
.registerQuickFixAction(highlightInfo
, new DeleteCatchFix((PsiParameter
)catchParameter
));
1597 return highlightInfo
;
1605 public static HighlightInfo
checkTernaryOperatorConditionIsBoolean(PsiExpression expression
) {
1606 if (expression
.getParent() instanceof PsiConditionalExpression
&&
1607 ((PsiConditionalExpression
)expression
.getParent()).getCondition() == expression
&& expression
.getType() != null &&
1608 !TypeConversionUtil
.isBooleanType(expression
.getType())) {
1609 PsiType foundType
= expression
.getType();
1610 return createIncompatibleTypeHighlightInfo(PsiType
.BOOLEAN
, foundType
, expression
.getTextRange());
1617 public static HighlightInfo
checkStatementPrependedWithCaseInsideSwitch(PsiStatement statement
) {
1618 if (!(statement
instanceof PsiSwitchLabelStatement
) && statement
.getParent() instanceof PsiCodeBlock
&&
1619 statement
.getParent().getParent() instanceof PsiSwitchStatement
&&
1620 ((PsiCodeBlock
)statement
.getParent()).getStatements().length
!= 0 &&
1621 statement
== ((PsiCodeBlock
)statement
.getParent()).getStatements()[0]) {
1622 return HighlightInfo
1623 .createHighlightInfo(HighlightInfoType
.ERROR
, statement
, JavaErrorMessages
.message("statement.must.be.prepended.with.case.label"));
1630 public static HighlightInfo
checkAssertOperatorTypes(PsiExpression expression
) {
1631 if (!(expression
.getParent() instanceof PsiAssertStatement
)) {
1634 PsiAssertStatement assertStatement
= (PsiAssertStatement
)expression
.getParent();
1635 PsiType type
= expression
.getType();
1636 if (type
== null) return null;
1637 if (expression
== assertStatement
.getAssertCondition() && !TypeConversionUtil
.isBooleanType(type
)) {
1638 // addTypeCast quickfix is not applicable here since no type can be cast to boolean
1639 return createIncompatibleTypeHighlightInfo(PsiType
.BOOLEAN
, type
, expression
.getTextRange());
1641 else if (expression
== assertStatement
.getAssertDescription() && TypeConversionUtil
.isVoidType(type
)) {
1642 String description
= JavaErrorMessages
.message("void.type.is.not.allowed");
1643 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, expression
, description
);
1650 public static HighlightInfo
checkSynchronizedExpressionType(PsiExpression expression
) {
1651 if (expression
.getParent() instanceof PsiSynchronizedStatement
) {
1652 PsiType type
= expression
.getType();
1653 if (type
== null) return null;
1654 PsiSynchronizedStatement synchronizedStatement
= (PsiSynchronizedStatement
)expression
.getParent();
1655 if (expression
== synchronizedStatement
.getLockExpression() &&
1656 (type
instanceof PsiPrimitiveType
|| TypeConversionUtil
.isNullType(type
))) {
1657 PsiClassType objectType
= PsiType
.getJavaLangObject(expression
.getManager(), expression
.getResolveScope());
1658 return createIncompatibleTypeHighlightInfo(objectType
, type
, expression
.getTextRange());
1666 public static HighlightInfo
checkConditionalExpressionBranchTypesMatch(PsiExpression expression
) {
1667 if (!(expression
.getParent() instanceof PsiConditionalExpression
)) {
1670 PsiConditionalExpression conditionalExpression
= (PsiConditionalExpression
)expression
.getParent();
1671 // check else branches only
1672 if (conditionalExpression
.getElseExpression() != expression
) return null;
1673 final PsiExpression thenExpression
= conditionalExpression
.getThenExpression();
1674 assert thenExpression
!= null;
1675 PsiType thenType
= thenExpression
.getType();
1676 PsiType elseType
= expression
.getType();
1677 if (thenType
== null || elseType
== null) return null;
1678 if (conditionalExpression
.getType() == null) {
1679 // cannot derive type of conditional expression
1680 // elsetype will never be castable to thentype, so no quick fix here
1681 return createIncompatibleTypeHighlightInfo(thenType
, elseType
, expression
.getTextRange());
1686 private static HighlightInfo
createIncompatibleTypeHighlightInfo(final PsiType lType
, final PsiType rType
, final TextRange textRange
) {
1687 PsiType lType1
= lType
;
1688 PsiType rType1
= rType
;
1689 PsiTypeParameter
[] lTypeParams
= PsiTypeParameter
.EMPTY_ARRAY
;
1690 PsiSubstitutor lTypeSubstitutor
= PsiSubstitutor
.EMPTY
;
1691 if (lType1
instanceof PsiClassType
) {
1692 PsiClassType
.ClassResolveResult resolveResult
= ((PsiClassType
)lType1
).resolveGenerics();
1693 lTypeSubstitutor
= resolveResult
.getSubstitutor();
1694 PsiClass psiClass
= resolveResult
.getElement();
1695 if (psiClass
instanceof PsiAnonymousClass
) {
1696 lType1
= ((PsiAnonymousClass
)psiClass
).getBaseClassType();
1697 resolveResult
= ((PsiClassType
)lType1
).resolveGenerics();
1698 lTypeSubstitutor
= resolveResult
.getSubstitutor();
1699 psiClass
= resolveResult
.getElement();
1701 lTypeParams
= psiClass
== null ? PsiTypeParameter
.EMPTY_ARRAY
: psiClass
.getTypeParameters();
1703 PsiTypeParameter
[] rTypeParams
= PsiTypeParameter
.EMPTY_ARRAY
;
1704 PsiSubstitutor rTypeSubstitutor
= PsiSubstitutor
.EMPTY
;
1705 if (rType1
instanceof PsiClassType
) {
1706 PsiClassType
.ClassResolveResult resolveResult
= ((PsiClassType
)rType1
).resolveGenerics();
1707 rTypeSubstitutor
= resolveResult
.getSubstitutor();
1708 PsiClass psiClass
= resolveResult
.getElement();
1709 if (psiClass
instanceof PsiAnonymousClass
) {
1710 rType1
= ((PsiAnonymousClass
)psiClass
).getBaseClassType();
1711 resolveResult
= ((PsiClassType
)rType1
).resolveGenerics();
1712 rTypeSubstitutor
= resolveResult
.getSubstitutor();
1713 psiClass
= resolveResult
.getElement();
1715 rTypeParams
= psiClass
== null ? PsiTypeParameter
.EMPTY_ARRAY
: psiClass
.getTypeParameters();
1719 int typeParamColumns
= Math
.max(lTypeParams
.length
, rTypeParams
.length
);
1720 @NonNls String requredRow
= "";
1721 @NonNls String foundRow
= "";
1722 for (int i
= 0; i
< typeParamColumns
; i
++) {
1723 PsiTypeParameter lTypeParameter
= i
>= lTypeParams
.length ?
null : lTypeParams
[i
];
1724 PsiTypeParameter rTypeParameter
= i
>= rTypeParams
.length ?
null : rTypeParams
[i
];
1725 PsiType lSubstedType
= lTypeParameter
== null ?
null : lTypeSubstitutor
.substitute(lTypeParameter
);
1726 PsiType rSubstedType
= rTypeParameter
== null ?
null : rTypeSubstitutor
.substitute(rTypeParameter
);
1727 boolean matches
= Comparing
.equal(lSubstedType
, rSubstedType
);
1728 @NonNls String openBrace
= i
== 0 ?
"<" : "";
1729 @NonNls String closeBrace
= i
== typeParamColumns
- 1 ?
">" : ",";
1730 requredRow
+= "<td>" + (lTypeParams
.length
== 0 ?
"" : openBrace
) + redIfNotMatch(lSubstedType
, matches
) +
1731 (i
< lTypeParams
.length ? closeBrace
: "") + "</td>";
1732 foundRow
+= "<td>" + (rTypeParams
.length
== 0 ?
"" : openBrace
) + redIfNotMatch(rSubstedType
, matches
) +
1733 (i
< rTypeParams
.length ? closeBrace
: "") + "</td>";
1735 PsiType lRawType
= lType1
instanceof PsiClassType ?
((PsiClassType
)lType1
).rawType() : lType1
;
1736 PsiType rRawType
= rType1
instanceof PsiClassType ?
((PsiClassType
)rType1
).rawType() : rType1
;
1737 boolean assignable
= lRawType
== null || rRawType
== null || TypeConversionUtil
.isAssignable(lRawType
, rRawType
);
1739 String toolTip
= JavaErrorMessages
.message("incompatible.types.html.tooltip",
1740 redIfNotMatch(lRawType
, assignable
), requredRow
,
1741 redIfNotMatch(rRawType
, assignable
), foundRow
);
1743 String description
= JavaErrorMessages
.message("incompatible.types", formatType(lType1
), formatType(rType1
));
1745 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, null, textRange
.getStartOffset(), textRange
.getEndOffset(),
1746 description
, toolTip
);
1750 public static HighlightInfo
checkSingleImportClassConflict(PsiImportStatement statement
,
1751 Map
<String
, Pair
<PsiImportStatementBase
, PsiClass
>> singleImportedClasses
) {
1752 if (statement
.isOnDemand()) return null;
1753 PsiElement element
= statement
.resolve();
1754 if (element
instanceof PsiClass
) {
1755 String name
= ((PsiClass
)element
).getName();
1756 Pair
<PsiImportStatementBase
, PsiClass
> imported
= singleImportedClasses
.get(name
);
1757 PsiClass importedClass
= imported
== null ?
null : imported
.getSecond();
1758 if (importedClass
!= null && !element
.getManager().areElementsEquivalent(importedClass
, element
)) {
1759 String description
= JavaErrorMessages
.message("single.import.class.conflict", formatClass(importedClass
));
1760 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, statement
, description
);
1762 singleImportedClasses
.put(name
, Pair
.<PsiImportStatementBase
, PsiClass
>create(statement
, (PsiClass
)element
));
1769 private static String
redIfNotMatch(PsiType type
, boolean matches
) {
1770 if (matches
) return getFQName(type
, false);
1771 return "<font color=red><b>" + getFQName(type
, true) + "</b></font>";
1774 private static String
getFQName(PsiType type
, boolean longName
) {
1775 if (type
== null) return "";
1776 return XmlStringUtil
.escapeString(longName ? type
.getInternalCanonicalText() : type
.getPresentableText());
1781 public static HighlightInfo
checkMustBeThrowable(PsiType type
, PsiElement context
, boolean addCastIntention
) {
1782 if (type
== null) return null;
1783 PsiElementFactory factory
= JavaPsiFacade
.getInstance(context
.getProject()).getElementFactory();
1784 PsiClassType throwable
= factory
.createTypeByFQClassName("java.lang.Throwable", context
.getResolveScope());
1785 if (!TypeConversionUtil
.isAssignable(throwable
, type
)) {
1786 HighlightInfo highlightInfo
= createIncompatibleTypeHighlightInfo(throwable
, type
, context
.getTextRange());
1787 if (addCastIntention
&& TypeConversionUtil
.areTypesConvertible(type
, throwable
)) {
1788 if (context
instanceof PsiExpression
) {
1789 QuickFixAction
.registerQuickFixAction(highlightInfo
, new AddTypeCastFix(throwable
, (PsiExpression
)context
));
1792 return highlightInfo
;
1799 private static HighlightInfo
checkMustBeThrowable(PsiClass aClass
, PsiElement context
) {
1800 if (aClass
== null) return null;
1801 PsiClassType type
= JavaPsiFacade
.getInstance(aClass
.getProject()).getElementFactory().createType(aClass
);
1802 return checkMustBeThrowable(type
, context
, false);
1807 public static HighlightInfo
checkLabelDefined(PsiIdentifier labelIdentifier
, PsiStatement exitedStatement
) {
1808 if (labelIdentifier
== null) return null;
1809 String label
= labelIdentifier
.getText();
1810 if (label
== null) return null;
1811 if (exitedStatement
== null) {
1812 String message
= JavaErrorMessages
.message("unresolved.label", label
);
1813 return HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, labelIdentifier
, message
);
1820 public static HighlightInfo
checkReference(PsiJavaCodeReferenceElement ref
, JavaResolveResult result
, PsiElement resolved
) {
1821 PsiElement refName
= ref
.getReferenceNameElement();
1823 if (!(refName
instanceof PsiIdentifier
) && !(refName
instanceof PsiKeyword
)) return null;
1824 HighlightInfo highlightInfo
= checkMemberReferencedBeforeConstructorCalled(ref
);
1825 if (highlightInfo
!= null) return highlightInfo
;
1827 PsiElement refParent
= ref
.getParent();
1828 if (!(refParent
instanceof PsiMethodCallExpression
)) {
1829 if (resolved
== null) {
1830 // do not highlight unknown packages - javac does not care about illegal package names
1831 if (isInsidePackageStatement(refName
)) return null;
1832 if (result
.isPackagePrefixPackageReference()) return null;
1833 JavaResolveResult
[] results
= ref
.multiResolve(true);
1835 if (results
.length
> 1) {
1836 String t1
= format(results
[0].getElement());
1837 String t2
= format(results
[1].getElement());
1838 description
= JavaErrorMessages
.message("ambiguous.reference", refName
.getText(), t1
, t2
);
1841 description
= JavaErrorMessages
.message("cannot.resolve.symbol", refName
.getText());
1844 HighlightInfoType type
= HighlightInfoType
.WRONG_REF
;
1845 if (PsiUtil
.isInsideJavadocComment(ref
)) return null;
1847 HighlightInfo info
= HighlightInfo
.createHighlightInfo(type
, refName
, description
);
1849 UnresolvedReferenceQuickFixProvider
.registerReferenceFixes(ref
, new QuickFixActionRegistrarImpl(info
));
1853 if (!result
.isValidResult() && !PsiUtil
.isInsideJavadocComment(ref
)) {
1854 if (!result
.isAccessible()) {
1855 String description
= buildProblemWithAccessDescription(ref
, result
);
1856 HighlightInfo info
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.WRONG_REF
, ref
.getReferenceNameElement(), description
);
1857 if (result
.isStaticsScopeCorrect()) {
1858 registerAccessQuickFixAction((PsiMember
)resolved
, ref
, info
, result
.getCurrentFileResolveScope());
1859 if (ref
instanceof PsiReferenceExpression
) {
1860 QuickFixAction
.registerQuickFixAction(info
, new RenameWrongRefFix((PsiReferenceExpression
)ref
));
1866 if (!result
.isStaticsScopeCorrect()) {
1867 String description
= buildProblemWithStaticDescription(resolved
);
1868 HighlightInfo info
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.WRONG_REF
, ref
.getReferenceNameElement(), description
);
1869 registerStaticProblemQuickFixAction(resolved
, info
, ref
);
1870 if (ref
instanceof PsiReferenceExpression
) {
1871 QuickFixAction
.registerQuickFixAction(info
, new RenameWrongRefFix((PsiReferenceExpression
)ref
));
1876 if ((resolved
instanceof PsiLocalVariable
|| resolved
instanceof PsiParameter
) && !(resolved
instanceof ImplicitVariable
)) {
1877 highlightInfo
= HighlightControlFlowUtil
.checkVariableMustBeFinal((PsiVariable
)resolved
, ref
);
1880 return highlightInfo
;
1883 private static String
format(PsiElement element
) {
1884 if (element
instanceof PsiClass
) return formatClass((PsiClass
)element
);
1885 if (element
instanceof PsiMethod
) return formatMethod((PsiMethod
)element
);
1886 return ElementDescriptionUtil
.getElementDescription(element
, HighlightUsagesDescriptionLocation
.INSTANCE
);
1889 private static boolean isInsidePackageStatement(PsiElement element
) {
1890 while (element
!= null) {
1891 if (element
instanceof PsiPackageStatement
) return true;
1892 if (!(element
instanceof PsiIdentifier
) && !(element
instanceof PsiJavaCodeReferenceElement
)) return false;
1893 element
= element
.getParent();
1899 public static HighlightInfo
checkElementInReferenceList(PsiJavaCodeReferenceElement ref
,
1900 PsiReferenceList referenceList
,
1901 JavaResolveResult resolveResult
) {
1902 PsiElement resolved
= resolveResult
.getElement();
1903 HighlightInfo highlightInfo
= null;
1904 PsiElement refGrandParent
= referenceList
.getParent();
1905 if (resolved
instanceof PsiClass
) {
1906 PsiClass aClass
= (PsiClass
)resolved
;
1907 if (refGrandParent
instanceof PsiClass
) {
1908 if (refGrandParent
instanceof PsiTypeParameter
) {
1909 highlightInfo
= GenericsHighlightUtil
.checkElementInTypeParameterExtendsList(referenceList
, resolveResult
, ref
);
1912 highlightInfo
= HighlightClassUtil
.checkExtendsClassAndImplementsInterface(referenceList
, resolveResult
, ref
);
1913 if (highlightInfo
== null) {
1914 highlightInfo
= HighlightClassUtil
.checkCannotInheritFromFinal(aClass
, ref
);
1916 if (highlightInfo
== null) {
1917 highlightInfo
= GenericsHighlightUtil
.checkCannotInheritFromEnum(aClass
, ref
);
1919 if (highlightInfo
== null) {
1920 highlightInfo
= GenericsHighlightUtil
.checkCannotInheritFromTypeParameter(aClass
, ref
);
1924 else if (refGrandParent
instanceof PsiMethod
&& ((PsiMethod
)refGrandParent
).getThrowsList() == referenceList
) {
1925 highlightInfo
= checkMustBeThrowable(aClass
, ref
);
1928 else if (refGrandParent
instanceof PsiMethod
&& referenceList
== ((PsiMethod
)refGrandParent
).getThrowsList()) {
1929 highlightInfo
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, ref
, JavaErrorMessages
.message("class.name.expected"));
1931 return highlightInfo
;
1935 public static boolean isSerializable(PsiClass aClass
) {
1936 PsiManager manager
= aClass
.getManager();
1937 PsiClass serializableClass
= JavaPsiFacade
.getInstance(manager
.getProject()).findClass("java.io.Serializable", aClass
.getResolveScope());
1938 return serializableClass
!= null && aClass
.isInheritor(serializableClass
, true);
1941 public static boolean isSerializationImplicitlyUsedField(PsiField field
) {
1942 final String name
= field
.getName();
1943 if (!SERIAL_VERSION_UID_FIELD_NAME
.equals(name
) && !SERIAL_PERSISTENT_FIELDS_FIELD_NAME
.equals(name
)) return false;
1944 if (!field
.hasModifierProperty(PsiModifier
.STATIC
)) return false;
1945 PsiClass aClass
= field
.getContainingClass();
1946 return aClass
== null || isSerializable(aClass
);
1949 public static HighlightInfo
checkClassReferenceAfterQualifier(final PsiReferenceExpression expression
, final PsiElement resolved
) {
1950 if (!(resolved
instanceof PsiClass
)) return null;
1951 final PsiExpression qualifier
= expression
.getQualifierExpression();
1952 if (qualifier
== null) return null;
1953 if (qualifier
instanceof PsiReferenceExpression
) {
1954 PsiElement qualifierResolved
= ((PsiReferenceExpression
)qualifier
).resolve();
1955 if (qualifierResolved
instanceof PsiClass
|| qualifierResolved
instanceof PsiPackage
) return null;
1957 HighlightInfo info
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, qualifier
, JavaErrorMessages
.message("expected.class.or.package"));
1958 QuickFixAction
.registerQuickFixAction(info
, new RemoveQualifierFix(qualifier
, expression
, (PsiClass
)resolved
));
1962 public static void registerChangeVariableTypeFixes(PsiVariable parameter
, PsiType itemType
, HighlightInfo highlightInfo
) {
1963 for (ChangeVariableTypeQuickFixProvider fixProvider
: Extensions
.getExtensions(ChangeVariableTypeQuickFixProvider
.EP_NAME
)) {
1964 for (IntentionAction action
: fixProvider
.getFixes(parameter
, itemType
)) {
1965 QuickFixAction
.registerQuickFixAction(highlightInfo
, action
, null);