google / ksp

Kotlin Symbol Processing API
https://github.com/google/ksp
Apache License 2.0
2.84k stars 266 forks source link

IllegalStateException: unhandled visibility: local #613

Closed elihart closed 2 months ago

elihart commented 3 years ago

KSP is throwing an internal error within fun MemberDescriptor.toKSModifiers with the following stacktrace:

java.lang.IllegalStateException: unhandled visibility: local
        at com.google.devtools.ksp.symbol.impl.UtilsKt.toKSModifiers(utils.kt:178)
        at com.google.devtools.ksp.symbol.impl.binary.KSClassDeclarationDescriptorImpl$modifiers$2.invoke(KSClassDeclarationDescriptorImpl.kt:123)
        at com.google.devtools.ksp.symbol.impl.binary.KSClassDeclarationDescriptorImpl$modifiers$2.invoke(KSClassDeclarationDescriptorImpl.kt:121)
        at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
        at com.google.devtools.ksp.symbol.impl.binary.KSClassDeclarationDescriptorImpl.getModifiers(KSClassDeclarationDescriptorImpl.kt:121)

I haven't been able to track down the exact type causing the issue so I can't give a repro yet, but it seems like a straightforward case to add to the when statement.

The line numbers are out of date as we are using beta07 due to kotlin versioning restrictions, but I didn't see a fix in recent versions so it seems like it would still be an issue in the latest release.

elihart commented 3 years ago

I tracked down the specific offender. Our class has a property like this

    private var preDrawListener = object : ViewTreeObserver.OnPreDrawListener {
         ...
    }

So the property type is a local object instance, and looking up the modifiers on the type causes this crash.

A work around is to specify the type explicitly - private var preDrawListener: ViewTreeObserver.OnPreDrawListener = object : ViewTreeObserver.OnPreDrawListener

neetopia commented 3 years ago

It appears to be a straightforward issue but actually I was having hard time reproduce it even with your reproduce code. Basically it looks that we are missing the handling for local descriptors for classes, but local should mean class declared in a function body, where descriptor impl means it is from library, but I am unable to reproduce a test case where I can reference a local class from a library, since they are most likely name mangled to avoid this to happen, like for

class Foo {
    fun bar() {
        class Inner
    }
}

it will be Foo$bar$Inner, which does not seem to be the case in your code. Can you give me more details as to how to reproduce it? Like where is ViewTreeObserver.OnPreDrawListener declared, is it from library or source code, and if private var preDrawListener is from source or library?

elihart commented 3 years ago

Hm, sorry for the trouble. I can provide additional information.

Both the object class ViewTreeObserver.OnPreDrawListener and the var preDrawListener property are defined in compiled libraries (different libraries; the ViewTreeObserver is an Android OS class, the property is a class within our project in another module).

I am accessing the type indirectly via Room's XProcessing abstraction over KSP, and that is doing some manipulation of the properties and types that might be causing the unexpected behavior.

I am invoking XProcessing's KspTypeElement.getDeclaredMethods(), which then uses KSClassDeclaration.getDeclaredProperties(): and on each property gets the type in respect to the containing class via KSPropertyDeclaration.typeAsMemberOf(KSClassDeclaration.asStarProjectedType()).

The full stacktrace is:

Caused by: java.lang.IllegalStateException: unhandled visibility: local
    at com.google.devtools.ksp.symbol.impl.UtilsKt.toKSModifiers(utils.kt:178)
    at com.google.devtools.ksp.symbol.impl.binary.KSClassDeclarationDescriptorImpl$modifiers$2.invoke(KSClassDeclarationDescriptorImpl.kt:123)
    at com.google.devtools.ksp.symbol.impl.binary.KSClassDeclarationDescriptorImpl$modifiers$2.invoke(KSClassDeclarationDescriptorImpl.kt:121)
    at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
    at com.google.devtools.ksp.symbol.impl.binary.KSClassDeclarationDescriptorImpl.getModifiers(KSClassDeclarationDescriptorImpl.kt:121)
    at androidx.room.compiler.processing.ksp.KSTypeExtKt.isInline(KSTypeExt.kt:234)
    at androidx.room.compiler.processing.ksp.KspTypeElement$syntheticGetterSetterMethods$2.invoke(KspTypeElement.kt:167)
    at androidx.room.compiler.processing.ksp.KspTypeElement$syntheticGetterSetterMethods$2.invoke(KspTypeElement.kt:165)
    at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
    at androidx.room.compiler.processing.ksp.KspTypeElement.getSyntheticGetterSetterMethods(KspTypeElement.kt:165)
    at androidx.room.compiler.processing.ksp.KspTypeElement.access$getSyntheticGetterSetterMethods(KspTypeElement.kt:45)
    at androidx.room.compiler.processing.ksp.KspTypeElement$_declaredMethods$2.invoke(KspTypeElement.kt:319)
    at androidx.room.compiler.processing.ksp.KspTypeElement$_declaredMethods$2.invoke(KspTypeElement.kt:292)
    at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
    at androidx.room.compiler.processing.ksp.KspTypeElement.get_declaredMethods(KspTypeElement.kt:292)
    at androidx.room.compiler.processing.ksp.KspTypeElement.getDeclaredMethods(KspTypeElement.kt:323)
neetopia commented 2 years ago

Hi @elihart while I am still not able to reproduce on our side, the fix looks pretty straightforward, we do have a tentative fix from #697 which is included with 1.0.1-RC, can you take a try with it to see if it resolves your issue? Thanks

elihart commented 2 years ago

Thanks for the update. I won't be able to try it for a while though as we first need to update our large project to kotlin 1.6.0, update Compose and other dependencies on the kotlin version, etc so it will be several weeks

neetopia commented 2 years ago

with #704 , it might be worth to consider a 1.5.31-1.0.1-RC . @ting-yuan thoughts?