idea插件开发-UAST

        UAST(统一抽象语法树)是针对 JVM(Java 虚拟机)的不同编程语言的PSI上的抽象层。它提供了一个统一的 API,用于处理公共语言元素,如类和方法声明、文字值和控制流运算符。不同的 JVM 语言有它们自己的PSI,但许多 IDE 功能,如检查、装订线标记、引用注入和许多其他功能,对所有这些语言都以相同的方式工作。使用 UAST 允许使用单个实现提供可在所有受支持的 JVM 语言中工作的功能。比如spring框架插件就使用了这种技术,完全支持java和kotlin。

        UAST 是只读 API。有实验UastCodeGenerationPlugin和JvmElementActionsFactory类,但目前不建议外部使用。

一、使用UAST

        UAST 的基本元素是UElement。不到必要的时候不建议使用UAST,因为性能并不是太好。

1、PSI 2 UAST

UastContextKt.toUElement(element);

//转换PsiElement为特定的UElement,可选下列方法之一
UastContextKt.toUElement(element, UCallExpression.class);
UastFacade.INSTANCE.convertElementWithParent(element,
    new Class[]{UInjectionHost.class, UReferenceExpression.class});
UastFacade.INSTANCE.convertToAlternatives(element,
    new Class[]{UField.class, UParameter.class});

2、UAST 2 PSI

        UElement#sourcePsi属性返回对应PsiElement的原始语言。sourcePsi是一个“物理” PsiElement,它主要用于获取原始文件中的文本范围(例如,用于突出显示)。有些UElement是“虚拟的”,因此没有sourcePsi。

        UElement#javaPsi返回 "Java-like" 型的PsiElement。PsiElement使不同的 JVM 语言模仿 Java 语言以保持与 Java-API 的兼容性的一种“伪造” 。例如,调用时MethodReferencesSearch.search(PsiMethod),只有 Java 原生提供PsiMethod;因此,其他 JVM 语言PsiMethod通过UMethod#javaPsi。

        所以UElement#javaPsi仅适用于 Java。因此UElement#sourcePsi应该用于获取文本范围或用于检查警告/装订线标记放置的锚元素。简而言之:

sourcePsi:

  • PsiElement是物理的:表示原始语言来源中的真实存在
  • 可用于突出显示、PSI 修改、创建智能指针等。
  • 除非绝对需要,否则不应强制转换(例如,处理特定语言的情况)

javaPsi:

  • 应该仅用作 JVM 可见声明的表示:PsiClass, PsiMethod,PsiField用于获取它们的名称、类型、参数等,或将它们传递给接受 Java-PSI 声明的方法
  • 不保证是物理的:来源中不存在
  • 不可修改:调用修改方法可能会引发非 Java 语言的异常

二、UAST Visitor

        在 UAST 中,没有统一的方法来获取children(UElement尽管可以通过 获取其父项UElement#uastParent)。因此,将 UAST 作为树遍历的唯一方法是传UastVisitor做为参数传递给UElement.accept()方法。

        UastVisitor可以通过UastVisitorAdapter或UastHintedVisitorAdapter方法被转换为PsiElementVisitor。建议使用提供更好的性能和更可预测的结果的UastHintedVisitorAdapter类。

        UastVisitor可以转换为PsiElementVisitor使用。后者更可取,因为它提供更好的性能和更可预测的结果。如果不需要处理很多种类型的UElement或比较复杂的结构,建议不要直接使用UastVisitor。建议使用PsiElementVisitor遍历PSI树,然后通过UastContext.toUElement()把PsiElement转换为UAST。

三、兼容性说明

        UAST提供了一种统一的方式来通过、UField、UClass等来表示 JVM 兼容声明。但同时,所有的 JVM 语言插件都实现了PsiMethod, PsiClass, 等等 以兼容 Java。这些实现可以通过属性获得UElement#javaPsi。

        UAST 是不同语言 PSI 之上的抽象层,并试图构建一个统一的树(参见检查 UAST 树)。这导致 UAST 和原始语言之间的树结构可能严重不同,因此无法保证保留祖先-后代关系。

你可能感兴趣的:(Idea插件开发,intellij-idea,java,ide)