eclipse中ast

我们离JavaParser 3.0的第一个候选发布版本越来越近。 我们添加的最后一项功能是支持观察抽象语法树的所有节点的更改。 当我为此功能编写代码时,我收到了Danny van Bruggen(又名Matozoid)和Cruz Maximilien的宝贵反馈。 因此,我使用“我们”来指代JavaParser团队。

AST节点上的哪些观察者可以用于?

我认为这对于JavaParser的生态系统来说是非常重要的功能,因为它通过对AST所做的更改做出React,使与JavaParser的集成变得更加容易。 可以观察到的可能更改是为类设置新名称或添加新字段。 不同的工具可以以不同的方式对这些变化做出React。 例如:

  • 编辑者可以更新其符号列表,该列表可用于自动完成等操作
  • 一些框架可以重新生成源代码以反映更改
  • 可以执行验证以验证新更改是否导致无效的AST
  • JavaSymbolSolver之类的库可以重新计算表达式的类型

这些只是我想到的一些想法,但我认为使用JavaParser的大多数方案都可以从对更改做出React的可能性中受益。

AstObserver

JavaParser 3.0 AST基于Nodes和NodeLists。 一个节点,例如一个TypeDeclaration ,可以具有不同的子组。 当这些组可以包含多个节点时,我们使用NodeLists。 例如,一个TypeDeclarations可以具有多个成员(字段,方法,内部类)。 因此,每个TypeDeclaration都有一个NodeList来包含字段,一个NodeList来包含方法,等等。其他子项(如TypeDeclaration的名称)则直接包含在一个节点中。

我们引入了一个名为AstObserver的新接口 AstObserver接收节点和NodeList上的更改。

/*** An Observer for an AST element (either a Node or a NodeList).*/
public interface AstObserver {/*** Type of change occurring on a List*/public enum ListChangeType {ADDITION,REMOVAL}/*** The value of a property is changed** @param observedNode owner of the property* @param property property changed* @param oldValue value of the property before the change* @param newValue value of the property after the change*/void propertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue);/*** The parent of a node is changed** @param observedNode node of which the parent is changed* @param previousParent previous parent* @param newParent new parent*/void parentChange(Node observedNode, Node previousParent, Node newParent);/*** A list is changed** @param observedNode list changed* @param type type of change* @param index position at which the changed occurred* @param nodeAddedOrRemoved element added or removed*/void listChange(NodeList observedNode, ListChangeType type, int index, Node nodeAddedOrRemoved);
}

观察什么

现在我们有了一个AstObserver ,我们需要确定它应该接收哪些更改。 我们考虑了三种可能的情况:

  1. 仅观察一个节点,例如ClassDeclaration。 观察者将收到有关该节点上的更改的通知(例如,如果类更改名称),而不是其任何后代的通知。 例如,如果类更改名称的字段不会通知观察者
  2. 对于观察者注册时的节点及其所有后代。 在这种情况下,如果我注册了ClassDeclaration的观察者,则将通知我有关类及其所有字段和方法的更改。 如果添加了新字段并在以后进行了修改,那么我将不会收到有关这些更改的通知
  3. 对于一个节点及其所有后代,在观察者注册时存在的节点和以后添加的节点。

因此,Node现在具有此方法:

/*** Register a new observer for the given node. Depending on the mode specified also descendants, existing* and new, could be observed. For more details seeObserverRegistrationMode .*/public void register(AstObserver observer, ObserverRegistrationMode mode) {if (mode == null) {throw new IllegalArgumentException("Mode should be not null");}switch (mode) {case JUST_THIS_NODE:register(observer);break;case THIS_NODE_AND_EXISTING_DESCENDANTS:registerForSubtree(observer);break;case SELF_PROPAGATING:registerForSubtree(PropagatingAstObserver.transformInPropagatingObserver(observer));break;default:throw new UnsupportedOperationException("This mode is not supported: " + mode);}}

为了区分这三种情况,我们仅使用一个枚举( ObserverRegistrationMode )。 稍后,您将看到我们如何实现PropagatingAstObserver

实施对观察员的支持

如果JavaParser基于诸如EMF之类的元建模框架,则这将非常简单。 鉴于情况并非如此,我需要在AST类的所有设置器中添加一个通知调用(其中有90个左右)。

因此,当在特定节点上调用setter时,它将通知所有观察者。 简单。 以TypeDeclaration <T>中的 setName 为例

@Override
public T setName(SimpleName name) {notifyPropertyChange(ObservableProperty.NAME, this.name, name);this.name = assertNotNull(name);setAsParentNodeOf(name);return (T) this;
}

鉴于我们没有适当的元模型,因此没有属性的定义。 因此,我们在枚举中添加了一个名为ObservableProperty的属性列表。 通过这种方式,观察者可以检查更改了哪个属性并决定如何做出React。

观察者的内部等级

