[java] Support inner class members in JavaLangClassMemberReference

#IDEA-373584 Fixed

GitOrigin-RevId: b9a2862766d62df666202694fa0be39d2625777c
This commit is contained in:
Bart van Helvert
2025-06-09 20:00:17 +00:00
committed by intellij-monorepo-bot
parent d942ea174c
commit f4e3ab41cf
4 changed files with 50 additions and 20 deletions
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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.psi.impl.source.resolve.reference.impl;
import com.intellij.codeInsight.completion.InsertHandler;
@@ -6,6 +6,7 @@ import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.completion.JavaLookupElementBuilder;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInspection.reference.PsiMemberReference;
import com.intellij.lang.jvm.JvmModifier;
import com.intellij.psi.*;
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod;
import com.intellij.psi.util.PsiTreeUtil;
@@ -183,18 +184,31 @@ public class JavaLangClassMemberReference extends PsiReferenceBase<PsiLiteralExp
}
private static int matchMethodArguments(PsiMethod method, List<ReflectiveType> argumentTypes) {
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameters.length != argumentTypes.size()) {
// Get nested classes because they need to be passed if not static
List<PsiClass> enclosingClasses = PsiTreeUtil.collectParents(method, PsiClass.class, false, parent -> {
return parent instanceof PsiFile || parent instanceof PsiClass cls && cls.hasModifier(JvmModifier.STATIC);
});
if (!enclosingClasses.isEmpty()) {
// the containing class of the method doesn't need to be passed
enclosingClasses = ContainerUtil.reverse(enclosingClasses).subList(0, enclosingClasses.size() - 1);
}
final List<PsiType> containingClassTypes = ContainerUtil.map(
enclosingClasses, cls -> JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createType(cls)
);
final List<PsiType> methodParamTypes = ContainerUtil.map(method.getParameterList().getParameters(), p -> p.getType());
final List<PsiType> allTypes = ContainerUtil.concat(containingClassTypes, methodParamTypes);
if (allTypes.size() != argumentTypes.size()) {
return -1;
}
int mismatchCount = 0;
for (int i = 0; i < parameters.length; i++) {
for (int i = 0; i < allTypes.size(); i++) {
final ReflectiveType argumentType = argumentTypes.get(i);
if (argumentType == null) {
mismatchCount++;
continue;
}
if (!argumentType.isEqualTo(parameters[i].getType())) {
if (!argumentType.isEqualTo(allTypes.get(i))) {
return -1;
}
}
@@ -0,0 +1,14 @@
class Constructors {
class X {
X() {}
X(String a) {}
}
public void testConstructor() throws Exception {
X.class.getDeclaredConstructor<warning descr="Cannot resolve constructor with specified argument types">()</warning>;
X.class.getDeclaredConstructor<warning descr="Cannot resolve constructor with specified argument types">(String.class)</warning>;
X.class.getDeclaredConstructor(Constructors.class);
X.class.getDeclaredConstructor(Constructors.class, String.class);
}
}
@@ -0,0 +1,14 @@
class Constructors {
public void testConstructor() throws Exception {
class X {
X() {}
X(String a) {}
}
X.class.getDeclaredConstructor<warning descr="Cannot resolve constructor with specified argument types">()</warning>;
X.class.getDeclaredConstructor<warning descr="Cannot resolve constructor with specified argument types">(String.class)</warning>;
X.class.getDeclaredConstructor(Constructors.class);
X.class.getDeclaredConstructor(Constructors.class, String.class);
}
}
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// 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.codeInspection
import com.intellij.JavaTestUtil
@@ -40,6 +26,8 @@ class JavaReflectionMemberAccessTest : LightJavaCodeInsightFixtureTestCase() {
fun testFieldExists() = doTest(true)
fun testMethodExists() = doTest(true)
fun testConstructorExists() = doTest(true)
fun testConstructorInnerClass() = doTest(true)
fun testConstructorLocalClass() = doTest(true)
fun testNewInstance() = doTest(true)
fun testBugs() = doTest(true)