How well does the UAST system support custom language development?
Answered
I'm developing a custom language plugin that needs to support parsing elements in KtClass, PsiClass, and the current processing logic is this:
- Get the fully qualified class name
- use JavaPsiFacade#findClass to get PsiClass instance
- According to the language of the PsiClass instance, decide whether to get the KtClass instance according to the PsiClass instance: PsiTreeUtil#findChildOfType(PsiClass -> VirtualFile -> PsiFile, KtClass::class.java)
- Also based on the language of the PsiClass instance, decide to use PsiField or KtProperty to resolve the child elements of the instance, and then implement all the logic supported by the custom language, such as reference resolution, completion hints, syntax highlighting, renaming, structure view, and so on
Then I found something called 'UAST', which is a common abstraction for all JVM languages, and it looks like there are definitions for UClass, UField, and so on, which could theoretically simplify my implementation considerably, or at least eliminate the need to handle the same concepts with different logic depending on the language type.
For now, if I can use UAST to implement the following logic, then I can simplify my logic chain from the second step onwards to 'UClass#getFields'.
- does UAST support getting UClass instances as fully qualified names? If not, can we only use JavaPsiFacade#findClass to get PsiClass instances and then convert them to UClass?
- what are the current ways to get UAST instances? Is there only one way to get a Psi instance first, and then convert it to a UAST instance?
- Can UAST implement all the logic in custom language development and thus use UAST instead of my handling of Psi, Kt elements?
Please sign in to leave a comment.
Hi,
First, did you get familiar with https://plugins.jetbrains.com/docs/intellij/uast.html?
Regarding your questions:
JavaPsiFacade
(it should also find Kotlin classes as a light implementation ofPsiClass
), and then convert it to UAST: https://plugins.jetbrains.com/docs/intellij/uast.html#psi-to-uast-conversionPsiElement
toUElement
. See the link above.In general, I suggest trying it out, and if UAST is insufficient in some cases, you can also fall back to Java/Kotlin-specific code provided via your custom extension point and Java/Kotlin-specific implementations. See https://github.com/JetBrains/intellij-community/blob/243/plugins/devkit/devkit-core/src/inspections/IncorrectCancellationExceptionHandlingInspection.kt#L278-L298 as an example.
You can also report an issue or request a feature at http://youtrack.jetbrains.com/issues/IJPL with
- Subsystem: Core. Platform API
- Tag UAST.
I did read that page ahead of time, which is why I had those questions. It's just that I was working on a feature when I asked the question before, and couldn't interrupt to open a new attempt, but now I can try it out!
However, I'll try to refine those questions with my own attempts, because there may be other people who have the same problem, and I've had questions like “Is this the best solution?”
My custom language are designed to be associated with
PsiMethod
/KtProperty
in Java/Kotlin interfaces with specific annotations. To make a custom language look like a language, you need to implement at least the References and Resolve features.Prior to that, from which version of idea was UAST available?
With this goal in mind, my attempts for UAST are as follows:
dsfGetting the
UClass
is currently achieved by first getting thePsiClass
instance viaJavaPsiFacade
and then callingcom.intellij.psi.PsiElement?.toUElement()
. I noticed that there isUastFacade
, but it doesn't have a method likefindUClass
likeJavaPsiFacade
hasfindClass
?Get
UAnnotation
, simply useuAnnotations
orfindAnnotation(fqName: kotlin.String)
Getting
PsiMethod
/KtProperty
instances, currently it's a matter of getting aPsiClass
instance, then determining if the language is kotlin or not, then using specific logic for the specific language. InUClass
, my assumption is that you also need to determine the language before deciding whether to callgetFields
orgetMethods
, but in reality, for the kotlin interface,getFields
returns the empty list andgetMethods
returns the Java version?In Kotlin, the interface is defined as follows:
Attempted results:
After trying it out, I think this would be better here for now, what do you think? It's just that I'm considering using UAST with the original intention of no longer needing to judge the language, and this still doesn't satisfy me directly, it's still a bit of a hassle
Getting the UAST version of the
PsiPackage
, but there doesn't seem to be anything likeUPackage
? After trying, there is no such thing either. So, UAST doesn't do a language-specific implementation forPsiPackage
, just usePsiPackage
directly?PsiReferenceBase
needsPsiElement
, so after getting the targetUElement
, you still need to convert it toPsiElement
and then buildPsiReferenceBase
, here you can usesourcePsi
directly to get the original language element.Hi,
Sometimes it is helpful to use Dump UAST Tree action to understand UAST trees better.