UDN-企业互联网技术人气社区

板块导航

浏览  : 524
回复  : 1

[讨论交流] Java代码分析器(四): 代码改写技术

[复制链接]
开花包的头像 楼主
发表于 2016-8-4 21:49:23 | 显示全部楼层 |阅读模式
  一般的工具只能分析代码,不能改变代码,除了IDE的重构功能。但我们还是有办法实现的。

  不想让黑科技失传,趁着Java 7还在广泛使用,赶紧写下来(可能无法支持Java 8)。

  这个小框架让你看文章前就能上手,快速对代码库做分析/改写,性能很高: https://github.com/sorra/exia

  下面介绍经过验证的具体技术,能局部修改代码,调API就行了(感谢Eclipse)。文档里很难查到这些,痛的回忆……

  核心代码如下:

  1.   import org.eclipse.jface.text.Document;

  2.   import org.eclipse.text.edits.TextEdit;

  3.   CompilationUnit cu = parseAST(...); //parse方法参见系列文章

  4.   cu.recordModifications(); //开始记录AST变化事件

  5.   doChangesOnAST(...); //直接在树上改变结点,参见系列文章

  6.   Document document = new Document(content);

  7.   TextEdit edits = cu.rewrite(document, formatterOptions); //树上的变化生成了像diff一样的东西

  8.   edits.apply(document); //应用diff

  9.   return document.get(); //得到新的代码,未改动的部分几乎都保持原样
复制代码


  我用的formatterOptions:

  1.   private static final Map formatterOptions = DefaultCodeFormatterConstants.getEclipseDefaultSettings();

  2.   static {

  3.   formatterOptions.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7);

  4.   formatterOptions.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7);

  5.   formatterOptions.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7);

  6.   formatterOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, JavaCore.SPACE);

  7.   formatterOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, "2");

  8.   formatterOptions.put(DefaultCodeFormatterConstants.FORMATTER_LINE_SPLIT, "100");

  9.   formatterOptions.put(DefaultCodeFormatterConstants.FORMATTER_JOIN_LINES_IN_COMMENTS, DefaultCodeFormatterConstants.FALSE);

  10.   // change the option to wrap each enum constant on a new line

  11.   formatterOptions.put(

  12.   DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ENUM_CONSTANTS,

  13.   DefaultCodeFormatterConstants.createAlignmentValue(

  14.   true,

  15.   DefaultCodeFormatterConstants.WRAP_ONE_PER_LINE,

  16.   DefaultCodeFormatterConstants.INDENT_ON_COLUMN));

  17.   }
复制代码


  如果改动幅度很大,被改的代码可能会缩进混乱。忍一忍吧,这套API原本会把代码改错,我定位到bug,提给Eclipse,他们发现问题很深,最后没什么办法,只能牺牲缩进换来代码正确性。

  由于以上原因,这套便利的API在Java 8不再保证支持。据说只能用原始的ListRewrite来改代码…… 珍惜着用吧。

  最后再介绍两个便利方法:

  ASTNode#delete()

  结点能把自身从树上移除。调这个方法不需要知道parent结点的类型,用起来就知道方便了。

  replaceNode

  我仿写的方法,能任意替换一个结点,不需要知道parent结点的类型。

  1.   public static void replaceNode(ASTNode old, ASTNode neo) {

  2.   StructuralPropertyDescriptor p = old.getLocationInParent();

  3.   if (p == null) {

  4.   // node is unparented

  5.   return;

  6.   }

  7.   if (p.isChildProperty()) {

  8.   old.getParent().setStructuralProperty(p, neo);

  9.   return;

  10.   }

  11.   if (p.isChildListProperty()) {

  12.   List l = (List) old.getParent().getStructuralProperty(p);

  13.   l.set(l.indexOf(old), neo);

  14.   }

  15.   }
复制代码


原文作者: sorra    来源:开发者头条

相关帖子

发表于 2016-8-5 13:43:12 | 显示全部楼层
一般的工具只能分析代码,不能改变代码,除了IDE的重构功能
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部