Skip to content

Commit

Permalink
Allow source navigation into lambdas even if the lambda is in a field…
Browse files Browse the repository at this point in the history
… initializer
  • Loading branch information
Earthcomputer committed Feb 20, 2025
1 parent b72a700 commit ac9583b
Showing 1 changed file with 29 additions and 28 deletions.
57 changes: 29 additions & 28 deletions src/main/kotlin/platform/mixin/util/AsmUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -714,45 +714,46 @@ private fun findContainingMethod(clazz: ClassNode, lambdaMethod: MethodNode): Pa
return null
}

private fun findAssociatedLambda(psiClass: PsiClass, clazz: ClassNode, lambdaMethod: MethodNode): PsiElement? {
private fun findAssociatedLambda(project: Project, scope: GlobalSearchScope, clazz: ClassNode, lambdaMethod: MethodNode): PsiElement? {
return RecursionManager.doPreventingRecursion(lambdaMethod, false) {
val pair = findContainingMethod(clazz, lambdaMethod) ?: return@doPreventingRecursion null
val (containingMethod, locationInfo) = pair
val parent = findAssociatedLambda(psiClass, clazz, containingMethod)
?: psiClass.findMethods(containingMethod.memberReference).firstOrNull()
?: return@doPreventingRecursion null
val containingBodyElements = findAssociatedLambda(project, scope, clazz, containingMethod)?.let(::listOf)
?: containingMethod.findBodyElements(clazz, project, scope).ifEmpty { return@doPreventingRecursion null }

val psiFile = psiClass.containingFile ?: return@doPreventingRecursion null
val psiFile = containingBodyElements.first().containingFile ?: return@doPreventingRecursion null
val matcher = locationInfo.createMatcher<PsiElement>(psiFile)
parent.accept(
object : JavaRecursiveElementWalkingVisitor() {
override fun visitAnonymousClass(aClass: PsiAnonymousClass) {
// skip anonymous classes
}

override fun visitClass(aClass: PsiClass) {
// skip inner classes
}

override fun visitLambdaExpression(expression: PsiLambdaExpression) {
if (matcher.accept(expression)) {
stopWalking()
for (bodyElement in containingBodyElements) {
bodyElement.accept(
object : JavaRecursiveElementWalkingVisitor() {
override fun visitAnonymousClass(aClass: PsiAnonymousClass) {
// skip anonymous classes
}
// skip walking inside the lambda
}

override fun visitMethodReferenceExpression(expression: PsiMethodReferenceExpression) {
// walk inside the reference first, visits the qualifier first (it's first in the bytecode)
super.visitMethodReferenceExpression(expression)
override fun visitClass(aClass: PsiClass) {
// skip inner classes
}

if (expression.hasSyntheticMethod) {
override fun visitLambdaExpression(expression: PsiLambdaExpression) {
if (matcher.accept(expression)) {
stopWalking()
}
// skip walking inside the lambda
}
}
},
)

override fun visitMethodReferenceExpression(expression: PsiMethodReferenceExpression) {
// walk inside the reference first, visits the qualifier first (it's first in the bytecode)
super.visitMethodReferenceExpression(expression)

if (expression.hasSyntheticMethod) {
if (matcher.accept(expression)) {
stopWalking()
}
}
}
},
)
}

matcher.result
}
Expand Down Expand Up @@ -979,7 +980,7 @@ fun MethodNode.findSourceElement(
// don't walk into stub compiled elements to look for lambdas
return null
}
return findAssociatedLambda(psiClass, clazz, this)
return findAssociatedLambda(project, scope, clazz, this)
}

fun MethodNode.findBodyElements(clazz: ClassNode, project: Project, scope: GlobalSearchScope): List<PsiElement> {
Expand Down

0 comments on commit ac9583b

Please sign in to comment.