Change Signature: Implement parameter propagation UI
#KT-7902 In progress
This commit is contained in:
+1
-1
@@ -211,7 +211,7 @@ public class KotlinCallHierarchyNodeDescriptor extends HierarchyNodeDescriptor i
|
||||
return containerText != null ? containerText + "." + elementText : elementText;
|
||||
}
|
||||
|
||||
private static String renderNamedFunction(FunctionDescriptor descriptor) {
|
||||
public static String renderNamedFunction(FunctionDescriptor descriptor) {
|
||||
DeclarationDescriptor descriptorForName = descriptor instanceof ConstructorDescriptor
|
||||
? descriptor.getContainingDeclaration()
|
||||
: descriptor;
|
||||
|
||||
+55
-40
@@ -187,29 +187,39 @@ public class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStructure {
|
||||
private Processor<PsiReference> defaultQueryProcessor(
|
||||
final HierarchyNodeDescriptor descriptor,
|
||||
final Map<PsiElement, HierarchyNodeDescriptor> methodToDescriptorMap,
|
||||
final boolean kotlinOnly
|
||||
boolean kotlinOnly
|
||||
) {
|
||||
return new ReadActionProcessor<PsiReference>() {
|
||||
return new CalleeReferenceProcessor(kotlinOnly) {
|
||||
@Override
|
||||
public boolean processInReadAction(PsiReference ref) {
|
||||
// copied from Java
|
||||
if (!(ref instanceof PsiReferenceExpression || ref instanceof JetReference)) {
|
||||
if (!(ref instanceof PsiElement)) {
|
||||
protected void onAccept(@NotNull PsiReference ref, @NotNull PsiElement element) {
|
||||
addNodeDescriptorForElement(ref, element, methodToDescriptorMap, descriptor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static abstract class CalleeReferenceProcessor extends ReadActionProcessor<PsiReference> {
|
||||
private final boolean kotlinOnly;
|
||||
|
||||
public CalleeReferenceProcessor(boolean only) {
|
||||
kotlinOnly = only;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processInReadAction(PsiReference ref) {
|
||||
// copied from Java
|
||||
if (!(ref instanceof PsiReferenceExpression || ref instanceof JetReference)) {
|
||||
if (!(ref instanceof PsiElement)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PsiElement parent = ((PsiElement) ref).getParent();
|
||||
if (parent instanceof PsiNewExpression) {
|
||||
if (((PsiNewExpression) parent).getClassReference() != ref) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PsiElement parent = ((PsiElement) ref).getParent();
|
||||
if (parent instanceof PsiNewExpression) {
|
||||
if (((PsiNewExpression) parent).getClassReference() != ref) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (parent instanceof PsiAnonymousClass) {
|
||||
if (((PsiAnonymousClass) parent).getBaseClassReference() != ref) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
}
|
||||
else if (parent instanceof PsiAnonymousClass) {
|
||||
if (((PsiAnonymousClass) parent).getBaseClassReference() != ref) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -218,28 +228,33 @@ public class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStructure {
|
||||
// Accept implicit superclass constructor reference in Java code
|
||||
if (!(refTarget instanceof PsiMethod && ((PsiMethod) refTarget).isConstructor())) return true;
|
||||
}
|
||||
|
||||
PsiElement refElement = ref.getElement();
|
||||
if (PsiTreeUtil.getParentOfType(refElement, JetImportDirective.class, true) != null) return true;
|
||||
|
||||
PsiElement element = HierarchyUtils.getCallHierarchyElement(refElement);
|
||||
|
||||
if (kotlinOnly && !(element instanceof JetNamedDeclaration)) return true;
|
||||
|
||||
// If reference belongs to property initializer, show enclosing declaration instead
|
||||
if (element instanceof JetProperty) {
|
||||
JetProperty property = (JetProperty) element;
|
||||
if (PsiTreeUtil.isAncestor(property.getInitializer(), refElement, false)) {
|
||||
element = HierarchyUtils.getCallHierarchyElement(element.getParent());
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (element != null) {
|
||||
addNodeDescriptorForElement(ref, element, methodToDescriptorMap, descriptor);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
PsiElement refElement = ref.getElement();
|
||||
if (PsiTreeUtil.getParentOfType(refElement, JetImportDirective.class, true) != null) return true;
|
||||
|
||||
PsiElement element = HierarchyUtils.getCallHierarchyElement(refElement);
|
||||
|
||||
if (kotlinOnly && !(element instanceof JetNamedDeclaration)) return true;
|
||||
|
||||
// If reference belongs to property initializer, show enclosing declaration instead
|
||||
if (element instanceof JetProperty) {
|
||||
JetProperty property = (JetProperty) element;
|
||||
if (PsiTreeUtil.isAncestor(property.getInitializer(), refElement, false)) {
|
||||
element = HierarchyUtils.getCallHierarchyElement(element.getParent());
|
||||
}
|
||||
}
|
||||
|
||||
if (element != null) {
|
||||
onAccept(ref, element);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract void onAccept(@NotNull PsiReference ref, @NotNull PsiElement element);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -155,8 +155,8 @@ public class JetChangeSignatureDialog(
|
||||
return true
|
||||
}
|
||||
|
||||
override fun createCallerChooser(title: String, treeToReuse: Tree, callback: Consumer<Set<PsiElement>>) =
|
||||
throw UnsupportedOperationException()
|
||||
override fun createCallerChooser(title: String, treeToReuse: Tree?, callback: Consumer<Set<PsiElement>>) =
|
||||
KotlinCallerChooser(myMethod.getMethod(), myProject, title, treeToReuse, callback)
|
||||
|
||||
override fun getTableEditor(table: JTable, item: ParameterTableModelItemBase<JetParameterInfo>): JBTableRowEditor? {
|
||||
return object : JBTableRowEditor() {
|
||||
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.idea.refactoring.changeSignature.ui
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiClassOwner
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.search.searches.MethodReferencesSearch
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.refactoring.changeSignature.CallerChooserBase
|
||||
import com.intellij.refactoring.changeSignature.MethodNodeBase
|
||||
import com.intellij.ui.ColoredTreeCellRenderer
|
||||
import com.intellij.ui.JBColor
|
||||
import com.intellij.ui.SimpleTextAttributes
|
||||
import com.intellij.ui.treeStructure.Tree
|
||||
import com.intellij.util.Consumer
|
||||
import com.intellij.util.containers
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import org.jetbrains.kotlin.asJava.getRepresentativeLightMethod
|
||||
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.JetFileType
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getJavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.hierarchy.calls.KotlinCallHierarchyNodeDescriptor
|
||||
import org.jetbrains.kotlin.idea.hierarchy.calls.KotlinCallerMethodsTreeStructure
|
||||
import org.jetbrains.kotlin.psi.JetClass
|
||||
import org.jetbrains.kotlin.psi.JetFunction
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import java.util.HashSet
|
||||
import java.util.LinkedHashSet
|
||||
|
||||
public class KotlinCallerChooser(
|
||||
declaration: PsiElement,
|
||||
project: Project,
|
||||
title: String,
|
||||
previousTree: Tree?,
|
||||
callback: Consumer<Set<PsiElement>>
|
||||
): CallerChooserBase<PsiElement>(declaration, project, title, previousTree, "dummy." + JetFileType.EXTENSION, callback) {
|
||||
override fun createTreeNode(method: PsiElement?, called: containers.HashSet<PsiElement>, cancelCallback: Runnable): KotlinMethodNode {
|
||||
return KotlinMethodNode(method, called, myProject, cancelCallback)
|
||||
}
|
||||
|
||||
override fun findDeepestSuperMethods(method: PsiElement) =
|
||||
method.toLightMethods().singleOrNull()?.findDeepestSuperMethods()
|
||||
|
||||
override fun getEmptyCallerText() =
|
||||
"Caller text \nwith highlighted callee call would be shown here"
|
||||
|
||||
override fun getEmptyCalleeText() =
|
||||
"Callee text would be shown here"
|
||||
}
|
||||
|
||||
public class KotlinMethodNode(
|
||||
method: PsiElement?,
|
||||
called: HashSet<PsiElement>,
|
||||
project: Project,
|
||||
cancelCallback: Runnable
|
||||
): MethodNodeBase<PsiElement>(method?.namedUnwrappedElement ?: method, called, project, cancelCallback) {
|
||||
override fun createNode(caller: PsiElement, called: HashSet<PsiElement>) =
|
||||
KotlinMethodNode(caller, called, myProject, myCancelCallback)
|
||||
|
||||
override fun customizeRendererText(renderer: ColoredTreeCellRenderer) {
|
||||
val descriptor = when (myMethod) {
|
||||
is JetFunction -> myMethod.resolveToDescriptor() as FunctionDescriptor
|
||||
is JetClass -> (myMethod.resolveToDescriptor() as ClassDescriptor).getUnsubstitutedPrimaryConstructor() ?: return
|
||||
is PsiMethod -> myMethod.getJavaMethodDescriptor()
|
||||
else -> throw AssertionError("Invalid declaration: ${myMethod.getElementTextWithContext()}")
|
||||
}
|
||||
val containerName = sequence<DeclarationDescriptor>(descriptor) { it.getContainingDeclaration() }
|
||||
.firstOrNull { it is ClassDescriptor }
|
||||
?.getName()
|
||||
|
||||
val renderedFunction = KotlinCallHierarchyNodeDescriptor.renderNamedFunction(descriptor)
|
||||
val renderedFunctionWithContainer =
|
||||
containerName?.let {
|
||||
"${if (it.isSpecial()) "[Anonymous]" else it.asString()}.$renderedFunction"
|
||||
} ?: renderedFunction
|
||||
|
||||
val attributes = if (isEnabled())
|
||||
SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, UIUtil.getTreeForeground())
|
||||
else
|
||||
SimpleTextAttributes.EXCLUDED_ATTRIBUTES
|
||||
renderer.append(renderedFunctionWithContainer, attributes)
|
||||
|
||||
val packageName = (myMethod.getContainingFile() as? PsiClassOwner)?.getPackageName() ?: ""
|
||||
renderer.append(" ($packageName)", SimpleTextAttributes(SimpleTextAttributes.STYLE_ITALIC, JBColor.GRAY))
|
||||
}
|
||||
|
||||
override fun computeCallers(): List<PsiElement> {
|
||||
if (myMethod == null) return emptyList()
|
||||
|
||||
val callers = LinkedHashSet<PsiElement>()
|
||||
|
||||
val processor = object: KotlinCallerMethodsTreeStructure.CalleeReferenceProcessor(false) {
|
||||
override fun onAccept(ref: PsiReference, element: PsiElement) {
|
||||
if ((element is JetFunction || element is JetClass || element is PsiMethod) && element !in myCalled) {
|
||||
callers.add(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
val query = myMethod.getRepresentativeLightMethod()?.let { MethodReferencesSearch.search(it, it.getUseScope(), true) }
|
||||
?: ReferencesSearch.search(myMethod, myMethod.getUseScope())
|
||||
query.forEach { processor.process(it) }
|
||||
return callers.toList()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user