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);
            }
            
相关推荐
智慧物业老杨4 小时前
物业日常巡查的数智化重构:从“打卡式巡检“到“闭环式风控“
android·java·人工智能·系统架构·rxjava
步行cgn10 小时前
Spring c 命名空间注入详解
java·后端·spring
明月_清风10 小时前
Maven 到底是什么?一篇文章搞懂 Java 项目构建与依赖管理
java·后端·maven
aramae11 小时前
MySQL复合查询(8)
java·c语言·开发语言·后端·算法
Rain的Java大神之路11 小时前
如何快速上传10G文件
java·spring boot·redis·后端·mysql·spring cloud·面试
Wang's Blog12 小时前
Java 接入Redis: 通用命令与键管理
java·服务器·redis
Wang's Blog12 小时前
Java 接入Redis: 列表集合与有序集合操作命令
java·服务器·redis
Ivanqhz12 小时前
SVD++算法
java·服务器·网络·深度学习·神经网络
qq_25183645713 小时前
springboot vue3 开发实现 拼豆管理系统
java·开发语言·ai编程
caoerzhong14 小时前
JeeWMS 开源仓库管理系统全景解读:一套 Java WMS 如何把 WMS/OMS/BMS/TMS 装进同一个系统
java·开源