mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
[kotlin] k2 call hierarchy: copy/paste implementation
KTIJ-29300 GitOrigin-RevId: 231ba561e739001057df55e569a1de683bd12e22
This commit is contained in:
committed by
intellij-monorepo-bot
parent
58bd4f5b72
commit
5aba74cafd
@@ -59,5 +59,7 @@
|
||||
<orderEntry type="library" name="kotlinc.analysis-api-k2" level="project" />
|
||||
<orderEntry type="module" module-name="kotlin.formatter.minimal" />
|
||||
<orderEntry type="module" module-name="kotlin.refactorings.k2" />
|
||||
<orderEntry type="module" module-name="intellij.java" />
|
||||
<orderEntry type="module" module-name="kotlin.searching.base" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -232,6 +232,11 @@
|
||||
|
||||
<vcs.codeVisionLanguageContext language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.codeInsight.hints.KotlinVcsCodeVisionContext"/>
|
||||
|
||||
<callHierarchyProvider
|
||||
language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.k2.codeinsight.hierarchy.calls.KotlinCallHierarchyProvider"/>
|
||||
<hierarchy.referenceProcessor implementation="org.jetbrains.kotlin.idea.k2.codeinsight.hierarchy.calls.KotlinCallReferenceProcessor"/>
|
||||
</extensions>
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
<codeinsight.quickfix.registrar implementation="org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreateFromUsageQuickFixesRegistrar"/>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.kotlin.idea.k2.codeinsight.hierarchy.calls
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.psi.KtCallElement
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
|
||||
|
||||
abstract class CalleeReferenceVisitorBase protected constructor(private val deepTraversal: Boolean) : KtTreeVisitorVoid() {
|
||||
|
||||
protected abstract fun processDeclaration(reference: KtSimpleNameExpression, declaration: PsiElement)
|
||||
|
||||
override fun visitKtElement(element: KtElement) {
|
||||
if (deepTraversal || !(element is KtClassOrObject || element is KtNamedFunction)) {
|
||||
super.visitKtElement(element)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
|
||||
val declaration = expression.mainReference.resolve()
|
||||
if (declaration == null || (declaration.containingFile as? KtFile)?.isCompiled == true) return
|
||||
|
||||
if (declaration is KtProperty && !declaration.isLocal || isCallable(declaration, expression)) {
|
||||
processDeclaration(expression, declaration)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
// Accept callees of KtCallElement which refer to Kotlin function, Kotlin class or Java method
|
||||
private fun isCallable(declaration: PsiElement, reference: KtSimpleNameExpression): Boolean {
|
||||
val callElement = PsiTreeUtil.getParentOfType(reference, KtCallElement::class.java)
|
||||
if (callElement == null || !PsiTreeUtil.isAncestor(callElement.calleeExpression, reference, false)) return false
|
||||
|
||||
return declaration is KtClassOrObject
|
||||
|| declaration is KtNamedFunction
|
||||
|| declaration is PsiMethod
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.kotlin.idea.k2.codeinsight.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.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 javax.swing.JTree
|
||||
|
||||
class KotlinCallHierarchyBrowser(element: PsiElement) :
|
||||
CallHierarchyBrowserBase(element.project, element) {
|
||||
override fun createTrees(trees: MutableMap<in String, in JTree>) {
|
||||
val baseOnThisMethodAction = BaseOnThisMethodAction()
|
||||
|
||||
val tree1 = createTree(false)
|
||||
PopupHandler.installPopupMenu(
|
||||
tree1,
|
||||
IdeActions.GROUP_CALL_HIERARCHY_POPUP,
|
||||
ActionPlaces.CALL_HIERARCHY_VIEW_POPUP
|
||||
)
|
||||
baseOnThisMethodAction.registerCustomShortcutSet(
|
||||
ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).shortcutSet,
|
||||
tree1
|
||||
)
|
||||
trees[getCalleeType()] = tree1
|
||||
|
||||
val tree2 = createTree(false)
|
||||
PopupHandler.installPopupMenu(
|
||||
tree2,
|
||||
IdeActions.GROUP_CALL_HIERARCHY_POPUP,
|
||||
ActionPlaces.CALL_HIERARCHY_VIEW_POPUP
|
||||
)
|
||||
baseOnThisMethodAction.registerCustomShortcutSet(
|
||||
ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).shortcutSet,
|
||||
tree2
|
||||
)
|
||||
trees[getCallerType()] = tree2
|
||||
}
|
||||
|
||||
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(
|
||||
type: String,
|
||||
psiElement: PsiElement
|
||||
): HierarchyTreeStructure? {
|
||||
if (psiElement !is KtElement) return null
|
||||
return when (type) {
|
||||
getCallerType() -> KotlinCallerTreeStructure(psiElement, currentScopeType)
|
||||
getCalleeType() -> KotlinCalleeTreeStructure(psiElement, currentScopeType)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun getComparator(): Comparator<NodeDescriptor<*>> {
|
||||
return JavaHierarchyUtil.getComparator(myProject)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun getTargetElement(descriptor: HierarchyNodeDescriptor): PsiElement? {
|
||||
return (descriptor as? KotlinCallHierarchyNodeDescriptor)?.psiElement
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.kotlin.idea.k2.codeinsight.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.NlsSafe
|
||||
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.analysis.api.KaSession
|
||||
import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.analysis.api.renderer.types.impl.KaTypeRendererForSource
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaClassOrObjectSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaConstructorSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaFunctionLikeSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaFunctionSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaPackageSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaVariableSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KaNamedSymbol
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import java.awt.Font
|
||||
|
||||
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(myProject, null, element, isBase, navigateToReference)
|
||||
|
||||
fun incrementUsageCount() {
|
||||
usageCount++
|
||||
javaDelegate.incrementUsageCount()
|
||||
}
|
||||
|
||||
fun addReference(reference: PsiReference) {
|
||||
references.add(reference)
|
||||
javaDelegate.addReference(reference)
|
||||
}
|
||||
|
||||
override fun isValid(): Boolean {
|
||||
val myElement = psiElement
|
||||
return myElement != null && myElement.isValid
|
||||
}
|
||||
|
||||
override fun update(): Boolean {
|
||||
val oldText = myHighlightedText
|
||||
val oldIcon = icon
|
||||
|
||||
val flags: Int = if (isMarkReadOnly) {
|
||||
Iconable.ICON_FLAG_VISIBILITY or Iconable.ICON_FLAG_READ_STATUS
|
||||
} else {
|
||||
Iconable.ICON_FLAG_VISIBILITY
|
||||
}
|
||||
|
||||
var changes = super.update()
|
||||
|
||||
val elementText = (psiElement as? KtElement)?.let { analyze(it) { renderElement(it) } }
|
||||
if (elementText == null) {
|
||||
val invalidPrefix = IdeBundle.message("node.hierarchy.invalid")
|
||||
if (!myHighlightedText.text.startsWith(invalidPrefix)) {
|
||||
myHighlightedText.beginning.addText(invalidPrefix, getInvalidPrefixAttributes())
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
val targetElement = psiElement
|
||||
val elementIcon = targetElement!!.getIcon(flags)
|
||||
|
||||
icon = if (changes && myIsBase) {
|
||||
LayeredIcon(2).apply {
|
||||
setIcon(elementIcon, 0)
|
||||
setIcon(AllIcons.General.Modified, 1, -AllIcons.General.Modified.iconWidth / 2, 0)
|
||||
}
|
||||
} else {
|
||||
elementIcon
|
||||
}
|
||||
|
||||
val mainTextAttributes: TextAttributes? = if (myColor != null) {
|
||||
TextAttributes(myColor, null, null, null, Font.PLAIN)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
myHighlightedText = CompositeAppearance()
|
||||
myHighlightedText.ending.addText(elementText, mainTextAttributes)
|
||||
if (usageCount > 1) {
|
||||
myHighlightedText.ending.addText(
|
||||
IdeBundle.message("node.call.hierarchy.N.usages", usageCount),
|
||||
getUsageCountPrefixAttributes(),
|
||||
)
|
||||
}
|
||||
|
||||
@NlsSafe
|
||||
val packageName = KtPsiUtil.getPackageName(targetElement as KtElement) ?: ""
|
||||
|
||||
myHighlightedText.ending.addText(" ($packageName)", getPackageNameAttributes())
|
||||
myName = myHighlightedText.text
|
||||
|
||||
if (!(Comparing.equal(myHighlightedText, oldText) && Comparing.equal(icon, oldIcon))) {
|
||||
changes = true
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
||||
|
||||
override fun navigate(requestFocus: Boolean) {
|
||||
javaDelegate.navigate(requestFocus)
|
||||
}
|
||||
|
||||
override fun canNavigate(): Boolean {
|
||||
return javaDelegate.canNavigate()
|
||||
}
|
||||
|
||||
override fun canNavigateToSource(): Boolean {
|
||||
return javaDelegate.canNavigateToSource()
|
||||
}
|
||||
|
||||
companion object {
|
||||
context(KaSession)
|
||||
@NlsSafe
|
||||
private fun renderElement(element: PsiElement?): String? {
|
||||
when (element) {
|
||||
is KtFile -> {
|
||||
return element.name
|
||||
}
|
||||
!is KtNamedDeclaration -> {
|
||||
return null
|
||||
}
|
||||
else -> {
|
||||
var declarationSymbol = element.getSymbol()
|
||||
val elementText: String?
|
||||
when (element) {
|
||||
is KtClassOrObject -> {
|
||||
when {
|
||||
element is KtObjectDeclaration && element.isCompanion() -> {
|
||||
val containingDescriptor = declarationSymbol.getContainingSymbol()
|
||||
if (containingDescriptor !is KaClassOrObjectSymbol) return null
|
||||
declarationSymbol = containingDescriptor
|
||||
elementText = renderClassOrObject(declarationSymbol)
|
||||
}
|
||||
element is KtEnumEntry -> {
|
||||
elementText = element.name
|
||||
}
|
||||
else -> {
|
||||
elementText = if (element.name != null) {
|
||||
renderClassOrObject(declarationSymbol as KaClassOrObjectSymbol)
|
||||
} else {
|
||||
KotlinBundle.message("hierarchy.text.anonymous")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is KtNamedFunction, is KtConstructor<*> -> {
|
||||
if (declarationSymbol !is KaFunctionLikeSymbol) return null
|
||||
elementText = renderNamedFunction(declarationSymbol)
|
||||
}
|
||||
is KtProperty -> {
|
||||
elementText = element.name
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
|
||||
if (elementText == null) return null
|
||||
var containerText: String? = null
|
||||
var containerDescriptor = declarationSymbol.getContainingSymbol()
|
||||
while (containerDescriptor != null) {
|
||||
if (containerDescriptor is KaPackageSymbol) {
|
||||
break
|
||||
}
|
||||
val name = (containerDescriptor as? KaNamedSymbol)?.name?.takeUnless { containerDescriptor is KaVariableSymbol }
|
||||
if (name != null && !name.isSpecial) {
|
||||
val identifier = name.identifier
|
||||
containerText = if (containerText != null) "$identifier.$containerText" else identifier
|
||||
}
|
||||
containerDescriptor = containerDescriptor.getContainingSymbol()
|
||||
}
|
||||
return if (containerText != null) "$containerText.$elementText" else elementText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context(KaSession)
|
||||
fun renderNamedFunction(symbol: KaFunctionLikeSymbol): String? {
|
||||
val name = ((symbol as? KaFunctionSymbol)?.name ?: ((symbol as? KaConstructorSymbol)?.getContainingSymbol() as? KaClassOrObjectSymbol)?.name)?.asString() ?: return null
|
||||
val paramTypes =
|
||||
StringUtil.join(
|
||||
symbol.valueParameters,
|
||||
{
|
||||
it.returnType.render(KaTypeRendererForSource.WITH_SHORT_NAMES, position = Variance.INVARIANT)
|
||||
},
|
||||
", "
|
||||
)
|
||||
return "$name($paramTypes)"
|
||||
}
|
||||
|
||||
private fun renderClassOrObject(descriptor: KaClassOrObjectSymbol): String {
|
||||
return descriptor.name?.asString() ?: KotlinBundle.message("hierarchy.text.anonymous")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
package org.jetbrains.kotlin.idea.k2.codeinsight.hierarchy.calls
|
||||
|
||||
import com.intellij.ide.hierarchy.CallHierarchyBrowserBase
|
||||
import com.intellij.ide.hierarchy.HierarchyBrowser
|
||||
import com.intellij.ide.hierarchy.HierarchyProvider
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
class KotlinCallHierarchyProvider : HierarchyProvider {
|
||||
override fun getTarget(dataContext: DataContext): KtElement? {
|
||||
val element = dataContext.getData(CommonDataKeys.PSI_ELEMENT)?.let { getCallHierarchyElement(it) }
|
||||
if (element is KtFile) return null
|
||||
return element
|
||||
}
|
||||
|
||||
override fun createHierarchyBrowser(target: PsiElement) = KotlinCallHierarchyBrowser(target)
|
||||
|
||||
override fun browserActivated(hierarchyBrowser: HierarchyBrowser) {
|
||||
(hierarchyBrowser as KotlinCallHierarchyBrowser).changeView(CallHierarchyBrowserBase.getCallerType())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
package org.jetbrains.kotlin.idea.k2.codeinsight.hierarchy.calls
|
||||
|
||||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor
|
||||
import com.intellij.ide.hierarchy.call.CallReferenceProcessor
|
||||
import com.intellij.ide.hierarchy.call.JavaCallHierarchyData
|
||||
import com.intellij.ide.util.treeView.NodeDescriptor
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
|
||||
class KotlinCallReferenceProcessor : CallReferenceProcessor {
|
||||
override fun process(reference: PsiReference, data: JavaCallHierarchyData): Boolean {
|
||||
val nodeDescriptor = data.nodeDescriptor as? HierarchyNodeDescriptor ?: return false
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
KotlinCallerTreeStructure.processReference(
|
||||
reference,
|
||||
reference.element,
|
||||
nodeDescriptor,
|
||||
data.resultMap as MutableMap<PsiElement, NodeDescriptor<*>>,
|
||||
true
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
package org.jetbrains.kotlin.idea.k2.codeinsight.hierarchy.calls
|
||||
|
||||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor
|
||||
import com.intellij.ide.hierarchy.HierarchyTreeStructure
|
||||
import com.intellij.ide.hierarchy.call.CallHierarchyNodeDescriptor
|
||||
import com.intellij.ide.hierarchy.call.CalleeMethodsTreeStructure
|
||||
import com.intellij.ide.util.treeView.NodeDescriptor
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMember
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.util.ArrayUtil
|
||||
import org.jetbrains.kotlin.asJava.unwrapped
|
||||
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesSupport
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
|
||||
class KotlinCalleeTreeStructure(
|
||||
element: KtElement,
|
||||
private val scopeType: String
|
||||
) : HierarchyTreeStructure(
|
||||
element.project,
|
||||
KotlinCallHierarchyNodeDescriptor(null, element, true, false)
|
||||
) {
|
||||
private fun KtElement.getCalleeSearchScope(): List<KtElement> = when (this) {
|
||||
is KtNamedFunction, is KtFunctionLiteral, is KtPropertyAccessor -> listOf((this as KtDeclarationWithBody).bodyExpression)
|
||||
is KtProperty -> accessors.map { it.bodyExpression }
|
||||
is KtClassOrObject -> {
|
||||
superTypeListEntries.filterIsInstance<KtCallElement>() +
|
||||
getAnonymousInitializers().map { it.body } +
|
||||
declarations.asSequence().filterIsInstance<KtProperty>().map { it.initializer }.toList()
|
||||
}
|
||||
else -> emptyList()
|
||||
}.filterNotNull()
|
||||
|
||||
override fun buildChildren(nodeDescriptor: HierarchyNodeDescriptor): Array<Any> {
|
||||
if (nodeDescriptor is CallHierarchyNodeDescriptor) {
|
||||
val psiMethod = nodeDescriptor.enclosingElement as? PsiMethod ?: return ArrayUtil.EMPTY_OBJECT_ARRAY
|
||||
return CalleeMethodsTreeStructure(myProject, psiMethod as PsiMember, scopeType).getChildElements(nodeDescriptor)
|
||||
}
|
||||
|
||||
val element = nodeDescriptor.psiElement as? KtElement ?: return ArrayUtil.EMPTY_OBJECT_ARRAY
|
||||
|
||||
val result = LinkedHashSet<HierarchyNodeDescriptor>()
|
||||
val baseClass = (element as? KtDeclaration)?.containingClassOrObject
|
||||
val calleeToDescriptorMap = HashMap<PsiElement, NodeDescriptor<*>>()
|
||||
|
||||
element.getCalleeSearchScope().forEach {
|
||||
it.accept(
|
||||
object : CalleeReferenceVisitorBase(false) {
|
||||
override fun processDeclaration(reference: KtSimpleNameExpression, declaration: PsiElement) {
|
||||
if (!isInScope(baseClass, declaration, scopeType)) return
|
||||
result += (getOrCreateNodeDescriptor(
|
||||
parent = nodeDescriptor, originalElement = declaration, reference = null,
|
||||
navigateToReference = false,
|
||||
elementToDescriptorMap = calleeToDescriptorMap,
|
||||
isJavaMap = false
|
||||
)
|
||||
?: return)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
for (it in KotlinFindUsagesSupport.searchOverriders(element, element.useScope)) {
|
||||
val overrider = it.unwrapped as? KtElement ?: continue
|
||||
if (!isInScope(baseClass, overrider, scopeType)) continue
|
||||
result += KotlinCallHierarchyNodeDescriptor(nodeDescriptor, overrider, false, false)
|
||||
}
|
||||
|
||||
return result.toArray()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
package org.jetbrains.kotlin.idea.k2.codeinsight.hierarchy.calls
|
||||
|
||||
import com.intellij.find.findUsages.JavaFindUsagesOptions
|
||||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor
|
||||
import com.intellij.ide.hierarchy.HierarchyTreeStructure
|
||||
import com.intellij.ide.hierarchy.call.CallHierarchyNodeDescriptor
|
||||
import com.intellij.ide.hierarchy.call.CallerMethodsTreeStructure
|
||||
import com.intellij.ide.util.treeView.NodeDescriptor
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMember
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.impl.source.resolve.JavaResolveUtil
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.util.ArrayUtil
|
||||
import org.jetbrains.kotlin.idea.base.searching.usages.KotlinClassFindUsagesOptions
|
||||
import org.jetbrains.kotlin.idea.base.searching.usages.KotlinFunctionFindUsagesOptions
|
||||
import org.jetbrains.kotlin.idea.base.searching.usages.KotlinPropertyFindUsagesOptions
|
||||
import org.jetbrains.kotlin.idea.base.searching.usages.processAllUsages
|
||||
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport
|
||||
import org.jetbrains.kotlin.kdoc.psi.api.KDoc
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
|
||||
class KotlinCallerTreeStructure(
|
||||
element: KtElement,
|
||||
private val scopeType: String
|
||||
) : HierarchyTreeStructure(element.project, KotlinCallHierarchyNodeDescriptor(null, element, true, false)) {
|
||||
companion object {
|
||||
internal fun processReference(
|
||||
reference: PsiReference?,
|
||||
refElement: PsiElement,
|
||||
nodeDescriptor: HierarchyNodeDescriptor,
|
||||
callerToDescriptorMap: MutableMap<PsiElement, NodeDescriptor<*>>,
|
||||
isJavaMap: Boolean
|
||||
) {
|
||||
var callerElement: PsiElement? = when (refElement) {
|
||||
is KtElement -> getCallHierarchyElement(refElement)
|
||||
else -> {
|
||||
val psiMember = refElement.getNonStrictParentOfType<PsiMember>()
|
||||
psiMember as? PsiMethod ?: psiMember?.containingClass
|
||||
}
|
||||
}
|
||||
if (callerElement is KtProperty) {
|
||||
if (PsiTreeUtil.isAncestor(callerElement.initializer, refElement, false)) {
|
||||
callerElement = getCallHierarchyElement(callerElement.parent)
|
||||
}
|
||||
}
|
||||
if (callerElement == null) return
|
||||
|
||||
getOrCreateNodeDescriptor(
|
||||
parent = nodeDescriptor,
|
||||
originalElement = callerElement,
|
||||
reference = reference,
|
||||
navigateToReference = true,
|
||||
elementToDescriptorMap = callerToDescriptorMap,
|
||||
isJavaMap = isJavaMap
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildChildren(
|
||||
element: PsiElement,
|
||||
nodeDescriptor: HierarchyNodeDescriptor,
|
||||
callerToDescriptorMap: MutableMap<PsiElement, NodeDescriptor<*>>
|
||||
): Collection<Any> {
|
||||
if (nodeDescriptor is CallHierarchyNodeDescriptor) {
|
||||
val psiMethod = nodeDescriptor.enclosingElement as? PsiMethod ?: return emptyList()
|
||||
return CallerMethodsTreeStructure(myProject, psiMethod as PsiMember, scopeType).getChildElements(nodeDescriptor).toList()
|
||||
}
|
||||
|
||||
if (element !is KtDeclaration) return emptyList()
|
||||
|
||||
val baseClass = (element as? KtDeclaration)?.containingClassOrObject
|
||||
val searchScope = getSearchScope(scopeType, baseClass)
|
||||
|
||||
val findOptions: JavaFindUsagesOptions = when (element) {
|
||||
is KtNamedFunction, is KtConstructor<*> -> KotlinFunctionFindUsagesOptions(myProject)
|
||||
is KtProperty -> KotlinPropertyFindUsagesOptions(myProject)
|
||||
is KtPropertyAccessor -> KotlinPropertyFindUsagesOptions(myProject).apply {
|
||||
isReadAccess = element.isGetter
|
||||
isWriteAccess = element.isSetter
|
||||
}
|
||||
is KtEnumEntry -> KotlinClassFindUsagesOptions(myProject)
|
||||
is KtClass, is KtObjectDeclaration -> KotlinClassFindUsagesOptions(myProject).apply {
|
||||
isUsages = false
|
||||
}
|
||||
else -> return emptyList()
|
||||
}
|
||||
findOptions.isSkipImportStatements = true
|
||||
findOptions.searchScope = searchScope
|
||||
findOptions.isSearchForTextOccurrences = false
|
||||
|
||||
val elementToSearch = when (element) {
|
||||
is KtPropertyAccessor -> element.property
|
||||
else -> element
|
||||
}
|
||||
|
||||
// If reference belongs to property initializer, show enclosing declaration instead
|
||||
elementToSearch.processAllUsages(findOptions) {
|
||||
val refElement = it.element
|
||||
val isInKDoc = PsiTreeUtil.getParentOfType(refElement, KDoc::class.java) != null
|
||||
if (refElement != null && !JavaResolveUtil.isInJavaDoc(refElement) && !isInKDoc) {
|
||||
processReference(it.reference, refElement, nodeDescriptor, callerToDescriptorMap, false)
|
||||
}
|
||||
}
|
||||
|
||||
return callerToDescriptorMap.values
|
||||
}
|
||||
|
||||
override fun buildChildren(nodeDescriptor: HierarchyNodeDescriptor): Array<Any> {
|
||||
val element = nodeDescriptor.psiElement as? KtDeclaration ?: return ArrayUtil.EMPTY_OBJECT_ARRAY
|
||||
val callerToDescriptorMap = hashMapOf<PsiElement, NodeDescriptor<*>>()
|
||||
if (element is KtCallableDeclaration && element.hasModifier(KtTokens.OVERRIDE_KEYWORD)) {
|
||||
return KotlinSearchUsagesSupport.getInstance(element.project).findSuperMethodsNoWrapping(element, true)
|
||||
.flatMap { rootElement ->
|
||||
val rootNodeDescriptor = when (rootElement) {
|
||||
is KtElement -> nodeDescriptor
|
||||
is PsiMethod -> CallHierarchyNodeDescriptor(
|
||||
myProject,
|
||||
nodeDescriptor.parentDescriptor as HierarchyNodeDescriptor?,
|
||||
rootElement,
|
||||
nodeDescriptor.parentDescriptor == null,
|
||||
false
|
||||
)
|
||||
else -> return@flatMap emptyList<Any>()
|
||||
}
|
||||
buildChildren(rootElement, rootNodeDescriptor, callerToDescriptorMap)
|
||||
}.toTypedArray()
|
||||
} else {
|
||||
return buildChildren(element, nodeDescriptor, callerToDescriptorMap).toTypedArray()
|
||||
}
|
||||
}
|
||||
|
||||
override fun isAlwaysShowPlus() = true
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.kotlin.idea.k2.codeinsight.hierarchy.calls
|
||||
|
||||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor
|
||||
import com.intellij.ide.hierarchy.call.CallHierarchyNodeDescriptor
|
||||
import com.intellij.ide.util.treeView.NodeDescriptor
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMember
|
||||
import com.intellij.psi.PsiReference
|
||||
import org.jetbrains.kotlin.asJava.toLightElements
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
|
||||
fun isCallHierarchyElement(e: PsiElement): Boolean {
|
||||
return (e is KtNamedFunction && e.name != null) ||
|
||||
e is KtSecondaryConstructor ||
|
||||
(e is KtProperty && !e.isLocal) ||
|
||||
e is KtObjectDeclaration ||
|
||||
(e is KtClass && !e.isInterface()) ||
|
||||
e is KtFile
|
||||
}
|
||||
|
||||
fun getCallHierarchyElement(element: PsiElement) = element.parentsWithSelf.firstOrNull(::isCallHierarchyElement) as? KtElement
|
||||
|
||||
private fun NodeDescriptor<*>.incrementUsageCount() {
|
||||
when (this) {
|
||||
is KotlinCallHierarchyNodeDescriptor -> incrementUsageCount()
|
||||
is CallHierarchyNodeDescriptor -> incrementUsageCount()
|
||||
}
|
||||
}
|
||||
|
||||
private fun NodeDescriptor<*>.addReference(reference: PsiReference) {
|
||||
when (this) {
|
||||
is KotlinCallHierarchyNodeDescriptor -> addReference(reference)
|
||||
is CallHierarchyNodeDescriptor -> addReference(reference)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun getOrCreateNodeDescriptor(
|
||||
parent: HierarchyNodeDescriptor,
|
||||
originalElement: PsiElement,
|
||||
reference: PsiReference?,
|
||||
navigateToReference: Boolean,
|
||||
elementToDescriptorMap: MutableMap<PsiElement, NodeDescriptor<*>>,
|
||||
isJavaMap: Boolean
|
||||
): HierarchyNodeDescriptor? {
|
||||
val element = (if (isJavaMap && originalElement is KtElement) originalElement.toLightElements().firstOrNull() else originalElement)
|
||||
?: return null
|
||||
|
||||
val existingDescriptor = elementToDescriptorMap[element] as? HierarchyNodeDescriptor
|
||||
val result = if (existingDescriptor != null) {
|
||||
existingDescriptor.incrementUsageCount()
|
||||
existingDescriptor
|
||||
} else {
|
||||
val newDescriptor: HierarchyNodeDescriptor = when (element) {
|
||||
is KtElement -> KotlinCallHierarchyNodeDescriptor(parent, element, false, navigateToReference)
|
||||
is PsiMember -> CallHierarchyNodeDescriptor(element.project, parent, element, false, navigateToReference)
|
||||
else -> return null
|
||||
}
|
||||
elementToDescriptorMap[element] = newDescriptor
|
||||
newDescriptor
|
||||
}
|
||||
|
||||
if (reference != null) {
|
||||
result.addReference(reference)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.k2.hierarchy
|
||||
|
||||
import com.intellij.ide.hierarchy.HierarchyBrowserBaseEx
|
||||
import com.intellij.ide.hierarchy.HierarchyProvider
|
||||
import com.intellij.ide.hierarchy.HierarchyTreeStructure
|
||||
import com.intellij.ide.hierarchy.LanguageCallHierarchy
|
||||
import com.intellij.ide.hierarchy.LanguageMethodHierarchy
|
||||
import com.intellij.ide.hierarchy.actions.BrowseHierarchyActionBase
|
||||
import com.intellij.ide.hierarchy.call.CallerMethodsTreeStructure
|
||||
import com.intellij.lang.LanguageExtension
|
||||
import com.intellij.openapi.util.Computable
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMember
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil.RefactoringErrorHintException
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import com.intellij.util.ArrayUtil
|
||||
import junit.framework.ComparisonFailure
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.analysis.api.permissions.KaAllowAnalysisOnEdt
|
||||
import org.jetbrains.kotlin.analysis.api.permissions.allowAnalysisOnEdt
|
||||
import org.jetbrains.kotlin.idea.KotlinHierarchyViewTestBase
|
||||
import org.jetbrains.kotlin.idea.k2.codeinsight.hierarchy.calls.KotlinCalleeTreeStructure
|
||||
import org.jetbrains.kotlin.idea.k2.codeinsight.hierarchy.calls.KotlinCallerTreeStructure
|
||||
import org.jetbrains.kotlin.idea.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.idea.test.createTextEditorBasedDataContext
|
||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractFirHierarchyTest : KotlinHierarchyViewTestBase() {
|
||||
protected var folderName: String? = null
|
||||
|
||||
private fun doHierarchyTest(folderName: String, structure: () -> HierarchyTreeStructure) {
|
||||
this.folderName = folderName
|
||||
doHierarchyTest(structure, *filesToConfigure)
|
||||
}
|
||||
|
||||
protected fun doCallerHierarchyTest(folderName: String) = doHierarchyTest(folderName) {
|
||||
KotlinCallerTreeStructure(
|
||||
(getElementAtCaret(LanguageCallHierarchy.INSTANCE) as KtElement),
|
||||
HierarchyBrowserBaseEx.SCOPE_PROJECT
|
||||
)
|
||||
}
|
||||
|
||||
protected fun doCallerJavaHierarchyTest(folderName: String) = doHierarchyTest(folderName) {
|
||||
CallerMethodsTreeStructure(
|
||||
project,
|
||||
getElementAtCaret(LanguageCallHierarchy.INSTANCE) as PsiMember,
|
||||
HierarchyBrowserBaseEx.SCOPE_PROJECT
|
||||
)
|
||||
}
|
||||
|
||||
protected fun doCalleeHierarchyTest(folderName: String) = doHierarchyTest(folderName) {
|
||||
KotlinCalleeTreeStructure(
|
||||
(getElementAtCaret(LanguageCallHierarchy.INSTANCE) as KtElement),
|
||||
HierarchyBrowserBaseEx.SCOPE_PROJECT
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private fun getElementAtCaret(extension: LanguageExtension<HierarchyProvider>): PsiElement {
|
||||
val file = PsiDocumentManager.getInstance(project).getPsiFile(editor.document)
|
||||
val dataContext = createTextEditorBasedDataContext(project, editor, editor.caretModel.currentCaret)
|
||||
return BrowseHierarchyActionBase.findProvider(extension, file, file, dataContext)?.getTarget(dataContext)
|
||||
?: throw RefactoringErrorHintException("Cannot apply action for element at caret")
|
||||
}
|
||||
|
||||
protected val filesToConfigure: Array<String>
|
||||
get() {
|
||||
val folderName = folderName ?: error("folderName should be initialized")
|
||||
val files: MutableList<String> = ArrayList(2)
|
||||
FileUtil.processFilesRecursively(
|
||||
File(folderName)
|
||||
) { file ->
|
||||
val fileName = file.name
|
||||
if (fileName.endsWith(".kt") || fileName.endsWith(".java")) {
|
||||
files.add(fileName)
|
||||
}
|
||||
true
|
||||
}
|
||||
files.sort()
|
||||
return ArrayUtil.toStringArray(files)
|
||||
}
|
||||
|
||||
@OptIn(KaAllowAnalysisOnEdt::class)
|
||||
@Throws(Exception::class)
|
||||
override fun doHierarchyTest(
|
||||
treeStructureComputable: Computable<out HierarchyTreeStructure>,
|
||||
vararg fileNames: String
|
||||
) {
|
||||
try {
|
||||
allowAnalysisOnEdt {
|
||||
super.doHierarchyTest(treeStructureComputable, *fileNames)
|
||||
}
|
||||
} catch (e: RefactoringErrorHintException) {
|
||||
val file = File(folderName, "messages.txt")
|
||||
if (file.exists()) {
|
||||
val expectedMessage = FileUtil.loadFile(file, true)
|
||||
TestCase.assertEquals(expectedMessage, e.localizedMessage)
|
||||
} else {
|
||||
TestCase.fail("Unexpected error: " + e.localizedMessage)
|
||||
}
|
||||
} catch (failure: ComparisonFailure) {
|
||||
val actual = failure.actual
|
||||
val verificationFile = File(testDataDirectory, getTestName(false) + "_verification.xml")
|
||||
KotlinTestUtils.assertEqualsToFile(verificationFile, actual)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.getInstance()
|
||||
|
||||
override val testDataDirectory: File
|
||||
get() {
|
||||
val testRoot = super.testDataDirectory
|
||||
val testDir = KotlinTestUtils.getTestDataFileName(this.javaClass, name) ?: error("Test data file name is missing")
|
||||
return File(testRoot, testDir)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
|
||||
package org.jetbrains.kotlin.idea.k2.hierarchy;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode;
|
||||
import org.jetbrains.kotlin.idea.base.test.TestRoot;
|
||||
import org.jetbrains.kotlin.idea.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.idea.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* This class is generated by {@link org.jetbrains.kotlin.testGenerator.generator.TestGenerator}.
|
||||
* DO NOT MODIFY MANUALLY.
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
@TestRoot("code-insight/kotlin.code-insight.k2")
|
||||
@TestDataPath("$CONTENT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public abstract class FirHierarchyTestGenerated extends AbstractFirHierarchyTest {
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../../idea/tests/testData/hierarchy/calls/callers")
|
||||
public static class Callers extends AbstractFirHierarchyTest {
|
||||
@java.lang.Override
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public final KotlinPluginMode getPluginMode() {
|
||||
return KotlinPluginMode.K2;
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doCallerHierarchyTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("callInsideAnonymousFun")
|
||||
public void testCallInsideAnonymousFun() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/callInsideAnonymousFun/");
|
||||
}
|
||||
|
||||
@TestMetadata("callInsideLambda")
|
||||
public void testCallInsideLambda() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/callInsideLambda/");
|
||||
}
|
||||
|
||||
@TestMetadata("insideJavadoc")
|
||||
public void testInsideJavadoc() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/insideJavadoc/");
|
||||
}
|
||||
|
||||
@TestMetadata("insideKDoc")
|
||||
public void testInsideKDoc() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/insideKDoc/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinClass")
|
||||
public void testKotlinClass() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinClass/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinEnumClass")
|
||||
public void testKotlinEnumClass() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinEnumClass/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinEnumEntry")
|
||||
public void testKotlinEnumEntry() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinEnumEntry/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinFunction")
|
||||
public void testKotlinFunction() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinFunctionNonCallUsages")
|
||||
public void testKotlinFunctionNonCallUsages() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinFunctionNonCallUsages/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinInterface")
|
||||
public void testKotlinInterface() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinInterface/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinLocalClass")
|
||||
public void testKotlinLocalClass() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinLocalClass/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinLocalFunction")
|
||||
public void testKotlinLocalFunction() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinLocalFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinLocalFunctionWithNonLocalCallers")
|
||||
public void testKotlinLocalFunctionWithNonLocalCallers() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinLocalFunctionWithNonLocalCallers/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinNestedClass")
|
||||
public void testKotlinNestedClass() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinNestedClass/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinNestedInnerClass")
|
||||
public void testKotlinNestedInnerClass() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinNestedInnerClass/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinObjectDeclaration")
|
||||
public void testKotlinObjectDeclaration() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinObjectDeclaration/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinPackageFunction")
|
||||
public void testKotlinPackageFunction() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinPackageFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinPackageProperty")
|
||||
public void testKotlinPackageProperty() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinPackageProperty/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinPrimaryConstructorImplicitCalls")
|
||||
public void testKotlinPrimaryConstructorImplicitCalls() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinPrimaryConstructorImplicitCalls/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinPrivateClass")
|
||||
public void testKotlinPrivateClass() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinPrivateClass/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinPrivateFunction")
|
||||
public void testKotlinPrivateFunction() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinPrivateFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinPrivateProperty")
|
||||
public void testKotlinPrivateProperty() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinPrivateProperty/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinProperty")
|
||||
public void testKotlinProperty() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinProperty/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinSecondaryConstructor")
|
||||
public void testKotlinSecondaryConstructor() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinSecondaryConstructor/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinSecondaryConstructorImplicitCalls")
|
||||
public void testKotlinSecondaryConstructorImplicitCalls() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinSecondaryConstructorImplicitCalls/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinUnresolvedFunction")
|
||||
public void testKotlinUnresolvedFunction() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callers/kotlinUnresolvedFunction/");
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../../idea/tests/testData/hierarchy/calls/callersJava")
|
||||
public static class CallersJava extends AbstractFirHierarchyTest {
|
||||
@java.lang.Override
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public final KotlinPluginMode getPluginMode() {
|
||||
return KotlinPluginMode.K2;
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doCallerJavaHierarchyTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("javaMethod")
|
||||
public void testJavaMethod() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callersJava/javaMethod/");
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../../idea/tests/testData/hierarchy/calls/callees")
|
||||
public static class Callees extends AbstractFirHierarchyTest {
|
||||
@java.lang.Override
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public final KotlinPluginMode getPluginMode() {
|
||||
return KotlinPluginMode.K2;
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doCalleeHierarchyTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAnonymousObject")
|
||||
public void testKotlinAnonymousObject() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callees/kotlinAnonymousObject/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinClass")
|
||||
public void testKotlinClass() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callees/kotlinClass/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinClassObject")
|
||||
public void testKotlinClassObject() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callees/kotlinClassObject/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinEnumClass")
|
||||
public void testKotlinEnumClass() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callees/kotlinEnumClass/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinFunction")
|
||||
public void testKotlinFunction() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callees/kotlinFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinInterface")
|
||||
public void testKotlinInterface() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callees/kotlinInterface/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinLocalClass")
|
||||
public void testKotlinLocalClass() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callees/kotlinLocalClass/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinLocalFunction")
|
||||
public void testKotlinLocalFunction() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callees/kotlinLocalFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinNestedClass")
|
||||
public void testKotlinNestedClass() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callees/kotlinNestedClass/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinObject")
|
||||
public void testKotlinObject() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callees/kotlinObject/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinPackageFunction")
|
||||
public void testKotlinPackageFunction() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callees/kotlinPackageFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinPackageProperty")
|
||||
public void testKotlinPackageProperty() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callees/kotlinPackageProperty/");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinProperty")
|
||||
public void testKotlinProperty() throws Exception {
|
||||
runTest("../../idea/tests/testData/hierarchy/calls/callees/kotlinProperty/");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import org.jetbrains.kotlin.idea.k2.AbstractK2ExpressionTypeTest
|
||||
import org.jetbrains.kotlin.idea.k2.AbstractKotlinFirBreadcrumbsTest
|
||||
import org.jetbrains.kotlin.idea.k2.AbstractKotlinFirJoinLinesTest
|
||||
import org.jetbrains.kotlin.idea.k2.AbstractKotlinFirPairMatcherTest
|
||||
import org.jetbrains.kotlin.idea.k2.hierarchy.AbstractFirHierarchyTest
|
||||
import org.jetbrains.kotlin.idea.k2.hints.AbstractKtCallChainHintsProviderTest
|
||||
import org.jetbrains.kotlin.idea.k2.hints.AbstractKtLambdasHintsProvider
|
||||
import org.jetbrains.kotlin.idea.k2.hints.AbstractKtParameterHintsProviderTest
|
||||
@@ -18,6 +19,7 @@ import org.jetbrains.kotlin.idea.k2.surroundWith.AbstractKotlinFirSurroundWithTe
|
||||
import org.jetbrains.kotlin.idea.k2.unwrap.AbstractKotlinFirUnwrapRemoveTest
|
||||
import org.jetbrains.kotlin.testGenerator.model.*
|
||||
import org.jetbrains.kotlin.testGenerator.model.GroupCategory.*
|
||||
import org.jetbrains.kotlin.testGenerator.model.Patterns.DIRECTORY
|
||||
import org.jetbrains.kotlin.testGenerator.model.Patterns.KT
|
||||
import org.jetbrains.kotlin.testGenerator.model.Patterns.KT_OR_KTS
|
||||
import org.jetbrains.kotlin.testGenerator.model.Patterns.TEST
|
||||
@@ -114,6 +116,12 @@ internal fun MutableTWorkspace.generateK2CodeInsightTests() {
|
||||
model("../../../idea/tests/testData/codeInsight/renderingKDoc")
|
||||
}
|
||||
|
||||
testClass<AbstractFirHierarchyTest> {
|
||||
model("../../../idea/tests/testData/hierarchy/calls/callers", pattern = DIRECTORY, isRecursive = false, testMethodName = "doCallerHierarchyTest")
|
||||
model("../../../idea/tests/testData/hierarchy/calls/callersJava", pattern = DIRECTORY, isRecursive = false, testMethodName = "doCallerJavaHierarchyTest")
|
||||
model("../../../idea/tests/testData/hierarchy/calls/callees", pattern = DIRECTORY, isRecursive = false, testMethodName = "doCalleeHierarchyTest")
|
||||
}
|
||||
|
||||
testClass<AbstractKotlinFirJoinLinesTest> {
|
||||
model("../../../idea/tests/testData/joinLines")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user