我是AST的新手(我第一次写插件).表达在现实生活中可能相当复杂.例如,我想知道如何解决对齐的左侧和右侧.
class Visitor extends ASTVisitor
{
    @Override
    public boolean visit(Assignment node)
    {
        //here,how do I get the final name to each each side of the assignment resolves?
    }
}

我还有另一个疑问,我如何获取用于调用方法的实例?

public boolean visit(MethodInvocation node)
{
    //how do I get to kNow the object used to invoke this method?
    //like,for example,MyClass is a class,and it has a field called myField
    //the type of myField has a method called myMethod.
    //how do I find myField? or for that matter some myLocalVariable used in the same way.
}

假设以下任务

SomeType.someStaticmethod(params).someInstanceMethod(moreParams).someField =
     [another expression with arbitrary complexity]

如何从Assigment节点访问someField?

而且,MethodInvocation的哪个属性为我提供了用于调用方法的实例?

编辑1:鉴于我收到的答案,我的问题显然不清楚.我不想解决这个特殊的表达方式.我希望能够在给定任何赋值的情况下找出它所分配的名称,以及分配给第一个名称的名称(如果不是rvalue).

因此,例如,方法调用的参数可以是字段访问或先前声明的局部变量.

SomeType.someStaticmethod(instance.field).someInstanceMethod(type.staticField,localVariable,localField).Field.destinationField

所以,这是一个充满希望的客观问题:给定左侧和右侧具有任意复杂性的任何赋值语句,如何获得分配给的最终字段/变量,以及分配的最终(如果有)字段/变量它.

编辑2:更具体地说,我想要实现的是不变性,通过注释@Const:

/**
* When Applied to a method,ensures the method doesn't change in any
* way the state of the object used to invoke it,i.e.,all the fields
* of the object must remain the same,and no field may be returned,* unless the field itself is marked as {@code @Const} or the field is
* a primitive non-array type. A method  annotated with {@code @Const} 
* can only invoke other {@code @Const} methods of its class,can only 
* use the class's fields to invoke {@code @Const} methods of the fields 
* classes and can only pass fields as parameters to methods that 
* annotate that formal parameter as {@code @Const}.
*
* When applied to a formal parameter,ensures the method will not
* modify the value referenced by the formal parameter. A formal   
* parameter annotated as {@code @Const} will not be aliased inside the
* body of the method. The method is not allowed to invoke another 
* method and pass the annotated parameter,save if the other method 
* also annotates the formal parameter as {@code @Const}. The method is 
* not allowed to use the parameter to invoke any of its type's methods,* unless the method being invoked is also annotated as {@code @Const}
* 
* When applied to a field,ensures the field cannot be aliased and that
* no code can alter the state of that field,either from inside the   
* class that owns the field or from outside it. Any constructor in any
* derived class is allowed to set the value of the field and invoke any
* methods using it. As for methods,only those annotated as
* {@code @Const} may be invoked using the field. The field may only be
* passed as a parameter to a method if the method annotates the 
* corresponding formal parameter as {@code @Const}
* 
* When applied to a local variable,ensures neither the block where the
* variable is declared or any nested block will alter the value of that 
* local variable. The local variable may be defined only once,at any
* point where it is in scope and cannot be aliased. Only methods
* annotated as {@code @Const} may be invoked using this variable,and 
* the variable  may only be passed as a parameter to another method if 
* said method annotates its corresponding formal parameter as
* {@code @Const}
*
*/
@Retention(RetentionPolicy.soURCE)
@Target({ElementType.METHOD,ElementType.ParaMETER,ElementType.FIELD,ElementType.LOCAL_VARIABLE})
@Inherited
public @interface Const
{

}

要做到这一点,我要做的第一件事就是将作业的左侧标记为@Const(足够简单).我还必须检测何时和表达式的右侧是标记为@Const的字段,在这种情况下,它只能在相同类型的@Const变量的定义中分配.

问题是我很难找到表达式右侧的终极字段,以避免使字段混叠并使@Const注释无效.

解决方法

访问者是一个非常好的工具,但是对于特定问题的正确解决方案并不总是让一个访问者耐心地等待它的访问方法被调用…你问的问题就是这种情况的一个例子.

让我们改写你想要做的事情:

>您想要识别以识别每个任务(即leftSide = rightSide)
>对于每个赋值,您要确定左侧的性质(即,它是局部变量还是字段访问),如果它确实是字段访问,则您要构建对应的“路径”到该字段(即源对象,后跟一系列方法调用或字段访问,以字段访问结束).
>对于每个作业,您要确定与右侧对应的类似“路径”.

