Hello. In the code below, I'm in a `visitFunction`...
# compiler
l
Hello. In the code below, I'm in a
visitFunction
with
IrFunction
bar
and I want to access the property
foo
through
IrProperty
. For this concrete example, I can look through the parents and use
thisReceiver
. However, in a real scenario
bar
can be nested arbitrarily deep in various declarations. It could be in a non-inner class and have no access to
foo
. Is there a simple way to access it and tell if it is accessible?
Copy code
class Foo {
    val foo = "foo"

    inner class Bar {
        fun bar() {
            foo // I want to access this
        }
    }
}
(What I'm trying to do is to see if I can write a simple compiler plugin, a logging thing that automatically provides the tag. So for this example a log entry could read, "bar was called in Foo[foo].Bar". Kotlin 2.4)
y
There might be an easier way to do this, but I've had success using
IrElementTransformerVoidWithContext
and changing its scope tracking mechanism to keep track of properties for containing declarations. I think you can use that to keep track manually of what dispatch receivers you have access to (i.e. by seeing what classes you're nested under, but stopping at the first non-inner outer class).
l
I'm currently doing approximately that, without manual tracking. Walking back the declarations in a loop with this:
Copy code
if (!parent.isInner) canReachReceiver = false
parent = parent.parent
While this works (and is sufficient for my use case—the plugin is only meant to be using in-house for now), it looks like a roundabout solution. Also, you can have non-inner classes that could access
foo
, for example you can have a class definition inside a method of
Foo
. Or maybe something else? It feels like there should be a better way.
y
I think checking for local classes should solve that. If a class is local or inner, continue checking the outer ones, otherwise stop. You can use the scopes thing to do this ahead-of-time so that you don't recalculate it every time.
i
I am not sure I completely understood your use case. For the task of tracking value scope you can look at ValueScopeUpdater and everything around it. This is that we use to check that generated IR is valid. Don't think you can use it as is, but you can definitely copy and modify some parts.
l
Thank you. Looking at the code around that I see
outerScopesAreInvisible = owner _is_ IrClass && !owner.isInner && owner.visibility != DescriptorVisibilities._LOCAL
,_ suggesting that the logic is sound. I see how I could use the scopes too.