出于性能原因,每个节点都有自己的观察者列表。 当我们要观察节点的所有后代时,我们只需向该子树中的所有节点和节点列表添加相同的观察者即可。

但是,这还不够,因为在某些情况下,您可能还需要观察放置观察者后添加到子树中的所有节点。 我们通过使用PropagatingAstObserver做到这一点。 这是一个AstObserver,当看到一个新节点已附加到该节点时,它也开始观察该新节点。 简单吧?

/*** This AstObserver attach itself to all new nodes added to the nodes already observed.*/
public abstract class PropagatingAstObserver implements AstObserver {/*** Wrap a given observer to make it self-propagating. If the given observer is an instance of PropagatingAstObserver* the observer is returned without changes.*/public static PropagatingAstObserver transformInPropagatingObserver(final AstObserver observer) {if (observer instanceof PropagatingAstObserver) {return (PropagatingAstObserver)observer;}return new PropagatingAstObserver() {@Overridepublic void concretePropertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue) {observer.propertyChange(observedNode, property, oldValue, newValue);}@Overridepublic void concreteListChange(NodeList observedNode, ListChangeType type, int index, Node nodeAddedOrRemoved) {observer.listChange(observedNode, type, index, nodeAddedOrRemoved);}@Overridepublic void parentChange(Node observedNode, Node previousParent, Node newParent) {observer.parentChange(observedNode, previousParent, newParent);}};}@Overridepublic final void propertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue) {considerRemoving(oldValue);considerAdding(newValue);concretePropertyChange(observedNode, property, oldValue, newValue);}@Overridepublic final void listChange(NodeList observedNode, ListChangeType type, int index, Node nodeAddedOrRemoved) {if (type == ListChangeType.REMOVAL) {considerRemoving(nodeAddedOrRemoved);} else if (type == ListChangeType.ADDITION) {considerAdding(nodeAddedOrRemoved);}concreteListChange(observedNode, type, index, nodeAddedOrRemoved);}public void concretePropertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue) {// do nothing}public void concreteListChange(NodeList observedNode, ListChangeType type, int index, Node nodeAddedOrRemoved) {// do nothing}@Overridepublic void parentChange(Node observedNode, Node previousParent, Node newParent) {// do nothing}private void considerRemoving(Object element) {if (element instanceof Observable) {if (((Observable) element).isRegistered(this)) {((Observable) element).unregister(this);}}}private void considerAdding(Object element) {if (element instanceof Node) {((Node) element).registerForSubtree(this);} else if (element instanceof Observable) {((Observable) element).register(this);}}}

观察员在行动

让我们看看这在实践中如何工作:

// write some code and parse it
String code = "class A { int f; void foo(int p) { return 'z'; }}";
CompilationUnit cu = JavaParser.parse(code);// set up our observer
List changes = new ArrayList<>();
AstObserver observer = new AstObserverAdapter() {@Overridepublic void propertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue) {changes.add(String.format("%s.%s changed from %s to %s", observedNode.getClass().getSimpleName(), property.name().toLowerCase(), oldValue, newValue));}
};
cu.getClassByName("A").register(observer, /* Here we could use different modes */);// Doing some changes
cu.getClassByName("A").setName("MyCoolClass");
cu.getClassByName("MyCoolClass").getFieldByName("f").setElementType(new PrimitiveType(PrimitiveType.Primitive.Boolean));
cu.getClassByName("MyCoolClass").getMethodsByName("foo").get(0).getParamByName("p").setName("myParam");
// Here we are adding a new field and immediately changing it
cu.getClassByName("MyCoolClass").addField("int", "bar").getVariables().get(0).setInit("0");// If we registered our observer with mode JUST_THIS_NODE
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass"), changes);// If we registered our observer with mode THIS_NODE_AND_EXISTING_DESCENDANTS
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass","FieldDeclaration.element_type changed from int to boolean","VariableDeclaratorId.name changed from p to myParam"), changes);// If we registered our observer with mode SELF_PROPAGATING
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass","FieldDeclaration.element_type changed from int to boolean","VariableDeclaratorId.name changed from p to myParam","FieldDeclaration.modifiers changed from [] to []","FieldDeclaration.element_type changed from empty to int","VariableDeclaratorId.array_bracket_pairs_after_id changed from com.github.javaparser.ast.NodeList@1 to com.github.javaparser.ast.NodeList@1","VariableDeclarator.init changed from null to 0"), changes);

结论

我对此新功能感到非常兴奋,因为我认为它使JavaParser可以完成更多很酷的事情。 我认为我们作为提交者的工作是使其他人能够做我们目前未预见的事情。 我们应该只是充当推动者,然后躲开。

我真的很好奇,看看人们会如何发展。 顺便说一句,您知道您想让我们知道的任何使用JavaParser的项目吗? 在GitHub上发表评论或打开问题,我们期待您的来信!

