diff --git a/arrow-libs/optics/arrow-optics-ksp-plugin/src/main/kotlin/arrow/optics/plugin/internals/domain.kt b/arrow-libs/optics/arrow-optics-ksp-plugin/src/main/kotlin/arrow/optics/plugin/internals/domain.kt index b59e25c4f6..7652804661 100644 --- a/arrow-libs/optics/arrow-optics-ksp-plugin/src/main/kotlin/arrow/optics/plugin/internals/domain.kt +++ b/arrow-libs/optics/arrow-optics-ksp-plugin/src/main/kotlin/arrow/optics/plugin/internals/domain.kt @@ -6,9 +6,11 @@ import arrow.optics.plugin.companionObject import com.google.devtools.ksp.getDeclaredProperties import com.google.devtools.ksp.getVisibility import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSDeclaration import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSTypeParameter import com.google.devtools.ksp.symbol.Variance +import com.google.devtools.ksp.symbol.Visibility import java.util.* data class ADT(val declaration: KSClassDeclaration, val targets: List) { @@ -16,8 +18,7 @@ data class ADT(val declaration: KSClassDeclaration, val targets: List) { val sourceName = declaration.simpleName.asString().replaceFirstChar { it.lowercase(Locale.getDefault()) }.sanitize() val simpleName = declaration.nameWithParentClass val packageName = declaration.packageName.asSanitizedString() - val visibilityModifierName = - (declaration.companionObject?.getVisibility() ?: declaration.getVisibility()).name.lowercase() + val visibilityModifierName = declaration.effectiveCompanionVisibility.name.lowercase() val typeParameters: List = declaration.typeParameters.map { tyParam -> if (tyParam.variance == Variance.STAR) return@map "*" // val prefix = when (it.variance) { @@ -52,6 +53,36 @@ val KSClassDeclaration.nameWithParentClass: String else -> simpleName.asString() } +val KSClassDeclaration.effectiveCompanionVisibility: Visibility + get() { + val visibilities = + listOfNotNull(companionObject?.getVisibility(), getVisibility()) + + allParentDeclarations().filterIsInstance().map { it.getVisibility() } + return visibilities.foldRight(Visibility.PUBLIC, Visibility::plus) + } + +fun KSDeclaration.allParentDeclarations(): List = when (val parent = parentDeclaration) { + null -> emptyList() + else -> listOfNotNull(parent) + parent.allParentDeclarations() +} + +operator fun Visibility.plus(other: Visibility): Visibility = when { + this == other -> this + + this == Visibility.PUBLIC -> other + + other == Visibility.PUBLIC -> this + + this == Visibility.LOCAL || other == Visibility.LOCAL -> Visibility.LOCAL + + this == Visibility.PRIVATE || other == Visibility.PRIVATE -> Visibility.PRIVATE + + (this == Visibility.INTERNAL || this == Visibility.PROTECTED) && + (other == Visibility.INTERNAL || other == Visibility.PROTECTED) -> Visibility.PRIVATE + + else -> Visibility.PRIVATE +} + enum class OpticsTarget { ISO, LENS, diff --git a/arrow-libs/optics/arrow-optics-ksp-plugin/src/test/kotlin/arrow/optics/plugin/Compilation.kt b/arrow-libs/optics/arrow-optics-ksp-plugin/src/test/kotlin/arrow/optics/plugin/Compilation.kt index d1f10b4c03..81793a4118 100644 --- a/arrow-libs/optics/arrow-optics-ksp-plugin/src/test/kotlin/arrow/optics/plugin/Compilation.kt +++ b/arrow-libs/optics/arrow-optics-ksp-plugin/src/test/kotlin/arrow/optics/plugin/Compilation.kt @@ -89,7 +89,7 @@ fun buildCompilation( this.sources = sources.toList() this.verbose = false this.allWarningsAsErrors = allWarningsAsErrors - this.languageVersion = "2.0" + this.languageVersion = "2.1" if (contextParameters) { this.kotlincArguments = listOf("-Xcontext-parameters") } diff --git a/arrow-libs/optics/arrow-optics-ksp-plugin/src/test/kotlin/arrow/optics/plugin/DSLTests.kt b/arrow-libs/optics/arrow-optics-ksp-plugin/src/test/kotlin/arrow/optics/plugin/DSLTests.kt index a3ad8c8739..c33f97b3ea 100755 --- a/arrow-libs/optics/arrow-optics-ksp-plugin/src/test/kotlin/arrow/optics/plugin/DSLTests.kt +++ b/arrow-libs/optics/arrow-optics-ksp-plugin/src/test/kotlin/arrow/optics/plugin/DSLTests.kt @@ -13,7 +13,7 @@ class DSLTests { |$dslModel |$dslValues |val modify = Employees.employees.every.company.notNull.address - | .street.name.modify(employees, String::toUpperCase) + | .street.name.modify(employees, String::uppercase) |val r = modify.employees.map { it.company?.address?.street?.name }.toString() """.evals("r" to "[LAMBDA STREET, LAMBDA STREET]") } diff --git a/arrow-libs/optics/arrow-optics-ksp-plugin/src/test/kotlin/arrow/optics/plugin/LensTests.kt b/arrow-libs/optics/arrow-optics-ksp-plugin/src/test/kotlin/arrow/optics/plugin/LensTests.kt index dbd5241ddd..652f36a0dd 100755 --- a/arrow-libs/optics/arrow-optics-ksp-plugin/src/test/kotlin/arrow/optics/plugin/LensTests.kt +++ b/arrow-libs/optics/arrow-optics-ksp-plugin/src/test/kotlin/arrow/optics/plugin/LensTests.kt @@ -325,4 +325,23 @@ class LensTests { |val r = lens != null """.evals("r" to true) } + + @Test + fun `Visibilities are correctly computed (#3869)`() { + """ + |$`package` + |$imports + |@optics + |internal sealed interface Interface { + | @optics + | data class DataClass(val value: Int) : Interface { + | companion object + | } + | companion object + |} + | + |internal val lens: Lens = Interface.DataClass.value + |internal val r = lens != null + """.evals("r" to true) + } } diff --git a/generator-scripts/tuple.generator.kts b/generator-scripts/tuple.generator.kts index 36d04196df..fff41c82be 100644 --- a/generator-scripts/tuple.generator.kts +++ b/generator-scripts/tuple.generator.kts @@ -28,15 +28,15 @@ for (i in 2..maxTuple) { val letters = availableLetters.take(i + 1) - val diamond1 = "<${letters.joinToString { it.toUpperCase() }}>" - val diamond2 = "<${letters.dropLast(1).joinToString { it.toUpperCase() }}>" + val diamond1 = "<${letters.joinToString { it.uppercase() }}>" + val diamond2 = "<${letters.dropLast(1).joinToString { it.uppercase() }}>" val newLetter = availableLetters[i] val constructor = (letters.dropLast(1).map { "this.$it" } + newLetter).joinToString() fileContent.append( - "operator fun $diamond1 Tuple$i$diamond2.plus($newLetter: ${newLetter.toUpperCase()}): Tuple${i+1}$diamond1 = Tuple${i + 1}($constructor)" + "operator fun $diamond1 Tuple$i$diamond2.plus($newLetter: ${newLetter.uppercase()}): Tuple${i+1}$diamond1 = Tuple${i + 1}($constructor)" ) fileContent.append("\n") @@ -44,4 +44,4 @@ for (i in 2..maxTuple) { val fileLocation = "../modules/core/arrow-syntax/src/main/kotlin/arrow/syntax/collections/tuple.kt" -File("tuple.kt").writeText(fileContent.toString()) \ No newline at end of file +File("tuple.kt").writeText(fileContent.toString())