我认为你已经解决了第1点:你只需创建一个扩展org.eclipse.jdt.core.dom.ASTVisitor的类;在那里,你重写#visit(Assignment)方法.最后,在适当的地方,您实例化您的访问者类,并让它访问AST树,从哪个节点开始匹配您的需求(很可能是compilationunit,TypeDeclaration或MethodDeclaration的实例).

那又怎样? #visit(Assignment)方法确实接收Assignment节点.直接在该对象上,您可以获得左侧和右侧表达式(assignment.getLeftHandSide()和assignment.getRightHandSide()).正如你所提到的,两个都是表达式,它们可能变得相当复杂,那么我们如何从这些子树中提取干净,线性的“路径”呢?访问者肯定是这样做的最好方式,但这里有捕获,应该使用不同的访问者来完成,而不是让你的第一个访问者(一个捕获的分配)继续下降任何一方的表达.技术上可以使用单个访问者完成所有操作,但这将涉及访问者内部的重要状态管理.无论如何,我非常相信这种管理的复杂程度如此之高,以至于这种实施实际上效率会低于不同的访问者.

所以我们可以像这样形象:

class MyAssignmentListVisitor extends ASTVisitor {
    @Override
    public boolean visit(Assignment assignment) {
        FieldAccessLineralizationVisitor leftHandSideVisitor = new FieldAccessLineralizationVisitor();
        assignment.getLeftHandSide().accept(leftHandSideVisitor);
        LinearFieldAccess leftHandSidePath = leftHandSideVisitor.asLinearFieldAccess();

        FieldAccessLineralizationVisitor rightHandSideVisitor = new FieldAccessLineralizationVisitor();
        assignment.getRightHandSide().accept(rightHandSideVisitor);
        LinearFieldAccess rightHandSidePath = rightHandSideVisitor.asLinearFieldAccess();

        processAssigment(leftHandSidePath,rightHandSidePath);

        return true;
    }
}

class FieldAccessLineralizationVisitor extends ASTVisitor {

    List<?> significantFieldAccessparts = [...];

    // ... varIoUs visit method expecting concrete subtypes of Expression ...

    @Override
    public boolean visit(Assignment assignment) {
        // Found an assignment inside an assignment; ignore its
        // left hand side,as it does not affect the "path" for 
        // the assignment currently being investigated

        assignment.getRightHandSide().accept(this);

        return false;
    }
}

请注意,此代码中MyAssignmentListVisitor.visit(Assignment)返回true,表示应递归检查赋值的子项.这听起来可能没必要,Java语言确实支持几种结构,其中赋值可能包含其他赋值;例如考虑以下极端情况:

(vara = someObject).someField = varB = (varC = new SomeClass(varD = "string").someField);

出于同样的原因,在表达式的线性化期间仅访问赋值的右侧,因为赋值的“结果值”是其右侧.在这种情况下,左手边只是一个可以安全忽略的副作用.

鉴于我不知道您的特定情况所需的信息的性质,我将不再进一步描述路径实际建模的原型.您可能更适合为左侧表达式和右侧表达式分别创建不同的访问者类,例如为了更好地处理右侧可能实际涉及多个变量/字段/方法调用的事实通过二元运算符.这将是你的决定.

关于要讨论的AST树的访问者遍历仍然存在一些主要问题,即通过依赖于默认节点遍历顺序,您失去了获取每个节点之间关系的信息的机会.例如,给定表达式this.someMethod(this.fieldA).fieldB,您将看到类似于以下序列的内容:

FieldAccess      => corresponding to the whole expression
MethodInvovation => corresponding to this.someMethod(this.fieldA)
ThisExpression
SimpleName ("someMethod")
FieldAccess      => corresponding to this.fieldA
ThisExpression
SimpleName ("fieldA")
SimpleName ("fieldB")

根本无法从这一系列事件中推断出线性化表达式.您将希望明确拦截每个节点,并仅在适当的情况下以适当的顺序显式递归节点的子节点.例如,我们可以做到以下几点:

@Override
    public boolean visit(FieldAccess fieldAccess) {
        // FieldAccess :: <expression>.<name>

        // First descend on the "subject" of the field access
        fieldAccess.getExpression().accept(this);

        // Then append the name of the accessed field itself
        this.path.append(fieldAccess.getName().getIdentifier());

        return false;
    }

    @Override
    public boolean visit(MethodInvocation methodInvocation) {
        // MethodInvocation :: <expression>.<methodName><<typeArguments>>(arguments)

        // First descend on the "subject" of the method invocation
        methodInvocation.getExpression().accept(this);

        // Then append the name of the accessed field itself
        this.path.append(methodAccess.getName().getIdentifier() + "()");

        return false;
    }

    @Override
    public boolean visit(ThisExpression thisExpression) {
        // ThisExpression :: [<qualifier>.] this

        // I will ignore the qualifier part for Now,it will be up
        // to you to determine if it is pertinent
        this.path.append("this");

        return false;
    }

