Skip to content

Commit f07b5ea

Browse files
committed
Refactorings: clean smapUtil, moves, renames
1 parent 1c955a6 commit f07b5ea

File tree

4 files changed

+128
-132
lines changed

4 files changed

+128
-132
lines changed

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

Lines changed: 121 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,53 @@ import com.intellij.debugger.SourcePosition
2020
import com.intellij.debugger.engine.DebugProcess
2121
import com.intellij.debugger.jdi.VirtualMachineProxyImpl
2222
import com.intellij.openapi.application.ApplicationManager
23+
import com.intellij.openapi.compiler.CompilerPaths
2324
import com.intellij.openapi.project.Project
25+
import com.intellij.openapi.roots.ProjectFileIndex
2426
import com.intellij.openapi.vfs.VirtualFile
2527
import com.intellij.psi.search.GlobalSearchScope
28+
import com.intellij.util.containers.ConcurrentWeakFactoryMap
29+
import com.intellij.util.containers.ContainerUtil
2630
import com.sun.jdi.Location
2731
import com.sun.jdi.ReferenceType
2832
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
33+
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
34+
import org.jetbrains.kotlin.idea.refactoring.getLineCount
2935
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
36+
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
37+
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
3038
import org.jetbrains.kotlin.idea.util.application.runReadAction
3139
import org.jetbrains.kotlin.lexer.KtTokens
40+
import org.jetbrains.kotlin.load.kotlin.JvmVirtualFileFinder
41+
import org.jetbrains.kotlin.name.ClassId
3242
import org.jetbrains.kotlin.name.FqName
43+
import org.jetbrains.kotlin.name.Name
44+
import org.jetbrains.kotlin.name.tail
3345
import org.jetbrains.kotlin.psi.KtFile
3446
import org.jetbrains.kotlin.psi.KtFunction
3547
import org.jetbrains.kotlin.psi.psiUtil.parents
3648
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
49+
import org.jetbrains.kotlin.utils.addToStdlib.check
3750
import org.jetbrains.kotlin.utils.getOrPutNullable
3851
import org.jetbrains.org.objectweb.asm.*
52+
import java.io.File
3953
import java.util.*
4054

