1

Is there a way to create a Kotlin compiler plugin that can modify the code being written?

I don't want to create separate generated code but actually modify the code itself.

For example, given this source:

Original

@Composable
fun MyScreen() {
    Surface {
        Button(onClick = { 
            println("Clicked") 
        })
    }
}

I want to change the output code to be this:

Modified by plugin

@Composable
fun MyScreen() {
    Surface {
        Button(onClick = 
            track("MyScreen", "Surface", "Button") {
                println("Clicked")
            }
        )
    }
}

Or even just change the import:

Original

import androidx.compose.material.Button

@Composable
fun MyScreen() {
    ...
}

Modified by plugin

import com.mycompany.project.wrappers.Button

@Composable
fun MyScreen() {
    ...
}
Samuel Neff
  • 73,278
  • 17
  • 138
  • 182
  • Your question seems to focus on writing a compiler plugin, but you also tagged the question with _aspectj_, which is how I found it. If you have an AspectJ question, please let me know. – kriegaex Mar 18 '23 at 08:24
  • @kriegaex Thanks for clarifying. I was looking into doing the same with AspectJ and hence it was on my mind. The question is very focused on a compiler plugin. I can post a separate question worded specifically for AspectJ. In my brief review of the docs, it didn't look like I could do this.. search for all click handlers and then wrap them in a custom function call using data from the call hierarchy. Or replace the import with a different import.. – Samuel Neff Mar 19 '23 at 16:40
  • AspectJ works on byte code level, not on source level. So you cannot "replace imports", whatever that should be good for. No sources are generated, but you can certainly replace one method call by another one. The details depend on your situation. If you feel like posting a separate AspectJ question, please make sure to link to a minimal reproducer on GitHub, so I can reproduce and test what you want to do. Only then can I suggest a solution, if what you want is doable with AspectJ. I do not speak Kotlin, so without a reproducer I cannot help you. – kriegaex Mar 19 '23 at 17:08
  • @kriegaex thanks, I'll take a stab at it with AspectJ and post a question if I can't get it to work on my own. Replacing the method call is basically the same as replacing the import at a byte-code level I think. – Samuel Neff Mar 22 '23 at 00:33
  • Did you find any solution for this? – cJ_ Jul 29 '23 at 23:05
  • @cJ_ I ended up switching jobs and technology, so no, I'm not working in Kotlin anymore. – Samuel Neff Jul 30 '23 at 21:16
  • @cJ_ I switched jobs before getting to this and don't work in Kotlin anymore. Sadly I would have like to been able to implement this. Now I have a bigger task. Find a way to build a nice code generation system for TypeScript where I can generate files and have them included the way Kotlin/Gradle does. I have some ideas. – Samuel Neff Aug 08 '23 at 14:48

1 Answers1

1

KSP doesn't offer modifying function bodies, because KSP is unable to look at function body.

You can achieve modification of function body expression if you use write your own Kotlin compiler plugin. Kotlin compiler plugin will allow you to modify the code in compile-time.

Nikola Despotoski
  • 49,966
  • 15
  • 119
  • 148