From 01bc97b6cc808ad49c716ff1ad8746fed7727ef6 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Wed, 29 Jan 2025 12:47:55 +0100 Subject: [PATCH] [java-highlighting] checkAmbiguousMethodCallIdentifier -> ExpressionChecker Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only) GitOrigin-RevId: 0edb80ae452250e0d12ff987aa5701b048dc91cb --- .../JavaCompilationErrorBundle.properties | 4 + .../highlighting/ExpressionChecker.java | 63 +++++++ .../highlighting/JavaErrorVisitor.java | 1 + .../highlighting/errors/JavaErrorKinds.java | 28 +++- .../impl/analysis/HighlightFixUtil.java | 2 + .../impl/analysis/HighlightMethodUtil.java | 154 ------------------ .../impl/analysis/HighlightVisitorImpl.java | 43 +---- .../impl/analysis/JavaErrorFixProvider.java | 17 +- .../interfaceMethods/ExtensionMethods.java | 2 +- ...ticCallOnChildWithNotAccessibleParent.java | 2 +- 10 files changed, 117 insertions(+), 199 deletions(-) diff --git a/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties b/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties index 23f06f2e44b7..db68c475bbe3 100644 --- a/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties +++ b/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties @@ -242,6 +242,7 @@ reference.qualifier.primitive=Cannot access fields on ''{0}'' type reference.unresolved=Cannot resolve symbol ''{0}'' reference.ambiguous=Reference to ''{0}'' is ambiguous, both ''{1}'' and ''{2}'' match reference.implicit.class=Implicitly declared class ''{0}'' cannot be referenced +reference.non.static.from.static.context=Non-static {0} ''{1}'' cannot be referenced from a static context statement.case.outside.switch=Case statement outside switch statement.invalid=Invalid statement @@ -296,6 +297,9 @@ call.constructor.duplicate=Only one explicit constructor call allowed in constru call.constructor.record.in.canonical=Canonical constructor cannot delegate to another constructor call.constructor.recursive=Recursive constructor call call.unresolved=Cannot resolve method ''{0}'' +call.unresolved.name=Cannot resolve method ''{0}'' +call.qualifier.primitive=Cannot call methods on ''{0}'' type +call.ambiguous.no.match=Cannot resolve method ''{0}'' in ''{1}'' call.ambiguous=Ambiguous method call: both ''{0}'' and ''{1}'' match # {0} - colspan, {1} - method1, {2} - class1, {3} - method2, {4} - class2 call.ambiguous.tooltip=\ 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 c500c1054604..25d26bfdee6f 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 @@ -16,6 +16,7 @@ import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.search.searches.ImplicitClassSearch; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.*; +import com.intellij.refactoring.util.RefactoringChangeUtil; import com.intellij.util.JavaPsiConstructorUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.ThreeState; @@ -26,6 +27,7 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import static com.intellij.util.ObjectUtils.tryCast; +import static java.util.Objects.*; final class ExpressionChecker { private final @NotNull JavaErrorVisitor myVisitor; @@ -1150,6 +1152,67 @@ final class ExpressionChecker { } } + void checkAmbiguousMethodCallIdentifier(JavaResolveResult @NotNull [] resolveResults, + @NotNull JavaResolveResult resolveResult, + @NotNull PsiMethodCallExpression methodCall) { + PsiReferenceExpression referenceToMethod = methodCall.getMethodExpression(); + PsiElement element = resolveResult.getElement(); + MethodCandidateInfo methodCandidate2 = findCandidates(resolveResults).second; + if (methodCandidate2 != null) return; + + PsiElement anchor = requireNonNullElse(referenceToMethod.getReferenceNameElement(), referenceToMethod); + if (element instanceof PsiModifierListOwner owner && !resolveResult.isAccessible()) { + myVisitor.myModifierChecker.reportAccessProblem(referenceToMethod, owner, resolveResult); + } + else if (element != null && !resolveResult.isStaticsScopeCorrect()) { + if (element instanceof PsiMethod psiMethod && psiMethod.hasModifierProperty(PsiModifier.STATIC)) { + PsiClass containingClass = psiMethod.getContainingClass(); + if (containingClass != null && containingClass.isInterface()) { + myVisitor.checkFeature(anchor, JavaFeature.STATIC_INTERFACE_CALLS); + if (myVisitor.hasErrorResults()) return; + checkStaticInterfaceCallQualifier(referenceToMethod, resolveResult, containingClass); + if (myVisitor.hasErrorResults()) return; + } + } + myVisitor.report(JavaErrorKinds.REFERENCE_NON_STATIC_FROM_STATIC_CONTEXT.create(referenceToMethod, element)); + } + else if (!ContainerUtil.exists(resolveResults, result -> result instanceof MethodCandidateInfo && result.isAccessible())) { + PsiClass qualifierClass = RefactoringChangeUtil.getQualifierClass(referenceToMethod); + String className = qualifierClass != null ? qualifierClass.getName() : null; + PsiExpression qualifierExpression = referenceToMethod.getQualifierExpression(); + + if (className != null) { + if (IncompleteModelUtil.isIncompleteModel(myVisitor.file()) && + IncompleteModelUtil.canBePendingReference(referenceToMethod)) { + myVisitor.report(JavaErrorKinds.REFERENCE_PENDING.create(anchor)); + return; + } + myVisitor.report(JavaErrorKinds.CALL_AMBIGUOUS_NO_MATCH.create(methodCall, resolveResults)); + } + else if (qualifierExpression != null && + qualifierExpression.getType() instanceof PsiPrimitiveType primitiveType && + !primitiveType.equals(PsiTypes.nullType())) { + if (PsiTypes.voidType().equals(primitiveType) && + PsiUtil.deparenthesizeExpression(qualifierExpression) instanceof PsiReferenceExpression) { + return; + } + myVisitor.report(JavaErrorKinds.CALL_QUALIFIER_PRIMITIVE.create(methodCall, primitiveType)); + } + else { + if (qualifierExpression != null) { + PsiType type = qualifierExpression.getType(); + if (type instanceof PsiClassType t && t.resolve() == null || PsiTypes.nullType().equals(type)) return; + } + if (IncompleteModelUtil.isIncompleteModel(myVisitor.file()) && IncompleteModelUtil.canBePendingReference(referenceToMethod)) { + myVisitor.report(JavaErrorKinds.REFERENCE_PENDING.create(anchor)); + return; + } + myVisitor.report(JavaErrorKinds.CALL_UNRESOLVED_NAME.create(methodCall, resolveResults)); + } + } + } + + void checkRestrictedIdentifierReference(@NotNull PsiJavaCodeReferenceElement ref, @NotNull PsiClass resolved) { String name = resolved.getName(); if (PsiTypesUtil.isRestrictedIdentifier(name, myVisitor.languageLevel())) { 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 72ff55fde320..101f69e22e02 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 @@ -619,6 +619,7 @@ final class JavaErrorVisitor extends JavaElementVisitor { (!result.isAccessible() || !result.isStaticsScopeCorrect())) { PsiExpressionList list = methodCallExpression.getArgumentList(); if (!myExpressionChecker.isDummyConstructorCall(methodCallExpression, list, expression)) { + myExpressionChecker.checkAmbiguousMethodCallIdentifier(results, result, methodCallExpression); if (!PsiTreeUtil.findChildrenOfType(methodCallExpression.getArgumentList(), PsiLambdaExpression.class).isEmpty()) { PsiElement nameElement = expression.getReferenceNameElement(); if (nameElement != null) { 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 39b302572b1e..21003964f7e5 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 @@ -2,6 +2,7 @@ package com.intellij.java.codeserver.highlighting.errors; import com.intellij.codeInsight.AnnotationTargetUtil; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightMessageUtil; import com.intellij.core.JavaPsiBundle; import com.intellij.java.codeserver.highlighting.JavaCompilationErrorBundle; import com.intellij.java.codeserver.highlighting.errors.JavaErrorKind.Parameterized; @@ -13,6 +14,7 @@ import com.intellij.pom.java.JavaFeature; import com.intellij.psi.*; import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.*; +import com.intellij.refactoring.util.RefactoringChangeUtil; import com.intellij.util.VisibilityUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -811,6 +813,15 @@ public final class JavaErrorKinds { .withRawDescription((ref, results) -> message("reference.ambiguous", ref.getReferenceName(), format(requireNonNull(results.get(0).getElement())), format(requireNonNull(results.get(1).getElement())))); + public static final Parameterized REFERENCE_NON_STATIC_FROM_STATIC_CONTEXT = + parameterized(PsiJavaCodeReferenceElement.class, PsiElement.class, "reference.non.static.from.static.context") + .withHighlightType((ref, refElement) -> JavaErrorHighlightType.WRONG_REF) + .withAnchor((ref, refElement) -> requireNonNullElse(ref.getReferenceNameElement(), ref)) + .withRawDescription((ref, refElement) -> { + String type = JavaElementKind.fromElement(refElement).lessDescriptive().subject(); + String name = HighlightMessageUtil.getSymbolName(refElement, PsiSubstitutor.EMPTY); + return message("reference.non.static.from.static.context", type, name); + }); public static final Simple STATEMENT_CASE_OUTSIDE_SWITCH = error("statement.case.outside.switch"); public static final Simple STATEMENT_INVALID = error("statement.invalid"); @@ -886,12 +897,27 @@ public final class JavaErrorKinds { .withAnchor((call, results) -> call.getArgumentList()) .withRawDescription((call, results) -> message( "call.unresolved", call.getMethodExpression().getReferenceName() + formatArgumentTypes(call.getArgumentList(), true))); + public static final Parameterized CALL_UNRESOLVED_NAME = + parameterized(PsiMethodCallExpression.class, JavaResolveResult[].class, "call.unresolved.name") + .withRange((call, cls) -> getRange(call)) + .withRawDescription((call, results) -> message( + "call.unresolved.name", call.getMethodExpression().getReferenceName() + formatArgumentTypes(call.getArgumentList(), true))); public static final Parameterized CALL_AMBIGUOUS = parameterized(PsiMethodCallExpression.class, JavaAmbiguousCallContext.class, "call.ambiguous") .withAnchor((call, ctx) -> call.getArgumentList()) .withRawDescription((call, ctx) -> ctx.description()) .withTooltip((call, ctx) -> ctx.tooltip()); - + public static final Parameterized CALL_AMBIGUOUS_NO_MATCH = + parameterized(PsiMethodCallExpression.class, JavaResolveResult[].class, "call.ambiguous.no.match") + .withRange((call, cls) -> getRange(call)) + .withRawDescription( + (call, cls) -> message("call.ambiguous.no.match", call.getMethodExpression().getReferenceName(), + requireNonNull(RefactoringChangeUtil.getQualifierClass(call.getMethodExpression())).getName())); + public static final Parameterized CALL_QUALIFIER_PRIMITIVE = + parameterized(PsiMethodCallExpression.class, PsiPrimitiveType.class, "call.qualifier.primitive") + .withHighlightType((ref, type) -> JavaErrorHighlightType.WRONG_REF) + .withRange((call, type) -> getRange(call)) + .withRawDescription((call, type) -> message("call.qualifier.primitive", type.getPresentableText())); public static final Parameterized CALL_DIRECT_ABSTRACT_METHOD_ACCESS = parameterized(PsiMethodCallExpression.class, PsiMethod.class, "call.direct.abstract.method.access") diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightFixUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightFixUtil.java index 47ce6ecc57e5..ad00167b4c73 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightFixUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightFixUtil.java @@ -510,6 +510,7 @@ public final class HighlightFixUtil { registerUsageFixes(methodCall, info); RemoveRedundantArgumentsFix.registerIntentions(methodCandidates, list, info); + info.accept(RemoveRepeatingCallFix.createFix(methodCall)); registerChangeParameterClassFix(methodCall, list, info); } @@ -797,6 +798,7 @@ public final class HighlightFixUtil { WrapExpressionFix.registerWrapAction(candidates, list.getExpressions(), sink); PermuteArgumentsFix.registerFix(sink, methodCall, candidates); registerChangeParameterClassFix(methodCall, list, sink); + registerMethodCallIntentions(sink, methodCall, list); } private static final class ReturnModel { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index adb5523b9ea0..c88bf99d5f88 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -5,27 +5,19 @@ import com.intellij.codeInsight.ExceptionUtil; import com.intellij.codeInsight.daemon.JavaErrorBundle; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; -import com.intellij.codeInsight.daemon.impl.quickfix.*; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.QuickFixFactory; -import com.intellij.codeInsight.quickfix.LazyQuickFixUpdater; -import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider; import com.intellij.codeInspection.LocalQuickFixOnPsiElementAsIntentionAdapter; import com.intellij.core.JavaPsiBundle; import com.intellij.openapi.util.NlsContexts; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.pom.java.JavaFeature; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; -import com.intellij.psi.impl.IncompleteModelUtil; import com.intellij.psi.impl.light.LightRecordMethod; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; -import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.util.*; -import com.intellij.refactoring.util.RefactoringChangeUtil; -import com.intellij.util.ObjectUtils; import com.intellij.xml.util.XmlStringUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -281,139 +273,6 @@ public final class HighlightMethodUtil { return JavaErrorBundle.message("static.interface.method.call.qualifier"); } - static boolean isDummyConstructorCall(@NotNull PsiMethodCallExpression methodCall, - @NotNull PsiResolveHelper resolveHelper, - @NotNull PsiExpressionList list, - @NotNull PsiReferenceExpression referenceToMethod) { - boolean isDummy = false; - boolean isThisOrSuper = referenceToMethod.getReferenceNameElement() instanceof PsiKeyword; - if (isThisOrSuper) { - // super(..) or this(..) - if (list.isEmpty()) { // implicit ctr call - CandidateInfo[] candidates = resolveHelper.getReferencedMethodCandidates(methodCall, true); - if (candidates.length == 1 && !candidates[0].getElement().isPhysical()) { - isDummy = true;// dummy constructor - } - } - } - return isDummy; - } - - static HighlightInfo.Builder checkAmbiguousMethodCallIdentifier(@NotNull PsiReferenceExpression referenceToMethod, - JavaResolveResult @NotNull [] resolveResults, - @NotNull PsiExpressionList list, - @Nullable PsiElement element, - @NotNull JavaResolveResult resolveResult, - @NotNull PsiMethodCallExpression methodCall, - @NotNull LanguageLevel languageLevel, - @NotNull PsiFile file) { - MethodCandidateInfo methodCandidate2 = findCandidates(resolveResults).second; - if (methodCandidate2 != null) return null; - MethodCandidateInfo[] candidates = HighlightFixUtil.toMethodCandidates(resolveResults); - - HighlightInfoType highlightInfoType = HighlightInfoType.ERROR; - String description; - PsiElement elementToHighlight = ObjectUtils.notNull(referenceToMethod.getReferenceNameElement(), referenceToMethod); - if (element != null && !resolveResult.isAccessible()) { - description = HighlightUtil.accessProblemDescription(referenceToMethod, element, resolveResult); - } - else if (element != null && !resolveResult.isStaticsScopeCorrect()) { - if (element instanceof PsiMethod psiMethod && psiMethod.hasModifierProperty(PsiModifier.STATIC)) { - PsiClass containingClass = psiMethod.getContainingClass(); - if (containingClass != null && containingClass.isInterface()) { - HighlightInfo.Builder info = HighlightUtil.checkFeature(elementToHighlight, JavaFeature.STATIC_INTERFACE_CALLS, languageLevel, file); - if (info != null) return info; - info = checkStaticInterfaceCallQualifier(referenceToMethod, resolveResult, elementToHighlight, containingClass); - if (info != null) return info; - } - } - - description = HighlightUtil.staticContextProblemDescription(element); - } - else if (candidates.length == 0) { - PsiClass qualifierClass = RefactoringChangeUtil.getQualifierClass(referenceToMethod); - String className = qualifierClass != null ? qualifierClass.getName() : null; - PsiExpression qualifierExpression = referenceToMethod.getQualifierExpression(); - - if (className != null) { - if (IncompleteModelUtil.isIncompleteModel(file) && - IncompleteModelUtil.canBePendingReference(referenceToMethod)) { - return HighlightUtil.getPendingReferenceHighlightInfo(elementToHighlight); - } - description = JavaErrorBundle.message("ambiguous.method.call.no.match", referenceToMethod.getReferenceName(), className); - } - else if (qualifierExpression != null && - qualifierExpression.getType() instanceof PsiPrimitiveType primitiveType && - !primitiveType.equals(PsiTypes.nullType())) { - if (PsiTypes.voidType().equals(primitiveType) && - PsiUtil.deparenthesizeExpression(qualifierExpression) instanceof PsiReferenceExpression) { - return null; - } - description = JavaErrorBundle.message("cannot.call.method.on.type", primitiveType.getPresentableText(false)); - } - else { - if (qualifierExpression != null) { - PsiType type = qualifierExpression.getType(); - if (type instanceof PsiClassType t && t.resolve() == null || PsiTypes.nullType().equals(type)) { - return null; - } - } - if (IncompleteModelUtil.isIncompleteModel(file) && IncompleteModelUtil.canBePendingReference(referenceToMethod)) { - return HighlightUtil.getPendingReferenceHighlightInfo(elementToHighlight); - } - description = - JavaErrorBundle.message("cannot.resolve.method", referenceToMethod.getReferenceName() + buildArgTypesList(list, true)); - } - highlightInfoType = HighlightInfoType.WRONG_REF; - } - else { - return null; - } - - String toolTip = XmlStringUtil.escapeString(description); - HighlightInfo.Builder builder = - HighlightInfo.newHighlightInfo(highlightInfoType).range(elementToHighlight).description(description).escapedToolTip(toolTip); - if (element != null && !resolveResult.isStaticsScopeCorrect()) { - HighlightFixUtil.registerStaticProblemQuickFixAction(asConsumer(builder), element, referenceToMethod); - } - HighlightFixUtil.registerMethodCallIntentions(asConsumer(builder), methodCall, list); - - TextRange fixRange = getFixRange(elementToHighlight); - CastMethodArgumentFix.REGISTRAR.registerCastActions(candidates, methodCall, asConsumer(builder)); - WrapWithAdapterMethodCallFix.registerCastActions(candidates, methodCall, asConsumer(builder)); - WrapObjectWithOptionalOfNullableFix.REGISTAR.registerCastActions(candidates, methodCall, asConsumer(builder)); - WrapExpressionFix.registerWrapAction(candidates, list.getExpressions(), asConsumer(builder)); - PermuteArgumentsFix.registerFix(asConsumer(builder), methodCall, candidates); - var action = RemoveRepeatingCallFix.createFix(methodCall); - if (action != null) { - builder.registerFix(action, null, null, fixRange, null); - } - HighlightFixUtil.registerChangeParameterClassFix(methodCall, list, asConsumer(builder)); - if (candidates.length == 0) { - PsiReference ref = methodCall.getMethodExpression(); - UnresolvedReferenceQuickFixProvider.registerUnresolvedReferenceLazyQuickFixes(ref, builder); - } - return builder; - } - - private static @NotNull Pair findCandidates(JavaResolveResult @NotNull [] resolveResults) { - MethodCandidateInfo methodCandidate1 = null; - MethodCandidateInfo methodCandidate2 = null; - for (JavaResolveResult result : resolveResults) { - if (!(result instanceof MethodCandidateInfo candidate)) continue; - if (candidate.isApplicable() && !candidate.getElement().isConstructor()) { - if (methodCandidate1 == null) { - methodCandidate1 = candidate; - } - else { - methodCandidate2 = candidate; - break; - } - } - } - return Pair.pair(methodCandidate1, methodCandidate2); - } - static HighlightInfo.Builder checkAbstractMethodInConcreteClass(@NotNull PsiMethod method, @NotNull PsiElement elementToHighlight) { HighlightInfo.Builder errorResult = null; PsiClass aClass = method.getContainingClass(); @@ -473,19 +332,6 @@ public final class HighlightMethodUtil { return range; } - private static @NotNull String buildArgTypesList(@NotNull PsiExpressionList list, boolean shortNames) { - StringBuilder builder = new StringBuilder(); - builder.append("("); - PsiExpression[] args = list.getExpressions(); - for (int i = 0; i < args.length; i++) { - if (i > 0) builder.append(", "); - PsiType argType = args[i].getType(); - builder.append(argType != null ? (shortNames ? argType.getPresentableText() : JavaHighlightUtil.formatType(argType)) : "?"); - } - builder.append(")"); - return builder.toString(); - } - static boolean hasSurroundingInferenceError(@NotNull PsiElement context) { PsiCall topCall = LambdaUtil.treeWalkUp(context); if (topCall == null) return false; 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 225a56100bf1..596d9051ab32 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 @@ -16,7 +16,6 @@ import com.intellij.core.JavaPsiBundle; import com.intellij.java.codeserver.highlighting.JavaErrorCollector; import com.intellij.java.codeserver.highlighting.errors.JavaCompilationError; import com.intellij.java.codeserver.highlighting.errors.JavaErrorHighlightType; -import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.lang.jvm.JvmModifier; @@ -62,6 +61,7 @@ import java.util.*; import java.util.function.Consumer; import java.util.function.Function; +import static com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds.*; import static com.intellij.psi.PsiModifier.SEALED; import static com.intellij.util.ObjectUtils.tryCast; import static java.util.Objects.*; @@ -99,11 +99,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh private final Map myInsideConstructorOfClassCache = new HashMap<>(); // null value means "cached but no corresponding ctr found" private boolean myHasError; // true if myHolder.add() was called with HighlightInfo of >=ERROR severity. On each .visit(PsiElement) call this flag is reset. Useful to determine whether the error was already reported while visiting this PsiElement. - @Contract(pure = true) - private @NotNull PsiResolveHelper getResolveHelper() { - return PsiResolveHelper.getInstance(getProject()); - } - protected HighlightVisitorImpl() { } @@ -138,7 +133,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } /** - * @deprecated use {@link #HighlightVisitorImpl()} and {@link #getResolveHelper()} + * @deprecated use {@link #HighlightVisitorImpl()} */ @Deprecated(forRemoval = true) protected HighlightVisitorImpl(@NotNull PsiResolveHelper psiResolveHelper) { @@ -251,8 +246,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh info.range(anchor); } errorFixProvider.processFixes(error, fix -> info.registerFix(fix.asIntention(), null, null, null, null)); - error.psiForKind(JavaErrorKinds.EXPRESSION_EXPECTED, JavaErrorKinds.REFERENCE_UNRESOLVED, JavaErrorKinds.REFERENCE_AMBIGUOUS) - .or(() -> error.psiForKind(JavaErrorKinds.TYPE_UNKNOWN_CLASS).map(PsiTypeElement::getInnermostComponentReferenceElement)) + error.psiForKind(EXPRESSION_EXPECTED, REFERENCE_UNRESOLVED, REFERENCE_AMBIGUOUS) + .or(() -> error.psiForKind(TYPE_UNKNOWN_CLASS).map(PsiTypeElement::getInnermostComponentReferenceElement)) + .or(() -> error.psiForKind(CALL_AMBIGUOUS_NO_MATCH, CALL_UNRESOLVED).map(PsiMethodCallExpression::getMethodExpression)) .ifPresent(ref -> UnresolvedReferenceQuickFixProvider.registerUnresolvedReferenceLazyQuickFixes(ref, info)); add(info); } @@ -752,7 +748,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh @Override public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) { - JavaResolveResult resultForIncompleteCode = doVisitReferenceElement(expression); + doVisitReferenceElement(expression); if (!hasErrorResults()) { visitExpression(expression); @@ -780,22 +776,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - PsiElement parent = expression.getParent(); - if (parent instanceof PsiMethodCallExpression methodCallExpression && - methodCallExpression.getMethodExpression() == expression && - (!result.isAccessible() || !result.isStaticsScopeCorrect())) { - PsiExpressionList list = methodCallExpression.getArgumentList(); - PsiResolveHelper resolveHelper = getResolveHelper(); - if (!HighlightMethodUtil.isDummyConstructorCall(methodCallExpression, resolveHelper, list, expression)) { - try { - add(HighlightMethodUtil.checkAmbiguousMethodCallIdentifier( - expression, results, list, resolved, result, methodCallExpression, myLanguageLevel, myFile)); - } - catch (IndexNotReadyException ignored) { - } - } - } - if (!hasErrorResults()) add(GenericsHighlightUtil.checkAccessStaticFieldFromEnumConstructor(expression, result)); if (!hasErrorResults()) add(HighlightUtil.checkClassReferenceAfterQualifier(expression, resolved)); PsiExpression qualifierExpression = expression.getQualifierExpression(); @@ -1177,17 +1157,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - @Override - public void visitDefaultCaseLabelElement(@NotNull PsiDefaultCaseLabelElement element) { - super.visitDefaultCaseLabelElement(element); - // "case default:" will be highlighted as "The label for the default case must only use the 'default' keyword, without 'case'". - // see SwitchBlockHighlightingModel#checkSwitchLabelValues - // The "case default:" syntax was only allowed in outdated preview versions of Java (from Java 17 Preview to Java 19 Preview). - // And even if the "case default" syntax was allowed not only in outdated preview versions of Java, using "case default:" - // instead of "default:" looks weird. Therefore, for this case, we do not check the feature availability and do not - // suggest increasing the language level. - } - @Override public void visitPatternVariable(@NotNull PsiPatternVariable variable) { super.visitPatternVariable(variable); 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 5293bd88faba..0227d5ad39bc 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 @@ -405,14 +405,21 @@ final class JavaErrorFixProvider { } } }); - fixes(CALL_AMBIGUOUS, (error, sink) -> { - PsiMethodCallExpression methodCall = error.psi(); - JavaResolveResult[] resolveResults = error.context().results(); - HighlightFixUtil.registerAmbiguousCallFixes(sink, methodCall, resolveResults); + fixes(CALL_UNRESOLVED_NAME, + (error, sink) -> HighlightFixUtil.registerMethodCallIntentions(sink, error.psi(), error.psi().getArgumentList())); + fix(CALL_QUALIFIER_PRIMITIVE, error -> myFactory.createRenameWrongRefFix(error.psi().getMethodExpression())); + fixes(CALL_QUALIFIER_PRIMITIVE, + (error, sink) -> HighlightFixUtil.registerMethodCallIntentions(sink, error.psi(), error.psi().getArgumentList())); + fixes(CALL_AMBIGUOUS, (error, sink) -> HighlightFixUtil.registerAmbiguousCallFixes(sink, error.psi(), error.context().results())); + fixes(CALL_AMBIGUOUS_NO_MATCH, (error, sink) -> HighlightFixUtil.registerAmbiguousCallFixes(sink, error.psi(), error.context())); + fixes(REFERENCE_NON_STATIC_FROM_STATIC_CONTEXT, (error, sink) -> { + HighlightFixUtil.registerStaticProblemQuickFixAction(sink, error.context(), error.psi()); + if (error.psi().getParent() instanceof PsiMethodCallExpression methodCall) { + HighlightFixUtil.registerMethodCallIntentions(sink, methodCall, methodCall.getArgumentList()); + } }); fixes(CALL_UNRESOLVED, (error, sink) -> { PsiMethodCallExpression methodCall = error.psi(); - HighlightFixUtil.registerMethodCallIntentions(sink, methodCall, methodCall.getArgumentList()); JavaResolveResult[] resolveResults = error.context(); if (resolveResults.length == 1) { PsiElement element = resolveResults[0].getElement(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/interfaceMethods/ExtensionMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/interfaceMethods/ExtensionMethods.java index 5d5d09ddf30a..e9d924a6a742 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/interfaceMethods/ExtensionMethods.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/interfaceMethods/ExtensionMethods.java @@ -23,7 +23,7 @@ class C { interface II extends I { default void m() { I.super.m(); - super.m(); + super.m(); System.out.println(I.super.i); System.out.println(super.i); diff --git a/java/java-tests/testData/codeInsight/multipleJdks/java3/p/StaticCallOnChildWithNotAccessibleParent.java b/java/java-tests/testData/codeInsight/multipleJdks/java3/p/StaticCallOnChildWithNotAccessibleParent.java index 5384f853cea8..e4b787e24f1f 100644 --- a/java/java-tests/testData/codeInsight/multipleJdks/java3/p/StaticCallOnChildWithNotAccessibleParent.java +++ b/java/java-tests/testData/codeInsight/multipleJdks/java3/p/StaticCallOnChildWithNotAccessibleParent.java @@ -4,7 +4,7 @@ import static p.ChildClass.*; class Sample { public static void main(String[] args) { - ChildClass.foo(); + ChildClass.foo(); foo(); ChildClass cc = ChildClass2.childClass(); }