mixin origin info & navigation

This commit is contained in:
Max Medvedev
2012-11-29 16:24:27 +04:00
parent e54c0114e3
commit fe096e3a94
3 changed files with 64 additions and 31 deletions
@@ -46,6 +46,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrReferenceResolveUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrGdkMethodImpl;
import org.jetbrains.plugins.groovy.lang.resolve.noncode.MixinMemberContributor;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor;
@@ -218,19 +219,7 @@ public class GdkMethodUtil {
final GrReferenceExpression qualifier = result.second;
final PsiClass mixin = result.third;
final DelegatingScopeProcessor delegate = new DelegatingScopeProcessor(processor) {
@Override
public boolean execute(@NotNull PsiElement element, ResolveState delegateState) {
if (element instanceof PsiMethod && isCategoryMethod((PsiMethod)element, subjectType, qualifier, null)) {
PsiMethod method = (PsiMethod)element;
return processor.execute(GrGdkMethodImpl.createGdkMethod(method, false, generateOriginInfo(method)), delegateState);
}
else if (element instanceof PsiMethod && ((PsiMethod)element).hasModifierProperty(PsiModifier.PUBLIC)) {
super.execute(element, delegateState);
}
return true;
}
};
final DelegatingScopeProcessor delegate = new MixinMemberContributor.MixinProcessor(processor, subjectType, qualifier);
mixin.processDeclarations(delegate, state, null, place);
}
}
@@ -15,10 +15,14 @@
*/
package org.jetbrains.plugins.groovy.lang.resolve.noncode;
import com.intellij.codeInsight.completion.originInfo.OriginInfoAwareElement;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightMethod;
import com.intellij.psi.scope.DelegatingScopeProcessor;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationArrayInitializer;
@@ -66,26 +70,15 @@ public class MixinMemberContributor extends NonCodeMembersContributor {
}
}
final MixinProcessor delegate = new MixinProcessor(processor, qualifierType, place);
for (PsiClass mixin : mixins) {
if (!mixin.processDeclarations(new DelegatingScopeProcessor(processor) {
@Override
public boolean execute(@NotNull PsiElement element, ResolveState state) {
if (element instanceof PsiMethod && GdkMethodUtil.isCategoryMethod((PsiMethod)element, qualifierType, place, state.get(PsiSubstitutor.KEY))) {
PsiMethod method = (PsiMethod)element;
String originInfo = getOriginInfo(method);
return super.execute(GrGdkMethodImpl.createGdkMethod(method, false, originInfo), state);
}
else {
return super.execute(element, state);
}
}
}, state, null, place)) {
if (!mixin.processDeclarations(delegate, state, null, place)) {
return;
}
}
}
private static String getOriginInfo(PsiMethod element) {
public static String getOriginInfoForCategory(PsiMethod element) {
PsiClass aClass = element.getContainingClass();
if (aClass != null && aClass.getName() != null) {
return "mixed in from " + aClass.getName();
@@ -93,6 +86,10 @@ public class MixinMemberContributor extends NonCodeMembersContributor {
return "mixed in";
}
public static String getOriginInfoForMixin(@NotNull PsiType subjectType) {
return "mixed in " + subjectType.getPresentableText();
}
private static List<PsiAnnotation> getAllMixins(PsiModifierList modifierList) {
final ArrayList<PsiAnnotation> result = new ArrayList<PsiAnnotation>();
for (PsiAnnotation annotation : modifierList.getApplicableAnnotations()) {
@@ -115,4 +112,53 @@ public class MixinMemberContributor extends NonCodeMembersContributor {
}
}
}
private static class MixinedMethod extends LightMethod implements OriginInfoAwareElement, PsiMirrorElement {
private final String myOriginInfo;
private final PsiMethod myPrototype;
public MixinedMethod(@NotNull PsiMethod method, String originInfo) {
super(method.getManager(), method, ObjectUtils.assertNotNull(method.getContainingClass()));
myOriginInfo = originInfo;
myPrototype = method;
}
@Nullable
@Override
public String getOriginInfo() {
return myOriginInfo;
}
@NotNull
@Override
public PsiElement getPrototype() {
return myPrototype;
}
}
public static class MixinProcessor extends DelegatingScopeProcessor {
private final PsiType myType;
private final PsiElement myPlace;
public MixinProcessor(PsiScopeProcessor delegate, @NotNull PsiType qualifierType, @Nullable PsiElement place) {
super(delegate);
myType = qualifierType;
myPlace = place;
}
@Override
public boolean execute(@NotNull PsiElement element, ResolveState state) {
if (element instanceof PsiMethod && GdkMethodUtil.isCategoryMethod((PsiMethod)element, myType, myPlace, state.get(PsiSubstitutor.KEY))) {
PsiMethod method = (PsiMethod)element;
String originInfo = getOriginInfoForCategory(method);
return super.execute(GrGdkMethodImpl.createGdkMethod(method, false, originInfo), state);
}
else if (element instanceof PsiMethod) {
return super.execute(new MixinedMethod((PsiMethod)element, getOriginInfoForMixin(myType)), state);
}
else {
return super.execute(element, state);
}
}
}
}
@@ -783,8 +783,7 @@ print new B().f<caret>oo()
""")
def resolved = ref.resolve()
assertInstanceOf(resolved, GrMethod)
assertTrue(resolved.physical)
assertInstanceOf(resolved, PsiMethod)
}
void testTwoMixinsInModifierList() {
@@ -812,8 +811,7 @@ class OtherPersonMixin {
""")
def resolved = ref.resolve()
assertInstanceOf(resolved, GrMethod)
assertTrue(resolved.physical)
assertInstanceOf(resolved, PsiMethod)
}