Skip to content

Commit 6d1d0c9

Browse files
committed
feat: go to definition for JDK classes
1 parent 32362af commit 6d1d0c9

File tree

1 file changed

+20
-9
lines changed

1 file changed

+20
-9
lines changed

app/src/main/kotlin/org/kotlinlsp/actions/GoToDefinition.kt

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.analysis.api.analyze
1212
import org.jetbrains.kotlin.analysis.api.platform.packages.KotlinPackagePartProviderFactory
1313
import org.jetbrains.kotlin.analysis.api.symbols.KaCallableSymbol
1414
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinClassFileDecompiler
15+
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
1516
import org.jetbrains.kotlin.idea.references.mainReference
1617
import org.jetbrains.kotlin.psi.KtFile
1718
import org.jetbrains.kotlin.psi.KtReferenceExpression
@@ -29,10 +30,23 @@ fun goToDefinitionAction(ktFile: KtFile, position: Position): Location? = analyz
2930
val ref = ktFile.findReferenceAt(offset) ?: return null
3031
val element = ref.resolve() ?: return tryResolveFromKotlinLibrary(ktFile, offset)
3132
val file = element.containingFile ?: return null
33+
34+
// It comes from a java .class file
3235
if(file.viewProvider.document == null) {
33-
// This comes from a java .class file
34-
// TODO Handle the case of JDK .class files (jrt:// urls)
35-
return tryDecompileJavaClass(file)
36+
if(file.virtualFile.url.startsWith("jrt:/")) {
37+
// Comes from JDK
38+
val classFile = File.createTempFile("jrtClass", ".class")
39+
classFile.writeBytes(file.virtualFile.contentsToByteArray())
40+
val result = tryDecompileJavaClass(classFile.toPath())
41+
classFile.delete()
42+
return result
43+
} else {
44+
// Comes from JAR
45+
val classFile = extractClassFromJar("${file.containingDirectory}/${file.containingFile.name}") ?: return null
46+
val result = tryDecompileJavaClass(classFile.toPath())
47+
classFile.delete()
48+
return result
49+
}
3650
}
3751
val range = element.textRange.toLspRange(file)
3852
val folder = file.containingDirectory.toString().removePrefix("PsiDirectory:")
@@ -83,18 +97,17 @@ private fun KaSession.tryResolveFromKotlinLibrary(ktFile: KtFile, offset: Int):
8397
}
8498
}
8599

86-
private fun tryDecompileJavaClass(file: PsiFile): Location? {
87-
val classFile = extractClassFromJar("${file.containingDirectory}/${file.containingFile.name}") ?: return null
100+
private fun tryDecompileJavaClass(path: Path): Location? {
88101
val outputDir = Files.createTempDirectory("fernflower_output").toFile()
89102
try {
90103
val args = arrayOf(
91104
"-jpr=1",
92-
classFile.absolutePath,
105+
path.absolutePathString(),
93106
outputDir.absolutePath
94107
)
95108
ConsoleDecompiler.main(args)
96109

97-
val outName = classFile.toPath().fileName.replaceExtensionWith(".java")
110+
val outName = path.fileName.replaceExtensionWith(".java")
98111
val outPath = outputDir.toPath().resolve(outName)
99112
if (!Files.exists(outPath)) return null
100113
outPath.toFile().setWritable(false)
@@ -109,8 +122,6 @@ private fun tryDecompileJavaClass(file: PsiFile): Location? {
109122
} catch (e: Exception) {
110123
warn(e.message ?: "Unknown fernflower error")
111124
return null
112-
} finally {
113-
classFile.delete()
114125
}
115126
}
116127

0 commit comments

Comments
 (0)