Method Hierarchy: Refactoring
- Do not rely on light methods and Java method hierarchy - Support val/var parameters - Support built-in member functions #KT-14346 Fixed
This commit is contained in:
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.asJava
|
|||||||
|
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.util.IncorrectOperationException
|
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotationForSourceEntry
|
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotationForSourceEntry
|
||||||
@@ -30,6 +29,7 @@ import org.jetbrains.kotlin.load.java.propertyNameByGetMethodName
|
|||||||
import org.jetbrains.kotlin.load.java.propertyNameBySetMethodName
|
import org.jetbrains.kotlin.load.java.propertyNameBySetMethodName
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
@@ -37,6 +37,15 @@ import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
|
|||||||
|
|
||||||
fun KtClassOrObject.toLightClass(): KtLightClass? = LightClassGenerationSupport.getInstance(project).getLightClass(this)
|
fun KtClassOrObject.toLightClass(): KtLightClass? = LightClassGenerationSupport.getInstance(project).getLightClass(this)
|
||||||
|
|
||||||
|
fun KtClassOrObject.toLightClassWithBuiltinMapping(): PsiClass? {
|
||||||
|
toLightClass()?.let { return it }
|
||||||
|
|
||||||
|
val fqName = fqName ?: return null
|
||||||
|
val javaClassFqName = JavaToKotlinClassMap.mapKotlinToJava(fqName.toUnsafe())?.asSingleFqName() ?: return null
|
||||||
|
val searchScope = useScope as? GlobalSearchScope ?: return null
|
||||||
|
return JavaPsiFacade.getInstance(project).findClass(javaClassFqName.asString(), searchScope)
|
||||||
|
}
|
||||||
|
|
||||||
fun KtFile.findFacadeClass(): KtLightClass? {
|
fun KtFile.findFacadeClass(): KtLightClass? {
|
||||||
return LightClassGenerationSupport.getInstance(project)
|
return LightClassGenerationSupport.getInstance(project)
|
||||||
.getFacadeClassesInPackage(packageFqName, this.useScope as? GlobalSearchScope ?: GlobalSearchScope.projectScope(project))
|
.getFacadeClassesInPackage(packageFqName, this.useScope as? GlobalSearchScope ?: GlobalSearchScope.projectScope(project))
|
||||||
|
|||||||
+2
-2
@@ -22,13 +22,13 @@ import com.intellij.psi.PsiModifier
|
|||||||
import com.intellij.psi.search.searches.ClassInheritorsSearch
|
import com.intellij.psi.search.searches.ClassInheritorsSearch
|
||||||
import com.intellij.util.EmptyQuery
|
import com.intellij.util.EmptyQuery
|
||||||
import com.intellij.util.Query
|
import com.intellij.util.Query
|
||||||
import org.jetbrains.kotlin.asJava.toLightClass
|
import org.jetbrains.kotlin.asJava.toLightClassWithBuiltinMapping
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
|
||||||
fun HierarchySearchRequest<*>.searchInheritors(): Query<PsiClass> {
|
fun HierarchySearchRequest<*>.searchInheritors(): Query<PsiClass> {
|
||||||
val psiClass: PsiClass = when (originalElement) {
|
val psiClass: PsiClass = when (originalElement) {
|
||||||
is KtClassOrObject -> runReadAction { originalElement.toLightClass() }
|
is KtClassOrObject -> runReadAction { originalElement.toLightClassWithBuiltinMapping() }
|
||||||
is PsiClass -> originalElement
|
is PsiClass -> originalElement
|
||||||
else -> null
|
else -> null
|
||||||
} ?: return EmptyQuery.getEmptyQuery()
|
} ?: return EmptyQuery.getEmptyQuery()
|
||||||
|
|||||||
+27
-11
@@ -16,23 +16,42 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.hierarchy.overrides
|
package org.jetbrains.kotlin.idea.hierarchy.overrides
|
||||||
|
|
||||||
|
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor
|
||||||
import com.intellij.ide.hierarchy.HierarchyTreeStructure
|
import com.intellij.ide.hierarchy.HierarchyTreeStructure
|
||||||
|
import com.intellij.ide.hierarchy.JavaHierarchyUtil
|
||||||
import com.intellij.ide.hierarchy.MethodHierarchyBrowserBase
|
import com.intellij.ide.hierarchy.MethodHierarchyBrowserBase
|
||||||
import com.intellij.ide.hierarchy.method.MethodHierarchyBrowser
|
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.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.ElementDescriptionUtil
|
import com.intellij.psi.ElementDescriptionUtil
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiMethod
|
import com.intellij.ui.PopupHandler
|
||||||
import com.intellij.usageView.UsageViewLongNameLocation
|
import com.intellij.usageView.UsageViewLongNameLocation
|
||||||
import org.jetbrains.kotlin.asJava.getRepresentativeLightMethod
|
|
||||||
import org.jetbrains.kotlin.asJava.unwrapped
|
import org.jetbrains.kotlin.asJava.unwrapped
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
import javax.swing.JPanel
|
import javax.swing.JPanel
|
||||||
|
import javax.swing.JTree
|
||||||
|
|
||||||
class KotlinOverrideHierarchyBrowser(
|
class KotlinOverrideHierarchyBrowser(
|
||||||
project: Project, baseElement: PsiElement
|
project: Project, baseElement: PsiElement
|
||||||
) : MethodHierarchyBrowser(project, baseElement.getRepresentativeLightMethod()) {
|
) : MethodHierarchyBrowserBase(project, baseElement) {
|
||||||
|
override fun createTrees(trees: MutableMap<String, JTree>) {
|
||||||
|
val actionManager = ActionManager.getInstance()
|
||||||
|
|
||||||
|
val tree = createTree(false)
|
||||||
|
|
||||||
|
val group = actionManager.getAction(IdeActions.GROUP_METHOD_HIERARCHY_POPUP) as ActionGroup
|
||||||
|
PopupHandler.installPopupHandler(tree, group, ActionPlaces.METHOD_HIERARCHY_VIEW_POPUP, actionManager)
|
||||||
|
|
||||||
|
BaseOnThisMethodAction().registerCustomShortcutSet(actionManager.getAction(IdeActions.ACTION_METHOD_HIERARCHY).shortcutSet, tree)
|
||||||
|
|
||||||
|
trees.put(MethodHierarchyBrowserBase.METHOD_TYPE, tree)
|
||||||
|
}
|
||||||
|
|
||||||
override fun createLegendPanel(): JPanel? =
|
override fun createLegendPanel(): JPanel? =
|
||||||
MethodHierarchyBrowserBase.createStandardLegendPanel(
|
MethodHierarchyBrowserBase.createStandardLegendPanel(
|
||||||
KotlinBundle.message("hierarchy.legend.member.is.defined.in.class"),
|
KotlinBundle.message("hierarchy.legend.member.is.defined.in.class"),
|
||||||
@@ -40,18 +59,15 @@ class KotlinOverrideHierarchyBrowser(
|
|||||||
KotlinBundle.message("hierarchy.legend.member.should.be.defined")
|
KotlinBundle.message("hierarchy.legend.member.should.be.defined")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override fun getElementFromDescriptor(descriptor: HierarchyNodeDescriptor) = descriptor.psiElement
|
||||||
|
|
||||||
override fun isApplicableElement(psiElement: PsiElement): Boolean =
|
override fun isApplicableElement(psiElement: PsiElement): Boolean =
|
||||||
psiElement.isOverrideHierarchyElement()
|
psiElement.isOverrideHierarchyElement()
|
||||||
|
|
||||||
override fun createHierarchyTreeStructure(typeName: String, psiElement: PsiElement): HierarchyTreeStructure? =
|
override fun createHierarchyTreeStructure(typeName: String, psiElement: PsiElement): HierarchyTreeStructure? =
|
||||||
if (typeName == MethodHierarchyBrowserBase.METHOD_TYPE) KotlinOverrideTreeStructure(myProject, psiElement) else null
|
if (typeName == MethodHierarchyBrowserBase.METHOD_TYPE) KotlinOverrideTreeStructure(myProject, psiElement as KtCallableDeclaration) else null
|
||||||
|
|
||||||
override fun getBaseMethod(): PsiMethod? {
|
override fun getComparator() = JavaHierarchyUtil.getComparator(myProject)!!
|
||||||
val builder = myBuilders.get(myCurrentViewType)
|
|
||||||
if (builder == null) return null
|
|
||||||
|
|
||||||
return (builder.treeStructure as KotlinOverrideTreeStructure).javaTreeStructures.get(0).baseMethod
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getContentDisplayName(typeName: String, element: PsiElement): String? {
|
override fun getContentDisplayName(typeName: String, element: PsiElement): String? {
|
||||||
val targetElement = element.unwrapped
|
val targetElement = element.unwrapped
|
||||||
|
|||||||
+163
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.hierarchy.overrides
|
||||||
|
|
||||||
|
import com.intellij.icons.AllIcons
|
||||||
|
import com.intellij.ide.IdeBundle
|
||||||
|
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor
|
||||||
|
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.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiMember
|
||||||
|
import com.intellij.ui.LayeredIcon
|
||||||
|
import com.intellij.ui.RowIcon
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.getJavaMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
|
||||||
|
import org.jetbrains.kotlin.types.substitutions.getTypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.util.findCallableMemberBySignature
|
||||||
|
import java.awt.Font
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
class KotlinOverrideHierarchyNodeDescriptor (
|
||||||
|
parentNode: HierarchyNodeDescriptor?,
|
||||||
|
klass: PsiElement,
|
||||||
|
baseElement: PsiElement
|
||||||
|
) : HierarchyNodeDescriptor(klass.project, parentNode, klass, parentNode == null) {
|
||||||
|
private val baseElement = baseElement.createSmartPointer()
|
||||||
|
|
||||||
|
private var rawIcon: Icon? = null
|
||||||
|
private var stateIcon: Icon? = null
|
||||||
|
|
||||||
|
private fun resolveToDescriptor(psiElement: PsiElement): DeclarationDescriptor? {
|
||||||
|
return when (psiElement) {
|
||||||
|
is KtNamedDeclaration -> psiElement.resolveToDescriptor()
|
||||||
|
is PsiMember -> psiElement.getJavaMemberDescriptor()
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getBaseDescriptor() = baseElement.element?.let { resolveToDescriptor(it) } as? CallableMemberDescriptor
|
||||||
|
|
||||||
|
private fun getCurrentClassDescriptor() = psiElement?.let { resolveToDescriptor(it) } as? ClassDescriptor
|
||||||
|
|
||||||
|
private fun getCurrentDescriptor(): CallableMemberDescriptor? {
|
||||||
|
val classDescriptor = getCurrentClassDescriptor() ?: return null
|
||||||
|
val baseDescriptor = getBaseDescriptor() ?: return null
|
||||||
|
val baseClassDescriptor = baseDescriptor.containingDeclaration as? ClassDescriptor ?: return null
|
||||||
|
val substitutor = getTypeSubstitutor(baseClassDescriptor.defaultType, classDescriptor.defaultType) ?: return null
|
||||||
|
return classDescriptor.findCallableMemberBySignature(baseDescriptor.substitute(substitutor) as CallableMemberDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun calculateState(): Icon? {
|
||||||
|
val classDescriptor = getCurrentClassDescriptor() ?: return null
|
||||||
|
val callableDescriptor = getCurrentDescriptor() ?: return AllIcons.Hierarchy.MethodNotDefined
|
||||||
|
|
||||||
|
if (callableDescriptor.kind == CallableMemberDescriptor.Kind.DECLARATION) {
|
||||||
|
if (callableDescriptor.modality == Modality.ABSTRACT) return null
|
||||||
|
return AllIcons.Hierarchy.MethodDefined
|
||||||
|
}
|
||||||
|
|
||||||
|
val isAbstractClass = classDescriptor.modality == Modality.ABSTRACT
|
||||||
|
val hasBaseImplementation = DescriptorUtils.getAllOverriddenDeclarations(callableDescriptor).any { it.modality != Modality.ABSTRACT }
|
||||||
|
return if (isAbstractClass || hasBaseImplementation) AllIcons.Hierarchy.MethodNotDefined else AllIcons.Hierarchy.ShouldDefineMethod
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(): Boolean {
|
||||||
|
var flags = Iconable.ICON_FLAG_VISIBILITY
|
||||||
|
if (isMarkReadOnly) {
|
||||||
|
flags = flags or Iconable.ICON_FLAG_READ_STATUS
|
||||||
|
}
|
||||||
|
|
||||||
|
var changes = super.update()
|
||||||
|
|
||||||
|
val classPsi = psiElement
|
||||||
|
val classDescriptor = getCurrentClassDescriptor()
|
||||||
|
if (classPsi == null || classDescriptor == null) {
|
||||||
|
val invalidPrefix = IdeBundle.message("node.hierarchy.invalid")
|
||||||
|
if (!myHighlightedText.text.startsWith(invalidPrefix)) {
|
||||||
|
myHighlightedText.beginning.addText(invalidPrefix, getInvalidPrefixAttributes())
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
val newRawIcon = classPsi.getIcon(flags)
|
||||||
|
val newStateIcon = calculateState()
|
||||||
|
|
||||||
|
if (changes || newRawIcon !== rawIcon || newStateIcon !== stateIcon) {
|
||||||
|
changes = true
|
||||||
|
|
||||||
|
rawIcon = newRawIcon
|
||||||
|
stateIcon = newStateIcon
|
||||||
|
|
||||||
|
var newIcon = rawIcon
|
||||||
|
|
||||||
|
if (myIsBase) {
|
||||||
|
val icon = LayeredIcon(2)
|
||||||
|
icon.setIcon(newIcon, 0)
|
||||||
|
icon.setIcon(AllIcons.Hierarchy.Base, 1, -AllIcons.Hierarchy.Base.iconWidth / 2, 0)
|
||||||
|
newIcon = icon
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateIcon != null) {
|
||||||
|
newIcon = RowIcon(stateIcon, newIcon)
|
||||||
|
}
|
||||||
|
|
||||||
|
icon = newIcon
|
||||||
|
}
|
||||||
|
|
||||||
|
val oldText = myHighlightedText
|
||||||
|
|
||||||
|
myHighlightedText = CompositeAppearance()
|
||||||
|
var classNameAttributes: TextAttributes? = null
|
||||||
|
if (myColor != null) {
|
||||||
|
classNameAttributes = TextAttributes(myColor, null, null, null, Font.PLAIN)
|
||||||
|
}
|
||||||
|
|
||||||
|
with (myHighlightedText.ending) {
|
||||||
|
addText(classDescriptor.name.asString(), classNameAttributes)
|
||||||
|
classDescriptor.parents.forEach { parentDescriptor ->
|
||||||
|
when (parentDescriptor) {
|
||||||
|
is MemberDescriptor -> {
|
||||||
|
addText(" in ${parentDescriptor.name.asString()}", classNameAttributes)
|
||||||
|
if (parentDescriptor is FunctionDescriptor) {
|
||||||
|
addText("()", classNameAttributes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is PackageFragmentDescriptor -> {
|
||||||
|
addText(" (${parentDescriptor.fqName.asString()})", HierarchyNodeDescriptor.getPackageNameAttributes())
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
myName = myHighlightedText.text
|
||||||
|
|
||||||
|
if (!Comparing.equal(myHighlightedText, oldText)) {
|
||||||
|
changes = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-6
@@ -23,10 +23,9 @@ import com.intellij.ide.hierarchy.MethodHierarchyBrowserBase
|
|||||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||||
import com.intellij.openapi.actionSystem.DataContext
|
import com.intellij.openapi.actionSystem.DataContext
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiMethod
|
|
||||||
import org.jetbrains.kotlin.idea.hierarchy.getCurrentElement
|
import org.jetbrains.kotlin.idea.hierarchy.getCurrentElement
|
||||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||||
import org.jetbrains.kotlin.psi.KtProperty
|
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypesAndPredicate
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypesAndPredicate
|
||||||
|
|
||||||
class KotlinOverrideHierarchyProvider: HierarchyProvider {
|
class KotlinOverrideHierarchyProvider: HierarchyProvider {
|
||||||
@@ -44,8 +43,7 @@ class KotlinOverrideHierarchyProvider: HierarchyProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getOverrideHierarchyElement(element: PsiElement?): PsiElement?
|
private fun getOverrideHierarchyElement(element: PsiElement?): PsiElement?
|
||||||
= element?.getParentOfTypesAndPredicate() { it.isOverrideHierarchyElement() }
|
= element?.getParentOfTypesAndPredicate { it.isOverrideHierarchyElement() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun PsiElement.isOverrideHierarchyElement(): Boolean
|
fun PsiElement.isOverrideHierarchyElement() = this is KtCallableDeclaration && containingClassOrObject != null
|
||||||
= this is PsiMethod || this is KtNamedFunction || this is KtProperty
|
|
||||||
|
|||||||
+22
-18
@@ -16,31 +16,35 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.hierarchy.overrides
|
package org.jetbrains.kotlin.idea.hierarchy.overrides
|
||||||
|
|
||||||
import com.intellij.ide.hierarchy.HierarchyTreeStructure
|
import com.intellij.icons.AllIcons
|
||||||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor
|
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor
|
||||||
|
import com.intellij.ide.hierarchy.HierarchyTreeStructure
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.ide.hierarchy.method.MethodHierarchyNodeDescriptor
|
|
||||||
import com.intellij.ide.hierarchy.method.MethodHierarchyTreeStructure
|
|
||||||
import com.intellij.util.ArrayUtil
|
import com.intellij.util.ArrayUtil
|
||||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
import org.jetbrains.kotlin.asJava.unwrapped
|
||||||
import com.intellij.util.containers.ContainerUtil
|
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
|
||||||
|
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
|
||||||
class KotlinOverrideTreeStructure(project: Project, val element: PsiElement) : HierarchyTreeStructure(project, null) {
|
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||||
val javaTreeStructures = element.toLightMethods().map { method -> MethodHierarchyTreeStructure(project, method) }
|
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
||||||
|
|
||||||
|
class KotlinOverrideTreeStructure(project: Project, declaration: KtCallableDeclaration) : HierarchyTreeStructure(project, null) {
|
||||||
init {
|
init {
|
||||||
setBaseElement(javaTreeStructures.first().baseDescriptor!!)
|
setBaseElement(KotlinOverrideHierarchyNodeDescriptor(null, declaration.containingClassOrObject!!, declaration))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val baseElement = declaration.createSmartPointer()
|
||||||
|
|
||||||
override fun buildChildren(nodeDescriptor: HierarchyNodeDescriptor): Array<Any> {
|
override fun buildChildren(nodeDescriptor: HierarchyNodeDescriptor): Array<Any> {
|
||||||
fun buildChildrenByTreeStructure(javaTreeStructure: MethodHierarchyTreeStructure): Array<Any> {
|
val baseElement = baseElement.element ?: return ArrayUtil.EMPTY_OBJECT_ARRAY
|
||||||
return javaTreeStructure.getChildElements(nodeDescriptor as MethodHierarchyNodeDescriptor) ?: ArrayUtil.EMPTY_OBJECT_ARRAY
|
val psiElement = nodeDescriptor.psiElement ?: return ArrayUtil.EMPTY_OBJECT_ARRAY
|
||||||
}
|
val subclasses = HierarchySearchRequest(psiElement, psiElement.useScope, false).searchInheritors().findAll()
|
||||||
|
return subclasses
|
||||||
return javaTreeStructures
|
.mapNotNull {
|
||||||
.asSequence()
|
val subclass = it.unwrapped ?: return@mapNotNull null
|
||||||
.map (::buildChildrenByTreeStructure)
|
KotlinOverrideHierarchyNodeDescriptor(nodeDescriptor, subclass, baseElement)
|
||||||
.reduce { a, b -> ContainerUtil.union(a.toSet(), b.toSet()).toTypedArray() }
|
}
|
||||||
|
.filter { it.calculateState() != AllIcons.Hierarchy.MethodNotDefined }
|
||||||
|
.toTypedArray()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
<node text="List (kotlin.collections)" base="true">
|
||||||
|
<node text="UnmodifiableList in Collections (java.util)"/>
|
||||||
|
<node text="CheckedList in Collections (java.util)"/>
|
||||||
|
<node text="SynchronizedList in Collections (java.util)"/>
|
||||||
|
<node text="AbstractList (java.util)">
|
||||||
|
<node text="ArrayList in Arrays (java.util)"/>
|
||||||
|
<node text="EmptyList in Collections (java.util)"/>
|
||||||
|
<node text="SubList in ArrayList (java.util)"/>
|
||||||
|
<node text="AbstractSequentialList (java.util)"/>
|
||||||
|
<node text="CopiesList in Collections (java.util)"/>
|
||||||
|
<node text="SingletonList in Collections (java.util)"/>
|
||||||
|
<node text="ArrayList (java.util)"/>
|
||||||
|
</node>
|
||||||
|
<node text="ArrayList (java.util)"/>
|
||||||
|
<node text="AbstractList (kotlin.collections)">
|
||||||
|
<node text="SubList in AbstractList (kotlin.collections)"/>
|
||||||
|
<node text="ReversedListReadOnly (kotlin.collections)"/>
|
||||||
|
</node>
|
||||||
|
<node text="EmptyList (kotlin.collections)"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo(list: List<String>){
|
||||||
|
list.<caret>get(1)
|
||||||
|
}
|
||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
<node text="T ()" base="true">
|
||||||
|
<node text="B ()"/>
|
||||||
|
<node text="X ()"/>
|
||||||
|
<node text="Y ()">
|
||||||
|
<node text="A ()">
|
||||||
|
<node text="C ()"/>
|
||||||
|
</node>
|
||||||
|
<node text="Z ()">
|
||||||
|
<node text="D ()"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun <caret>foo() {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Cannot apply action for element at caret
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
<node text="T ()" base="true">
|
||||||
|
<node text="B ()"/>
|
||||||
|
<node text="X ()"/>
|
||||||
|
<node text="Y ()"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
open class T(open var <caret>foo: String = "")
|
||||||
|
|
||||||
|
open class X: T("") {
|
||||||
|
override var foo: String
|
||||||
|
get() = ""
|
||||||
|
set(value: String) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Y(override var foo: String = ""): T(foo)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
class B extends T {
|
||||||
|
B() {
|
||||||
|
super("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFoo() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFoo(String value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.idea.hierarchy.calls.KotlinCalleeTreeStructure;
|
|||||||
import org.jetbrains.kotlin.idea.hierarchy.calls.KotlinCallerTreeStructure;
|
import org.jetbrains.kotlin.idea.hierarchy.calls.KotlinCallerTreeStructure;
|
||||||
import org.jetbrains.kotlin.idea.hierarchy.overrides.KotlinOverrideTreeStructure;
|
import org.jetbrains.kotlin.idea.hierarchy.overrides.KotlinOverrideTreeStructure;
|
||||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
|
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallableDeclaration;
|
||||||
import org.jetbrains.kotlin.psi.KtElement;
|
import org.jetbrains.kotlin.psi.KtElement;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -173,7 +174,7 @@ public abstract class AbstractHierarchyTest extends KotlinHierarchyViewTestBase
|
|||||||
public HierarchyTreeStructure compute() {
|
public HierarchyTreeStructure compute() {
|
||||||
return new KotlinOverrideTreeStructure(
|
return new KotlinOverrideTreeStructure(
|
||||||
getProject(),
|
getProject(),
|
||||||
getElementAtCaret(LanguageCallHierarchy.INSTANCE)
|
(KtCallableDeclaration) getElementAtCaret(LanguageMethodHierarchy.INSTANCE)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -560,6 +560,12 @@ public class HierarchyTestGenerated extends AbstractHierarchyTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/hierarchy/overrides"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, false);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/hierarchy/overrides"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinBuiltInMemberFunction")
|
||||||
|
public void testKotlinBuiltInMemberFunction() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/hierarchy/overrides/kotlinBuiltInMemberFunction/");
|
||||||
|
doOverrideHierarchyTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kotlinFunctionInClass")
|
@TestMetadata("kotlinFunctionInClass")
|
||||||
public void testKotlinFunctionInClass() throws Exception {
|
public void testKotlinFunctionInClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/hierarchy/overrides/kotlinFunctionInClass/");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/hierarchy/overrides/kotlinFunctionInClass/");
|
||||||
@@ -583,5 +589,17 @@ public class HierarchyTestGenerated extends AbstractHierarchyTest {
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/hierarchy/overrides/kotlinPropertyInTrait/");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/hierarchy/overrides/kotlinPropertyInTrait/");
|
||||||
doOverrideHierarchyTest(fileName);
|
doOverrideHierarchyTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinTopLevelFunction")
|
||||||
|
public void testKotlinTopLevelFunction() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/hierarchy/overrides/kotlinTopLevelFunction/");
|
||||||
|
doOverrideHierarchyTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlinVarParameter")
|
||||||
|
public void testKotlinVarParameter() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/hierarchy/overrides/kotlinVarParameter/");
|
||||||
|
doOverrideHierarchyTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user