Fix type parameters referenced by the bounds of other type parameters not being added in anonymous to inner intention.

#IDEA-373936 fixed

closes https://github.com/JetBrains/intellij-community/pull/3075


(cherry picked from commit fe3b036de7f23154be56f1116c58a0eef408c4dd)

IJ-MR-164968

GitOrigin-RevId: b1f78464d8129718f9d5a479a099c173a640d174
This commit is contained in:
joe
2025-06-04 01:09:19 +01:00
committed by intellij-monorepo-bot
parent 2b1032ad17
commit a548b99409
4 changed files with 47 additions and 8 deletions

View File

@@ -36,6 +36,7 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.JavaPsiConstructorUtil;
import com.siyeh.ig.jdk.VarargParameterInspection;
import com.siyeh.ig.psiutils.PsiElementOrderComparator;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -55,7 +56,7 @@ public class AnonymousToInnerHandler implements RefactoringActionHandlerOnPsiEle
protected VariableInfo[] myVariableInfos;
protected boolean myMakeStatic;
private final Set<PsiTypeParameter> myTypeParametersToCreate = new LinkedHashSet<>();
private final List<PsiTypeParameter> myTypeParametersToCreate = new ArrayList<>();
@Override
public void invoke(@NotNull Project project, PsiElement @NotNull [] elements, DataContext dataContext) {
@@ -224,10 +225,9 @@ public class AnonymousToInnerHandler implements RefactoringActionHandlerOnPsiEle
buf.append(innerClass.getName());
if (!myTypeParametersToCreate.isEmpty()) {
buf.append("<");
int idx = 0;
for (Iterator<PsiTypeParameter> it = myTypeParametersToCreate.iterator(); it.hasNext(); idx++) {
for (int idx = 0; idx < myTypeParametersToCreate.size(); idx++) {
if (idx > 0) buf.append(", ");
String typeParamName = it.next().getName();
String typeParamName = myTypeParametersToCreate.get(idx).getName();
buf.append(typeParamName);
}
buf.append(">");
@@ -714,8 +714,12 @@ public class AnonymousToInnerHandler implements RefactoringActionHandlerOnPsiEle
}
}
private void calculateTypeParametersToCreate () {
private void calculateTypeParametersToCreate() {
Deque<PsiElement> visitQueue = new ArrayDeque<>();
JavaRecursiveElementWalkingVisitor visitor = new JavaRecursiveElementWalkingVisitor() {
private final Set<PsiTypeParameter> myAddedTypeParameters = new HashSet<>();
@Override
public void visitReferenceElement(@NotNull PsiJavaCodeReferenceElement reference) {
super.visitReferenceElement(reference);
@@ -724,18 +728,28 @@ public class AnonymousToInnerHandler implements RefactoringActionHandlerOnPsiEle
final PsiTypeParameterListOwner owner = typeParameter.getOwner();
if (owner != null && !PsiTreeUtil.isAncestor(myAnonOrLocalClass, owner, false) &&
(!PsiTreeUtil.isAncestor(owner, myTargetClass, false) || myMakeStatic)) {
myTypeParametersToCreate.add(typeParameter);
if (myAddedTypeParameters.add(typeParameter)) {
myTypeParametersToCreate.add(typeParameter);
visitQueue.add(typeParameter.getExtendsList());
}
}
}
}
};
myAnonOrLocalClass.accept(visitor);
visitQueue.add(myAnonOrLocalClass);
for (VariableInfo info : myVariableInfos) {
PsiTypeElement typeElement = info.variable.getTypeElement();
if (typeElement != null) {
typeElement.accept(visitor);
visitQueue.add(typeElement);
}
}
while (!visitQueue.isEmpty()) {
visitQueue.remove().accept(visitor);
}
// Need the elements to appear in order so that type parameters aren't used before their declaration
myTypeParametersToCreate.sort(PsiElementOrderComparator.getInstance());
}
@Override

View File

@@ -0,0 +1,10 @@
class Test<T> {
<U extends T, V extends Comparable<U>> void test() {
class <caret>Inner {
V foo() {
return null;
}
}
new Inner();
}
}

View File

@@ -0,0 +1,11 @@
class Test<T> {
<U extends T, V extends Comparable<U>> void test() {
new Inner<U, V>();
}
private class Inner<U extends T, V extends Comparable<U>> {
V foo() {
return null;
}
}
}

View File

@@ -31,6 +31,10 @@ public class AnonymousToInnerTest extends LightJavaCodeInsightTestCase {
doTest("MyIterator", false);
}
public void testGenericParametersWithGenericBounds() {
doTest("Inner", false);
}
public void testInsideInterface() { // IDEADEV-29446
doTest("MyRunnable", true);
}