openrewrite Lossless Semantic Trees (LST)

Lossless Semantic Trees (LST) 是 openrewrite的 代码解析和修改的核心理论,取代了传统的abstract syntax tree。

支持对java 和yaml文件进行LST解析

1 vs ast

1.1Lossless Semantic Tree (LST) is a tree representation of code

1.2比AST(abstract syntax tree) 可以提供精准搜索和转换,特性

  • Type-attributed提供类型信息
    Format-preserving格式保持

2 lifecycle

2.1OpenRewrite 进程创建一个存储在内存中的 LST。这反映了磁盘上存储库的当前状态。

2.2该过程通过对 LST 进行转换来继续。在过程中可以仅仅增加 search marker (search 类recipe) ,也可以修改代码

2.3配方运行完成后,LST 将转换回文本,然后用于覆盖任何已更改的现有文件(注意:如果是dryRun,不修改文件,仅输出diff)。

2.4覆盖所有文件后,该过程结束。recipe运行之间不存储任何内容。

2.5如果您在第一个recipe完成后运行另一个recipe,则届时将生成一个新的 LST。

2.6如果之前的recipe进行了更改,并且这些更改存在于本地,则新生成的 LST 将具有所有这些更改。如果之前的recipe没有进行任何更改,那么 LST 实际上将与之前相同。

3 Java LST

3.1CompilationUnit

3.1.1root of the Java LST,一个java 文件就是一个CompilationUnit

3.1.2Package

3.1.3Import

fieldAccess:这里的fieldAccess 其实import的类名称

3.1.4ClassDeclaration

  • block
  • Identifier 注意identifier 是任意名称(类,变量,方法 。。),即实际很多地方都有
  • VariableDeclaration
  • Expression anything that returns a value,MethodInvocation, Identifier, and Binary are all examples of expressions
  • MethodDeclaration 包括了方案body
  • MethodInvocation 包括了参数
  • NewClass new 新实例/对象 Statement if, while, try, Block, return, and
    MethodInvocation are all examples of statements.
  • VariableDeclarations

3.2注意其实type非常多,可以通过debug或者TreeVisitingPrinter来查看明细

3.2.1debug

在JavaIsoVisitor类的visitCompilationUnit 增加断点

@Override

public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, P p) {

return (J.CompilationUnit) super.visitCompilationUnit(cu, p);

}

查看CU对象

3.3使用TreeVisitingPrinter输出

java 复制代码
public class TreeVisitingPrinterRecipe extends Recipe {
    @Override
    public String getDisplayName() {
        return "JavaIsoVisitor"
    }

    @Override
    public JavaIsoVisitor<ExecutionContext> getVisitor() {
        return new JavaIsoVisitor<ExecutionContext>() {
            @Override
            public J.CompilationUnit visitCompilationUnit(J.CompilationUnit compUnit, ExecutionContext executionContext) {
                // This next line could be omitted in favor of a breakpoint
                // if you'd prefer to use the debugger instead.
                System.out.println(TreeVisitingPrinter.printTree(getCursor()));
                return super.visitCompilationUnit(compUnit, executionContext);
            }
        };
    }

@Override
public @Description String getDescription() {
// TODO Auto-generated method stub
return "JavaIsoVisitor."
}
}

3.3.2output example

java 复制代码
----J.CompilationUnit
    \---J.ClassDeclaration
        |---J.Identifier | "A"
        \---J.Block
            \-------J.MethodDeclaration | "MethodDeclaration{A{name=test,return=void,parameters=[]}}"
                    |---J.Primitive | "void"
                    |---J.Identifier | "test"
                    |-----------J.Empty
                    \---J.Block
                        |-------J.VariableDeclarations | "int a"
                        |       |---J.Primitive | "int"
                        |       \-------J.VariableDeclarations.NamedVariable | "a"
                        |               \---J.Identifier | "a"
                        \-------J.Assignment | "a = 0"
                                |---J.Identifier | "a"
                                \-------J.Literal | "0"

3.3.3comment 读取有一定问题,不会输出

3.4问题

3.4.1读取comment有一些问题

java 复制代码
public static String readFile(String filePath) throws IOException {
        byte[] bytes = Files.readAllBytes(Paths.get(filePath)); // new file comment-----
        return new String(bytes, "UTF-8"); // chatset ----->StandardCharsets.UTF_8
        
    } 

输出如下

java 复制代码
visitReturn->TextComment(multiline=false, text= new file comment-----, suffix=
        , markers=Markers(id=48453257-5524-4864-a28f-0a18937fcd4f, markers=[]))

即最后一个comment没有读取到,而且把上一行的comment 挂到return上

另外方法前的comment也会挂到方法上而不是class内

测试所用方法

java 复制代码
 @Override
            public Statement visitStatement(Statement statement, ExecutionContext executionContext) {
            if (statement.getComments().size()>0) {
            statement.getComments().forEach( 
            comment->{
            TextComment text=(TextComment) comment
            System.out.println("visitStatement->"+statement.print()+"->->"+ text.getText()+" -->end<--");
            }
            );
            
            }
                return (Statement) super.visitStatement(statement, executionContext);
            }
            
相关推荐
代码不停15 分钟前
Java单链表和哈希表题目练习
java·开发语言·散列表
Dxxyyyy17 分钟前
零基础学JAVA--Day37(坦克大战1.0)
java·开发语言
OranTech21 分钟前
第28节课-夕夕超市收银系统(下)-笔记
java
IDOlaoluo29 分钟前
jakarta-tomcat-connectors-jk2-src.tar.gz 安装教程(详细步骤及附安装包)
java·tomcat
SheepHappy35 分钟前
MyBatis-Plus 源码阅读(三)条件构造器原理深度剖析
java·源码阅读
zhaomy202536 分钟前
从ThreadLocal到ScopedValue:Java上下文管理的架构演进与实战指南
java·后端
用户849137175471642 分钟前
从源码看设计:Java 集合框架的安全性与性能权衡 (基于 JDK 1.8)
java·面试
华仔啊43 分钟前
10分钟搞定!SpringBoot+Vue3 整合 SSE 实现实时消息推送
java·vue.js·后端
l***77521 小时前
总结:Spring Boot 之spring.factories
java·spring boot·spring
天若有情6731 小时前
笑喷!乌鸦哥版demo函数掀桌怒怼主函数:难办?那就别办了!
java·前端·servlet