5e822c24bb
Reviewed-by: vromero
700 lines
27 KiB
Java
700 lines
27 KiB
Java
/*
|
|
* 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.
|
|
*/
|
|
|
|
/**
|
|
* @test
|
|
* @bug 8024694 8334870
|
|
* @summary Check javac can handle various Runtime(In)VisibleParameterAnnotations attribute combinations
|
|
* @enablePreview
|
|
* @library /tools/lib
|
|
* @modules jdk.compiler/com.sun.tools.javac.api
|
|
* jdk.compiler/com.sun.tools.javac.main
|
|
* jdk.compiler/com.sun.tools.javac.util
|
|
* @build toolbox.ToolBox toolbox.JavacTask
|
|
* @run main ParameterAnnotations
|
|
*/
|
|
|
|
import java.io.OutputStream;
|
|
import java.lang.classfile.ClassFile;
|
|
import java.lang.classfile.ClassModel;
|
|
import java.lang.classfile.ClassTransform;
|
|
import java.lang.classfile.MethodBuilder;
|
|
import java.lang.classfile.MethodElement;
|
|
import java.lang.classfile.MethodTransform;
|
|
import java.lang.classfile.attribute.MethodParametersAttribute;
|
|
import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute;
|
|
import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute;
|
|
import java.lang.classfile.attribute.SignatureAttribute;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.Paths;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.stream.Collectors;
|
|
import javax.annotation.processing.AbstractProcessor;
|
|
import javax.annotation.processing.RoundEnvironment;
|
|
import javax.annotation.processing.SupportedAnnotationTypes;
|
|
import javax.lang.model.SourceVersion;
|
|
import javax.lang.model.element.ExecutableElement;
|
|
import javax.lang.model.element.TypeElement;
|
|
import javax.lang.model.element.VariableElement;
|
|
import javax.lang.model.util.ElementFilter;
|
|
|
|
import toolbox.TestRunner;
|
|
import toolbox.JavacTask;
|
|
import toolbox.Task;
|
|
import toolbox.ToolBox;
|
|
|
|
public class ParameterAnnotations extends TestRunner {
|
|
|
|
ToolBox tb;
|
|
|
|
public static void main(String... args) throws Exception {
|
|
new ParameterAnnotations().runTests();
|
|
}
|
|
|
|
ParameterAnnotations() {
|
|
super(System.err);
|
|
tb = new ToolBox();
|
|
}
|
|
|
|
public void runTests() throws Exception {
|
|
runTests(m -> new Object[] { Paths.get(m.getName()) });
|
|
}
|
|
|
|
@Test
|
|
public void testEnum(Path base) throws Exception {
|
|
//not parameterized:
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public enum E {
|
|
A(0);
|
|
E(@Visible @Invisible long i) {}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"E",
|
|
MethodTransform.ACCEPT_ALL,
|
|
"@Invisible @Visible long");
|
|
//parameterized:
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public enum E {
|
|
A(0);
|
|
<T> E(@Visible @Invisible long i) {}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"E",
|
|
MethodTransform.ACCEPT_ALL,
|
|
"@Invisible @Visible long");
|
|
//not parameterized, and no Signature attribute:
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public enum E {
|
|
A(0);
|
|
E(@Visible @Invisible long i) {}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"E",
|
|
NO_SIGNATURE,
|
|
"java.lang.String, int, @Invisible @Visible long");
|
|
//not parameterized, and no Signature and MethodParameters attribute:
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public enum E {
|
|
A(0);
|
|
E(@Visible @Invisible long i) {}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"E",
|
|
NO_SIGNATURE_NO_METHOD_PARAMETERS,
|
|
"java.lang.String, int, @Invisible @Visible long");
|
|
}
|
|
|
|
@Test
|
|
public void testInnerClass(Path base) throws Exception {
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
public class I {
|
|
public I(@Visible @Invisible long l) {}
|
|
public String toString() {
|
|
return T.this.toString(); //force outer this capture
|
|
}
|
|
}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T$I",
|
|
MethodTransform.ACCEPT_ALL,
|
|
"@Invisible @Visible long");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
public class I {
|
|
public <T> I(@Visible @Invisible long l) {}
|
|
public String toString() {
|
|
return T.this.toString(); //force outer this capture
|
|
}
|
|
}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T$I",
|
|
MethodTransform.ACCEPT_ALL,
|
|
"@Invisible @Visible long");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
public class I {
|
|
public I(@Visible @Invisible long l) {}
|
|
public String toString() {
|
|
return T.this.toString(); //force outer this capture
|
|
}
|
|
}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T$I",
|
|
NO_SIGNATURE,
|
|
"@Invisible @Visible long");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
public class I {
|
|
public I(@Visible @Invisible long l) {}
|
|
public String toString() {
|
|
return T.this.toString(); //force outer this capture
|
|
}
|
|
}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T$I",
|
|
NO_SIGNATURE_NO_METHOD_PARAMETERS,
|
|
"@Invisible @Visible long");
|
|
}
|
|
|
|
@Test
|
|
public void testCapturingLocal(Path base) throws Exception {
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
public void test(int i) {
|
|
class I {
|
|
public I(@Visible @Invisible long l) {}
|
|
public String toString() {
|
|
return T.this.toString() + i; //force outer this capture
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T$1I",
|
|
MethodTransform.ACCEPT_ALL,
|
|
"@Invisible @Visible long");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
public void test(int i) {
|
|
class I {
|
|
public <T> I(@Visible @Invisible long l) {}
|
|
public String toString() {
|
|
return T.this.toString() + i; //force outer this capture
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T$1I",
|
|
MethodTransform.ACCEPT_ALL,
|
|
"@Invisible @Visible long");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
public void test(int i) {
|
|
class I {
|
|
public I(@Visible @Invisible long l) {}
|
|
public String toString() {
|
|
return T.this.toString() + i; //force outer this capture
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T$1I",
|
|
NO_SIGNATURE,
|
|
"T, @Invisible @Visible long, int");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
public void test(int i) {
|
|
class I {
|
|
public I(@Visible @Invisible long l) {}
|
|
public String toString() {
|
|
return T.this.toString() + i; //force outer this capture
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T$1I",
|
|
NO_SIGNATURE_NO_METHOD_PARAMETERS,
|
|
"T, @Invisible @Visible long, int");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
{
|
|
int i = 0;
|
|
class I {
|
|
public I(@Visible @Invisible long l) {}
|
|
public String toString() {
|
|
return T.this.toString() + i; //force outer this capture
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T$1I",
|
|
MethodTransform.ACCEPT_ALL,
|
|
"@Invisible @Visible long");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
{
|
|
int i = 0;
|
|
class I {
|
|
public <T> I(@Visible @Invisible long l) {}
|
|
public String toString() {
|
|
return T.this.toString() + i; //force outer this capture
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T$1I",
|
|
MethodTransform.ACCEPT_ALL,
|
|
"@Invisible @Visible long");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
{
|
|
int i = 0;
|
|
class I {
|
|
public I(@Visible @Invisible long l) {}
|
|
public String toString() {
|
|
return T.this.toString() + i; //force outer this capture
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T$1I",
|
|
NO_SIGNATURE,
|
|
"T, @Invisible @Visible long, int");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
{
|
|
int i = 0;
|
|
class I {
|
|
public I(@Visible @Invisible long l) {}
|
|
public String toString() {
|
|
return T.this.toString() + i; //force outer this capture
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T$1I",
|
|
NO_SIGNATURE_NO_METHOD_PARAMETERS,
|
|
"T, @Invisible @Visible long, int");
|
|
}
|
|
|
|
@Test
|
|
public void testSyntheticTests(Path base) throws Exception {
|
|
//Signature attribute will defined one parameter, but the
|
|
//Runtime(In)VisibleParameterAnnotations will define 3 parameters:
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
public void test(int i) {
|
|
class I {
|
|
public I(@Visible @Invisible long l) {}
|
|
public String toString() {
|
|
return T.this.toString() + i; //force outer this capture
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T$1I",
|
|
new MethodTransform() {
|
|
@Override
|
|
public void accept(MethodBuilder builder, MethodElement element) {
|
|
if (element instanceof RuntimeInvisibleParameterAnnotationsAttribute annos) {
|
|
assert annos.parameterAnnotations().size() == 1;
|
|
builder.accept(RuntimeInvisibleParameterAnnotationsAttribute.of(List.of(List.of(), annos.parameterAnnotations().get(0), List.of())));
|
|
} else if (element instanceof RuntimeVisibleParameterAnnotationsAttribute annos) {
|
|
assert annos.parameterAnnotations().size() == 1;
|
|
builder.accept(RuntimeVisibleParameterAnnotationsAttribute.of(List.of(List.of(), annos.parameterAnnotations().get(0), List.of())));
|
|
} else {
|
|
builder.accept(element);
|
|
}
|
|
}
|
|
},
|
|
"@Invisible @Visible long");
|
|
//no Signature attribute, no synthetic parameters,
|
|
//but less entries in Runtime(In)VisibleParameterAnnotations than parameters
|
|
//no way to map anything:
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
public T(int i, @Visible @Invisible long l, String s) {}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T",
|
|
new MethodTransform() {
|
|
@Override
|
|
public void accept(MethodBuilder builder, MethodElement element) {
|
|
if (element instanceof RuntimeInvisibleParameterAnnotationsAttribute annos) {
|
|
assert annos.parameterAnnotations().size() == 3;
|
|
builder.accept(RuntimeInvisibleParameterAnnotationsAttribute.of(List.of(annos.parameterAnnotations().get(1))));
|
|
} else if (element instanceof RuntimeVisibleParameterAnnotationsAttribute annos) {
|
|
assert annos.parameterAnnotations().size() == 3;
|
|
builder.accept(RuntimeVisibleParameterAnnotationsAttribute.of(List.of(annos.parameterAnnotations().get(1))));
|
|
} else {
|
|
builder.accept(element);
|
|
}
|
|
}
|
|
},
|
|
"int, long, java.lang.String",
|
|
"- compiler.warn.runtime.invisible.parameter.annotations: T.class",
|
|
"1 warning");
|
|
//no Signature attribute, no synthetic parameters,
|
|
//but more entries in Runtime(In)VisibleParameterAnnotations than parameters
|
|
//no way to map anything:
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
public T(@Visible @Invisible long l) {}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T",
|
|
new MethodTransform() {
|
|
@Override
|
|
public void accept(MethodBuilder builder, MethodElement element) {
|
|
if (element instanceof RuntimeInvisibleParameterAnnotationsAttribute annos) {
|
|
assert annos.parameterAnnotations().size() == 1;
|
|
builder.accept(RuntimeInvisibleParameterAnnotationsAttribute.of(List.of(List.of(), annos.parameterAnnotations().get(0), List.of())));
|
|
} else if (element instanceof RuntimeVisibleParameterAnnotationsAttribute annos) {
|
|
assert annos.parameterAnnotations().size() == 1;
|
|
builder.accept(RuntimeVisibleParameterAnnotationsAttribute.of(List.of(List.of(), annos.parameterAnnotations().get(0), List.of())));
|
|
} else {
|
|
builder.accept(element);
|
|
}
|
|
}
|
|
},
|
|
"long",
|
|
"- compiler.warn.runtime.invisible.parameter.annotations: T.class",
|
|
"1 warning");
|
|
//mismatched lengths on RuntimeVisibleParameterAnnotations and
|
|
//RuntimeInvisibleParameterAnnotations:
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public class T {
|
|
public T(@Visible @Invisible long l) {}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"T",
|
|
new MethodTransform() {
|
|
@Override
|
|
public void accept(MethodBuilder builder, MethodElement element) {
|
|
if (element instanceof RuntimeInvisibleParameterAnnotationsAttribute annos) {
|
|
assert annos.parameterAnnotations().size() == 1;
|
|
builder.accept(annos); //keep intact
|
|
} else if (element instanceof RuntimeVisibleParameterAnnotationsAttribute annos) {
|
|
assert annos.parameterAnnotations().size() == 1;
|
|
builder.accept(RuntimeVisibleParameterAnnotationsAttribute.of(List.of(List.of(), annos.parameterAnnotations().get(0), List.of())));
|
|
} else {
|
|
builder.accept(element);
|
|
}
|
|
}
|
|
},
|
|
"long",
|
|
"- compiler.warn.runtime.visible.invisible.param.annotations.mismatch: T.class",
|
|
"1 warning");
|
|
}
|
|
|
|
@Test
|
|
public void testRecord(Path base) throws Exception {
|
|
//implicit constructor:
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public record R(int i, @Visible @Invisible long l, String s) {
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"R",
|
|
MethodTransform.ACCEPT_ALL,
|
|
"int, @Invisible @Visible long, java.lang.String");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public record R(int i, @Visible @Invisible long l, String s) {
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"R",
|
|
NO_SIGNATURE,
|
|
"int, @Invisible @Visible long, java.lang.String");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public record R(int i, @Visible @Invisible long l, String s) {
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"R",
|
|
NO_SIGNATURE_NO_METHOD_PARAMETERS,
|
|
"int, @Invisible @Visible long, java.lang.String");
|
|
//compact constructor:
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public record R(int i, @Visible @Invisible long l, String s) {
|
|
public R {}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"R",
|
|
MethodTransform.ACCEPT_ALL,
|
|
"int, @Invisible @Visible long, java.lang.String");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public record R(int i, @Visible @Invisible long l, String s) {
|
|
public R {}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"R",
|
|
NO_SIGNATURE,
|
|
"int, @Invisible @Visible long, java.lang.String");
|
|
doTest(base,
|
|
"""
|
|
import java.lang.annotation.*;
|
|
public record R(int i, @Visible @Invisible long l, String s) {
|
|
public R {}
|
|
}
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface Visible {}
|
|
@interface Invisible {}
|
|
""",
|
|
"R",
|
|
NO_SIGNATURE_NO_METHOD_PARAMETERS,
|
|
"int, @Invisible @Visible long, java.lang.String");
|
|
}
|
|
|
|
private MethodTransform NO_SIGNATURE =
|
|
MethodTransform.dropping(element -> element instanceof SignatureAttribute);
|
|
|
|
private MethodTransform NO_SIGNATURE_NO_METHOD_PARAMETERS =
|
|
MethodTransform.dropping(element -> element instanceof SignatureAttribute ||
|
|
element instanceof MethodParametersAttribute);
|
|
|
|
private void doTest(Path base, String code, String binaryNameToCheck,
|
|
MethodTransform changeConstructor, String expectedOutput,
|
|
String... expectedDiagnostics) throws Exception {
|
|
Path current = base.resolve(".");
|
|
Path src = current.resolve("src");
|
|
Path classes = current.resolve("classes");
|
|
tb.writeJavaFiles(src, code);
|
|
|
|
Files.createDirectories(classes);
|
|
|
|
new JavacTask(tb)
|
|
.outdir(classes)
|
|
.files(tb.findJavaFiles(src))
|
|
.run(Task.Expect.SUCCESS)
|
|
.writeAll();
|
|
|
|
Path classfile = classes.resolve(binaryNameToCheck + ".class");
|
|
ClassFile cf = ClassFile.of();
|
|
|
|
ClassModel model = cf.parse(classfile);
|
|
|
|
byte[] newClassFile = cf.transformClass(model,
|
|
ClassTransform.transformingMethods(m -> m.methodName()
|
|
.equalsString("<init>"),
|
|
changeConstructor));
|
|
|
|
try (OutputStream out = Files.newOutputStream(classfile)) {
|
|
out.write(newClassFile);
|
|
}
|
|
|
|
Task.Result result = new JavacTask(tb)
|
|
.options("-classpath", classes.toString(),
|
|
"-processor", TestAP.class.getName(),
|
|
"-XDrawDiagnostics",
|
|
"-Xlint:classfile")
|
|
.outdir(classes)
|
|
.classes(binaryNameToCheck)
|
|
.run(Task.Expect.SUCCESS)
|
|
.writeAll();
|
|
List<String> out = result.getOutputLines(Task.OutputKind.STDOUT);
|
|
if (!out.equals(List.of(expectedOutput))) {
|
|
throw new AssertionError("Expected: " + List.of(expectedOutput) + ", but got: " + out);
|
|
}
|
|
List<String> diagnostics =
|
|
new ArrayList<>(result.getOutputLines(Task.OutputKind.DIRECT));
|
|
diagnostics.remove("");
|
|
if (!diagnostics.equals(List.of(expectedDiagnostics))) {
|
|
throw new AssertionError("Expected: " + List.of(expectedDiagnostics) + ", but got: " + diagnostics);
|
|
}
|
|
}
|
|
|
|
@SupportedAnnotationTypes("*")
|
|
public static final class TestAP extends AbstractProcessor {
|
|
|
|
@Override
|
|
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
|
for (TypeElement clazz : ElementFilter.typesIn(roundEnv.getRootElements())) {
|
|
for (ExecutableElement el : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
|
|
String sep = "";
|
|
|
|
for (VariableElement p : el.getParameters()) {
|
|
System.out.print(sep);
|
|
if (!p.getAnnotationMirrors().isEmpty()) {
|
|
System.out.print(p.getAnnotationMirrors()
|
|
.stream()
|
|
.map(m -> m.toString())
|
|
.collect(Collectors.joining(" ")));
|
|
System.out.print(" ");
|
|
}
|
|
System.out.print(p.asType());
|
|
sep = ", ";
|
|
}
|
|
|
|
System.out.println();
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public SourceVersion getSupportedSourceVersion() {
|
|
return SourceVersion.latest();
|
|
}
|
|
|
|
}
|
|
}
|