Add special class for getting methods from traits
This commit is contained in:
+6
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
* Copyright 2010-2014 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.
|
||||
@@ -32,8 +32,11 @@ import org.jetbrains.jet.lang.psi.JetClassOrObject
|
||||
import com.intellij.psi.impl.light.LightTypeParameterListBuilder
|
||||
import com.intellij.psi.search.SearchScope
|
||||
|
||||
public class KotlinLightMethodForDeclaration(
|
||||
manager: PsiManager, override val delegate: PsiMethod, override val origin: JetDeclaration, containingClass: PsiClass
|
||||
open public class KotlinLightMethodForDeclaration(
|
||||
manager: PsiManager,
|
||||
override val delegate: PsiMethod,
|
||||
override val origin: JetDeclaration,
|
||||
containingClass: PsiClass
|
||||
): LightMethod(manager, delegate, containingClass), KotlinLightMethod {
|
||||
|
||||
private val paramsList: CachedValue<PsiParameterList> by Delegates.blockingLazy {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.jet.asJava
|
||||
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.PsiMethod
|
||||
import org.jetbrains.jet.lang.psi.JetDeclaration
|
||||
import com.intellij.psi.PsiClass
|
||||
import org.jetbrains.jet.asJava.KotlinLightMethodFromTrait
|
||||
import com.intellij.psi.PsiElement
|
||||
|
||||
|
||||
public class KotlinLightMethodFromTrait(manager: PsiManager,
|
||||
override val delegate: PsiMethod,
|
||||
override val origin: JetDeclaration,
|
||||
containingClass: PsiClass) :
|
||||
KotlinLightMethodForDeclaration(manager, delegate, origin, containingClass) {
|
||||
|
||||
override fun copy(): PsiElement {
|
||||
return KotlinLightMethodFromTrait(getManager()!!, delegate, origin.copy() as JetDeclaration, getContainingClass()!!)
|
||||
}
|
||||
}
|
||||
+27
-5
@@ -24,9 +24,12 @@ import com.intellij.psi.impl.light.LightField;
|
||||
import com.intellij.psi.impl.light.LightMethod;
|
||||
import com.intellij.psi.impl.source.ClassInnerStuffCache;
|
||||
import com.intellij.psi.impl.source.PsiExtensibleClass;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import kotlin.Function1;
|
||||
import kotlin.KotlinPackage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
|
||||
@@ -125,13 +128,18 @@ public abstract class KotlinWrappingLightClass extends AbstractLightClass implem
|
||||
@NotNull
|
||||
@Override
|
||||
public List<PsiMethod> getOwnMethods() {
|
||||
return ContainerUtil.map(getDelegate().getMethods(), new Function<PsiMethod, PsiMethod>() {
|
||||
return KotlinPackage.map(getDelegate().getMethods(), new Function1<PsiMethod, PsiMethod>() {
|
||||
@Override
|
||||
public PsiMethod fun(PsiMethod method) {
|
||||
public PsiMethod invoke(PsiMethod method) {
|
||||
JetDeclaration declaration = ClsWrapperStubPsiFactory.getOriginalDeclaration(method);
|
||||
return declaration != null
|
||||
? new KotlinLightMethodForDeclaration(myManager, method, declaration, KotlinWrappingLightClass.this)
|
||||
: new LightMethod(myManager, method, KotlinWrappingLightClass.this);
|
||||
|
||||
if (declaration != null) {
|
||||
return !isMethodFromTrait(declaration) ?
|
||||
new KotlinLightMethodForDeclaration(myManager, method, declaration, KotlinWrappingLightClass.this) :
|
||||
new KotlinLightMethodFromTrait(myManager, method, declaration, KotlinWrappingLightClass.this);
|
||||
}
|
||||
|
||||
return new LightMethod(myManager, method, KotlinWrappingLightClass.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -152,4 +160,18 @@ public abstract class KotlinWrappingLightClass extends AbstractLightClass implem
|
||||
JetClassOrObject origin = getOrigin();
|
||||
return origin == null ? null : origin.getText();
|
||||
}
|
||||
|
||||
private boolean isMethodFromTrait(@NotNull JetDeclaration originMethodDeclaration) {
|
||||
if (!(originMethodDeclaration instanceof JetNamedFunction ||
|
||||
originMethodDeclaration instanceof JetPropertyAccessor ||
|
||||
originMethodDeclaration instanceof JetProperty)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JetClassOrObject parentOfMethodOrigin = PsiTreeUtil.getParentOfType(originMethodDeclaration, JetClassOrObject.class);
|
||||
JetClassOrObject thisClassDeclaration = getOrigin();
|
||||
|
||||
// Method was generated from declaration in some other trait
|
||||
return (parentOfMethodOrigin != null && thisClassDeclaration != parentOfMethodOrigin && JetPsiUtil.isTrait(parentOfMethodOrigin));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.jet.plugin.highlighter;
|
||||
|
||||
import com.google.common.collect.*;
|
||||
import com.intellij.codeHighlighting.Pass;
|
||||
import com.intellij.codeInsight.daemon.DaemonBundle;
|
||||
import com.intellij.codeInsight.daemon.GutterIconNavigationHandler;
|
||||
import com.intellij.codeInsight.daemon.LineMarkerInfo;
|
||||
import com.intellij.codeInsight.daemon.LineMarkerProvider;
|
||||
@@ -25,13 +26,18 @@ import com.intellij.codeInsight.daemon.impl.GutterIconTooltipHelper;
|
||||
import com.intellij.codeInsight.daemon.impl.LineMarkerNavigator;
|
||||
import com.intellij.codeInsight.daemon.impl.MarkerType;
|
||||
import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator;
|
||||
import com.intellij.codeInsight.navigation.ListBackgroundUpdaterTask;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.util.DefaultPsiElementCellRenderer;
|
||||
import com.intellij.ide.util.MethodCellRenderer;
|
||||
import com.intellij.ide.util.PsiClassListCellRenderer;
|
||||
import com.intellij.ide.util.PsiElementListCellRenderer;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
@@ -41,6 +47,7 @@ import com.intellij.psi.search.PsiElementProcessorAdapter;
|
||||
import com.intellij.psi.search.searches.AllOverridingMethodsSearch;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.psi.search.searches.OverridingMethodsSearch;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashSet;
|
||||
@@ -48,6 +55,7 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
import org.jetbrains.jet.asJava.KotlinLightMethodFromTrait;
|
||||
import org.jetbrains.jet.asJava.LightClassUtil;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
@@ -98,7 +106,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
|
||||
@Override
|
||||
public String fun(@Nullable PsiElement element) {
|
||||
PsiMethod psiMethod = getPsiMethod(element);
|
||||
return psiMethod != null ? MarkerType.getOverriddenMethodTooltip(psiMethod) : null;
|
||||
return psiMethod != null ? getOverriddenMethodTooltip(psiMethod) : null;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -107,7 +115,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
|
||||
public void browse(@Nullable MouseEvent e, @Nullable PsiElement element) {
|
||||
PsiMethod psiMethod = getPsiMethod(element);
|
||||
if (psiMethod != null) {
|
||||
MarkerType.navigateToOverriddenMethod(e, psiMethod);
|
||||
navigateToOverriddenMethod(e, psiMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -485,13 +493,111 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
|
||||
return overridden;
|
||||
}
|
||||
|
||||
public static String getOverriddenMethodTooltip(PsiMethod method) {
|
||||
PsiElementProcessor.CollectElementsWithLimit<PsiMethod> processor = new PsiElementProcessor.CollectElementsWithLimit<PsiMethod>(5);
|
||||
OverridingMethodsSearch.search(method, true).forEach(new PsiElementProcessorAdapter<PsiMethod>(processor));
|
||||
|
||||
boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT);
|
||||
|
||||
if (processor.isOverflow()){
|
||||
return isAbstract ? DaemonBundle.message("method.is.implemented.too.many") : DaemonBundle.message("method.is.overridden.too.many");
|
||||
}
|
||||
|
||||
PsiMethod[] javaOverridings = processor.toArray(PsiMethod.EMPTY_ARRAY);
|
||||
List<PsiMethod> filter = ContainerUtil.filter(javaOverridings, new Condition<PsiMethod>() {
|
||||
@Override
|
||||
public boolean value(PsiMethod method) {
|
||||
return !(method instanceof KotlinLightMethodFromTrait);
|
||||
}
|
||||
});
|
||||
PsiMethod[] overridings = filter.toArray(new PsiMethod[filter.size()]);
|
||||
|
||||
if (overridings.length == 0) return null;
|
||||
|
||||
Comparator<PsiMethod> comparator = new MethodCellRenderer(false).getComparator();
|
||||
Arrays.sort(overridings, comparator);
|
||||
|
||||
String start = isAbstract ? DaemonBundle.message("method.is.implemented.header") : DaemonBundle.message("method.is.overriden.header");
|
||||
@NonNls String pattern = " {1}";
|
||||
return GutterIconTooltipHelper.composeText(overridings, start, pattern);
|
||||
}
|
||||
|
||||
public static void navigateToOverriddenMethod(MouseEvent e, final PsiMethod method) {
|
||||
if (DumbService.isDumb(method.getProject())) {
|
||||
DumbService.getInstance(method.getProject()).showDumbModeNotification(
|
||||
"Navigation to overriding classes is not possible during index update");
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiElementProcessor.CollectElementsWithLimit<PsiMethod> collectProcessor =
|
||||
new PsiElementProcessor.CollectElementsWithLimit<PsiMethod>(2, new THashSet<PsiMethod>());
|
||||
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
OverridingMethodsSearch.search(method, true).forEach(new PsiElementProcessorAdapter<PsiMethod>(collectProcessor));
|
||||
}
|
||||
}, "Searching for overriding methods", true, method.getProject(), (JComponent)e.getComponent())) {
|
||||
return;
|
||||
}
|
||||
|
||||
PsiMethod[] javaOverridings = collectProcessor.toArray(PsiMethod.EMPTY_ARRAY);
|
||||
List<PsiMethod> filter = ContainerUtil.filter(javaOverridings, new Condition<PsiMethod>() {
|
||||
@Override
|
||||
public boolean value(PsiMethod method) {
|
||||
return !(method instanceof KotlinLightMethodFromTrait);
|
||||
}
|
||||
});
|
||||
PsiMethod[] overridings = filter.toArray(new PsiMethod[filter.size()]);
|
||||
|
||||
if (overridings.length == 0) return;
|
||||
boolean showMethodNames = !PsiUtil.allMethodsHaveSameSignature(overridings);
|
||||
MethodCellRenderer renderer = new MethodCellRenderer(showMethodNames);
|
||||
Arrays.sort(overridings, renderer.getComparator());
|
||||
OverridingMethodsUpdater methodsUpdater = new OverridingMethodsUpdater(method, renderer);
|
||||
PsiElementListNavigator.openTargets(e, overridings, methodsUpdater.getCaption(overridings.length), "Overriding methods of " + method.getName(), renderer, methodsUpdater);
|
||||
}
|
||||
|
||||
private static class OverridingMethodsUpdater extends ListBackgroundUpdaterTask {
|
||||
private final PsiMethod myMethod;
|
||||
private final PsiElementListCellRenderer myRenderer;
|
||||
|
||||
public OverridingMethodsUpdater(PsiMethod method, PsiElementListCellRenderer renderer) {
|
||||
super(method.getProject(), "Searching for overriding methods");
|
||||
myMethod = method;
|
||||
myRenderer = renderer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCaption(int size) {
|
||||
return myMethod.hasModifierProperty(PsiModifier.ABSTRACT) ?
|
||||
DaemonBundle.message("navigation.title.implementation.method", myMethod.getName(), size) :
|
||||
DaemonBundle.message("navigation.title.overrider.method", myMethod.getName(), size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(@NotNull final ProgressIndicator indicator) {
|
||||
super.run(indicator);
|
||||
OverridingMethodsSearch.search(myMethod, true).forEach(
|
||||
new CommonProcessors.CollectProcessor<PsiMethod>() {
|
||||
@Override
|
||||
public boolean process(PsiMethod psiMethod) {
|
||||
if (!updateComponent(psiMethod, myRenderer.getComparator())) {
|
||||
indicator.cancel();
|
||||
}
|
||||
indicator.checkCanceled();
|
||||
return super.process(psiMethod);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static class KotlinSuperNavigationHandler implements GutterIconNavigationHandler<JetElement> {
|
||||
private List<NavigatablePsiElement> testNavigableElements;
|
||||
|
||||
@TestOnly
|
||||
@NotNull
|
||||
public Collection<NavigatablePsiElement> getNavigationElements() {
|
||||
Collection<NavigatablePsiElement> navigationResult = testNavigableElements;
|
||||
public List<NavigatablePsiElement> getNavigationElements() {
|
||||
List<NavigatablePsiElement> navigationResult = testNavigableElements;
|
||||
testNavigableElements = null;
|
||||
return navigationResult;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user