From 16fad73d840ea61068cc8a2cfb6b2b4f7fc6c4fb Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Fri, 10 Sep 2010 15:48:13 +0400 Subject: [PATCH] IDEA-57505 Support collection members --- .../psi/impl/light/LightFieldBuilder.java | 85 +++++++++++++++++++ .../psi/impl/light/LightVariableBuilder.java | 12 ++- plugins/groovy/src/META-INF/plugin.xml | 1 + .../groovy/lang/resolve/ResolveUtil.java | 14 +++ .../GrCollectionTypeMembersProvider.java | 71 ++++++++++++++++ .../lang/resolve/ResolvePropertyTest.groovy | 6 ++ .../property/collectionItemFields/A.groovy | 2 + 7 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 java/java-impl/src/com/intellij/psi/impl/light/LightFieldBuilder.java create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/GrCollectionTypeMembersProvider.java create mode 100644 plugins/groovy/testdata/resolve/property/collectionItemFields/A.groovy diff --git a/java/java-impl/src/com/intellij/psi/impl/light/LightFieldBuilder.java b/java/java-impl/src/com/intellij/psi/impl/light/LightFieldBuilder.java new file mode 100644 index 000000000000..23b717de8240 --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/impl/light/LightFieldBuilder.java @@ -0,0 +1,85 @@ +/* + * Copyright 2000-2010 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.psi.*; +import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Maxim.Medvedev + */ +public class LightFieldBuilder extends LightVariableBuilder implements PsiField { + PsiClass myContainingClass = null; + PsiExpression myInitializer = null; + private PsiDocComment myDocComment = null; + private boolean myIsDeprecated = false; + + public LightFieldBuilder(@NotNull String name, @NotNull String type, @NotNull PsiElement navigationElement) { + super(name, JavaPsiFacade.getElementFactory(navigationElement.getProject()).createTypeFromText(type, navigationElement), + navigationElement); + } + + public LightFieldBuilder(@NotNull String name, @NotNull PsiType type, @NotNull PsiElement navigationElement) { + super(name, type, navigationElement); + } + + public LightFieldBuilder(PsiManager manager, @NotNull String name, @NotNull PsiType type) { + super(manager, name, type); + } + + public LightFieldBuilder setContainingClass(PsiClass psiClass) { + myContainingClass = psiClass; + return this; + } + + @Override + public void setInitializer(@Nullable PsiExpression initializer) throws IncorrectOperationException { + myInitializer = initializer; + } + + @Override + public PsiExpression getInitializer() { + return myInitializer; + } + + @Override + public PsiDocComment getDocComment() { + return myDocComment; + } + + public LightFieldBuilder setDocComment(PsiDocComment docComment) { + myDocComment = docComment; + return this; + } + + @Override + public boolean isDeprecated() { + return myIsDeprecated; + } + + public LightFieldBuilder setIsDeprecated(boolean isDeprecated) { + myIsDeprecated = isDeprecated; + return this; + } + + @Override + public PsiClass getContainingClass() { + return myContainingClass; + } +} diff --git a/java/java-impl/src/com/intellij/psi/impl/light/LightVariableBuilder.java b/java/java-impl/src/com/intellij/psi/impl/light/LightVariableBuilder.java index 6932cb320c0e..aa537cd501b5 100644 --- a/java/java-impl/src/com/intellij/psi/impl/light/LightVariableBuilder.java +++ b/java/java-impl/src/com/intellij/psi/impl/light/LightVariableBuilder.java @@ -14,7 +14,7 @@ import javax.swing.*; /** * @author peter */ -public class LightVariableBuilder extends LightElement implements PsiVariable { +public class LightVariableBuilder extends LightElement implements PsiVariable { private final String myName; private final PsiType myType; private volatile LightModifierList myModifierList; @@ -53,9 +53,9 @@ public class LightVariableBuilder extends LightElement implements PsiVariable { return myModifierList; } - public LightVariableBuilder setModifiers(String... modifiers) { + public T setModifiers(String... modifiers) { myModifierList = new LightModifierList(getManager(), getLanguage(), modifiers); - return this; + return (T)this; } @Override @@ -112,10 +112,8 @@ public class LightVariableBuilder extends LightElement implements PsiVariable { return ElementPresentationUtil.addVisibilityIcon(this, flags, baseIcon); } - public LightVariableBuilder setBaseIcon(Icon baseIcon) { + public T setBaseIcon(Icon baseIcon) { myBaseIcon = baseIcon; - return this; + return (T)this; } - - } diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 91efcba7edbd..82f3b9b8e787 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -54,6 +54,7 @@ + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java index 63d27e8d1dfb..218335f477db 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java @@ -127,6 +127,20 @@ public class ResolveUtil { return true; } + public static boolean processAllDeclarations(@NotNull PsiType type, + @NotNull PsiScopeProcessor processor, + @NotNull ResolveState state, + @NotNull GroovyPsiElement place) { + if (type instanceof PsiClassType) { + final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)type).resolveGenerics(); + final PsiClass psiClass = resolveResult.getElement(); + if (psiClass != null) { + if (!psiClass.processDeclarations(processor, state, null, place)) return false; + } + } + return processNonCodeMethods(type, processor, place); + } + public static boolean processNonCodeMethods(PsiType type, PsiScopeProcessor processor, GroovyPsiElement place) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/GrCollectionTypeMembersProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/GrCollectionTypeMembersProvider.java new file mode 100644 index 000000000000..6f27d2e24472 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/GrCollectionTypeMembersProvider.java @@ -0,0 +1,71 @@ +/* + * Copyright 2000-2010 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 org.jetbrains.plugins.groovy.lang.resolve.noncode; + +import com.intellij.openapi.util.Key; +import com.intellij.psi.*; +import com.intellij.psi.impl.light.LightFieldBuilder; +import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; +import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; + +/** + * @author Maxim.Medvedev + */ +public class GrCollectionTypeMembersProvider extends NonCodeMembersContributor { + @Override + public void processDynamicElements(final @NotNull PsiType qualifierType, + final PsiScopeProcessor processor, + final GroovyPsiElement place, + final ResolveState state) { + if (!(qualifierType instanceof PsiClassType)) return; + if (!InheritanceUtil.isInheritor(qualifierType, CommonClassNames.JAVA_UTIL_COLLECTION)) return; + + final PsiType collectionType = PsiUtil.extractIterableTypeParameter(qualifierType, true); + if (collectionType == null) return; + + ResolveUtil.processAllDeclarations(collectionType, new PsiScopeProcessor() { + @Override + public boolean execute(PsiElement element, ResolveState state) { + if (element instanceof PsiField) { + final PsiType type = ((PsiField)element).getType(); + String typeText = CommonClassNames.JAVA_UTIL_COLLECTION; + if (type instanceof PsiClassType) { + typeText = typeText + "<" + type.getCanonicalText() + ">"; + } + LightFieldBuilder lightField = new LightFieldBuilder(((PsiField)element).getName(), typeText, element).setContainingClass( + JavaPsiFacade.getInstance(place.getProject()).findClass(CommonClassNames.JAVA_UTIL_COLLECTION, place.getResolveScope())); + return processor.execute(lightField, state); + } + return true; + } + + @Override + public T getHint(Key hintKey) { + return processor.getHint(hintKey); + } + + @Override + public void handleEvent(Event event, Object associated) { + processor.handleEvent(event, associated); + } + }, state, place); + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy index 377262330679..a1fef2e7d82e 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy @@ -575,4 +575,10 @@ setFoo(2) PsiElement resolved = ref.resolve() assertInstanceOf resolved, PsiMethod } + + public void testCollectionItemFields() { + PsiReference ref = configureByFile("collectionItemFields/A.groovy") + PsiElement resolved = ref.resolve() + assertInstanceOf resolved, PsiField + } } \ No newline at end of file diff --git a/plugins/groovy/testdata/resolve/property/collectionItemFields/A.groovy b/plugins/groovy/testdata/resolve/property/collectionItemFields/A.groovy new file mode 100644 index 000000000000..c93e0dda9491 --- /dev/null +++ b/plugins/groovy/testdata/resolve/property/collectionItemFields/A.groovy @@ -0,0 +1,2 @@ +def list = ["a", "v"] +Collection collection = list.value \ No newline at end of file