/* * Copyright (c) 2017, 2018, 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 8193125 * @summary test modifiers with java.base * @library /tools/lib * @modules * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * jdk.jdeps/com.sun.tools.classfile * @build toolbox.ToolBox toolbox.JavacTask * @run main JavaBaseTest */ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import com.sun.tools.classfile.Attribute; import com.sun.tools.classfile.Attributes; import com.sun.tools.classfile.ClassFile; import com.sun.tools.classfile.ClassWriter; import com.sun.tools.classfile.Module_attribute; import toolbox.JavacTask; import toolbox.Task; import toolbox.Task.Expect; import toolbox.ToolBox; public class JavaBaseTest { public static void main(String... args) throws Exception { JavaBaseTest t = new JavaBaseTest(); t.run(); } final List> modifiers = List.of( List.of("static"), List.of("transitive"), List.of("static", "transitive") ); final String specVersion = System.getProperty("java.specification.version"); final List targets = specVersion.equals("10") ? List.of("9", "10") : List.of("9", "10", specVersion); enum Mode { SOURCE, CLASS }; ToolBox tb = new ToolBox(); int testCount = 0; int errorCount = 0; void run() throws Exception { for (List mods : modifiers) { for (String target : targets) { for (Mode mode : Mode.values()) { test(mods, target, mode); } } } System.err.println(testCount + " tests"); if (errorCount > 0) { throw new Exception(errorCount + " errors found"); } } void test(List mods, String target, Mode mode) { System.err.println("Test " + mods + " " + target + " " + mode); testCount++; try { Path base = Paths.get(String.join("-", mods)) .resolve(target).resolve(mode.name().toLowerCase()); Files.createDirectories(base); switch (mode) { case SOURCE: testSource(base, mods, target); break; case CLASS: testClass(base, mods, target); break; } } catch (Exception e) { error("Exception: " + e); e.printStackTrace(); } System.err.println(); } void testSource(Path base, List mods, String target) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { requires " + String.join(" ", mods) + " java.base; }"); Path modules = Files.createDirectories(base.resolve("modules")); boolean expectOK = target.equals("9"); String log = new JavacTask(tb) .outdir(modules) .options("-XDrawDiagnostics", "--release", target) .files(tb.findJavaFiles(src)) .run(expectOK ? Task.Expect.SUCCESS : Task.Expect.FAIL) .writeAll() .getOutput(Task.OutputKind.DIRECT); if (!expectOK) { boolean foundErrorMessage = false; for (String mod : mods) { String key = mod.equals("static") ? "compiler.err.mod.not.allowed.here" : "compiler.err.modifier.not.allowed.here"; String message = "module-info.java:1:12: " + key + ": " + mod; if (log.contains(message)) { foundErrorMessage = true; } } if (!foundErrorMessage) { throw new Exception("expected error message not found"); } } } void testClass(Path base, List mods, String target) throws Exception { createClass(base, mods, target); Path src = base.resolve("src"); tb.writeJavaFiles(src, "module mx { requires m; }"); Path modules = Files.createDirectories(base.resolve("modules")); boolean expectOK = target.equals("9"); String log = new JavacTask(tb) .outdir(modules) .options("-XDrawDiagnostics", "--module-path", base.resolve("test-modules").toString()) .files(tb.findJavaFiles(src)) .run(expectOK ? Task.Expect.SUCCESS : Task.Expect.FAIL) .writeAll() .getOutput(Task.OutputKind.DIRECT); if (!expectOK) { boolean foundErrorMessage = false; for (String mod : mods) { String flag = mod.equals("static") ? "ACC_STATIC_PHASE (0x0040)" : "ACC_TRANSITIVE (0x0020)"; String message = "- compiler.err.cant.access: m.module-info," + " (compiler.misc.bad.class.file.header: module-info.class," + " (compiler.misc.bad.requires.flag: " + flag + ")"; if (log.contains(message)) { foundErrorMessage = true; } } if (!foundErrorMessage) { throw new Exception("expected error message not found"); } } } void createClass(Path base, List mods, String target) throws Exception { Path src1 = base.resolve("interim-src"); tb.writeJavaFiles(src1, "module m { requires java.base; }"); Path modules1 = Files.createDirectories(base.resolve("interim-modules")); new JavacTask(tb) .outdir(modules1) .options("--release", target) .files(tb.findJavaFiles(src1)) .run(Task.Expect.SUCCESS) .writeAll(); ClassFile cf1 = ClassFile.read(modules1.resolve("module-info.class")); Map attrMap = new LinkedHashMap<>(cf1.attributes.map); Module_attribute modAttr1 = (Module_attribute) attrMap.get("Module"); Module_attribute.RequiresEntry[] requires = new Module_attribute.RequiresEntry[modAttr1.requires_count]; for (int i = 0; i < modAttr1.requires_count; i++) { Module_attribute.RequiresEntry e1 = modAttr1.requires[i]; int flags = e1.requires_flags; Module_attribute.RequiresEntry e2; if (e1.getRequires(cf1.constant_pool).equals("java.base")) { for (String mod : mods) { switch (mod) { case "static": flags |= Module_attribute.ACC_STATIC_PHASE; break; case "transitive": flags |= Module_attribute.ACC_TRANSITIVE; break; } } e2 = new Module_attribute.RequiresEntry( e1.requires_index, flags, e1.requires_version_index); } else { e2 = e1; } requires[i] = e2; } Module_attribute modAttr2 = new Module_attribute( modAttr1.attribute_name_index, modAttr1.module_name, modAttr1.module_flags, modAttr1.module_version_index, requires, modAttr1.exports, modAttr1.opens, modAttr1.uses_index, modAttr1.provides); attrMap.put("Module", modAttr2); Attributes attributes = new Attributes(attrMap); ClassFile cf2 = new ClassFile( cf1.magic, cf1.minor_version, cf1.major_version, cf1.constant_pool, cf1.access_flags, cf1.this_class, cf1.super_class, cf1.interfaces, cf1.fields, cf1.methods, attributes); Path modInfo = base.resolve("test-modules").resolve("module-info.class"); Files.createDirectories(modInfo.getParent()); new ClassWriter().write(cf2, modInfo.toFile()); } private void error(String message) { System.err.println("Error: " + message); errorCount++; } }