create NewPsiElement that extend ExistingPsiElement.

At Rename Refactoring we have a simple way to create PsiElement:

When the rename refactoring is performed, the method PsiNamedElement.setName() is called for the renamed element, and PsiReference.handleElementRename() is called for all references to the renamed element. Both of these methods perform basically the same action: replace the underlying AST node of the PSI element with the node containing the new text entered by the user. Creating a fully correct AST node from scratch is quite difficult. Thus, surprisingly, the easiest way to get the replacement node is to create a dummy file in the custom language so that it would contain the necessary node in its parse tree, build the parse tree and extract the necessary node from it.

Example: setName() implementation for a Properties language plugin

But is " Creating a fully correct AST node from scratch" for the new PsiElement" really too complicated? Did anyone implement something like that?

Let say I want to create NewPsiElement that extend the functionality of ExistingPsiElement, generated from the declaration in parser's BNF. But the NewPsiElement could/should not have the corresponding declaration in BNF (so, it's not possible to use that hack above with fake PsiFile creation).

More specific example: I would like to extend (add interface implementation) of one of the existing class (extends PsiElement) in another plugging. I have no ability to change classes generated from that plugin BNF. So I want to extend that existing class and then replace instances of that existing class with instances of my new class. Is it possible somehow? Will parser accept descendants of existing class in place of existing class?

PS Would be really nice to create a new class that extends the class of existing element, and then when creating the instance of that new class just .clone() content of existing element.

Or maybe there is some way to inject method/interface into existing PsiElement?

1 comment

You can subclass/extend any PsiElement.  And, you can replace a PsiElement with another one (PsiElement.replace()).  Getting your element to be created instead of the normal one requires you to subclass the ASTFactory from the plugin you wish to override, and then to register your factory subclass as the one to use for the target language. 

Registering is normally done via the com.intellij.lang.ast.factory tag in the plugin.xml.  However, multiple factories would then be registered, which may either create an error or the last one wins (I don't know, since I haven't tried).

You will also have to be sure that the plugin you are depending upon is loaded first.  You do that by specifying dependencies in your plugin.xml.

 

1

Please sign in to leave a comment.