55+
fun isInlineFunctionLineNumber(file: VirtualFile, lineNumber: Int, project: Project): Boolean {
56+
if (ProjectRootsUtil.isProjectSourceFile(project, file)) {
57+
val linesInFile = file.toPsiFile(project)?.getLineCount() ?: return false
58+
return lineNumber > linesInFile
59+
}
60+
61+
return true
62+
}
63+
64+
fun readDebugBytecodeInfo(project: Project,
65+
jvmName: JvmClassName,
66+
file: VirtualFile): BytecodeDebugInfo? {
67+
return KotlinDebuggerCaches.getOrReadDebugInfoFromBytecode(project, jvmName, file)
68+
}
69+
4170
fun noStrataLineNumber(location: Location, isDexDebug: Boolean, project: Project, preferInlined: Boolean = false): Int {
4271
if (isDexDebug) {
4372
if (!preferInlined) {
@@ -73,13 +102,100 @@ fun getLastLineNumberForLocation(location: Location, project: Project, searchSco
73102
return lineMapping.values.firstOrNull { it.contains(lineNumber) }?.last()
74103
}
75104

76-
fun readLineNumberTableMapping(bytes: ByteArray): Map<BytecodeMethodKey, Map<String, Set<Int>>> {
105+
class WeakBytecodeDebugInfoStorage : ConcurrentWeakFactoryMap<BinaryCacheKey, BytecodeDebugInfo?>() {
106+
override fun create(key: BinaryCacheKey): BytecodeDebugInfo? {
107+
val bytes = readClassFileImpl(key.project, key.jvmName, key.file) ?: return null
108+
109+
val smapData = readDebugInfo(bytes)
110+
val lineNumberMapping = readLineNumberTableMapping(bytes)
111+
112+
return BytecodeDebugInfo(smapData, lineNumberMapping)
113+
}
114+
override fun createMap(): Map<BinaryCacheKey, BytecodeDebugInfo?> {
115+
return ContainerUtil.createConcurrentWeakKeyWeakValueMap()
116+
}
117+
}
118+
119+
class BytecodeDebugInfo(val smapData: SmapData?, val lineTableMapping: Map<BytecodeMethodKey, Map<String, Set<Int>>>)
120+
121+
data class BytecodeMethodKey(val methodName: String, val signature: String)
122+
123+
data class BinaryCacheKey(val project: Project, val jvmName: JvmClassName, val file: VirtualFile)
124+
125+
private fun readClassFileImpl(project: Project,
126+
jvmName: JvmClassName,
127+
file: VirtualFile): ByteArray? {
128+
val fqNameWithInners = jvmName.fqNameForClassNameWithoutDollars.tail(jvmName.packageFqName)
129+
130+
fun readFromLibrary(): ByteArray? {
131+
if (!ProjectRootsUtil.isLibrarySourceFile(project, file)) return null
132+
133+
val classId = ClassId(jvmName.packageFqName, Name.identifier(fqNameWithInners.asString()))
134+
135+
val fileFinder = JvmVirtualFileFinder.SERVICE.getInstance(project)
136+
val classFile = fileFinder.findVirtualFileWithHeader(classId) ?: return null
137+
return classFile.contentsToByteArray()
138+
}
139+
140+
fun readFromOutput(isForTestClasses: Boolean): ByteArray? {
141+
if (!ProjectRootsUtil.isProjectSourceFile(project, file)) return null
142+
143+
val module = ProjectFileIndex.SERVICE.getInstance(project).getModuleForFile(file)
144+
val outputDir = CompilerPaths.getModuleOutputDirectory(module, /*forTests = */ isForTestClasses) ?: return null
145+
146+
val className = fqNameWithInners.asString().replace('.', '$')
147+
var classByDirectory = findClassFileByPath(jvmName.packageFqName.asString(), className, outputDir)
148+
149+
if (classByDirectory == null) {
150+
if (!isForTestClasses) {
151+
return null
152+
}
153+
154+
val outputModeDirName = outputDir.name
155+
val androidTestOutputDir = outputDir.parent?.parent?.findChild("androidTest")?.findChild(outputModeDirName) ?: return null
156+
157+
classByDirectory = findClassFileByPath(jvmName.packageFqName.asString(), className, androidTestOutputDir) ?: return null
158+
}
159+
160+
return classByDirectory.readBytes()
161+
}
162+
163+
fun readFromSourceOutput(): ByteArray? = readFromOutput(false)
164+
165+
fun readFromTestOutput(): ByteArray? = readFromOutput(true)
166+
167+
return readFromLibrary() ?:
168+
readFromSourceOutput() ?:
169+
readFromTestOutput()
170+
}
171+
172+
private fun findClassFileByPath(packageName: String, className: String, outputDir: VirtualFile): File? {
173+
val outDirFile = File(outputDir.path).check(File::exists) ?: return null
174+
175+
val parentDirectory = File(outDirFile, packageName.replace(".", File.separator))
176+
if (!parentDirectory.exists()) return null
177+
178+
if (ApplicationManager.getApplication().isUnitTestMode) {
179+
val beforeDexFileClassFile = File(parentDirectory, className + ".class.before_dex")
180+
if (beforeDexFileClassFile.exists()) {
181+
return beforeDexFileClassFile
182+
}
183+
}
184+
185+
val classFile = File(parentDirectory, className + ".class")
186+
if (classFile.exists()) {
187+
return classFile
188+
}
189+
190+
return null
191+
}
192+
193+
private fun readLineNumberTableMapping(bytes: ByteArray): Map<BytecodeMethodKey, Map<String, Set<Int>>> {
77194
val lineNumberMapping = HashMap<BytecodeMethodKey, Map<String, Set<Int>>>()
78195

79196
ClassReader(bytes).accept(object : ClassVisitor(InlineCodegenUtil.API) {
80197
override fun visitMethod(access: Int, name: String?, desc: String?, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
81198
if (name == null || desc == null) {
82-
// TODO: check constructors
83199
return null
84200
}
85201

@@ -113,7 +229,7 @@ internal fun getOriginalPositionOfInlinedLine(location: Location, project: Proje
113229
return mapStacktraceLineToSource(smapData, lineNumber, project, SourceLineKind.EXECUTED_LINE, searchScope)
114230
}
115231

116-
internal fun findAndReadClassFile(
232+
private fun findAndReadClassFile(
117233
fqName: FqName, fileName: String, project: Project, searchScope: GlobalSearchScope,
118234
fileFilter: (VirtualFile) -> Boolean): BytecodeDebugInfo? {
119235
val internalName = fqName.asString().replace('.', '/')
@@ -124,7 +240,7 @@ internal fun findAndReadClassFile(
124240
val virtualFile = file.virtualFile ?: return null
125241
if (!fileFilter(virtualFile)) return null
126242

127-
return readClassFile(project, jvmClassName, virtualFile)
243+
return readDebugBytecodeInfo(project, jvmClassName, virtualFile)
128244
}
129245

130246
internal fun getLocationsOfInlinedLine(type: ReferenceType, position: SourcePosition, sourceSearchScope: GlobalSearchScope): List<Location> {
@@ -156,7 +272,7 @@ private fun inlinedLinesNumbers(
156272

157273
val virtualFile = file.virtualFile ?: return listOf()
158274

159-
val debugInfo = readClassFile(project, jvmClassName, virtualFile) ?: return listOf()
275+
val debugInfo = readDebugBytecodeInfo(project, jvmClassName, virtualFile) ?: return listOf()
160276
val smapData = debugInfo.smapData ?: return listOf()
161277

162278
val smap = smapData.kotlinStrata ?: return listOf()

idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinDebuggerCaches.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
4141
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
4242
import org.jetbrains.kotlin.idea.debugger.BinaryCacheKey
4343
import org.jetbrains.kotlin.idea.debugger.BytecodeDebugInfo
44-
import org.jetbrains.kotlin.idea.debugger.WeakConcurrentBinaryStorage
44+
import org.jetbrains.kotlin.idea.debugger.WeakBytecodeDebugInfoStorage
4545
import org.jetbrains.kotlin.idea.util.application.runReadAction
4646
import org.jetbrains.kotlin.psi.KtCodeFragment
4747
import org.jetbrains.kotlin.psi.KtElement
@@ -74,10 +74,10 @@ class KotlinDebuggerCaches(project: Project) {
7474
PsiModificationTracker.MODIFICATION_COUNT)
7575
}, false)
7676

77-
private val binaryCache = CachedValuesManager.getManager(project).createCachedValue(
77+
private val debugInfoCache = CachedValuesManager.getManager(project).createCachedValue(
7878
{
79-
CachedValueProvider.Result<WeakConcurrentBinaryStorage>(
80-
WeakConcurrentBinaryStorage(),
79+
CachedValueProvider.Result<WeakBytecodeDebugInfoStorage>(
80+
WeakBytecodeDebugInfoStorage(),
8181
PsiModificationTracker.MODIFICATION_COUNT)
8282
}, false)
8383

@@ -166,12 +166,12 @@ class KotlinDebuggerCaches(project: Project) {
166166
}
167167
}
168168

169-
fun readFileContent(
169+
fun getOrReadDebugInfoFromBytecode(
170170
project: Project,
171171
jvmName: JvmClassName,
172172
file: VirtualFile): BytecodeDebugInfo? {
173173
val cache = getInstance(project)
174-
return cache.binaryCache.value[BinaryCacheKey(project, jvmName, file)]
174+
return cache.debugInfoCache.value[BinaryCacheKey(project, jvmName, file)]
175175
}
176176

177177
private fun getElementToCreateTypeMapperForLibraryFile(element: PsiElement?) =

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

Lines changed: 0 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -16,136 +16,16 @@
1616

1717
package org.jetbrains.kotlin.idea.debugger
1818

19-
import com.intellij.openapi.application.ApplicationManager
20-
import com.intellij.openapi.compiler.CompilerPaths
2119
import com.intellij.openapi.project.Project
22-
import com.intellij.openapi.roots.ProjectFileIndex
23-
import com.intellij.openapi.vfs.VirtualFile
2420
import com.intellij.psi.search.GlobalSearchScope
25-
import com.intellij.util.containers.ConcurrentWeakFactoryMap
26-
import com.intellij.util.containers.ContainerUtil
2721
import org.jetbrains.kotlin.codegen.inline.FileMapping
2822
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
2923
import org.jetbrains.kotlin.codegen.inline.SMAP
3024
import org.jetbrains.kotlin.codegen.inline.SMAPParser
31-
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
32-
import org.jetbrains.kotlin.idea.refactoring.getLineCount
33-
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
34-
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
35-
import org.jetbrains.kotlin.load.kotlin.JvmVirtualFileFinder
36-
import org.jetbrains.kotlin.name.ClassId
37-
import org.jetbrains.kotlin.name.Name
38-
import org.jetbrains.kotlin.name.tail
3925
import org.jetbrains.kotlin.psi.KtFile
4026
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
41-
import org.jetbrains.kotlin.utils.addToStdlib.check
4227
import org.jetbrains.org.objectweb.asm.ClassReader
4328
import org.jetbrains.org.objectweb.asm.ClassVisitor
44-
import java.io.File
45-
46-
fun isInlineFunctionLineNumber(file: VirtualFile, lineNumber: Int, project: Project): Boolean {
47-
if (ProjectRootsUtil.isProjectSourceFile(project, file)) {
48-
val linesInFile = file.toPsiFile(project)?.getLineCount() ?: return false
49-
return lineNumber > linesInFile
50-
}
51-
52-
return true
53-
}
54-
55-
class WeakConcurrentBinaryStorage : ConcurrentWeakFactoryMap<BinaryCacheKey, BytecodeDebugInfo?>() {
56-
override fun create(key: BinaryCacheKey): BytecodeDebugInfo? {
57-
val bytes = readClassFileImpl(key.project, key.jvmName, key.file) ?: return null
58-
59-
val smapData = readDebugInfo(bytes)
60-
val lineNumberMapping = readLineNumberTableMapping(bytes)
61-
62-
return BytecodeDebugInfo(smapData, lineNumberMapping)
63-
}
64-
65-
override fun createMap(): Map<BinaryCacheKey, BytecodeDebugInfo?> {
66-
return ContainerUtil.createConcurrentWeakKeyWeakValueMap()
67-
}
68-
}
69-
70-
fun readClassFile(project: Project,
71-
jvmName: JvmClassName,
72-
file: VirtualFile): BytecodeDebugInfo? {
73-
return KotlinDebuggerCaches.readFileContent(project, jvmName, file)
74-
}
75-
76-
class BytecodeDebugInfo(val smapData: SmapData?, val lineTableMapping: Map<BytecodeMethodKey, Map<String, Set<Int>>>)
77-
78-
data class BytecodeMethodKey(val methodName: String, val signature: String)
79-
data class BinaryCacheKey(val project: Project, val jvmName: JvmClassName, val file: VirtualFile)
80-
81-
private fun readClassFileImpl(project: Project,
82-
jvmName: JvmClassName,
83-
file: VirtualFile): ByteArray? {
84-
val fqNameWithInners = jvmName.fqNameForClassNameWithoutDollars.tail(jvmName.packageFqName)
85-
86-
fun readFromLibrary(): ByteArray? {
87-
if (!ProjectRootsUtil.isLibrarySourceFile(project, file)) return null
88-
89-
val classId = ClassId(jvmName.packageFqName, Name.identifier(fqNameWithInners.asString()))
90-
91-
val fileFinder = JvmVirtualFileFinder.SERVICE.getInstance(project)
92-
val classFile = fileFinder.findVirtualFileWithHeader(classId) ?: return null
93-
return classFile.contentsToByteArray()
94-
}
95-
96-
fun readFromOutput(isForTestClasses: Boolean): ByteArray? {
97-
if (!ProjectRootsUtil.isProjectSourceFile(project, file)) return null
98-
99-
val module = ProjectFileIndex.SERVICE.getInstance(project).getModuleForFile(file)
100-
val outputDir = CompilerPaths.getModuleOutputDirectory(module, /*forTests = */ isForTestClasses) ?: return null
101-
102-
val className = fqNameWithInners.asString().replace('.', '$')
103-
var classByDirectory = findClassFileByPath(jvmName.packageFqName.asString(), className, outputDir)
104-
105-
if (classByDirectory == null) {
106-
if (!isForTestClasses) {
107-
return null
108-
}
109-
110-
val outputModeDirName = outputDir.name
111-
val androidTestOutputDir = outputDir.parent?.parent?.findChild("androidTest")?.findChild(outputModeDirName) ?: return null
112-
113-
classByDirectory = findClassFileByPath(jvmName.packageFqName.asString(), className, androidTestOutputDir) ?: return null
114-
}
115-
116-
println("Read file: " + classByDirectory)
117-
return classByDirectory.readBytes()
118-
}
119-
120-
fun readFromSourceOutput(): ByteArray? = readFromOutput(false)
121-
122-
fun readFromTestOutput(): ByteArray? = readFromOutput(true)
123-
124-
return readFromLibrary() ?:
125-
readFromSourceOutput() ?:
126-
readFromTestOutput()
127-
}
128-
129-
private fun findClassFileByPath(packageName: String, className: String, outputDir: VirtualFile): File? {
130-
val outDirFile = File(outputDir.path).check(File::exists) ?: return null
131-
132-
val parentDirectory = File(outDirFile, packageName.replace(".", File.separator))
133-
if (!parentDirectory.exists()) return null
134-
135-
if (ApplicationManager.getApplication().isUnitTestMode) {
136-
val beforeDexFileClassFile = File(parentDirectory, className + ".class.before_dex")
137-
if (beforeDexFileClassFile.exists()) {
138-
return beforeDexFileClassFile
139-
}
140-
}
141-
142-
val classFile = File(parentDirectory, className + ".class")
143-
if (classFile.exists()) {
144-
return classFile
145-
}
146-
147-
return null
148-
}
14929

15030
enum class SourceLineKind {
15131
CALL_LINE,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class KotlinExceptionFilter(private val searchScope: GlobalSearchScope) : Filter
7575
private fun createHyperlinks(jvmName: JvmClassName, file: VirtualFile, line: Int, project: Project): InlineFunctionHyperLinkInfo? {
7676
if (!isInlineFunctionLineNumber(file, line, project)) return null
7777

78-
val debugInfo = readClassFile(project, jvmName, file) ?: return null
78+
val debugInfo = readDebugBytecodeInfo(project, jvmName, file) ?: return null
7979
val smapData = debugInfo.smapData ?: return null
8080

8181
val inlineInfos = arrayListOf<InlineFunctionHyperLinkInfo.InlineInfo>()

0 commit comments

Comments
 (0)