Skip to content

Commit dd964e9

Browse files
Debugger: fix breakpoints inside inline functions in libraries sources
1 parent 34b88f5 commit dd964e9

File tree

7 files changed

+53
-15
lines changed

7 files changed

+53
-15
lines changed

ChangeLog.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515

1616
#### Debugger
1717

18-
- Fix text with line breaks in popup with line breakpoint variants
1918
- Do not cast to runtime type unavailable in current scope
19+
- Fix text with line breaks in popup with line breakpoint variants
20+
- Fix breakpoints inside inline functions in libraries sources
2021

2122
## 1.0.2
2223

idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import com.intellij.openapi.ui.MessageType
3434
import com.intellij.psi.PsiElement
3535
import com.intellij.psi.PsiFile
3636
import com.intellij.psi.impl.compiled.ClsFileImpl
37+
import com.intellij.psi.search.GlobalSearchScope
3738
import com.intellij.psi.search.searches.ReferencesSearch
3839
import com.intellij.psi.util.PsiTreeUtil
3940
import com.intellij.util.ThreeState
@@ -63,6 +64,7 @@ import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches.Computed
6364
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile
6465
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
6566
import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
67+
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
6668
import org.jetbrains.kotlin.idea.util.DebuggerUtils
6769
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
6870
import org.jetbrains.kotlin.idea.util.application.runReadAction
@@ -81,6 +83,11 @@ import com.intellij.debugger.engine.DebuggerUtils as JDebuggerUtils
8183

8284
class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiRequestPositionManager, PositionManagerEx() {
8385

86+
private val scopes = listOf(
87+
myDebugProcess.searchScope,
88+
KotlinSourceFilterScope.librarySources(GlobalSearchScope.allScope(myDebugProcess.project), myDebugProcess.project)
89+
)
90+
8491
override fun evaluateCondition(context: EvaluationContext, frame: StackFrameProxyImpl, location: Location, expression: String): ThreeState? {
8592
return ThreeState.UNSURE
8693
}
@@ -106,7 +113,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
106113
val javaClassName = JvmClassName.byInternalName(defaultInternalName(location))
107114
val project = myDebugProcess.project
108115

109-
val defaultPsiFile = DebuggerUtils.findSourceFileForClass(project, myDebugProcess.searchScope, javaClassName, javaSourceFileName)
116+
val defaultPsiFile = DebuggerUtils.findSourceFileForClass(project, scopes, javaClassName, javaSourceFileName)
110117
if (defaultPsiFile != null) {
111118
return SourcePosition.createFromLine(defaultPsiFile, 0)
112119
}
@@ -218,7 +225,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
218225

219226
val project = myDebugProcess.project
220227

221-
return DebuggerUtils.findSourceFileForClass(project, myDebugProcess.searchScope, className, sourceName)
228+
return DebuggerUtils.findSourceFileForClass(project, scopes, className, sourceName)
222229
}
223230

