IDEA-315933 javadoc: handle wrongful inner class references

Also handle implicit constructor references

GitOrigin-RevId: bd97341568c86156d5b410061e7e989325f85775
This commit is contained in:
Mathias
2026-05-28 11:09:43 +00:00
committed by intellij-monorepo-bot
parent 1d40227e07
commit 692f53aee0
12 changed files with 50 additions and 15 deletions
@@ -175,12 +175,19 @@ public final class JavaDocUtil {
return null;
}
/// Find a field or method referenced by `refClass`
///
/// @param poundIndex the index where `#` is in `refTextCorrected`.
private static @Nullable PsiElement findReference(@NotNull PsiClass refClass,
PsiElement context,
boolean useNavigationElement,
String refTextCorrected,
int poundIndex) {
PsiElement member = findReferencedMember(refClass, refTextCorrected.substring(poundIndex + 1), context);
if (poundIndex >= 0 && member instanceof PsiClass && member != refClass) {
// Psi subclasses class cannot be referred through `#` but the same class implicit constructor can
return null;
}
return useNavigationElement && member != null ? member.getNavigationElement() : member;
}
@@ -239,6 +246,9 @@ public final class JavaDocUtil {
for (PsiMethod method : methods) {
if (method.getName().equals(name)) return method;
}
// Implicit constructor is not part of the methods
if (memberRefText.equals(aClass.getName())) return aClass;
return null;
}
else {
@@ -282,7 +292,13 @@ public final class JavaDocUtil {
PsiMethod[] methods = PsiDocMethodOrFieldRef.findMethods(methodSignature, aClass, name, allMethods);
if (methods.length == 0) return null;
if (methods.length == 0) {
// Check for implicit constructor
if (types.length == 0 && name.equals(aClass.getName())) {
return aClass;
}
return null;
}
PsiMethod found = methods[0];
@@ -69,6 +69,7 @@ import java.util.Objects;
import java.util.Set;
/// PsiElement that is a _guarantee_ to reference either a **method** or a **field**.
/// Implicit constructors will resolve to the referring class
///
/// @see PsiDocReferenceHolder PsiDocReferenceHolder for other ways to reference methods and fields
public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDocTagValue, Constants {
@@ -280,8 +281,9 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo
}
final MethodSignature methodSignature;
List<PsiType> types = null;
if (signature != null) {
final List<PsiType> types = new ArrayList<>(signature.length);
types = new ArrayList<>(signature.length);
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(element.getProject());
for (String s : signature) {
try {
@@ -301,7 +303,13 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo
PsiMethod[] methods = findMethods(methodSignature, scope, name, getAllMethods(scope, referringElement));
if (methods.length == 0) return null;
if (methods.length == 0) {
// Implicit constructor resolves to the class since we can't point to missing code
if (name.equals(scope.getName()) && (types == null || types.isEmpty())) {
return new MethodOrFieldReference(referringElement, new PsiElement[]{scope});
}
return null;
}
return new MethodOrFieldReference(referringElement, methods) {
@@ -1,10 +0,0 @@
class Test {
/**
* @param ppp see {@link #<error descr="Cannot resolve symbol 'Test'">Test</error>}
*/
public void i(int ppp) {}
class A {
public void foo() {}
}
}
@@ -1,6 +1,6 @@
class Test {
/**
* @param ppp see {@link #<error descr="Cannot resolve symbol 'Test'">Test</error>}
* @param ppp see {@link #Test}
*/
public void i(int ppp) {}
@@ -0,0 +1,6 @@
/// [#<error descr="Cannot resolve symbol '#Inner'">Inner</error>]
///
/// [Outer#<error descr="Cannot resolve symbol 'Outer#Inner'">Inner</error>]
class Outer {
class Inner{}
}
@@ -0,0 +1 @@
<html><head><base href="placeholder"></head><body><div class='definition'><pre><span style="color:#000080;font-weight:bold;">public</span> <span style="color:#000080;font-weight:bold;">class</span> <span style="color:#000000;">BeautifulDespair</span></pre></div><div class='content'><p>I am used to listen to a song called <a href="psi_element://BeautifulDespair"><code><span style="color:#0000ff;">.BeautifulDespair</span></code></a></p><p>(variant <a href="psi_element://BeautifulDespair"><code><span style="color:#0000ff;">.BeautifulDespair()</span></code></a>)</p></div><table class='sections'><p></table>
@@ -0,0 +1,5 @@
/// I am used to listen to a song called [#BeautifulDespair]
///
/// (variant [#BeautifulDespair()])
public class BeautifulDespair {}
@@ -0,0 +1 @@
<html><head><base href="placeholder"></head><body><div class='definition'><pre><span style="color:#000080;font-weight:bold;">class</span> <span style="color:#000000;">Outer</span></pre></div><div class='content'><p><span style="color:#ff0000">Inner</span></p><p><span style="color:#ff0000">Outer.Inner</span></p></div><table class='sections'><p></table>
@@ -0,0 +1,6 @@
/// [#Inner]
///
/// [Outer#Inner]
class Outer {
class Inner{}
}
@@ -136,6 +136,7 @@ public class JavadocDeclarationHighlightingTest extends LightDaemonAnalyzerTestC
public void testCommentsInModifierList() { doTest(); }
public void testCommentsBeforeType() { doTest(); }
public void testCommentsBeforeName() { doTest(); }
public void testWrongfulInnerClassReferences() { doTest(); }
public void testIssueLinksInJavaDoc() {
IssueNavigationConfiguration navigationConfiguration = IssueNavigationConfiguration.getInstance(getProject());
@@ -92,7 +92,6 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testException3() { doTest(); }
public void testException4() { myMissingJavadocInspection.METHOD_SETTINGS.MINIMAL_VISIBILITY = "package"; doTest(); }
public void testInheritJavaDoc() { setLanguageLevel(LanguageLevel.JDK_1_3); doTest(); }
public void testLink0() { doTest(); }
public void testLinkFromInnerClassToSelfMethod() { doTest(); }
public void testValueBadReference() { doTest(); }
public void testValueGoodReference() { doTest(); }
@@ -264,6 +264,8 @@ public class JavaDocInfoGeneratorTest extends JavaCodeInsightTestCase {
verifyJavadocFor("SecondSealer");
}
public void testParameterizedLinks() { doTestClass(); }
public void testWrongfulInnerClassReferences() { doTestClass(); }
public void testImplicitConstructor() { doTestClass(); }
public void testRepeatableAnnotations() {
useJava8();