Java: better error message on duplicate reference in extends/implements list (IDEA-354856)

GitOrigin-RevId: 0ba4eed5966c273f94552d7fe623a69bb6eb6c95
This commit is contained in:
Bas Leijdekkers
2024-06-12 17:48:52 +02:00
committed by intellij-monorepo-bot
parent 0715321e22
commit 3b9377a54b
5 changed files with 21 additions and 22 deletions

View File

@@ -734,29 +734,27 @@ public final class HighlightClassUtil {
return null;
}
static HighlightInfo.Builder checkExtendsDuplicate(@NotNull PsiJavaCodeReferenceElement element, @Nullable PsiElement resolved, @NotNull PsiFile containingFile) {
static HighlightInfo.Builder checkExtendsDuplicate(@NotNull PsiJavaCodeReferenceElement element,
@Nullable PsiElement resolved,
@NotNull PsiFile containingFile) {
if (!(element.getParent() instanceof PsiReferenceList list)) return null;
if (!(list.getParent() instanceof PsiClass)) return null;
if (!(resolved instanceof PsiClass aClass)) return null;
PsiClassType[] referencedTypes = list.getReferencedTypes();
int dupCount = 0;
PsiManager manager = containingFile.getManager();
for (PsiClassType referencedType : referencedTypes) {
PsiClass resolvedElement = referencedType.resolve();
if (resolvedElement != null && manager.areElementsEquivalent(resolvedElement, aClass)) {
dupCount++;
}
PsiJavaCodeReferenceElement sibling = PsiTreeUtil.getPrevSiblingOfType(element, PsiJavaCodeReferenceElement.class);
while (true) {
if (sibling == null) return null;
PsiElement target = sibling.resolve();
if (manager.areElementsEquivalent(target, aClass)) break;
sibling = PsiTreeUtil.getPrevSiblingOfType(sibling, PsiJavaCodeReferenceElement.class);
}
if (dupCount > 1) {
String name = HighlightUtil.formatClass(aClass);
String description = JavaErrorBundle.message("duplicate.class", name);
HighlightInfo.Builder info =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description);
IntentionAction action = QuickFixFactory.getInstance().createRemoveDuplicateExtendsAction(name);
info.registerFix(action, null, null, null, null);
return info;
}
return null;
String name = HighlightUtil.formatClass(aClass);
String description = JavaErrorBundle.message("duplicate.reference.in.list", name, list.getFirstChild().getText());
HighlightInfo.Builder info =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description);
IntentionAction action = QuickFixFactory.getInstance().createRemoveDuplicateExtendsAction(name);
info.registerFix(action, null, null, null, null);
return info;
}
static HighlightInfo.Builder checkClassAlreadyImported(@NotNull PsiClass aClass, @NotNull PsiElement elementToHighlight) {

View File

@@ -112,6 +112,7 @@ class.must.implement.method=Class ''{0}'' must implement abstract method ''{1}''
abstract.cannot.be.instantiated=''{0}'' is abstract; cannot be instantiated
duplicate.class.in.other.file=Duplicate class found in the file ''{0}''
duplicate.class=Duplicate class: ''{0}''
duplicate.reference.in.list=Duplicate reference to ''{0}'' in ''{1}'' list
public.class.should.be.named.after.file=Class ''{0}'' is public, should be declared in a file named ''{0}.java''
inheritance.from.final.class=Cannot inherit from {1} ''{0}''
package.name.file.path.mismatch=Package name ''{0}'' does not correspond to the file path ''{1}''

View File

@@ -3,10 +3,10 @@
class a {
}
class b extends <error descr="Duplicate class: 'a'">a</error>, <error descr="Duplicate class: 'a'">a</error> {
class b extends a, <error descr="Duplicate reference to 'a' in 'extends' list">a</error> {
}
interface i {}
class c implements <error descr="Duplicate class: 'i'">i</error>, <error descr="Duplicate class: 'i'">i</error> {
class c implements i, <error descr="Duplicate reference to 'i' in 'implements' list">i</error> {
}

View File

@@ -19,7 +19,7 @@ final class A1 extends Sealed1 {
final class C1 extends Sealed1 {
}
sealed abstract class Sealed2 permits <error descr="Duplicate class: 'A2'">A2</error>, <error descr="Duplicate class: 'A2'">A2</error> {
sealed abstract class Sealed2 permits A2, <error descr="Duplicate reference to 'A2' in 'permits' list">A2</error> {
}
final class A2 extends Sealed2 {

View File

@@ -4,7 +4,7 @@ import java.lang.annotation.Target;
interface I0 <error descr="Invalid permits clause: 'I0' must be sealed">permits</error> I {}
sealed interface I extends I0 permits <error descr="Cannot resolve symbol 'Unresolved'">Unresolved</error>, <error descr="Duplicate class: 'p.I1'">I1</error>, <error descr="Duplicate class: 'p.I1'">I1</error>{}
sealed interface I extends I0 permits <error descr="Cannot resolve symbol 'Unresolved'">Unresolved</error>, I1, <error descr="Duplicate reference to 'p.I1' in 'permits' list">I1</error>{}
non-sealed interface I1 extends I {}
sealed interface <error descr="Sealed class permits clause must contain all subclasses">A</error> {}