From 419abadcdae7f22f7fdb3459fd1ad8ede0f7661f Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Tue, 26 Dec 2017 15:48:00 +0300 Subject: [PATCH] Search for Kotlin sources in project too in fallback scope When debugging in Gradle or Maven we may miss debug scope completely, but still want to be responsible for building source positions for all Kotlin source files (other PositionManagers may produce unexpected results). --- .../debugger/DebuggerClassNameProvider.kt | 4 +-- .../debugger/InlineCallableUsagesSearcher.kt | 9 +++-- .../idea/debugger/KotlinPositionManager.kt | 35 ++++++++++++++----- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/DebuggerClassNameProvider.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/DebuggerClassNameProvider.kt index 32b3c64ac4b..25d2a3c3237 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/DebuggerClassNameProvider.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/DebuggerClassNameProvider.kt @@ -20,7 +20,6 @@ import com.intellij.debugger.SourcePosition import com.intellij.debugger.engine.DebugProcess import com.intellij.debugger.engine.DebuggerUtils import com.intellij.psi.PsiElement -import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.PsiTreeUtil import com.sun.jdi.AbsentInformationException import com.sun.jdi.ReferenceType @@ -46,7 +45,6 @@ import java.util.* class DebuggerClassNameProvider( private val debugProcess: DebugProcess, - scopes: List, val findInlineUseSites: Boolean = true, val alwaysReturnLambdaParentClass: Boolean = true ) { @@ -71,7 +69,7 @@ class DebuggerClassNameProvider( } } - private val inlineUsagesSearcher = InlineCallableUsagesSearcher(debugProcess, scopes) + private val inlineUsagesSearcher = InlineCallableUsagesSearcher(debugProcess) /** * Returns classes in which the given line number *is* present. diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/InlineCallableUsagesSearcher.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/InlineCallableUsagesSearcher.kt index c5fa96c2c48..548ffc54b8d 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/InlineCallableUsagesSearcher.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/InlineCallableUsagesSearcher.kt @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.idea.debugger.DebuggerClassNameProvider.Companion.ge import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches.ComputedClassNames import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage +import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.psi.KtDeclaration @@ -38,10 +39,7 @@ import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.inline.InlineUtil -class InlineCallableUsagesSearcher( - private val myDebugProcess: DebugProcess, - val scopes: List -) { +class InlineCallableUsagesSearcher(private val myDebugProcess: DebugProcess) { fun findInlinedCalls( declaration: KtDeclaration, bindingContext: BindingContext = KotlinDebuggerCaches.getOrCreateTypeMapper(declaration).bindingContext, @@ -102,7 +100,8 @@ class InlineCallableUsagesSearcher( private fun getScopeForInlineDeclarationUsages(inlineDeclaration: KtDeclaration): GlobalSearchScope { val virtualFile = runReadAction { inlineDeclaration.containingFile.virtualFile } return if (virtualFile != null && ProjectRootsUtil.isLibraryFile(myDebugProcess.project, virtualFile)) { - GlobalSearchScope.union(scopes.toTypedArray()) + myDebugProcess.searchScope.uniteWith( + KotlinSourceFilterScope.librarySources(GlobalSearchScope.allScope(myDebugProcess.project), myDebugProcess.project)) } else { myDebugProcess.searchScope diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt index 1310c6de63f..24372130d84 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt @@ -26,9 +26,12 @@ import com.intellij.debugger.engine.evaluation.EvaluationContext import com.intellij.debugger.impl.DebuggerUtilsEx import com.intellij.debugger.jdi.StackFrameProxyImpl import com.intellij.debugger.requests.ClassPrepareRequestor +import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.PsiFile import com.intellij.psi.impl.compiled.ClsFileImpl +import com.intellij.psi.search.DelegatingGlobalSearchScope import com.intellij.psi.search.GlobalSearchScope import com.intellij.util.ThreeState import com.intellij.xdebugger.frame.XStackFrame @@ -60,10 +63,24 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName import com.intellij.debugger.engine.DebuggerUtils as JDebuggerUtils class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiRequestPositionManager, PositionManagerEx() { + private val allKotlinFilesScope = + object : DelegatingGlobalSearchScope( + KotlinSourceFilterScope.projectAndLibrariesSources(GlobalSearchScope.allScope(myDebugProcess.project), myDebugProcess.project) + ) { + private val projectIndex = ProjectRootManager.getInstance(myDebugProcess.project).fileIndex + private val scopeComparator = + Comparator.comparing(projectIndex::isInSourceContent) + .thenComparing(projectIndex::isInLibrarySource) + .thenComparing { file1, file2 -> super.compare(file1, file2) } - private val scopes: List = listOf( + override fun compare(file1: VirtualFile, file2: VirtualFile): Int { + return scopeComparator.compare(file1, file2) + } + } + + private val sourceSearchScopes: List = listOf( myDebugProcess.searchScope, - KotlinSourceFilterScope.librarySources(GlobalSearchScope.allScope(myDebugProcess.project), myDebugProcess.project) + allKotlinFilesScope ) override fun evaluateCondition(context: EvaluationContext, frame: StackFrameProxyImpl, location: Location, expression: String): ThreeState? { @@ -100,12 +117,12 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq val javaClassName = JvmClassName.byInternalName(defaultInternalName(location)) val project = myDebugProcess.project - val defaultPsiFile = DebuggerUtils.findSourceFileForClass(project, scopes, javaClassName, javaSourceFileName) + val defaultPsiFile = DebuggerUtils.findSourceFileForClass(project, sourceSearchScopes, javaClassName, javaSourceFileName) if (defaultPsiFile != null) { return SourcePosition.createFromLine(defaultPsiFile, 0) } } - catch(e: AbsentInformationException) { + catch (e: AbsentInformationException) { // ignored } } @@ -208,7 +225,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq continue } - val internalClassNames = DebuggerClassNameProvider(myDebugProcess, scopes, alwaysReturnLambdaParentClass = false) + val internalClassNames = DebuggerClassNameProvider(myDebugProcess, alwaysReturnLambdaParentClass = false) .getOuterClassNamesForElement(literal.firstChild) .classNames @@ -257,7 +274,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq val project = myDebugProcess.project - return DebuggerUtils.findSourceFileForClass(project, scopes, className, sourceName) + return DebuggerUtils.findSourceFileForClass(project, sourceSearchScopes, className, sourceName) } private fun defaultInternalName(location: Location): String { @@ -271,7 +288,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq val psiFile = sourcePosition.file if (psiFile is KtFile) { if (!ProjectRootsUtil.isInProjectOrLibSource(psiFile)) return emptyList() - return DebuggerClassNameProvider(myDebugProcess, scopes).getClassesForPosition(sourcePosition) + return DebuggerClassNameProvider(myDebugProcess).getClassesForPosition(sourcePosition) } if (psiFile is ClsFileImpl) { @@ -286,7 +303,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq } fun originalClassNamesForPosition(position: SourcePosition): List { - return DebuggerClassNameProvider(myDebugProcess, scopes, findInlineUseSites = false).getOuterClassNamesForPosition(position) + return DebuggerClassNameProvider(myDebugProcess, findInlineUseSites = false).getOuterClassNamesForPosition(position) } override fun locationsOfLine(type: ReferenceType, position: SourcePosition): List { @@ -325,7 +342,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq throw NoDataException.INSTANCE } - val classNames = DebuggerClassNameProvider(myDebugProcess, scopes).getOuterClassNamesForPosition(position) + val classNames = DebuggerClassNameProvider(myDebugProcess).getOuterClassNamesForPosition(position) return classNames.flatMap { name -> listOfNotNull( myDebugProcess.requestsManager.createClassPrepareRequest(requestor, name),