1 /* 2 * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8308590 27 * @summary Test basic modeling for value classes 28 * @library /tools/lib /tools/javac/lib 29 * @modules 30 * jdk.compiler/com.sun.tools.javac.api 31 * jdk.compiler/com.sun.tools.javac.main 32 * @build toolbox.ToolBox toolbox.JavacTask JavacTestingAbstractProcessor 33 * @run main TestValueClasses 34 */ 35 36 import java.io.*; 37 import java.nio.file.Files; 38 import java.nio.file.Path; 39 import java.nio.file.Paths; 40 import java.util.*; 41 42 import javax.annotation.processing.*; 43 import javax.lang.model.*; 44 import javax.lang.model.element.*; 45 import javax.lang.model.type.*; 46 import javax.lang.model.util.*; 47 import java.time.*; 48 49 import toolbox.JavacTask; 50 import toolbox.Task; 51 import toolbox.Task.Mode; 52 import toolbox.Task.OutputKind; 53 import toolbox.TestRunner; 54 import toolbox.ToolBox; 55 56 public class TestValueClasses extends TestRunner { 57 58 protected ToolBox tb; 59 60 TestValueClasses() { 61 super(System.err); 62 tb = new ToolBox(); 63 } 64 65 public static void main(String... args) throws Exception { 66 new TestValueClasses().runTests(); 67 } 68 69 /** 70 * Run all methods annotated with @Test, and throw an exception if any 71 * errors are reported.. 72 * 73 * @throws Exception if any errors occurred 74 */ 75 protected void runTests() throws Exception { 76 runTests(m -> new Object[] { Paths.get(m.getName()) }); 77 } 78 79 Path[] findJavaFiles(Path... paths) throws IOException { 80 return tb.findJavaFiles(paths); 81 } 82 83 void checkOutputContains(String log, String... expect) throws Exception { 84 for (String e : expect) { 85 if (!log.contains(e)) { 86 throw new Exception("expected output not found: " + e); 87 } 88 } 89 } 90 91 @Test 92 public void testValueClassesProcessor(Path base) throws Exception { 93 Path src = base.resolve("src"); 94 Path r = src.resolve("Test"); 95 96 Path classes = base.resolve("classes"); 97 98 Files.createDirectories(classes); 99 100 tb.writeJavaFiles(r, 101 """ 102 interface Interface {} 103 104 value class ValueClass {} 105 106 class IdentityClass {} 107 108 value record ValueRecord() {} 109 """ 110 ); 111 112 List<String> expected = List.of( 113 "- compiler.note.proc.messager: visiting: Interface Modifiers: [abstract]", 114 "- compiler.note.proc.messager: visiting: ValueClass Modifiers: [value, final]", 115 "- compiler.note.proc.messager: constructor modifiers: []", 116 "- compiler.note.proc.messager: visiting: IdentityClass Modifiers: []", 117 "- compiler.note.proc.messager: constructor modifiers: []", 118 "- compiler.note.proc.messager: visiting: ValueRecord Modifiers: [value, final]", 119 "- compiler.note.proc.messager: constructor modifiers: []", 120 "- compiler.note.preview.filename: Interface.java, DEFAULT", 121 "- compiler.note.preview.recompile" 122 ); 123 124 for (Mode mode : new Mode[] {Mode.API}) { 125 List<String> log = new JavacTask(tb, mode) 126 .options("--enable-preview", "-source", String.valueOf(Runtime.version().feature()), "-processor", ValueClassesProcessor.class.getName(), 127 "-XDrawDiagnostics") 128 .files(findJavaFiles(src)) 129 .outdir(classes) 130 .run() 131 .writeAll() 132 .getOutputLines(Task.OutputKind.DIRECT); 133 134 System.out.println("log:" +log); 135 136 if (!expected.equals(log)) { 137 if (expected.size() == log.size()) { 138 for (int i = 0; i < expected.size(); i++) { 139 if (!expected.get(i).equals(log.get(i))) { 140 System.err.println("failing at line " + (i + 1)); 141 System.err.println(" expecting " + expected.get(i)); 142 System.err.println(" found " + log.get(i)); 143 } 144 } 145 } else { 146 System.err.println("expected and log lists differ in length"); 147 } 148 throw new AssertionError("Unexpected output: " + log); 149 } 150 } 151 } 152 153 public static final class ValueClassesProcessor extends JavacTestingAbstractProcessor { 154 155 @Override 156 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 157 if (!roundEnv.processingOver()) { 158 Messager messager = processingEnv.getMessager(); 159 ElementScanner scanner = new ValueClassesScanner(messager); 160 for(Element rootElement : roundEnv.getRootElements()) { 161 scanner.visit(rootElement); 162 } 163 } 164 return true; 165 } 166 167 class ValueClassesScanner extends ElementScanner<Void, Void> { 168 169 Messager messager; 170 171 public ValueClassesScanner(Messager messager) { 172 this.messager = messager; 173 } 174 175 @Override 176 public Void visitType(TypeElement element, Void p) { 177 messager.printNote("visiting: " + element.getSimpleName() + " Modifiers: " + element.getModifiers()); 178 List<? extends Element> enclosedElements = element.getEnclosedElements(); 179 for (Element elem : enclosedElements) { 180 System.out.println("visiting " + elem.getSimpleName()); 181 switch (elem.getSimpleName().toString()) { 182 case "<init>": 183 messager.printNote(" constructor modifiers: " + elem.getModifiers()); 184 break; 185 default: 186 break; 187 } 188 } 189 return super.visitType(element, p); 190 } 191 } 192 } 193 }