在前面的示例中,这些方法将在路径中收集以下序列:this,someMethod(),fieldB.我认为,这非常接近你所寻找的.如果您想收集所有字段访问/方法调用序列(例如,您希望访问者返回this,fieldB和this,fieldA),那么您可以重写访问(MethodInvocation)方法大致类似于这个:

@Override
    public boolean visit(MethodInvocation methodInvocation) {
        // MethodInvocation :: <expression>.<methodName><<typeArguments>>(arguments)

        // First descend on the "subject" of the method invocation
        methodInvocation.getExpression().accept(this);

        // Then append the name of the accessed field itself
        this.path.append(methodAccess.getName().getIdentifier() + "()");

        // Now deal with method arguments,each within its own,distinct access chain
        for (Expression arg : methodInvocation.getArguments()) {
            LinearPath orginalPath = this.path;
            this.path = new LinearPath();

            arg.accept(this);

            this.collectedpaths.append(this.path);
            this.path = originalPath;
        }

        return false;
    }

最后,如果您想知道路径中每一步的值类型,则必须查看与每个节点关联的绑定对象,例如:methodInvocation.resolveMethodBinding().getDeclaringClass().但请注意,必须在构建AST树时明确请求绑定解析.

上面的代码将无法正确处理更多的语言结构;不过,我相信你应该能够自己解决这些遗留问题.如果您需要查看引用实现,请查看类org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteFlattener,它基本上从现有的AST树重构Java源代码;虽然这个特定的访问者比大多数其他ASTVisitors大得多,但它更容易理解.

对OP编辑#2的响应更新

这是您最近编辑后的更新起点.仍有许多情况需要处理,但这更符合您的具体问题.另请注意,尽管我使用了大量的instanceof检查(因为这对我来说比较容易,因为我在简单的文本编辑器中编写代码,并且没有在ASTNode常量上完成代码),您可以选择node.getNodeType()上的switch语句,通常效率更高.

class ConstCheckVisitor extends ASTVisitor {

    @Override
    public boolean visit(MethodInvocation methodInvocation) {    
        if (isConst(methodInvocation.getExpression())) {
            if (isConst(methodInvocation.resolveMethodBinding().getmethodDeclaration()))
                reportInvokingNonConstMethodonConstSubject(methodInvocation);
        }

        return true;
    }

    @Override
    public boolean visit(Assignment assignment) {
        if (isConst(assignment.getLeftHandSide())) {
            if ( /* assignment to @Const value is not acceptable in the current situation */ )
                reportAssignmentToConst(assignment.getLeftHandSide());

            // FIXME: I assume here that aliasing a @Const value to
            //        another @Const value is acceptable. Is that right?

        } else if (isImplicitelyConst(assigment.getLeftHandSide())) {
            reportAssignmentToImplicitConst(assignment.getLeftHandSide());        

        } else if (isConst(assignment.getRightHandSide())) {
            reportAliasing(assignment.getRightHandSide());
        }

        return true;
    }

    private boolean isConst(Expression expression) {
        if (expression instanceof FieldAccess)
            return (isConst(((FieldAccess) expression).resolveFieldBinding()));

        if (expression instanceof SuperFieldAccess)
            return isConst(((SuperFieldAccess) expression).resolveFieldBinding());

        if (expression instanceof Name)
            return isConst(((Name) expression).resolveBinding());

        if (expression instanceof ArrayAccess)
            return isConst(((ArrayAccess) expression).getArray());

        if (expression instanceof Assignment)
            return isConst(((Assignment) expression).getRightHandSide());

        return false;
    }

    private boolean isImplicitConst(Expression expression) {
        // Check if field is actually accessed through a @Const chain
        if (expression instanceof FieldAccess)
            return isConst((FieldAccess expression).getExpression()) ||
                   isimplicitConst((FieldAccess expression).getExpression());

        // FIXME: Not sure about the effect of MethodInvocation,assuming
        //        that its subject is const or implicitly const

        return false;
    }

    private boolean isConst(IBinding binding) {
        if ((binding instanceof IVariableBinding) || (binding instanceof IMethodBinding))
            return containsConstAnnotation(binding.getAnnotations());

        return false;
    }
}

