Hi, I'm trying to write a plugin using arrow meta ...
# arrow
m
Hi, I'm trying to write a plugin using arrow meta that injects some code at the beginning of some functions. Is there a way to modify a KtNamedFunction bodyBlockExpression?
p
Hey @Marcello Lelio Albano, it should be possible to do this using
Transform.replace
. You can reference all elements of the original KtNamedFunction in the
newDeclaration
while also injecting additional code. This should work as inspiration for what you're trying to do.
r
@Marcello Lelio Albano just a friendly heads up that Quotes and in general the PSI layer will be replaced with Frontend IR once this is stable around Kotlin 1.6 or 1.7. Performing body replacements in the AST instead of generating new sources with
Transform.newSources
has also disadvantages as whatever declaration you introduce won’t be visible to the IDEA plugin. For example if you intercept
Copy code
fun foo() {
  val x = 1
}
and replace it for
Copy code
fun foo() {
  val x = 2
}
There is no visual indication in the IDE that X was replaced by a compiler plugin or instrumented in any way and it becomes confusing to the end user. We had the alternative to push our own IDE plugin as well but that also requires all users of metaprogramming create IDE plugins extending the Kotlin plugin and it becomes extremely complex very quick for any simple feature. We hope FIR addresses these issues and then the Quote system will be based on FIR instead of PSI+compiler descriptors.
m
Thanks for answering. Is there a way to do this in
arrow
without touching the function signature (i.e. keeping same arguments, annotations, generics, etc) ? I think it's ok there is no visual indication right now but I may want to revisit this in future.
r
If you don’t need visual indications then you can perform this transformation in the backend IR tree directly. You can intercept and transform any node in the IR tree. In this case you would be watching for functions and replacing the statements in their body to include additional statements or rewrite the function body
Copy code
val Meta.myPlugin: CliPlugin
  get() =
    "Intercepts functions and replaces their body" {
      meta(
        irFunction { 
          it.body...         
        }
      )
    }
that will get called on each declared function
If you know something inside the body you are looking for, for example a call then you can use
irCall
or whatever node you are after to identify the transformation. Returning
null
from that lambda is a no op.
It filters and transforms in the same block.
m
This is super helpful. Will try it. Thank you!
Can you make an example of manipulation in the lamba function? Maybe even adding a simple println() - I can't seem to find any example of this
I think I figured out!
👍 1