IDEA Rebuild项目错误:Information:java: java.lang.AssertionError: Value of x -1
问题:java.lang.AssertionError: Value of x -1
模仿lombok工具,我的enumgen工具基本上写完了。
发布后准备投产时翻车了!公司的项目emax-rpcapi-list依赖enumgen后,IDEA Rebuild Project时,或者maven package/install的时候,出现报错→Information:java: java.lang.AssertionError: Value of x -1
下面是关于这个错误的详细信息:
Information:java: 编译器 (1.8.0_241) 中出现异常错误。如果在 Bug Database (http://bugs.java.com) 中没有找到该错误, 请通
过 Java Bug 报告页 (http://bugreport.java.com) 建立该 Java 编译器 Bug。请在报告中附上您的程序和以下诊断信息。谢谢。 Information:java: java.lang.AssertionError: Value of x -1 Information:java: at com.sun.tools.javac.util.Assert.error(Assert.java:133) Information:java: at com.sun.tools.javac.util.Assert.check(Assert.java:94) Information:java: at com.sun.tools.javac.util.Bits.incl(Bits.java:186) Information:java: at com.sun.tools.javac.comp.Flow$AssignAnalyzer.initParam(Flow.java:1858) Information:java: at com.sun.tools.javac.comp.Flow$AssignAnalyzer.visitMethodDef(Flow.java:1807) Information:java: at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:778) Information:java: at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49) Information:java: at com.sun.tools.javac.comp.Flow$BaseAnalyzer.scan(Flow.java:404) Information:java: at com.sun.tools.javac.comp.Flow$AssignAnalyzer.scan(Flow.java:1382) Information:java: at com.sun.tools.javac.comp.Flow$AssignAnalyzer.visitClassDef(Flow.java:1749) Information:java: at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:693) Information:java: at com.sun.tools.javac.comp.Flow$AssignAnalyzer.analyzeTree(Flow.java:2446) Information:java: at com.sun.tools.javac.comp.Flow$AssignAnalyzer.analyzeTree(Flow.java:2429) Information:java: at com.sun.tools.javac.comp.Flow.analyzeTree(Flow.java:211) Information:java: at com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1327) Information:java: at com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1296) Information:java: at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:901) Information:java: at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:860) Information:java: at com.sun.tools.javac.main.Main.compile(Main.java:523) Information:java: at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129) Information:java: at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138) Information:java: at org.jetbrains.jps.javac.JavacMain.compile(JavacMain.java:207) Information:java: at org.jetbrains.jps.incremental.java.JavaBuilder.compileJava(JavaBuilder.java:493) Information:java: at org.jetbrains.jps.incremental.java.JavaBuilder.compile(JavaBuilder.java:345) Information:java: at org.jetbrains.jps.incremental.java.JavaBuilder.doBuild(JavaBuilder.java:270) Information:java: at org.jetbrains.jps.incremental.java.JavaBuilder.build(JavaBuilder.java:223) Information:java: at org.jetbrains.jps.incremental.IncProjectBuilder.runModuleLevelBuilders(IncProjectBuilder.java:1414) Information:java: at org.jetbrains.jps.incremental.IncProjectBuilder.runBuildersForChunk(IncProjectBuilder.java:1092) Information:java: at org.jetbrains.jps.incremental.IncProjectBuilder.buildTargetsChunk(IncProjectBuilder.java:1159) Information:java: at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunkIfAffected(IncProjectBuilder.java:1053) Information:java: at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunks(IncProjectBuilder.java:882) Information:java: at org.jetbrains.jps.incremental.IncProjectBuilder.runBuild(IncProjectBuilder.java:449) Information:java: at org.jetbrains.jps.incremental.IncProjectBuilder.build(IncProjectBuilder.java:190) Information:java: at org.jetbrains.jps.cmdline.BuildRunner.runBuild(BuildRunner.java:138) Information:java: at org.jetbrains.jps.cmdline.BuildSession.runBuild(BuildSession.java:297) Information:java: at org.jetbrains.jps.cmdline.BuildSession.run(BuildSession.java:130) Information:java: at org.jetbrains.jps.cmdline.BuildMain$MyMessageHandler.lambda$channelRead0$0(BuildMain.java:218) Information:java: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) Information:java: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) Information:java: at java.lang.Thread.run(Thread.java:748) Information:java: Errors occurred while compiling module 'zhenghe-rpcapistyle' Information:javac 1.8.0_241 was used to compile java sources Information:2023/3/20 20:57 - Build completed with 1 error and 0 warnings in 5 s 993 ms Error:java: Compilation failed: internal java compiler error
此问题网上资料较少,在sun平台有网友提问,但是没有结果。
临时解决
这个错误让我有点摸不着头脑。因为我自己的demo项目在依赖了enumgen是可以正常使用的。
由于emax-rpcapi-list和我的demo项目同时也都依赖了lombok,直觉分析是enumgen与lombok产生冲突。我去修改我的注解处理器实现逻辑,去尝试解决,未能修复。中间排查过程比较曲折。最后在比对emax-rpcapi-list和我的demo工程两者的mvn:dependency:tree时,才有了下面的临时解决办法。
- 第一个是调整maven dependencies依赖顺序。我的要在lombok的前面先行依赖enumgen。
- 第二个是lombok版本兼容性。lombok版本1.18.20是有问题的,升级lombok的版本到1.18.24,就可以了。
问题又出现了
为什么叫临时解决办法呢? 因为我的enumgen后续又扩展了一些代码。结果,同样的错误又出现了→Information:java: java.lang.AssertionError: Value of x -1
我开始仔细分析错误堆栈,注意到 visitClassDef、visitMethodDef 这些关键字。
Flow:2493 ---
Flow$AssignAnalyzer#visitMethodDef
@Override public void visitMethodDef(JCMethodDecl tree) { if (tree.body == null) { return; } /* MemberEnter can generate synthetic methods ignore them */ if ((tree.sym.flags() & SYNTHETIC) != 0) { return; } Lint lintPrev = lint; lint = lint.augment(tree.sym); try { super.visitMethodDef(tree); // 这里调用super---Flow$AbstractAssignAnalyzer } finally { lint = lintPrev; } }
Flow$AbstractAssignAnalyzer#visitMethodDef(JCMethodDecl)
for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { JCVariableDecl def = l.head; scan(def); Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag"); /* If we are executing the code from Gen, then there can be * synthetic or mandated variables, ignore them. */ initParam(def); }
Flow:1795
Flow$AbstractAssignAnalyzer#initParam(JCVariableDecl)
protected void initParam(JCVariableDecl def) { inits.incl(def.sym.adr); // inits是com.sun.tools.javac.util.Bits实例 uninits.excl(def.sym.adr); }
com.sun.tools.javac.util.Bits#incl
/** Include x in this set. */ public void incl(int x) { Assert.check(currentState != BitsState.UNKNOWN); Assert.check(x >= 0, "Value of x " + x); // 这里调用了Assert#check sizeTo((x >>> wordshift) + 1); bits[x >>> wordshift] = bits[x >>> wordshift] | (1 << (x & wordmask)); currentState = BitsState.NORMAL; }
JCVariableDecl.sym.adr见Symbol#adr
/** The variable's address. Used for different purposes during * flow analysis, translation and code generation. * Flow analysis: * If this is a blank final or local variable, its sequence number. * Translation: * If this is a private field, its access number. * Code generation: * If this is a local variable, its logical slot number. */ public int adr = -1;
借助百度翻译来理解一下这段javadoc:
/**变量的地址。在Flow分析、翻译和代码生成过程中用于不同的目的。
*Flow分析:
*如果这是一个空白的最终变量或局部变量,那么它就是序列号。
*Translation:
*如果这是一个私人字段,那么它就是访问号码。
*代码生成:
*如果这是一个局部变量,那么它就是逻辑槽号。*/
public int adr = -1;
堆栈里是Flow$Analyzer,所以推断是我的变量定义的问题。然后,就是一顿改修改的类似下面的VarDef相关的代码,主要是关注VarDef的第一个参数modifier,发现也就只能用Flags.PARAMETER。依然无法解决问题。
JCTree.JCVariableDecl var_exception = maker.VarDef(maker.Modifiers(Flags.PARAMETER), names.fromString("e"), maker.Ident(names.fromString(exceptionClass.getSimpleName())), null);
最终的解决方案
先贴出来我的代码吧
1 @Override 2 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 3 final Set<? extends Element> dataAnnotations = roundEnv.getElementsAnnotatedWith(EnumGetByCode.class); 4 dataAnnotations.stream() 5 .filter(element -> element.getKind() == ElementKind.ENUM)//筛选枚举类 6 .map(element -> trees.getTree(element)) 7 .forEach(tree -> { 8 tree.accept(new TreeTranslator() { 9 @Override 10 public void visitClassDef(JCTree.JCClassDecl jcClassDecl) { 11 astUtil.setClass(jcClassDecl); 12 13 prependGetBeanByName(jcClassDecl); 14 15 JCTree.JCMethodDecl newMethodDecl = prependGetBeanByCode(jcClassDecl); 16 if (newMethodDecl != null) { 17 astUtil.addImport(jcClassDecl); 18 19 prependGetDescriptionByCode(jcClassDecl, newMethodDecl); 20 } 21 super.visitClassDef(jcClassDecl); 22 23 } 24 }); 25 } 26 ); 27 return true; 28 }
终极解决办法是参考简书上的一篇帖子,设置上下文的treeMaker实例的pos。
当到达下个注解使用处时,需要首先设置一下pos。因为系统中有很多的类或者方法使用了目标注解,而在代码生成过程中(也就是accept里重写visitClassDef为当前class append或prepend的元素),没有对treeMarker.pos的修改,使得其一直保持不变即使操作已经进行到下个类文件,pos仍然是不变的。
的确如此,当我在visitClassDef把那些append或prepend注释掉时,是不会出现这个错误的。
修改后的代码,就是在上面第8行调用tree.accept前面,加上一行代码: maker.pos = tree.pos;
终于松了一口气!
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/17239766.html