• 1 Java程序文件中函数起始行和终止行在程序文件位置中的判定__抽象语法树方法


    应用需求:

    实现对BigCloneBench中函数体的克隆检测,必须标注出起始行号和终止行号。

    问题:

    给定一个Java文件,从中提取出每个函数的起始行和终止行。

    难点:

    这个问题的难点在于,对于Java的解析器而言,其在形成抽象语法树的过程中,已经对源码文件进行了划分,然后,形成了对函数的抽象语法树。但是这部分操作是不开源的,因此我们无法操作。我们只能在已经形成的抽象语法树上进行操作,读取函数的起始行和终止行。

    技术手段:

     Eclipse中的Eclipse JDT提供了一组访问和操作Java源代码的API,Eclipse AST是其中一个重要组成部分,它提供了AST、ASTParser、ASTNode、ASTVisitor等类,通过这些类可以获取、创建、访问和修改抽象语法树。

    实验与观察:

    示例函数:

    主体程序代码:

            CompilationUnit cu = extractCompilationUnit(sourceFilePath, javaVersion);
            
            //Method visitor
            MethodVisitor methodVisitor = new MethodVisitor();
            cu.accept(methodVisitor);
            List<MethodDeclaration> methods = methodVisitor.getMethods();
            for(MethodDeclaration method : methods){
                
                int methodStartLineNumber=cu.getLineNumber(method.getStartPosition());
                System.out.println("methodCode:");
                System.out.println(method.toString());
                System.out.println(methodStartLineNumber);
    
                //Visit the method node and extract all ASTNodes
                nodes = ASTNodeVisitor.visitMethod(method);
                int j=0;
                for (ASTNode node : nodes) {
                    System.out.println("子节点"+(++j));
                    System.out.println("所在起始行:"+cu.getLineNumber(node.getStartPosition()));//计算起始行
                    System.out.println("所在终止行:"+cu.getLineNumber(node.getStartPosition()+node.getLength()-1));//计算终止行
                    System.out.println("子节点类型:"+ASTNode.nodeClassForType(node.getNodeType()));
                    System.out.println("子节点内容:");
                    System.out.println(node.toString());                
                }
    }

    其中,cu是使用ASTParser类对Java文件进行解析以后得到的CompilationUnit类的编译单元。MethodVisitor继承ASTVisitor类,是对抽象语法树的每个MethodDeclaration类节点进行存储,构建methods列表,每个元素对应一个函数的抽象语法树的顶层节点。ASTNodeVisitor的visitMethod方法则对method对应抽象语法树的每个节点进行遍历,将节点存储到nodes列表中。

    部分输出结果是:

    methodCode:
    /** 
     * Creates an instance of  {@link Antlr4ErrorLog}.
     * @param log The Maven log
     */
    public Antlr4ErrorLog(Tool tool,BuildContext buildContext,Log log){
      this.tool=tool;
      this.buildContext=buildContext;
      this.log=log;
    }
    52

    可以看到:示例函数的起始行52是javadoc对应起始行的位置,并不是public起始行的位置。这是因为一个method的抽象语法树单元是包括javadoc单元和block单元的,其规则为:

    * <pre>
     * MethodDeclaration:
     *    [ Javadoc ] { ExtendedModifier } [ <b>&lt;</b> TypeParameter { <b>,</b> TypeParameter } <b>&gt;</b> ] ( Type | <b>void</b> )
     *        Identifier <b>(</b>
     *            [ ReceiverParameter <b>,</b> ] [ FormalParameter { <b>,</b> FormalParameter } ]
     *        <b>)</b> { Dimension }
     *        [ <b>throws</b> Type { <b>,</b> Type } ]
     *        ( Block | <b>;</b> )
     * ConstructorDeclaration:
     *    [ Javadoc ] { ExtendedModifier } [ <b>&lt;</b> TypeParameter { <b>,</b> TypeParameter } <b>&gt;</b> ]
     *        Identifier <b>(</b>
     *            [ ReceiverParameter <b>,</b> ] [ FormalParameter { <b>,</b> FormalParameter } ]
     *        <b>)</b> { Dimension }
     *        [ <b>throws</b> Type { <b>,</b> Type } ]
     *        ( Block | <b>;</b> )
     * </pre>
    可以看到Block是最后的一个元素。

    我们做三种进一步的小实验:

    实验一:移动大括号{,观察函数主体位置

    假如我们将{从public所在行打到下一行去,即58行,我们再观察一下:

    输出结果:

    我们会看到,block的所在行从57行变成了58行。

    实验二:添加人工注释,观察节点内容变化

    输出结果:

    之前终止行是61行,现在是第62行。然后public还有block等的起始行都是58。虽然第57行注释没有被解析为抽象语法树的内容,但是,整个函数的行数还是包括人工注释的行数!

    所以,如何精确计算函数的起始位置和终止位置?不能简简单单的去除javadoc的行数!

    结论:人工注释不被解析,只有javadoc格式才会被解析成为抽象语法树的一部分。但是,尽管没有被解析进去,但是人工注释的那一行被包含在内。你会发现函数的总行数增加了。

    实验三:在大括号}后添加注释

    最终方案:

    我们不能简单通过去除javadoc行数的方式得到函数真正函数体和声明的起始行和终止行。

    我们只有首先判断是否有javadoc节点,如果没有,接下来的第一个节点的行号就是起始行。然后,函数的终止行很好计算。

    于是,就有了方法。

     不再展开。

  • 相关阅读:
    P6406 [COCI2014-2015] Norma 分治+数学
    CF547D Mike and Fish 欧拉回路
    P6628 [省选联考 2020 B 卷] 丁香之路 欧拉路+最小生成树
    2020 CSP-S2 游记
    CF594D REQ 树状数组+质因数分解
    CF416E President's Path floyd
    CF1385F Removing Leaves 拓扑排序
    CF449C Jzzhu and Apples 思维题
    回溯法与八皇后问题
    codewars-7kyu:Sum of the first nth term of Series
  • 原文地址:https://www.cnblogs.com/xiaojieshisilang/p/10219344.html
Copyright © 2020-2023  润新知