224231
private fun defaultInternalName(location: Location): String {
@@ -450,7 +457,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
450457
val functionName = function.readAction { it.name }
451458

452459
val task = Runnable {
453-
ReferencesSearch.search(function, myDebugProcess.searchScope).forEach {
460+
ReferencesSearch.search(function, GlobalSearchScope.union(scopes.toTypedArray())).forEach {
454461
if (!it.readAction { it.isImportUsage() }) {
455462
val usage = (it.element as? KtElement)?.let { getElementToCalculateClassName(it) }
456463
if (usage != null) {
@@ -527,7 +534,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
527534
val result = hashSetOf<String>()
528535
val inlineFunction = parameter.containingDeclaration.source.getPsi() as? KtNamedFunction ?: return emptySet()
529536

530-
ReferencesSearch.search(inlineFunction, myDebugProcess.searchScope).forEach {
537+
ReferencesSearch.search(inlineFunction, GlobalSearchScope.union(scopes.toTypedArray())).forEach {
531538
runReadAction {
532539
if (!it.isImportUsage()) {
533540
val call = (it.element as? KtExpression)?.let { KtPsiUtil.getParentCallIfPresent(it) }

idea/src/org/jetbrains/kotlin/idea/filters/KotlinExceptionFilter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class KotlinExceptionFilter(private val searchScope: GlobalSearchScope) : Filter
6363
val internalName = fullyQualifiedName.replace('.', '/')
6464
val jvmClassName = JvmClassName.byInternalName(internalName)
6565

66-
val file = DebuggerUtils.findSourceFileForClass(project, searchScope, jvmClassName, fileName) ?: return null
66+
val file = DebuggerUtils.findSourceFileForClassIncludeLibrarySources(project, searchScope, jvmClassName, fileName) ?: return null
6767

6868
val virtualFile = file.virtualFile ?: return null
6969

@@ -121,7 +121,7 @@ class KotlinExceptionFilter(private val searchScope: GlobalSearchScope) : Filter
121121
} ?: return null
122122

123123
val newJvmName = JvmClassName.byInternalName(mappingInfo.path)
124-
val newSourceFile = DebuggerUtils.findSourceFileForClass(project, searchScope, newJvmName, mappingInfo.name) ?: return null
124+
val newSourceFile = DebuggerUtils.findSourceFileForClassIncludeLibrarySources(project, searchScope, newJvmName, mappingInfo.name) ?: return null
125125
return OpenFileHyperlinkInfo(project, newSourceFile.virtualFile, mappingInfo.getIntervalIfContains(line)!!.map(line) - 1)
126126
}
127127

idea/src/org/jetbrains/kotlin/idea/util/DebuggerUtils.kt

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,28 @@ object DebuggerUtils {
4242

4343
private val KOTLIN_EXTENSIONS = Sets.newHashSet("kt", "kts")
4444

45+
fun findSourceFileForClassIncludeLibrarySources(
46+
project: Project,
47+
scope: GlobalSearchScope,
48+
className: JvmClassName,
49+
fileName: String): KtFile? {
50+
return findSourceFileForClass(
51+
project,
52+
listOf(scope, KotlinSourceFilterScope.librarySources(GlobalSearchScope.allScope(project), project)),
53+
className,
54+
fileName)
55+
}
56+
4557
fun findSourceFileForClass(
4658
project: Project,
47-
searchScope: GlobalSearchScope,
59+
scopes: List<GlobalSearchScope>,
4860
className: JvmClassName,
4961
fileName: String): KtFile? {
5062
val extension = FileUtilRt.getExtension(fileName)
5163
if (!KOTLIN_EXTENSIONS.contains(extension)) return null
5264
if (DumbService.getInstance(project).isDumb) return null
5365

54-
val filesWithExactName = findFilesByNameInPackage(className, fileName, project, searchScope).check { it.isNotEmpty() }
55-
// Source files for libraries aren't included into ModuleWithDependencies scope
56-
?: findFilesByNameInPackage(
57-
className, fileName, project,
58-
KotlinSourceFilterScope.librarySources(GlobalSearchScope.allScope(project), project))
66+
val filesWithExactName = scopes.findFirstNotEmpty { findFilesByNameInPackage(className, fileName, project, it) } ?: return null
5967

6068
if (filesWithExactName.isEmpty()) return null
6169

@@ -65,7 +73,7 @@ object DebuggerUtils {
6573

6674
// Static facade or inner class of such facade?
6775
val partFqName = className.fqNameForClassNameWithoutDollars
68-
val filesForPart = StaticFacadeIndexUtil.findFilesForFilePart(partFqName, searchScope, project)
76+
val filesForPart = scopes.findFirstNotEmpty { StaticFacadeIndexUtil.findFilesForFilePart(partFqName, it, project) } ?: return null
6977
if (!filesForPart.isEmpty()) {
7078
for (file in filesForPart) {
7179
if (file.name == fileName) {
@@ -79,6 +87,15 @@ object DebuggerUtils {
7987
return filesWithExactName.first()
8088
}
8189

90+
private fun <T, R> Collection<T>.findFirstNotEmpty(predicate: (T) -> Collection<R>): Collection<R>? {
91+
var result: Collection<R> = emptyList()
92+
for (e in this) {
93+
result = predicate(e)
94+
if (result.isNotEmpty()) break
95+
}
96+
return result
97+
}
98+
8299
private fun findFilesByNameInPackage(className: JvmClassName, fileName: String, project: Project, searchScope: GlobalSearchScope)
83100
= findFilesWithExactPackage(className.packageFqName, searchScope, project).filter { it.name == fileName }
84101

idea/testData/debugger/customLibraryForTinyApp/inlineFunInLibrary/inlineFunInLibrary.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,12 @@ package customLib.inlineFunInLibrary
22

33
public inline fun inlineFun(f: () -> Unit) {
44
1 + 1
5+
inlineFunInner {
6+
1 + 1
7+
}
8+
}
9+
10+
public inline fun inlineFunInner(f: () -> Unit) {
11+
// Breakpoint 2
12+
1 + 1
513
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
LineBreakpoint created at inlineFunInLibrary.kt:4
2+
LineBreakpoint created at inlineFunInLibrary.kt:12
23
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! breakpointInInlineFun.BreakpointInInlineFunKt
34
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
45
inlineFunInLibrary.kt:4
6+
inlineFunInLibrary.kt:12
57
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
68

79
Process finished with exit code 0

idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/breakpointInInlineFun.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ fun main(args: Array<String>) {
66
inlineFun { }
77
}
88

9-
// ADDITIONAL_BREAKPOINT: inlineFunInLibrary.kt:public inline fun inlineFun
9+
// RESUME: 2
10+
11+
// ADDITIONAL_BREAKPOINT: inlineFunInLibrary.kt:public inline fun inlineFun
12+
// ADDITIONAL_BREAKPOINT: inlineFunInLibrary.kt: Breakpoint 2

0 commit comments

Comments
 (0)