java.lang.AssertionError 添加带有参数的生成方法时由编译器抛出
java.lang.AssertionError thrown by compiler when adding generated method with parameters
我正在使用带注释处理器的内部 sun API (com.sun.tools.javac
) 修改现有的 class。我可以使用以下代码生成 MethodDecl
并将其添加到 ClassDecl
:
JCTree.JCClassDecl classDecl = ...
JCTree.JCMethodDecl methodDecl = ...
JCTree[] trees = new JCTree[classDecl.defs.length() + 1];
trees[classDecl.defs.length()] = methodDecl;
classDecl.defs = List.from(trees);
在我尝试向方法声明中添加参数之前,它工作正常。我使用下面的代码生成一个新的 MethodDecl
:
Map<String, Class<?>> paramMap = ...
List<JCVariableDecl> parameters = List.from(paramMap.entrySet().stream()
.map(e -> treeMaker.VarDef(treeMaker.Modifiers(Flags.PARAMETER), elements.getName(e.getKey()), getType(e.getValue()), null))
.toArray(JCVariableDecl[]::new));
...
JCMethodDecl methodDecl = treeMaker.MethodDef(modifiers, methodName, returnType, genericParameters, parameters, throwables, methodBody, null);
我在编译时得到以下堆栈跟踪:
An exception has occurred in the compiler (9). Please file a bug against the Java compiler via the Java bug reporting page (http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com) for duplicates. Include your program and the following diagnostic in your report. Thank you.
java.lang.AssertionError
at jdk.compiler/com.sun.tools.javac.util.Assert.error(Assert.java:155)
at jdk.compiler/com.sun.tools.javac.util.Assert.check(Assert.java:46)
at jdk.compiler/com.sun.tools.javac.util.Bits.incl(Bits.java:186)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.initParam(Flow.java:1931)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.visitMethodDef(Flow.java:1880)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:866)
at jdk.compiler/com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
at jdk.compiler/com.sun.tools.javac.comp.Flow$BaseAnalyzer.scan(Flow.java:393)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.scan(Flow.java:1451)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.visitClassDef(Flow.java:1822)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:774)
at jdk.compiler/com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
at jdk.compiler/com.sun.tools.javac.comp.Flow$BaseAnalyzer.scan(Flow.java:393)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.scan(Flow.java:1451)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.analyzeTree(Flow.java:2521)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.analyzeTree(Flow.java:2504)
at jdk.compiler/com.sun.tools.javac.comp.Flow.analyzeTree(Flow.java:212)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1389)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1363)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:959)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall[=13=](JavacTaskImpl.java:100)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:142)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:96)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:90)
at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:49)
at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:36)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:99)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:52)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:37)
at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:35)
at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:25)
at org.gradle.api.tasks.compile.JavaCompile.performCompilation(JavaCompile.java:204)
at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:189)
at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:121)
at jdk.internal.reflect.GeneratedMethodAccessor170.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$IncrementalTaskAction.doExecute(DefaultTaskClassInfoStore.java:179)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:135)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:122)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.run(ExecuteActionsTaskExecuter.java:121)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:110)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:92)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:70)
at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:97)
at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:87)
at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.run(DefaultTaskGraphExecuter.java:248)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:123)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access0(DefaultTaskPlanExecutor.java:79)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.execute(DefaultTaskPlanExecutor.java:104)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.execute(DefaultTaskPlanExecutor.java:98)
at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:625)
at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:580)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:98)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:59)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:128)
at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.access[=13=]0(DefaultBuildExecuter.java:23)
at org.gradle.execution.DefaultBuildExecuter.proceed(DefaultBuildExecuter.java:43)
at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:46)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
at org.gradle.initialization.DefaultGradleLauncher$ExecuteTasks.run(DefaultGradleLauncher.java:314)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
at org.gradle.initialization.DefaultGradleLauncher.runTasks(DefaultGradleLauncher.java:204)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:134)
at org.gradle.initialization.DefaultGradleLauncher.executeTasks(DefaultGradleLauncher.java:109)
at org.gradle.internal.invocation.GradleBuildController.call(GradleBuildController.java:78)
at org.gradle.internal.invocation.GradleBuildController.call(GradleBuildController.java:75)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:152)
at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:100)
at org.gradle.internal.invocation.GradleBuildController.run(GradleBuildController.java:75)
at org.gradle.tooling.internal.provider.runner.BuildModelActionRunner.run(BuildModelActionRunner.java:53)
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32)
at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:43)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:40)
at org.gradle.tooling.internal.provider.SubscribableBuildActionRunner.run(SubscribableBuildActionRunner.java:51)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:47)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:30)
at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:39)
at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:25)
at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:80)
at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:53)
at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:57)
at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:32)
at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:36)
at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:25)
at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:43)
at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:29)
at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:64)
at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:29)
at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:59)
at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:44)
at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:45)
at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:30)
at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:67)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput.call(ForwardClientInput.java:74)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput.call(ForwardClientInput.java:72)
at org.gradle.util.Swapper.swap(Swapper.java:38)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:62)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:82)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy.run(StartBuildOrRespondWithBusy.java:50)
at org.gradle.launcher.daemon.server.DaemonStateCoordinator.run(DaemonStateCoordinator.java:295)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl.run(ManagedExecutorImpl.java:46)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
at java.base/java.lang.Thread.run(Thread.java:844)
当我用 List.nil()
替换参数时,这段代码编译完美,这就是为什么我认为问题与参数有关。
抛出异常的代码如下:
public void incl(int x) {
Assert.check(currentState != BitsState.UNKNOWN);
Assert.check(x >= 0); // <-- this line
sizeTo((x >>> wordshift) + 1);
bits[x >>> wordshift] = bits[x >>> wordshift] |
(1 << (x & wordmask));
currentState = BitsState.NORMAL;
}
visitMethodDef
被调用(来自Flow
class):
//important part in method visitMethodDef
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);
}
调用 initParam
:
protected void initParam(JCVariableDecl def) {
inits.incl(def.sym.adr);
uninits.excl(def.sym.adr);
}
所以如果我理解正确的话,参数的 sym.adr
是 < 0。手动创建 Symbol
并将 adr
字段设置为大于 0 的值是行不通的。
生成的代码(MethodDecl#toString
)有效:
public static java.lang.String test(java.lang.String arg) {
System.out.println("Running test method!");
return new java.lang.String("Hello!");
}
总结一下:在编译带有参数的生成方法时抛出 java.lang.AssertionError
,我不确定如何修复它。
实际上,Symbol
class 的 JavaDoc 告诉您 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.
它的默认值是 -1
,这基本上是 null
的基本类型等价物,所以你得到的是语义上(尽管不是技术上)的 NullPointerException
。您需要根据上述文档填写参数位置(可能还需要一些逆向工程,因为您使用的是内部API)。
我已经设法通过创建 MethodSymbol 来生成功能参数,将其与 TreeMaker::MethodDef(MethodSymbol, JCTree.JCBlock) 一起使用以创建新的 JCTree.JCMethodDecl,然后迭代它们通过参数将它们的 adr 设置为 0(这是被接受的,@Piotr Wilkin 提到的规范中没有任何内容让我相信这不应该有效)。
// maker is a TreeMaker instance
// sym is a Symbol.MethodSymbol instance
// body is a JCTree.JCBlock instance
JCTree.JCMethodDecl decl = maker.MethodDef(sym, body);
decl.params.forEach(p -> {
p.sym.adr = 0;
});
我想这是有效的原因,因为 javac 不会尝试创建新符号(因为已经存在),并且 VarSymbols(JCTree.JCVariableDecl 的符号字段)是可变的。此外,搜索 javac 代码表明几乎没有尝试覆盖它。
看了javac的源码,终于找到解决方法了
重点是sym.adr
的值是-1
,然后由newVar()
赋值:
// Flow$AssignAnalyzer
void newVar(JCVariableDecl varDecl) {
...
sym.adr = nextadr;
}
但是只有当 tree.sym
是 trackable
时 newVar()
才会被 visitVarDef()
调用:
// Flow$AssignAnalyzer
public void visitVarDef(JCVariableDecl tree) {
...
boolean track = trackable(tree.sym);
if (track && tree.sym.owner.kind == MTH) {
newVar(tree);
}
...
}
// Flow$AssignAnalyzer
protected boolean trackable(VarSymbol sym) {
return
sym.pos >= startPos &&
((sym.owner.kind == MTH ||
isFinalUninitializedField(sym)));
}
所以我们应该在生成我们的方法时确保sym.pos >= startPos
为真。
总之,我们应该在调用TreeMaker.MethodDef()
之前仔细设置TreeMaker.pos
,如下所示:
// ensure the current pos is valid
treeMaker.at(jcClassDecl.pos);
treeMaker.MethodDef(...);
以上解决方案都没有解决我的问题。
为了解决这个问题,我们需要使用TreeMaker.Param(),而不是TreeMaker.VarDef() .
这是对我有帮助的解决方案:
错误的解决方法:
return treeMaker.MethodDef(
modifiers,
elementUtils.getName(methodName),
treeMaker.Type(new Type.JCVoidType()),
List.nil(),
List.of(treeMaker.VarDef(treeMaker.Modifiers(0), paramName, treeMaker.Type(type), null)),
List.nil(),
body,
null
);
工作解决方案:
return treeMaker.MethodDef(
modifiers,
elementUtils.getName(methodName),
treeMaker.Type(new Type.JCVoidType()),
List.nil(),
List.of(treeMaker.Param(paramName, type, null)),
List.nil(),
body,
null
);
我遵循了@fashare2015 的想法。这是我的代码
public static JCTree.JCMethodDecl createSetMethod(JCTree.JCVariableDecl field) {
JCTree.JCFieldAccess thisX = TreeMaker.Select(TreeMaker.Ident(NameApi.fromString("this")), field.name);
JCTree.JCAssign assign = TreeMaker.Assign(thisX, TreeMaker.Ident(field.name));
JCTree.JCExpression methodType = TreeMaker.Type(new Type.JCVoidType());
JCTree.JCBlock methodBody = TreeMaker.Block(0, List.of(TreeMaker.Exec(assign)));
Name methodName = NameApi.fromString(StringUtils.generateMethodName("set", field.getName().toString()));
JCTree.JCVariableDecl param = TreeMaker.VarDef(TreeMaker.Modifiers(Flags.PARAMETER), field.name, field.vartype, null);
param.pos = field.pos; // <---- This lines I used
return TreeMaker.MethodDef(TreeMaker.Modifiers(Flags.PUBLIC), methodName, methodType,
List.nil(), List.of(param), List.nil(), methodBody, null);
}
我使用 JDK 版本 14。
你可以在这里拉取我的演示:link
我找到了解决办法:
在执行创建getter方法之前,添加这段代码:
treeMaker.pos = jcVariableDecl.pos;
例如:
//add this code ,redefine the position of parameters in the syntax tree:
treeMaker.pos = jcVariableDecl.pos;
treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC),
getNewMethodName(jcVariableDecl.getName(), "set"),
methodType,
List.nil(),
parameters,
List.nil(),
block,
null);
我正在使用带注释处理器的内部 sun API (com.sun.tools.javac
) 修改现有的 class。我可以使用以下代码生成 MethodDecl
并将其添加到 ClassDecl
:
JCTree.JCClassDecl classDecl = ...
JCTree.JCMethodDecl methodDecl = ...
JCTree[] trees = new JCTree[classDecl.defs.length() + 1];
trees[classDecl.defs.length()] = methodDecl;
classDecl.defs = List.from(trees);
在我尝试向方法声明中添加参数之前,它工作正常。我使用下面的代码生成一个新的 MethodDecl
:
Map<String, Class<?>> paramMap = ...
List<JCVariableDecl> parameters = List.from(paramMap.entrySet().stream()
.map(e -> treeMaker.VarDef(treeMaker.Modifiers(Flags.PARAMETER), elements.getName(e.getKey()), getType(e.getValue()), null))
.toArray(JCVariableDecl[]::new));
...
JCMethodDecl methodDecl = treeMaker.MethodDef(modifiers, methodName, returnType, genericParameters, parameters, throwables, methodBody, null);
我在编译时得到以下堆栈跟踪:
An exception has occurred in the compiler (9). Please file a bug against the Java compiler via the Java bug reporting page (http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com) for duplicates. Include your program and the following diagnostic in your report. Thank you.
java.lang.AssertionError
at jdk.compiler/com.sun.tools.javac.util.Assert.error(Assert.java:155)
at jdk.compiler/com.sun.tools.javac.util.Assert.check(Assert.java:46)
at jdk.compiler/com.sun.tools.javac.util.Bits.incl(Bits.java:186)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.initParam(Flow.java:1931)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.visitMethodDef(Flow.java:1880)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:866)
at jdk.compiler/com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
at jdk.compiler/com.sun.tools.javac.comp.Flow$BaseAnalyzer.scan(Flow.java:393)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.scan(Flow.java:1451)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.visitClassDef(Flow.java:1822)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:774)
at jdk.compiler/com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
at jdk.compiler/com.sun.tools.javac.comp.Flow$BaseAnalyzer.scan(Flow.java:393)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.scan(Flow.java:1451)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.analyzeTree(Flow.java:2521)
at jdk.compiler/com.sun.tools.javac.comp.Flow$AssignAnalyzer.analyzeTree(Flow.java:2504)
at jdk.compiler/com.sun.tools.javac.comp.Flow.analyzeTree(Flow.java:212)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1389)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1363)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:959)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall[=13=](JavacTaskImpl.java:100)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:142)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:96)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:90)
at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:49)
at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:36)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:99)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:52)
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:37)
at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:35)
at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:25)
at org.gradle.api.tasks.compile.JavaCompile.performCompilation(JavaCompile.java:204)
at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:189)
at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:121)
at jdk.internal.reflect.GeneratedMethodAccessor170.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$IncrementalTaskAction.doExecute(DefaultTaskClassInfoStore.java:179)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:135)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:122)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.run(ExecuteActionsTaskExecuter.java:121)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:110)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:92)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:70)
at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:97)
at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:87)
at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.run(DefaultTaskGraphExecuter.java:248)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:123)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access0(DefaultTaskPlanExecutor.java:79)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.execute(DefaultTaskPlanExecutor.java:104)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.execute(DefaultTaskPlanExecutor.java:98)
at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:625)
at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:580)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:98)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:59)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:128)
at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.access[=13=]0(DefaultBuildExecuter.java:23)
at org.gradle.execution.DefaultBuildExecuter.proceed(DefaultBuildExecuter.java:43)
at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:46)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
at org.gradle.initialization.DefaultGradleLauncher$ExecuteTasks.run(DefaultGradleLauncher.java:314)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
at org.gradle.initialization.DefaultGradleLauncher.runTasks(DefaultGradleLauncher.java:204)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:134)
at org.gradle.initialization.DefaultGradleLauncher.executeTasks(DefaultGradleLauncher.java:109)
at org.gradle.internal.invocation.GradleBuildController.call(GradleBuildController.java:78)
at org.gradle.internal.invocation.GradleBuildController.call(GradleBuildController.java:75)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:152)
at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:100)
at org.gradle.internal.invocation.GradleBuildController.run(GradleBuildController.java:75)
at org.gradle.tooling.internal.provider.runner.BuildModelActionRunner.run(BuildModelActionRunner.java:53)
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32)
at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:43)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:40)
at org.gradle.tooling.internal.provider.SubscribableBuildActionRunner.run(SubscribableBuildActionRunner.java:51)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:47)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:30)
at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:39)
at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:25)
at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:80)
at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:53)
at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:57)
at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:32)
at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:36)
at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:25)
at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:43)
at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:29)
at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:64)
at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:29)
at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:59)
at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:44)
at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:45)
at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:30)
at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:67)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput.call(ForwardClientInput.java:74)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput.call(ForwardClientInput.java:72)
at org.gradle.util.Swapper.swap(Swapper.java:38)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:62)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:82)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy.run(StartBuildOrRespondWithBusy.java:50)
at org.gradle.launcher.daemon.server.DaemonStateCoordinator.run(DaemonStateCoordinator.java:295)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl.run(ManagedExecutorImpl.java:46)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
at java.base/java.lang.Thread.run(Thread.java:844)
当我用 List.nil()
替换参数时,这段代码编译完美,这就是为什么我认为问题与参数有关。
抛出异常的代码如下:
public void incl(int x) {
Assert.check(currentState != BitsState.UNKNOWN);
Assert.check(x >= 0); // <-- this line
sizeTo((x >>> wordshift) + 1);
bits[x >>> wordshift] = bits[x >>> wordshift] |
(1 << (x & wordmask));
currentState = BitsState.NORMAL;
}
visitMethodDef
被调用(来自Flow
class):
//important part in method visitMethodDef
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);
}
调用 initParam
:
protected void initParam(JCVariableDecl def) {
inits.incl(def.sym.adr);
uninits.excl(def.sym.adr);
}
所以如果我理解正确的话,参数的 sym.adr
是 < 0。手动创建 Symbol
并将 adr
字段设置为大于 0 的值是行不通的。
生成的代码(MethodDecl#toString
)有效:
public static java.lang.String test(java.lang.String arg) {
System.out.println("Running test method!");
return new java.lang.String("Hello!");
}
总结一下:在编译带有参数的生成方法时抛出 java.lang.AssertionError
,我不确定如何修复它。
实际上,Symbol
class 的 JavaDoc 告诉您 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.
它的默认值是 -1
,这基本上是 null
的基本类型等价物,所以你得到的是语义上(尽管不是技术上)的 NullPointerException
。您需要根据上述文档填写参数位置(可能还需要一些逆向工程,因为您使用的是内部API)。
我已经设法通过创建 MethodSymbol 来生成功能参数,将其与 TreeMaker::MethodDef(MethodSymbol, JCTree.JCBlock) 一起使用以创建新的 JCTree.JCMethodDecl,然后迭代它们通过参数将它们的 adr 设置为 0(这是被接受的,@Piotr Wilkin 提到的规范中没有任何内容让我相信这不应该有效)。
// maker is a TreeMaker instance
// sym is a Symbol.MethodSymbol instance
// body is a JCTree.JCBlock instance
JCTree.JCMethodDecl decl = maker.MethodDef(sym, body);
decl.params.forEach(p -> {
p.sym.adr = 0;
});
我想这是有效的原因,因为 javac 不会尝试创建新符号(因为已经存在),并且 VarSymbols(JCTree.JCVariableDecl 的符号字段)是可变的。此外,搜索 javac 代码表明几乎没有尝试覆盖它。
看了javac的源码,终于找到解决方法了
重点是sym.adr
的值是-1
,然后由newVar()
赋值:
// Flow$AssignAnalyzer
void newVar(JCVariableDecl varDecl) {
...
sym.adr = nextadr;
}
但是只有当 tree.sym
是 trackable
时 newVar()
才会被 visitVarDef()
调用:
// Flow$AssignAnalyzer
public void visitVarDef(JCVariableDecl tree) {
...
boolean track = trackable(tree.sym);
if (track && tree.sym.owner.kind == MTH) {
newVar(tree);
}
...
}
// Flow$AssignAnalyzer
protected boolean trackable(VarSymbol sym) {
return
sym.pos >= startPos &&
((sym.owner.kind == MTH ||
isFinalUninitializedField(sym)));
}
所以我们应该在生成我们的方法时确保sym.pos >= startPos
为真。
总之,我们应该在调用TreeMaker.MethodDef()
之前仔细设置TreeMaker.pos
,如下所示:
// ensure the current pos is valid
treeMaker.at(jcClassDecl.pos);
treeMaker.MethodDef(...);
以上解决方案都没有解决我的问题。
为了解决这个问题,我们需要使用TreeMaker.Param(),而不是TreeMaker.VarDef() . 这是对我有帮助的解决方案:
错误的解决方法:
return treeMaker.MethodDef(
modifiers,
elementUtils.getName(methodName),
treeMaker.Type(new Type.JCVoidType()),
List.nil(),
List.of(treeMaker.VarDef(treeMaker.Modifiers(0), paramName, treeMaker.Type(type), null)),
List.nil(),
body,
null
);
工作解决方案:
return treeMaker.MethodDef(
modifiers,
elementUtils.getName(methodName),
treeMaker.Type(new Type.JCVoidType()),
List.nil(),
List.of(treeMaker.Param(paramName, type, null)),
List.nil(),
body,
null
);
我遵循了@fashare2015 的想法。这是我的代码
public static JCTree.JCMethodDecl createSetMethod(JCTree.JCVariableDecl field) {
JCTree.JCFieldAccess thisX = TreeMaker.Select(TreeMaker.Ident(NameApi.fromString("this")), field.name);
JCTree.JCAssign assign = TreeMaker.Assign(thisX, TreeMaker.Ident(field.name));
JCTree.JCExpression methodType = TreeMaker.Type(new Type.JCVoidType());
JCTree.JCBlock methodBody = TreeMaker.Block(0, List.of(TreeMaker.Exec(assign)));
Name methodName = NameApi.fromString(StringUtils.generateMethodName("set", field.getName().toString()));
JCTree.JCVariableDecl param = TreeMaker.VarDef(TreeMaker.Modifiers(Flags.PARAMETER), field.name, field.vartype, null);
param.pos = field.pos; // <---- This lines I used
return TreeMaker.MethodDef(TreeMaker.Modifiers(Flags.PUBLIC), methodName, methodType,
List.nil(), List.of(param), List.nil(), methodBody, null);
}
我使用 JDK 版本 14。
你可以在这里拉取我的演示:link
我找到了解决办法:
在执行创建getter方法之前,添加这段代码:
treeMaker.pos = jcVariableDecl.pos;
例如:
//add this code ,redefine the position of parameters in the syntax tree:
treeMaker.pos = jcVariableDecl.pos;
treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC),
getNewMethodName(jcVariableDecl.getName(), "set"),
methodType,
List.nil(),
parameters,
List.nil(),
block,
null);