翻译自: https://www.javacodegeeks.com/2016/11/observers-ast-nodes-javaparser.html

eclipse中ast

eclipse中ast_JavaParser中AST节点的观察者相关推荐

  1. JavaParser中AST节点的观察者

    我们离JavaParser 3.0的第一个候选发布版本越来越近. 我们添加的最后一项功能是支持观察抽象语法树的所有节点的更改. 当我为此功能编写代码时,我收到了Danny van Bruggen(又名 ...

  2. asp.net中web.config配置节点大全详解

    web.config 文件查找规则:        (1)如果在当前页面所在目录下存在web.config文件,查看是否存在所要查找的结点名称,如果存在返回结果并停止查找.        (2)如果当 ...

  3. 在Eclipse或MyEclipse中安装findbugs插件

    2019独角兽企业重金招聘Python工程师标准>>> 我们都知道,在Eclipse或MyEclipse中安装插件有两种方式,一种是在线安装,第二种是先下载插件然后在本地安装. 在这 ...

  4. 【 C 】在单链表中插入一个新节点的尝试(二)

    在上篇博文中:[ C ]在单链表中插入一个新节点的尝试(一),我们最后提到了如果向单链表的开头(起始位置)插入一个节点,上篇博文中给出的程序显然完成不了这任务. 这篇博文中,我们将解决这个问题,给出一 ...

  5. 【 C 】在单链表中插入一个新节点的尝试(一)

    根据<C和指针>中讲解链表的知识,记录最终写一个在单链表中插入一个新节点的函数的过程,这个分析过程十分的有趣,准备了两篇博文,用于记录这个过程. 链表是以结构体和指针为基础的,所以结构体和 ...

  6. [转]NS2仿真过程中解决动画仿真节点未定义问题

    原文地址:http://blog.myspace.cn/e/400266384.htm 其实,这个问题已经出现很长时间了,但是直到昨天问题才得到解决. 问题描述 用NS2运行无线仿真,然后运行动画程序 ...

  7. 二叉树中如何求根节点到任意节点的路径?

    二叉树中如何求任一节点的路径呢? 思路 使用先序遍历,处理的时候让节点入栈,并且加上标志位即可. 使用另外的result保存最终的路径. 函数 void pre_order(TreeNode * no ...

  8. 【深度学习】网络中隐含层神经元节点的个数(需要学习的特征数目)

    http://blog.csdn.net/zouxy09/article/details/9983399 1.网络中隐含层神经元节点的个数(需要学习的特征数目),采集的密度(也就是convolutio ...

  9. 在Eclipse 2.0中使用版本控制系统CVS

    董向辉 (xianghui.dong@mail.ia.ac.cn) 2002 年 7 月 2002年6月28日,Eclipse 2.0正式版已经正式完成,这将是Java开发工具历史上的一个重要事件,E ...

最新文章

  1. 盘点程序员写过的惊天 Bug
  2. jquery插件,nocube
  3. #x开头的是什么编码呢。浏览器可以解释它。如中国等同与中文中国?
  4. 2021年零基础带你走进nacos的世界之云服务器下载安装nacos-小白教程,详细到爆了!
  5. python地图 两点距离_没学过还真不会!怎样才能画出准确的地图?
  6. 死锁必要条件、解决死锁策略
  7. a,b值进行交换的方法
  8. 2.策略模式(Strategy)
  9. TI C6000 TMS320C6678 DSP+ Zynq-7045的PS + PL异构多核案例开发手册(4)
  10. 使用阿里云短信API接口
  11. ai怎么渐变颜色_AI渐变工具怎么使用?AI渐变工具使用方法介绍
  12. Dynamic CRM 2016 IFD配置(1)证书颁发机构配置
  13. PT6303加充电电路的一套原理图
  14. TortoiseSVN patch 创建并应用补丁
  15. 王牌战争文明重启服务器维护中,王牌战争文明重启常见问题解答-王牌战争文明重启常见问题一览_牛游戏网...
  16. linux系统tomcat升级,Tomcat 7 升级到 Tomcat 8 历程
  17. 统计双色球各个数字的中奖概率
  18. singleSpa记录
  19. 致远SPM解决方案之库存管理
  20. matlab从mp4文件中提取音频,怎么提取MP4视频中的音频,将MP4格式转换为MP3格式

热门文章

  1. 周末狂欢赛1(玩游戏/Game,函数,JOIOI王国)
  2. 2021牛客OI赛前集训营-提高组(第五场)C-第K排列【dp】
  3. P7099-[yLOI2020]灼【数学期望,结论】
  4. P4643-[国家集训队]阿狸和桃子的游戏【结论】
  5. P1368-工艺【最小表示法】
  6. 各种模板(数据结构图论)
  7. CF526G Spiders Evil Plan(树上最优性问题、倍增+线段树)
  8. HDU5833 异或方程组的初步学习
  9. Hibernate框架之入门配置
  10. 【Android布局】控件布置