201: Convert KotlinCallHierarchyBrowser and KotlinCallHierarchyBrowser

Need convert to use Kotlin typealias feature.
This commit is contained in:
Nikolay Krasko
2020-01-28 21:55:08 +03:00
committed by Nikolay Krasko
parent b795b38794
commit b92a228fb3
2 changed files with 220 additions and 253 deletions
@@ -13,88 +13,85 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.hierarchy.calls
package org.jetbrains.kotlin.idea.hierarchy.calls;
import com.intellij.ide.hierarchy.CallHierarchyBrowserBase
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor
import com.intellij.ide.hierarchy.HierarchyTreeStructure
import com.intellij.ide.hierarchy.JavaHierarchyUtil
import com.intellij.ide.util.treeView.NodeDescriptor
import com.intellij.openapi.actionSystem.ActionGroup
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.ActionPlaces
import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.ui.PopupHandler
import org.jetbrains.kotlin.psi.KtElement
import java.util.*
import javax.swing.JTree
import com.intellij.ide.hierarchy.CallHierarchyBrowserBase;
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
import com.intellij.ide.hierarchy.JavaHierarchyUtil;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.ui.PopupHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.psi.KtElement;
import javax.swing.*;
import java.util.Comparator;
import java.util.Map;
public class KotlinCallHierarchyBrowser extends CallHierarchyBrowserBase {
public KotlinCallHierarchyBrowser(@NotNull PsiElement element) {
super(element.getProject(), element);
}
@Override
protected void createTrees(@NotNull Map<String, JTree> type2TreeMap) {
ActionGroup group = (ActionGroup) ActionManager.getInstance().getAction(IdeActions.GROUP_CALL_HIERARCHY_POPUP);
JTree tree1 = createTree(false);
PopupHandler.installPopupHandler(tree1, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP, ActionManager.getInstance());
BaseOnThisMethodAction baseOnThisMethodAction = new BaseOnThisMethodAction();
class KotlinCallHierarchyBrowser(element: PsiElement) :
CallHierarchyBrowserBase(element.project, element) {
override fun createTrees(type2TreeMap: MutableMap<String, JTree>) {
val group =
ActionManager.getInstance().getAction(IdeActions.GROUP_CALL_HIERARCHY_POPUP) as ActionGroup
val tree1 = createTree(false)
PopupHandler.installPopupHandler(
tree1,
group,
ActionPlaces.CALL_HIERARCHY_VIEW_POPUP,
ActionManager.getInstance()
)
val baseOnThisMethodAction =
BaseOnThisMethodAction()
baseOnThisMethodAction.registerCustomShortcutSet(
ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).getShortcutSet(), tree1
);
type2TreeMap.put(CALLEE_TYPE, tree1);
JTree tree2 = createTree(false);
PopupHandler.installPopupHandler(tree2, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP, ActionManager.getInstance());
ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).shortcutSet,
tree1
)
type2TreeMap[CALLEE_TYPE] = tree1
val tree2 = createTree(false)
PopupHandler.installPopupHandler(
tree2,
group,
ActionPlaces.CALL_HIERARCHY_VIEW_POPUP,
ActionManager.getInstance()
)
baseOnThisMethodAction.registerCustomShortcutSet(
ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).getShortcutSet(), tree2
);
type2TreeMap.put(CALLER_TYPE, tree2);
ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).shortcutSet,
tree2
)
type2TreeMap[CALLER_TYPE] = tree2
}
private static PsiElement getTargetElement(@NotNull HierarchyNodeDescriptor descriptor) {
if (descriptor instanceof KotlinCallHierarchyNodeDescriptor) {
return descriptor.getPsiElement();
override fun getElementFromDescriptor(descriptor: HierarchyNodeDescriptor): PsiElement? {
return getTargetElement(descriptor)
}
override fun isApplicableElement(element: PsiElement): Boolean {
return if (element is PsiClass) false else isCallHierarchyElement(element) // PsiClass is not allowed at the hierarchy root
}
override fun createHierarchyTreeStructure(
typeName: String,
psiElement: PsiElement
): HierarchyTreeStructure? {
if (psiElement !is KtElement) return null
if (typeName == CALLER_TYPE) {
return KotlinCallerTreeStructure(psiElement, currentScopeType)
}
return null;
return if (typeName == CALLEE_TYPE) {
KotlinCalleeTreeStructure(psiElement, currentScopeType)
} else null
}
@Override
protected PsiElement getElementFromDescriptor(@NotNull HierarchyNodeDescriptor descriptor) {
return getTargetElement(descriptor);
override fun getComparator(): Comparator<NodeDescriptor<*>> {
return JavaHierarchyUtil.getComparator(myProject)
}
@Override
protected boolean isApplicableElement(@NotNull PsiElement element) {
if (element instanceof PsiClass) return false; // PsiClass is not allowed at the hierarchy root
return CallHierarchyUtilsKt.isCallHierarchyElement(element);
}
@Override
protected HierarchyTreeStructure createHierarchyTreeStructure(@NotNull String typeName, @NotNull PsiElement psiElement) {
if (!(psiElement instanceof KtElement)) return null;
if (typeName.equals(CALLER_TYPE)) {
return new KotlinCallerTreeStructure((KtElement) psiElement, getCurrentScopeType());
companion object {
private fun getTargetElement(descriptor: HierarchyNodeDescriptor): PsiElement? {
return (descriptor as? KotlinCallHierarchyNodeDescriptor)?.psiElement
}
if (typeName.equals(CALLEE_TYPE)) {
return new KotlinCalleeTreeStructure((KtElement) psiElement, getCurrentScopeType());
}
return null;
}
@Override
protected Comparator<NodeDescriptor> getComparator() {
return JavaHierarchyUtil.getComparator(myProject);
}
}
}
@@ -13,221 +13,191 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.hierarchy.calls
package org.jetbrains.kotlin.idea.hierarchy.calls;
import com.intellij.icons.AllIcons
import com.intellij.ide.IdeBundle
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor
import com.intellij.ide.hierarchy.call.CallHierarchyNodeDescriptor
import com.intellij.openapi.editor.markup.TextAttributes
import com.intellij.openapi.roots.ui.util.CompositeAppearance
import com.intellij.openapi.util.Comparing
import com.intellij.openapi.util.Iconable
import com.intellij.openapi.util.text.StringUtil
import com.intellij.pom.Navigatable
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.ui.LayeredIcon
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import java.awt.Font
import java.util.*
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
import com.intellij.ide.hierarchy.call.CallHierarchyNodeDescriptor;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.roots.ui.util.CompositeAppearance;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.Navigatable;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.ui.LayeredIcon;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode;
import javax.swing.*;
import java.awt.*;
import java.util.HashSet;
import java.util.Set;
public class KotlinCallHierarchyNodeDescriptor extends HierarchyNodeDescriptor implements Navigatable {
private int usageCount = 1;
private final Set<PsiReference> references = new HashSet<>();
private final CallHierarchyNodeDescriptor javaDelegate;
public KotlinCallHierarchyNodeDescriptor(
@Nullable HierarchyNodeDescriptor parentDescriptor,
@NotNull KtElement element,
boolean isBase,
boolean navigateToReference) {
super(element.getProject(), parentDescriptor, element, isBase);
this.javaDelegate = new CallHierarchyNodeDescriptor(myProject, null, element, isBase, navigateToReference);
class KotlinCallHierarchyNodeDescriptor(
parentDescriptor: HierarchyNodeDescriptor?,
element: KtElement,
isBase: Boolean,
navigateToReference: Boolean
) : HierarchyNodeDescriptor(element.project, parentDescriptor, element, isBase),
Navigatable {
private var usageCount = 1
private val references: MutableSet<PsiReference> =
HashSet()
private val javaDelegate: CallHierarchyNodeDescriptor
fun incrementUsageCount() {
usageCount++
javaDelegate.incrementUsageCount()
}
public final void incrementUsageCount() {
usageCount++;
javaDelegate.incrementUsageCount();
fun addReference(reference: PsiReference) {
references.add(reference)
javaDelegate.addReference(reference)
}
public final void addReference(PsiReference reference) {
references.add(reference);
javaDelegate.addReference(reference);
override fun isValid(): Boolean {
val myElement = psiElement
return myElement != null && myElement.isValid
}
@Override
public final boolean isValid(){
//noinspection ConstantConditions
PsiElement myElement = getPsiElement();
return myElement != null && myElement.isValid();
}
@Override
public final boolean update(){
CompositeAppearance oldText = myHighlightedText;
Icon oldIcon = getIcon();
int flags = Iconable.ICON_FLAG_VISIBILITY;
if (isMarkReadOnly()) {
flags |= Iconable.ICON_FLAG_READ_STATUS;
override fun update(): Boolean {
val oldText = myHighlightedText
val oldIcon = icon
var flags = Iconable.ICON_FLAG_VISIBILITY
if (isMarkReadOnly) {
flags = flags or Iconable.ICON_FLAG_READ_STATUS
}
boolean changes = super.update();
PsiElement targetElement = getPsiElement();
String elementText = renderElement(targetElement);
var changes = super.update()
val targetElement = psiElement
val elementText = renderElement(targetElement)
if (elementText == null) {
String invalidPrefix = IdeBundle.message("node.hierarchy.invalid");
if (!myHighlightedText.getText().startsWith(invalidPrefix)) {
myHighlightedText.getBeginning().addText(invalidPrefix, HierarchyNodeDescriptor.getInvalidPrefixAttributes());
val invalidPrefix = IdeBundle.message("node.hierarchy.invalid")
if (!myHighlightedText.text.startsWith(invalidPrefix)) {
myHighlightedText.beginning
.addText(invalidPrefix, getInvalidPrefixAttributes())
}
return true;
return true
}
Icon newIcon = targetElement.getIcon(flags);
var newIcon = targetElement!!.getIcon(flags)
if (changes && myIsBase) {
LayeredIcon icon = new LayeredIcon(2);
icon.setIcon(newIcon, 0);
icon.setIcon(AllIcons.General.Modified, 1, -AllIcons.General.Modified.getIconWidth() / 2, 0);
newIcon = icon;
val icon = LayeredIcon(2)
icon.setIcon(newIcon, 0)
icon.setIcon(AllIcons.General.Modified, 1, -AllIcons.General.Modified.iconWidth / 2, 0)
newIcon = icon
}
setIcon(newIcon);
myHighlightedText = new CompositeAppearance();
TextAttributes mainTextAttributes = null;
icon = newIcon
myHighlightedText = CompositeAppearance()
var mainTextAttributes: TextAttributes? = null
if (myColor != null) {
mainTextAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN);
mainTextAttributes = TextAttributes(myColor, null, null, null, Font.PLAIN)
}
String packageName = KtPsiUtil.getPackageName((KtElement) targetElement);
myHighlightedText.getEnding().addText(elementText, mainTextAttributes);
var packageName =
KtPsiUtil.getPackageName((targetElement as KtElement?)!!)
myHighlightedText.ending.addText(elementText, mainTextAttributes)
if (usageCount > 1) {
myHighlightedText.getEnding().addText(
IdeBundle.message("node.call.hierarchy.N.usages", usageCount),
HierarchyNodeDescriptor.getUsageCountPrefixAttributes()
);
myHighlightedText.ending.addText(
IdeBundle.message("node.call.hierarchy.N.usages", usageCount),
getUsageCountPrefixAttributes()
)
}
if (packageName == null) {
packageName = "";
packageName = ""
}
myHighlightedText.getEnding().addText(" (" + packageName + ")", HierarchyNodeDescriptor.getPackageNameAttributes());
myName = myHighlightedText.getText();
if (!(Comparing.equal(myHighlightedText, oldText) && Comparing.equal(getIcon(), oldIcon))) {
changes = true;
myHighlightedText.ending
.addText(" ($packageName)", getPackageNameAttributes())
myName = myHighlightedText.text
if (!(Comparing.equal(myHighlightedText, oldText) && Comparing.equal(icon, oldIcon))
) {
changes = true
}
return changes;
return changes
}
@Nullable
private static String renderElement(@Nullable PsiElement element) {
if (element instanceof KtFile) {
return ((KtFile) element).getName();
}
override fun navigate(requestFocus: Boolean) {
javaDelegate.navigate(requestFocus)
}
if (!(element instanceof KtNamedDeclaration)) {
return null;
}
override fun canNavigate(): Boolean {
return javaDelegate.canNavigate()
}
DeclarationDescriptor descriptor = ResolutionUtils.resolveToDescriptorIfAny((KtNamedDeclaration) element, BodyResolveMode.PARTIAL);
if (descriptor == null) return null;
override fun canNavigateToSource(): Boolean {
return javaDelegate.canNavigateToSource()
}
String elementText;
if (element instanceof KtClassOrObject) {
if (element instanceof KtObjectDeclaration && ((KtObjectDeclaration) element).isCompanion()) {
descriptor = descriptor.getContainingDeclaration();
if (!(descriptor instanceof ClassDescriptor)) return null;
elementText = renderClassOrObject((ClassDescriptor) descriptor);
companion object {
private fun renderElement(element: PsiElement?): String? {
if (element is KtFile) {
return element.name
}
else if (element instanceof KtEnumEntry) {
elementText = ((KtEnumEntry) element).getName();
if (element !is KtNamedDeclaration) {
return null
}
else {
if (((KtClassOrObject) element).getName() != null) {
elementText = renderClassOrObject((ClassDescriptor) descriptor);
var descriptor: DeclarationDescriptor? =
element as KtNamedDeclaration?. resolveToDescriptorIfAny BodyResolveMode.PARTIAL
?: return null
val elementText: String?
if (element is KtClassOrObject) {
if (element is KtObjectDeclaration && element.isCompanion()) {
descriptor = descriptor.containingDeclaration
if (descriptor !is ClassDescriptor) return null
elementText = renderClassOrObject(descriptor)
} else if (element is KtEnumEntry) {
elementText = element.name
} else {
elementText = if (element.name != null) {
renderClassOrObject(descriptor as ClassDescriptor)
} else {
"[anonymous]"
}
}
else {
elementText = "[anonymous]";
} else if (element is KtNamedFunction || element is KtConstructor<*>) {
if (descriptor !is FunctionDescriptor) return null
elementText = renderNamedFunction(descriptor)
} else if (element is KtProperty) {
elementText = element.name
} else return null
if (elementText == null) return null
var containerText: String? = null
var containerDescriptor = descriptor.containingDeclaration
while (containerDescriptor != null) {
if (containerDescriptor is PackageFragmentDescriptor || containerDescriptor is ModuleDescriptor) {
break
}
val name = containerDescriptor.name
if (!name.isSpecial) {
val identifier = name.identifier
containerText = if (containerText != null) "$identifier.$containerText" else identifier
}
containerDescriptor = containerDescriptor.containingDeclaration
}
}
else if ((element instanceof KtNamedFunction || element instanceof KtConstructor)) {
if (!(descriptor instanceof FunctionDescriptor)) return null;
elementText = renderNamedFunction((FunctionDescriptor) descriptor);
}
else if (element instanceof KtProperty) {
elementText = ((KtProperty) element).getName();
}
else return null;
if (elementText == null) return null;
String containerText = null;
DeclarationDescriptor containerDescriptor = descriptor.getContainingDeclaration();
while (containerDescriptor != null) {
if (containerDescriptor instanceof PackageFragmentDescriptor || containerDescriptor instanceof ModuleDescriptor) {
break;
}
Name name = containerDescriptor.getName();
if (!name.isSpecial()) {
String identifier = name.getIdentifier();
containerText = containerText != null ? identifier + "." + containerText : identifier;
}
containerDescriptor = containerDescriptor.getContainingDeclaration();
return if (containerText != null) "$containerText.$elementText" else elementText
}
return containerText != null ? containerText + "." + elementText : elementText;
}
fun renderNamedFunction(descriptor: FunctionDescriptor): String {
val descriptorForName: DeclarationDescriptor =
(descriptor as? ConstructorDescriptor)?.containingDeclaration ?: descriptor
val name = descriptorForName.name.asString()
val paramTypes =
StringUtil.join(
descriptor.valueParameters,
{ descriptor1: ValueParameterDescriptor ->
DescriptorRenderer
.SHORT_NAMES_IN_TYPES
.renderType(descriptor1.type)
},
", "
)
return "$name($paramTypes)"
}
public static String renderNamedFunction(@NotNull FunctionDescriptor descriptor) {
DeclarationDescriptor descriptorForName = descriptor instanceof ConstructorDescriptor
? descriptor.getContainingDeclaration()
: descriptor;
String name = descriptorForName.getName().asString();
String paramTypes = StringUtil.join(
descriptor.getValueParameters(),
descriptor1 -> DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(descriptor1.getType()),
", "
);
return name + "(" + paramTypes + ")";
private fun renderClassOrObject(descriptor: ClassDescriptor): String {
return descriptor.name.asString()
}
}
private static String renderClassOrObject(ClassDescriptor descriptor) {
return descriptor.getName().asString();
init {
javaDelegate = CallHierarchyNodeDescriptor(myProject, null, element, isBase, navigateToReference)
}
@Override
public void navigate(boolean requestFocus) {
javaDelegate.navigate(requestFocus);
}
@Override
public boolean canNavigate() {
return javaDelegate.canNavigate();
}
@Override
public boolean canNavigateToSource() {
return javaDelegate.canNavigateToSource();
}
}
}