Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
stefankoppier committed Jun 17, 2024
1 parent 0e0c71b commit 14a8d79
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package io.github.mappie.resolving.classes

import io.github.mappie.resolving.*
import io.github.mappie.util.getterName
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.fileEntry
import org.jetbrains.kotlin.ir.util.hasDefaultValue
import org.jetbrains.kotlin.ir.util.isClass

class ClassResolver(private val declaration: IrFunction) {
Expand All @@ -16,39 +14,16 @@ class ClassResolver(private val declaration: IrFunction) {
require(declaration.returnType.getClass()!!.isClass)
}

fun resolve(): List<Mapping> {
val possibilities = declaration.accept(ConstructorsCollector(), Unit)
val getters = sourceParameter.accept(GettersCollector(), Unit)
val dispatchReceiverSymbol = sourceParameter.symbol
val concreteSources = declaration.body?.accept(ObjectBodyCollector(declaration.fileEntry, dispatchReceiverSymbol), Unit) ?: emptyList()
fun resolve(): List<ConstructorCallMapping> {
val constructor = ObjectMappingsConstructor.of(declaration.returnType, sourceParameter)
.apply { getters.addAll(sourceParameter.accept(GettersCollector(), Unit)) }

return possibilities.map { constructor ->
val targets = constructor.valueParameters
val mappings = targets.associateWith { target ->
val concreteSource = concreteSources.firstOrNull { it.first == target.name }
declaration.body?.accept(ObjectMappingBodyCollector(declaration.fileEntry, sourceParameter.symbol), constructor)

if (concreteSource != null) {
listOf(concreteSource.second)
} else {
val getter = getters.firstOrNull { getter ->
getter.name == getterName(target.name)
}
if (getter != null) {
listOf(PropertySource(getter.symbol, target.type, sourceParameter.symbol, true))
} else if (target.hasDefaultValue()) {
listOf(DefaultParameterValueSource(target.defaultValue!!.expression))
} else {
emptyList()
}
}
}

ConstructorCallMapping(
targetType = declaration.returnType,
sourceType = sourceParameter.type,
symbol = constructor.symbol,
mappings = mappings
)
return declaration.accept(ConstructorsCollector(), Unit).map {
ObjectMappingsConstructor.of(constructor).apply {
this.constructor = it
}.construct()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,34 +23,34 @@ import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name

class ObjectBodyCollector(
class ObjectMappingBodyCollector(
file: IrFileEntry,
private val dispatchReceiverSymbol: IrValueSymbol,
) : BaseVisitor<List<Pair<Name, ObjectMappingSource>>, Unit>(file) {
) : BaseVisitor<ObjectMappingsConstructor, ObjectMappingsConstructor>(file) {

override fun visitBlockBody(body: IrBlockBody, data: Unit): List<Pair<Name, ObjectMappingSource>> {
override fun visitBlockBody(body: IrBlockBody, data: ObjectMappingsConstructor): ObjectMappingsConstructor {
return body.statements.single().accept(data)
}

override fun visitReturn(expression: IrReturn, data: Unit): List<Pair<Name, ObjectMappingSource>> {
override fun visitReturn(expression: IrReturn, data: ObjectMappingsConstructor): ObjectMappingsConstructor {
return expression.value.accept(data)
}

override fun visitCall(expression: IrCall, data: Unit): List<Pair<Name, ObjectMappingSource>> {
override fun visitCall(expression: IrCall, data: ObjectMappingsConstructor): ObjectMappingsConstructor {
return when (expression.symbol.owner.name) {
IDENTIFIER_MAPPING -> {
expression.valueArguments.first()?.accept(data) ?: emptyList()
expression.valueArguments.first()?.accept(data) ?: data
}
else -> {
emptyList()
data
}
}
}

override fun visitFunctionExpression(expression: IrFunctionExpression, data: Unit): List<Pair<Name, ObjectMappingSource>> {
return expression.function.body!!.statements.mapNotNull {
it.accept(ObjectBodyStatementCollector(file, dispatchReceiverSymbol), Unit)
}
override fun visitFunctionExpression(expression: IrFunctionExpression, data: ObjectMappingsConstructor): ObjectMappingsConstructor {
return expression.function.body?.statements?.fold(data) { acc, current ->
acc.let { current.accept(ObjectBodyStatementCollector(file, dispatchReceiverSymbol), Unit)?.let { acc.explicit(it) } ?: it }
} ?: data
}
}

Expand All @@ -62,13 +62,13 @@ private class ObjectBodyStatementCollector(
override fun visitCall(expression: IrCall, data: Unit): Pair<Name, ObjectMappingSource>? {
return when (expression.symbol.owner.name) {
IDENTIFIER_MAPPED_FROM_PROPERTY, IDENTIFIER_MAPPED_FROM_CONSTANT -> {
val target = expression.extensionReceiver!!.accept(TargetValueCollector(), Unit)
val target = expression.extensionReceiver!!.accept(TargetValueCollector(), data)
val source = expression.valueArguments.first()!!.accept(SourceValueCollector(dispatchReceiverSymbol), Unit)

target to source
}
IDENTIFIER_MAPPED_FROM_EXPRESSION -> {
val target = expression.extensionReceiver!!.accept(TargetValueCollector(), Unit)
val target = expression.extensionReceiver!!.accept(TargetValueCollector(), data)
val source = expression.valueArguments.first() as IrFunctionExpression

target to ExpressionSource(
Expand Down Expand Up @@ -131,8 +131,6 @@ private class MapperReferenceCollector : BaseVisitor<IrFunctionExpression, Unit>
.wrap(expression)
}



override fun visitCall(expression: IrCall, data: Unit): IrFunctionExpression {
require(expression.origin == IrStatementOrigin.GET_PROPERTY)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package io.github.mappie.resolving.classes

import io.github.mappie.resolving.ConstructorCallMapping
import io.github.mappie.util.getterName
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.hasDefaultValue
import org.jetbrains.kotlin.name.Name

class ObjectMappingsConstructor(val targetType: IrType, val source: IrValueParameter) {

var getters = mutableListOf<IrSimpleFunction>()

// TODO: Map of lists for detecting duplicates
var explicit = mutableListOf<Pair<Name, ObjectMappingSource>>()

var constructor: IrConstructor? = null

private val targets
get() = constructor?.valueParameters ?: emptyList()

fun construct(): ConstructorCallMapping {
val mappings = targets.associateWith { target ->
val concreteSource = explicit.firstOrNull { it.first == target.name }

if (concreteSource != null) {
listOf(concreteSource.second)
} else {
val getter = getters.firstOrNull { getter ->
getter.name == getterName(target.name)
}
if (getter != null) {
listOf(PropertySource(getter.symbol, target.type, source.symbol, true))
} else if (target.hasDefaultValue()) {
listOf(DefaultParameterValueSource(target.defaultValue!!.expression))
} else {
emptyList()
}
}
}

return ConstructorCallMapping(
targetType = targetType,
sourceType = source.type,
symbol = constructor!!.symbol,
mappings = mappings
)
}

fun explicit(entry: Pair<Name, ObjectMappingSource>): ObjectMappingsConstructor =
apply { explicit.add(entry) }

companion object {
fun of(constructor: ObjectMappingsConstructor) =
ObjectMappingsConstructor(constructor.targetType, constructor.source).apply {
getters = constructor.getters
explicit = constructor.explicit
}

fun of(targetType: IrType, source: IrValueParameter) =
ObjectMappingsConstructor(targetType, source)
}
}

0 comments on commit 14a8d79

Please sign in to comment.