4775d872a5a49f0a56197d6d5e6af76381f65a0b
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInsight / daemon / impl / analysis / GenericsHighlightUtil.java
blob4775d872a5a49f0a56197d6d5e6af76381f65a0b
1 /*
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.
16 package com.intellij.codeInsight.daemon.impl.analysis;
18 import com.intellij.codeInsight.daemon.HighlightDisplayKey;
19 import com.intellij.codeInsight.daemon.JavaErrorMessages;
20 import com.intellij.codeInsight.daemon.impl.HighlightInfo;
21 import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
22 import com.intellij.codeInsight.daemon.impl.JavaHightlightInfoTypes;
23 import com.intellij.codeInsight.daemon.impl.quickfix.*;
24 import com.intellij.codeInsight.intention.EmptyIntentionAction;
25 import com.intellij.codeInsight.intention.IntentionAction;
26 import com.intellij.codeInsight.intention.QuickFixFactory;
27 import com.intellij.codeInspection.InspectionProfile;
28 import com.intellij.codeInspection.LocalInspectionTool;
29 import com.intellij.codeInspection.ex.InspectionManagerEx;
30 import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
31 import com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection;
32 import com.intellij.openapi.diagnostic.Logger;
33 import com.intellij.openapi.project.IndexNotReadyException;
34 import com.intellij.openapi.project.Project;
35 import com.intellij.openapi.util.Comparing;
36 import com.intellij.openapi.util.TextRange;
37 import com.intellij.pom.java.LanguageLevel;
38 import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
39 import com.intellij.psi.*;
40 import com.intellij.psi.search.GlobalSearchScope;
41 import com.intellij.psi.search.searches.SuperMethodsSearch;
42 import com.intellij.psi.util.*;
43 import com.intellij.util.containers.HashMap;
44 import com.intellij.util.containers.HashSet;
45 import gnu.trove.THashMap;
46 import org.jetbrains.annotations.NonNls;
47 import org.jetbrains.annotations.NotNull;
48 import org.jetbrains.annotations.Nullable;
50 import java.util.*;
52 /**
53 * @author cdr
56 public class GenericsHighlightUtil {
57 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.analysis.GenericsHighlightUtil");
58 private static final String GENERICS_ARE_NOT_SUPPORTED = JavaErrorMessages.message("generics.are.not.supported");
59 private static final QuickFixFactory QUICK_FIX_FACTORY = QuickFixFactory.getInstance();
61 private GenericsHighlightUtil() {}
63 public static HighlightInfo checkInferredTypeArguments(PsiMethod genericMethod,
64 PsiMethodCallExpression call,
65 PsiSubstitutor substitutor) {
66 PsiTypeParameter[] typeParameters = genericMethod.getTypeParameters();
67 for (PsiTypeParameter typeParameter : typeParameters) {
68 PsiType substituted = substitutor.substitute(typeParameter);
69 if (substituted == null) return null;
70 substituted = PsiUtil.captureToplevelWildcards(substituted, call);
71 PsiClassType[] extendsTypes = typeParameter.getExtendsListTypes();
72 for (PsiClassType type : extendsTypes) {
73 PsiType extendsType = substitutor.substitute(type);
74 if (!TypeConversionUtil.isAssignable(extendsType, substituted, false)) {
75 PsiClass boundClass = extendsType instanceof PsiClassType ? ((PsiClassType)extendsType).resolve() : null;
77 @NonNls String messageKey = boundClass == null || typeParameter.isInterface() == boundClass.isInterface()
78 ? "generics.inferred.type.for.type.parameter.is.not.within.its.bound.extend"
79 : "generics.inferred.type.for.type.parameter.is.not.within.its.bound.implement";
81 String description = JavaErrorMessages.message(
82 messageKey,
83 HighlightUtil.formatClass(typeParameter),
84 HighlightUtil.formatType(extendsType),
85 HighlightUtil.formatType(substituted)
88 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, call, description);
93 return null;
96 public static HighlightInfo checkParameterizedReferenceTypeArguments(PsiElement resolved,
97 final PsiJavaCodeReferenceElement referenceElement,
98 final PsiSubstitutor substitutor) {
99 if (!(resolved instanceof PsiTypeParameterListOwner)) return null;
100 final PsiTypeParameterListOwner typeParameterListOwner = (PsiTypeParameterListOwner)resolved;
101 return checkReferenceTypeArgumentList(typeParameterListOwner, referenceElement.getParameterList(), substitutor, true);
104 public static HighlightInfo checkReferenceTypeArgumentList(final PsiTypeParameterListOwner typeParameterListOwner,
105 final PsiReferenceParameterList referenceParameterList,
106 final PsiSubstitutor substitutor,
107 boolean registerIntentions) {
108 if (referenceParameterList != null && !PsiUtil.isLanguageLevel5OrHigher(referenceParameterList)) {
109 if (referenceParameterList.getTypeParameterElements().length > 0) {
110 HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceParameterList, GENERICS_ARE_NOT_SUPPORTED);
111 QuickFixAction.registerQuickFixAction(info, new ShowModulePropertiesFix(referenceParameterList));
112 QuickFixAction.registerQuickFixAction(info, new IncreaseLanguageLevelFix(LanguageLevel.JDK_1_5));
113 return info;
117 final PsiTypeParameter[] typeParameters = typeParameterListOwner.getTypeParameters();
118 final int targetParametersNum = typeParameters.length;
119 final int refParametersNum = referenceParameterList == null ? 0 : referenceParameterList.getTypeParameterElements().length;
120 if (targetParametersNum != refParametersNum && refParametersNum != 0) {
121 final String description;
122 if (targetParametersNum == 0) {
123 description = JavaErrorMessages.message(
124 "generics.type.or.method.does.not.have.type.parameters",
125 typeParameterListOwnerCategoryDescription(typeParameterListOwner),
126 typeParameterListOwnerDescription(typeParameterListOwner)
129 else {
130 description = JavaErrorMessages.message(
131 "generics.wrong.number.of.type.arguments", refParametersNum, targetParametersNum
135 final HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceParameterList, description);
136 if (registerIntentions) {
137 PsiElement pparent = referenceParameterList.getParent().getParent();
138 if (pparent instanceof PsiTypeElement) {
139 PsiElement variable = pparent.getParent();
140 if (variable instanceof PsiVariable) {
141 VariableParameterizedTypeFix.registerIntentions(highlightInfo, (PsiVariable)variable, referenceParameterList);
145 return highlightInfo;
148 // bounds check
149 if (targetParametersNum > 0 && refParametersNum != 0) {
150 final PsiTypeElement[] referenceElements = referenceParameterList.getTypeParameterElements();
151 for (int i = 0; i < typeParameters.length; i++) {
152 PsiTypeParameter classParameter = typeParameters[i];
153 final PsiTypeElement typeElement = referenceElements[i];
154 final PsiType type = typeElement.getType();
155 if (!(type instanceof PsiClassType)) continue;
156 final PsiClass referenceClass = ((PsiClassType)type).resolve();
157 if (referenceClass == null) continue;
158 final PsiClassType[] bounds = classParameter.getSuperTypes();
159 for (PsiClassType type1 : bounds) {
160 PsiType bound = substitutor.substitute(type1);
161 if (!TypeConversionUtil.isAssignable(bound, type, false)) {
162 PsiClass boundClass = bound instanceof PsiClassType ? ((PsiClassType)bound).resolve() : null;
164 @NonNls final String messageKey = boundClass == null || referenceClass.isInterface() == boundClass.isInterface()
165 ? "generics.type.parameter.is.not.within.its.bound.extend"
166 : "generics.type.parameter.is.not.within.its.bound.implement";
168 String description = JavaErrorMessages.message(messageKey,
169 HighlightUtil.formatClass(referenceClass),
170 HighlightUtil.formatType(bound));
172 final HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR,
173 typeElement,
174 description);
175 if (bound instanceof PsiClassType) {
176 QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createExtendsListFix(referenceClass, (PsiClassType)bound, true),
177 null);
179 return highlightInfo;
185 return null;
188 private static String typeParameterListOwnerDescription(final PsiTypeParameterListOwner typeParameterListOwner) {
189 if (typeParameterListOwner instanceof PsiClass) {
190 return HighlightUtil.formatClass((PsiClass)typeParameterListOwner);
192 else if (typeParameterListOwner instanceof PsiMethod) {
193 return HighlightUtil.formatMethod((PsiMethod)typeParameterListOwner);
195 else {
196 LOG.error("Unknown " + typeParameterListOwner);
197 return "?";
201 private static String typeParameterListOwnerCategoryDescription(final PsiTypeParameterListOwner typeParameterListOwner) {
202 if (typeParameterListOwner instanceof PsiClass) {
203 return JavaErrorMessages.message("generics.holder.type");
205 else if (typeParameterListOwner instanceof PsiMethod) {
206 return JavaErrorMessages.message("generics.holder.method");
208 else {
209 LOG.error("Unknown " + typeParameterListOwner);
210 return "?";
214 public static HighlightInfo checkElementInTypeParameterExtendsList(PsiReferenceList referenceList, JavaResolveResult resolveResult, PsiElement element) {
215 PsiClass aClass = (PsiClass)referenceList.getParent();
216 final PsiJavaCodeReferenceElement[] referenceElements = referenceList.getReferenceElements();
217 PsiClass extendFrom = (PsiClass)resolveResult.getElement();
218 if (extendFrom == null) return null;
219 HighlightInfo errorResult = null;
220 if (!extendFrom.isInterface() && referenceElements.length != 0 && element != referenceElements[0]) {
221 final String description = HighlightClassUtil.INTERFACE_EXPECTED;
222 errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, element, description);
223 PsiClassType type =
224 JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(extendFrom, resolveResult.getSubstitutor());
225 QuickFixAction.registerQuickFixAction(errorResult, new MoveBoundClassToFrontFix(aClass, type), null);
227 else if (referenceElements.length != 0 && element != referenceElements[0] && referenceElements[0].resolve() instanceof PsiTypeParameter) {
228 final String description = JavaErrorMessages.message("type.parameter.cannot.be.followed.by.other.bounds");
229 errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, element, description);
230 PsiClassType type =
231 JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(extendFrom, resolveResult.getSubstitutor());
232 IntentionAction fix = QUICK_FIX_FACTORY.createExtendsListFix(aClass, type, false);
233 QuickFixAction.registerQuickFixAction(errorResult, fix, null);
235 return errorResult;
237 public static HighlightInfo checkInterfaceMultipleInheritance(PsiClass aClass) {
238 if (aClass instanceof PsiTypeParameter) return null;
239 final PsiClassType[] types = aClass.getSuperTypes();
240 if (types.length < 2) return null;
241 Map<PsiClass, PsiSubstitutor> inheritedClasses = new HashMap<PsiClass, PsiSubstitutor>();
242 final TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass);
243 return checkInterfaceMultipleInheritance(aClass,
244 PsiSubstitutor.EMPTY, inheritedClasses,
245 new HashSet<PsiClass>(), textRange);
248 private static HighlightInfo checkInterfaceMultipleInheritance(PsiClass aClass,
249 PsiSubstitutor derivedSubstitutor,
250 Map<PsiClass, PsiSubstitutor> inheritedClasses,
251 Set<PsiClass> visited,
252 TextRange textRange) {
253 final PsiClassType[] superTypes = aClass.getSuperTypes();
254 for (PsiClassType superType : superTypes) {
255 final PsiClassType.ClassResolveResult result = superType.resolveGenerics();
256 final PsiClass superClass = result.getElement();
257 if (superClass == null || visited.contains(superClass)) continue;
258 PsiSubstitutor superTypeSubstitutor = result.getSubstitutor();
259 superTypeSubstitutor = MethodSignatureUtil.combineSubstitutors(superTypeSubstitutor, derivedSubstitutor);
261 final PsiSubstitutor inheritedSubstitutor = inheritedClasses.get(superClass);
262 if (inheritedSubstitutor != null) {
263 final PsiTypeParameter[] typeParameters = superClass.getTypeParameters();
264 for (PsiTypeParameter typeParameter : typeParameters) {
265 PsiType type1 = inheritedSubstitutor.substitute(typeParameter);
266 PsiType type2 = superTypeSubstitutor.substitute(typeParameter);
268 if (!Comparing.equal(type1, type2)) {
269 String description = JavaErrorMessages.message("generics.cannot.be.inherited.with.different.type.arguments",
270 HighlightUtil.formatClass(superClass),
271 HighlightUtil.formatType(type1),
272 HighlightUtil.formatType(type2));
273 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, textRange, description);
277 inheritedClasses.put(superClass, superTypeSubstitutor);
278 visited.add(superClass);
279 final HighlightInfo highlightInfo = checkInterfaceMultipleInheritance(superClass, superTypeSubstitutor, inheritedClasses, visited, textRange);
280 visited.remove(superClass);
282 if (highlightInfo != null) return highlightInfo;
284 return null;
287 public static HighlightInfo checkOverrideEquivalentMethods(final PsiClass aClass) {
288 final Collection<HierarchicalMethodSignature> signaturesWithSupers = aClass.getVisibleSignatures();
289 PsiManager manager = aClass.getManager();
290 Map<MethodSignature, MethodSignatureBackedByPsiMethod> sameErasureMethods =
291 new THashMap<MethodSignature, MethodSignatureBackedByPsiMethod>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);
293 for (HierarchicalMethodSignature signature : signaturesWithSupers) {
294 HighlightInfo info = checkSameErasureNotSubsignatureInner(signature, manager, aClass, sameErasureMethods);
295 if (info != null) return info;
298 return null;
301 private static HighlightInfo checkSameErasureNotSubsignatureInner(final HierarchicalMethodSignature signature,
302 final PsiManager manager,
303 final PsiClass aClass,
304 final Map<MethodSignature, MethodSignatureBackedByPsiMethod> sameErasureMethods) {
305 PsiMethod method = signature.getMethod();
306 JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject());
307 if (!facade.getResolveHelper().isAccessible(method, aClass, null)) return null;
308 MethodSignature signatureToErase = method.getSignature(PsiSubstitutor.EMPTY);
309 MethodSignatureBackedByPsiMethod sameErasure = sameErasureMethods.get(signatureToErase);
310 HighlightInfo info;
311 if (sameErasure != null) {
312 info = checkSameErasureNotSubsignatureOrSameClass(sameErasure, signature, aClass, method);
313 if (info != null) return info;
315 sameErasureMethods.put(signatureToErase, signature);
316 List<HierarchicalMethodSignature> supers = signature.getSuperSignatures();
317 for (HierarchicalMethodSignature superSignature : supers) {
318 info = checkSameErasureNotSubsignatureInner(superSignature, manager, aClass, sameErasureMethods);
319 if (info != null) return info;
321 return null;
324 private static HighlightInfo checkSameErasureNotSubsignatureOrSameClass(final MethodSignatureBackedByPsiMethod signatureToCheck,
325 final HierarchicalMethodSignature superSignature,
326 final PsiClass aClass,
327 final PsiMethod superMethod) {
328 final PsiMethod checkMethod = signatureToCheck.getMethod();
329 if (superMethod.equals(checkMethod)) return null;
330 PsiClass checkContainingClass = checkMethod.getContainingClass();
331 LOG.assertTrue(checkContainingClass != null);
332 PsiClass superContainingClass = superMethod.getContainingClass();
333 boolean checkEqualsSuper = checkContainingClass.equals(superContainingClass);
334 if (checkMethod.isConstructor()) {
335 if (!superMethod.isConstructor() || !checkEqualsSuper) return null;
337 else if (superMethod.isConstructor()) return null;
339 if (checkMethod.hasModifierProperty(PsiModifier.STATIC) && !checkEqualsSuper) {
340 return null;
343 final PsiType retErasure1 = TypeConversionUtil.erasure(checkMethod.getReturnType());
344 final PsiType retErasure2 = TypeConversionUtil.erasure(superMethod.getReturnType());
345 if (!Comparing.equal(retErasure1, retErasure2) &&
346 !TypeConversionUtil.isVoidType(retErasure1) &&
347 !TypeConversionUtil.isVoidType(retErasure2) &&
348 !(checkEqualsSuper && Arrays.equals(superSignature.getParameterTypes(), signatureToCheck.getParameterTypes()))) {
349 return null;
352 if (!checkEqualsSuper && MethodSignatureUtil.isSubsignature(superSignature, signatureToCheck)) {
353 return null;
355 if (aClass.equals(checkContainingClass)) {
356 boolean sameClass = aClass.equals(superContainingClass);
357 return getSameErasureMessage(sameClass, checkMethod, superMethod, HighlightNamesUtil.getMethodDeclarationTextRange(checkMethod));
359 else {
360 return getSameErasureMessage(false, checkMethod, superMethod, HighlightNamesUtil.getClassDeclarationTextRange(aClass));
364 private static HighlightInfo getSameErasureMessage(final boolean sameClass, final PsiMethod method, final PsiMethod superMethod,
365 TextRange textRange) {
366 @NonNls final String key = sameClass ? "generics.methods.have.same.erasure" : "generics.methods.have.same.erasure.override";
367 String description = JavaErrorMessages.message(key, HighlightMethodUtil.createClashMethodMessage(method, superMethod, !sameClass));
368 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, textRange, description);
371 public static HighlightInfo checkTypeParameterInstantiation(PsiNewExpression expression) {
372 PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
373 if (classReference == null) return null;
374 final JavaResolveResult result = classReference.advancedResolve(false);
375 final PsiElement element = result.getElement();
376 if (element instanceof PsiTypeParameter) {
377 String description = JavaErrorMessages.message("generics.type.parameter.cannot.be.instantiated",
378 HighlightUtil.formatClass((PsiTypeParameter)element));
379 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, classReference, description);
381 return null;
384 public static HighlightInfo checkWildcardUsage(PsiTypeElement typeElement) {
385 PsiType type = typeElement.getType();
386 if (type instanceof PsiWildcardType) {
387 if (typeElement.getParent() instanceof PsiReferenceParameterList) {
388 PsiElement parent = typeElement.getParent().getParent();
389 LOG.assertTrue(parent instanceof PsiJavaCodeReferenceElement, parent);
390 PsiElement refParent = parent.getParent();
391 if (refParent instanceof PsiAnonymousClass) refParent = refParent.getParent();
392 if (refParent instanceof PsiNewExpression) {
393 PsiNewExpression newExpression = (PsiNewExpression)refParent;
394 if (!(newExpression.getType() instanceof PsiArrayType)) {
395 String description = JavaErrorMessages.message("wildcard.type.cannot.be.instantiated", HighlightUtil.formatType(type));
396 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, typeElement, description);
399 else if (refParent instanceof PsiReferenceList) {
400 PsiElement refPParent = refParent.getParent();
401 if (!(refPParent instanceof PsiTypeParameter) || refParent != ((PsiTypeParameter)refPParent).getExtendsList()) {
402 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR,
403 typeElement,
404 JavaErrorMessages.message("generics.wildcard.not.expected"));
408 else {
409 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR,
410 typeElement,
411 JavaErrorMessages.message("generics.wildcards.may.be.used.only.as.reference.parameters"));
415 return null;
418 public static HighlightInfo checkReferenceTypeUsedAsTypeArgument(PsiTypeElement typeElement) {
419 final PsiType type = typeElement.getType();
420 if (type instanceof PsiPrimitiveType ||
421 type instanceof PsiWildcardType && ((PsiWildcardType)type).getBound() instanceof PsiPrimitiveType) {
422 final PsiElement element = new PsiMatcherImpl(typeElement)
423 .parent(PsiMatchers.hasClass(PsiReferenceParameterList.class))
424 .parent(PsiMatchers.hasClass(PsiJavaCodeReferenceElement.class))
425 .getElement();
426 if (element == null) return null;
428 String description = JavaErrorMessages.message("generics.type.argument.cannot.be.of.primitive.type");
429 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, typeElement, description);
432 return null;
435 //precondition: TypeConversionUtil.isAssignable(lType, rType) || expressionAssignable
436 public static HighlightInfo checkRawToGenericAssignment(PsiType lType, PsiType rType, @NotNull final PsiElement elementToHighlight) {
437 if (!PsiUtil.isLanguageLevel5OrHigher(elementToHighlight)) return null;
438 final HighlightDisplayKey key = HighlightDisplayKey.find(UncheckedWarningLocalInspection.SHORT_NAME);
439 if (!InspectionProjectProfileManager.getInstance(elementToHighlight.getProject()).getInspectionProfile().isToolEnabled(key,
440 elementToHighlight)) return null;
441 if (!isRawToGeneric(lType, rType)) return null;
442 String description = JavaErrorMessages.message("generics.unchecked.assignment",
443 HighlightUtil.formatType(rType),
444 HighlightUtil.formatType(lType));
446 return createUncheckedWarning(elementToHighlight, key, description, elementToHighlight);
449 private static boolean isRawToGeneric(PsiType lType, PsiType rType) {
450 if (lType instanceof PsiPrimitiveType || rType instanceof PsiPrimitiveType) return false;
451 if (lType.equals(rType)) return false;
452 if (lType instanceof PsiArrayType && rType instanceof PsiArrayType) {
453 return isRawToGeneric(((PsiArrayType)lType).getComponentType(), ((PsiArrayType)rType).getComponentType());
455 if (lType instanceof PsiArrayType || rType instanceof PsiArrayType) return false;
457 if (rType instanceof PsiIntersectionType) {
458 for (PsiType type : ((PsiIntersectionType)rType).getConjuncts()) {
459 if (isRawToGeneric(lType, type)) return true;
461 return false;
462 } else if (lType instanceof PsiIntersectionType) {
463 for (PsiType type : ((PsiIntersectionType)lType).getConjuncts()) {
464 if (isRawToGeneric(type, rType)) return true;
466 return false;
469 if (lType instanceof PsiCapturedWildcardType || rType instanceof PsiCapturedWildcardType) {
470 return false;
473 if (lType instanceof PsiWildcardType || rType instanceof PsiWildcardType) return false;
475 boolean isValidType = lType instanceof PsiClassType && rType instanceof PsiClassType;
476 if (!isValidType) {
477 LOG.error("Invalid types: rType =" + rType + ", lType=" + lType);
479 PsiClassType.ClassResolveResult lResolveResult = ((PsiClassType)lType).resolveGenerics();
480 PsiClassType.ClassResolveResult rResolveResult = ((PsiClassType)rType).resolveGenerics();
481 PsiClass lClass = lResolveResult.getElement();
482 PsiClass rClass = rResolveResult.getElement();
484 if (rClass instanceof PsiAnonymousClass) {
485 return isRawToGeneric(lType, ((PsiAnonymousClass)rClass).getBaseClassType());
488 PsiSubstitutor lSubstitutor = lResolveResult.getSubstitutor();
489 PsiSubstitutor rSubstitutor = rResolveResult.getSubstitutor();
490 if (lClass == null || rClass == null) return false;
491 if (lClass instanceof PsiTypeParameter &&
492 !InheritanceUtil.isInheritorOrSelf(rClass, lClass, true)) return true;
494 if (!lClass.getManager().areElementsEquivalent(lClass, rClass)) {
495 if (lClass.isInheritor(rClass, true)) {
496 lSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(rClass, lClass, lSubstitutor);
497 lClass = rClass;
499 else if (rClass.isInheritor(lClass, true)) {
500 rSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(lClass, rClass, rSubstitutor);
501 rClass = lClass;
503 else {
504 return false;
508 Iterator<PsiTypeParameter> lIterator = PsiUtil.typeParametersIterator(lClass);
509 Iterator<PsiTypeParameter> rIterator = PsiUtil.typeParametersIterator(rClass);
510 while (lIterator.hasNext()) {
511 if (!rIterator.hasNext()) return false;
512 PsiTypeParameter lParameter = lIterator.next();
513 PsiTypeParameter rParameter = rIterator.next();
514 PsiType lTypeArg = lSubstitutor.substitute(lParameter);
515 PsiType rTypeArg = rSubstitutor.substituteWithBoundsPromotion(rParameter);
516 if (lTypeArg == null) continue;
517 if (rTypeArg == null) {
518 if (lTypeArg instanceof PsiWildcardType && ((PsiWildcardType) lTypeArg).getBound() == null) {
519 continue;
521 else {
522 return true;
525 if (isUncheckedTypeArgumentConversion(lTypeArg, rTypeArg)) return true;
527 return false;
530 public static HighlightInfo checkUncheckedTypeCast(PsiTypeCastExpression typeCast) {
531 if (!PsiUtil.isLanguageLevel5OrHigher(typeCast)) return null;
532 final HighlightDisplayKey key = HighlightDisplayKey.find(UncheckedWarningLocalInspection.SHORT_NAME);
533 if (!InspectionProjectProfileManager.getInstance(typeCast.getProject()).getInspectionProfile().isToolEnabled(key, typeCast)) return null;
534 final PsiTypeElement typeElement = typeCast.getCastType();
535 if (typeElement == null) return null;
536 final PsiType castType = typeElement.getType();
537 final PsiExpression expression = typeCast.getOperand();
538 if (expression == null) return null;
539 final PsiType exprType = expression.getType();
540 if (exprType == null) return null;
541 if (isUncheckedCast(castType, exprType)) {
542 String description = JavaErrorMessages.message("generics.unchecked.cast",
543 HighlightUtil.formatType(exprType),
544 HighlightUtil.formatType(castType));
545 return createUncheckedWarning(expression, key, description, typeCast);
547 return null;
550 private static boolean isUncheckedCast(PsiType castType, PsiType operandType) {
551 if (TypeConversionUtil.isAssignable(castType, operandType, false)) return false;
553 castType = castType.getDeepComponentType();
554 if (castType instanceof PsiClassType) {
555 final PsiClassType castClassType = (PsiClassType)castType;
556 operandType = operandType.getDeepComponentType();
558 if (!(operandType instanceof PsiClassType)) return false;
559 final PsiClassType operandClassType = (PsiClassType)operandType;
560 final PsiClassType.ClassResolveResult castResult = castClassType.resolveGenerics();
561 final PsiClassType.ClassResolveResult operandResult = operandClassType.resolveGenerics();
562 final PsiClass operandClass = operandResult.getElement();
563 final PsiClass castClass = castResult.getElement();
565 if (operandClass == null || castClass == null) return false;
566 if (castClass instanceof PsiTypeParameter) return true;
568 if (castClassType.hasNonTrivialParameters()) {
569 if (operandClassType.isRaw()) return true;
570 if (castClass.isInheritor(operandClass, true)) {
571 PsiSubstitutor castSubstitutor = castResult.getSubstitutor();
572 for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(castClass)) {
573 PsiSubstitutor modifiedSubstitutor = castSubstitutor.put(typeParameter, null);
574 PsiClassType otherType =
575 JavaPsiFacade.getInstance(typeParameter.getProject()).getElementFactory().createType(castClass, modifiedSubstitutor);
576 if (TypeConversionUtil.isAssignable(operandType, otherType, false)) return true;
578 return false;
580 return true;
584 return false;
587 private static boolean isUncheckedTypeArgumentConversion (PsiType lTypeArg, PsiType rTypeArg) {
588 if (lTypeArg instanceof PsiPrimitiveType || rTypeArg instanceof PsiPrimitiveType) return false;
589 if (lTypeArg.equals(rTypeArg)) return false;
590 if (lTypeArg instanceof PsiCapturedWildcardType) {
591 //ignore capture conversion
592 return isUncheckedTypeArgumentConversion(((PsiCapturedWildcardType)lTypeArg).getWildcard(), rTypeArg);
594 if (rTypeArg instanceof PsiCapturedWildcardType) {
595 //ignore capture conversion
596 return isUncheckedTypeArgumentConversion(lTypeArg, ((PsiCapturedWildcardType)rTypeArg).getWildcard());
599 if (lTypeArg instanceof PsiWildcardType || rTypeArg instanceof PsiWildcardType) {
600 return !lTypeArg.isAssignableFrom(rTypeArg);
603 if (lTypeArg instanceof PsiArrayType && rTypeArg instanceof PsiArrayType) {
604 return isUncheckedTypeArgumentConversion(((PsiArrayType)rTypeArg).getComponentType(), ((PsiArrayType)lTypeArg).getComponentType());
606 if (lTypeArg instanceof PsiArrayType || rTypeArg instanceof PsiArrayType) return false;
607 if (lTypeArg instanceof PsiIntersectionType) {
608 for (PsiType type : ((PsiIntersectionType)lTypeArg).getConjuncts()) {
609 if (!isUncheckedTypeArgumentConversion(type, rTypeArg)) return false;
611 return true;
613 if (!(lTypeArg instanceof PsiClassType)) {
614 LOG.error("left: "+lTypeArg + "; "+lTypeArg.getClass());
616 if (rTypeArg instanceof PsiIntersectionType) {
617 for (PsiType type : ((PsiIntersectionType)rTypeArg).getConjuncts()) {
618 if (!isUncheckedTypeArgumentConversion(lTypeArg, type)) return false;
620 return true;
622 if (!(rTypeArg instanceof PsiClassType)) {
623 LOG.error("right :"+rTypeArg + "; "+rTypeArg.getClass());
625 return ((PsiClassType)lTypeArg).resolve() instanceof PsiTypeParameter ||
626 ((PsiClassType)rTypeArg).resolve() instanceof PsiTypeParameter;
629 public static HighlightInfo checkUncheckedCall(JavaResolveResult resolveResult, PsiCall call) {
630 if (!PsiUtil.isLanguageLevel5OrHigher(call)) return null;
631 final HighlightDisplayKey key = HighlightDisplayKey.find(UncheckedWarningLocalInspection.SHORT_NAME);
632 if (!InspectionProjectProfileManager.getInstance(call.getProject()).getInspectionProfile().isToolEnabled(key, call)) return null;
634 final PsiMethod method = (PsiMethod)resolveResult.getElement();
635 if (method == null) return null;
636 final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
637 final PsiParameter[] parameters = method.getParameterList().getParameters();
638 for (final PsiParameter parameter : parameters) {
639 final PsiType parameterType = parameter.getType();
640 if (parameterType.accept(new PsiTypeVisitor<Boolean>() {
641 public Boolean visitPrimitiveType(PsiPrimitiveType primitiveType) {
642 return Boolean.FALSE;
645 public Boolean visitArrayType(PsiArrayType arrayType) {
646 return arrayType.getComponentType().accept(this);
649 public Boolean visitClassType(PsiClassType classType) {
650 PsiClass psiClass = classType.resolve();
651 if (psiClass instanceof PsiTypeParameter) {
652 return substitutor.substitute((PsiTypeParameter)psiClass) == null ? Boolean.TRUE : Boolean.FALSE;
654 PsiType[] parameters = classType.getParameters();
655 for (PsiType parameter : parameters) {
656 if (parameter.accept(this).booleanValue()) return Boolean.TRUE;
659 return Boolean.FALSE;
662 public Boolean visitWildcardType(PsiWildcardType wildcardType) {
663 PsiType bound = wildcardType.getBound();
664 if (bound != null) return bound.accept(this);
665 return Boolean.FALSE;
668 public Boolean visitEllipsisType(PsiEllipsisType ellipsisType) {
669 return ellipsisType.getComponentType().accept(this);
671 }).booleanValue()) {
672 final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
673 PsiType type = elementFactory.createType(method.getContainingClass(), substitutor);
674 String description = JavaErrorMessages.message("generics.unchecked.call.to.member.of.raw.type",
675 HighlightUtil.formatMethod(method),
676 HighlightUtil.formatType(type));
677 PsiElement element = call instanceof PsiMethodCallExpression
678 ? ((PsiMethodCallExpression)call).getMethodExpression()
679 : call;
680 return createUncheckedWarning(call, key, description, element);
683 return null;
686 private static HighlightInfo createUncheckedWarning(PsiElement context, HighlightDisplayKey key, String description, PsiElement elementToHighlight) {
687 final InspectionProfile inspectionProfile =
688 InspectionProjectProfileManager.getInstance(context.getProject()).getInspectionProfile();
689 final LocalInspectionTool tool =
690 ((LocalInspectionToolWrapper)inspectionProfile.getInspectionTool(UncheckedWarningLocalInspection.SHORT_NAME, elementToHighlight)).getTool();
691 if (InspectionManagerEx.inspectionResultSuppressed(context, tool)) return null;
692 HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(JavaHightlightInfoTypes.UNCHECKED_WARNING, elementToHighlight, description);
693 QuickFixAction.registerQuickFixAction(highlightInfo, new GenerifyFileFix(elementToHighlight.getContainingFile()), key);
694 return highlightInfo;
697 public static HighlightInfo checkForeachLoopParameterType(PsiForeachStatement statement) {
698 final PsiParameter parameter = statement.getIterationParameter();
699 final PsiExpression expression = statement.getIteratedValue();
700 if (expression == null) return null;
701 final PsiType itemType = getCollectionItemType(expression);
702 if (itemType == null) {
703 String description = JavaErrorMessages.message("foreach.not.applicable",
704 HighlightUtil.formatType(expression.getType()));
705 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, description);
707 final int start = parameter.getTextRange().getStartOffset();
708 final int end = expression.getTextRange().getEndOffset();
709 final PsiType parameterType = parameter.getType();
710 HighlightInfo highlightInfo = HighlightUtil.checkAssignability(parameterType, itemType, null, new TextRange(start, end));
711 if (highlightInfo != null) {
712 HighlightUtil.registerChangeVariableTypeFixes(parameter, itemType, highlightInfo);
713 } else {
714 highlightInfo = checkRawToGenericAssignment(parameterType, itemType, statement.getIterationParameter());
716 return highlightInfo;
719 @Nullable
720 private static PsiType getCollectionItemType(PsiExpression expression) {
721 final PsiType type = expression.getType();
722 if (type == null) return null;
723 if (type instanceof PsiArrayType) {
724 return ((PsiArrayType)type).getComponentType();
726 if (type instanceof PsiClassType) {
727 final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)type).resolveGenerics();
728 PsiClass aClass = resolveResult.getElement();
729 if (aClass == null) return null;
730 final PsiManager manager = aClass.getManager();
731 final String qName = aClass.getQualifiedName();
732 PsiSubstitutor substitutor = resolveResult.getSubstitutor();
733 JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject());
734 if (qName != null) {
735 PsiClass myClass = facade.findClass(qName, expression.getResolveScope());
736 if (myClass != null && myClass != aClass) {
737 //different JDKs
738 PsiTypeParameter thisTypeParameter = getIterableTypeParameter(facade, myClass);
739 if (thisTypeParameter == null) return null;
740 PsiTypeParameter thatTypeParameter = getIterableTypeParameter(facade, aClass);
741 if (thatTypeParameter != null) { //it can be null if we reference collection in JDK1.4 module from JDK5 source
742 substitutor = substitutor.put(thisTypeParameter, substitutor.substitute(thatTypeParameter));
744 aClass = myClass;
747 PsiTypeParameter typeParameter = getIterableTypeParameter(facade, aClass);
748 if (typeParameter == null) return null;
749 PsiClass owner = (PsiClass)typeParameter.getOwner();
750 if (owner == null) return null;
751 PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getClassSubstitutor(owner, aClass, PsiSubstitutor.EMPTY);
752 if (superClassSubstitutor == null) return null;
753 PsiType itemType = superClassSubstitutor.substitute(typeParameter);
754 itemType = substitutor.substitute(itemType);
755 return itemType == null ? PsiType.getJavaLangObject(manager, aClass.getResolveScope()) : itemType;
757 return null;
760 @Nullable
761 private static PsiTypeParameter getIterableTypeParameter(final JavaPsiFacade facade, final PsiClass context) {
762 PsiClass iterable = facade.findClass("java.lang.Iterable", context.getResolveScope());
763 if (iterable == null) return null;
764 PsiTypeParameter[] typeParameters = iterable.getTypeParameters();
765 if (typeParameters.length != 1) return null;
766 return typeParameters[0];
769 @Nullable
770 public static HighlightInfo checkAccessStaticFieldFromEnumConstructor(PsiReferenceExpression expr, JavaResolveResult result) {
771 final PsiElement resolved = result.getElement();
773 if (!(resolved instanceof PsiField)) return null;
774 if (!((PsiModifierListOwner)resolved).hasModifierProperty(PsiModifier.STATIC)) return null;
775 final PsiMember constructorOrInitializer = PsiUtil.findEnclosingConstructorOrInitializer(expr);
776 if (constructorOrInitializer == null) return null;
777 if (constructorOrInitializer.hasModifierProperty(PsiModifier.STATIC)) return null;
778 final PsiClass aClass = constructorOrInitializer.getContainingClass();
779 if (aClass == null) return null;
780 if (!aClass.isEnum()) return null;
781 final PsiField field = (PsiField)resolved;
782 if (field.getContainingClass() != aClass) return null;
783 final PsiType type = field.getType();
785 //TODO is access to enum constant is allowed ?
786 if (type instanceof PsiClassType && ((PsiClassType)type).resolve() == aClass) return null;
788 if (PsiUtil.isCompileTimeConstant(field)) return null;
790 String description = JavaErrorMessages.message(
791 "illegal.to.access.static.member.from.enum.constructor.or.instance.initializer",
792 HighlightMessageUtil.getSymbolName(resolved, result.getSubstitutor())
795 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expr, description);
798 @Nullable
799 public static HighlightInfo checkEnumInstantiation(PsiNewExpression expression) {
800 final PsiType type = expression.getType();
801 if (type instanceof PsiClassType) {
802 final PsiClass aClass = ((PsiClassType)type).resolve();
803 if (aClass != null && aClass.isEnum()) {
804 String description = JavaErrorMessages.message("enum.types.cannot.be.instantiated");
805 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, description);
808 return null;
811 @Nullable
812 public static HighlightInfo checkGenericArrayCreation(PsiElement element, PsiType type) {
813 if (type instanceof PsiArrayType) {
814 PsiType componentType = type.getDeepComponentType();
815 if (componentType instanceof PsiClassType) {
816 final PsiClassType classType = (PsiClassType)componentType;
817 PsiType[] parameters = classType.getParameters();
818 for (PsiType parameter : parameters) {
819 if (!(parameter instanceof PsiWildcardType) || ((PsiWildcardType)parameter).getBound() != null) {
820 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR,
821 element,
822 JavaErrorMessages.message("generic.array.creation"));
825 final PsiClass resolved = ((PsiClassType)PsiUtil.convertAnonymousToBaseType(classType)).resolve();
826 if (resolved instanceof PsiTypeParameter) {
827 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR,
828 element,
829 JavaErrorMessages.message("generic.array.creation"));
834 return null;
837 private static final MethodSignature ourValuesEnumSyntheticMethod = MethodSignatureUtil.createMethodSignature("values",
838 PsiType.EMPTY_ARRAY,
839 PsiTypeParameter.EMPTY_ARRAY,
840 PsiSubstitutor.EMPTY);
842 public static boolean isEnumSyntheticMethod(MethodSignature methodSignature, Project project) {
843 if (methodSignature.equals(ourValuesEnumSyntheticMethod)) return true;
844 final PsiType javaLangString = PsiType.getJavaLangString(PsiManager.getInstance(project), GlobalSearchScope.allScope(project));
845 final MethodSignature valueOfMethod = MethodSignatureUtil.createMethodSignature("valueOf", new PsiType[]{javaLangString}, PsiTypeParameter.EMPTY_ARRAY,
846 PsiSubstitutor.EMPTY);
847 return valueOfMethod.equals(methodSignature);
850 public static HighlightInfo checkTypeParametersList(PsiTypeParameterList parameterList) {
851 PsiTypeParameter[] typeParameters = parameterList.getTypeParameters();
852 if (typeParameters.length == 0) return null;
853 if (!PsiUtil.isLanguageLevel5OrHigher(parameterList)) {
854 HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, parameterList, GENERICS_ARE_NOT_SUPPORTED);
855 QuickFixAction.registerQuickFixAction(info, new ShowModulePropertiesFix(parameterList));
856 QuickFixAction.registerQuickFixAction(info, new IncreaseLanguageLevelFix(LanguageLevel.JDK_1_5));
857 return info;
859 final PsiElement parent = parameterList.getParent();
860 if (parent instanceof PsiClass && ((PsiClass)parent).isEnum()) {
861 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR,
862 parameterList,
863 JavaErrorMessages.message("generics.enum.may.not.have.type.parameters"));
865 if (parent instanceof PsiAnnotationMethod) {
866 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, parameterList, JavaErrorMessages.message("generics.annotation.members.may.not.have.type.parameters"));
868 else if (parent instanceof PsiClass && ((PsiClass)parent).isAnnotationType()) {
869 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, parameterList, JavaErrorMessages.message("annotation.may.not.have.type.parameters"));
872 for (int i = 0; i < typeParameters.length; i++) {
873 final PsiTypeParameter typeParameter1 = typeParameters[i];
874 String name1 = typeParameter1.getName();
875 for (int j = i+1; j < typeParameters.length; j++) {
876 final PsiTypeParameter typeParameter2 = typeParameters[j];
877 String name2 = typeParameter2.getName();
878 if (Comparing.strEqual(name1, name2)) {
879 String message = JavaErrorMessages.message("generics.duplicate.type.parameter", name1);
880 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, typeParameter2, message);
884 return null;
887 public static HighlightInfo checkCatchParameterIsClass(PsiParameter parameter) {
888 if (parameter.getDeclarationScope() instanceof PsiCatchSection) {
889 PsiType type = parameter.getType();
890 if (type instanceof PsiClassType) {
891 PsiClass aClass = ((PsiClassType)type).resolve();
892 if (aClass instanceof PsiTypeParameter) {
893 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR,
894 parameter.getTypeElement(),
895 JavaErrorMessages.message("generics.cannot.catch.type.parameters"));
900 return null;
903 public static HighlightInfo checkInstanceOfGenericType(PsiInstanceOfExpression expression) {
904 final PsiTypeElement checkTypeElement = expression.getCheckType();
905 if (checkTypeElement == null) return null;
906 PsiElement ref = checkTypeElement.getInnermostComponentReferenceElement();
907 while (ref instanceof PsiJavaCodeReferenceElement) {
908 final HighlightInfo result = isIllegalForInstanceOf((PsiJavaCodeReferenceElement)ref, checkTypeElement);
909 if (result != null) return result;
910 ref = ((PsiQualifiedReference)ref).getQualifier();
912 return null;
915 private static HighlightInfo isIllegalForInstanceOf(PsiJavaCodeReferenceElement ref, final PsiTypeElement typeElement) {
916 final PsiElement resolved = ref.resolve();
917 if (resolved instanceof PsiTypeParameter) {
918 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, ref, JavaErrorMessages.message("generics.cannot.instanceof.type.parameters"));
921 final PsiType[] parameters = ref.getTypeParameters();
922 for (PsiType parameterType : parameters) {
923 if (parameterType != null &&
924 !(parameterType instanceof PsiWildcardType && ((PsiWildcardType)parameterType).getBound() == null)) {
925 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, typeElement, JavaErrorMessages.message("illegal.generic.type.for.instanceof"));
929 return null;
932 public static HighlightInfo checkClassObjectAccessExpression(PsiClassObjectAccessExpression expression) {
933 PsiType type = expression.getOperand().getType();
934 if (type instanceof PsiClassType) {
935 PsiClass aClass = ((PsiClassType)type).resolve();
936 if (aClass instanceof PsiTypeParameter) {
937 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR,
938 expression.getOperand(),
939 JavaErrorMessages.message("cannot.select.dot.class.from.type.variable"));
943 return null;
946 @Nullable
947 public static HighlightInfo checkOverrideAnnotation(PsiMethod method) {
948 PsiModifierList list = method.getModifierList();
949 final PsiAnnotation overrideAnnotation = list.findAnnotation("java.lang.Override");
950 if (overrideAnnotation == null) {
951 return null;
953 try {
954 MethodSignatureBackedByPsiMethod superMethod = SuperMethodsSearch.search(method, null, true, false).findFirst();
955 if (superMethod == null) {
956 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, overrideAnnotation,
957 JavaErrorMessages.message("method.doesnot.override.super"));
959 LanguageLevel languageLevel = PsiUtil.getLanguageLevel(method);
960 PsiClass superClass = superMethod.getMethod().getContainingClass();
961 if (languageLevel.equals(LanguageLevel.JDK_1_5) &&
962 superClass != null &&
963 superClass.isInterface()) {
964 HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, overrideAnnotation, JavaErrorMessages.message("override.not.allowed.in.interfaces"));
965 QuickFixAction.registerQuickFixAction(info, new IncreaseLanguageLevelFix(LanguageLevel.JDK_1_6));
966 return info;
968 return null;
970 catch (IndexNotReadyException e) {
971 return null;
975 static void checkEnumConstantForConstructorProblems(PsiEnumConstant enumConstant, final HighlightInfoHolder holder) {
976 PsiClass containingClass = enumConstant.getContainingClass();
977 if (enumConstant.getInitializingClass() == null) {
978 HighlightInfo highlightInfo = HighlightClassUtil.checkInstantiationOfAbstractClass(containingClass, enumConstant.getNameIdentifier());
979 if (highlightInfo != null) {
980 holder.add(highlightInfo);
981 return;
983 highlightInfo = HighlightClassUtil.checkClassWithAbstractMethods(enumConstant.getContainingClass(), enumConstant.getNameIdentifier());
984 if (highlightInfo != null) {
985 holder.add(highlightInfo);
986 return;
989 PsiClassType type = JavaPsiFacade.getInstance(enumConstant.getProject()).getElementFactory().createType(containingClass);
991 HighlightMethodUtil.checkConstructorCall(type.resolveGenerics(), enumConstant, type, null, holder);
994 public static HighlightInfo checkEnumSuperConstructorCall(PsiMethodCallExpression expr) {
995 PsiReferenceExpression methodExpression = expr.getMethodExpression();
996 final PsiElement refNameElement = methodExpression.getReferenceNameElement();
997 if (refNameElement != null && PsiKeyword.SUPER.equals(refNameElement.getText())) {
998 final PsiMember constructor = PsiUtil.findEnclosingConstructorOrInitializer(expr);
999 if (constructor instanceof PsiMethod && constructor.getContainingClass().isEnum()) {
1000 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR,
1001 expr,
1002 JavaErrorMessages.message("call.to.super.is.not.allowed.in.enum.constructor"));
1005 return null;
1008 public static HighlightInfo checkVarArgParameterIsLast(PsiParameter parameter) {
1009 PsiElement declarationScope = parameter.getDeclarationScope();
1010 if (declarationScope instanceof PsiMethod) {
1011 PsiParameter[] params = ((PsiMethod)declarationScope).getParameterList().getParameters();
1012 if (parameter.isVarArgs()) {
1013 if (!PsiUtil.getLanguageLevel(parameter).hasEnumKeywordAndAutoboxing()) {
1014 HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, parameter, JavaErrorMessages.message("varargs.prior.15"));
1015 QuickFixAction.registerQuickFixAction(info, new IncreaseLanguageLevelFix(LanguageLevel.JDK_1_5));
1016 return info;
1019 if (params[params.length - 1] != parameter) {
1020 HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, parameter,
1021 JavaErrorMessages.message("vararg.not.last.parameter"));
1022 QuickFixAction.registerQuickFixAction(info, new MakeVarargParameterLastFix(parameter), null);
1023 return info;
1027 return null;
1030 public static List<HighlightInfo> checkEnumConstantModifierList(PsiModifierList modifierList) {
1031 List<HighlightInfo> list = null;
1032 PsiElement[] children = modifierList.getChildren();
1033 for (PsiElement child : children) {
1034 if (child instanceof PsiKeyword) {
1035 if (list == null) {
1036 list = new ArrayList<HighlightInfo>();
1038 list.add(HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR,
1039 child,
1040 JavaErrorMessages.message("modifiers.for.enum.constants")));
1043 return list;
1046 public static HighlightInfo checkGenericCallWithRawArguments(JavaResolveResult resolveResult, PsiCallExpression callExpression) {
1047 final PsiMethod method = (PsiMethod)resolveResult.getElement();
1048 if (method == null) return null;
1049 final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
1050 final PsiExpressionList argumentList = callExpression.getArgumentList();
1051 if (argumentList == null) return null;
1052 final PsiExpression[] expressions = argumentList.getExpressions();
1053 final PsiParameter[] parameters = method.getParameterList().getParameters();
1054 for (int i = 0; i < expressions.length; i++) {
1055 PsiParameter parameter = parameters[Math.min(i, parameters.length - 1)];
1056 final PsiExpression expression = expressions[i];
1057 final PsiType parameterType = substitutor.substitute(parameter.getType());
1058 final PsiType expressionType = substitutor.substitute(expression.getType());
1059 if (expressionType != null) {
1060 final HighlightInfo highlightInfo = checkRawToGenericAssignment(parameterType, expressionType, expression);
1061 if (highlightInfo != null) return highlightInfo;
1064 return null;
1067 public static HighlightInfo checkParametersOnRaw(PsiReferenceParameterList refParamList) {
1068 if (refParamList.getTypeArguments().length == 0) return null;
1069 JavaResolveResult resolveResult = null;
1070 PsiElement parent = refParamList.getParent();
1071 if (parent instanceof PsiJavaCodeReferenceElement) {
1072 resolveResult = ((PsiJavaCodeReferenceElement)parent).advancedResolve(false);
1073 } else if (parent instanceof PsiCallExpression) {
1074 resolveResult = ((PsiCallExpression)parent).resolveMethodGenerics();
1076 if (resolveResult != null) {
1077 PsiElement element = resolveResult.getElement();
1078 if (!(element instanceof PsiTypeParameterListOwner)) return null;
1079 if (((PsiModifierListOwner)element).hasModifierProperty(PsiModifier.STATIC)) return null;
1080 PsiClass containingClass = ((PsiMember)element).getContainingClass();
1081 if (containingClass != null && PsiUtil.isRawSubstitutor(containingClass, resolveResult.getSubstitutor())) {
1082 final String message = element instanceof PsiClass
1083 ? JavaErrorMessages.message("generics.type.arguments.on.raw.type")
1084 : JavaErrorMessages.message("generics.type.arguments.on.raw.method");
1086 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, refParamList, message);
1089 return null;
1092 public static HighlightInfo checkCannotInheritFromEnum(PsiClass superClass, PsiElement elementToHighlight) {
1093 HighlightInfo errorResult = null;
1094 if (Comparing.strEqual("java.lang.Enum",superClass.getQualifiedName())) {
1095 String message = JavaErrorMessages.message("classes.extends.enum");
1096 errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, elementToHighlight, message);
1098 return errorResult;
1100 public static HighlightInfo checkGenericCannotExtendException(PsiReferenceList list) {
1101 PsiElement parent = list.getParent();
1102 if (!(parent instanceof PsiClass)) return null;
1103 PsiClass aClass = (PsiClass)parent;
1105 if (!aClass.hasTypeParameters() || aClass.getExtendsList() != list) return null;
1106 PsiJavaCodeReferenceElement[] referenceElements = list.getReferenceElements();
1107 PsiClass throwableClass = null;
1108 for (PsiJavaCodeReferenceElement referenceElement : referenceElements) {
1109 PsiElement resolved = referenceElement.resolve();
1110 if (!(resolved instanceof PsiClass)) continue;
1111 if (throwableClass == null) {
1112 throwableClass = JavaPsiFacade.getInstance(aClass.getProject()).findClass("java.lang.Throwable", aClass.getResolveScope());
1114 if (InheritanceUtil.isInheritorOrSelf((PsiClass)resolved, throwableClass, true)) {
1115 String message = JavaErrorMessages.message("generic.extend.exception");
1116 HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceElement, message);
1117 PsiClassType classType = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType((PsiClass)resolved);
1118 QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createExtendsListFix(aClass, classType, false));
1119 return highlightInfo;
1122 return null;
1125 public static HighlightInfo checkUncheckedOverriding (PsiMethod overrider, final List<HierarchicalMethodSignature> superMethodSignatures) {
1126 if (!PsiUtil.isLanguageLevel5OrHigher(overrider)) return null;
1127 final HighlightDisplayKey key = HighlightDisplayKey.find(UncheckedWarningLocalInspection.SHORT_NAME);
1128 final InspectionProfile inspectionProfile =
1129 InspectionProjectProfileManager.getInstance(overrider.getProject()).getInspectionProfile();
1130 if (!inspectionProfile.isToolEnabled(key, overrider)) return null;
1131 final LocalInspectionTool tool =
1132 ((LocalInspectionToolWrapper)inspectionProfile.getInspectionTool(UncheckedWarningLocalInspection.SHORT_NAME, overrider)).getTool();
1133 if (InspectionManagerEx.inspectionResultSuppressed(overrider, tool)) return null;
1134 final MethodSignature signature = overrider.getSignature(PsiSubstitutor.EMPTY);
1135 for (MethodSignatureBackedByPsiMethod superSignature : superMethodSignatures) {
1136 PsiMethod baseMethod = superSignature.getMethod();
1137 PsiSubstitutor substitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(signature, superSignature);
1138 if (substitutor == null) substitutor = superSignature.getSubstitutor();
1139 if (PsiUtil.isRawSubstitutor(baseMethod, superSignature.getSubstitutor())) continue;
1140 final PsiType baseReturnType = substitutor.substitute(baseMethod.getReturnType());
1141 final PsiType overriderReturnType = overrider.getReturnType();
1142 if (baseReturnType == null || overriderReturnType == null) return null;
1143 if (isRawToGeneric(baseReturnType, overriderReturnType)) {
1144 final String message = JavaErrorMessages.message("unchecked.overriding.incompatible.return.type",
1145 HighlightUtil.formatType(overriderReturnType),
1146 HighlightUtil.formatType(baseReturnType));
1148 final PsiTypeElement returnTypeElement = overrider.getReturnTypeElement();
1149 LOG.assertTrue(returnTypeElement != null);
1150 final HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(JavaHightlightInfoTypes.UNCHECKED_WARNING, returnTypeElement, message);
1151 QuickFixAction.registerQuickFixAction(highlightInfo,
1152 new EmptyIntentionAction(JavaErrorMessages.message("unchecked.overriding")),
1153 key);
1155 return highlightInfo;
1158 return null;
1161 public static HighlightInfo checkEnumMustNotBeLocal(final PsiClass aClass) {
1162 if (!aClass.isEnum()) return null;
1163 PsiElement parent = aClass.getParent();
1164 if (!(parent instanceof PsiClass || parent instanceof PsiFile)) {
1165 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR,
1166 HighlightNamesUtil.getClassDeclarationTextRange(aClass),
1167 JavaErrorMessages.message("local.enum"));
1169 return null;
1172 public static HighlightInfo checkSelectStaticClassFromParameterizedType(final PsiElement resolved, final PsiJavaCodeReferenceElement ref) {
1173 if (resolved instanceof PsiClass && ((PsiClass)resolved).hasModifierProperty(PsiModifier.STATIC)) {
1174 final PsiElement qualifier = ref.getQualifier();
1175 if (qualifier instanceof PsiJavaCodeReferenceElement) {
1176 final PsiReferenceParameterList parameterList = ((PsiJavaCodeReferenceElement)qualifier).getParameterList();
1177 if (parameterList != null && parameterList.getTypeArguments().length > 0) {
1178 final String message = JavaErrorMessages.message("generics.select.static.class.from.parameterized.type",
1179 HighlightUtil.formatClass((PsiClass)resolved));
1180 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, parameterList, message);
1184 return null;
1187 public static HighlightInfo checkCannotInheritFromTypeParameter(final PsiClass superClass, final PsiJavaCodeReferenceElement toHighlight) {
1188 if (superClass instanceof PsiTypeParameter) {
1189 return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, toHighlight,
1190 JavaErrorMessages.message("class.cannot.inherit.from.its.type.parameter"));
1192 return null;