diff options
6 files changed, 127 insertions, 4 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java index bdbb120e13..cddbcf6388 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java @@ -31,8 +31,14 @@ import java.util.List; import java.util.Set; import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.ToolFactory; +import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.tests.util.Util; +import org.eclipse.jdt.core.util.IClassFileAttribute; +import org.eclipse.jdt.core.util.IClassFileReader; +import org.eclipse.jdt.core.util.IModuleAttribute; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.codegen.AttributeNamesConstants; import junit.framework.AssertionFailedError; import junit.framework.Test; @@ -5312,4 +5318,79 @@ public void testBug521362_emptyFile() { false, "unnamed package is not allowed in named modules"); } + public void testBug548195() { + File outputDirectory = new File(OUTPUT_DIR); + Util.flushDirectoryContent(outputDirectory); + String out = "bin"; + String directory = OUTPUT_DIR + File.separator + "src"; + String moduleLoc = directory + File.separator + "mod.one"; + List<String> files = new ArrayList<>(); + writeFileCollecting(files, moduleLoc, "module-info.java", + "module mod.one { \n" + + " exports p;\n" + + "}"); + writeFileCollecting(files, moduleLoc + File.separator + "p", "X.java", + "package p;\n" + + "public class X {\n" + + "}"); + + StringBuffer buffer = new StringBuffer(); + String binDir = OUTPUT_DIR + File.separator + out; + buffer.append("-d " + binDir ) + .append(" -9 ") + .append(" -classpath \"") + .append(Util.getJavaClassLibsAsString()) + .append("\" ") + .append(" -warn:-unused") + .append(" --module-source-path " + "\"" + directory + "\" ") + .append(" --module-version 47.11 "); + String outText = isJRE9Plus ? "" : "Could not invoke method java.lang.module.ModuleDescriptor.Version.parse(), cannot validate module version.\n"; + runConformModuleTest(files, buffer, outText, "", false); + + IClassFileReader cfr = ToolFactory.createDefaultClassFileReader(binDir + File.separator + "mod.one" + File.separator + "module-info.class", IClassFileReader.CLASSFILE_ATTRIBUTES); + assertNotNull("Error reading module-info.class", cfr); + IClassFileAttribute[] attrs = cfr.getAttributes(); + for (IClassFileAttribute attr : attrs) { + char[] name = attr.getAttributeName(); + if (CharOperation.equals(name, AttributeNamesConstants.ModuleName)) { + IModuleAttribute modAttr = (IModuleAttribute) attr; + String expectedVersion = isJRE9Plus ? "47.11" : ""; + assertEquals("version in attribute", expectedVersion, new String(modAttr.getModuleVersionValue())); + return; + } + } + fail("module attribute not found"); + } + public void testBug548195fail() { + File outputDirectory = new File(OUTPUT_DIR); + Util.flushDirectoryContent(outputDirectory); + String out = "bin"; + String directory = OUTPUT_DIR + File.separator + "src"; + String moduleLoc = directory + File.separator + "mod.one"; + List<String> files = new ArrayList<>(); + writeFileCollecting(files, moduleLoc, "module-info.java", + "module mod.one { \n" + + " exports p;\n" + + "}"); + writeFileCollecting(files, moduleLoc + File.separator + "p", "X.java", + "package p;\n" + + "public class X {\n" + + "}"); + + StringBuffer buffer = new StringBuffer(); + String binDir = OUTPUT_DIR + File.separator + out; + buffer.append("-d " + binDir ) + .append(" -9 ") + .append(" -classpath \"") + .append(Util.getJavaClassLibsAsString()) + .append("\" ") + .append(" -warn:-unused") + .append(" --module-source-path " + "\"" + directory + "\" ") + .append(" --module-version fourtyseven.11 "); + if (isJRE9Plus) { + runNegativeModuleTest(files, buffer, "", "fourtyseven.11: Version string does not start with a number\n", false, "bad value"); + } else { + runConformModuleTest(files, buffer, "Could not invoke method java.lang.module.ModuleDescriptor.Version.parse(), cannot validate module version.\n", "", false); + } + } } diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java index 5c3b70291f..7a74db1569 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -49,6 +49,8 @@ import java.io.StringReader; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.nio.file.Path; import java.nio.file.Paths; import java.text.DateFormat; @@ -1367,6 +1369,7 @@ public class Main implements ProblemSeverities, SuffixConstants { protected FileSystem.Classpath[] checkedClasspaths; // For single module mode protected IModule module; + private String moduleVersion; // paths to external annotations: protected List<String> annotationPaths; protected boolean annotationsFromClasspath; @@ -1440,6 +1443,7 @@ public class Main implements ProblemSeverities, SuffixConstants { private PrintWriter err; protected ArrayList<CategorizedProblem> extraProblems; + public final static String bundleName = "org.eclipse.jdt.internal.compiler.batch.messages"; //$NON-NLS-1$ // two uses: recognize 'none' in options; code the singleton none // for the '-d none' option (wherever it may be found) @@ -1842,6 +1846,7 @@ public void configure(String[] argv) { final int INSIDE_ADD_MODULES = 29; final int INSIDE_RELEASE = 30; final int INSIDE_LIMIT_MODULES = 31; + final int INSIDE_MODULE_VERSION = 32; final int DEFAULT = 0; ArrayList<String> bootclasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH); @@ -2258,6 +2263,10 @@ public void configure(String[] argv) { mode = INSIDE_LIMIT_MODULES; continue; } + if (currentArg.equals("--module-version")) { //$NON-NLS-1$ + mode = INSIDE_MODULE_VERSION; + continue; + } if (currentArg.equals("-sourcepath")) {//$NON-NLS-1$ if (sourcepathClasspathArg != null) { StringBuffer errorMessage = new StringBuffer(); @@ -2918,6 +2927,10 @@ public void configure(String[] argv) { this.limitedModules.add(tokenizer.nextToken().trim()); } continue; + case INSIDE_MODULE_VERSION: + mode = DEFAULT; + this.moduleVersion = validateModuleVersion(currentArg); + continue; case INSIDE_CLASSPATH_start: mode = DEFAULT; index += processPaths(newCommandLineArgs, index, currentArg, classpaths); @@ -3212,6 +3225,22 @@ public void configure(String[] argv) { this.pendingErrors = null; } } +private String validateModuleVersion(String versionString) { + try { + Class<?> versionClass = Class.forName("java.lang.module.ModuleDescriptor$Version"); //$NON-NLS-1$ + Method method = versionClass.getMethod("parse", String.class); //$NON-NLS-1$ + try { + method.invoke(null, versionString); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof IllegalArgumentException) + throw (IllegalArgumentException) e.getCause(); + } + } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException e) { + this.logger.logWarning(this.bind("configure.no.ModuleDescriptorVersionparse")); //$NON-NLS-1$ + } + return versionString; +} + private Parser getNewParser() { return new Parser(new ProblemReporter(getHandlingPolicy(), new CompilerOptions(this.options), getProblemFactory()), false); @@ -4778,6 +4807,7 @@ private void initRootModules(LookupEnvironment environment, FileSystem fileSyste } } } + environment.moduleVersion = this.moduleVersion; } private ReferenceBinding[] processClassNames(LookupEnvironment environment) { // check for .class file presence in case of apt processing diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties index 37a2143e9d..c476812a1a 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties @@ -102,6 +102,7 @@ configure.invalidInfo = invalid info token: ''{0}''. Ignoring this info token an configure.invalidInfoOption = invalid info option: ''{0}''. Must specify an info token configure.notOnModuleSourcePath = ''{0}'' does not belong to a module on the module source path +configure.no.ModuleDescriptorVersionparse = Could not invoke method java.lang.module.ModuleDescriptor.Version.parse(), cannot validate module version. ## configure.directoryNotExist = directory does not exist: {0} configure.unrecognizedOption = Unrecognized option : {0} diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java index b15d81aff5..705e2d4150 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java @@ -2752,9 +2752,10 @@ public class ClassFile implements TypeConstants, TypeIds { int flags = module.modifiers & ~(ClassFileConstants.AccModule); this.contents[localContentsOffset++] = (byte) (flags >> 8); this.contents[localContentsOffset++] = (byte) flags; - int module_version = 0; - this.contents[localContentsOffset++] = (byte) (module_version >> 8); - this.contents[localContentsOffset++] = (byte) module_version; + String moduleVersion = module.getModuleVersion(); + int module_version_idx = moduleVersion == null ? 0 : this.constantPool.literalIndex(moduleVersion.toCharArray()); + this.contents[localContentsOffset++] = (byte) (module_version_idx >> 8); + this.contents[localContentsOffset++] = (byte) module_version_idx; int attrLength = 6; // ================= requires section ================= diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java index af0e947fc9..0b189519c1 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java @@ -446,4 +446,12 @@ public class ModuleDeclaration extends ASTNode implements ReferenceContext { public void tagAsHavingIgnoredMandatoryErrors(int problemId) { // Nothing to do for this context; } + + public String getModuleVersion() { + if (this.scope != null) { + LookupEnvironment env = this.scope.environment().root; + return env.moduleVersion; + } + return null; + } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java index 3acb8552eb..426e30218c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java @@ -143,6 +143,8 @@ public class LookupEnvironment implements ProblemReasons, TypeConstants { */ public boolean suppressImportErrors; // per module + public String moduleVersion; // ROOT_ONLY + final static int BUILD_FIELDS_AND_METHODS = 4; final static int BUILD_TYPE_HIERARCHY = 1; final static int CHECK_AND_SET_IMPORTS = 2; |