• 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

    1. UastContextKt.toUElement(element);
    2. //转换PsiElement为特定的UElement,可选下列方法之一
    3. UastContextKt.toUElement(element, UCallExpression.class);
    4. UastFacade.INSTANCE.convertElementWithParent(element,
    5. new Class[]{UInjectionHost.class, UReferenceExpression.class});
    6. UastFacade.INSTANCE.convertToAlternatives(element,
    7. 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 和原始语言之间的树结构可能严重不同,因此无法保证保留祖先-后代关系。

  • 相关阅读:
    数据结构与算法【Java】03---栈
    有没有一段代码,让你为人类的智慧所折服
    「Java核心面试系列」Spring面试核心49问(附答案)
    Nginx漏洞总结
    分布式搜索引擎es-3
    kube-scheduler 抢占机制
    tp5微信公众号开发,申请公众号配置token验证
    【OpenCV-Python】教程:3-10 直方图(4)直方图反向投影
    leetcode做题笔记199. 二叉树的右视图
    【JavaScript】语法与对象以及案例验证码切换
  • 原文地址:https://blog.csdn.net/liudonglovehemin/article/details/130872967