[decompiler] add tests for generated psi text by builtin decompiler

This commit is contained in:
Ilya Kirillov
2023-08-25 21:47:13 +02:00
committed by Space Team
parent 5fc458d5a4
commit 714cb67254
7 changed files with 1379 additions and 31 deletions
@@ -1,28 +0,0 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.api.standalone.base.project.structure
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import com.intellij.util.io.URLUtil
import org.jetbrains.kotlin.analysis.decompiler.psi.BuiltInsVirtualFileProviderBaseImpl
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import java.net.URL
internal class BuiltInsVirtualFileProviderImp(
private val jarFileSystem: CoreJarFileSystem,
) : BuiltInsVirtualFileProviderBaseImpl() {
override fun findVirtualFile(url: URL): VirtualFile? {
val split = URLUtil.splitJarUrl(url.path)
?: errorWithAttachment("URL for builtins does not contain jar separator") {
withEntry("url", url) { url.toString() }
}
val jarPath = split.first
val builtInFile = split.second
val pathToQuery = jarPath + URLUtil.JAR_SEPARATOR + builtInFile
return jarFileSystem.findFileByPath(pathToQuery)
}
}
@@ -11,7 +11,6 @@ import com.intellij.core.CoreApplicationEnvironment
import com.intellij.core.CoreJavaFileManager
import com.intellij.core.CorePackageIndex
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.mock.MockApplication
import com.intellij.mock.MockProject
import com.intellij.openapi.Disposable
import com.intellij.openapi.extensions.PluginDescriptor
@@ -34,6 +33,7 @@ import org.jetbrains.kotlin.analysis.api.impl.base.java.source.JavaElementSource
import org.jetbrains.kotlin.analysis.api.impl.base.references.HLApiReferenceProviderService
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider
import org.jetbrains.kotlin.analysis.decompiler.psi.BuiltInsVirtualFileProvider
import org.jetbrains.kotlin.analysis.decompiler.psi.BuiltInsVirtualFileProviderCliImpl
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
import org.jetbrains.kotlin.analysis.decompiler.stub.file.DummyFileAttributeService
import org.jetbrains.kotlin.analysis.decompiler.stub.file.FileAttributeService
@@ -114,7 +114,7 @@ object StandaloneProjectFactory {
registerService(ClsKotlinBinaryClassCache::class.java)
registerService(
BuiltInsVirtualFileProvider::class.java,
BuiltInsVirtualFileProviderImp(applicationEnvironment.jarFileSystem as CoreJarFileSystem)
BuiltInsVirtualFileProviderCliImpl(applicationEnvironment.jarFileSystem as CoreJarFileSystem)
)
registerService(FileAttributeService::class.java, DummyFileAttributeService::class.java)
}
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.analysis.decompiler.psi
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import com.intellij.util.io.URLUtil
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
@@ -43,4 +45,17 @@ abstract class BuiltInsVirtualFileProviderBaseImpl : BuiltInsVirtualFileProvider
override fun getBuiltInVirtualFiles(): Set<VirtualFile> = builtinFiles
}
class BuiltInsVirtualFileProviderCliImpl(
private val jarFileSystem: CoreJarFileSystem,
) : BuiltInsVirtualFileProviderBaseImpl() {
override fun findVirtualFile(url: URL): VirtualFile? {
val split = URLUtil.splitJarUrl(url.path)
?: errorWithAttachment("URL for builtins does not contain jar separator") {
withEntry("url", url) { url.toString() }
}
val jarPath = split.first
val builtInFile = split.second
val pathToQuery = jarPath + URLUtil.JAR_SEPARATOR + builtInFile
return jarFileSystem.findFileByPath(pathToQuery)
}
}
@@ -0,0 +1,205 @@
// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available
package kotlin.collections
public interface Collection<out E> : kotlin.collections.Iterable<E> {
public abstract val size: kotlin.Int
public abstract operator fun contains(element: E): kotlin.Boolean
public abstract fun containsAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
public abstract fun isEmpty(): kotlin.Boolean
public abstract operator fun iterator(): kotlin.collections.Iterator<E>
}
public interface Iterable<out T> {
public abstract operator fun iterator(): kotlin.collections.Iterator<T>
}
public interface Iterator<out T> {
public abstract operator fun hasNext(): kotlin.Boolean
public abstract operator fun next(): T
}
public interface List<out E> : kotlin.collections.Collection<E> {
public abstract val size: kotlin.Int
public abstract operator fun contains(element: E): kotlin.Boolean
public abstract fun containsAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
public abstract operator fun get(index: kotlin.Int): E
public abstract fun indexOf(element: E): kotlin.Int
public abstract fun isEmpty(): kotlin.Boolean
public abstract operator fun iterator(): kotlin.collections.Iterator<E>
public abstract fun lastIndexOf(element: E): kotlin.Int
public abstract fun listIterator(): kotlin.collections.ListIterator<E>
public abstract fun listIterator(index: kotlin.Int): kotlin.collections.ListIterator<E>
public abstract fun subList(fromIndex: kotlin.Int, toIndex: kotlin.Int): kotlin.collections.List<E>
}
public interface ListIterator<out T> : kotlin.collections.Iterator<T> {
public abstract operator fun hasNext(): kotlin.Boolean
public abstract fun hasPrevious(): kotlin.Boolean
public abstract operator fun next(): T
public abstract fun nextIndex(): kotlin.Int
public abstract fun previous(): T
public abstract fun previousIndex(): kotlin.Int
}
public interface Map<K, out V> {
public abstract val entries: kotlin.collections.Set<kotlin.collections.Map.Entry<K, V>>
public abstract val keys: kotlin.collections.Set<K>
public abstract val size: kotlin.Int
public abstract val values: kotlin.collections.Collection<V>
public abstract fun containsKey(key: K): kotlin.Boolean
public abstract fun containsValue(value: V): kotlin.Boolean
public abstract operator fun get(key: K): V?
@kotlin.SinceKotlin @kotlin.internal.PlatformDependent public open fun getOrDefault(key: K, defaultValue: V): V { /* compiled code */ }
public abstract fun isEmpty(): kotlin.Boolean
public interface Entry<out K, out V> {
public abstract val key: K
public abstract val value: V
}
}
public interface MutableCollection<E> : kotlin.collections.Collection<E>, kotlin.collections.MutableIterable<E> {
public abstract fun add(element: E): kotlin.Boolean
public abstract fun addAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
public abstract fun clear(): kotlin.Unit
public abstract operator fun iterator(): kotlin.collections.MutableIterator<E>
public abstract fun remove(element: E): kotlin.Boolean
public abstract fun removeAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
public abstract fun retainAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
}
public interface MutableIterable<out T> : kotlin.collections.Iterable<T> {
public abstract operator fun iterator(): kotlin.collections.MutableIterator<T>
}
public interface MutableIterator<out T> : kotlin.collections.Iterator<T> {
public abstract fun remove(): kotlin.Unit
}
public interface MutableList<E> : kotlin.collections.List<E>, kotlin.collections.MutableCollection<E> {
public abstract fun add(element: E): kotlin.Boolean
public abstract fun add(index: kotlin.Int, element: E): kotlin.Unit
public abstract fun addAll(index: kotlin.Int, elements: kotlin.collections.Collection<E>): kotlin.Boolean
public abstract fun addAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
public abstract fun clear(): kotlin.Unit
public abstract fun listIterator(): kotlin.collections.MutableListIterator<E>
public abstract fun listIterator(index: kotlin.Int): kotlin.collections.MutableListIterator<E>
public abstract fun remove(element: E): kotlin.Boolean
public abstract fun removeAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
public abstract fun removeAt(index: kotlin.Int): E
public abstract fun retainAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
public abstract operator fun set(index: kotlin.Int, element: E): E
public abstract fun subList(fromIndex: kotlin.Int, toIndex: kotlin.Int): kotlin.collections.MutableList<E>
}
public interface MutableListIterator<T> : kotlin.collections.ListIterator<T>, kotlin.collections.MutableIterator<T> {
public abstract fun add(element: T): kotlin.Unit
public abstract operator fun hasNext(): kotlin.Boolean
public abstract operator fun next(): T
public abstract fun remove(): kotlin.Unit
public abstract fun set(element: T): kotlin.Unit
}
public interface MutableMap<K, V> : kotlin.collections.Map<K, V> {
public abstract val entries: kotlin.collections.MutableSet<kotlin.collections.MutableMap.MutableEntry<K, V>>
public abstract val keys: kotlin.collections.MutableSet<K>
public abstract val values: kotlin.collections.MutableCollection<V>
public abstract fun clear(): kotlin.Unit
public abstract fun put(key: K, value: V): V?
public abstract fun putAll(from: kotlin.collections.Map<out K, V>): kotlin.Unit
public abstract fun remove(key: K): V?
@kotlin.SinceKotlin @kotlin.internal.PlatformDependent public open fun remove(key: K, value: V): kotlin.Boolean { /* compiled code */ }
public interface MutableEntry<K, V> : kotlin.collections.Map.Entry<K, V> {
public abstract fun setValue(newValue: V): V
}
}
public interface MutableSet<E> : kotlin.collections.Set<E>, kotlin.collections.MutableCollection<E> {
public abstract fun add(element: E): kotlin.Boolean
public abstract fun addAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
public abstract fun clear(): kotlin.Unit
public abstract operator fun iterator(): kotlin.collections.MutableIterator<E>
public abstract fun remove(element: E): kotlin.Boolean
public abstract fun removeAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
public abstract fun retainAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
}
public interface Set<out E> : kotlin.collections.Collection<E> {
public abstract val size: kotlin.Int
public abstract operator fun contains(element: E): kotlin.Boolean
public abstract fun containsAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
public abstract fun isEmpty(): kotlin.Boolean
public abstract operator fun iterator(): kotlin.collections.Iterator<E>
}
@@ -0,0 +1,6 @@
// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available
package kotlin.coroutines
private fun hackToForceKotlinBuiltinsForKotlinCoroutinesPackage(): kotlin.Unit { /* compiled code */ }
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.decompiler.psi
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.analysis.decompiler.stub.files.AbstractDecompiledClassTest
import org.jetbrains.kotlin.idea.KotlinLanguage.INSTANCE
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.nio.file.Files
import java.nio.file.Paths
import kotlin.io.path.name
import kotlin.streams.toList
class BuiltinDecompilerToTextTest : AbstractDecompiledClassTest() {
fun testBuiltinDecompilationToText() {
val decompiledBuiltInKtFiles = loadBuiltIns()
val testDataPath = Paths.get(TEST_DATA_PATH)
for (file in decompiledBuiltInKtFiles) {
val resultFileName = file.name + DECOMPILED_TEXT_EXTENSION
val expectedFile = testDataPath.resolve(resultFileName)
KotlinTestUtils.assertEqualsToFile(expectedFile, file.text)
}
val expectedBuiltins = Files.list(testDataPath).toList()
assertEquals(
expectedBuiltins.map { it.name.removeSuffix(DECOMPILED_TEXT_EXTENSION) }.sorted(),
decompiledBuiltInKtFiles.map { it.name }.sorted(),
)
}
private fun loadBuiltIns(): Collection<KtFile> {
val psiManager = PsiManager.getInstance(project)
val builtInDecompiler = KotlinBuiltInDecompiler()
return BuiltInsVirtualFileProvider.getInstance().getBuiltInVirtualFiles().mapNotNull { virtualFile ->
createKtFileStub(psiManager, builtInDecompiler, virtualFile)
}
}
private fun createKtFileStub(
psiManager: PsiManager,
builtInDecompiler: KotlinBuiltInDecompiler,
virtualFile: VirtualFile,
): KtFile? {
val fileViewProvider = builtInDecompiler.createFileViewProvider(virtualFile, psiManager, physical = true)
val psiFile = fileViewProvider.getPsi(INSTANCE)
return psiFile as KtFile?
}
override fun setUp() {
super.setUp()
val applicationEnvironment = environment.projectEnvironment.environment
val application = applicationEnvironment.application
if (application.getService(BuiltInsVirtualFileProvider::class.java) == null) {
application.registerService(
BuiltInsVirtualFileProvider::class.java,
BuiltInsVirtualFileProviderCliImpl(applicationEnvironment.jarFileSystem as CoreJarFileSystem)
)
}
}
companion object {
private const val TEST_DATA_PATH = "analysis/decompiled/decompiler-to-psi/testData/builtins"
private const val DECOMPILED_TEXT_EXTENSION = ".decompiled.text.kt"
}
}