Skip to content

Commit

Permalink
Error on calls on compile dsl (#134)
Browse files Browse the repository at this point in the history
  • Loading branch information
stefankoppier authored Nov 21, 2024
1 parent 69019f5 commit 975d3dc
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ jobs:
run: ./gradlew build

- name: Coverage Report
if: github.ref == 'refs/heads/main'
run: ./gradlew testCodeCoverageReport

- name: Sonar
if: github.ref == 'refs/heads/main'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package tech.mappie.util

import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name

Expand Down Expand Up @@ -31,4 +32,8 @@ val IDENTIFIER_TRANSFORM = Name.identifier("transform")

val IDENTIFIER_VIA = Name.identifier("via")

val PACKAGE_TECH_MAPPIE_API_CONFIG = FqName("tech.mappie.api.config")
val PACKAGE_TECH_MAPPIE_API = FqName("tech.mappie.api")

val PACKAGE_TECH_MAPPIE_API_CONFIG = FqName("tech.mappie.api.config")

val CLASS_ID_OBJECT_MAPPING_CONSTRUCTOR = ClassId(PACKAGE_TECH_MAPPIE_API, Name.identifier("ObjectMappingConstructor"))
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ interface MappingValidation {
addAll(MapperGenerationRequestProblems.of(context, mapping).all())
addAll(ClassConfigProblems.of(context, mapping).all())
addAll(UnnecessaryFromPropertyNotNullProblems.of(context, mapping).all())
addAll(CompileTimeReceiverDslProblems.of(context, mapping).all())
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package tech.mappie.validation.problems.classes

import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.fileEntry
import tech.mappie.resolving.ClassMappingRequest
import tech.mappie.resolving.classes.sources.ValueMappingSource
import tech.mappie.util.CLASS_ID_OBJECT_MAPPING_CONSTRUCTOR
import tech.mappie.util.location
import org.jetbrains.kotlin.name.Name
import tech.mappie.validation.Problem
import tech.mappie.validation.ValidationContext

class CompileTimeReceiverDslProblems private constructor(
private val context: ValidationContext,
private val mappings: List<Pair<IrCall, ProblemSource>>,
) {
private enum class ProblemSource { EXTENSION, DISPATCH }

fun all(): List<Problem> = mappings.map { (call, source) ->
val name = call.symbol.owner.name.asString()
Problem.error(
when (source) {
ProblemSource.EXTENSION -> "The function $name was called as an extension method on the mapping dsl which does not exist after compilation"
ProblemSource.DISPATCH -> "The function $name was called on the mapping dsl which does not exist after compilation"
},
location(context.function.fileEntry, call),
buildList {
if (call.symbol.owner.name == Name.identifier("run")) {
add("Did you mean to use kotlin.run?")
}
}
)
}

companion object {
fun of(context: ValidationContext, mapping: ClassMappingRequest): CompileTimeReceiverDslProblems {
val mappings = mapping.mappings.values
.filter { it.size == 1 }
.map { it.single() }
.filterIsInstance<ValueMappingSource>()
.map { it.expression }
.filterIsInstance<IrCall>()

val dispatch = mappings
.filter { it.hasIncorrectDispatchReceiver(context) }
.map { it to ProblemSource.DISPATCH }

val extension = mappings
.filter { it.hasIncorrectExtensionReceiver(context) }
.map { it to ProblemSource.EXTENSION }

return CompileTimeReceiverDslProblems(context, dispatch + extension)
}

private fun IrCall.hasIncorrectExtensionReceiver(context: ValidationContext) =
extensionReceiver?.type?.classOrNull == context.pluginContext.referenceClass(CLASS_ID_OBJECT_MAPPING_CONSTRUCTOR)

private fun IrCall.hasIncorrectDispatchReceiver(context: ValidationContext) =
dispatchReceiver?.type?.classOrNull == context.pluginContext.referenceClass(CLASS_ID_OBJECT_MAPPING_CONSTRUCTOR)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,53 @@ class FromValueTest {
assertThat(mapper.map(Unit)).isEqualTo(Output(null))
}
}

@Test
fun `map property fromValue using extension receiver on mapping dsl should fail`() {
compile(directory) {
file("Test.kt",
"""
import tech.mappie.api.ObjectMappie
import tech.mappie.testing.objects.FromValueTest.*
class Mapper : ObjectMappie<Unit, Output>() {
override fun map(from: Unit) = mapping {
Output::value fromValue run {
"test"
}
}
}
"""
)
} satisfies {
isCompilationError()
hasErrorMessage(6,
"The function run was called as an extension method on the mapping dsl which does not exist after compilation",
listOf(
"Did you mean to use kotlin.run?"
)
)
}
}

@Test
fun `map property fromValue using dispatch receiver on mapping dsl should fail`() {
compile(directory) {
file("Test.kt",
"""
import tech.mappie.api.ObjectMappie
import tech.mappie.testing.objects.FromValueTest.*
class Mapper : ObjectMappie<Unit, Output>() {
override fun map(from: Unit) = mapping {
Output::value fromValue toString()
}
}
"""
)
} satisfies {
isCompilationError()
hasErrorMessage(6, "The function toString was called on the mapping dsl which does not exist after compilation")
}
}
}
4 changes: 4 additions & 0 deletions website/src/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
title: "Changelog"
layout: "layouts/changelog.html"
changelog:
- date: "tbd"
title: "v0.10.0"
items:
- "Added an explicit error message when the compile-time mapping dsl is used during runtime."
- date: "2024-11-18"
title: "v0.9.2"
items:
Expand Down

0 comments on commit 975d3dc

Please sign in to comment.