Michael Marshall

    Michael Marshall

    1 year ago
    I've got a custom detekt rule with type resolution and I'm receiving the
    bindingContext
    okay, but
    getType
    is always
    null
    . What should I be doing to get the class of the object declaration?
    override fun visitObjectDeclaration(declaration: KtObjectDeclaration) {
        super.visitObjectDeclaration(declaration)
    
        if (bindingContext == BindingContext.EMPTY) return
    
        if (bindingContext.getType(declaration) is Serializable) {
            report(
                CodeSmell(
                    issue = issue,
                    entity = Entity.from(declaration),
                    message = "Do not use Java Serialization for Kotlin objects."
                )
            )
        }
    }
    I have also tried, from various internet sources1.
    (declaration.resolve() as? ClassDescriptor)?.defaultType
    resolve() method not found 2.
    (declaration as KtCallableDeclaration).createTypeBindingForReturnType(bindingContext)?.type
    cast fails 3.
    declaration.kotlinType(bindingContext)
    always null
    gammax

    gammax

    1 year ago
    You should be good with:
    declaration.superTypeListEntries.any { it.text == "Serializable" }
    Michael Marshall

    Michael Marshall

    1 year ago
    Hey thanks for that, although I need to check the whole class hierarchy for Serializable, not just if it's a direct super class
    That's why I needed the type resolution, to perform the
    is Serializable
    check
    gammax

    gammax

    1 year ago
    I believe you should then use:
    bindingContext[BindingContext.CLASS, declaration]?.defaultType
    Michael Marshall

    Michael Marshall

    1 year ago
    That works almost! It still fails the
    is Serializable
    check, I think it's a
    SimpleTypeImpl
    rather than the actual class, or something lazy?
    Also is there any documentation for this? 😅
    gammax

    gammax

    1 year ago
    So the
    is Serializable
    check is most likely a bad approach. I believe you should reach a fully qualified type in some form and then do a string comparison with
    java.io.Serializable
    . As for the documentation, that’s Kotlin PSI & the compiler API. Really bad documented 😞 That’s a known issue on JetBrains table.
    Also my approach is generally to use the debugger. Like you add a breakpoint inside the rule, and then you try to evaluate expressions like the one I mentioned before. A bit of trial-n-error 🙂
    Michael Marshall

    Michael Marshall

    1 year ago
    Yeah it's been an absolute slog piecing together clues from around the internet 😂
    If I can't use
    isSerializable
    then I'll need to recurse up the whole class hierarchy won't I?
    In fact, if I can't get the class, I won't be able to do that either...
    gammax

    gammax

    1 year ago
    then I’ll need to recurse up the whole class hierarchy won’t I?
    Mmm not really. I believe that with type resolution, you should be able to get all the implemented interfaces, also the one of your superclasses..
    Michael Marshall

    Michael Marshall

    1 year ago
    I didn't realise it could do that, thanks for the help! Got it working with this
    private val KtObjectDeclaration.isJavaSerializable
            get() = bindingContext[BindingContext.CLASS, this]
                ?.defaultType
                ?.supertypes()
                ?.any { it.fqNameOrNull()?.asString() == "java.io.Serializable" } == true
    gammax

    gammax

    1 year ago
    Awesome 🚀