希望有所帮助.

java – 如何到达AST表达式的底部的更多相关文章

  1. Html5 Canvas实现图片标记、缩放、移动和保存历史状态功能 (附转换公式)

    这篇文章主要介绍了Html5 Canvas实现图片标记、缩放、移动和保存历史状态功能 (附转换公式),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. iOS &gt;&gt;块&gt;&gt;更改块外部的变量值

    我不是在处理一个Object并改变它,就像我的mString一样.我希望’center’属性的行为类似于myInt,因为它是直接访问的C结构,而不是指向对象的指针.我希望’backgroundColor’的行为类似于我的imstring,因为它是一个指向一个新对象的对象的指针,不是吗?

  3. ios – 类中的extern NSString * const.

    嗨,我有这个头文件:执行:当我在.pch文件中导入头文件时,我可以在任何地方访问常量.但我试着了解发生了什么.我从不为此对象分配init,因此它们不能是实例常量.所以常量必须是“类对象常量对吗?但我认为类对象不能包含数据.谁能解释一下?解决方法那些外部变量是app级全局变量.它们没有作用于类,它们不限于类的实例.Objective-C不支持实例或类级别全局变量.如果需要类级别常量,则需要定义类方法

  4. 寒城攻略:Listo 教你 25 天学会 Swift 语言 - 05 Strings and Characters

    Swift所代表的字符串是字符串类型,进而代表字符类型的值的集合//Swift的String和Character类型提供了一个快速的,兼容Unicode的方式来处理代码中的文本信息。每一个字符值代表一个Unicode字符,我们可以利用for-in循环来遍历字符串中的每一个字符println}//定义一个字符常量letyenSign:Character="$"printlncharacters")//使用"countElements()"函数来获取字符串的长度//8.ConcatenatingStrings

  5. swift 部分运算符

    下面的语句是无效的:ifx=y{println("这一特征可以防止使用相等的运算符(==)时,不小心使用赋值运算符(=)。通过使ifx=y无效,Swift可以帮助你避免代码中出现这些类型的错误")}2.swift中字符串的追加可以使用加法运算leth="hello,"letw="world"println(h+w)//输出hello,world3.范围运算符:闭区间运算符:表示[a,b]例如:forindexin1...5{println//输出1,2,3,4,5}半开区间运算符:表示[a,b)例如for

  6. 二 Swift学习之基本运算符

    二Swift学习之基本运算符————–借鉴老码团队翻译组-Tyrion1.1术语运算符有一元、二元和三元运算符。三元运算符操作三个操作对象,和C语言一样,Swift只有一个三元运算符,就是三目运算符(a?这不同于上面提到的自增和自减运算符。无疑空合运算符(??由于userDefinedColorName是一个可选类型,我们可以使用空合运算符去判断其值。

  7. Swift算术运算符

    ==,返回值为true和false逻辑运算符:!,&,&&,|,||(短路或)位运算符:~,^,>>,

  8. Swift语法基础:11 - Swift的运算术语, 赋值运算, 数值运算, 复合赋值

    在Swift当中当然是有与或非这三个逻辑运算符,并且兼容大部分C类运算符,比如“”,“=”,“==”,“=”,“+”,“-“,“*”,“/”,这些等等都支持,但这里有一点要注意一下,赋值符号“=”不返回值,以防止把“==”写成“=”导致程序出错.区别于C,Swfit还提供对浮点数类型进行取余预算“%”,还提供了C没有提供的区间,“0..

  9. Swift可选类型和可选链

    ),允许接受nil控制则是正常类型强制拆封如果我们能确定可选类型一定有值,那么在读取它的时候,可以在可选类型的后面加一个感叹号(!)println对result1中的语句进行了强制拆封前问号,后感叹号,强制拆封隐式拆封为了能够方便的访问可选类型,可以将可选类型后面的问号改成感叹号(!问号表示引用的时候,如果某个环节为nil,她不会出现错误,而是把nil返回给引用者,这种使用问号引用可选类型的方式叫做可选链三、使用问号?

  10. swift开发基础之变量和常量

    swift开发基础之变量和常量今天学习了一下swift语言感觉IOS又迈出了自己的一步代码上面简化了很多,并可以使用playground一个实时预览的效果注意:常量直接用let就行了如果对上面的常量重新赋值会出现错误不需要制定类型变量直接用var就行了可以多次赋值可以制定类型也可以不制定类型感觉很智能化可以多次重新赋值最后是一个变量叠加的问题只需要加一个\然后将数字括起来就行了playground

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部