Support "Find usages" for declarations contained in the library
#KT-4452 Fixed
This commit is contained in:
@@ -31,8 +31,13 @@ import org.jetbrains.jet.plugin.findUsages.handlers.KotlinTypeParameterFindUsage
|
||||
import org.jetbrains.jet.lang.psi.JetParameter
|
||||
import org.jetbrains.jet.lang.psi.JetNamedDeclaration
|
||||
import org.jetbrains.jet.lang.psi.JetClassOrObject
|
||||
import com.intellij.find.findUsages.FindUsagesManager
|
||||
import com.intellij.find.findUsages.JavaFindUsagesHandlerFactory
|
||||
import com.intellij.psi.PsiMethod
|
||||
|
||||
public class KotlinFindUsagesHandlerFactory(project: Project) : FindUsagesHandlerFactory() {
|
||||
val javaHandlerFactory = JavaFindUsagesHandlerFactory(project)
|
||||
|
||||
val findFunctionOptions = KotlinFunctionFindUsagesOptions(project)
|
||||
val findPropertyOptions = KotlinPropertyFindUsagesOptions(project)
|
||||
val findClassOptions = KotlinClassFindUsagesOptions(project)
|
||||
@@ -45,7 +50,7 @@ public class KotlinFindUsagesHandlerFactory(project: Project) : FindUsagesHandle
|
||||
element is JetParameter ||
|
||||
element is JetTypeParameter
|
||||
|
||||
public override fun createFindUsagesHandler(element: PsiElement, forHighlightUsages: Boolean): FindUsagesHandler {
|
||||
public override fun createFindUsagesHandler(element: PsiElement, forHighlightUsages: Boolean): FindUsagesHandler? {
|
||||
when(element) {
|
||||
is JetClassOrObject ->
|
||||
return KotlinFindClassUsagesHandler(element, this)
|
||||
@@ -56,13 +61,21 @@ public class KotlinFindUsagesHandlerFactory(project: Project) : FindUsagesHandle
|
||||
return if (forHighlightUsages) KotlinFindMemberUsagesHandler.getInstance(declaration, this)
|
||||
else JetRefactoringUtil.checkSuperMethods(declaration, null, "super.methods.action.key.find.usages")?.let { callables ->
|
||||
when (callables.size()) {
|
||||
0 -> null
|
||||
1 ->
|
||||
KotlinFindMemberUsagesHandler.getInstance(callables.get(0) as JetNamedDeclaration, this)
|
||||
0 -> FindUsagesHandler.NULL_HANDLER
|
||||
1 -> {
|
||||
val callable = callables.get(0)
|
||||
when (callable) {
|
||||
is JetNamedDeclaration ->
|
||||
KotlinFindMemberUsagesHandler.getInstance(callable, this)
|
||||
is PsiMethod ->
|
||||
javaHandlerFactory.createFindUsagesHandler(callable, forHighlightUsages)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
else ->
|
||||
KotlinFindMemberUsagesHandler.getInstance(declaration, callables, this)
|
||||
}
|
||||
} ?: FindUsagesHandler.NULL_HANDLER
|
||||
}
|
||||
}
|
||||
|
||||
is JetTypeParameter ->
|
||||
|
||||
@@ -19,13 +19,14 @@ package org.jetbrains.jet.plugin.refactoring;
|
||||
import com.intellij.codeInsight.unwrap.ScopeHighlighter;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.popup.JBPopupAdapter;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.searches.DeepestSuperMethodsSearch;
|
||||
import com.intellij.psi.util.PsiFormatUtil;
|
||||
import com.intellij.psi.util.PsiFormatUtilBase;
|
||||
import com.intellij.ui.components.JBList;
|
||||
@@ -33,12 +34,12 @@ import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.asJava.LightClassUtil;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.OverridingUtil;
|
||||
import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.PackageType;
|
||||
@@ -48,6 +49,7 @@ import org.jetbrains.jet.lexer.JetKeywordToken;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.jet.plugin.JetBundle;
|
||||
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils;
|
||||
import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil;
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||
|
||||
@@ -111,89 +113,48 @@ public class JetRefactoringUtil {
|
||||
return markAsJava ? "[Java] " + description : description;
|
||||
}
|
||||
|
||||
private static PsiElement toJetDeclarationOrMethod(PsiMethod method) {
|
||||
return (method instanceof KotlinLightMethod) ? ((KotlinLightMethod) method).getOrigin() : method;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<? extends PsiElement> getFunctionSuperDeclarations(@NotNull JetNamedFunction function) {
|
||||
PsiMethod lightMethod = LightClassUtil.getLightClassMethod(function);
|
||||
if (lightMethod == null) return Collections.emptyList();
|
||||
|
||||
return ContainerUtil.map(
|
||||
DeepestSuperMethodsSearch.search(lightMethod).findAll(),
|
||||
new Function<PsiMethod, PsiElement>() {
|
||||
@Override
|
||||
public PsiElement fun(PsiMethod method) {
|
||||
return toJetDeclarationOrMethod(method);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<? extends PsiElement> getPropertySuperDeclarations(@NotNull JetDeclaration declaration) {
|
||||
LightClassUtil.PropertyAccessorsPsiMethods lightMethods;
|
||||
if (declaration instanceof JetProperty) {
|
||||
lightMethods = LightClassUtil.getLightClassPropertyMethods((JetProperty) declaration);
|
||||
}
|
||||
else if (declaration instanceof JetParameter) {
|
||||
lightMethods = LightClassUtil.getLightClassPropertyMethods((JetParameter) declaration);
|
||||
}
|
||||
else return Collections.emptyList();
|
||||
|
||||
Collection<PsiMethod> foundMethods = new HashSet<PsiMethod>();
|
||||
if (lightMethods.getGetter() != null) {
|
||||
foundMethods.addAll(DeepestSuperMethodsSearch.search(lightMethods.getGetter()).findAll());
|
||||
}
|
||||
if (lightMethods.getSetter() != null) {
|
||||
foundMethods.addAll(DeepestSuperMethodsSearch.search(lightMethods.getSetter()).findAll());
|
||||
}
|
||||
|
||||
Set<PsiElement> declarations = new HashSet<PsiElement>();
|
||||
for (PsiMethod method : foundMethods) {
|
||||
declarations.add(toJetDeclarationOrMethod(method));
|
||||
}
|
||||
|
||||
return new ArrayList<PsiElement>(declarations);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<? extends PsiElement> getSuperDeclarations(@NotNull JetDeclaration declaration) {
|
||||
if (declaration instanceof JetNamedFunction) return getFunctionSuperDeclarations((JetNamedFunction) declaration);
|
||||
if (declaration instanceof JetProperty || declaration instanceof JetParameter) return getPropertySuperDeclarations(declaration);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static List<? extends PsiElement> checkSuperMethods(
|
||||
@NotNull JetDeclaration declaration, @Nullable Collection<PsiElement> ignore, @NotNull String actionStringKey
|
||||
) {
|
||||
BindingContext bindingContext =
|
||||
AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) declaration.getContainingFile()).getBindingContext();
|
||||
final BindingContext bindingContext = AnalyzerFacadeWithCache.getContextForElement(declaration);
|
||||
|
||||
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration);
|
||||
CallableDescriptor declarationDescriptor =
|
||||
(CallableDescriptor)bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration);
|
||||
|
||||
if (declarationDescriptor instanceof LocalVariableDescriptor) {
|
||||
if (declarationDescriptor == null || declarationDescriptor instanceof LocalVariableDescriptor) {
|
||||
return Collections.singletonList(declaration);
|
||||
}
|
||||
|
||||
List<? extends PsiElement> superDeclarations = getSuperDeclarations(declaration);
|
||||
final Project project = declaration.getProject();
|
||||
Map<PsiElement, CallableDescriptor> overriddenElementsToDescriptor = ContainerUtil.map2Map(
|
||||
OverridingUtil.getAllOverriddenDescriptors(declarationDescriptor),
|
||||
new Function<CallableDescriptor, Pair<PsiElement, CallableDescriptor>>() {
|
||||
@Override
|
||||
public Pair<PsiElement, CallableDescriptor> fun(CallableDescriptor descriptor) {
|
||||
return new Pair<PsiElement, CallableDescriptor>(
|
||||
DescriptorToDeclarationUtil.getDeclaration(project, descriptor, bindingContext),
|
||||
descriptor
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
overriddenElementsToDescriptor.remove(null);
|
||||
if (ignore != null) {
|
||||
superDeclarations.removeAll(ignore);
|
||||
overriddenElementsToDescriptor.keySet().removeAll(ignore);
|
||||
}
|
||||
|
||||
if (superDeclarations.isEmpty()) return Collections.singletonList(declaration);
|
||||
if (overriddenElementsToDescriptor.isEmpty()) return Collections.singletonList(declaration);
|
||||
|
||||
java.util.List<String> superClasses = getClassDescriptions(bindingContext, superDeclarations);
|
||||
return askUserForMethodsToSearch(declaration, declarationDescriptor, superDeclarations, superClasses, actionStringKey);
|
||||
List<String> superClasses = getClassDescriptions(overriddenElementsToDescriptor);
|
||||
return askUserForMethodsToSearch(declaration, declarationDescriptor, overriddenElementsToDescriptor, superClasses, actionStringKey);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<? extends PsiElement> askUserForMethodsToSearch(
|
||||
@NotNull JetDeclaration declaration,
|
||||
@NotNull DeclarationDescriptor declarationDescriptor,
|
||||
@NotNull List<? extends PsiElement> superMethods,
|
||||
@NotNull CallableDescriptor declarationDescriptor,
|
||||
@NotNull Map<PsiElement, CallableDescriptor> overriddenElementsToDescriptor,
|
||||
@NotNull List<String> superClasses,
|
||||
@NotNull String actionStringKey
|
||||
) {
|
||||
@@ -211,7 +172,7 @@ public class JetRefactoringUtil {
|
||||
);
|
||||
switch (exitCode) {
|
||||
case Messages.YES:
|
||||
return superMethods;
|
||||
return ContainerUtil.newArrayList(overriddenElementsToDescriptor.keySet());
|
||||
case Messages.NO:
|
||||
return Collections.singletonList(declaration);
|
||||
default:
|
||||
@@ -220,31 +181,24 @@ public class JetRefactoringUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<String> getClassDescriptions(
|
||||
@NotNull final BindingContext bindingContext, @NotNull Collection<? extends PsiElement> superMethods
|
||||
) {
|
||||
private static List<String> getClassDescriptions(@NotNull Map<PsiElement, CallableDescriptor> overriddenElementsToDescriptor) {
|
||||
return ContainerUtil.map(
|
||||
superMethods,
|
||||
new Function<PsiElement, String>() {
|
||||
overriddenElementsToDescriptor.entrySet(),
|
||||
new Function<Map.Entry<PsiElement, CallableDescriptor>, String>() {
|
||||
@Override
|
||||
public String fun(PsiElement element) {
|
||||
public String fun(Map.Entry<PsiElement, CallableDescriptor> entry) {
|
||||
String description;
|
||||
|
||||
PsiElement element = entry.getKey();
|
||||
CallableDescriptor descriptor = entry.getValue();
|
||||
if (element instanceof JetNamedFunction || element instanceof JetProperty) {
|
||||
DeclarationDescriptor descriptor =
|
||||
bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
|
||||
assert descriptor != null;
|
||||
|
||||
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
|
||||
assert containingDescriptor != null;
|
||||
|
||||
description = formatClassDescriptor(containingDescriptor);
|
||||
description = formatClassDescriptor(descriptor.getContainingDeclaration());
|
||||
}
|
||||
else {
|
||||
assert element instanceof PsiMethod;
|
||||
assert element instanceof PsiMethod : "Invalid element: " + element.getText();
|
||||
|
||||
PsiClass psiClass = ((PsiMethod) element).getContainingClass();
|
||||
assert psiClass != null;
|
||||
assert psiClass != null : "Invalid element: " + element.getText();
|
||||
|
||||
description = formatPsiClass(psiClass, true, false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user