Augment top level PsiClass

Hey,

I'm developing a plugin that provides support for Google AutoFactory.

In short, AutoFactory is an annotation processor that generates factory classes. 

 

I want my plugin to augment a given java package so the factory class will be instantly available.

I know how to create the relevant PsiClass instance, but I can't figure out how to add it to the package without writing actual files to disk.

 

I have looked in the Lombok plugin for examples, and they do generate classes (for @lombok.Builder), but the generated class is inner class whilst I require a top level one.

 

Help will be greatly appreciated.

 

0
9 comments

Hi Matan,

so you don't want to create physical file, only light class where the references could be resolved? Should this class be found by Ctrl-N and navigatable? If so, what should be opened in the editor?

Anna

0

Light class sounds good - I only need the IDE to be aware of the class existence and its methods. It shouldn't be navigable or opened in the editor. Are there any docs about light classes besides the JavaDoc?

Also, I want to be able to generate my light classes in reaction to PSI updates by the user. In my case, it's a user adding/removing/changing @AutoFactory annotations. How can I listen to such events?

0

So you want IDE to resolve to that classes automatically or do you have your own references?

0

I would like to generate my ow PSI tree for these classes.

 

0

Where are references on these classes? Do you provide them or are they normal java references?

0

I'm not entirely sure what is the meaning of "references" in this context, so I'll give a practical example of what I'm trying to solve.

Given the following code:

class Foo {

     @AutoFactory

     public Foo(String param) { /* stuff */ }

}

 

I'd like to generate:

 

class FooFactory {

    public Foo create(String param) { return new Foo(param); }

}

 

 

So the following code will be valid:

/* Somewhere else */

FooFactory ff = new FooFactory();

Foo foo = ff.create("bar");

 

I'd like to stress that this code is in fact valid because while compiling, an annotation processor actually generates these classes.

I just want IntelliJ to recognize these classes (like FooFactory) without depending on the annotation processor.

The idea is similar to what the Lombok plugin does - it just makes IntelliJ aware of the stuff lombok generates when compiling. 

Anyways, the user should not be able to see the generated code above - it's just for IntelliJ reference resolving.

 

Thanks!

0

Start with providing com.intellij.psi.PsiElementFinder#findClass. It allows to provide light class which would be picked by resolve but should not appear in the Ctrl-N

0

Okay, I did a naive implementation of PsiElementFinder, but it's not really working - it is called, successfully generates the PsiClass (LightPsiClassBuilder in my case) but somehow IntelliJ failes to use the returned class (without any exception thrown or anything of the likes).

I heavily suspected that I just didn't return the correct PsiClass implementation, so I even tried to return an actual PsiClass (not light) that I created from raw text (for debug purposes), but it still didn't have any effect.

I did register my AutoFactoryFinder class in plugin.xml (which is certain anyway because my class is called).

The POC code is here. It's quite short and fairly readable: 

https://github.com/matan129/autofactory-intellij-plugin/blob/fa1a20fe98eda917b648b63ac1239b3466c89904/src/main/java/mr/intellij/plugin/autofactory/elements/AutoFactoryFinder.java

 

If you could point me in the right direction it'd be very helpful.

Thanks in advance!

0

During resolve of a class reference (e.g. in variable type declaration) should be invoked com.intellij.psi.impl.file.PsiPackageImpl#processDeclarations. (If the package should be also be generated, then you need to implement another method in Finder class as well). So put the breakpoint inside processDeclarations method and debug where it stops working as you expect. 

Anna

0

Please sign in to leave a comment.