diff --git a/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties b/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties index 43469abc4e28..01876e7f2117 100644 --- a/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties +++ b/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties @@ -128,6 +128,7 @@ class.generic.extends.exception=Generic class may not extend 'java.lang.Throwabl class.initializer.must.complete.normally=Initializer must be able to complete normally class.permitted.not.direct.subclass=Invalid permits clause: ''{0}'' must directly {1, choice, 1#extend|2#implement} ''{2}'' class.permitted.must.have.modifier=All sealed class subclasses must either be final, sealed or non-sealed +class.or.package.expected=Expected class or package class.implicit.no.main.method=Implicitly declared class contains no 'main' method class.implicit.invalid.file.name=The file name of an implicitly declared class is not a valid identifier diff --git a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ExpressionChecker.java b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ExpressionChecker.java index d4f5aef01dcc..f43472da1e78 100644 --- a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ExpressionChecker.java +++ b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ExpressionChecker.java @@ -871,6 +871,32 @@ final class ExpressionChecker { } } + void checkClassReferenceAfterQualifier(@NotNull PsiReferenceExpression expression, @Nullable PsiElement resolved) { + if (!(resolved instanceof PsiClass psiClass)) return; + PsiExpression qualifier = expression.getQualifierExpression(); + if (qualifier == null) return; + if (qualifier instanceof PsiReferenceExpression qExpression) { + PsiElement qualifierResolved = qExpression.resolve(); + if (qualifierResolved instanceof PsiClass || qualifierResolved instanceof PsiPackage) return; + + if (qualifierResolved == null) { + while (true) { + PsiElement qResolve = qExpression.resolve(); + if (qResolve == null || qResolve instanceof PsiClass || qResolve instanceof PsiPackage) { + PsiExpression qualifierExpression = qExpression.getQualifierExpression(); + if (qualifierExpression == null) return; + if (qualifierExpression instanceof PsiReferenceExpression ref) { + qExpression = ref; + continue; + } + } + break; + } + } + } + myVisitor.report(JavaErrorKinds.CLASS_OR_PACKAGE_EXPECTED.create(expression, psiClass)); + } + private static boolean hasYield(@NotNull PsiSwitchExpression switchExpression, @NotNull PsiElement scope) { class YieldFinder extends JavaRecursiveElementWalkingVisitor { private boolean hasYield; diff --git a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/JavaErrorVisitor.java b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/JavaErrorVisitor.java index a13bae049a3c..2267cda05cdc 100644 --- a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/JavaErrorVisitor.java +++ b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/JavaErrorVisitor.java @@ -475,11 +475,6 @@ final class JavaErrorVisitor extends JavaElementVisitor { if (!hasErrorResults()) { myClassChecker.checkClassDoesNotCallSuperConstructorOrHandleExceptions(aClass); } - //if (!hasErrorResults()) add(HighlightMethodUtil.checkOverrideEquivalentInheritedMethods(aClass, myFile, myLanguageLevel)); - if (!hasErrorResults()) { - //GenericsHighlightUtil.computeOverrideEquivalentMethodErrors(aClass, myOverrideEquivalentMethodsVisitedClasses, myOverrideEquivalentMethodsErrors); - //myErrorSink.accept(myOverrideEquivalentMethodsErrors.get(aClass)); - } if (!hasErrorResults()) myClassChecker.checkCyclicInheritance(aClass); if (!hasErrorResults()) myMethodChecker.checkOverrideEquivalentInheritedMethods(aClass); if (!hasErrorResults()) { @@ -828,6 +823,7 @@ final class JavaErrorVisitor extends JavaElementVisitor { } if (!hasErrorResults()) myGenericsChecker.checkAccessStaticFieldFromEnumConstructor(expression, result); myExpressionChecker.checkUnqualifiedSuperInDefaultMethod(expression, qualifierExpression); + if (!hasErrorResults()) myExpressionChecker.checkClassReferenceAfterQualifier(expression, resolved); if (!hasErrorResults() && resolved instanceof PsiModifierListOwner) checkPreviewFeature(expression); } diff --git a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/errors/JavaErrorKinds.java b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/errors/JavaErrorKinds.java index 14f6d4e52d31..f1c38c4c7329 100644 --- a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/errors/JavaErrorKinds.java +++ b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/errors/JavaErrorKinds.java @@ -430,6 +430,9 @@ public final class JavaErrorKinds { ctx.subClass().getName(), ctx.subClass().isInterface() == ctx.superClass().isInterface() ? 1 : 2, ctx.superClass().getName())); + public static final Parameterized CLASS_OR_PACKAGE_EXPECTED = + parameterized(PsiReferenceExpression.class, PsiClass.class, "class.or.package.expected") + .withAnchor(ref -> ref.getQualifierExpression()); public static final Simple VALUE_CLASS_EXTENDS_NON_ABSTRACT = error("value.class.extends.non.abstract"); diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index fafc67416d67..2f7fa172b280 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -525,55 +525,6 @@ public final class HighlightUtil { return ElementDescriptionUtil.getElementDescription(element, HighlightUsagesDescriptionLocation.INSTANCE); } - static HighlightInfo.Builder checkClassReferenceAfterQualifier(@NotNull PsiReferenceExpression expression, @Nullable PsiElement resolved) { - if (!(resolved instanceof PsiClass)) return null; - PsiExpression qualifier = expression.getQualifierExpression(); - if (qualifier == null) return null; - if (qualifier instanceof PsiReferenceExpression qExpression) { - PsiElement qualifierResolved = qExpression.resolve(); - if (qualifierResolved instanceof PsiClass || qualifierResolved instanceof PsiPackage) return null; - - if (qualifierResolved == null) { - while (true) { - PsiElement qResolve = qExpression.resolve(); - if (qResolve == null || qResolve instanceof PsiClass || qResolve instanceof PsiPackage) { - PsiExpression qualifierExpression = qExpression.getQualifierExpression(); - if (qualifierExpression == null) return null; - if (qualifierExpression instanceof PsiReferenceExpression) { - qExpression = (PsiReferenceExpression)qualifierExpression; - continue; - } - } - break; - } - } - } - String description = JavaErrorBundle.message("expected.class.or.package"); - HighlightInfo.Builder info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(qualifier).descriptionAndTooltip(description); - IntentionAction action = getFixFactory().createRemoveQualifierFix(qualifier, expression, (PsiClass)resolved); - info.registerFix(action, null, null, null, null); - return info; - } - - private static @NotNull LanguageLevel getApplicableLevel(@NotNull PsiFile file, @NotNull JavaFeature feature) { - LanguageLevel standardLevel = feature.getStandardLevel(); - LanguageLevel featureLevel = feature.getMinimumLevel(); - if (featureLevel.isPreview()) { - JavaSdkVersion sdkVersion = JavaSdkVersionUtil.getJavaSdkVersion(file); - if (sdkVersion != null) { - if (standardLevel != null && sdkVersion.isAtLeast(JavaSdkVersion.fromLanguageLevel(standardLevel))) { - return standardLevel; - } - LanguageLevel previewLevel = sdkVersion.getMaxLanguageLevel().getPreviewLevel(); - if (previewLevel != null && previewLevel.isAtLeast(featureLevel)) { - return previewLevel; - } - } - } - return featureLevel; - } - static @Nullable HighlightInfo.Builder checkFeature(@NotNull PsiElement element, @NotNull JavaFeature feature, @NotNull LanguageLevel level, diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index d62496685d70..4e443795ec7a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -246,13 +246,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!hasErrorResults()) add(ModuleHighlightUtil.checkModuleReference(statement)); } - private void doVisitReferenceElement(@NotNull PsiJavaCodeReferenceElement ref) { - JavaResolveResult result = resolveOptimised(ref, myFile); - if (result != null) { - add(HighlightUtil.checkReference(ref, result)); - } - } - static @Nullable JavaResolveResult resolveOptimised(@NotNull PsiJavaCodeReferenceElement ref, @NotNull PsiFile containingFile) { try { if (ref instanceof PsiReferenceExpressionImpl) { @@ -267,36 +260,18 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - private JavaResolveResult @Nullable [] resolveOptimised(@NotNull PsiReferenceExpression expression) { - try { - if (expression instanceof PsiReferenceExpressionImpl) { - PsiReferenceExpressionImpl.OurGenericsResolver resolver = PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE; - return JavaResolveUtil.resolveWithContainingFile(expression, resolver, true, true, myFile); - } - else { - return expression.multiResolve(true); - } - } - catch (IndexNotReadyException e) { - return null; - } - } - @Override public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) { - doVisitReferenceElement(expression); + JavaResolveResult result = resolveOptimised(expression, myFile); + if (result != null) { + add(HighlightUtil.checkReference(expression, result)); + } if (!hasErrorResults()) { visitElement(expression); if (hasErrorResults()) return; } - JavaResolveResult[] results = resolveOptimised(expression); - if (results == null) return; - JavaResolveResult result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY; - - PsiElement resolved = result.getElement(); - if (!hasErrorResults()) add(HighlightUtil.checkClassReferenceAfterQualifier(expression, resolved)); PsiExpression qualifierExpression = expression.getQualifierExpression(); if (!hasErrorResults() && myJavaModule == null && qualifierExpression != null) { add(GenericsHighlightUtil.checkMemberSignatureTypesAccessibility(expression)); @@ -386,7 +361,10 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh public void visitReferenceElement(@NotNull PsiJavaCodeReferenceElement ref) { super.visitReferenceElement(ref); if (!(ref instanceof PsiExpression)) { - doVisitReferenceElement(ref); + JavaResolveResult result = resolveOptimised(ref, myFile); + if (result != null) { + add(HighlightUtil.checkReference(ref, result)); + } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorFixProvider.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorFixProvider.java index 435bd621622a..7c549e4aaf5e 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorFixProvider.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorFixProvider.java @@ -658,6 +658,8 @@ final class JavaErrorFixProvider { }; fix(REFERENCE_MEMBER_BEFORE_CONSTRUCTOR, qualifyFix); fix(CALL_MEMBER_BEFORE_CONSTRUCTOR, qualifyFix); + fix(CLASS_OR_PACKAGE_EXPECTED, error -> myFactory.createRemoveQualifierFix( + requireNonNull(error.psi().getQualifierExpression()), error.psi(), error.context())); } private void createAccessFixes() {