diff --git a/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiMethodUtil.java b/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiMethodUtil.java index d984da5087b8..6e0e4b9b5266 100644 --- a/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiMethodUtil.java +++ b/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiMethodUtil.java @@ -67,13 +67,14 @@ public final class JavaPsiMethodUtil { } /** - * @param aClass a class to analyze + * @param aClass a class to analyze * @param overrideEquivalentSuperMethods collection of override-equivalent super methods + * @param skipSelf whether to ignore methods defined directly in aClass * @return an abstract method from the supplied collection that must be implemented, because an override-equivalent * default method is present, and the ambiguity must be resolved. */ public static @Nullable PsiMethod getAbstractMethodToImplementWhenDefaultPresent( - @NotNull PsiClass aClass, @NotNull Collection overrideEquivalentSuperMethods) { + @NotNull PsiClass aClass, @NotNull Collection overrideEquivalentSuperMethods, boolean skipSelf) { if (aClass.hasModifierProperty(PsiModifier.ABSTRACT) || aClass instanceof PsiTypeParameter) return null; if (overrideEquivalentSuperMethods.size() <= 1) return null; PsiMethod abstractMethod = null; @@ -90,6 +91,7 @@ public final class JavaPsiMethodUtil { } } if (abstractMethod == null || defaultMethod == null) return null; + if (!skipSelf && MethodSignatureUtil.findMethodBySuperMethod(aClass, defaultMethod, false) != null) return null; PsiClass abstractMethodContainingClass = abstractMethod.getContainingClass(); if (abstractMethodContainingClass == null || !abstractMethodContainingClass.isInterface()) return null; PsiClass defaultMethodContainingClass = defaultMethod.getContainingClass(); diff --git a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/MethodChecker.java b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/MethodChecker.java index ab9880651d3f..3a0f51680f04 100644 --- a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/MethodChecker.java +++ b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/MethodChecker.java @@ -556,7 +556,7 @@ final class MethodChecker { Map> overrideEquivalent = PsiSuperMethodUtil.collectOverrideEquivalents(aClass); for (Set overrideEquivalentMethods : overrideEquivalent.values()) { - PsiMethod abstractMethod = JavaPsiMethodUtil.getAbstractMethodToImplementWhenDefaultPresent(aClass, overrideEquivalentMethods); + PsiMethod abstractMethod = JavaPsiMethodUtil.getAbstractMethodToImplementWhenDefaultPresent(aClass, overrideEquivalentMethods, false); if (abstractMethod != null) { PsiMethod anyAbstractMethod = ClassUtil.getAnyAbstractMethod(aClass); if (anyAbstractMethod != null) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java index 466e05e6645f..d0db02bd9bf3 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java @@ -782,7 +782,7 @@ public final class RefJavaUtilImpl extends RefJavaUtil { private static boolean hasUnrelatedDefaults(@NotNull PsiClass aClass, @NotNull Collection overrideEquivalentSuperMethods) { - return JavaPsiMethodUtil.getAbstractMethodToImplementWhenDefaultPresent(aClass, overrideEquivalentSuperMethods) != null || + return JavaPsiMethodUtil.getAbstractMethodToImplementWhenDefaultPresent(aClass, overrideEquivalentSuperMethods, true) != null || JavaPsiMethodUtil.getUnrelatedSuperMethods(aClass, overrideEquivalentSuperMethods) != null; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting21/MyCNMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting21/MyCNMap.java new file mode 100644 index 000000000000..1be9509235a5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting21/MyCNMap.java @@ -0,0 +1,111 @@ +import java.util.*; +import java.util.concurrent.ConcurrentNavigableMap; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class MyCNMap extends AbstractMap + implements ConcurrentNavigableMap { + public MyCNMap clone() { + throw new InternalError(); + } + + public native boolean containsKey(Object key); + + public native V get(Object key); + + public native V getOrDefault(Object key, V defaultValue); + + public native V put(K key, V value); + + public native V remove(Object key); + + public native boolean containsValue(Object value); + + public native int size(); + + public native boolean isEmpty(); + + public native void clear(); + + public native V computeIfAbsent(K key, Function mappingFunction); + + public native V computeIfPresent(K key, BiFunction remappingFunction); + + public native V compute(K key, BiFunction remappingFunction); + + public native V merge(K key, V value, BiFunction remappingFunction); + + public native NavigableSet keySet(); + + public native NavigableSet navigableKeySet(); + + public native Collection values(); + + public native Set> entrySet(); + + public native ConcurrentNavigableMap descendingMap(); + + public native NavigableSet descendingKeySet(); + + public native V putIfAbsent(K key, V value); + + public native boolean remove(Object key, Object value); + + public native boolean replace(K key, V oldValue, V newValue); + + public native V replace(K key, V value); + + public native Comparator comparator(); + + public native K firstKey(); + + public native K lastKey(); + + public native V putFirst(K k, V v); + + public native V putLast(K k, V v); + + public native ConcurrentNavigableMap subMap(K fromKey, + boolean fromInclusive, + K toKey, + boolean toInclusive); + + public native ConcurrentNavigableMap headMap(K toKey, boolean inclusive); + + public native ConcurrentNavigableMap tailMap(K fromKey, boolean inclusive); + + public native ConcurrentNavigableMap subMap(K fromKey, K toKey); + + public native ConcurrentNavigableMap headMap(K toKey); + + public native ConcurrentNavigableMap tailMap(K fromKey); + + public native Map.Entry lowerEntry(K key); + + public native K lowerKey(K key); + + public native Map.Entry floorEntry(K key); + + public native K floorKey(K key); + + public native Map.Entry ceilingEntry(K key); + + public native K ceilingKey(K key); + + public native Map.Entry higherEntry(K key); + + public native K higherKey(K key); + + public native Map.Entry firstEntry(); + + public native Map.Entry lastEntry(); + + public native Map.Entry pollFirstEntry(); + + public native Map.Entry pollLastEntry(); + + public native void forEach(BiConsumer action); + + public native void replaceAll(BiFunction function); +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightJava21HighlightingTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightJava21HighlightingTest.java new file mode 100644 index 000000000000..ec0df8142671 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightJava21HighlightingTest.java @@ -0,0 +1,28 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.java.codeInsight.daemon; + +import com.intellij.JavaTestUtil; +import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; +import org.jetbrains.annotations.NotNull; + +public final class LightJava21HighlightingTest extends LightJavaCodeInsightFixtureTestCase { + @Override + protected @NotNull LightProjectDescriptor getProjectDescriptor() { + return JAVA_21; + } + + @Override + public String getBasePath() { + return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/daemonCodeAnalyzer/advHighlighting21"; + } + + public void testMyCNMap() { + doTest(); + } + + private void doTest() { + myFixture.configureByFile(getTestName(false) + ".java"); + myFixture.checkHighlighting(); + } +}