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).
This commit is contained in:
Nikolay Krasko
2017-12-26 15:48:00 +03:00
parent f468990f97
commit 419abadcda
3 changed files with 31 additions and 17 deletions
@@ -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<GlobalSearchScope>,
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.
@@ -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<GlobalSearchScope>
) {
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
@@ -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<GlobalSearchScope> = listOf(
override fun compare(file1: VirtualFile, file2: VirtualFile): Int {
return scopeComparator.compare(file1, file2)
}
}
private val sourceSearchScopes: List<GlobalSearchScope> = 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<String> {
return DebuggerClassNameProvider(myDebugProcess, scopes, findInlineUseSites = false).getOuterClassNamesForPosition(position)
return DebuggerClassNameProvider(myDebugProcess, findInlineUseSites = false).getOuterClassNamesForPosition(position)
}
override fun locationsOfLine(type: ReferenceType, position: SourcePosition): List<Location> {
@@ -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),