8336777: BufferedMethodBuilder not initialized with static flag

Reviewed-by: asotona
This commit is contained in:
Chen Liang 2024-07-19 21:25:20 +00:00
parent c25c4896ad
commit 3ade2b6114
6 changed files with 102 additions and 11 deletions

@ -25,6 +25,7 @@
package jdk.internal.classfile.impl;
import java.lang.constant.MethodTypeDesc;
import java.lang.reflect.AccessFlag;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@ -44,7 +45,7 @@ import java.lang.classfile.MethodModel;
import java.lang.classfile.constantpool.Utf8Entry;
public final class BufferedMethodBuilder
implements TerminalMethodBuilder, MethodInfo {
implements TerminalMethodBuilder {
private final List<MethodElement> elements;
private final SplitConstantPool constantPool;
private final ClassFileImpl context;
@ -59,23 +60,32 @@ public final class BufferedMethodBuilder
ClassFileImpl context,
Utf8Entry nameInfo,
Utf8Entry typeInfo,
int flags,
MethodModel original) {
this.elements = new ArrayList<>();
this.constantPool = constantPool;
this.context = context;
this.name = nameInfo;
this.desc = typeInfo;
this.flags = AccessFlags.ofMethod();
this.flags = AccessFlags.ofMethod(flags);
this.original = original;
}
@Override
public MethodBuilder with(MethodElement element) {
elements.add(element);
if (element instanceof AccessFlags f) this.flags = f;
if (element instanceof AccessFlags f) this.flags = checkFlags(f);
return this;
}
private AccessFlags checkFlags(AccessFlags updated) {
boolean wasStatic = updated.has(AccessFlag.STATIC);
boolean isStatic = flags.has(AccessFlag.STATIC);
if (wasStatic != isStatic)
throw new IllegalArgumentException("Cannot change ACC_STATIC flag of method");
return updated;
}
@Override
public ConstantPoolBuilder constantPool() {
return constantPool;

@ -79,7 +79,7 @@ public final class ChainedClassBuilder
public ClassBuilder withMethod(Utf8Entry name, Utf8Entry descriptor, int flags,
Consumer<? super MethodBuilder> handler) {
consumer.accept(new BufferedMethodBuilder(terminal.constantPool, terminal.context,
name, descriptor, null)
name, descriptor, flags, null)
.run(handler)
.toModel());
return this;
@ -88,7 +88,7 @@ public final class ChainedClassBuilder
@Override
public ClassBuilder transformMethod(MethodModel method, MethodTransform transform) {
BufferedMethodBuilder builder = new BufferedMethodBuilder(terminal.constantPool, terminal.context,
method.methodName(), method.methodType(), method);
method.methodName(), method.methodType(), method.flags().flagsMask(), method);
builder.transform(method, transform);
consumer.accept(builder.toModel());
return this;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -42,7 +42,7 @@ import java.lang.classfile.constantpool.Utf8Entry;
public final class DirectMethodBuilder
extends AbstractDirectBuilder<MethodModel>
implements TerminalMethodBuilder, WritableElement<MethodModel>, MethodInfo {
implements TerminalMethodBuilder, WritableElement<MethodModel> {
final Utf8Entry name;
final Utf8Entry desc;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,7 +29,8 @@ import java.lang.classfile.constantpool.Utf8Entry;
import static java.lang.classfile.ClassFile.ACC_STATIC;
public interface MethodInfo {
public sealed interface MethodInfo
permits MethodImpl, TerminalMethodBuilder, BufferedMethodBuilder.Model {
Utf8Entry methodName();
Utf8Entry methodType();
MethodTypeDesc methodTypeSymbol();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,7 +28,7 @@ import java.lang.classfile.CodeModel;
import java.lang.classfile.MethodBuilder;
public sealed interface TerminalMethodBuilder
extends MethodBuilder
extends MethodBuilder, MethodInfo
permits BufferedMethodBuilder, DirectMethodBuilder {
BufferedCodeBuilder bufferedCodeBuilder(CodeModel original);
}

@ -0,0 +1,80 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import jdk.internal.classfile.impl.ChainedClassBuilder;
import org.junit.jupiter.api.Test;
import java.lang.classfile.ClassBuilder;
import java.lang.classfile.ClassElement;
import java.lang.classfile.ClassFile;
import java.lang.classfile.ClassTransform;
import java.lang.constant.ClassDesc;
import static java.lang.classfile.ClassFile.ACC_PUBLIC;
import static java.lang.classfile.ClassFile.ACC_STATIC;
import static java.lang.constant.ConstantDescs.MTD_void;
import static org.junit.jupiter.api.Assertions.*;
/*
* @test
* @bug 8336777
* @summary Testing MethodBuilder correctly rejecting resetting the static
* access flag.
* @run junit MethodBuilderStaticFlagTest
*/
class MethodBuilderStaticFlagTest {
void testClassBuilder(ClassBuilder clb) {
clb.withMethod("staticToStatic", MTD_void, ACC_STATIC, mb -> mb.withFlags(ACC_PUBLIC | ACC_STATIC));
assertThrows(IllegalArgumentException.class, () ->
clb.withMethod("staticToInstance", MTD_void, ACC_STATIC, mb -> mb.withFlags(ACC_PUBLIC)));
assertThrows(IllegalArgumentException.class, () ->
clb.withMethod("instanceToStatic", MTD_void, 0, mb -> mb.withFlags(ACC_PUBLIC | ACC_STATIC)));
clb.withMethod("instanceToInstance", MTD_void, 0, mb -> mb.withFlags(ACC_PUBLIC));
}
@Test
void testDirectBuilder() {
ClassFile.of().build(ClassDesc.of("C1"), this::testClassBuilder);
}
@Test
void testBufferedBuilder() {
var cf = ClassFile.of();
var bytes = cf.build(ClassDesc.of("C2"), _ -> {});
var cm = cf.parse(bytes);
cf.transformClass(cm, new ClassTransform() {
@Override
public void accept(ClassBuilder builder, ClassElement element) {
builder.with(element);
}
@Override
public void atEnd(ClassBuilder clb) {
assertInstanceOf(ChainedClassBuilder.class, clb);
testClassBuilder(clb);
}
}.andThen(ClassBuilder::with));
}
}