Skip to content

Commit

Permalink
Fixes #668
Browse files Browse the repository at this point in the history
  • Loading branch information
raamcosta committed Jul 25, 2024
1 parent adba1d4 commit 3d9764d
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 63 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
package com.ramcosta.composedestinations.codegen.model

data class DefaultValue(
val code: String,
val imports: List<String> = emptyList()
)
import com.ramcosta.composedestinations.codegen.commons.IllegalDestinationsSetup

sealed interface DefaultValue {

data class Error(val throwable: Throwable) : DefaultValue

data object NonExistent: DefaultValue

data class Available(
val code: String,
val imports: List<String> = emptyList()
) : DefaultValue
}

fun DefaultValue.unwrapAvailable(): DefaultValue.Available? = when (this) {
is DefaultValue.Available -> this
is DefaultValue.Error -> throw IllegalDestinationsSetup("Error reading default value", throwable)
is DefaultValue.NonExistent -> null
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ data class Parameter(
val type: TypeInfo,
val hasDefault: Boolean,
val isMarkedNavHostParam: Boolean,
val defaultValue: DefaultValue?,
val defaultValue: DefaultValue,
) {
val isMandatory: Boolean get() = !type.isNullable && !hasDefault
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.ramcosta.composedestinations.codegen.model.Importable
import com.ramcosta.composedestinations.codegen.model.Parameter
import com.ramcosta.composedestinations.codegen.model.TypeArgument
import com.ramcosta.composedestinations.codegen.model.TypeInfo
import com.ramcosta.composedestinations.codegen.model.unwrapAvailable
import com.ramcosta.composedestinations.codegen.writers.helpers.ImportableHelper
import com.ramcosta.composedestinations.codegen.writers.helpers.NavArgResolver

Expand Down Expand Up @@ -188,7 +189,7 @@ class NavArgumentBridgeCodeBuilder(
}

private fun defaultValueForInvokeFunction(it: Parameter): String {
return if (it.hasDefault) " = ${it.defaultValue?.code}"
return if (it.hasDefault) " = ${it.defaultValue.unwrapAvailable()?.code}"
else ""
}

Expand Down Expand Up @@ -329,7 +330,7 @@ class NavArgumentBridgeCodeBuilder(



private fun navArgDefaultCode(param: Parameter): String = param.defaultValue.let { defaultValue ->
private fun navArgDefaultCode(param: Parameter): String = param.defaultValue.unwrapAvailable().let { defaultValue ->
if (defaultValue == null) {
return ""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,12 @@ object DefaultParameterValueReader {

return if (auxText.startsWith("\"")) {
if (auxText.contains("\"\"\"")) {
throw IllegalDestinationsSetup("Multiline string literals are not supported as navigation argument defaults (near: '$auxText'")
DefaultValue.Error(
IllegalDestinationsSetup("Multiline string literals are not supported as navigation argument defaults (near: '$auxText'")
)
} else {
DefaultValue.Available(stringLiteralValue(auxText))
}
DefaultValue(stringLiteralValue(auxText))
} else {
importedDefaultValue(resolver, auxText, packageName, imports)
}
Expand Down Expand Up @@ -131,26 +134,28 @@ object DefaultParameterValueReader {
|| result == "false"
|| result == "null"
|| result.first().isDigit()) {
return DefaultValue(result)
return DefaultValue.Available(result)
}

val importableAux = result.removeFromTo("(", ")")

if (result.length - importableAux.length > 2) {
//we detected a function call with args, we can't resolve this
throw IllegalDestinationsSetup("Navigation arguments using function calls with parameters as their default value " +
"are not currently supported (near: '$auxText')")
return DefaultValue.Error(
IllegalDestinationsSetup("Navigation arguments using function calls with parameters as their default value " +
"are not currently supported (near: '$auxText')")
)
}

val importable = importableAux.split(".")[0]
val defValueImports = imports.filter { it.endsWith(".$importable") }

if (defValueImports.isNotEmpty()) {
return DefaultValue(result, defValueImports)
return DefaultValue.Available(result, defValueImports)
}

if (resolver.invoke(packageName, importable).existsAndIsAccessible()) {
return DefaultValue(result, listOf("${packageName}.$importable"))
return DefaultValue.Available(result, listOf("${packageName}.$importable"))
}

val wholePackageImports = imports
Expand All @@ -160,20 +165,20 @@ object DefaultParameterValueReader {
.filter { resolver.invoke(it.removeSuffix(".*"), importable).existsAndIsAccessible() }

if (validImports.size == 1) {
return DefaultValue(result, listOf(validImports[0]))
return DefaultValue.Available(result, listOf(validImports[0]))
}

if (result.startsWith("arrayListOf(") //std kotlin lib
|| result.startsWith("arrayOf(") //std kotlin lib
) {
return DefaultValue(result)
return DefaultValue.Available(result)
}

if (resolver.invoke(packageName, importable).existsAndIsPrivate()) {
throw IllegalDestinationsSetup("Navigation arguments with default values which uses a private declaration are not currently supported (near: '$auxText')")
return DefaultValue.Error(IllegalDestinationsSetup("Navigation arguments with default values which uses a private declaration are not currently supported (near: '$auxText')"))
}

return DefaultValue(result, wholePackageImports)
return DefaultValue.Available(result, wholePackageImports)
}
}

Expand Down Expand Up @@ -220,8 +225,8 @@ private fun String.indexOfFinalClosingParenthesis(): Int? {
}

@OptIn(KspExperimental::class)
fun KSValueParameter.getDefaultValue(resolver: Resolver): DefaultValue? {
if (!hasDefault) return null
fun KSValueParameter.getDefaultValue(resolver: Resolver): DefaultValue {
if (!hasDefault) return DefaultValue.NonExistent

/*
This is not ideal: having to read the first n lines of the file,
Expand All @@ -231,9 +236,11 @@ fun KSValueParameter.getDefaultValue(resolver: Resolver): DefaultValue? {
*/

if (location is NonExistLocation) {
throw IllegalDestinationsSetup("Cannot detect default value for navigation" +
" argument '${name!!.asString()}' because we don't have access to source code. " +
"Nav argument classes from other modules with default values are not supported!")
return DefaultValue.Error(
IllegalDestinationsSetup("Cannot detect default value for navigation" +
" argument '${name!!.asString()}' because we don't have access to source code. " +
"Nav argument classes from other modules with default values are not supported!")
)
}

Logger.instance.info("getDefaultValue | name = ${name!!.asString()} type = $type")
Expand Down
Loading

0 comments on commit 3d9764d

Please sign in to comment.