Status Update
Comments
pa...@google.com <pa...@google.com>
tn...@google.com <tn...@google.com> #2
Thanks for the detailed bug report -- I can reproduce it! (Having a full source file including all imports so that it reproed directly out of the box was very helpful -- much appreciated!)
Jinseong -- I debugged through it and it looks like this constructor call (on line 151) MultiSelectorStateImpl(
is treated as private; modifierList.hasModifierProperty(PsiModifier.PRIVATE)
returns true for it.
Note that this only happens in Kotlin 2.1.10, not in 2.1.0.
js...@google.com <js...@google.com> #3
One of the many case that now triggers this: Kotlin 2.1.10
Note that this only happens in Kotlin 2.1.10, not in 2.1.0.
I still can't figure out how this makes the difference, because Lint is using the "bundled" compiler artifacts. Instead,
Updating AGP from 8.10.0 alpha 04 to 05 triggers a lot of false positive SyntheticAccessor errors. (Reverting fix)
This is the hint because, in between, I landed changes about artifact updates (to 2.1.20-Beta2).
I debugged through it and it looks like this constructor call (on line 151)
MultiSelectorStateImpl(
is treated as private;modifierList.hasModifierProperty(PsiModifier.PRIVATE)
returns true for it.
Thanks to this hint, I went down to how SLC creates (resolved) constructor, and found a relevant change:
which points to some YT tickets filed from our side:
After reading those, I think this is, unfortunately, WAI, sort of.
Here is a minimal reproduction:
@JvmInline
value class MyColor(val value: Long)
class MultiSelectorStateImpl(val value: MyColor)
fun foo(c: MyColor) =
MultiSelectorStateImpl(c)
and my local Lint test failed like:
java.lang.AssertionError: Did not find "private " in "(val value: MyColor)" as suggested in the quickfix for issue SyntheticAccessor (text in range was "(val value: MyColor)")
at org.junit.Assert.fail(Assert.java:89)
at com.android.tools.lint.checks.infrastructure.TestLintClient.checkFix(TestLintClient.java:1346)
at com.android.tools.lint.checks.infrastructure.TestLintClient.report(TestLintClient.java:1081)
at com.android.tools.lint.client.api.LintDriver$LintClientWrapper.report(LintDriver.kt:2676)
at com.android.tools.lint.client.api.LintClient.report$default(LintClient.kt:179)
at com.android.tools.lint.detector.api.JavaContext.report(JavaContext.kt:293)
at com.android.tools.lint.checks.SyntheticAccessorDetector.reportError(SyntheticAccessorDetector.kt:243)
at com.android.tools.lint.checks.SyntheticAccessorDetector.access$reportError(SyntheticAccessorDetector.kt:52)
but indeed by-passed private
bail-out point (and attempted to apply a fix to remove private
modifier?).
If you look at the generated bytecode:
$ javap -v -p MultiSelectorStateImpl.class
...
private MultiSelectorStateImpl(long);
descriptor: (J)V
flags: (0x0002) ACC_PRIVATE
...
public MultiSelectorStateImpl(long, kotlin.jvm.internal.DefaultConstructorMarker);
descriptor: (JLkotlin/jvm/internal/DefaultConstructorMarker;)V
flags: (0x1001) ACC_PUBLIC, ACC_SYNTHETIC
...
The constructor is really private
, hiding it from Java viewpoint. If you try to call that constructor from Java, you'll see exactly same access control error.
On the other hand, if everything is in Kotlin, a synthetic (public
) constructor (w/ the marker) is used actually... but still the UAST/PSI resolution doesn't take that into account. Or... that synthetic one is not visible to Java either, and thus, ironically, UAST resolution also makes sense.
For now, I'm going to add a hot fix into SyntheticAccessor
and filter out private
ctor call if 1) call-site is Kotlin; and 2) that ctor is private
because of the presence of value
class parameter.
js...@google.com <js...@google.com>
an...@google.com <an...@google.com> #4
Thank you for your patience while our engineering team worked to resolve this issue. A fix for this issue is now available in:
- Android Studio Meerkat Feature Drop | 2024.3.2 Canary 7
- Android Gradle Plugin 8.10.0-alpha07
We encourage you to try the latest update.
If you notice further issues or have questions, please file a new bug report.
Thank you for taking the time to submit feedback — we really appreciate it!
to...@gmail.com <to...@gmail.com> #5
This is still an issue with kotlin 2.1.20 and AGP 8.11.0-alpha02
a.kt:109: Error: Access to private constructor of class SliderBrushColor2 requires synthetic accessor [SyntheticAccessor]
var result = thumbColor.hashCode()
~~~~~~~~~~~~~~~~~~~
Small repro:
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
data class SliderBrushColor2(
val color: Color = Color.Unspecified,
val brush: Brush? = null,
) {
val activeBrush: Brush
get() = brush ?: solidColor
val solidColor = SolidColor(color)
}
interface MaterialSliderColors2 {
@Composable
fun thumbColor(enabled: Boolean): State<Brush>
@Composable
fun trackColor(enabled: Boolean, active: Boolean): State<Brush>
@Composable
fun tickColor(enabled: Boolean, active: Boolean): State<Brush>
}
class DefaultMaterialSliderColors(
private val thumbColor: SliderBrushColor2,
private val disabledThumbColor: SliderBrushColor2,
private val activeTrackColor: SliderBrushColor2,
private val disabledActiveTrackColor: SliderBrushColor2,
private val inactiveTrackColor: SliderBrushColor2,
private val disabledInactiveTrackColor: SliderBrushColor2,
private val activeTickColor: SliderBrushColor2 = SliderBrushColor2(),
private val inactiveTickColor: SliderBrushColor2 = SliderBrushColor2(),
private val disabledActiveTickColor: SliderBrushColor2 = SliderBrushColor2(),
private val disabledInactiveTickColor: SliderBrushColor2 = SliderBrushColor2(),
) : MaterialSliderColors2 {
@Composable
override fun thumbColor(enabled: Boolean): State<Brush> {
return rememberUpdatedState(
if (enabled) {
thumbColor.activeBrush
} else {
disabledThumbColor.activeBrush
},
)
}
@Composable
override fun trackColor(enabled: Boolean, active: Boolean): State<Brush> {
return rememberUpdatedState(
if (enabled) {
if (active) {
activeTrackColor.activeBrush
} else {
inactiveTrackColor.activeBrush
}
} else {
if (active) {
disabledActiveTrackColor.activeBrush
} else {
disabledInactiveTrackColor.activeBrush
}
},
)
}
@Composable
override fun tickColor(enabled: Boolean, active: Boolean): State<Brush> {
return rememberUpdatedState(
if (enabled) {
if (active) {
activeTickColor.activeBrush
} else {
inactiveTickColor.activeBrush
}
} else {
if (active) {
disabledActiveTickColor.activeBrush
} else {
disabledInactiveTickColor.activeBrush
}
},
)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as DefaultMaterialSliderColors
if (thumbColor != other.thumbColor) return false
if (disabledThumbColor != other.disabledThumbColor) return false
if (activeTrackColor != other.activeTrackColor) return false
if (inactiveTrackColor != other.inactiveTrackColor) return false
if (disabledActiveTrackColor != other.disabledActiveTrackColor) return false
if (disabledInactiveTrackColor != other.disabledInactiveTrackColor) return false
return true
}
override fun hashCode(): Int {
var result = thumbColor.hashCode()
result = 31 * result + disabledThumbColor.hashCode()
result = 31 * result + activeTrackColor.hashCode()
result = 31 * result + inactiveTrackColor.hashCode()
result = 31 * result + disabledActiveTrackColor.hashCode()
result = 31 * result + disabledInactiveTrackColor.hashCode()
return result
}
}
js...@google.com <js...@google.com> #6
For now, I'm going to add a hot fix into
SyntheticAccessor
and filter outprivate
ctor call if 1) call-site is Kotlin; and 2) that ctor isprivate
because of the presence ofvalue
class parameter.
At a glance, it's data
class with value
class as a parameter; then its synthetic hashCode
is triggering an alarm. IIUC, SyntheticAccessor
is supposed to work on constructors, either user-defined ones or default one, but the way it detects default ctor looks strange to me. Anyhow, this is not the same issue, so let me file a separate one:
Description
Updating AGP from 8.10.0 alpha 04 to 05 triggers a lot of false positive SyntheticAccessor errors. (Reverting fix)
One of the many case that now triggers this: Kotlin 2.1.10