Kapt3: Initial implementation of JCTreeConverter
This commit is contained in:
committed by
Yan Zhulanow
parent
f07f367ff6
commit
5f45b41d53
@@ -40,5 +40,6 @@
|
||||
<orderEntry type="module" module-name="idea-android-output-parser" scope="TEST" />
|
||||
<orderEntry type="module" module-name="idea-maven" scope="TEST" />
|
||||
<orderEntry type="module" module-name="uast-kotlin" scope="TEST" />
|
||||
<orderEntry type="module" module-name="kapt3" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -136,6 +136,7 @@ import org.jetbrains.kotlin.js.test.semantics.*
|
||||
import org.jetbrains.kotlin.jvm.compiler.*
|
||||
import org.jetbrains.kotlin.jvm.runtime.AbstractJvm8RuntimeDescriptorLoaderTest
|
||||
import org.jetbrains.kotlin.jvm.runtime.AbstractJvmRuntimeDescriptorLoaderTest
|
||||
import org.jetbrains.kotlin.kapt3.test.AbstractJCTreeConverterTest
|
||||
import org.jetbrains.kotlin.kdoc.AbstractKDocLexerTest
|
||||
import org.jetbrains.kotlin.lang.resolve.android.test.AbstractAndroidBoxTest
|
||||
import org.jetbrains.kotlin.lang.resolve.android.test.AbstractAndroidBytecodeShapeTest
|
||||
@@ -1137,6 +1138,12 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
}
|
||||
|
||||
testGroup("plugins/kapt3/test", "plugins/kapt3/testData") {
|
||||
testClass<AbstractJCTreeConverterTest> {
|
||||
model("converter")
|
||||
}
|
||||
}
|
||||
|
||||
testGroup("plugins/android-extensions/android-extensions-idea/tests", "plugins/android-extensions/android-extensions-idea/testData") {
|
||||
testClass<AbstractAndroidCompletionTest>() {
|
||||
model("android/completion", recursive = false, extension = null)
|
||||
|
||||
@@ -15,5 +15,6 @@
|
||||
<orderEntry type="library" scope="TEST" name="junit-4.12" level="project" />
|
||||
<orderEntry type="module" module-name="cli" />
|
||||
<orderEntry type="module" module-name="util" />
|
||||
<orderEntry type="module" module-name="tests-common" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.kapt3
|
||||
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
import com.sun.tools.javac.tree.JCTree.*
|
||||
import com.sun.tools.javac.tree.TreeMaker
|
||||
import com.sun.tools.javac.util.Context
|
||||
import com.sun.tools.javac.util.Name
|
||||
import com.sun.tools.javac.util.Names
|
||||
import com.sun.tools.javac.util.SharedNameTable
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
|
||||
class JCTreeConverter(context: Context, val classes: List<ClassNode>, val origins: Map<Any, JvmDeclarationOrigin>) {
|
||||
private companion object {
|
||||
private val BLACKLISTED_ANNOTATATIONS = listOf(
|
||||
"java.lang.Deprecated", "kotlin.Deprecated", // Deprecated annotations
|
||||
"java.lang.annotation.", // Java annotations
|
||||
"org.jetbrains.annotations.", // Nullable/NotNull, ReadOnly, Mutable
|
||||
"kotlin.jvm.", "kotlin.Metadata" // Kotlin annotations from runtime
|
||||
)
|
||||
}
|
||||
|
||||
private val treeMaker = TreeMaker.instance(context)
|
||||
private val nameTable = SharedNameTable(Names.instance(context))
|
||||
|
||||
private var done = false
|
||||
|
||||
fun convert(): JavacList<JCCompilationUnit> {
|
||||
if (done) error(JCTreeConverter::class.java.simpleName + " can convert classes only once")
|
||||
done = true
|
||||
return mapValues(classes) { convertTopLevelClass(it) }
|
||||
}
|
||||
|
||||
private fun convertTopLevelClass(clazz: ClassNode): JCCompilationUnit? {
|
||||
val origin = origins[clazz] ?: return null
|
||||
val ktFile = origin.element?.containingFile as? KtFile ?: return null
|
||||
val descriptor = origin.descriptor as? ClassDescriptor ?: return null
|
||||
|
||||
// Nested classes will be processed during the outer classes conversion
|
||||
if (descriptor.containingDeclaration is ClassDescriptor) return null
|
||||
|
||||
val classDeclaration = convert(clazz)
|
||||
|
||||
val packageAnnotations = JavacList.nil<JCAnnotation>()
|
||||
val packageName = ktFile.packageFqName.asString()
|
||||
val packageClause = if (packageName.isEmpty()) null else convertFqName(packageName)
|
||||
|
||||
val imports = JavacList.nil<JCTree>()
|
||||
val classes = JavacList.of<JCTree>(classDeclaration)
|
||||
|
||||
return treeMaker.TopLevel(packageAnnotations, packageClause, imports + classes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false for the inner classe or if the origin for the class was not found.
|
||||
*/
|
||||
private fun convert(clazz: ClassNode): JCClassDecl? {
|
||||
if (isSynthetic(clazz.access)) return null
|
||||
|
||||
val descriptor = origins[clazz]?.descriptor as? ClassDescriptor ?: return null
|
||||
val modifiers = convertModifiers(clazz.access, clazz.visibleAnnotations, clazz.invisibleAnnotations)
|
||||
val simpleName = name(descriptor.name.asString())
|
||||
val typeParams = JavacList.nil<JCTypeParameter>()
|
||||
val extending = if (clazz.superName == "java/lang/Object") null else convertFqName(clazz.superName)
|
||||
val implementing = mapValues(clazz.interfaces) { convertFqName(it) }
|
||||
|
||||
val fields = mapValues<FieldNode, JCTree>(clazz.fields) { convertField(it) }
|
||||
val methods = mapValues<MethodNode, JCTree>(clazz.methods) { convertMethod(it, simpleName) }
|
||||
val nestedClasses = mapValues<InnerClassNode, JCTree>(clazz.innerClasses) { innerClass ->
|
||||
if (innerClass.outerName != clazz.name) return@mapValues null
|
||||
val innerClassNode = classes.firstOrNull { it.name == innerClass.name } ?: return@mapValues null
|
||||
convert(innerClassNode)
|
||||
}
|
||||
|
||||
return treeMaker.ClassDef(modifiers, simpleName, typeParams, extending, implementing, fields + methods + nestedClasses)
|
||||
}
|
||||
|
||||
private fun convertField(field: FieldNode): JCVariableDecl? {
|
||||
if (isSynthetic(field.access)) return null
|
||||
|
||||
val modifiers = convertModifiers(field.access, field.visibleAnnotations, field.invisibleAnnotations)
|
||||
val name = name(field.name)
|
||||
val type = convertFqName(Type.getType(field.desc).className)
|
||||
val value = field.value
|
||||
val initializer = when (value) {
|
||||
is Byte, is Boolean, is Char, is Short, is Int, is Long, is Float, is Double, is String -> treeMaker.Literal(value)
|
||||
else -> null
|
||||
}
|
||||
return treeMaker.VarDef(modifiers, name, type, initializer)
|
||||
}
|
||||
|
||||
private fun convertMethod(method: MethodNode, containingClassSimpleName: Name): JCMethodDecl? {
|
||||
if (isSynthetic(method.access)) return null
|
||||
|
||||
val modifiers = convertModifiers(method.access, method.visibleAnnotations, method.invisibleAnnotations)
|
||||
val name = if (method.name == "<init>") containingClassSimpleName else name(method.name)
|
||||
val typeParameters = JavacList.nil<JCTypeParameter>()
|
||||
val receiverParameter = null
|
||||
|
||||
val returnType = Type.getReturnType(method.desc)
|
||||
val returnTypeExpr = convertFqName(returnType.className)
|
||||
|
||||
val parametersInfo = method.getParametersInfo()
|
||||
val parameters = mapValues(parametersInfo) { info ->
|
||||
val modifiers = convertModifiers(info.access, info.visibleAnnotations, info.invisibleAnnotations)
|
||||
val name = name(info.name)
|
||||
val type = convertFqName(info.type)
|
||||
treeMaker.VarDef(modifiers, name, type, null)
|
||||
}
|
||||
|
||||
val thrown = mapValues(method.exceptions) { convertFqName(it) }
|
||||
|
||||
val defaultValue = method.annotationDefault?.let { convertLiteralExpression(it) }
|
||||
|
||||
val body = if (defaultValue != null) {
|
||||
null
|
||||
} else {
|
||||
val returnStatement = treeMaker.Return(convertLiteralExpression(getDefaultValue(returnType)))
|
||||
treeMaker.Block(0, JavacList.of(returnStatement))
|
||||
}
|
||||
|
||||
return treeMaker.MethodDef(modifiers, name, returnTypeExpr,
|
||||
typeParameters, receiverParameter, parameters, thrown, body, defaultValue)
|
||||
}
|
||||
|
||||
private fun convertModifiers(
|
||||
access: Int,
|
||||
visibleAnnotations: List<AnnotationNode>?,
|
||||
invisibleAnnotations: List<AnnotationNode>?
|
||||
): JCModifiers {
|
||||
var annotations = visibleAnnotations?.fold(JavacList.nil<JCAnnotation>()) { list, anno ->
|
||||
convertAnnotation(anno)?.let { list.prepend(it) } ?: list
|
||||
} ?: JavacList.nil()
|
||||
annotations = invisibleAnnotations?.fold(annotations) { list, anno ->
|
||||
convertAnnotation(anno)?.let { list.prepend(it) } ?: list
|
||||
} ?: annotations
|
||||
|
||||
return treeMaker.Modifiers(access.toLong(), annotations)
|
||||
}
|
||||
|
||||
private fun convertAnnotation(annotation: AnnotationNode): JCAnnotation? {
|
||||
val fqName = Type.getType(annotation.desc).className
|
||||
if (BLACKLISTED_ANNOTATATIONS.any { fqName.startsWith(it) }) return null
|
||||
|
||||
val name = convertFqName(fqName)
|
||||
val values = mapPairedValues<JCExpression>(annotation.values) { key, value ->
|
||||
treeMaker.Assign(convertSimpleName(key), convertLiteralExpression(value))
|
||||
}
|
||||
return treeMaker.Annotation(name, values)
|
||||
}
|
||||
|
||||
private fun convertLiteralExpression(value: Any?): JCExpression {
|
||||
return when (value) {
|
||||
null -> convertSimpleName("null")
|
||||
is Byte, is Boolean, is Char, is Short, is Int, is Long, is Float, is Double, is String -> treeMaker.Literal(value)
|
||||
|
||||
is ByteArray -> treeMaker.NewArray(null, JavacList.nil(), mapValues(value.asIterable()) { convertLiteralExpression(it) })
|
||||
is BooleanArray -> treeMaker.NewArray(null, JavacList.nil(), mapValues(value.asIterable()) { convertLiteralExpression(it) })
|
||||
is CharArray -> treeMaker.NewArray(null, JavacList.nil(), mapValues(value.asIterable()) { convertLiteralExpression(it) })
|
||||
is ShortArray -> treeMaker.NewArray(null, JavacList.nil(), mapValues(value.asIterable()) { convertLiteralExpression(it) })
|
||||
is IntArray -> treeMaker.NewArray(null, JavacList.nil(), mapValues(value.asIterable()) { convertLiteralExpression(it) })
|
||||
is LongArray -> treeMaker.NewArray(null, JavacList.nil(), mapValues(value.asIterable()) { convertLiteralExpression(it) })
|
||||
is FloatArray -> treeMaker.NewArray(null, JavacList.nil(), mapValues(value.asIterable()) { convertLiteralExpression(it) })
|
||||
is DoubleArray -> treeMaker.NewArray(null, JavacList.nil(), mapValues(value.asIterable()) { convertLiteralExpression(it) })
|
||||
is Array<*> -> treeMaker.NewArray(null, JavacList.nil(), mapValues(value.asIterable()) { convertLiteralExpression(it) })
|
||||
is List<*> -> treeMaker.NewArray(null, JavacList.nil(), mapValues(value) { convertLiteralExpression(it) })
|
||||
|
||||
is Type -> treeMaker.Select(convertFqName(value.className), name("class"))
|
||||
is AnnotationNode -> convertAnnotation(value) ?: error("Annotation is filtered out")
|
||||
else -> throw IllegalArgumentException("Illegal literal expression value: $value (${value.javaClass.canonicalName})")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDefaultValue(type: Type): Any? = when (type) {
|
||||
Type.BYTE_TYPE -> 0.toByte()
|
||||
Type.BOOLEAN_TYPE -> false
|
||||
Type.CHAR_TYPE -> '\u0000'
|
||||
Type.SHORT_TYPE -> 0.toShort()
|
||||
Type.INT_TYPE -> 0
|
||||
Type.LONG_TYPE -> 0L
|
||||
Type.FLOAT_TYPE -> 0.0F
|
||||
Type.DOUBLE_TYPE -> 0.0
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun convertFqName(internalOrFqName: String): JCExpression {
|
||||
val path = internalOrFqName.replace('/', '.').split('.')
|
||||
assert(path.isNotEmpty())
|
||||
if (path.size == 1) return convertSimpleName(path.single())
|
||||
|
||||
var expr = treeMaker.Select(convertSimpleName(path[0]), name(path[1]))
|
||||
for (index in 2..path.lastIndex) {
|
||||
expr = treeMaker.Select(expr, name(path[index]))
|
||||
}
|
||||
return expr
|
||||
}
|
||||
|
||||
private fun convertSimpleName(name: String): JCIdent = treeMaker.Ident(name(name))
|
||||
|
||||
private fun name(name: String) = nameTable.fromString(name)
|
||||
}
|
||||
|
||||
private class ParameterInfo(
|
||||
val access: Int,
|
||||
val name: String,
|
||||
val type: String,
|
||||
val visibleAnnotations: List<AnnotationNode>?,
|
||||
val invisibleAnnotations: List<AnnotationNode>?)
|
||||
|
||||
private fun MethodNode.getParametersInfo(): List<ParameterInfo> {
|
||||
val localVariables = this.localVariables ?: emptyList()
|
||||
val parameters = this.parameters ?: emptyList()
|
||||
val isStatic = (access and Opcodes.ACC_STATIC) > 0
|
||||
val parameterTypes = Type.getArgumentTypes(desc)
|
||||
return parameterTypes.mapIndexed { index, type ->
|
||||
val name = parameters.getOrNull(index)?.name ?: localVariables.getOrNull(index + (if (isStatic) 0 else 1))?.name ?: "p$index"
|
||||
val visibleAnnotations = visibleParameterAnnotations?.get(index)
|
||||
val invisibleAnnotations = invisibleParameterAnnotations?.get(index)
|
||||
ParameterInfo(0, name, type.className, visibleAnnotations, invisibleAnnotations)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T, R> mapValues(values: Iterable<T>?, f: (T) -> R?): JavacList<R> {
|
||||
if (values == null) return JavacList.nil()
|
||||
|
||||
var result = JavacList.nil<R>()
|
||||
for (item in values) {
|
||||
f(item)?.let { result = result.prepend(it) }
|
||||
}
|
||||
return result.reverse()
|
||||
}
|
||||
|
||||
private inline fun <T> mapPairedValues(valuePairs: List<Any>?, f: (String, Any) -> T?): JavacList<T> {
|
||||
if (valuePairs == null || valuePairs.isEmpty()) return JavacList.nil()
|
||||
|
||||
val size = valuePairs.size
|
||||
var result = JavacList.nil<T>()
|
||||
assert(size % 2 == 0)
|
||||
var index = 0
|
||||
while (index < size) {
|
||||
val key = valuePairs[index] as String
|
||||
val value = valuePairs[index + 1]
|
||||
f(key, value)?.let { result = result.prepend(it) }
|
||||
index += 2
|
||||
}
|
||||
return result.reverse()
|
||||
}
|
||||
|
||||
private operator fun <T : Any> JavacList<T>.plus(other: JavacList<T>): JavacList<T> {
|
||||
return this.appendList(other)
|
||||
}
|
||||
|
||||
private fun isSynthetic(access: Int) = (access and Opcodes.ACC_SYNTHETIC) > 0
|
||||
+1
-1
@@ -77,7 +77,7 @@ class Kapt3AnalysisCompletedHandlerExtension(
|
||||
}
|
||||
}
|
||||
|
||||
private class Kapt3BuilderFactory : ClassBuilderFactory {
|
||||
class Kapt3BuilderFactory : ClassBuilderFactory {
|
||||
val compiledClasses = mutableListOf<ClassNode>()
|
||||
val origins = mutableMapOf<Any, JvmDeclarationOrigin>()
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class KaptError : RuntimeException {
|
||||
}
|
||||
|
||||
class KaptRunner {
|
||||
private val context = Context()
|
||||
val context = Context()
|
||||
private val options: Options
|
||||
|
||||
init {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.kapt3.test
|
||||
|
||||
import org.jetbrains.kotlin.codegen.CodegenTestCase
|
||||
import org.jetbrains.kotlin.codegen.CodegenTestUtil
|
||||
import org.jetbrains.kotlin.kapt3.JCTreeConverter
|
||||
import org.jetbrains.kotlin.kapt3.Kapt3BuilderFactory
|
||||
import org.jetbrains.kotlin.kapt3.KaptRunner
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractJCTreeConverterTest : CodegenTestCase() {
|
||||
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>, javaFilesDir: File?) {
|
||||
val javaSources = javaFilesDir?.let { arrayOf(it) } ?: emptyArray()
|
||||
|
||||
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL, *javaSources)
|
||||
loadMultiFiles(files)
|
||||
|
||||
val txtFile = File(wholeFile.parentFile, wholeFile.nameWithoutExtension + ".txt")
|
||||
val classBuilderFactory = Kapt3BuilderFactory()
|
||||
CodegenTestUtil.generateFiles(myEnvironment, myFiles, classBuilderFactory)
|
||||
|
||||
val kaptRunner = KaptRunner()
|
||||
val converter = JCTreeConverter(kaptRunner.context, classBuilderFactory.compiledClasses, classBuilderFactory.origins)
|
||||
val javaFiles = converter.convert()
|
||||
|
||||
KotlinTestUtils.assertEqualsToFile(txtFile, javaFiles.joinToString("\n\n////////////////////\n\n"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.kapt3.test;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("plugins/kapt3/testData/converter")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class JCTreeConverterTestGenerated extends AbstractJCTreeConverterTest {
|
||||
public void testAllFilesPresentInConverter() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/kapt3/testData/converter"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClass.kt")
|
||||
public void testDataClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/dataClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
+18
-1
@@ -1,6 +1,23 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.kapt3.test
|
||||
|
||||
import org.jetbrains.kotlin.kapt3.KaptError
|
||||
import org.jetbrains.kotlin.kapt3.KaptRunner
|
||||
import org.junit.Assert
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
@@ -0,0 +1 @@
|
||||
data class User(val firstName: String, val secondName: String, val age: Int)
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
public final synchronized class User {
|
||||
private final java.lang.String firstName;
|
||||
private final java.lang.String secondName;
|
||||
private final int age;
|
||||
|
||||
public final java.lang.String getFirstName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final java.lang.String getSecondName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final int getAge() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void User(java.lang.String firstName, java.lang.String secondName, int age) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final java.lang.String component1() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final java.lang.String component2() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final int component3() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public final User copy(java.lang.String firstName, java.lang.String secondName, int age) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public java.lang.String toString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean equals(java.lang.Object p0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user