User: joe Date: 20 Feb 25 19:07 Revision: ac9583bd59a710b9ad34637e12fcbec49bf6c537 Summary: Allow source navigation into lambdas even if the lambda is in a field initializer TeamCity URL: https://ci.mcdev.io/viewModification.html?tab=vcsModificationFiles&modId=9838&personal=false Index: src/main/kotlin/platform/mixin/util/AsmUtil.kt =================================================================== --- src/main/kotlin/platform/mixin/util/AsmUtil.kt (revision b72a700d22fc91ba642d8dc8bfe9dd3c189e8add) +++ src/main/kotlin/platform/mixin/util/AsmUtil.kt (revision ac9583bd59a710b9ad34637e12fcbec49bf6c537) @@ -714,45 +714,46 @@ 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(psiFile) - parent.accept( + for (bodyElement in containingBodyElements) { + bodyElement.accept( - object : JavaRecursiveElementWalkingVisitor() { - override fun visitAnonymousClass(aClass: PsiAnonymousClass) { - // skip anonymous classes - } + object : JavaRecursiveElementWalkingVisitor() { + override fun visitAnonymousClass(aClass: PsiAnonymousClass) { + // skip anonymous classes + } - override fun visitClass(aClass: PsiClass) { - // skip inner classes - } + override fun visitClass(aClass: PsiClass) { + // skip inner classes + } - override fun visitLambdaExpression(expression: PsiLambdaExpression) { - if (matcher.accept(expression)) { - stopWalking() - } - // skip walking inside the lambda - } + 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) + 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() - } - } - } - }, - ) + if (expression.hasSyntheticMethod) { + if (matcher.accept(expression)) { + stopWalking() + } + } + } + }, + ) + } matcher.result } @@ -979,7 +980,7 @@ // 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 {