From 99931bd7a3f3bf78c42ebe9afb7e1d52054da417 Mon Sep 17 00:00:00 2001 From: "Maxim.Medvedev" Date: Mon, 12 Dec 2011 19:40:17 +0400 Subject: [PATCH] IDEA-78555 Intellij fails to compile Groovy class with @Delegate when there is also Java class --- .../psi/impl/light/LightMethodBuilder.java | 43 +++--- .../com/intellij/psi/impl/PsiImplUtil.java | 5 + .../light/LightTypeParameterListBuilder.java | 73 ++++++++++ .../psi/impl/source/PsiMethodImpl.java | 3 +- .../ast/DelegatedMethodsContributor.java | 11 +- .../groovy/compiler/GeneratorTest.java | 4 + .../delegateToMethodWithTypeParams.test | 129 ++++++++++++++++++ 7 files changed, 246 insertions(+), 22 deletions(-) create mode 100644 java/java-psi-impl/src/com/intellij/psi/impl/light/LightTypeParameterListBuilder.java create mode 100644 plugins/groovy/testdata/groovy/stubGenerator/delegateToMethodWithTypeParams.test diff --git a/java/java-impl/src/com/intellij/psi/impl/light/LightMethodBuilder.java b/java/java-impl/src/com/intellij/psi/impl/light/LightMethodBuilder.java index 7ae2ccb00bda..b014b49099ae 100644 --- a/java/java-impl/src/com/intellij/psi/impl/light/LightMethodBuilder.java +++ b/java/java-impl/src/com/intellij/psi/impl/light/LightMethodBuilder.java @@ -16,7 +16,7 @@ package com.intellij.psi.impl.light; import com.intellij.lang.Language; -import com.intellij.lang.StdLanguages; +import com.intellij.lang.java.JavaLanguage; import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.ItemPresentationProviders; import com.intellij.openapi.util.Computable; @@ -46,6 +46,7 @@ public class LightMethodBuilder extends LightElement implements PsiMethod { private Computable myReturnType; private final PsiModifierList myModifierList; private PsiParameterList myParameterList; + private PsiTypeParameterList myTypeParameterList; private PsiReferenceList myThrowsList; private Icon myBaseIcon; private PsiClass myContainingClass; @@ -58,9 +59,9 @@ public class LightMethodBuilder extends LightElement implements PsiMethod { } public LightMethodBuilder(PsiManager manager, String name) { - this(manager, StdLanguages.JAVA, name); + this(manager, JavaLanguage.INSTANCE, name); } - + public LightMethodBuilder(PsiManager manager, Language language, String name) { this(manager, language, name, new LightParameterListBuilder(manager, language), new LightModifierList(manager, language)); } @@ -70,7 +71,9 @@ public class LightMethodBuilder extends LightElement implements PsiMethod { String name, PsiParameterList parameterList, PsiModifierList modifierList) { - this(manager, language, name, parameterList, modifierList, new LightReferenceListBuilder(manager, language, PsiReferenceList.Role.THROWS_LIST)); + this(manager, language, name, parameterList, modifierList, + new LightReferenceListBuilder(manager, language, PsiReferenceList.Role.THROWS_LIST), + new LightTypeParameterListBuilder(manager, language)); } public LightMethodBuilder(PsiManager manager, @@ -78,12 +81,14 @@ public class LightMethodBuilder extends LightElement implements PsiMethod { String name, PsiParameterList parameterList, PsiModifierList modifierList, - PsiReferenceList throwsList) { + PsiReferenceList throwsList, + PsiTypeParameterList typeParameterList) { super(manager, language); myName = name; myParameterList = parameterList; myModifierList = modifierList; myThrowsList = throwsList; + myTypeParameterList = typeParameterList; } @Override @@ -93,18 +98,18 @@ public class LightMethodBuilder extends LightElement implements PsiMethod { @Override public boolean hasTypeParameters() { - return false; + return PsiImplUtil.hasTypeParameters(this); } @Override - @NotNull public PsiTypeParameter[] getTypeParameters() { - return PsiTypeParameter.EMPTY_ARRAY; + @NotNull + public PsiTypeParameter[] getTypeParameters() { + return PsiImplUtil.getTypeParameters(this); } @Override public PsiTypeParameterList getTypeParameterList() { - //todo - return null; + return myTypeParameterList; } @Override @@ -115,8 +120,7 @@ public class LightMethodBuilder extends LightElement implements PsiMethod { @Override public boolean isDeprecated() { - //todo - return false; + return PsiImplUtil.isDeprecatedByDocTag(this) || PsiImplUtil.isDeprecatedByAnnotation(this); } @Override @@ -208,16 +212,16 @@ public class LightMethodBuilder extends LightElement implements PsiMethod { public LightMethodBuilder addParameter(@NotNull String name, @NotNull String type) { return addParameter(name, JavaPsiFacade.getElementFactory(getProject()).createTypeFromText(type, this)); } - + public LightMethodBuilder addParameter(@NotNull String name, @NotNull PsiType type) { - return addParameter(new LightParameter(name, type, this, StdLanguages.JAVA)); + return addParameter(new LightParameter(name, type, this, JavaLanguage.INSTANCE)); } public LightMethodBuilder addParameter(@NotNull String name, @NotNull PsiType type, boolean isVarArgs) { if (isVarArgs && !(type instanceof PsiEllipsisType)) { type = new PsiEllipsisType(type); } - return addParameter(new LightParameter(name, type, this, StdLanguages.JAVA, isVarArgs)); + return addParameter(new LightParameter(name, type, this, JavaLanguage.INSTANCE, isVarArgs)); } public LightMethodBuilder addException(PsiClassType type) { @@ -254,8 +258,7 @@ public class LightMethodBuilder extends LightElement implements PsiMethod { @Override public boolean isVarArgs() { - //todo - return false; + return PsiImplUtil.isVarArgs(this); } @Override @@ -385,6 +388,7 @@ public class LightMethodBuilder extends LightElement implements PsiMethod { public PsiMethodReceiver getMethodReceiver() { return null; } + @Override @Nullable public PsiType getReturnTypeNoResolve() { @@ -422,4 +426,9 @@ public class LightMethodBuilder extends LightElement implements PsiMethod { result = 31 * result + myMethodKind.hashCode(); return result; } + + public LightMethodBuilder addTypeParameter(PsiTypeParameter parameter) { + ((LightTypeParameterListBuilder)myTypeParameterList).addParameter(new LightTypeParameter(parameter)); + return this; + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java index 2a97d470dee8..0756e93fb950 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java @@ -525,4 +525,9 @@ public class PsiImplUtil { } return result; } + + public static boolean isVarArgs(PsiMethod method) { + PsiParameter[] parameters = method.getParameterList().getParameters(); + return parameters.length > 0 && parameters[parameters.length - 1].isVarArgs(); + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/light/LightTypeParameterListBuilder.java b/java/java-psi-impl/src/com/intellij/psi/impl/light/LightTypeParameterListBuilder.java new file mode 100644 index 000000000000..78787dde907c --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/psi/impl/light/LightTypeParameterListBuilder.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2011 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. + */ +package com.intellij.psi.impl.light; + +import com.intellij.lang.Language; +import com.intellij.psi.*; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Max Medvedev + */ +public class LightTypeParameterListBuilder extends LightElement implements PsiTypeParameterList { + private final List myParameters = new ArrayList(); + private PsiTypeParameter[] cached = null; + + protected LightTypeParameterListBuilder(PsiManager manager, final Language language) { + super(manager, language); + } + + @Override + public String toString() { + return "Light type parameter list"; + } + + @Override + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof JavaElementVisitor) { + ((JavaElementVisitor)visitor).visitTypeParameterList(this); + } + else { + visitor.visitElement(this); + } + } + + @Override + public PsiTypeParameter[] getTypeParameters() { + if (cached == null) { + if (myParameters.size() == 0) { + cached = PsiTypeParameter.EMPTY_ARRAY; + } + else { + cached = myParameters.toArray(new PsiTypeParameter[myParameters.size()]); + } + } + return cached; + } + + @Override + public int getTypeParameterIndex(PsiTypeParameter typeParameter) { + return myParameters.indexOf(typeParameter); + } + + public void addParameter(PsiTypeParameter parameter) { + cached = null; + myParameters.add(parameter); + } +} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiMethodImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiMethodImpl.java index 7046c7762995..20948f4e00f2 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiMethodImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiMethodImpl.java @@ -316,8 +316,7 @@ public class PsiMethodImpl extends JavaStubPsiElement implements return stub.isVarArgs(); } - PsiParameter[] parameters = getParameterList().getParameters(); - return parameters.length > 0 && parameters[parameters.length - 1].isVarArgs(); + return PsiImplUtil.isVarArgs(this); } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ast/DelegatedMethodsContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ast/DelegatedMethodsContributor.java index 78faf0301610..2fc1c47ba350 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ast/DelegatedMethodsContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ast/DelegatedMethodsContributor.java @@ -96,16 +96,21 @@ public class DelegatedMethodsContributor extends AstTransformContributor { builder.setMethodReturnType(substitutor.substitute(method.getReturnType())); builder.setNavigationElement(method); builder.addModifier(PsiModifier.PUBLIC); + + final PsiTypeParameter[] typeParameters = method.getTypeParameters(); + for (PsiTypeParameter typeParameter : typeParameters) { + builder.addTypeParameter(typeParameter); + } + final PsiParameter[] originalParameters = method.getParameterList().getParameters(); final PsiClass containingClass = method.getContainingClass(); boolean isRaw = containingClass != null && PsiUtil.isRawSubstitutor(containingClass, substitutor); if (isRaw) { - PsiTypeParameter[] methodTypeParameters = method.getTypeParameters(); - substitutor = JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createRawSubstitutor(substitutor, methodTypeParameters); + substitutor = JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createRawSubstitutor(substitutor, typeParameters); } - for (int i = 0, originalParametersLength = originalParameters.length; i < originalParametersLength; i++) { + for (int i = 0; i < originalParameters.length; i++) { PsiParameter originalParameter = originalParameters[i]; PsiType type; if (isRaw) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GeneratorTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GeneratorTest.java index f3ec84ab43fb..2f1eff82df8f 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GeneratorTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GeneratorTest.java @@ -106,6 +106,10 @@ public class GeneratorTest extends LightGroovyTestCase { myFixture.addClass("package groovy.transform; public @interface AutoClone {}"); doTest(); } + + public void testDelegateToMethodWithTypeParams() { + doTest(); + } public void doTest() { final String relTestPath = getTestName(true) + ".test"; diff --git a/plugins/groovy/testdata/groovy/stubGenerator/delegateToMethodWithTypeParams.test b/plugins/groovy/testdata/groovy/stubGenerator/delegateToMethodWithTypeParams.test new file mode 100644 index 000000000000..f9a8fd237db3 --- /dev/null +++ b/plugins/groovy/testdata/groovy/stubGenerator/delegateToMethodWithTypeParams.test @@ -0,0 +1,129 @@ +abstract class TestDelegateIdea { + @Delegate + private List delegate = [] +} +----- +public abstract class TestDelegateIdea extends groovy.lang.GroovyObjectSupport implements java.util.List, groovy.lang.GroovyObject { +public int size() { +return 0; +} + +public boolean isEmpty() { +return false; +} + +public boolean contains(java.lang.Object o) { +return false; +} + +public java.util.Iterator iterator() { +return null; +} + +public java.lang.Object[] toArray() { +return null; +} + +public T[] toArray(T[] a) { +return null; +} + +public boolean add(java.lang.String o) { +return false; +} + +public boolean remove(java.lang.Object o) { +return false; +} + +public boolean containsAll(java.util.Collection c) { +return false; +} + +public boolean addAll(java.util.Collection c) { +return false; +} + +public boolean addAll(int index, java.util.Collection c) { +return false; +} + +public boolean removeAll(java.util.Collection c) { +return false; +} + +public boolean retainAll(java.util.Collection c) { +return false; +} + +public void clear() { +return ; +} + +public boolean equals(java.lang.Object o) { +return false; +} + +public int hashCode() { +return 0; +} + +public java.lang.String get(int index) { +return null; +} + +public java.lang.String set(int index, java.lang.String element) { +return null; +} + +public void add(int index, java.lang.String element) { +return ; +} + +public java.lang.String remove(int index) { +return null; +} + +public int indexOf(java.lang.Object o) { +return 0; +} + +public int lastIndexOf(java.lang.Object o) { +return 0; +} + +public java.util.ListIterator listIterator() { +return null; +} + +public java.util.ListIterator listIterator(int index) { +return null; +} + +public java.util.List subList(int fromIndex, int toIndex) { +return null; +} + +public java.lang.Object getProperty(java.lang.String property) { +return null; +} + +public void setProperty(java.lang.String property, java.lang.Object newValue) { +return ; +} + +public java.lang.Object invokeMethod(java.lang.String name, java.lang.Object args) { +return null; +} + +public groovy.lang.MetaClass getMetaClass() { +return null; +} + +public void setMetaClass(groovy.lang.MetaClass metaClass) { +return ; +} + +private java.util.List delegate = null; +} +--- \ No newline at end of file