blob: a82b24076e6ff09474fe983842399eca3686f015 [file] [log] [blame]
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.compiler.plugins.kotlin
import androidx.compose.compiler.plugins.kotlin.facade.SourceFile
import java.io.File
import org.intellij.lang.annotations.Language
import org.jetbrains.kotlin.codegen.GeneratedClassLoader
abstract class AbstractCodegenTest(useFir: Boolean) : AbstractCompilerTest(useFir) {
private fun dumpClasses(loader: GeneratedClassLoader) {
for (
file in loader.allGeneratedFiles.filter {
it.relativePath.endsWith(".class")
}
) {
println("------\nFILE: ${file.relativePath}\n------")
println(file.asText())
}
}
protected fun validateBytecode(
@Language("kotlin")
src: String,
dumpClasses: Boolean = false,
validate: (String) -> Unit
) {
val className = "Test_REPLACEME_${uniqueNumber++}"
val fileName = "$className.kt"
val loader = classLoader(
"""
@file:OptIn(
InternalComposeApi::class,
)
package test
import androidx.compose.runtime.*
$src
fun used(x: Any?) {}
""",
fileName, dumpClasses
)
val apiString = loader
.allGeneratedFiles
.filter { it.relativePath.endsWith(".class") }.joinToString("\n") {
it.asText().replace('$', '%').replace(className, "Test")
}
validate(apiString)
}
protected fun classLoader(
@Language("kotlin")
source: String,
fileName: String,
dumpClasses: Boolean = false
): GeneratedClassLoader {
val loader = createClassLoader(listOf(SourceFile(fileName, source)))
if (dumpClasses) dumpClasses(loader)
return loader
}
protected fun classLoader(
sources: Map<String, String>,
dumpClasses: Boolean = false
): GeneratedClassLoader {
val loader = createClassLoader(
sources.map { (fileName, source) -> SourceFile(fileName, source) }
)
if (dumpClasses) dumpClasses(loader)
return loader
}
protected fun classLoader(
platformSources: Map<String, String>,
commonSources: Map<String, String>,
dumpClasses: Boolean = false
): GeneratedClassLoader {
val loader = createClassLoader(
platformSources.map { (fileName, source) -> SourceFile(fileName, source) },
commonSources.map { (fileName, source) -> SourceFile(fileName, source) }
)
if (dumpClasses) dumpClasses(loader)
return loader
}
protected fun classLoader(
sources: Map<String, String>,
additionalPaths: List<File>,
dumpClasses: Boolean = false,
forcedFirSetting: Boolean? = null
): GeneratedClassLoader {
val loader = createClassLoader(
sources.map { (fileName, source) -> SourceFile(fileName, source) },
additionalPaths = additionalPaths,
forcedFirSetting = forcedFirSetting
)
if (dumpClasses) dumpClasses(loader)
return loader
}
protected fun testCompile(@Language("kotlin") source: String, dumpClasses: Boolean = false) {
classLoader(source, "Test.kt", dumpClasses)
}
protected val COMPOSE_VIEW_STUBS_IMPORTS = """
import android.view.View
import android.widget.TextView
import android.widget.Button
import android.view.Gravity
import android.widget.LinearLayout
import androidx.compose.runtime.Composable
""".trimIndent()
protected val COMPOSE_VIEW_STUBS = """
@Composable
fun TextView(
id: Int = 0,
gravity: Int = Gravity.TOP or Gravity.START,
text: String = "",
onClick: (() -> Unit)? = null,
onClickListener: View.OnClickListener? = null
) {
emitView(::TextView) {
if (id != 0) it.id = id
it.text = text
it.gravity = gravity
if (onClickListener != null) it.setOnClickListener(onClickListener)
if (onClick != null) it.setOnClickListener(View.OnClickListener { onClick() })
}
}
@Composable
fun Button(
id: Int = 0,
text: String = "",
onClick: (() -> Unit)? = null,
onClickListener: View.OnClickListener? = null
) {
emitView(::Button) {
if (id != 0) it.id = id
it.text = text
if (onClickListener != null) it.setOnClickListener(onClickListener)
if (onClick != null) it.setOnClickListener(View.OnClickListener { onClick() })
}
}
@Composable
fun LinearLayout(
id: Int = 0,
orientation: Int = LinearLayout.VERTICAL,
onClickListener: View.OnClickListener? = null,
content: @Composable () -> Unit
) {
emitView(
::LinearLayout,
{
if (id != 0) it.id = id
if (onClickListener != null) it.setOnClickListener(onClickListener)
it.orientation = orientation
},
content
)
}
""".trimIndent()
protected fun testCompileWithViewStubs(source: String, dumpClasses: Boolean = false) =
testCompile(
"""
$COMPOSE_VIEW_STUBS_IMPORTS
$source
$COMPOSE_VIEW_STUBS
""",
dumpClasses
)
}