Kapt3: Review fixes

This commit is contained in:
Yan Zhulanow
2016-11-01 19:53:32 +03:00
committed by Yan Zhulanow
parent 3a29bf5e01
commit e22ce14c36
6 changed files with 99 additions and 90 deletions
@@ -27,9 +27,9 @@ import org.jetbrains.org.objectweb.asm.tree.ClassNode
import org.jetbrains.org.objectweb.asm.tree.FieldNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
class Kapt3BuilderFactory : ClassBuilderFactory {
val compiledClasses = mutableListOf<ClassNode>()
val origins = mutableMapOf<Any, JvmDeclarationOrigin>()
internal class Kapt3BuilderFactory : ClassBuilderFactory {
internal val compiledClasses = mutableListOf<ClassNode>()
internal val origins = mutableMapOf<Any, JvmDeclarationOrigin>()
override fun getClassBuilderMode(): ClassBuilderMode = ClassBuilderMode.KAPT3
@@ -22,7 +22,6 @@ import com.sun.tools.javac.file.JavacFileManager
import com.sun.tools.javac.tree.JCTree
import com.sun.tools.javac.tree.JCTree.*
import com.sun.tools.javac.tree.TreeMaker
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -49,16 +48,16 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContext, val typeMappe
(Opcodes.ACC_DEPRECATED or Opcodes.ACC_INTERFACE or Opcodes.ACC_ANNOTATION or Opcodes.ACC_ENUM or Opcodes.ACC_STATIC).toLong()
private val METHOD_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or
(Opcodes.ACC_SYNCHRONIZED or Opcodes.ACC_STATIC or Opcodes.ACC_NATIVE or Opcodes.ACC_DEPRECATED).toLong()
(Opcodes.ACC_DEPRECATED or Opcodes.ACC_SYNCHRONIZED or Opcodes.ACC_NATIVE or Opcodes.ACC_STATIC).toLong()
private val FIELD_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or
(Opcodes.ACC_STATIC or Opcodes.ACC_VOLATILE or Opcodes.ACC_TRANSIENT or Opcodes.ACC_ENUM).toLong()
(Opcodes.ACC_VOLATILE or Opcodes.ACC_TRANSIENT or Opcodes.ACC_ENUM or Opcodes.ACC_STATIC).toLong()
private val PARAMETER_MODIFIERS = FIELD_MODIFIERS or Flags.PARAMETER or Flags.VARARGS or Opcodes.ACC_FINAL.toLong()
private val BLACKLISTED_ANNOTATATIONS = listOf(
private val BLACKLISTED_ANNOTATIONS = listOf(
"java.lang.Deprecated", "kotlin.Deprecated", // Deprecated annotations
"java.lang.Synthetic", //
"java.lang.Synthetic",
"java.lang.annotation.", // Java annotations
"org.jetbrains.annotations.", // Nullable/NotNull, ReadOnly, Mutable
"kotlin.jvm.", "kotlin.Metadata" // Kotlin annotations from runtime
@@ -74,18 +73,19 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContext, val typeMappe
fun convert(): JavacList<JCCompilationUnit> {
if (done) error(ClassFileToSourceStubConverter::class.java.simpleName + " can convert classes only once")
done = true
return mapValues(kaptContext.compiledClasses) { convertTopLevelClass(it) }
return mapJList(kaptContext.compiledClasses) { convertTopLevelClass(it) }
}
private fun convertTopLevelClass(clazz: ClassNode): JCCompilationUnit? {
val origin = kaptContext.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.isNested) return null
val classDeclaration = convertClass(clazz, true) ?: return null
val classDeclaration = convertClass(clazz) ?: return null
val packageAnnotations = JavacList.nil<JCAnnotation>()
val packageName = ktFile.packageFqName.asString()
@@ -103,7 +103,7 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContext, val typeMappe
/**
* Returns false for the inner classes or if the origin for the class was not found.
*/
private fun convertClass(clazz: ClassNode, isTopLevel: Boolean): JCClassDecl? {
private fun convertClass(clazz: ClassNode): JCClassDecl? {
if (isSynthetic(clazz.access)) return null
val descriptor = kaptContext.origins[clazz]?.descriptor as? ClassDescriptor ?: return null
@@ -119,14 +119,14 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContext, val typeMappe
&& descriptor.kind == ClassKind.INTERFACE
// DefaultImpls without any contents don't have INNERCLASS'es inside it (and inside the parent interface)
if (isDefaultImpls && (isTopLevel || (clazz.fields.isNullOrEmpty() && clazz.methods.isNullOrEmpty()))) {
if (isDefaultImpls && clazz.fields.isNullOrEmpty() && clazz.methods.isNullOrEmpty()) {
return null
}
val simpleName = treeMaker.name(if (isDefaultImpls) "DefaultImpls" else descriptor.name.asString())
val interfaces = mapValues(clazz.interfaces) {
if (isAnnotation && it == "java/lang/annotation/Annotation") return@mapValues null
val interfaces = mapJList(clazz.interfaces) {
if (isAnnotation && it == "java/lang/annotation/Annotation") return@mapJList null
treeMaker.FqName(it)
}
@@ -135,19 +135,19 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContext, val typeMappe
val hasSuperClass = clazz.superName != "java/lang/Object" && !isEnum
val genericType = signatureParser.parseClassSignature(clazz.signature, superClass, interfaces)
val fields = mapValues<FieldNode, JCTree>(clazz.fields) { convertField(it) }
val methods = mapValues<MethodNode, JCTree>(clazz.methods) {
val fields = mapJList<FieldNode, JCTree>(clazz.fields) { convertField(it) }
val methods = mapJList<MethodNode, JCTree>(clazz.methods) {
if (isEnum) {
if (it.name == "values" && it.desc == "()[L${clazz.name};") return@mapValues null
if (it.name == "valueOf" && it.desc == "(Ljava/lang/String;)L${clazz.name};") return@mapValues null
if (it.name == "values" && it.desc == "()[L${clazz.name};") return@mapJList null
if (it.name == "valueOf" && it.desc == "(Ljava/lang/String;)L${clazz.name};") return@mapJList null
}
convertMethod(it, clazz)
}
val nestedClasses = mapValues<InnerClassNode, JCTree>(clazz.innerClasses) { innerClass ->
if (innerClass.outerName != clazz.name) return@mapValues null
val innerClassNode = kaptContext.compiledClasses.firstOrNull { it.name == innerClass.name } ?: return@mapValues null
convertClass(innerClassNode, false)
val nestedClasses = mapJList<InnerClassNode, JCTree>(clazz.innerClasses) { innerClass ->
if (innerClass.outerName != clazz.name) return@mapJList null
val innerClassNode = kaptContext.compiledClasses.firstOrNull { it.name == innerClass.name } ?: return@mapJList null
convertClass(innerClassNode)
}
return treeMaker.ClassDef(
@@ -207,20 +207,23 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContext, val typeMappe
val parametersInfo = method.getParametersInfo(containingClass)
@Suppress("NAME_SHADOWING")
val parameters = mapValuesIndexed(parametersInfo) { index, info ->
val parameters = mapJListIndexed(parametersInfo) { index, info ->
val lastParameter = index == parametersInfo.lastIndex
val isArrayType = info.type.sort == Type.ARRAY
val varargs = if (lastParameter && isArrayType && method.isVarargs()) Flags.VARARGS else 0L
val modifiers = convertModifiers(
info.flags or varargs or Flags.PARAMETER,
ElementKind.PARAMETER, info.visibleAnnotations, info.invisibleAnnotations)
ElementKind.PARAMETER,
info.visibleAnnotations,
info.invisibleAnnotations)
val name = treeMaker.name(info.name)
val type = treeMaker.Type(info.type)
treeMaker.VarDef(modifiers, name, type, null)
}
val exceptionTypes = mapValues(method.exceptions) { treeMaker.FqName(it) }
val exceptionTypes = mapJList(method.exceptions) { treeMaker.FqName(it) }
val genericType = signatureParser.parseMethodSignature(method.signature, parameters, exceptionTypes, jcReturnType)
@@ -239,7 +242,7 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContext, val typeMappe
val superClassConstructor = superClass.constructors.firstOrNull { it.visibility.isVisible(null, it, declaration) }
val superClassConstructorCall = if (superClassConstructor != null) {
val args = mapValues(superClassConstructor.valueParameters) { param ->
val args = mapJList(superClassConstructor.valueParameters) { param ->
convertLiteralExpression(getDefaultValue(typeMapper.mapType(param.type)))
}
val call = treeMaker.Apply(JavacList.nil(), treeMaker.SimpleName("super"), args)
@@ -293,13 +296,16 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContext, val typeMappe
return treeMaker.Modifiers(flags, annotations)
}
private fun convertAnnotation(annotation: AnnotationNode): JCAnnotation? {
private fun convertAnnotation(annotation: AnnotationNode, filtered: Boolean = true): JCAnnotation? {
val annotationType = Type.getType(annotation.desc)
val fqName = annotationType.className
if (BLACKLISTED_ANNOTATATIONS.any { fqName.startsWith(it) }) return null
if (filtered) {
if (BLACKLISTED_ANNOTATIONS.any { fqName.startsWith(it) }) return null
}
val name = treeMaker.Type(annotationType)
val values = mapPairedValues<JCExpression>(annotation.values) { key, value ->
val values = mapPairedValuesJList<JCExpression>(annotation.values) { key, value ->
treeMaker.Assign(treeMaker.SimpleName(key), convertLiteralExpression(value))
}
return treeMaker.Annotation(name, values)
@@ -311,24 +317,24 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContext, val typeMappe
is Char -> treeMaker.Literal(TypeTag.CHAR, value.toInt())
is Byte, is Boolean, 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 ByteArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is BooleanArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is CharArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is ShortArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is IntArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is LongArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is FloatArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is DoubleArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is Array<*> -> { // Two-element String array for enumerations ([desc, fieldName])
assert(value.size == 2)
val enumType = Type.getType(value[0] as String)
val valueName = value[1] as String
treeMaker.Select(treeMaker.Type(enumType), treeMaker.name(valueName))
}
is List<*> -> treeMaker.NewArray(null, JavacList.nil(), org.jetbrains.kotlin.kapt3.mapValues(value) { convertLiteralExpression(it) })
is List<*> -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value) { convertLiteralExpression(it) })
is Type -> treeMaker.Select(treeMaker.Type(value), treeMaker.name("class"))
is AnnotationNode -> convertAnnotation(value) ?: error("Annotation is filtered out")
is AnnotationNode -> convertAnnotation(value, false)!!
else -> throw IllegalArgumentException("Illegal literal expression value: $value (${value.javaClass.canonicalName})")
}
}
@@ -24,15 +24,15 @@ import org.jetbrains.org.objectweb.asm.signature.SignatureVisitor
import java.util.*
import org.jetbrains.kotlin.kapt3.stubs.ElementKind.*
import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
import org.jetbrains.kotlin.kapt3.mapValues
import org.jetbrains.kotlin.kapt3.mapValuesIndexed
import org.jetbrains.kotlin.kapt3.mapJList
import org.jetbrains.kotlin.kapt3.mapJListIndexed
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.org.objectweb.asm.signature.SignatureReader
import com.sun.tools.javac.util.List as JavacList
/*
Root (Class)
* FormalTypeParameter
* TypeParameter
+ SuperClass
* Interface
@@ -67,10 +67,10 @@ import com.sun.tools.javac.util.List as JavacList
TypeVariable < InterfaceBound
SuperClass < TopLevel
+ ClassType
! ClassType
Interface < TopLevel
+ ClassType
! ClassType
ClassType < *
* TypeArgument
@@ -90,24 +90,25 @@ private class SignatureNode(val kind: ElementKind, val name: String? = null) {
class SignatureParser(val treeMaker: KaptTreeMaker) {
class ClassGenericSignature(
val typeParameters: com.sun.tools.javac.util.List<JCTypeParameter>,
val typeParameters: JavacList<JCTypeParameter>,
val superClass: JCExpression,
val interfaces: com.sun.tools.javac.util.List<JCExpression>)
val interfaces: JavacList<JCExpression>
)
class MethodGenericSignature(
val typeParameters: com.sun.tools.javac.util.List<JCTypeParameter>,
val parameterTypes: com.sun.tools.javac.util.List<JCVariableDecl>,
val exceptionTypes: com.sun.tools.javac.util.List<JCExpression>,
val typeParameters: JavacList<JCTypeParameter>,
val parameterTypes: JavacList<JCVariableDecl>,
val exceptionTypes: JavacList<JCExpression>,
val returnType: JCExpression?
)
fun parseClassSignature(
signature: String?,
rawSuperClass: JCExpression,
rawInterfaces: com.sun.tools.javac.util.List<JCExpression>
rawInterfaces: JavacList<JCExpression>
): ClassGenericSignature {
if (signature == null) {
return ClassGenericSignature(com.sun.tools.javac.util.List.nil(), rawSuperClass, rawInterfaces)
return ClassGenericSignature(JavacList.nil(), rawSuperClass, rawInterfaces)
}
val root = parse(signature)
@@ -116,20 +117,20 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
val interfaces = smartList()
root.split(typeParameters, TypeParameter, superClasses, SuperClass, interfaces, Interface)
val jcTypeParameters = mapValues(typeParameters) { parseTypeParameter(it) }
val jcTypeParameters = mapJList(typeParameters) { parseTypeParameter(it) }
val jcSuperClass = parseType(superClasses.single().children.single())
val jcInterfaces = mapValues(interfaces) { parseType(it.children.single()) }
val jcInterfaces = mapJList(interfaces) { parseType(it.children.single()) }
return ClassGenericSignature(jcTypeParameters, jcSuperClass, jcInterfaces)
}
fun parseMethodSignature(
signature: String?,
rawParameters: com.sun.tools.javac.util.List<JCVariableDecl>,
rawExceptionTypes: com.sun.tools.javac.util.List<JCExpression>,
rawParameters: JavacList<JCVariableDecl>,
rawExceptionTypes: JavacList<JCExpression>,
rawReturnType: JCExpression?
): MethodGenericSignature {
if (signature == null) {
return MethodGenericSignature(com.sun.tools.javac.util.List.nil(), rawParameters, rawExceptionTypes, rawReturnType)
return MethodGenericSignature(JavacList.nil(), rawParameters, rawExceptionTypes, rawReturnType)
}
val root = parse(signature)
@@ -139,14 +140,14 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
val returnTypes = smartList()
root.split(typeParameters, TypeParameter, parameterTypes, ParameterType, exceptionTypes, ExceptionType, returnTypes, ReturnType)
val jcTypeParameters = mapValues(typeParameters) { parseTypeParameter(it) }
val jcTypeParameters = mapJList(typeParameters) { parseTypeParameter(it) }
assert(rawParameters.size >= parameterTypes.size)
val offset = rawParameters.size - parameterTypes.size
val jcParameters = mapValuesIndexed(parameterTypes) { index, it ->
val jcParameters = mapJListIndexed(parameterTypes) { index, it ->
val rawParameter = rawParameters[index + offset]
treeMaker.VarDef(rawParameter.modifiers, rawParameter.getName(), parseType(it.children.single()), rawParameter.initializer)
}
val jcExceptionTypes = mapValues(exceptionTypes) { parseType(it) }
val jcExceptionTypes = mapJList(exceptionTypes) { parseType(it) }
val jcReturnType = if (rawReturnType == null) null else parseType(returnTypes.single().children.single())
return MethodGenericSignature(jcTypeParameters, jcParameters, jcExceptionTypes, jcReturnType)
}
@@ -173,7 +174,7 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
assert(classBounds.size <= 1)
val jcClassBound = classBounds.firstOrNull()?.let { parseBound(it) }
val jcInterfaceBounds = mapValues(interfaceBounds) { parseBound(it) }
val jcInterfaceBounds = mapJList(interfaceBounds) { parseBound(it) }
val allBounds = if (jcClassBound != null) jcInterfaceBounds.prepend(jcClassBound) else jcInterfaceBounds
return treeMaker.TypeParameter(treeMaker.name(node.name!!), allBounds)
}
@@ -192,9 +193,9 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
val fqNameExpression = treeMaker.FqName(classFqName)
if (args.isEmpty()) return fqNameExpression
treeMaker.TypeApply(fqNameExpression, mapValues(args) { arg ->
treeMaker.TypeApply(fqNameExpression, mapJList(args) { arg ->
assert(arg.kind == TypeArgument) { "Unexpected kind ${arg.kind}, $TypeArgument expected" }
val variance = arg.name ?: return@mapValues treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.UNBOUND), null)
val variance = arg.name ?: return@mapJList treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.UNBOUND), null)
val argType = parseType(arg.children.single())
when (variance.single()) {
@@ -331,17 +332,9 @@ private class SignatureParserVisitor : SignatureVisitor(Opcodes.ASM5) {
push(TypeArgument, parent = ClassType)
}
override fun visitTypeArgument(wildcard: Char): SignatureVisitor {
push(TypeArgument, parent = ClassType, name = wildcard.toString())
return super.visitTypeArgument(wildcard)
}
override fun visitClassType(name: String) {
push(ClassType, name = name)
}
override fun visitTypeVariable(name: String) {
push(TypeVariable, name = name)
override fun visitTypeArgument(variance: Char): SignatureVisitor {
push(TypeArgument, parent = ClassType, name = variance.toString())
return super.visitTypeArgument(variance)
}
override fun visitParameterType(): SignatureVisitor {
@@ -359,6 +352,14 @@ private class SignatureParserVisitor : SignatureVisitor(Opcodes.ASM5) {
return super.visitExceptionType()
}
override fun visitClassType(name: String) {
push(ClassType, name = name)
}
override fun visitTypeVariable(name: String) {
push(TypeVariable, name = name)
}
override fun visitBaseType(descriptor: Char) {
push(PrimitiveType, name = descriptor.toString())
}
@@ -22,7 +22,9 @@ class KaptLogger(val isVerbose: Boolean) {
}
fun info(message: String) {
if (isVerbose) println(PREFIX + message)
if (isVerbose) {
println(PREFIX + message)
}
}
inline fun info(message: () -> String) {
@@ -20,14 +20,14 @@ import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.ClassNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
internal fun isEnum(access: Int) = (access and Opcodes.ACC_ENUM) > 0
internal fun isPublic(access: Int) = (access and Opcodes.ACC_PUBLIC) > 0
internal fun isSynthetic(access: Int) = (access and Opcodes.ACC_SYNTHETIC) > 0
internal fun isFinal(access: Int) = (access and Opcodes.ACC_FINAL) > 0
internal fun isStatic(access: Int) = (access and Opcodes.ACC_STATIC) > 0
internal fun isAbstract(access: Int) = (access and Opcodes.ACC_ABSTRACT) > 0
internal fun ClassNode.isEnum() = (access and Opcodes.ACC_ENUM) > 0
internal fun ClassNode.isAnnotation() = (access and Opcodes.ACC_ANNOTATION) > 0
internal fun MethodNode.isVarargs() = (access and Opcodes.ACC_VARARGS) > 0
internal fun isEnum(access: Int) = (access and Opcodes.ACC_ENUM) != 0
internal fun isPublic(access: Int) = (access and Opcodes.ACC_PUBLIC) != 0
internal fun isSynthetic(access: Int) = (access and Opcodes.ACC_SYNTHETIC) != 0
internal fun isFinal(access: Int) = (access and Opcodes.ACC_FINAL) != 0
internal fun isStatic(access: Int) = (access and Opcodes.ACC_STATIC) != 0
internal fun isAbstract(access: Int) = (access and Opcodes.ACC_ABSTRACT) != 0
internal fun ClassNode.isEnum() = (access and Opcodes.ACC_ENUM) != 0
internal fun ClassNode.isAnnotation() = (access and Opcodes.ACC_ANNOTATION) != 0
internal fun MethodNode.isVarargs() = (access and Opcodes.ACC_VARARGS) != 0
internal fun <T> List<T>?.isNullOrEmpty() = this == null || this.isEmpty()
@@ -18,27 +18,27 @@ package org.jetbrains.kotlin.kapt3
import com.sun.tools.javac.util.List as JavacList
internal inline fun <T, R> mapValues(values: Iterable<T>?, f: (T) -> R?): JavacList<R> {
internal inline fun <T, R> mapJList(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) }
f(item)?.let { result = result.append(it) }
}
return result.reverse()
return result
}
internal inline fun <T, R> mapValuesIndexed(values: Iterable<T>?, f: (Int, T) -> R?): JavacList<R> {
internal inline fun <T, R> mapJListIndexed(values: Iterable<T>?, f: (Int, T) -> R?): JavacList<R> {
if (values == null) return JavacList.nil()
var result = JavacList.nil<R>()
values.forEachIndexed { index, item ->
f(index, item)?.let { result = result.prepend(it) }
f(index, item)?.let { result = result.append(it) }
}
return result.reverse()
return result
}
internal inline fun <T> mapPairedValues(valuePairs: List<Any>?, f: (String, Any) -> T?): JavacList<T> {
internal inline fun <T> mapPairedValuesJList(valuePairs: List<Any>?, f: (String, Any) -> T?): JavacList<T> {
if (valuePairs == null || valuePairs.isEmpty()) return JavacList.nil()
val size = valuePairs.size