2 * Copyright 2000-2016 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.JavaErrorMessages;
19 import com.intellij.codeInsight.daemon.impl.HighlightInfo;
20 import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
21 import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction;
22 import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixActionRegistrarImpl;
23 import com.intellij.codeInsight.intention.QuickFixFactory;
24 import com.intellij.openapi.diagnostic.Logger;
25 import com.intellij.openapi.project.DumbService;
26 import com.intellij.openapi.project.IndexNotReadyException;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.projectRoots.JavaSdkVersion;
29 import com.intellij.openapi.projectRoots.JavaVersionService;
30 import com.intellij.openapi.roots.FileIndexFacade;
31 import com.intellij.openapi.util.Comparing;
32 import com.intellij.openapi.util.Pair;
33 import com.intellij.openapi.util.TextRange;
34 import com.intellij.openapi.vfs.VirtualFile;
35 import com.intellij.pom.java.LanguageLevel;
36 import com.intellij.psi.*;
37 import com.intellij.psi.impl.PsiClassImplUtil;
38 import com.intellij.psi.search.GlobalSearchScope;
39 import com.intellij.psi.search.PsiShortNamesCache;
40 import com.intellij.psi.search.searches.ReferencesSearch;
41 import com.intellij.psi.search.searches.SuperMethodsSearch;
42 import com.intellij.psi.util.*;
43 import com.intellij.util.ArrayUtilRt;
44 import com.intellij.util.containers.ContainerUtil;
45 import com.intellij.util.containers.HashMap;
46 import com.intellij.util.containers.HashSet;
47 import gnu.trove.THashMap;
48 import gnu.trove.THashSet;
49 import org.jetbrains.annotations.NonNls;
50 import org.jetbrains.annotations.NotNull;
51 import org.jetbrains.annotations.Nullable;
58 public class GenericsHighlightUtil {
59 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.analysis.GenericsHighlightUtil");
61 private static final QuickFixFactory QUICK_FIX_FACTORY = QuickFixFactory.getInstance();
63 private GenericsHighlightUtil() { }
66 static HighlightInfo checkInferredTypeArguments(PsiTypeParameterListOwner listOwner,
68 PsiSubstitutor substitutor) {
69 return checkInferredTypeArguments(listOwner.getTypeParameters(), call, substitutor);
73 private static HighlightInfo checkInferredTypeArguments(PsiTypeParameter[] typeParameters,
75 PsiSubstitutor substitutor) {
76 final Pair<PsiTypeParameter, PsiType> inferredTypeArgument = GenericsUtil.findTypeParameterWithBoundError(typeParameters, substitutor,
78 if (inferredTypeArgument != null) {
79 final PsiType extendsType = inferredTypeArgument.second;
80 final PsiTypeParameter typeParameter = inferredTypeArgument.first;
81 PsiClass boundClass = extendsType instanceof PsiClassType ? ((PsiClassType)extendsType).resolve() : null;
83 @NonNls String messageKey = boundClass == null || typeParameter.isInterface() == boundClass.isInterface()
84 ? "generics.inferred.type.for.type.parameter.is.not.within.its.bound.extend"
85 : "generics.inferred.type.for.type.parameter.is.not.within.its.bound.implement";
87 String description = JavaErrorMessages.message(
89 HighlightUtil.formatClass(typeParameter),
90 JavaHighlightUtil.formatType(extendsType),
91 JavaHighlightUtil.formatType(substitutor.substitute(typeParameter))
93 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(call).descriptionAndTooltip(description).create();
100 static HighlightInfo checkParameterizedReferenceTypeArguments(final PsiElement resolved,
101 final PsiJavaCodeReferenceElement referenceElement,
102 final PsiSubstitutor substitutor,
103 @NotNull JavaSdkVersion javaSdkVersion) {
104 if (!(resolved instanceof PsiTypeParameterListOwner)) return null;
105 final PsiTypeParameterListOwner typeParameterListOwner = (PsiTypeParameterListOwner)resolved;
106 return checkReferenceTypeArgumentList(typeParameterListOwner, referenceElement.getParameterList(), substitutor, true, javaSdkVersion);
110 static HighlightInfo checkReferenceTypeArgumentList(final PsiTypeParameterListOwner typeParameterListOwner,
111 final PsiReferenceParameterList referenceParameterList,
112 final PsiSubstitutor substitutor,
113 boolean registerIntentions,
114 @NotNull JavaSdkVersion javaSdkVersion) {
115 PsiDiamondType.DiamondInferenceResult inferenceResult = null;
116 PsiTypeElement[] referenceElements = null;
117 if (referenceParameterList != null) {
118 referenceElements = referenceParameterList.getTypeParameterElements();
119 if (referenceElements.length == 1 && referenceElements[0].getType() instanceof PsiDiamondType) {
120 if (!typeParameterListOwner.hasTypeParameters()) {
121 final String description = JavaErrorMessages.message("generics.diamond.not.applicable");
122 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(referenceParameterList).descriptionAndTooltip(description).create();
124 inferenceResult = ((PsiDiamondType)referenceElements[0].getType()).resolveInferredTypes();
125 final String errorMessage = inferenceResult.getErrorMessage();
126 if (errorMessage != null) {
127 final PsiType expectedType = detectExpectedType(referenceParameterList);
128 if (!(inferenceResult.failedToInfer() && expectedType instanceof PsiClassType && ((PsiClassType)expectedType).isRaw())) {
130 .newHighlightInfo(HighlightInfoType.ERROR).range(referenceParameterList).descriptionAndTooltip(errorMessage).create();
136 final PsiTypeParameter[] typeParameters = typeParameterListOwner.getTypeParameters();
137 final int targetParametersNum = typeParameters.length;
138 final int refParametersNum = referenceParameterList == null ? 0 : referenceParameterList.getTypeArguments().length;
139 if (targetParametersNum != refParametersNum && refParametersNum != 0) {
140 final String description;
141 if (targetParametersNum == 0) {
142 if (PsiTreeUtil.getParentOfType(referenceParameterList, PsiCall.class) != null &&
143 typeParameterListOwner instanceof PsiMethod &&
144 (javaSdkVersion.isAtLeast(JavaSdkVersion.JDK_1_7) || hasSuperMethodsWithTypeParams((PsiMethod)typeParameterListOwner))) {
148 description = JavaErrorMessages.message(
149 "generics.type.or.method.does.not.have.type.parameters",
150 typeParameterListOwnerCategoryDescription(typeParameterListOwner),
151 typeParameterListOwnerDescription(typeParameterListOwner)
156 description = JavaErrorMessages.message("generics.wrong.number.of.type.arguments", refParametersNum, targetParametersNum);
159 if (description != null) {
160 final HighlightInfo highlightInfo =
161 HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(referenceParameterList).descriptionAndTooltip(description).create();
162 if (registerIntentions) {
163 if (typeParameterListOwner instanceof PsiClass) {
164 QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createChangeClassSignatureFromUsageFix((PsiClass)typeParameterListOwner, referenceParameterList));
167 PsiElement grandParent = referenceParameterList.getParent().getParent();
168 if (grandParent instanceof PsiTypeElement) {
169 PsiElement variable = grandParent.getParent();
170 if (variable instanceof PsiVariable) {
171 if (targetParametersNum == 0) {
172 QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createRemoveTypeArgumentsFix(variable));
174 registerVariableParameterizedTypeFixes(highlightInfo, (PsiVariable)variable, referenceParameterList, javaSdkVersion);
178 return highlightInfo;
183 if (targetParametersNum > 0 && refParametersNum != 0) {
184 if (inferenceResult != null) {
185 final PsiType[] types = inferenceResult.getTypes();
186 for (int i = 0; i < typeParameters.length; i++) {
187 final PsiType type = types[i];
188 final HighlightInfo highlightInfo = checkTypeParameterWithinItsBound(typeParameters[i], substitutor, type, referenceElements[0], referenceParameterList);
189 if (highlightInfo != null) return highlightInfo;
193 for (int i = 0; i < typeParameters.length; i++) {
194 final PsiTypeElement typeElement = referenceElements[i];
195 final HighlightInfo highlightInfo = checkTypeParameterWithinItsBound(typeParameters[i], substitutor, typeElement.getType(), typeElement, referenceParameterList);
196 if (highlightInfo != null) return highlightInfo;
204 private static boolean hasSuperMethodsWithTypeParams(PsiMethod method) {
205 for (PsiMethod superMethod : method.findDeepestSuperMethods()) {
206 if (superMethod.hasTypeParameters()) return true;
211 private static PsiType detectExpectedType(PsiReferenceParameterList referenceParameterList) {
212 final PsiNewExpression newExpression = PsiTreeUtil.getParentOfType(referenceParameterList, PsiNewExpression.class);
213 LOG.assertTrue(newExpression != null);
214 final PsiElement parent = newExpression.getParent();
215 PsiType expectedType = null;
216 if (parent instanceof PsiVariable && newExpression.equals(((PsiVariable)parent).getInitializer())) {
217 expectedType = ((PsiVariable)parent).getType();
219 else if (parent instanceof PsiAssignmentExpression && newExpression.equals(((PsiAssignmentExpression)parent).getRExpression())) {
220 expectedType = ((PsiAssignmentExpression)parent).getLExpression().getType();
222 else if (parent instanceof PsiReturnStatement) {
223 PsiElement method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class, PsiLambdaExpression.class);
224 if (method instanceof PsiMethod) {
225 expectedType = ((PsiMethod)method).getReturnType();
228 else if (parent instanceof PsiExpressionList) {
229 final PsiElement pParent = parent.getParent();
230 if (pParent instanceof PsiCallExpression && parent.equals(((PsiCallExpression)pParent).getArgumentList())) {
231 final PsiMethod method = ((PsiCallExpression)pParent).resolveMethod();
232 if (method != null) {
233 final PsiExpression[] expressions = ((PsiCallExpression)pParent).getArgumentList().getExpressions();
234 final int idx = ArrayUtilRt.find(expressions, newExpression);
236 final PsiParameterList parameterList = method.getParameterList();
237 if (idx < parameterList.getParametersCount()) {
238 expectedType = parameterList.getParameters()[idx].getType();
248 private static HighlightInfo checkTypeParameterWithinItsBound(PsiTypeParameter classParameter,
249 final PsiSubstitutor substitutor,
251 final PsiElement typeElement2Highlight,
252 PsiReferenceParameterList referenceParameterList) {
253 final PsiClass referenceClass = type instanceof PsiClassType ? ((PsiClassType)type).resolve() : null;
254 final PsiType psiType = substitutor.substitute(classParameter);
255 if (psiType instanceof PsiClassType && !(PsiUtil.resolveClassInType(psiType) instanceof PsiTypeParameter)) {
256 if (GenericsUtil.checkNotInBounds(type, psiType, referenceParameterList)) {
257 final String description = "Actual type argument and inferred type contradict each other";
258 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement2Highlight).descriptionAndTooltip(description).create();
262 final PsiClassType[] bounds = classParameter.getSuperTypes();
263 for (PsiClassType type1 : bounds) {
264 PsiType bound = substitutor.substitute(type1);
265 if (!bound.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) && GenericsUtil.checkNotInBounds(type, bound, referenceParameterList)) {
266 PsiClass boundClass = bound instanceof PsiClassType ? ((PsiClassType)bound).resolve() : null;
268 @NonNls final String messageKey = boundClass == null || referenceClass == null || referenceClass.isInterface() == boundClass.isInterface()
269 ? "generics.type.parameter.is.not.within.its.bound.extend"
270 : "generics.type.parameter.is.not.within.its.bound.implement";
272 String description = JavaErrorMessages.message(messageKey,
273 referenceClass != null ? HighlightUtil.formatClass(referenceClass) : type.getPresentableText(),
274 JavaHighlightUtil.formatType(bound));
276 final HighlightInfo info =
277 HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement2Highlight).descriptionAndTooltip(description).create();
278 if (bound instanceof PsiClassType && referenceClass != null && info != null) {
280 .registerQuickFixAction(info, QUICK_FIX_FACTORY.createExtendsListFix(referenceClass, (PsiClassType)bound, true),
289 private static String typeParameterListOwnerDescription(final PsiTypeParameterListOwner typeParameterListOwner) {
290 if (typeParameterListOwner instanceof PsiClass) {
291 return HighlightUtil.formatClass((PsiClass)typeParameterListOwner);
293 else if (typeParameterListOwner instanceof PsiMethod) {
294 return JavaHighlightUtil.formatMethod((PsiMethod)typeParameterListOwner);
297 LOG.error("Unknown " + typeParameterListOwner);
302 private static String typeParameterListOwnerCategoryDescription(final PsiTypeParameterListOwner typeParameterListOwner) {
303 if (typeParameterListOwner instanceof PsiClass) {
304 return JavaErrorMessages.message("generics.holder.type");
306 else if (typeParameterListOwner instanceof PsiMethod) {
307 return JavaErrorMessages.message("generics.holder.method");
310 LOG.error("Unknown " + typeParameterListOwner);
316 static HighlightInfo checkElementInTypeParameterExtendsList(@NotNull PsiReferenceList referenceList,
317 @NotNull PsiClass aClass,
318 @NotNull JavaResolveResult resolveResult,
319 @NotNull PsiElement element) {
320 final PsiJavaCodeReferenceElement[] referenceElements = referenceList.getReferenceElements();
321 PsiClass extendFrom = (PsiClass)resolveResult.getElement();
322 if (extendFrom == null) return null;
323 HighlightInfo errorResult = null;
324 if (!extendFrom.isInterface() && referenceElements.length != 0 && element != referenceElements[0]) {
325 String description = JavaErrorMessages.message("interface.expected");
326 errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create();
328 JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(extendFrom, resolveResult.getSubstitutor());
329 QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createMoveBoundClassToFrontFix(aClass, type), null);
331 else if (referenceElements.length != 0 && element != referenceElements[0] && referenceElements[0].resolve() instanceof PsiTypeParameter) {
332 final String description = JavaErrorMessages.message("type.parameter.cannot.be.followed.by.other.bounds");
333 errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create();
335 JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(extendFrom, resolveResult.getSubstitutor());
336 QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createExtendsListFix(aClass, type, false), null);
341 static HighlightInfo checkInterfaceMultipleInheritance(PsiClass aClass) {
342 final PsiClassType[] types = aClass.getSuperTypes();
343 if (types.length < 2) return null;
344 Map<PsiClass, PsiSubstitutor> inheritedClasses = new HashMap<>();
345 final TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass);
346 return checkInterfaceMultipleInheritance(aClass,
348 PsiSubstitutor.EMPTY, inheritedClasses,
349 new HashSet<>(), textRange);
352 private static HighlightInfo checkInterfaceMultipleInheritance(PsiClass aClass,
354 PsiSubstitutor derivedSubstitutor,
355 Map<PsiClass, PsiSubstitutor> inheritedClasses,
356 Set<PsiClass> visited,
357 TextRange textRange) {
358 final List<PsiClassType.ClassResolveResult> superTypes = PsiClassImplUtil.getScopeCorrectedSuperTypes(aClass, place.getResolveScope());
359 for (PsiClassType.ClassResolveResult result : superTypes) {
360 final PsiClass superClass = result.getElement();
361 if (superClass == null || visited.contains(superClass)) continue;
362 PsiSubstitutor superTypeSubstitutor = result.getSubstitutor();
363 superTypeSubstitutor = MethodSignatureUtil.combineSubstitutors(superTypeSubstitutor, derivedSubstitutor);
365 final PsiSubstitutor inheritedSubstitutor = inheritedClasses.get(superClass);
366 if (inheritedSubstitutor != null) {
367 final PsiTypeParameter[] typeParameters = superClass.getTypeParameters();
368 for (PsiTypeParameter typeParameter : typeParameters) {
369 PsiType type1 = inheritedSubstitutor.substitute(typeParameter);
370 PsiType type2 = superTypeSubstitutor.substitute(typeParameter);
372 if (!Comparing.equal(type1, type2)) {
373 String description = JavaErrorMessages.message("generics.cannot.be.inherited.with.different.type.arguments",
374 HighlightUtil.formatClass(superClass),
375 JavaHighlightUtil.formatType(type1),
376 JavaHighlightUtil.formatType(type2));
377 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
381 inheritedClasses.put(superClass, superTypeSubstitutor);
382 visited.add(superClass);
383 final HighlightInfo highlightInfo = checkInterfaceMultipleInheritance(superClass, place, superTypeSubstitutor, inheritedClasses, visited, textRange);
384 visited.remove(superClass);
386 if (highlightInfo != null) return highlightInfo;
391 static Collection<HighlightInfo> checkOverrideEquivalentMethods(@NotNull PsiClass aClass) {
392 List<HighlightInfo> result = new ArrayList<>();
393 final Collection<HierarchicalMethodSignature> signaturesWithSupers = aClass.getVisibleSignatures();
394 PsiManager manager = aClass.getManager();
395 Map<MethodSignature, MethodSignatureBackedByPsiMethod> sameErasureMethods =
396 new THashMap<>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);
398 final Set<MethodSignature> foundProblems = new THashSet<>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);
399 for (HierarchicalMethodSignature signature : signaturesWithSupers) {
400 HighlightInfo info = checkSameErasureNotSubSignatureInner(signature, manager, aClass, sameErasureMethods);
401 if (info != null && foundProblems.add(signature)) {
404 if (aClass instanceof PsiTypeParameter) {
405 info = HighlightMethodUtil.checkMethodIncompatibleReturnType(signature, signature.getSuperSignatures(), true, HighlightNamesUtil.getClassDeclarationTextRange(aClass));
412 return result.isEmpty() ? null : result;
415 static HighlightInfo checkDefaultMethodOverrideEquivalentToObjectNonPrivate(@NotNull LanguageLevel languageLevel,
416 @NotNull PsiClass aClass,
417 @NotNull PsiMethod method,
418 @NotNull PsiElement methodIdentifier) {
419 if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && aClass.isInterface() && method.hasModifierProperty(PsiModifier.DEFAULT)) {
420 HierarchicalMethodSignature sig = method.getHierarchicalMethodSignature();
421 for (HierarchicalMethodSignature methodSignature : sig.getSuperSignatures()) {
422 final PsiMethod objectMethod = methodSignature.getMethod();
423 final PsiClass containingClass = objectMethod.getContainingClass();
424 if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) && objectMethod.hasModifierProperty(PsiModifier.PUBLIC)) {
425 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
426 .descriptionAndTooltip("Default method '" + sig.getName() + "' overrides a member of 'java.lang.Object'")
427 .range(methodIdentifier)
435 static HighlightInfo checkUnrelatedDefaultMethods(@NotNull PsiClass aClass,
436 @NotNull PsiIdentifier classIdentifier) {
437 final Map<? extends MethodSignature, Set<PsiMethod>> overrideEquivalent = PsiSuperMethodUtil.collectOverrideEquivalents(aClass);
439 final boolean isInterface = aClass.isInterface();
440 for (Set<PsiMethod> overrideEquivalentMethods : overrideEquivalent.values()) {
441 if (overrideEquivalentMethods.size() <= 1) continue;
442 List<PsiMethod> defaults = null;
443 List<PsiMethod> abstracts = null;
444 boolean hasConcrete = false;
445 for (PsiMethod method : overrideEquivalentMethods) {
446 final boolean isDefault = method.hasModifierProperty(PsiModifier.DEFAULT);
447 final boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT);
449 if (defaults == null) defaults = new ArrayList<>(2);
450 defaults.add(method);
453 if (abstracts == null) abstracts = new ArrayList<>(2);
454 abstracts.add(method);
456 hasConcrete |= !isDefault && !isAbstract;
459 if (!hasConcrete && defaults != null) {
460 final PsiMethod defaultMethod = defaults.get(0);
461 final PsiClass defaultMethodContainingClass = defaultMethod.getContainingClass();
462 if (defaultMethodContainingClass == null) continue;
463 final PsiMethod unrelatedMethod = abstracts != null ? abstracts.get(0) : defaults.get(1);
464 final PsiClass unrelatedMethodContainingClass = unrelatedMethod.getContainingClass();
465 if (unrelatedMethodContainingClass == null) continue;
466 if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT) && !(aClass instanceof PsiTypeParameter)
467 && abstracts != null && unrelatedMethodContainingClass.isInterface()) {
468 if (defaultMethodContainingClass.isInheritor(unrelatedMethodContainingClass, true) &&
469 MethodSignatureUtil.isSubsignature(unrelatedMethod.getSignature(TypeConversionUtil.getSuperClassSubstitutor(unrelatedMethodContainingClass, defaultMethodContainingClass, PsiSubstitutor.EMPTY)),
470 defaultMethod.getSignature(PsiSubstitutor.EMPTY))) {
473 final String key = aClass instanceof PsiEnumConstantInitializer ? "enum.constant.should.implement.method" : "class.must.be.abstract";
474 final String message = JavaErrorMessages.message(key, HighlightUtil.formatClass(aClass, false), JavaHighlightUtil.formatMethod(abstracts.get(0)),
475 HighlightUtil.formatClass(unrelatedMethodContainingClass, false));
476 final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(classIdentifier).descriptionAndTooltip(message).create();
477 QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createImplementMethodsFix(aClass));
480 if (isInterface || abstracts == null || unrelatedMethodContainingClass.isInterface()) {
481 final List<PsiClass> defaultContainingClasses = ContainerUtil.mapNotNull(defaults, PsiMethod::getContainingClass);
482 final String unrelatedDefaults = hasUnrelatedDefaults(defaultContainingClasses);
483 if (unrelatedDefaults == null &&
484 (abstracts == null || !hasNotOverriddenAbstract(defaultContainingClasses, unrelatedMethodContainingClass))) {
488 final String message = unrelatedDefaults != null ? " inherits unrelated defaults for " : " inherits abstract and default for ";
489 final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(classIdentifier).descriptionAndTooltip(
490 HighlightUtil.formatClass(aClass) +
492 JavaHighlightUtil.formatMethod(defaultMethod) + " from types " +
493 (unrelatedDefaults != null ? unrelatedDefaults
494 : HighlightUtil.formatClass(defaultMethodContainingClass) + " and " + HighlightUtil.formatClass(unrelatedMethodContainingClass)))
496 QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createImplementMethodsFix(aClass));
504 private static boolean belongToOneHierarchy(@NotNull PsiClass defaultMethodContainingClass, @NotNull PsiClass unrelatedMethodContainingClass) {
505 return defaultMethodContainingClass.isInheritor(unrelatedMethodContainingClass, true) ||
506 unrelatedMethodContainingClass.isInheritor(defaultMethodContainingClass, true);
509 private static boolean hasNotOverriddenAbstract(List<PsiClass> defaultContainingClasses, @NotNull PsiClass abstractMethodContainingClass) {
510 return defaultContainingClasses.stream().noneMatch(containingClass -> belongToOneHierarchy(containingClass, abstractMethodContainingClass));
513 private static String hasUnrelatedDefaults(List<PsiClass> defaults) {
514 if (defaults.size() > 1) {
515 for (int i = 0; i < defaults.size(); i++) {
516 final PsiClass aClass1 = defaults.get(i);
517 for (int j = i + 1; j < defaults.size(); j++) {
518 final PsiClass aClass2 = defaults.get(j);
519 if (aClass2 != null && !belongToOneHierarchy(aClass1, aClass2)) {
520 return HighlightUtil.formatClass(aClass1) + " and " + HighlightUtil.formatClass(aClass2);
529 static HighlightInfo checkUnrelatedConcrete(@NotNull PsiClass psiClass,
530 @NotNull PsiIdentifier classIdentifier) {
531 final PsiClass superClass = psiClass.getSuperClass();
532 if (superClass != null && superClass.hasTypeParameters()) {
533 final Collection<HierarchicalMethodSignature> visibleSignatures = superClass.getVisibleSignatures();
534 final Map<MethodSignature, PsiMethod> overrideEquivalent = new THashMap<>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);
535 for (HierarchicalMethodSignature hms : visibleSignatures) {
536 final PsiMethod method = hms.getMethod();
537 if (method.isConstructor()) continue;
538 if (method.hasModifierProperty(PsiModifier.ABSTRACT) || method.hasModifierProperty(PsiModifier.DEFAULT)) continue;
539 if (psiClass.findMethodsBySignature(method, false).length > 0) continue;
540 final PsiClass containingClass = method.getContainingClass();
541 if (containingClass == null) continue;
542 final PsiSubstitutor containingClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(containingClass, psiClass, PsiSubstitutor.EMPTY);
543 final PsiSubstitutor finalSubstitutor = PsiSuperMethodUtil
544 .obtainFinalSubstitutor(containingClass, containingClassSubstitutor, hms.getSubstitutor(), false);
545 final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, finalSubstitutor, false);
546 final PsiMethod foundMethod = overrideEquivalent.get(signature);
547 PsiClass foundMethodContainingClass;
548 if (foundMethod != null &&
549 !foundMethod.hasModifierProperty(PsiModifier.ABSTRACT) &&
550 !foundMethod.hasModifierProperty(PsiModifier.DEFAULT) &&
551 (foundMethodContainingClass = foundMethod.getContainingClass()) != null) {
552 final String description =
554 JavaHighlightUtil.formatMethod(foundMethod) + " from " + HighlightUtil.formatClass(foundMethodContainingClass) +
556 JavaHighlightUtil.formatMethod(method) + " from " + HighlightUtil.formatClass(containingClass) +
557 " are inherited with the same signature";
559 final HighlightInfo info = HighlightInfo
560 .newHighlightInfo(HighlightInfoType.ERROR).range(classIdentifier).descriptionAndTooltip(
566 overrideEquivalent.put(signature, method);
573 private static HighlightInfo checkSameErasureNotSubSignatureInner(@NotNull HierarchicalMethodSignature signature,
574 @NotNull PsiManager manager,
575 @NotNull PsiClass aClass,
576 @NotNull Map<MethodSignature, MethodSignatureBackedByPsiMethod> sameErasureMethods) {
577 PsiMethod method = signature.getMethod();
578 JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject());
579 if (!facade.getResolveHelper().isAccessible(method, aClass, null)) return null;
580 MethodSignature signatureToErase = method.getSignature(PsiSubstitutor.EMPTY);
581 MethodSignatureBackedByPsiMethod sameErasure = sameErasureMethods.get(signatureToErase);
583 if (sameErasure != null) {
584 if (aClass instanceof PsiTypeParameter ||
585 MethodSignatureUtil.findMethodBySuperMethod(aClass, sameErasure.getMethod(), false) != null ||
586 !(InheritanceUtil.isInheritorOrSelf(sameErasure.getMethod().getContainingClass(), method.getContainingClass(), true) ||
587 InheritanceUtil.isInheritorOrSelf(method.getContainingClass(), sameErasure.getMethod().getContainingClass(), true))) {
588 info = checkSameErasureNotSubSignatureOrSameClass(sameErasure, signature, aClass, method);
589 if (info != null) return info;
593 sameErasureMethods.put(signatureToErase, signature);
595 List<HierarchicalMethodSignature> supers = signature.getSuperSignatures();
596 for (HierarchicalMethodSignature superSignature : supers) {
597 info = checkSameErasureNotSubSignatureInner(superSignature, manager, aClass, sameErasureMethods);
598 if (info != null) return info;
600 if (superSignature.isRaw() && !signature.isRaw()) {
601 final PsiType[] parameterTypes = signature.getParameterTypes();
602 PsiType[] erasedTypes = superSignature.getErasedParameterTypes();
603 for (int i = 0; i < erasedTypes.length; i++) {
604 if (!Comparing.equal(parameterTypes[i], erasedTypes[i])) {
605 return getSameErasureMessage(false, method, superSignature.getMethod(),
606 HighlightNamesUtil.getClassDeclarationTextRange(aClass));
616 private static HighlightInfo checkSameErasureNotSubSignatureOrSameClass(final MethodSignatureBackedByPsiMethod signatureToCheck,
617 final HierarchicalMethodSignature superSignature,
618 final PsiClass aClass,
619 final PsiMethod superMethod) {
620 final PsiMethod checkMethod = signatureToCheck.getMethod();
621 if (superMethod.equals(checkMethod)) return null;
622 PsiClass checkContainingClass = checkMethod.getContainingClass();
623 LOG.assertTrue(checkContainingClass != null);
624 PsiClass superContainingClass = superMethod.getContainingClass();
625 boolean checkEqualsSuper = checkContainingClass.equals(superContainingClass);
626 if (checkMethod.isConstructor()) {
627 if (!superMethod.isConstructor() || !checkEqualsSuper) return null;
629 else if (superMethod.isConstructor()) return null;
631 final boolean atLeast17 = JavaVersionService.getInstance().isAtLeast(aClass, JavaSdkVersion.JDK_1_7);
632 if (checkMethod.hasModifierProperty(PsiModifier.STATIC) && !checkEqualsSuper && !atLeast17) {
636 if (superMethod.hasModifierProperty(PsiModifier.STATIC) && superContainingClass != null &&
637 superContainingClass.isInterface() && PsiUtil.isLanguageLevel8OrHigher(superContainingClass)) {
641 final PsiType retErasure1 = TypeConversionUtil.erasure(checkMethod.getReturnType());
642 final PsiType retErasure2 = TypeConversionUtil.erasure(superMethod.getReturnType());
644 boolean differentReturnTypeErasure = !Comparing.equal(retErasure1, retErasure2);
645 if (checkEqualsSuper && atLeast17) {
646 if (retErasure1 != null && retErasure2 != null) {
647 differentReturnTypeErasure = !TypeConversionUtil.isAssignable(retErasure1, retErasure2);
650 differentReturnTypeErasure = !(retErasure1 == null && retErasure2 == null);
654 if (differentReturnTypeErasure &&
655 !TypeConversionUtil.isVoidType(retErasure1) &&
656 !TypeConversionUtil.isVoidType(retErasure2) &&
657 !(checkEqualsSuper && Arrays.equals(superSignature.getParameterTypes(), signatureToCheck.getParameterTypes())) &&
660 final PsiType[] erasedTypes = signatureToCheck.getErasedParameterTypes();
661 boolean erasure = erasedTypes.length > 0;
662 for (PsiType type : superSignature.getParameterTypes()) {
663 erasure &= Comparing.equal(type, erasedTypes[idx]);
667 if (!erasure) return null;
670 if (!checkEqualsSuper && MethodSignatureUtil.isSubsignature(superSignature, signatureToCheck)) {
673 if (superContainingClass != null && !superContainingClass.isInterface() && checkContainingClass.isInterface() && !aClass.equals(superContainingClass)) return null;
674 if (aClass.equals(checkContainingClass)) {
675 boolean sameClass = aClass.equals(superContainingClass);
676 return getSameErasureMessage(sameClass, checkMethod, superMethod, HighlightNamesUtil.getMethodDeclarationTextRange(checkMethod));
679 return getSameErasureMessage(false, checkMethod, superMethod, HighlightNamesUtil.getClassDeclarationTextRange(aClass));
683 private static HighlightInfo getSameErasureMessage(final boolean sameClass, @NotNull PsiMethod method, @NotNull PsiMethod superMethod,
684 TextRange textRange) {
685 @NonNls final String key = sameClass ? "generics.methods.have.same.erasure" :
686 method.hasModifierProperty(PsiModifier.STATIC) ?
687 "generics.methods.have.same.erasure.hide" :
688 "generics.methods.have.same.erasure.override";
689 String description = JavaErrorMessages.message(key, HighlightMethodUtil.createClashMethodMessage(method, superMethod, !sameClass));
690 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
693 static HighlightInfo checkTypeParameterInstantiation(PsiNewExpression expression) {
694 PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
695 if (classReference == null) return null;
696 final JavaResolveResult result = classReference.advancedResolve(false);
697 final PsiElement element = result.getElement();
698 if (element instanceof PsiTypeParameter) {
699 String description = JavaErrorMessages.message("generics.type.parameter.cannot.be.instantiated",
700 HighlightUtil.formatClass((PsiTypeParameter)element));
701 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(classReference).descriptionAndTooltip(description).create();
706 static HighlightInfo checkWildcardUsage(PsiTypeElement typeElement) {
707 PsiType type = typeElement.getType();
708 if (type instanceof PsiWildcardType) {
709 if (typeElement.getParent() instanceof PsiReferenceParameterList) {
710 PsiElement parent = typeElement.getParent().getParent();
711 LOG.assertTrue(parent instanceof PsiJavaCodeReferenceElement, parent);
712 PsiElement refParent = parent.getParent();
713 if (refParent instanceof PsiAnonymousClass) refParent = refParent.getParent();
714 if (refParent instanceof PsiNewExpression) {
715 PsiNewExpression newExpression = (PsiNewExpression)refParent;
716 if (!(newExpression.getType() instanceof PsiArrayType)) {
717 String description = JavaErrorMessages.message("wildcard.type.cannot.be.instantiated", JavaHighlightUtil.formatType(type));
718 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create();
721 else if (refParent instanceof PsiReferenceList) {
722 PsiElement refPParent = refParent.getParent();
723 if (!(refPParent instanceof PsiTypeParameter) || refParent != ((PsiTypeParameter)refPParent).getExtendsList()) {
724 String description = JavaErrorMessages.message("generics.wildcard.not.expected");
725 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create();
730 String description = JavaErrorMessages.message("generics.wildcards.may.be.used.only.as.reference.parameters");
731 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create();
738 static HighlightInfo checkReferenceTypeUsedAsTypeArgument(PsiTypeElement typeElement, LanguageLevel level) {
739 final PsiType type = typeElement.getType();
740 if (type != PsiType.NULL && type instanceof PsiPrimitiveType ||
741 type instanceof PsiWildcardType && ((PsiWildcardType)type).getBound() instanceof PsiPrimitiveType) {
742 final PsiElement element = new PsiMatcherImpl(typeElement)
743 .parent(PsiMatchers.hasClass(PsiReferenceParameterList.class))
744 .parent(PsiMatchers.hasClass(PsiJavaCodeReferenceElement.class, PsiNewExpression.class))
746 if (element == null) return null;
748 if (level.isAtLeast(LanguageLevel.JDK_X)) return null;
750 String text = JavaErrorMessages.message("generics.type.argument.cannot.be.of.primitive.type");
751 HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(text).create();
753 PsiType toConvert = type;
754 if (type instanceof PsiWildcardType) {
755 toConvert = ((PsiWildcardType)type).getBound();
757 if (toConvert instanceof PsiPrimitiveType) {
758 final PsiClassType boxedType = ((PsiPrimitiveType)toConvert).getBoxedType(typeElement);
759 if (boxedType != null) {
760 QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createReplacePrimitiveWithBoxedTypeAction(
761 typeElement, toConvert.getPresentableText(), ((PsiPrimitiveType)toConvert).getBoxedTypeName()));
764 return highlightInfo;
770 static HighlightInfo checkForeachExpressionTypeIsIterable(PsiExpression expression) {
771 if (expression == null || expression.getType() == null) return null;
772 final PsiType itemType = JavaGenericsUtil.getCollectionItemType(expression);
773 if (itemType == null) {
774 String description = JavaErrorMessages.message("foreach.not.applicable",
775 JavaHighlightUtil.formatType(expression.getType()));
776 final HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description).create();
777 QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createNotIterableForEachLoopFix(expression));
778 return highlightInfo;
783 static HighlightInfo checkForEachParameterType(@NotNull PsiForeachStatement statement, @NotNull PsiParameter parameter) {
784 final PsiExpression expression = statement.getIteratedValue();
785 final PsiType itemType = expression == null ? null : JavaGenericsUtil.getCollectionItemType(expression);
786 if (itemType == null) return null;
788 final PsiType parameterType = parameter.getType();
789 if (TypeConversionUtil.isAssignable(parameterType, itemType)) {
792 HighlightInfo highlightInfo = HighlightUtil.createIncompatibleTypeHighlightInfo(itemType, parameterType, parameter.getTextRange(), 0);
793 HighlightUtil.registerChangeVariableTypeFixes(parameter, itemType, expression, highlightInfo);
794 return highlightInfo;
797 //http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.2
799 static HighlightInfo checkAccessStaticFieldFromEnumConstructor(@NotNull PsiReferenceExpression expr, @NotNull JavaResolveResult result) {
800 final PsiElement resolved = result.getElement();
802 if (!(resolved instanceof PsiField)) return null;
803 if (!((PsiModifierListOwner)resolved).hasModifierProperty(PsiModifier.STATIC)) return null;
804 if (expr.getParent() instanceof PsiSwitchLabelStatement) return null;
805 final PsiMember constructorOrInitializer = PsiUtil.findEnclosingConstructorOrInitializer(expr);
806 if (constructorOrInitializer == null) return null;
807 if (constructorOrInitializer.hasModifierProperty(PsiModifier.STATIC)) return null;
808 final PsiClass aClass = constructorOrInitializer instanceof PsiEnumConstantInitializer ?
809 (PsiClass)constructorOrInitializer : constructorOrInitializer.getContainingClass();
810 if (aClass == null || !(aClass.isEnum() || aClass instanceof PsiEnumConstantInitializer)) return null;
811 final PsiField field = (PsiField)resolved;
812 if (aClass instanceof PsiEnumConstantInitializer) {
813 if (field.getContainingClass() != aClass.getSuperClass()) return null;
814 } else if (field.getContainingClass() != aClass) return null;
817 if (!JavaVersionService.getInstance().isAtLeast(field, JavaSdkVersion.JDK_1_6)) {
818 final PsiType type = field.getType();
819 if (type instanceof PsiClassType && ((PsiClassType)type).resolve() == aClass) return null;
822 if (PsiUtil.isCompileTimeConstant((PsiVariable)field)) return null;
824 String description = JavaErrorMessages.message(
825 "illegal.to.access.static.member.from.enum.constructor.or.instance.initializer",
826 HighlightMessageUtil.getSymbolName(resolved, result.getSubstitutor())
829 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expr).descriptionAndTooltip(description).create();
833 static HighlightInfo checkEnumInstantiation(PsiElement expression, PsiClass aClass) {
834 if (aClass != null && aClass.isEnum() &&
835 (!(expression instanceof PsiNewExpression) ||
836 ((PsiNewExpression)expression).getArrayDimensions().length == 0 && ((PsiNewExpression)expression).getArrayInitializer() == null)) {
837 String description = JavaErrorMessages.message("enum.types.cannot.be.instantiated");
838 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description).create();
844 static HighlightInfo checkGenericArrayCreation(PsiElement element, PsiType type) {
845 if (type instanceof PsiArrayType) {
846 if (!JavaGenericsUtil.isReifiableType(((PsiArrayType)type).getComponentType())) {
847 String description = JavaErrorMessages.message("generic.array.creation");
848 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create();
855 private static final MethodSignature ourValuesEnumSyntheticMethod = MethodSignatureUtil.createMethodSignature("values",
857 PsiTypeParameter.EMPTY_ARRAY,
858 PsiSubstitutor.EMPTY);
860 static boolean isEnumSyntheticMethod(MethodSignature methodSignature, Project project) {
861 if (methodSignature.equals(ourValuesEnumSyntheticMethod)) return true;
862 final PsiType javaLangString = PsiType.getJavaLangString(PsiManager.getInstance(project), GlobalSearchScope.allScope(project));
863 final MethodSignature valueOfMethod = MethodSignatureUtil.createMethodSignature("valueOf", new PsiType[]{javaLangString}, PsiTypeParameter.EMPTY_ARRAY,
864 PsiSubstitutor.EMPTY);
865 return valueOfMethod.equals(methodSignature);
869 static HighlightInfo checkTypeParametersList(PsiTypeParameterList list, PsiTypeParameter[] parameters, @NotNull LanguageLevel level) {
870 final PsiElement parent = list.getParent();
871 if (parent instanceof PsiClass && ((PsiClass)parent).isEnum()) {
872 String description = JavaErrorMessages.message("generics.enum.may.not.have.type.parameters");
873 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).descriptionAndTooltip(description).create();
875 if (PsiUtil.isAnnotationMethod(parent)) {
876 String description = JavaErrorMessages.message("generics.annotation.members.may.not.have.type.parameters");
877 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).descriptionAndTooltip(description).create();
879 if (parent instanceof PsiClass && ((PsiClass)parent).isAnnotationType()) {
880 String description = JavaErrorMessages.message("annotation.may.not.have.type.parameters");
881 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).descriptionAndTooltip(description).create();
884 for (int i = 0; i < parameters.length; i++) {
885 final PsiTypeParameter typeParameter1 = parameters[i];
886 final HighlightInfo cyclicInheritance = HighlightClassUtil.checkCyclicInheritance(typeParameter1);
887 if (cyclicInheritance != null) return cyclicInheritance;
888 String name1 = typeParameter1.getName();
889 for (int j = i + 1; j < parameters.length; j++) {
890 final PsiTypeParameter typeParameter2 = parameters[j];
891 String name2 = typeParameter2.getName();
892 if (Comparing.strEqual(name1, name2)) {
893 String message = JavaErrorMessages.message("generics.duplicate.type.parameter", name1);
894 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeParameter2).descriptionAndTooltip(message).create();
897 if (!level.isAtLeast(LanguageLevel.JDK_1_7)) {
898 for (PsiJavaCodeReferenceElement referenceElement : typeParameter1.getExtendsList().getReferenceElements()) {
899 final PsiElement resolve = referenceElement.resolve();
900 if (resolve instanceof PsiTypeParameter && ArrayUtilRt.find(parameters, resolve) > i) {
901 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(referenceElement.getTextRange()).descriptionAndTooltip("Illegal forward reference").create();
910 static Collection<HighlightInfo> checkCatchParameterIsClass(PsiParameter parameter) {
911 if (!(parameter.getDeclarationScope() instanceof PsiCatchSection)) return null;
912 final Collection<HighlightInfo> result = ContainerUtil.newArrayList();
914 final List<PsiTypeElement> typeElements = PsiUtil.getParameterTypeElements(parameter);
915 for (PsiTypeElement typeElement : typeElements) {
916 final PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(typeElement.getType());
917 if (aClass instanceof PsiTypeParameter) {
918 final String message = JavaErrorMessages.message("generics.cannot.catch.type.parameters");
919 result.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(message).create());
926 static HighlightInfo checkInstanceOfGenericType(PsiInstanceOfExpression expression) {
927 final PsiTypeElement checkTypeElement = expression.getCheckType();
928 if (checkTypeElement == null) return null;
929 return isIllegalForInstanceOf(checkTypeElement.getType(), checkTypeElement);
933 * 15.20.2 Type Comparison Operator instanceof
934 * ReferenceType mentioned after the instanceof operator is reifiable
936 private static HighlightInfo isIllegalForInstanceOf(PsiType type, final PsiTypeElement typeElement) {
937 final PsiClass resolved = PsiUtil.resolveClassInClassTypeOnly(type);
938 if (resolved instanceof PsiTypeParameter) {
939 String description = JavaErrorMessages.message("generics.cannot.instanceof.type.parameters");
940 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create();
943 if (!JavaGenericsUtil.isReifiableType(type)) {
944 String description = JavaErrorMessages.message("illegal.generic.type.for.instanceof");
945 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create();
951 static HighlightInfo checkClassObjectAccessExpression(PsiClassObjectAccessExpression expression) {
952 PsiType type = expression.getOperand().getType();
953 if (type instanceof PsiClassType) {
954 return canSelectFrom((PsiClassType)type, expression.getOperand());
956 if (type instanceof PsiArrayType) {
957 final PsiType arrayComponentType = type.getDeepComponentType();
958 if (arrayComponentType instanceof PsiClassType) {
959 return canSelectFrom((PsiClassType)arrayComponentType, expression.getOperand());
967 private static HighlightInfo canSelectFrom(PsiClassType type, PsiTypeElement operand) {
968 PsiClass aClass = type.resolve();
969 if (aClass instanceof PsiTypeParameter) {
970 String description = JavaErrorMessages.message("cannot.select.dot.class.from.type.variable");
971 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(operand).descriptionAndTooltip(description).create();
973 if (type.getParameters().length > 0) {
975 .newHighlightInfo(HighlightInfoType.ERROR).range(operand).descriptionAndTooltip("Cannot select from parameterized type").create();
981 static HighlightInfo checkOverrideAnnotation(@NotNull PsiMethod method,
982 @NotNull PsiAnnotation overrideAnnotation,
983 @NotNull LanguageLevel languageLevel) {
985 MethodSignatureBackedByPsiMethod superMethod = SuperMethodsSearch.search(method, null, true, false).findFirst();
986 if (superMethod != null && method.getContainingClass().isInterface()) {
987 final PsiMethod psiMethod = superMethod.getMethod();
988 final PsiClass containingClass = psiMethod.getContainingClass();
989 if (containingClass != null &&
990 CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) &&
991 psiMethod.hasModifierProperty(PsiModifier.PROTECTED)) {
995 if (superMethod == null) {
996 String description = JavaErrorMessages.message("method.does.not.override.super");
997 HighlightInfo highlightInfo =
998 HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(overrideAnnotation).descriptionAndTooltip(description).create();
999 QUICK_FIX_FACTORY.registerPullAsAbstractUpFixes(method, new QuickFixActionRegistrarImpl(highlightInfo));
1000 return highlightInfo;
1002 PsiClass superClass = superMethod.getMethod().getContainingClass();
1003 if (languageLevel.equals(LanguageLevel.JDK_1_5) &&
1004 superClass != null &&
1005 superClass.isInterface()) {
1006 String description = JavaErrorMessages.message("override.not.allowed.in.interfaces");
1007 HighlightInfo info =
1008 HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(overrideAnnotation).descriptionAndTooltip(description).create();
1009 QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createIncreaseLanguageLevelFix(LanguageLevel.JDK_1_6));
1014 catch (IndexNotReadyException e) {
1020 static HighlightInfo checkSafeVarargsAnnotation(PsiMethod method, LanguageLevel languageLevel) {
1021 PsiModifierList list = method.getModifierList();
1022 final PsiAnnotation safeVarargsAnnotation = list.findAnnotation("java.lang.SafeVarargs");
1023 if (safeVarargsAnnotation == null) {
1027 if (!method.isVarArgs()) {
1028 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(safeVarargsAnnotation).descriptionAndTooltip(
1029 "@SafeVarargs is not allowed on methods with fixed arity").create();
1031 if (!isSafeVarargsNoOverridingCondition(method, languageLevel)) {
1032 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(safeVarargsAnnotation).descriptionAndTooltip(
1033 "@SafeVarargs is not allowed on non-final instance methods").create();
1036 final PsiParameter varParameter = method.getParameterList().getParameters()[method.getParameterList().getParametersCount() - 1];
1038 for (PsiReference reference : ReferencesSearch.search(varParameter)) {
1039 final PsiElement element = reference.getElement();
1040 if (element instanceof PsiExpression && !PsiUtil.isAccessedForReading((PsiExpression)element)) {
1041 return HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING).range(element).descriptionAndTooltip(
1042 "@SafeVarargs do not suppress potentially unsafe operations").create();
1047 LOG.assertTrue(varParameter.isVarArgs());
1048 final PsiEllipsisType ellipsisType = (PsiEllipsisType)varParameter.getType();
1049 final PsiType componentType = ellipsisType.getComponentType();
1050 if (JavaGenericsUtil.isReifiableType(componentType)) {
1051 PsiElement element = varParameter.getTypeElement();
1052 return HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING).range(element).descriptionAndTooltip(
1053 "@SafeVarargs is not applicable for reifiable types").create();
1057 catch (IndexNotReadyException e) {
1062 public static boolean isSafeVarargsNoOverridingCondition(PsiMethod method, LanguageLevel languageLevel) {
1063 return method.hasModifierProperty(PsiModifier.FINAL) ||
1064 method.hasModifierProperty(PsiModifier.STATIC) ||
1065 method.isConstructor() ||
1066 method.hasModifierProperty(PsiModifier.PRIVATE) && languageLevel.isAtLeast(LanguageLevel.JDK_1_9);
1069 static void checkEnumConstantForConstructorProblems(@NotNull PsiEnumConstant enumConstant,
1070 @NotNull HighlightInfoHolder holder,
1071 @NotNull JavaSdkVersion javaSdkVersion) {
1072 PsiClass containingClass = enumConstant.getContainingClass();
1073 if (enumConstant.getInitializingClass() == null) {
1074 HighlightInfo highlightInfo = HighlightClassUtil.checkInstantiationOfAbstractClass(containingClass, enumConstant.getNameIdentifier());
1075 if (highlightInfo != null) {
1076 QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createImplementMethodsFix(enumConstant));
1077 holder.add(highlightInfo);
1080 highlightInfo = HighlightClassUtil.checkClassWithAbstractMethods(enumConstant.getContainingClass(), enumConstant, enumConstant.getNameIdentifier().getTextRange());
1081 if (highlightInfo != null) {
1082 holder.add(highlightInfo);
1086 PsiClassType type = JavaPsiFacade.getInstance(holder.getProject()).getElementFactory().createType(containingClass);
1088 HighlightMethodUtil.checkConstructorCall(type.resolveGenerics(), enumConstant, type, null, holder, javaSdkVersion);
1092 static HighlightInfo checkEnumSuperConstructorCall(PsiMethodCallExpression expr) {
1093 PsiReferenceExpression methodExpression = expr.getMethodExpression();
1094 final PsiElement refNameElement = methodExpression.getReferenceNameElement();
1095 if (refNameElement != null && PsiKeyword.SUPER.equals(refNameElement.getText())) {
1096 final PsiMember constructor = PsiUtil.findEnclosingConstructorOrInitializer(expr);
1097 if (constructor instanceof PsiMethod) {
1098 final PsiClass aClass = constructor.getContainingClass();
1099 if (aClass != null && aClass.isEnum()) {
1100 final String message = JavaErrorMessages.message("call.to.super.is.not.allowed.in.enum.constructor");
1101 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expr).descriptionAndTooltip(message).create();
1109 static HighlightInfo checkVarArgParameterIsLast(@NotNull PsiParameter parameter) {
1110 PsiElement declarationScope = parameter.getDeclarationScope();
1111 if (declarationScope instanceof PsiMethod) {
1112 PsiParameter[] params = ((PsiMethod)declarationScope).getParameterList().getParameters();
1113 if (params[params.length - 1] != parameter) {
1114 String description = JavaErrorMessages.message("vararg.not.last.parameter");
1115 HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parameter).descriptionAndTooltip(description).create();
1116 QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createMakeVarargParameterLastFix(parameter));
1124 static List<HighlightInfo> checkEnumConstantModifierList(PsiModifierList modifierList) {
1125 List<HighlightInfo> list = null;
1126 PsiElement[] children = modifierList.getChildren();
1127 for (PsiElement child : children) {
1128 if (child instanceof PsiKeyword) {
1130 list = new ArrayList<>();
1132 String description = JavaErrorMessages.message("modifiers.for.enum.constants");
1133 list.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(child).descriptionAndTooltip(description).create());
1140 static HighlightInfo checkParametersAllowed(PsiReferenceParameterList refParamList) {
1141 final PsiElement parent = refParamList.getParent();
1142 if (parent instanceof PsiReferenceExpression) {
1143 final PsiElement grandParent = parent.getParent();
1144 if (!(grandParent instanceof PsiMethodCallExpression) && !(parent instanceof PsiMethodReferenceExpression)) {
1145 final String message = JavaErrorMessages.message("generics.reference.parameters.not.allowed");
1146 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(refParamList).descriptionAndTooltip(message).create();
1154 static HighlightInfo checkParametersOnRaw(PsiReferenceParameterList refParamList) {
1155 JavaResolveResult resolveResult = null;
1156 PsiElement parent = refParamList.getParent();
1157 PsiElement qualifier = null;
1158 if (parent instanceof PsiJavaCodeReferenceElement) {
1159 resolveResult = ((PsiJavaCodeReferenceElement)parent).advancedResolve(false);
1160 qualifier = ((PsiJavaCodeReferenceElement)parent).getQualifier();
1162 else if (parent instanceof PsiCallExpression) {
1163 resolveResult = ((PsiCallExpression)parent).resolveMethodGenerics();
1164 if (parent instanceof PsiMethodCallExpression) {
1165 final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)parent).getMethodExpression();
1166 qualifier = methodExpression.getQualifier();
1169 if (resolveResult != null) {
1170 PsiElement element = resolveResult.getElement();
1171 if (!(element instanceof PsiTypeParameterListOwner)) return null;
1172 if (((PsiModifierListOwner)element).hasModifierProperty(PsiModifier.STATIC)) return null;
1173 if (qualifier instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement)qualifier).resolve() instanceof PsiTypeParameter) return null;
1174 PsiClass containingClass = ((PsiMember)element).getContainingClass();
1175 if (containingClass != null && PsiUtil.isRawSubstitutor(containingClass, resolveResult.getSubstitutor())) {
1176 if ((parent instanceof PsiCallExpression || parent instanceof PsiMethodReferenceExpression) && PsiUtil.isLanguageLevel7OrHigher(parent)) {
1180 if (element instanceof PsiMethod) {
1181 if (((PsiMethod)element).findSuperMethods().length > 0) return null;
1182 if (qualifier instanceof PsiReferenceExpression){
1183 final PsiType type = ((PsiReferenceExpression)qualifier).getType();
1184 final boolean isJavac7 = JavaVersionService.getInstance().isAtLeast(containingClass, JavaSdkVersion.JDK_1_7);
1185 if (type instanceof PsiClassType && isJavac7 && ((PsiClassType)type).isRaw()) return null;
1186 final PsiClass typeParameter = PsiUtil.resolveClassInType(type);
1187 if (typeParameter instanceof PsiTypeParameter) {
1188 if (isJavac7) return null;
1189 for (PsiClassType classType : typeParameter.getExtendsListTypes()) {
1190 final PsiClass resolve = classType.resolve();
1191 if (resolve != null) {
1192 final PsiMethod[] superMethods = resolve.findMethodsBySignature((PsiMethod)element, true);
1193 for (PsiMethod superMethod : superMethods) {
1194 if (!PsiUtil.isRawSubstitutor(superMethod, resolveResult.getSubstitutor())) {
1203 final String message = element instanceof PsiClass
1204 ? JavaErrorMessages.message("generics.type.arguments.on.raw.type")
1205 : JavaErrorMessages.message("generics.type.arguments.on.raw.method");
1207 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(refParamList).descriptionAndTooltip(message).create();
1213 static HighlightInfo checkCannotInheritFromEnum(PsiClass superClass, PsiElement elementToHighlight) {
1214 HighlightInfo errorResult = null;
1215 if (Comparing.strEqual("java.lang.Enum", superClass.getQualifiedName())) {
1216 String message = JavaErrorMessages.message("classes.extends.enum");
1218 HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(elementToHighlight).descriptionAndTooltip(message).create();
1223 static HighlightInfo checkGenericCannotExtendException(PsiReferenceList list) {
1224 PsiElement parent = list.getParent();
1225 if (!(parent instanceof PsiClass)) return null;
1226 PsiClass aClass = (PsiClass)parent;
1228 if (!aClass.hasTypeParameters() || aClass.getExtendsList() != list) return null;
1229 PsiJavaCodeReferenceElement[] referenceElements = list.getReferenceElements();
1230 PsiClass throwableClass = null;
1231 for (PsiJavaCodeReferenceElement referenceElement : referenceElements) {
1232 PsiElement resolved = referenceElement.resolve();
1233 if (!(resolved instanceof PsiClass)) continue;
1234 if (throwableClass == null) {
1235 throwableClass = JavaPsiFacade.getInstance(aClass.getProject()).findClass("java.lang.Throwable", aClass.getResolveScope());
1237 if (InheritanceUtil.isInheritorOrSelf((PsiClass)resolved, throwableClass, true)) {
1238 String message = JavaErrorMessages.message("generic.extend.exception");
1239 HighlightInfo highlightInfo =
1240 HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(referenceElement).descriptionAndTooltip(message).create();
1241 PsiClassType classType = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType((PsiClass)resolved);
1242 QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createExtendsListFix(aClass, classType, false));
1243 return highlightInfo;
1249 static HighlightInfo checkEnumMustNotBeLocal(final PsiClass aClass) {
1250 if (!aClass.isEnum()) return null;
1251 PsiElement parent = aClass.getParent();
1252 if (!(parent instanceof PsiClass || parent instanceof PsiFile || parent instanceof PsiClassLevelDeclarationStatement)) {
1253 String description = JavaErrorMessages.message("local.enum");
1254 TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass);
1255 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
1260 static HighlightInfo checkEnumWithoutConstantsCantHaveAbstractMethods(final PsiClass aClass) {
1261 if (!aClass.isEnum()) return null;
1262 for (PsiField field : aClass.getFields()) {
1263 if (field instanceof PsiEnumConstant) {
1267 for (PsiMethod method : aClass.getMethods()) {
1268 if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
1269 final String description = "Enum declaration without enum constants cannot have abstract methods";
1270 final TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass);
1271 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
1277 static HighlightInfo checkSelectStaticClassFromParameterizedType(final PsiElement resolved, final PsiJavaCodeReferenceElement ref) {
1278 if (resolved instanceof PsiClass && ((PsiClass)resolved).hasModifierProperty(PsiModifier.STATIC)) {
1279 final PsiElement qualifier = ref.getQualifier();
1280 if (qualifier instanceof PsiJavaCodeReferenceElement) {
1281 final PsiReferenceParameterList parameterList = ((PsiJavaCodeReferenceElement)qualifier).getParameterList();
1282 if (parameterList != null && parameterList.getTypeArguments().length > 0) {
1283 final String message = JavaErrorMessages.message("generics.select.static.class.from.parameterized.type",
1284 HighlightUtil.formatClass((PsiClass)resolved));
1285 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parameterList).descriptionAndTooltip(message).create();
1292 static HighlightInfo checkCannotInheritFromTypeParameter(final PsiClass superClass, final PsiJavaCodeReferenceElement toHighlight) {
1293 if (superClass instanceof PsiTypeParameter) {
1294 String description = JavaErrorMessages.message("class.cannot.inherit.from.its.type.parameter");
1295 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(toHighlight).descriptionAndTooltip(description).create();
1301 * http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.8
1303 static HighlightInfo checkRawOnParameterizedType(@NotNull PsiJavaCodeReferenceElement parent, PsiElement resolved) {
1304 PsiReferenceParameterList list = parent.getParameterList();
1305 if (list == null || list.getTypeArguments().length > 0) return null;
1306 final PsiElement qualifier = parent.getQualifier();
1307 if (qualifier instanceof PsiJavaCodeReferenceElement &&
1308 ((PsiJavaCodeReferenceElement)qualifier).getTypeParameters().length > 0 &&
1309 resolved instanceof PsiTypeParameterListOwner &&
1310 ((PsiTypeParameterListOwner)resolved).hasTypeParameters() &&
1311 !((PsiTypeParameterListOwner)resolved).hasModifierProperty(PsiModifier.STATIC)) {
1312 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(parent).descriptionAndTooltip(
1313 "Improper formed type; some type parameters are missing").create();
1318 static HighlightInfo checkCannotPassInner(PsiJavaCodeReferenceElement ref) {
1319 if (ref.getParent() instanceof PsiTypeElement) {
1320 final PsiClass psiClass = PsiTreeUtil.getParentOfType(ref, PsiClass.class);
1321 if (psiClass == null) return null;
1322 if (PsiTreeUtil.isAncestor(psiClass.getExtendsList(), ref, false) ||
1323 PsiTreeUtil.isAncestor(psiClass.getImplementsList(), ref, false)) {
1324 final PsiElement qualifier = ref.getQualifier();
1325 if (qualifier instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement)qualifier).resolve() == psiClass) {
1326 final PsiJavaCodeReferenceElement referenceElement = PsiTreeUtil.getParentOfType(ref, PsiJavaCodeReferenceElement.class);
1327 if (referenceElement == null) return null;
1328 final PsiElement typeClass = referenceElement.resolve();
1329 if (!(typeClass instanceof PsiClass)) return null;
1330 final PsiElement resolve = ref.resolve();
1331 final PsiClass containingClass = resolve != null ? ((PsiClass)resolve).getContainingClass() : null;
1332 if (containingClass == null) return null;
1333 if (psiClass.isInheritor(containingClass, true) ||
1334 unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance((PsiClass)typeClass, ((PsiClass)resolve).getExtendsList()) ||
1335 unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance((PsiClass)typeClass, ((PsiClass)resolve).getImplementsList())) {
1336 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(((PsiClass)resolve).getName() + " is not accessible in current context").range(ref).create();
1344 private static boolean unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance(PsiClass containingClass,
1345 PsiReferenceList referenceList) {
1346 if (referenceList != null) {
1347 for (PsiJavaCodeReferenceElement referenceElement : referenceList.getReferenceElements()) {
1348 if (!referenceElement.isQualified()) {
1349 final PsiElement superClass = referenceElement.resolve();
1350 if (superClass instanceof PsiClass) {
1351 final PsiClass superContainingClass = ((PsiClass)superClass).getContainingClass();
1352 if (superContainingClass != null &&
1353 InheritanceUtil.isInheritorOrSelf(containingClass, superContainingClass, true) &&
1354 !PsiTreeUtil.isAncestor(superContainingClass, containingClass, true)) {
1364 private static void registerVariableParameterizedTypeFixes(@Nullable HighlightInfo highlightInfo,
1365 @NotNull PsiVariable variable,
1366 @NotNull PsiReferenceParameterList parameterList,
1367 @NotNull JavaSdkVersion version) {
1368 PsiType type = variable.getType();
1369 if (!(type instanceof PsiClassType) || highlightInfo == null) return;
1371 if (DumbService.getInstance(variable.getProject()).isDumb()) return;
1373 String shortName = ((PsiClassType)type).getClassName();
1374 PsiManager manager = parameterList.getManager();
1375 final JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject());
1376 PsiShortNamesCache shortNamesCache = PsiShortNamesCache.getInstance(parameterList.getProject());
1377 PsiClass[] classes = shortNamesCache.getClassesByName(shortName, GlobalSearchScope.allScope(manager.getProject()));
1378 PsiElementFactory factory = facade.getElementFactory();
1379 for (PsiClass aClass : classes) {
1380 if (checkReferenceTypeArgumentList(aClass, parameterList, PsiSubstitutor.EMPTY, false, version) == null) {
1381 PsiType[] actualTypeParameters = parameterList.getTypeArguments();
1382 PsiTypeParameter[] classTypeParameters = aClass.getTypeParameters();
1383 Map<PsiTypeParameter, PsiType> map = new java.util.HashMap<>();
1384 for (int j = 0; j < classTypeParameters.length; j++) {
1385 PsiTypeParameter classTypeParameter = classTypeParameters[j];
1386 PsiType actualTypeParameter = actualTypeParameters[j];
1387 map.put(classTypeParameter, actualTypeParameter);
1389 PsiSubstitutor substitutor = factory.createSubstitutor(map);
1390 PsiType suggestedType = factory.createType(aClass, substitutor);
1391 HighlightUtil.registerChangeVariableTypeFixes(variable, suggestedType, variable.getInitializer(), highlightInfo);
1396 static HighlightInfo checkInferredIntersections(PsiSubstitutor substitutor, TextRange ref) {
1397 for (Map.Entry<PsiTypeParameter, PsiType> typeEntry : substitutor.getSubstitutionMap().entrySet()) {
1398 final String parameterName = typeEntry.getKey().getName();
1399 final PsiType type = typeEntry.getValue();
1400 if (type instanceof PsiIntersectionType) {
1401 final String conflictingConjunctsMessage = ((PsiIntersectionType)type).getConflictingConjunctsMessage();
1402 if (conflictingConjunctsMessage != null) {
1403 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
1404 .descriptionAndTooltip("Type parameter " + parameterName + " has incompatible upper bounds: " + conflictingConjunctsMessage)
1405 .range(ref).create();
1412 static HighlightInfo areSupersAccessible(@NotNull PsiClass aClass) {
1413 return areSupersAccessible(aClass, aClass.getResolveScope(), HighlightNamesUtil.getClassDeclarationTextRange(aClass), true);
1416 static HighlightInfo areSupersAccessible(@NotNull PsiClass aClass, PsiReferenceExpression ref) {
1417 final GlobalSearchScope resolveScope = ref.getResolveScope();
1418 final HighlightInfo info = areSupersAccessible(aClass, resolveScope, ref.getTextRange(), false);
1423 String message = null;
1424 final PsiElement parent = ref.getParent();
1425 if (parent instanceof PsiMethodCallExpression) {
1426 final JavaResolveResult resolveResult = ((PsiMethodCallExpression)parent).resolveMethodGenerics();
1427 final PsiMethod method = (PsiMethod)resolveResult.getElement();
1428 if (method != null) {
1429 final HashSet<PsiClass> classes = new HashSet<>();
1430 final JavaPsiFacade facade = JavaPsiFacade.getInstance(aClass.getProject());
1431 final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
1433 message = isSuperTypeAccessible(substitutor.substitute(method.getReturnType()), classes, false, resolveScope, facade);
1434 if (message == null) {
1435 for (PsiType type : method.getSignature(substitutor).getParameterTypes()) {
1437 message = isSuperTypeAccessible(type, classes, false, resolveScope, facade);
1438 if (message != null) {
1446 final PsiElement resolve = ref.resolve();
1447 if (resolve instanceof PsiField) {
1448 message = isSuperTypeAccessible(((PsiField)resolve).getType(), new HashSet<>(), false, resolveScope, JavaPsiFacade.getInstance(aClass.getProject()));
1452 if (message != null) {
1453 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
1454 .descriptionAndTooltip(message)
1455 .range(ref.getTextRange())
1463 private static HighlightInfo areSupersAccessible(@NotNull PsiClass aClass,
1464 GlobalSearchScope resolveScope,
1466 boolean checkParameters) {
1467 final JavaPsiFacade factory = JavaPsiFacade.getInstance(aClass.getProject());
1468 for (PsiClassType superType : aClass.getSuperTypes()) {
1469 final String notAccessibleErrorMessage = isSuperTypeAccessible(superType, new HashSet<>(), checkParameters, resolveScope, factory);
1470 if (notAccessibleErrorMessage != null) {
1471 return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
1472 .descriptionAndTooltip(notAccessibleErrorMessage)
1481 private static String isSuperTypeAccessible(PsiType superType,
1482 HashSet<PsiClass> classes,
1483 boolean checkParameters,
1484 GlobalSearchScope resolveScope,
1485 JavaPsiFacade factory) {
1486 final PsiClass aClass = PsiUtil.resolveClassInType(superType);
1487 if (aClass != null && classes.add(aClass)) {
1488 VirtualFile vFile = PsiUtilCore.getVirtualFile(aClass);
1489 if (vFile == null) {
1492 FileIndexFacade index = FileIndexFacade.getInstance(aClass.getProject());
1493 if (!index.isInSource(vFile) && !index.isInLibraryClasses(vFile)) {
1497 final String qualifiedName = aClass.getQualifiedName();
1498 if (qualifiedName != null && factory.findClass(qualifiedName, resolveScope) == null) {
1499 return "Cannot access " + HighlightUtil.formatClass(aClass);
1502 if (checkParameters) {
1503 boolean isInLibrary = !index.isInContent(vFile);
1504 if (superType instanceof PsiClassType) {
1505 for (PsiType psiType : ((PsiClassType)superType).getParameters()) {
1506 final String notAccessibleMessage = isSuperTypeAccessible(psiType, classes, true, resolveScope, factory);
1507 if (notAccessibleMessage != null) {
1508 return notAccessibleMessage;
1513 for (PsiClassType type : aClass.getSuperTypes()) {
1514 final String notAccessibleMessage = isSuperTypeAccessible(type, classes, !isInLibrary, resolveScope, factory);
1515 if (notAccessibleMessage != null) {
1516 return notAccessibleMessage;
1524 static HighlightInfo checkTypeParameterOverrideEquivalentMethods(PsiClass aClass, LanguageLevel level) {
1525 if (aClass instanceof PsiTypeParameter && level.isAtLeast(LanguageLevel.JDK_1_7)) {
1526 final PsiReferenceList extendsList = aClass.getExtendsList();
1527 if (extendsList != null && extendsList.getReferenceElements().length > 1) {
1528 //todo suppress erased methods which come from the same class
1529 final Collection<HighlightInfo> result = checkOverrideEquivalentMethods(aClass);
1530 if (result != null && !result.isEmpty()) {
1531 return result.iterator().next();