Mercurial > hg > openjdk > jigsaw > langtools
changeset 445:51b53bc20417 jigsaw-b01
Merge
author | mr |
---|---|
date | Fri, 06 Nov 2009 13:20:18 -0800 |
parents | 8fb9b4be3cb1 (current diff) bd48e67333aa (diff) |
children | 6b9edecbb15a |
files | .hgtags .jcheck/conf src/share/classes/com/sun/tools/classfile/ModuleExportTable_attribute.java src/share/classes/com/sun/tools/classfile/ModuleMemberTable_attribute.java src/share/classes/com/sun/tools/javac/code/Source.java src/share/classes/com/sun/tools/javac/comp/Attr.java src/share/classes/com/sun/tools/javac/comp/Lower.java src/share/classes/com/sun/tools/javac/resources/compiler.properties |
diffstat | 98 files changed, 7303 insertions(+), 565 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Mon Nov 02 21:36:59 2009 -0800 +++ b/.hgtags Fri Nov 06 13:20:18 2009 -0800 @@ -30,6 +30,7 @@ dbdeb4a7581b2a8699644b91cae6793cb01953f7 jdk7-b53 197a7f881937d406a01214aa9ded49c073f7d380 jdk7-b54 7394a8694cedea574c7dbd38de87f4cbe0e27b8a jdk7-b55 +9359f5d705289c8680748d11bc80978edc957ba1 j1-2009-demo 825f23a4f262eb06cfc94406140f3bfecb17ffe8 jdk7-b56 4030cc469205bbd517ca629fb170afb81760bbc5 jdk7-b57 5bcac54d408b436d2364925ee7947b5609e07962 jdk7-b58
--- a/.jcheck/conf Mon Nov 02 21:36:59 2009 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -project=jdk7
--- a/make/build.xml Mon Nov 02 21:36:59 2009 -0800 +++ b/make/build.xml Fri Nov 06 13:20:18 2009 -0800 @@ -204,7 +204,7 @@ <javadoc-tool name="javac" includes="${javac.includes}" options="${javadoc.jls3.option}"/> </target> - <target name="jtreg-javac" depends="build-javac,-def-jtreg"> + <target name="jtreg-javac" depends="build-javac,build-javap,-def-jtreg"> <jtreg-tool name="javac" tests="${javac.tests}"/> </target>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/source/tree/ModuleClassTree.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,34 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.source.tree; + +import java.util.List; +import javax.lang.model.element.Name; + +public interface ModuleClassTree extends Tree { + List<? extends Name> getFlags(); + Tree getClassName(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/source/tree/ModuleIdTree.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,36 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.source.tree; + +import javax.lang.model.element.Name; + +/** + * + */ +public interface ModuleIdTree extends Tree { + Tree getModuleName(); + Name getModuleVersion(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/source/tree/ModulePermitsTree.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,32 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.source.tree; + +import java.util.List; + +public interface ModulePermitsTree extends Tree { + List<? extends ExpressionTree> getModuleNames(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/source/tree/ModuleRequiresTree.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,34 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.source.tree; + +import java.util.List; +import javax.lang.model.element.Name; + +public interface ModuleRequiresTree extends Tree { + List<? extends Name> getFlags(); + List<? extends ModuleIdTree> getModuleIds(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/source/tree/ModuleTree.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,39 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.source.tree; + +import java.util.List; + + +/** + * + */ +public interface ModuleTree extends Tree { + List<? extends AnnotationTree> getAnnotations(); + ModuleIdTree getId(); + List<? extends ModuleIdTree> getProvides(); + List<? extends Tree> getMetadataList(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/source/tree/PackageTree.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,13 @@ + +package com.sun.source.tree; + +import java.util.List; + + +/** + * + */ +public interface PackageTree extends Tree { + List<? extends AnnotationTree> getAnnotations(); + Tree getPackageId(); +}
--- a/src/share/classes/com/sun/source/tree/Tree.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/source/tree/Tree.java Fri Nov 06 13:20:18 2009 -0800 @@ -552,6 +552,18 @@ */ ERRONEOUS(ErroneousTree.class), + MODULE(ModuleTree.class), + + MODULE_CLASS(ModuleClassTree.class), + + MODULE_ID(ModuleIdTree.class), + + MODULE_PERMITS(ModulePermitsTree.class), + + MODULE_REQUIRES(ModuleRequiresTree.class), + + PACKAGE(PackageTree.class), + /** * An implementation-reserved node. This is the not the node * you are looking for.
--- a/src/share/classes/com/sun/source/tree/TreeVisitor.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/source/tree/TreeVisitor.java Fri Nov 06 13:20:18 2009 -0800 @@ -84,8 +84,14 @@ R visitLiteral(LiteralTree node, P p); R visitMethod(MethodTree node, P p); R visitModifiers(ModifiersTree node, P p); + R visitModule(ModuleTree node, P p); + R visitModuleClass(ModuleClassTree node, P p); + R visitModuleId(ModuleIdTree node, P p); + R visitModulePermits(ModulePermitsTree node, P p); + R visitModuleRequires(ModuleRequiresTree node, P p); R visitNewArray(NewArrayTree node, P p); R visitNewClass(NewClassTree node, P p); + R visitPackage(PackageTree node, P p); R visitParenthesized(ParenthesizedTree node, P p); R visitReturn(ReturnTree node, P p); R visitMemberSelect(MemberSelectTree node, P p);
--- a/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Fri Nov 06 13:20:18 2009 -0800 @@ -33,7 +33,7 @@ * @author Peter von der Ahé * @since 1.6 */ -public class SimpleTreeVisitor <R,P> implements TreeVisitor<R,P> { +public class SimpleTreeVisitor<R,P> implements TreeVisitor<R,P> { protected final R DEFAULT_VALUE; protected SimpleTreeVisitor() { @@ -252,6 +252,30 @@ return defaultAction(node, p); } + public R visitModule(ModuleTree node, P p) { + return defaultAction(node, p); + } + + public R visitModuleClass(ModuleClassTree node, P p) { + return defaultAction(node, p); + } + + public R visitModuleId(ModuleIdTree node, P p) { + return defaultAction(node, p); + } + + public R visitModulePermits(ModulePermitsTree node, P p) { + return defaultAction(node, p); + } + + public R visitModuleRequires(ModuleRequiresTree node, P p) { + return defaultAction(node, p); + } + + public R visitPackage(PackageTree node, P p) { + return defaultAction(node, p); + } + public R visitOther(Tree node, P p) { return defaultAction(node, p); }
--- a/src/share/classes/com/sun/source/util/TreeScanner.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/source/util/TreeScanner.java Fri Nov 06 13:20:18 2009 -0800 @@ -380,6 +380,34 @@ return r; } + public R visitModule(ModuleTree node, P p) { + R r = scan(node.getAnnotations(), p); + r = scanAndReduce(node.getId(), p, r); + return r; + } + + public R visitModuleClass(ModuleClassTree node, P p) { + return scan(node.getClassName(), p); + } + + public R visitModuleId(ModuleIdTree node, P p) { + return scan(node.getModuleName(), p); + } + + public R visitModulePermits(ModulePermitsTree node, P p) { + return scan(node.getModuleNames(), p); + } + + public R visitModuleRequires(ModuleRequiresTree node, P p) { + return scan(node.getModuleIds(), p); + } + + public R visitPackage(PackageTree node, P p) { + R r = scan(node.getAnnotations(), p); + r = scanAndReduce(node.getPackageId(), p, r); + return r; + } + public R visitOther(Tree node, P p) { return null; }
--- a/src/share/classes/com/sun/tools/classfile/Attribute.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/classfile/Attribute.java Fri Nov 06 13:20:18 2009 -0800 @@ -64,10 +64,12 @@ public static final String StackMapTable = "StackMapTable"; public static final String Synthetic = "Synthetic"; - // JSR 277/294 + // JSR 294 public static final String Module = "Module"; - public static final String ModuleExportTable = "ModuleExportTable"; - public static final String ModuleMemberTable = "ModuleMemberTable"; + public static final String ModuleClass = "ModuleClass"; + public static final String ModulePermits = "ModulePermits"; + public static final String ModuleProvides = "ModuleProvides"; + public static final String ModuleRequires = "ModuleRequires"; public static class Factory { public Factory() { @@ -78,10 +80,6 @@ this.compat = compat; } - public void setJSR277(boolean jsr277) { - this.jsr277 = jsr277; - } - public Attribute createAttribute(ClassReader cr, int name_index, byte[] data) throws IOException { if (standardAttributes == null) @@ -121,11 +119,11 @@ standardAttributes.put(LocalVariableTable, LocalVariableTable_attribute.class); standardAttributes.put(LocalVariableTypeTable, LocalVariableTypeTable_attribute.class); - if (jsr277) { - standardAttributes.put(Module, Module_attribute.class); - standardAttributes.put(ModuleExportTable, ModuleExportTable_attribute.class); - standardAttributes.put(ModuleMemberTable, ModuleMemberTable_attribute.class); - } + standardAttributes.put(Module, Module_attribute.class); + standardAttributes.put(ModuleClass, ModuleClass_attribute.class); + standardAttributes.put(ModulePermits, ModulePermits_attribute.class); + standardAttributes.put(ModuleProvides, ModuleProvides_attribute.class); + standardAttributes.put(ModuleRequires, ModuleRequires_attribute.class); if (!compat) { // old javap does not recognize recent attributes standardAttributes.put(CompilationID, CompilationID_attribute.class); @@ -148,7 +146,6 @@ private Map<String,Class<? extends Attribute>> standardAttributes; private boolean compat; // don't support recent attrs in compatibility mode - private boolean jsr277; // support new jsr277 attrs } public static Attribute read(ClassReader cr) throws IOException { @@ -203,7 +200,9 @@ R visitSynthetic(Synthetic_attribute attr, P p); R visitModule(Module_attribute attr, P p); - R visitModuleExportTable(ModuleExportTable_attribute attr, P p); - R visitModuleMemberTable(ModuleMemberTable_attribute attr, P p); + R visitModuleClass(ModuleClass_attribute attr, P p); + R visitModulePermits(ModulePermits_attribute attr, P p); + R visitModuleProvides(ModuleProvides_attribute attr, P p); + R visitModuleRequires(ModuleRequires_attribute attr, P p); } }
--- a/src/share/classes/com/sun/tools/classfile/ClassTranslator.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/classfile/ClassTranslator.java Fri Nov 06 13:20:18 2009 -0800 @@ -33,6 +33,7 @@ import com.sun.tools.classfile.ConstantPool.CONSTANT_InterfaceMethodref_info; import com.sun.tools.classfile.ConstantPool.CONSTANT_Long_info; import com.sun.tools.classfile.ConstantPool.CONSTANT_Methodref_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_ModuleId_info; import com.sun.tools.classfile.ConstantPool.CONSTANT_NameAndType_info; import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info; import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info; @@ -313,6 +314,32 @@ return info; } + public CPInfo visitMethodref(CONSTANT_Methodref_info info, Map<Object, Object> translations) { + CONSTANT_Methodref_info info2 = (CONSTANT_Methodref_info) translations.get(info); + if (info2 == null) { + ConstantPool cp2 = translate(info.cp, translations); + if (cp2 == info.cp) + info2 = info; + else + info2 = new CONSTANT_Methodref_info(cp2, info.class_index, info.name_and_type_index); + translations.put(info, info2); + } + return info; + } + + public CPInfo visitModuleId(CONSTANT_ModuleId_info info, Map<Object, Object> translations) { + CONSTANT_ModuleId_info info2 = (CONSTANT_ModuleId_info) translations.get(info); + if (info2 == null) { + ConstantPool cp2 = translate(info.cp, translations); + if (cp2 == info.cp) + info2 = info; + else + info2 = new CONSTANT_ModuleId_info(cp2, info.name_index, info.version_index); + translations.put(info, info2); + } + return info; + } + public CPInfo visitNameAndType(CONSTANT_NameAndType_info info, Map<Object, Object> translations) { CONSTANT_NameAndType_info info2 = (CONSTANT_NameAndType_info) translations.get(info); if (info2 == null) { @@ -326,19 +353,6 @@ return info; } - public CPInfo visitMethodref(CONSTANT_Methodref_info info, Map<Object, Object> translations) { - CONSTANT_Methodref_info info2 = (CONSTANT_Methodref_info) translations.get(info); - if (info2 == null) { - ConstantPool cp2 = translate(info.cp, translations); - if (cp2 == info.cp) - info2 = info; - else - info2 = new CONSTANT_Methodref_info(cp2, info.class_index, info.name_and_type_index); - translations.put(info, info2); - } - return info; - } - public CPInfo visitString(CONSTANT_String_info info, Map<Object, Object> translations) { CONSTANT_String_info info2 = (CONSTANT_String_info) translations.get(info); if (info2 == null) {
--- a/src/share/classes/com/sun/tools/classfile/ClassWriter.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/classfile/ClassWriter.java Fri Nov 06 13:20:18 2009 -0800 @@ -272,16 +272,22 @@ return 2; } + public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) { + return writeRef(info, out); + } + + public Integer visitModuleId(CONSTANT_ModuleId_info info, ClassOutputStream out) { + out.writeShort(info.name_index); + out.writeShort(info.version_index); + return 1; + } + public Integer visitNameAndType(CONSTANT_NameAndType_info info, ClassOutputStream out) { out.writeShort(info.name_index); out.writeShort(info.type_index); return 1; } - public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) { - return writeRef(info, out); - } - public Integer visitString(CONSTANT_String_info info, ClassOutputStream out) { out.writeShort(info.string_index); return 1; @@ -450,24 +456,45 @@ } public Void visitModule(Module_attribute attr, ClassOutputStream out) { - out.writeShort(attr.module_name); + out.writeShort(attr.module_id_index); return null; } - public Void visitModuleExportTable(ModuleExportTable_attribute attr, ClassOutputStream out) { - out.writeShort(attr.export_type_table.length); - for (int i: attr.export_type_table) + public Void visitModuleClass(ModuleClass_attribute attr, ClassOutputStream out) { + out.writeShort(attr.class_index); + out.writeShort(attr.attributes.length); + for (int index: attr.attributes) { + out.writeShort(index); + } + return null; + } + + public Void visitModulePermits(ModulePermits_attribute attr, ClassOutputStream out) { + out.writeShort(attr.permits_table.length); + for (int i: attr.permits_table) out.writeShort(i); return null; } - public Void visitModuleMemberTable(ModuleMemberTable_attribute attr, ClassOutputStream out) { - out.writeShort(attr.package_member_table.length); - for (int i: attr.package_member_table) + public Void visitModuleProvides(ModuleProvides_attribute attr, ClassOutputStream out) { + out.writeShort(attr.provides_table.length); + for (int i: attr.provides_table) out.writeShort(i); return null; } + public Void visitModuleRequires(ModuleRequires_attribute attr, ClassOutputStream out) { + out.writeShort(attr.requires_table.length); + for (ModuleRequires_attribute.Entry e: attr.requires_table) { + out.writeShort(e.requires_index); + out.writeShort(e.attributes.length); + for (int i = 0; i < e.attributes_length; i++) { + out.writeShort(e.attributes[i]); + } + } + return null; + } + public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) { annotationWriter.write(attr.annotations, out); return null;
--- a/src/share/classes/com/sun/tools/classfile/ConstantPool.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/classfile/ConstantPool.java Fri Nov 06 13:20:18 2009 -0800 @@ -114,6 +114,7 @@ public static final int CONSTANT_Methodref = 10; public static final int CONSTANT_InterfaceMethodref = 11; public static final int CONSTANT_NameAndType = 12; + public static final int CONSTANT_ModuleId = 13; ConstantPool(ClassReader cr) throws IOException, InvalidEntry { int count = cr.readUnsignedShort(); @@ -155,6 +156,10 @@ pool[i] = new CONSTANT_Methodref_info(this, cr); break; + case CONSTANT_ModuleId: + pool[i] = new CONSTANT_ModuleId_info(this, cr); + break; + case CONSTANT_NameAndType: pool[i] = new CONSTANT_NameAndType_info(this, cr); break; @@ -218,6 +223,10 @@ return ((CONSTANT_Class_info) get(index, CONSTANT_Class)); } + public CONSTANT_ModuleId_info getModuleIdInfo(int index) throws InvalidIndex, UnexpectedEntry { + return ((CONSTANT_ModuleId_info) get(index, CONSTANT_ModuleId)); + } + public CONSTANT_NameAndType_info getNameAndTypeInfo(int index) throws InvalidIndex, UnexpectedEntry { return ((CONSTANT_NameAndType_info) get(index, CONSTANT_NameAndType)); } @@ -280,8 +289,9 @@ R visitInteger(CONSTANT_Integer_info info, P p); R visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, P p); R visitLong(CONSTANT_Long_info info, P p); + R visitMethodref(CONSTANT_Methodref_info info, P p); + R visitModuleId(CONSTANT_ModuleId_info info, P p); R visitNameAndType(CONSTANT_NameAndType_info info, P p); - R visitMethodref(CONSTANT_Methodref_info info, P p); R visitString(CONSTANT_String_info info, P p); R visitUtf8(CONSTANT_Utf8_info info, P p); } @@ -601,6 +611,48 @@ } } + public static class CONSTANT_ModuleId_info extends CPInfo { + CONSTANT_ModuleId_info(ConstantPool cp, ClassReader cr) throws IOException { + super(cp); + name_index = cr.readUnsignedShort(); + version_index = cr.readUnsignedShort(); + } + + public CONSTANT_ModuleId_info(ConstantPool cp, int name_index, int version_index) { + super(cp); + this.name_index = name_index; + this.version_index = version_index; + } + + public int getTag() { + return CONSTANT_ModuleId; + } + + public String getName() throws ConstantPoolException { + return cp.getUTF8Value(name_index); + } + + public int byteLength() { + return 5; + } + + public String getVersion() throws ConstantPoolException { + return (version_index == 0 ? null : cp.getUTF8Value(version_index)); + } + + @Override + public String toString() { + return "CONSTANT_ModuleId_info[name_index: " + name_index + ", version_index: " + version_index + "]"; + } + + public <R, D> R accept(Visitor<R, D> visitor, D data) { + return visitor.visitModuleId(this, data); + } + + public final int name_index; + public final int version_index; + } + public static class CONSTANT_NameAndType_info extends CPInfo { CONSTANT_NameAndType_info(ConstantPool cp, ClassReader cr) throws IOException { super(cp); @@ -630,15 +682,15 @@ return cp.getUTF8Value(type_index); } - public <R, D> R accept(Visitor<R, D> visitor, D data) { - return visitor.visitNameAndType(this, data); - } - @Override public String toString() { return "CONSTANT_NameAndType_info[name_index: " + name_index + ", type_index: " + type_index + "]"; } + public <R, D> R accept(Visitor<R, D> visitor, D data) { + return visitor.visitNameAndType(this, data); + } + public final int name_index; public final int type_index; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/classfile/ModuleClass_attribute.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.tools.classfile; + +import java.io.IOException; + +import com.sun.tools.classfile.ConstantPool.*; + +/** + * See JSR294. + * + * <p><b>This is NOT part of any API supported by Sun Microsystems. If + * you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice.</b> + */ +public class ModuleClass_attribute extends Attribute { + ModuleClass_attribute(ClassReader cr, int name_index, int length) throws IOException { + super(name_index, length); + class_index = cr.readUnsignedShort(); + attributes_length = cr.readUnsignedShort(); + attributes = new int[attributes_length]; + for (int i = 0; i < attributes.length; i++) + attributes[i] = cr.readUnsignedShort(); + } + + public ModuleClass_attribute(ConstantPool constant_pool, int class_index, int[] attributes) + throws ConstantPoolException { + this(constant_pool.getUTF8Index(Attribute.ModuleRequires), class_index, attributes); + } + + public ModuleClass_attribute(int name_index, int class_index, int[] attributes) { + super(name_index, 2 + attributes.length * 2); + this.class_index = class_index; + this.attributes_length = attributes.length; + this.attributes = attributes; + } + + public CONSTANT_Class_info getClassInfo(ConstantPool constant_pool) throws ConstantPoolException { + if (class_index == 0) + return null; + return constant_pool.getClassInfo(class_index); + } + + public String getClassName(ConstantPool constant_pool) throws ConstantPoolException { + if (class_index == 0) + return null; + return constant_pool.getClassInfo(class_index).getName(); + } + + public String[] getClassAttributes(ConstantPool constant_pool) throws ConstantPoolException { + String[] attrs = new String[attributes.length]; + for (int i = 0; i < attrs.length; i++) + attrs[i] = constant_pool.getUTF8Value(attributes[i]); + return attrs; + } + + public <R, D> R accept(Visitor<R, D> visitor, D data) { + return visitor.visitModuleClass(this, data); + } + + public final int class_index; + public final int attributes_length; + public final int[] attributes; +}
--- a/src/share/classes/com/sun/tools/classfile/ModuleExportTable_attribute.java Mon Nov 02 21:36:59 2009 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright 2007-2008 Sun Microsystems, Inc. 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. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun in the LICENSE file that accompanied this code. - * - * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JSR 277. - * - * <p><b>This is NOT part of any API supported by Sun Microsystems. If - * you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice.</b> - */ -public class ModuleExportTable_attribute extends Attribute { - ModuleExportTable_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - int export_type_length = cr.readUnsignedShort(); - export_type_table = new int[export_type_length]; - for (int i = 0; i < export_type_table.length; i++) - export_type_table[i] = cr.readUnsignedShort(); - } - - public ModuleExportTable_attribute(ConstantPool cp, int[] export_type_table) - throws ConstantPoolException { - this(cp.getUTF8Index(Attribute.ModuleExportTable), export_type_table); - } - - public ModuleExportTable_attribute(int name_index, int[] export_type_table) { - super(name_index, 2 + 2 * export_type_table.length); - this.export_type_table = export_type_table; - } - - public int getExportTypeCount() { - return export_type_table.length; - } - - public String getExportTypeName(int index, ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getUTF8Value(export_type_table[index]); - } - - public <R, P> R accept(Visitor<R, P> visitor, P p) { - return visitor.visitModuleExportTable(this, p); - } - - public final int[] export_type_table; -}
--- a/src/share/classes/com/sun/tools/classfile/ModuleMemberTable_attribute.java Mon Nov 02 21:36:59 2009 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright 2007-2008 Sun Microsystems, Inc. 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. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun in the LICENSE file that accompanied this code. - * - * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ -package com.sun.tools.classfile; - -import java.io.IOException; - -/** - * See JSR 277. - * - * <p><b>This is NOT part of any API supported by Sun Microsystems. If - * you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice.</b> - */ -public class ModuleMemberTable_attribute extends Attribute { - ModuleMemberTable_attribute(ClassReader cr, int name_index, int length) throws IOException { - super(name_index, length); - int package_member_length = cr.readUnsignedShort(); - package_member_table = new int[package_member_length]; - for (int i = 0; i < package_member_table.length; i++) - package_member_table[i] = cr.readUnsignedShort(); - } - - public ModuleMemberTable_attribute(ConstantPool cp, int[] package_member_table) - throws ConstantPoolException { - this(cp.getUTF8Index(Attribute.ModuleMemberTable), package_member_table); - } - - public ModuleMemberTable_attribute(int name_index, int[] package_member_table) { - super(name_index, 2 + 2 * package_member_table.length); - this.package_member_table = package_member_table; - } - - public int getPackageMemberCount() { - return package_member_table.length; - } - - public String getPackageMemberName(int index, ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getUTF8Value(package_member_table[index]); - } - - public <R, P> R accept(Visitor<R, P> visitor, P p) { - return visitor.visitModuleMemberTable(this, p); - } - - public final int[] package_member_table; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/classfile/ModulePermits_attribute.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.tools.classfile; + +import java.io.IOException; + +/** + * See JSR294. + * + * <p><b>This is NOT part of any API supported by Sun Microsystems. If + * you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice.</b> + */ +public class ModulePermits_attribute extends Attribute { + ModulePermits_attribute(ClassReader cr, int name_index, int length) throws IOException { + super(name_index, length); + permits_length = cr.readUnsignedShort(); + permits_table = new int[permits_length]; + for (int i = 0; i < permits_length; i++) + permits_table[i] = cr.readUnsignedShort(); + } + + public ModulePermits_attribute(ConstantPool constant_pool, int[] provides_table) + throws ConstantPoolException { + this(constant_pool.getUTF8Index(Attribute.ModulePermits), provides_table); + } + + public ModulePermits_attribute(int name_index, int[] permits_table) { + super(name_index, 2 + 2 * permits_table.length); + this.permits_length = permits_table.length; + this.permits_table = permits_table; + } + + public String getPermits(int index, ConstantPool constant_pool) throws ConstantPoolException { + int permits_index = permits_table[index]; + return constant_pool.getUTF8Value(permits_index); + } + + public <R, D> R accept(Visitor<R, D> visitor, D data) { + return visitor.visitModulePermits(this, data); + } + + public final int permits_length; + public final int[] permits_table; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/classfile/ModuleProvides_attribute.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.tools.classfile; + +import java.io.IOException; +import com.sun.tools.classfile.ConstantPool.CONSTANT_ModuleId_info; + +/** + * See JSR294. + * + * <p><b>This is NOT part of any API supported by Sun Microsystems. If + * you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice.</b> + */ +public class ModuleProvides_attribute extends Attribute { + ModuleProvides_attribute(ClassReader cr, int name_index, int length) throws IOException { + super(name_index, length); + provides_length = cr.readUnsignedShort(); + provides_table = new int[provides_length]; + for (int i = 0; i < provides_length; i++) + provides_table[i] = cr.readUnsignedShort(); + } + + public ModuleProvides_attribute(ConstantPool constant_pool, int[] provides_table) + throws ConstantPoolException { + this(constant_pool.getUTF8Index(Attribute.ModuleProvides), provides_table); + } + + public ModuleProvides_attribute(int name_index, int[] provides_table) { + super(name_index, 2 + 2 * provides_table.length); + this.provides_length = provides_table.length; + this.provides_table = provides_table; + } + + public CONSTANT_ModuleId_info getProvides(int index, ConstantPool constant_pool) throws ConstantPoolException { + int provides_index = provides_table[index]; + return constant_pool.getModuleIdInfo(provides_index); + } + + public <R, D> R accept(Visitor<R, D> visitor, D data) { + return visitor.visitModuleProvides(this, data); + } + + public final int provides_length; + public final int[] provides_table; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/classfile/ModuleRequires_attribute.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,89 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.tools.classfile; + +import java.io.IOException; + +/** + * See JSR294. + * + * <p><b>This is NOT part of any API supported by Sun Microsystems. If + * you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice.</b> + */ +public class ModuleRequires_attribute extends Attribute { + ModuleRequires_attribute(ClassReader cr, int name_index, int length) throws IOException { + super(name_index, length); + requires_length = cr.readUnsignedShort(); + requires_table = new Entry[requires_length]; + for (int i = 0; i < requires_length; i++) + requires_table[i] = new Entry(cr); + } + + public ModuleRequires_attribute(ConstantPool constant_pool, Entry[] requires_table) + throws ConstantPoolException { + this(constant_pool.getUTF8Index(Attribute.ModuleRequires), requires_table); + } + + public ModuleRequires_attribute(int name_index, Entry[] requires_table) { + super(name_index, 2 + length(requires_table)); + this.requires_length = requires_table.length; + this.requires_table = requires_table; + } + + public <R, D> R accept(Visitor<R, D> visitor, D data) { + return visitor.visitModuleRequires(this, data); + } + + public final int requires_length; + public final Entry[] requires_table; + + private static int length(Entry[] requires_table) { + int n = 0; + for (int i = 0; i < requires_table.length; i++) + n += requires_table[i].length(); + return n; + } + + public static class Entry { + Entry(ClassReader cr) throws IOException { + requires_index = cr.readUnsignedShort(); + attributes_length = cr.readUnsignedShort(); + attributes = new int[attributes_length]; + for (int i = 0; i < attributes_length; i++) + attributes[i] = cr.readUnsignedShort(); + } + + public int length() { + return 4 + attributes_length * 2; + } + + public final int requires_index; + public final int attributes_length; + public final int[] attributes; + } +}
--- a/src/share/classes/com/sun/tools/classfile/Module_attribute.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/classfile/Module_attribute.java Fri Nov 06 13:20:18 2009 -0800 @@ -28,7 +28,7 @@ import java.io.IOException; /** - * See JSR 277. + * See JSR 294. * * <p><b>This is NOT part of any API supported by Sun Microsystems. If * you write code that depends on this, you do so at your own risk. @@ -38,27 +38,26 @@ public class Module_attribute extends Attribute { Module_attribute(ClassReader cr, int name_index, int length) throws IOException { super(name_index, length); - module_name = cr.readUnsignedShort(); + module_id_index = cr.readUnsignedShort(); } - public Module_attribute(ConstantPool constant_pool, int module_name) - throws ConstantPoolException { - this(constant_pool.getUTF8Index(Attribute.Module), module_name); - } - - public Module_attribute(int name_index, int module_name) { + public Module_attribute(int name_index, int module_id_index) { super(name_index, 2); - this.module_name = module_name; + this.module_id_index = module_id_index; } public String getModuleName(ConstantPool constant_pool) throws ConstantPoolException { - return constant_pool.getUTF8Value(module_name); + return constant_pool.getModuleIdInfo(module_id_index).getName(); + } + + public String getModuleVersion(ConstantPool constant_pool) throws ConstantPoolException { + return constant_pool.getModuleIdInfo(module_id_index).getVersion(); } public <R, D> R accept(Visitor<R, D> visitor, D data) { return visitor.visitModule(this, data); } - public final int module_name; + public final int module_id_index; }
--- a/src/share/classes/com/sun/tools/javac/code/Flags.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Flags.java Fri Nov 06 13:20:18 2009 -0800 @@ -112,7 +112,10 @@ * classfile v49.0. */ public static final int ENUM = 1<<14; - public static final int StandardFlags = 0x0fff; + /** Module access, added in classfile v51.0. */ + public static final int MODULE = 1<<15; + + public static final int StandardFlags = 0x8fff; // Because the following access flags are overloaded with other // bit positions, we translate them when reading and writing class @@ -232,15 +235,15 @@ /** Modifier masks. */ public static final int - AccessFlags = PUBLIC | PROTECTED | PRIVATE, + AccessFlags = PUBLIC | PROTECTED | PRIVATE | MODULE, LocalClassFlags = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC, MemberClassFlags = LocalClassFlags | INTERFACE | AccessFlags, - ClassFlags = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION, - InterfaceVarFlags = FINAL | STATIC | PUBLIC, + ClassFlags = LocalClassFlags | INTERFACE | PUBLIC | MODULE | ANNOTATION, + InterfaceVarFlags = FINAL | STATIC | PUBLIC | MODULE, VarFlags = AccessFlags | FINAL | STATIC | VOLATILE | TRANSIENT | ENUM, ConstructorFlags = AccessFlags, - InterfaceMethodFlags = ABSTRACT | PUBLIC, + InterfaceMethodFlags = ABSTRACT | PUBLIC | MODULE, MethodFlags = AccessFlags | ABSTRACT | STATIC | NATIVE | SYNCHRONIZED | FINAL | STRICTFP; public static final long @@ -253,6 +256,7 @@ if (0 != (flags & PUBLIC)) modifiers.add(Modifier.PUBLIC); if (0 != (flags & PROTECTED)) modifiers.add(Modifier.PROTECTED); if (0 != (flags & PRIVATE)) modifiers.add(Modifier.PRIVATE); + if (0 != (flags & MODULE)) modifiers.add(Modifier.MODULE); if (0 != (flags & ABSTRACT)) modifiers.add(Modifier.ABSTRACT); if (0 != (flags & STATIC)) modifiers.add(Modifier.STATIC); if (0 != (flags & FINAL)) modifiers.add(Modifier.FINAL); @@ -284,6 +288,10 @@ return symbol.getConstValue() != null; } + public static boolean isModuleAccess(Symbol symbol) { + return (symbol.flags() & MODULE) != 0; + } + public enum Flag { PUBLIC("public"), @@ -303,6 +311,7 @@ DEPRECATED("deprecated"), HASINIT("hasinit"), ENUM("enum"), + MODULE("module"), IPROXY("iproxy"), NOOUTERTHIS("noouterthis"), EXISTS("exists"), @@ -323,6 +332,7 @@ this.name = name; } + @Override public String toString() { return name; }
--- a/src/share/classes/com/sun/tools/javac/code/Kinds.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Kinds.java Fri Nov 06 13:20:18 2009 -0800 @@ -71,9 +71,13 @@ */ public final static int MTH = 1 << 4; + /** The kind of modules. + */ + public final static int MDL = 1 << 5; + /** The error kind, which includes all other kinds. */ - public final static int ERR = (1 << 5) - 1; + public final static int ERR = (1 << 6) - 1; /** The set of all kinds. */ @@ -103,7 +107,8 @@ VAL("kindname.value"), METHOD("kindname.method"), CLASS("kindname.class"), - PACKAGE("kindname.package"); + PACKAGE("kindname.package"), + MODULE("kindname.module"); private String name;
--- a/src/share/classes/com/sun/tools/javac/code/Printer.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Printer.java Fri Nov 06 13:20:18 2009 -0800 @@ -227,6 +227,11 @@ return visitType(t, locale); } + @Override + public String visitModuleType(ModuleType t, Locale locale) { + return visitType(t, locale); + } + public String visitType(Type t, Locale locale) { String s = (t.tsym == null || t.tsym.name == null) ? localize(locale, "compiler.misc.type.none")
--- a/src/share/classes/com/sun/tools/javac/code/Scope.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Scope.java Fri Nov 06 13:20:18 2009 -0800 @@ -96,7 +96,7 @@ this.shared = 0; } - /** Construct a new scope, within scope next, with given owner, + /** Construct a new scope, with given owner, * using a fresh table of length INITIAL_SIZE. */ public Scope(Symbol owner) {
--- a/src/share/classes/com/sun/tools/javac/code/Source.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Source.java Fri Nov 06 13:20:18 2009 -0800 @@ -153,6 +153,12 @@ public boolean allowAnonOuterThis() { return compareTo(JDK1_5) >= 0; } + public boolean allowModules() { + return compareTo(JDK1_7) >= 0; + } + public boolean allowImportsBeforePackage() { + return compareTo(JDK1_7) >= 0; + } public boolean addBridges() { return compareTo(JDK1_5) >= 0; }
--- a/src/share/classes/com/sun/tools/javac/code/Symbol.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java Fri Nov 06 13:20:18 2009 -0800 @@ -25,9 +25,11 @@ package com.sun.tools.javac.code; +import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import javax.lang.model.element.*; +import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import com.sun.tools.javac.util.*; @@ -37,12 +39,14 @@ import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.jvm.*; +import com.sun.tools.javac.jvm.ClassFile.ModuleId; import com.sun.tools.javac.model.*; import com.sun.tools.javac.tree.JCTree; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.TypeTags.*; +import static com.sun.tools.javac.code.Flags.MODULE; // disambiguate /** Root class for Java symbols. It contains subclasses * for specific sorts of symbols, such as variables, methods and operators, @@ -305,6 +309,13 @@ return (PackageSymbol) sym; } + /** The module which indirectly owns this symbol. + */ + public ModuleSymbol modle() { + ClassSymbol c = outermostClass(); + return c == null ? null : c.modle; + } + /** Is this symbol a subclass of `base'? Only defined for ClassSymbols. */ public boolean isSubClass(Symbol base, Types types) { @@ -383,6 +394,20 @@ return false; } return (clazz.flags() & INTERFACE) == 0; + case MODULE: + ModuleSymbol thisModule = this.modle(); + for (Symbol sup = clazz; + sup != null && sup != this.owner; + sup = types.supertype(sup.type).tsym) { + if (sup.type.isErroneous()) + return true; // error recovery + if ((sup.flags() & COMPOUND) != 0) + continue; + if (sup.modle() != thisModule) + return false; + } + return true; + } } @@ -612,6 +637,78 @@ } } + public static class ModuleRequires implements ModuleElement.ModuleRequires { + public ModuleId moduleId; + public List<Name> flags; + + public ModuleRequires(ModuleId moduleIdQuery, List<Name> flags) { + this.moduleId = moduleIdQuery; + this.flags = flags; + } + + public ModuleElement.ModuleId getModuleId() { + return moduleId; + } + + public java.util.List<? extends CharSequence> getFlags() { + return flags; + } + + } + + /** A class for module symbols. + */ + public static class ModuleSymbol extends TypeSymbol implements ModuleElement // JIGSAW need TypeSymbol? + /*implements ModuleElement*/ { + public Name fullname; + public Name version; + + public ClassSymbol module_info; + + public ClassSymbol className; + public List<Name> classFlags; + public ListBuffer<Name> permits; + public ListBuffer<ClassFile.ModuleId> provides; + public Map<ClassFile.ModuleId,Symbol.ModuleRequires> requires; + public JavaFileManager.Location location; + + public ModuleSymbol() { + super(0, null, null, null); + this.kind = MDL; + this.type = new ModuleType(this); + } + + public ModuleSymbol(Name name, Symbol owner) { + super(0, name, null, owner); + this.kind = MDL; + this.type = new ModuleType(this); + this.fullname = formFullName(name, owner); + } + + public java.util.List<Symbol.ModuleRequires> getRequires() { + List<Symbol.ModuleRequires> l = List.nil(); + for (Symbol.ModuleRequires mr: requires.values()) { + l = l.prepend(mr); + } + return l.reverse(); + } + + @Override + public String toString() { + String n = fullname== null ? "<unknown>" : String.valueOf(fullname); // null-safe + return (version == null) ? n : n + "@" + version; + } + + @Override + public Name getQualifiedName() { + return fullname; + } + + public boolean isUnnamed() { + return name.isEmpty() && owner != null; + } + } + /** A class for package symbols */ public static class PackageSymbol extends TypeSymbol @@ -688,6 +785,10 @@ /** A class for class symbols */ public static class ClassSymbol extends TypeSymbol implements TypeElement { + /** + * The module for the class. + */ + public ModuleSymbol modle; /** a scope for all class members; variables, methods and inner classes * type parameters are not part of this scope
--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java Fri Nov 06 13:20:18 2009 -0800 @@ -77,6 +77,14 @@ private final ClassReader reader; private final Target target; + /** A symbol for the root module. + */ + public final ModuleSymbol rootModule; + + /** A symbol for the unnamed module. + */ + public final ModuleSymbol unnamedModule; + /** A symbol for the root package. */ public final PackageSymbol rootPackage; @@ -355,9 +363,17 @@ unknownType = new Type(TypeTags.UNKNOWN, null); // create the basic builtin symbols + final JavacMessages messages = JavacMessages.instance(context); + rootModule = new ModuleSymbol(names.empty, null); + unnamedModule = new ModuleSymbol(names.empty, rootModule) { + @Override + public String toString() { + return messages.getLocalizedString("compiler.misc.unnamed.module"); + } + }; rootPackage = new PackageSymbol(names.empty, null); - final JavacMessages messages = JavacMessages.instance(context); unnamedPackage = new PackageSymbol(names.empty, rootPackage) { + @Override public String toString() { return messages.getLocalizedString("compiler.misc.unnamed.package"); }
--- a/src/share/classes/com/sun/tools/javac/code/Type.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Type.java Fri Nov 06 13:20:18 2009 -0800 @@ -917,6 +917,34 @@ } } + public static class ModuleType extends Type implements NoType { + + ModuleType(TypeSymbol tsym) { + super(TypeTags.MODULE, tsym); + } + + @Override + public <R,S> R accept(Type.Visitor<R,S> v, S s) { + return v.visitModuleType(this, s); + } + + @Override + public String toString() { + return tsym.getQualifiedName().toString(); + } + + @Override + public TypeKind getKind() { + return TypeKind.MODULE; + } + + @Override + public <R, P> R accept(TypeVisitor<R, P> v, P p) { + return v.visitNoType(this, p); + } + } + + public static class TypeVar extends Type implements TypeVariable { /** The bound of this type variable; set from outside. @@ -1301,6 +1329,7 @@ R visitArrayType(ArrayType t, S s); R visitMethodType(MethodType t, S s); R visitPackageType(PackageType t, S s); + R visitModuleType(ModuleType t, S s); R visitTypeVar(TypeVar t, S s); R visitCapturedType(CapturedType t, S s); R visitForAll(ForAll t, S s);
--- a/src/share/classes/com/sun/tools/javac/code/TypeTags.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/TypeTags.java Fri Nov 06 13:20:18 2009 -0800 @@ -90,9 +90,14 @@ */ public static final int PACKAGE = METHOD+1; + /** The tag of all module "types". + */ + public static final int MODULE = PACKAGE+1; + + /** The tag of all (source-level) type variables. */ - public static final int TYPEVAR = PACKAGE+1; + public static final int TYPEVAR = MODULE+1; /** The tag of all type arguments. */
--- a/src/share/classes/com/sun/tools/javac/code/Types.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java Fri Nov 06 13:20:18 2009 -0800 @@ -3407,6 +3407,7 @@ public R visitArrayType(ArrayType t, S s) { return visitType(t, s); } public R visitMethodType(MethodType t, S s) { return visitType(t, s); } public R visitPackageType(PackageType t, S s) { return visitType(t, s); } + public R visitModuleType(ModuleType t, S s) { return visitType(t, s); } public R visitTypeVar(TypeVar t, S s) { return visitType(t, s); } public R visitCapturedType(CapturedType t, S s) { return visitType(t, s); } public R visitForAll(ForAll t, S s) { return visitType(t, s); }
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Nov 06 13:20:18 2009 -0800 @@ -646,6 +646,9 @@ // JLS ??? chk.checkOverride(tree, m); + // Module modifier may not be used in unnamed module + chk.checkModuleModifier(tree.pos(), m); + // Create a new environment with local scope // for attributing the method. Env<AttrContext> localEnv = memberEnter.methodEnv(tree, env); @@ -768,6 +771,8 @@ try { chk.checkDeprecatedAnnotation(tree.pos(), v); + // Module modifier may not be used in unnamed module + chk.checkModuleModifier(tree.pos(), v); if (tree.init != null) { if ((v.flags_field & FINAL) != 0 && tree.init.getTag() != JCTree.NEWCLASS) { @@ -2707,6 +2712,26 @@ result = tree.type = attribType(tree.getUnderlyingType(), env); } + public void visitModuleDef(JCModuleDecl tree) { + attribStats(tree.getMetadataList(), env); + } + + public void visitModuleRequires(JCModuleRequires tree) { + } + + public void visitModulePermits(JCModulePermits tree) { + } + + public void visitModuleClass(JCModuleClass tree) { + ModuleSymbol msym = env.toplevel.modle; + Type t = attribType(tree.qualId, env); + if (t.tag == CLASS) { + // check duplicates + msym.className = (ClassSymbol) tree.qualId.type.tsym; + msym.classFlags = tree.flags; + } + } + public void visitErroneous(JCErroneous tree) { if (tree.errs != null) for (JCTree err : tree.errs) @@ -2720,6 +2745,33 @@ throw new AssertionError(); } + public void analyze(Env<AttrContext> env) { + switch (env.tree.getTag()) { + case JCTree.MODULE: + attribModule(env.tree.pos(), ((JCModuleDecl)env.tree).sym); + break; + default: + attribClass(env.tree.pos(), env.enclClass.sym); + } + } + + public void attribModule(DiagnosticPosition pos, ModuleSymbol m) { + try { + annotate.flush(); + attribModule(m); + } catch (CompletionFailure ex) { + chk.completionError(pos, ex); + } + + } + + void attribModule(ModuleSymbol m) { + // Get environment current at the point of module definition. + Env<AttrContext> env = enter.typeEnvs.get(m); + //System.err.println("Attr.attribModule: " + env + " " + env.tree); + attribStat(env.tree, env); + } + /** Main method: attribute class definition associated with given class symbol. * reporting completion failures at the given position. * @param pos The source position at which completion errors are to be @@ -2822,6 +2874,9 @@ chk.validate(tree.extending, env); chk.validate(tree.implementing, env); + // Module modifier may not be used in unnamed module + chk.checkModuleModifier(tree.pos(), c); + // If this is a non-abstract class, check that it has no abstract // methods or unimplemented methods of an implemented interface. if ((c.flags() & (ABSTRACT | INTERFACE)) == 0) {
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Fri Nov 06 13:20:18 2009 -0800 @@ -44,6 +44,7 @@ import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.TypeTags.*; +import static com.sun.tools.javac.code.Flags.MODULE; // resolve ambiguity /** Type checking helper class for the attribution phase. * @@ -665,7 +666,7 @@ } /** Check that given modifiers are legal for given symbol and - * return modifiers together with any implicit modififiers for that symbol. + * return modifiers together with any implicit modifiers for that symbol. * Warning: we can't use flags() here since this method * is called during class enter, when flags() would cause a premature * completion. @@ -680,8 +681,12 @@ case VAR: if (sym.owner.kind != TYP) mask = LocalVarFlags; - else if ((sym.owner.flags_field & INTERFACE) != 0) - mask = implicit = InterfaceVarFlags; + else if ((sym.owner.flags_field & INTERFACE) != 0) { + mask = InterfaceVarFlags; + implicit = STATIC | FINAL; + if ((flags & MODULE) == 0) + implicit |= PUBLIC; + } else mask = VarFlags; break; @@ -695,8 +700,12 @@ mask = PRIVATE; } else mask = ConstructorFlags; - } else if ((sym.owner.flags_field & INTERFACE) != 0) - mask = implicit = InterfaceMethodFlags; + } else if ((sym.owner.flags_field & INTERFACE) != 0) { + mask = InterfaceMethodFlags; + implicit = ABSTRACT; + if ((flags & MODULE) == 0) + implicit |= PUBLIC; + } else { mask = MethodFlags; } @@ -724,13 +733,19 @@ mask |= STATIC; else if ((flags & ENUM) != 0) log.error(pos, "enums.must.be.static"); + if ((sym.owner.flags_field & INTERFACE) != 0) { + if ((flags & MODULE) == 0) + implicit |= PUBLIC; + } // Nested interfaces and enums are always STATIC (Spec ???) - if ((flags & (INTERFACE | ENUM)) != 0 ) implicit = STATIC; + if ((flags & (INTERFACE | ENUM)) != 0 ) + implicit = STATIC; } else { mask = ClassFlags; } // Interfaces are always ABSTRACT - if ((flags & INTERFACE) != 0) implicit |= ABSTRACT; + if ((flags & INTERFACE) != 0) + implicit |= ABSTRACT; if ((flags & ENUM) != 0) { // enums can't be declared abstract or final @@ -750,8 +765,7 @@ mask |= INTERFACE; } else { - log.error(pos, - "mod.not.allowed.here", asFlagSet(illegal)); + log.error(pos, "mod.not.allowed.here", asFlagSet(illegal)); } } else if ((sym.kind == TYP || @@ -767,11 +781,15 @@ && checkDisjoint(pos, flags, PUBLIC, - PRIVATE | PROTECTED) + PRIVATE | PROTECTED | MODULE) && checkDisjoint(pos, flags, PRIVATE, - PUBLIC | PROTECTED) + PUBLIC | PROTECTED | MODULE) + && + checkDisjoint(pos, flags, + PROTECTED, + PUBLIC | PRIVATE | MODULE) && checkDisjoint(pos, flags, FINAL, @@ -786,6 +804,16 @@ return flags & (mask | ~StandardFlags) | implicit; } + /** + * Determine if module modifier is legal here. + */ + void checkModuleModifier(DiagnosticPosition pos, Symbol sym) { + // JIGSAW FIXME +// if (Flags.isModuleAccess(sym) && sym.packge().modle == syms.unnamedModule) { +// log.error(pos, "module.not.allowed.here"); +// } + } + /** Determine if this enum should be implicitly final. * @@ -1620,8 +1648,8 @@ MethodSymbol implmeth = absmeth.implementation(impl, types, true); if (implmeth == null || implmeth == absmeth) undef = absmeth; + } } - } if (undef == null) { Type st = types.supertype(c.type); if (st.tag == CLASS)
--- a/src/share/classes/com/sun/tools/javac/comp/Enter.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/Enter.java Fri Nov 06 13:20:18 2009 -0800 @@ -101,6 +101,7 @@ Types types; Lint lint; JavaFileManager fileManager; + Modules modules; private final Todo todo; @@ -123,6 +124,7 @@ types = Types.instance(context); annotate = Annotate.instance(context); lint = Lint.instance(context); + modules = Modules.instance(context); predefClassDef = make.ClassDef( make.Modifiers(PUBLIC), @@ -224,6 +226,21 @@ ? ((JCClassDecl) env.tree).sym.members_field : env.info.scope; } + /** Create a fresh environment for modules. + * + * @param tree The module definition. + * @param env The environment current outside of the module definition. + */ + public Env<AttrContext> moduleEnv(JCModuleDecl tree, Env<AttrContext> env) { + Env<AttrContext> localEnv = + env.dup(tree, env.info.dup(new Scope(tree.sym))); + localEnv.enclClass = predefClassDef; + localEnv.outer = env; + localEnv.info.isSelfCall = false; + localEnv.info.lint = null; // leave this to be filled in by Attr, + // when annotations have been processed + return localEnv; + } /* ************************************************************************ * Visitor methods for phase 1: class enter @@ -268,55 +285,65 @@ return ts.toList(); } + @Override public void visitTopLevel(JCCompilationUnit tree) { JavaFileObject prev = log.useSource(tree.sourcefile); boolean addEnv = false; - boolean isPkgInfo = tree.sourcefile.isNameCompatible("package-info", - JavaFileObject.Kind.SOURCE); - if (tree.pid != null) { - tree.packge = reader.enterPackage(TreeInfo.fullName(tree.pid)); - if (tree.packageAnnotations.nonEmpty()) { - if (isPkgInfo) { - addEnv = true; - } else { - log.error(tree.packageAnnotations.head.pos(), - "pkg.annotations.sb.in.package-info.java"); - } + + boolean isPackageInfo = TreeInfo.isPackageInfo(tree); + boolean isModuleInfo = TreeInfo.isModuleInfo(tree); + JCPackageDecl pd = TreeInfo.getPackage(tree); + + if (pd != null) { + tree.packge = pd.sym = reader.enterPackage(TreeInfo.fullName(pd.packageId)); + if (pd.annots.nonEmpty() && !isPackageInfo) { + log.error(pd.annots.head.pos(), + "pkg.annotations.sb.in.package-info.java"); } } else { tree.packge = syms.unnamedPackage; } tree.packge.complete(); // Find all classes in package. - Env<AttrContext> env = topLevelEnv(tree); + + Env<AttrContext> treeEnv = topLevelEnv(tree); // Save environment of package-info.java file. - if (isPkgInfo) { + if (isPackageInfo) { + addEnv = (pd != null) && pd.annots.nonEmpty(); + Env<AttrContext> env0 = typeEnvs.get(tree.packge); if (env0 == null) { - typeEnvs.put(tree.packge, env); + typeEnvs.put(tree.packge, treeEnv); } else { JCCompilationUnit tree0 = env0.toplevel; if (!fileManager.isSameFile(tree.sourcefile, tree0.sourcefile)) { - log.warning(tree.pid != null ? tree.pid.pos() - : null, + log.warning(pd != null ? pd.pos() : null, "pkg-info.already.seen", tree.packge); - if (addEnv || (tree0.packageAnnotations.isEmpty() && + if (addEnv || (tree0.getPackageAnnotations().isEmpty() && tree.docComments != null && tree.docComments.get(tree) != null)) { - typeEnvs.put(tree.packge, env); + typeEnvs.put(tree.packge, treeEnv); } } } + } else if (isModuleInfo) { + JCModuleDecl md = TreeInfo.getModule(tree); + if (md != null) { + typeEnvs.put(md.sym, treeEnv); + } } - classEnter(tree.defs, env); - if (addEnv) { - todo.append(env); - } + + classEnter(tree.defs, treeEnv); + + if (addEnv) + todo.append(treeEnv); + log.useSource(prev); result = null; } + @Override public void visitClassDef(JCClassDecl tree) { Symbol owner = env.info.scope.owner; Scope enclScope = enterScope(env); @@ -342,7 +369,9 @@ // We are seeing a member class. c = reader.enterClass(tree.name, (TypeSymbol)owner); if ((owner.flags_field & INTERFACE) != 0) { - tree.mods.flags |= PUBLIC | STATIC; + if ((tree.mods.flags & MODULE) == 0) + tree.mods.flags |= PUBLIC; + tree.mods.flags |= STATIC; } } else { // We are seeing a local class. @@ -374,6 +403,7 @@ c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree); c.sourcefile = env.toplevel.sourcefile; c.members_field = new Scope(c); + c.modle = env.toplevel.modle; ClassType ct = (ClassType)c.type; if (owner.kind != PCK && (c.flags_field & STATIC) == 0) { @@ -422,6 +452,7 @@ * Enter a symbol for type parameter in local scope, after checking that it * is unique. */ + @Override public void visitTypeParameter(JCTypeParameter tree) { TypeVar a = (tree.type != null) ? (TypeVar)tree.type @@ -433,8 +464,16 @@ result = a; } + @Override + public void visitModuleDef(JCModuleDecl tree) { + Env<AttrContext> moduleEnv = moduleEnv(tree, env); + typeEnvs.put(tree.sym, moduleEnv); + todo.append(moduleEnv); + } + /** Default class enter visitor method: do nothing. */ + @Override public void visitTree(JCTree tree) { result = null; } @@ -454,9 +493,13 @@ public void complete(List<JCCompilationUnit> trees, ClassSymbol c) { annotate.enterStart(); ListBuffer<ClassSymbol> prevUncompleted = uncompleted; - if (memberEnter.completionEnabled) uncompleted = new ListBuffer<ClassSymbol>(); + if (memberEnter.completionEnabled) + uncompleted = new ListBuffer<ClassSymbol>(); try { + // process module declarations + modules.enter(trees); + // enter all classes, and construct uncompleted list classEnter(trees, null); @@ -476,11 +519,14 @@ for (JCCompilationUnit tree : trees) { if (tree.starImportScope.elems == null) { JavaFileObject prev = log.useSource(tree.sourcefile); - Env<AttrContext> env = typeEnvs.get(tree); - if (env == null) - env = topLevelEnv(tree); - memberEnter.memberEnter(tree, env); - log.useSource(prev); + try { + Env<AttrContext> tenv = typeEnvs.get(tree); + if (tenv == null) + tenv = topLevelEnv(tree); + memberEnter.memberEnter(tree, tenv); + } finally { + log.useSource(prev); + } } } }
--- a/src/share/classes/com/sun/tools/javac/comp/Flow.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java Fri Nov 06 13:20:18 2009 -0800 @@ -1269,6 +1269,10 @@ // Do nothing for TopLevel since each class is visited individually } + public void visitModuleDef(JCModuleDecl tree) { + // Do nothing for modules + } + /************************************************************************** * utility methods for ignoring type-annotated casts lint checking *************************************************************************/
--- a/src/share/classes/com/sun/tools/javac/comp/Lower.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java Fri Nov 06 13:20:18 2009 -0800 @@ -1983,34 +1983,40 @@ } public void visitTopLevel(JCCompilationUnit tree) { - if (tree.packageAnnotations.nonEmpty()) { - Name name = names.package_info; + if (TreeInfo.isPackageInfo(tree)) { + JCPackageDecl pd = TreeInfo.getPackage(tree); long flags = Flags.ABSTRACT | Flags.INTERFACE; if (target.isPackageInfoSynthetic()) - // package-info is marked SYNTHETIC in JDK 1.6 and later releases - flags = flags | Flags.SYNTHETIC; - JCClassDecl packageAnnotationsClass - = make.ClassDef(make.Modifiers(flags, - tree.packageAnnotations), - name, List.<JCTypeParameter>nil(), - null, List.<JCExpression>nil(), List.<JCTree>nil()); - ClassSymbol c = reader.enterClass(name, tree.packge); - c.flatname = names.fromString(tree.packge + "." + name); - c.sourcefile = tree.sourcefile; + flags |= SYNTHETIC; + ClassSymbol c = reader.enterClass(names.package_info, tree.packge); + c.sourcefile = attrEnv.toplevel.sourcefile; c.completer = null; c.members_field = new Scope(c); c.flags_field = flags; - c.attributes_field = tree.packge.attributes_field; + c.attributes_field = pd.sym.attributes_field; + c.modle = attrEnv.toplevel.modle; + pd.sym.attributes_field = List.nil(); ClassType ctype = (ClassType) c.type; ctype.supertype_field = syms.objectType; ctype.interfaces_field = List.nil(); - packageAnnotationsClass.sym = c; - - - translated.append(packageAnnotationsClass); + createInfoClass(pd.annots, c); } } + public void visitModuleDef(JCModuleDecl tree) { + createInfoClass(tree.annots, tree.sym.module_info); + } + + private void createInfoClass(List<JCAnnotation> annots, ClassSymbol c) { + long flags = Flags.ABSTRACT | Flags.INTERFACE; + JCClassDecl infoClass = + make.ClassDef(make.Modifiers(flags, annots), + c.name, List.<JCTypeParameter>nil(), + null, List.<JCExpression>nil(), List.<JCTree>nil()); + infoClass.sym = c; + translated.append(infoClass); + } + public void visitClassDef(JCClassDecl tree) { ClassSymbol currentClassPrev = currentClass; MethodSymbol currentMethodSymPrev = currentMethodSym;
--- a/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Fri Nov 06 13:20:18 2009 -0800 @@ -33,6 +33,7 @@ import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.util.*; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; import com.sun.tools.javac.code.Type.*; @@ -42,7 +43,7 @@ import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.TypeTags.*; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import static com.sun.tools.javac.code.Flags.MODULE; // resolve ambiguity /** This is the second phase of Enter, in which classes are completed * by entering their members into the class scope using @@ -160,6 +161,7 @@ Env<AttrContext> env) { final JavaFileObject sourcefile = env.toplevel.sourcefile; final Scope toScope = env.toplevel.starImportScope; + final ModuleSymbol modle = env.toplevel.modle; final PackageSymbol packge = env.toplevel.packge; final TypeSymbol origin = tsym; @@ -180,7 +182,7 @@ Symbol sym = e.sym; if (sym.kind == TYP && (sym.flags() & STATIC) != 0 && - staticImportAccessible(sym, packge) && + staticImportAccessible(sym, modle, packge) && sym.isMemberOf(origin, types) && !toScope.includes(sym)) toScope.enter(sym, fromScope, origin.members()); @@ -208,7 +210,7 @@ for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) { Symbol sym = e.sym; if (sym.isStatic() && sym.kind != TYP && - staticImportAccessible(sym, packge) && + staticImportAccessible(sym, modle, packge) && !toScope.includes(sym) && sym.isMemberOf(origin, types)) { toScope.enter(sym, fromScope, origin.members()); @@ -222,7 +224,7 @@ } // is the sym accessible everywhere in packge? - boolean staticImportAccessible(Symbol sym, PackageSymbol packge) { + boolean staticImportAccessible(Symbol sym, ModuleSymbol modle, PackageSymbol packge) { int flags = (int)(sym.flags() & AccessFlags); switch (flags) { default: @@ -233,6 +235,8 @@ case 0: case PROTECTED: return sym.packge() == packge; + case MODULE: + return sym.modle() == modle; } } @@ -253,6 +257,7 @@ } final Scope toScope = env.toplevel.namedImportScope; + final ModuleSymbol modle = env.toplevel.modle; final PackageSymbol packge = env.toplevel.packge; final TypeSymbol origin = tsym; @@ -274,7 +279,7 @@ Symbol sym = e.sym; if (sym.isStatic() && sym.kind == TYP && - staticImportAccessible(sym, packge) && + staticImportAccessible(sym, modle, packge) && sym.isMemberOf(origin, types) && chk.checkUniqueStaticImport(pos, sym, toScope)) toScope.enter(sym, sym.owner.members(), origin.members()); @@ -304,7 +309,7 @@ e = e.next()) { Symbol sym = e.sym; if (sym.isStatic() && - staticImportAccessible(sym, packge) && + staticImportAccessible(sym, modle, packge) && sym.isMemberOf(origin, types)) { found = true; if (sym.kind == MTH || @@ -502,23 +507,36 @@ return; } + JCModuleDecl md = TreeInfo.getModule(tree); + JCPackageDecl pd = TreeInfo.getPackage(tree); + // check that no class exists with same fully qualified name as // toplevel package - if (checkClash && tree.pid != null) { + if (checkClash && pd != null) { Symbol p = tree.packge; while (p.owner != syms.rootPackage) { p.owner.complete(); // enter all class members of p if (syms.classes.get(p.getQualifiedName()) != null) { log.error(tree.pos, - "pkg.clashes.with.class.of.same.name", - p); + "pkg.clashes.with.class.of.same.name", + p); } p = p.owner; } } + // set up module and its dependencies + /*temp*/if (tree.modle != null)/*temp*/ // JIGSAW TEMP: tree.modle SHOULD ALWAYS BE SET + tree.modle.complete(); + + // process module annotations + if (md != null) { + annotateLater(md.annots, env, md.sym); + } + // process package annotations - annotateLater(tree.packageAnnotations, env, tree.packge); + if (pd != null) + annotateLater(pd.annots, env, pd.sym); // Import-on-demand java.lang. importAll(tree.pos, reader.enterPackage(names.java_lang), env);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/comp/Modules.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,878 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +package com.sun.tools.javac.comp; + +import com.sun.tools.javac.code.Scope; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symbol.ClassSymbol; +import com.sun.tools.javac.code.Symbol.CompletionFailure; +import com.sun.tools.javac.code.Symbol.ModuleRequires; +import com.sun.tools.javac.code.Symbol.ModuleSymbol; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.jvm.ClassFile; +import com.sun.tools.javac.jvm.ClassFile.ModuleId; +import com.sun.tools.javac.jvm.ClassReader; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCModuleClass; +import com.sun.tools.javac.tree.JCTree.JCModuleDecl; +import com.sun.tools.javac.tree.JCTree.JCModuleId; +import com.sun.tools.javac.tree.JCTree.JCModulePermits; +import com.sun.tools.javac.tree.JCTree.JCModuleRequires; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Names; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import javax.lang.model.element.ModuleElement; +import javax.lang.model.util.ModuleResolver; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileManager.Location; +import javax.tools.JavaFileObject; +import javax.tools.ModuleFileManager; +import javax.tools.ModuleFileManager.InvalidFileObjectException; +import javax.tools.ModuleFileManager.ModuleMode; + +import static javax.tools.StandardLocation.*; + +/** + * <p><b>This is NOT part of any API supported by Sun Microsystems. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice.</b> + */ +public class Modules extends JCTree.Visitor { + ClassReader reader; + Log log; + JavaFileManager fileManager; + ModuleFileManager moduleFileManager; + Names names; + Symtab syms; + + ModuleMode mode; + + /** The set of locations for entered trees */ + Set<Location> rootLocns = new LinkedHashSet<Location>(); + + // The following should be moved to Symtab, with possible reference in ClassReader + Map<Location,ModuleSymbol> allModules = new LinkedHashMap<Location,ModuleSymbol>(); + + /** The current top level tree */ + JCCompilationUnit currTopLevel; + + /** The symbol currently being analyzed. */ + ModuleSymbol currSym; + + static class ModuleContext { + ModuleContext(JCModuleDecl decl) { + this.decl = decl; + } + final JCModuleDecl decl; + boolean seenPlatformRequires; + } + + Env<ModuleContext> env; + Map<ModuleSymbol, Env<ModuleContext>> moduleEnvs = new HashMap<ModuleSymbol, Env<ModuleContext>>(); + + /** True if file manager is not a ModuleFileManager and we have + * seen module declaration in input trees. */ + boolean moduleFileManagerUnavailable; + + public static Modules instance(Context context) { + Modules instance = context.get(Modules.class); + if (instance == null) + instance = new Modules(context); + return instance; + } + + protected Modules(Context context) { + context.put(Modules.class, this); + log = Log.instance(context); + reader = ClassReader.instance(context); + fileManager = context.get(JavaFileManager.class); + names = Names.instance(context); + syms = Symtab.instance(context); + + if (fileManager instanceof ModuleFileManager) { + moduleFileManager = (ModuleFileManager) fileManager; + mode = moduleFileManager.getModuleMode(); + } else + mode = ModuleMode.SINGLE; + } + + <T extends JCTree> void acceptAll(List<T> trees) { + for (List<T> l = trees; l.nonEmpty(); l = l.tail) + l.head.accept(this); + } + + + + @Override + public void visitModuleDef(JCModuleDecl tree) { + DEBUG("Modules.visitModuleDef " + tree.id); + + if (mode == ModuleMode.SINGLE) { + if (moduleFileManager == null) { + log.error(tree, "mdl.module.file.manager.required"); + moduleFileManagerUnavailable = true; + } else { + currTopLevel.locn = moduleFileManager.join(List.of(CLASS_PATH, SOURCE_PATH)); + if (state == State.INITIAL) + rootLocns.add(currTopLevel.locn); + } + } + + ModuleSymbol sym = enterModule(currTopLevel.locn); + if (sym.name != null) { + log.error(tree.pos(), "mdl.already.defined", sym.module_info.sourcefile); + sym = new ModuleSymbol(TreeInfo.fullName(tree.id.qualId), syms.rootModule); + } else { + sym.name = sym.fullname = TreeInfo.fullName(tree.id.qualId); + sym.module_info.fullname = ClassSymbol.formFullName(sym.module_info.name, sym); + sym.module_info.flatname = ClassSymbol.formFlatName(sym.module_info.name, sym); + sym.module_info.sourcefile = currTopLevel.sourcefile; + sym.module_info.members_field = new Scope(sym.module_info); + sym.completer = null; + } + + DEBUG("Modules.visitModuleDef name " + sym.name); + DEBUG("Modules.visitModuleDef fullname " + sym.fullname); + DEBUG("Modules.visitModuleDef flatName() " + sym.flatName()); + DEBUG("Modules.visitModuleDef m-i name " + sym.module_info.name); + DEBUG("Modules.visitModuleDef m-i fullname " + sym.module_info.fullname); + DEBUG("Modules.visitModuleDef m-i flatname " + sym.module_info.flatname); + + sym.location = currTopLevel.locn; + tree.sym = sym; + + sym.version = tree.getId().version; + sym.permits = new ListBuffer<Name>(); + sym.provides = new ListBuffer<ModuleId>(); + sym.requires = new LinkedHashMap<ModuleId,ModuleRequires>(); + for (List<JCModuleId> l = tree.provides; l.nonEmpty(); l = l.tail) { + JCModuleId moduleId = l.head; + sym.provides.append(new ModuleId(TreeInfo.fullName(moduleId.qualId), moduleId.version)); + } + + currSym = sym; + Env<ModuleContext> menv = env.dup(tree, new ModuleContext(tree)); + moduleEnvs.put(sym, menv); + Env<ModuleContext> prev = env; + env = menv; + try { + acceptAll(tree.metadata); + + if (!env.info.seenPlatformRequires) { + ModuleId mid = getDefaultPlatformModule(); + sym.requires.put(mid, new ModuleRequires(mid, List.of(names.synthetic))); + } + } finally { + currSym = null; + env = prev; + } + } + + @Override + public void visitTopLevel(JCCompilationUnit tree) { + DEBUG("Modules.visitTopLevel " + tree.sourcefile); + env = new Env<ModuleContext>(tree, null); + env.toplevel = tree; + currTopLevel = tree; + JavaFileObject prev = log.useSource(tree.sourcefile); + try { + if (mode == ModuleMode.MULTIPLE) { + assert moduleFileManager != null; + Location l = moduleFileManager.join(List.of(MODULE_PATH, SOURCE_PATH)); + JCExpression pn = tree.getPackageName(); + String pkgName = (pn == null) ? "" : TreeInfo.fullName(pn).toString(); + try { + tree.locn = moduleFileManager.getModuleLocation(l, tree.sourcefile, pkgName); + DEBUG("Modules.visitTopLevel MULTIPLE " + tree.locn); + if (state == State.INITIAL) + rootLocns.add(tree.locn); + } catch (InvalidFileObjectException e) { + log.error(pn, "mdl.file.in.wrong.directory", tree.sourcefile, pkgName); + } + } + + if (TreeInfo.isModuleInfo(tree)) + acceptAll(tree.defs); + } finally { + currTopLevel = null; + log.useSource(prev); + DEBUG("Modules.visitTopLevel EXIT rootLocns=" + rootLocns); + } + } + + @Override + public void visitModuleClass(JCModuleClass tree) { +// ModuleSymbol sym = currSym; +// Name className = TreeInfo.fullName(tree.qualId); +// // JIGSAW TODO check conflicts (at most one class) +// sym.className = reader.enterClass(className); +// sym.classFlags = tree.flags; + } + + @Override + public void visitModulePermits(JCModulePermits tree) { + ModuleSymbol sym = currSym; + for (List<JCExpression> l = tree.moduleNames; l.nonEmpty(); l = l.tail) { + JCTree qualId = l.head; + Name moduleName = TreeInfo.fullName(qualId); + // JIGSAW TODO check duplicates + sym.permits.add(moduleName); + } + } + + @Override + public void visitModuleRequires(JCModuleRequires tree) { + ModuleSymbol sym = currSym; + for (List<JCModuleId> l = tree.moduleIds; l.nonEmpty(); l = l.tail) { + JCModuleId moduleId = l.head; + ModuleId mid = new ModuleId(TreeInfo.fullName(moduleId.qualId), moduleId.version); + // JIGSAW TODO check duplicates + sym.requires.put(mid, new ModuleRequires(mid, tree.flags)); + ModuleResolver mr = getModuleResolver(); + if (mr.isPlatformName(mid.name)) + env.info.seenPlatformRequires = true; + } + } + + @Override + public void visitTree(JCTree tree) { } + + ModuleSymbol enterModule(Location locn) { + ModuleSymbol sym = allModules.get(locn); + if (sym == null) { + sym = new ModuleSymbol(null, syms.rootModule); + sym.location = locn; + sym.module_info = new ClassSymbol(0, names.module_info, sym); + sym.module_info.modle = sym; + sym.completer = new Symbol.Completer() { + public void complete(Symbol sym) throws CompletionFailure { + readModule((ModuleSymbol) sym); + } + }; + allModules.put(locn, sym); + } + return sym; + } + + void readModule(ModuleSymbol sym) { + Location locn = sym.location; + JavaFileObject srcFile = getModuleInfo(locn, JavaFileObject.Kind.SOURCE); + JavaFileObject classFile = getModuleInfo(locn, JavaFileObject.Kind.CLASS); + DEBUG("Modules.readModule: src:" + srcFile + " class:" + classFile); + JavaFileObject file; + if (srcFile == null) { + if (classFile == null) { + sym.name = names.empty; // unnamed module + return; + } + file = classFile; + } else if (classFile == null) + file = srcFile; + else + file = reader.preferredFileObject(srcFile, classFile); + DEBUG("Modules.readModule: select:" + file); + + sym.module_info.classfile = file; + DEBUG("Modules.readModule: complete:" + sym + " " + sym.module_info.classfile); + reader.complete(sym); + assert sym.name != null; + DEBUG("Modules.readModule: finished:" + sym + " name:" + sym.name + " fullname:" + sym.fullname + " flatName():" + sym.flatName()); + } + + JavaFileObject getModuleInfo(Location locn, JavaFileObject.Kind kind) { + try { + return fileManager.getJavaFileForInput(locn, "module-info", kind); + } catch (IOException e) { + return null; + } + } + + ModuleId getDefaultPlatformModule() { + if (defaultPlatformModule == null) { + ModuleResolver mr = getModuleResolver(); + String def = mr.getDefaultPlatformModule(); + int at = def.indexOf("@"); + if (at == -1) + defaultPlatformModule = new ModuleId(names.fromString(def), null); + else { + Name name = names.fromString(def.substring(0, at).trim()); + Name version = names.fromString(def.substring(at + 1).trim()); + defaultPlatformModule = new ModuleId(name, version); + } + } + return defaultPlatformModule; + } + // where + private ModuleId defaultPlatformModule; + + private boolean resolve(List<JCCompilationUnit> trees) { + if (moduleFileManagerUnavailable) + return false; + + DEBUG("Modules.resolve mode=" + mode + ", rootLocns=" + rootLocns + " (" + rootLocns.size() + "]" ); + if (mode == ModuleMode.SINGLE && rootLocns.isEmpty()) { + if (moduleFileManager != null) { + rootLocns.add(moduleFileManager.join(List.of(CLASS_PATH, SOURCE_PATH))); + } else { + // TODO: check for module-info.{java,class} and give error if found + // TODO?? use a custom DEFAULT locn, instead of null?? + return true; + } + } + + DEBUG("Modules.resolve: building roots, rootLocns=" + rootLocns); + List<ModuleSymbol> roots = List.nil(); + for (Location locn: rootLocns) { + DEBUG("Modules.resolve: building roots: locn: " + locn); + ModuleSymbol msym = enterModule(locn); + DEBUG("Modules.resolve: building roots: msym: " + msym); + msym.complete(); + DEBUG("Modules.resolve: building roots: completed: " + msym); + if (msym.name != names.empty) + roots = roots.prepend(msym); + } + roots = roots.reverse(); + DEBUG("Modules.resolve: roots: " + roots); + + updateTrees(trees); + + if (roots.isEmpty()) + return true; + + DEBUG("Modules.resolve: modules so far: " + allModules); + + DEBUG("Modules.resolve: reading module-info as needed"); + Location l = (moduleFileManager.getModuleMode() == ModuleMode.SINGLE) + ? MODULE_PATH : moduleFileManager.join(List.of(MODULE_PATH, SOURCE_PATH)); + for (Location locn: moduleFileManager.getModuleLocations(l)) { + DEBUG("Modules.resolve: ensuring module-info for " + locn); + enterModule(locn).complete(); + } + + DEBUG("Modules.resolve: resolve modules"); + ModuleResolver mr = getModuleResolver(); + DEBUG("Modules.resolve: module resolver: " + mr); + try { + ListBuffer<ModuleSymbol> namedModules = new ListBuffer<ModuleSymbol>(); + for (ModuleSymbol msym: allModules.values()) { + if (msym.name != names.empty) + namedModules.add(msym); + } + Iterable<? extends ModuleElement> modules = + mr.resolve(roots, namedModules); + + ListBuffer<Location> locns = new ListBuffer<Location>(); + for (ModuleElement me: modules) { + ModuleSymbol msym = (ModuleSymbol) me; + DEBUG("Modules.resolve: msym: " + msym); + DEBUG("Modules.resolve: msym.location: " + msym.location); + locns.add(msym.location); + } + Location merged = moduleFileManager.join(locns); + DEBUG("Modules.resolve: merged result: " + merged); + reader.setPathLocation(merged); + } catch (ModuleResolver.ResolutionException e) { + DEBUG("Modules.resolve: resolution error " + e); + e.printStackTrace(); + return false; + } + return true; + + } + + protected ModuleResolver getModuleResolver() { + if (moduleResolver != null) + return moduleResolver; + + ServiceLoader<ModuleResolver> loader = ServiceLoader.load(ModuleResolver.class); + // for now, use the first available, if any + for (Iterator<ModuleResolver> iter = loader.iterator(); iter.hasNext(); ) { + moduleResolver = iter.next(); + return moduleResolver; + } + + // use Class.forName on jigsaw module resolve + + // use ZeroMod + moduleResolver = new ZeroMod(new ErrorHandler() { + public void report(ModuleSymbol msym, ModuleId mid, String key, Object... args) { + error(msym, mid, key, args); + } + }); + return moduleResolver; + } + // where + private ModuleResolver moduleResolver; + + private void error(ModuleSymbol msym, ModuleId id, String key, Object... args) { + // TODO, determine error location from msym, mid + ClassSymbol minfo = msym.module_info; + + Env<ModuleContext> menv = moduleEnvs.get(msym); + DEBUG("Modules.error " + msym + " -- " + moduleEnvs.get(msym)); + JavaFileObject fo; + JCDiagnostic.DiagnosticPosition pos; + if (menv == null) { + fo = (minfo.sourcefile != null ? minfo.sourcefile : minfo.classfile); + if (fo == null) + fo = msym.module_info.classfile; + pos = null; + } else { + fo = menv.toplevel.sourcefile; + pos = treeFinder.find(menv.info.decl, id); + } + + JavaFileObject prev = log.useSource(fo); + try { + log.error(pos, key, args); + } finally { + log.useSource(prev); + } + } + + class TreeFinder extends JCTree.Visitor { + ModuleId mid; + JCTree result; + + JCTree find(JCTree tree, ModuleId mid) { + DEBUG("Modules.TreeFinder.find mid=" + mid); + this.mid = mid; + result = null; + tree.accept(this); + DEBUG("Modules.TreeFinder.find result=" + result); + return result; + } + + @Override + public void visitModuleDef(JCModuleDecl tree) { + search(tree.id); + search(tree.provides); + search(tree.metadata); + } + + @Override + public void visitModuleRequires(JCModuleRequires tree) { + search(tree.moduleIds); + } + + @Override + public void visitModuleId(JCModuleId tree) { + DEBUG("Modules.treeFinder.visitModuleId " + tree + " " + mid); + if (equal(TreeInfo.fullName(tree.qualId), mid.name) && equal(tree.version, mid.version)) + result = tree; + DEBUG("Modules.treeFinder.visitModuleId result " + result); + } + + void search(JCTree tree) { + if (result != null) + return; + + tree.accept(this); + } + + void search(List<? extends JCTree> trees) { + if (result != null) + return; + + for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) { + l.head.accept(this); + if (result != null) + return; + } + } + + <T> boolean equal(T t1, T t2) { + DEBUG("Modules.treeFinder.equal " + t1 + " " + t2 + (t1 == null ? t2 == null : t1.equals(t2))); + return t1 == null ? t2 == null : t1.equals(t2); + } + } + TreeFinder treeFinder = new TreeFinder(); + + private void updateTrees(List<JCCompilationUnit> trees) { + if (mode == ModuleMode.SINGLE) { + assert rootLocns.size() == 1; + Location locn = rootLocns.iterator().next(); + locn.getClass(); // debug + ModuleSymbol msym = allModules.get(locn); + DEBUG("Modules.updateTrees: update SINGLE trees: " + locn + " " + msym); + if (msym == null) { + msym = syms.unnamedModule; + DEBUG("Modules.updateTrees: using unnamed module " + syms.unnamedModule.completer); + } + for (List<JCCompilationUnit> l = trees; l.nonEmpty(); l = l.tail) { + JCCompilationUnit tree = l.head; + assert tree.locn == null || tree.locn == locn; + tree.locn = locn; + assert tree.modle == null || tree.modle == msym; + tree.modle = msym; + } + } else { + for (List<JCCompilationUnit> l = trees; l.nonEmpty(); l = l.tail) { + JCCompilationUnit t = l.head; + ModuleSymbol msym = allModules.get(t.locn); + if (msym == null) { + msym = syms.unnamedModule; + DEBUG("Modules.updateTrees: using unnamed module " + syms.unnamedModule.completer); + } + t.modle = msym; + DEBUG("Modules.updateTrees: update MULTIPLE trees: " + t.locn + " " + t.modle); + } + } + } + + private enum State { INITIAL, RESOLVING, RESOLVED}; + private State state = State.INITIAL; + + private int enterCount = 0; // debug only + + public boolean enter(List<JCCompilationUnit> trees) { + int count = enterCount++; + DEBUG("Modules.enter " + count + " " + state); + + DEBUG("Modules.enter " + count + ": acceptAll"); + acceptAll(trees); + + try { // debug + + switch (state) { + case INITIAL: + state = State.RESOLVING; + try { + return resolve(trees); + } finally { + state = State.RESOLVED; + } + + case RESOLVING: + updateTrees(trees); + return true; + + case RESOLVED: + return true; + + default: + throw new AssertionError(); + } + + // debug + } finally { + DEBUG("Modules.enter " + count + ": exit " + state); + } + } + + // Quick and dirty temporary debug printing; + // this should all be removed prior to final integration + boolean DEBUG = false; + void DEBUG(String s) { + if (DEBUG) + System.err.println(s); + } + + private static <T> String toString(Iterable<T> items) { + StringBuilder sb = new StringBuilder(); + sb.append("["); + String sep = ""; + for (T t: items) { + sb.append(sep); + sb.append(t); + sep = ","; + } + sb.append("]"); + return sb.toString(); + } + + // should be static within ZeroMod + enum VersionErrorKind { + NO_VERSION_AVAILABLE("mdl.no.version.available"), + NO_UNIQUE_VERSION_AVAILABLE("mdl.no.unique.version.available"), + REQUIRED_VERSION_NOT_AVAILABLE("mdl.required.version.not.available"); + VersionErrorKind(String key) { this.key = key; } + final String key; + }; + + interface ErrorHandler { + void report(ModuleSymbol msym, ModuleId mid, String key, Object... args); + } + + class ZeroMod implements ModuleResolver { + private ErrorHandler errorHandler; + + ZeroMod(ErrorHandler e) { + errorHandler = e; + } + + public Iterable<? extends ModuleElement> resolve( + Iterable<? extends ModuleElement> roots, + Iterable<? extends ModuleElement> modules) + { + DEBUG("ZeroMod: roots: " + Modules.toString(roots)); + DEBUG("ZeroMod: modules: " + Modules.toString(modules)); + roots.getClass(); + modules.getClass(); + + moduleTable = buildModuleTable(modules); + List<Node> rootNodes = getNodes(roots); + tarjan(rootNodes); + + DEBUG("ZeroMod.NODE MAP {"); + for (Node n: nodeMap.values()) + DEBUG(" Node " + n + " " + n.scc); + DEBUG("}"); + + ListBuffer<ModuleSymbol> results = new ListBuffer<ModuleSymbol>(); + for (Node node: rootNodes) { + if (!results.contains(node.sym)) + getVisibleModules(node.scc, results); + } + + DEBUG("ZeroMod: results: " + Modules.toString(results)); + return results; + } + + public Iterable<? extends ModuleElement> getVisibleModules(ModuleElement elem) { + ModuleSymbol sym = (ModuleSymbol) elem; + DEBUG("ZeroMod getVisibleModules " + getNode(sym)); + SCC scc = getNode(sym).scc; + ListBuffer<ModuleSymbol> results = new ListBuffer<ModuleSymbol>(); + getVisibleModules(scc, results); + return results.toList(); + } + + private void getVisibleModules(SCC scc, ListBuffer<ModuleSymbol> results) { + for (Node n: scc.nodes) + results.add(n.sym); + for (SCC child: scc.getChildren()) + getVisibleModules(child, results); + } + + private Map<Name, Map<Name, ModuleSymbol>> buildModuleTable( + Iterable<? extends ModuleElement> modules) { + Map<Name, Map<Name, ModuleSymbol>> table = new HashMap<Name, Map<Name, ModuleSymbol>>(); + // build module index + for (ModuleElement elem: modules) { + ModuleSymbol sym = (ModuleSymbol) elem; + add(table, sym, new ClassFile.ModuleId(sym.name, sym.version)); + for (List<ClassFile.ModuleId> l = sym.provides.toList(); l.nonEmpty(); l = l.tail) + add(table, sym, l.head); + } + return table; + } + + private void add(Map<Name, Map<Name, ModuleSymbol>> table, + ModuleSymbol sym, ModuleId mid) { + Map<Name, ModuleSymbol> versions = table.get(mid.name); + if (versions == null) + table.put(mid.name, versions = new HashMap<Name, ModuleSymbol>()); + ModuleSymbol m = versions.get(mid.version); + if (m != null) + // TODO ?? enhance error to disambiguate between define and provides + errorHandler.report(sym, mid, "mdl.duplicate.definition", m); + else + versions.put(mid.version, sym); + } + + private ModuleSymbol getModule(ModuleId mid) throws ModuleException { + Map<Name, ModuleSymbol> versions = moduleTable.get(mid.name); + if (versions == null) + throw new ModuleException("mdl.no.version.available", mid); + if (mid.version == null) { + if (versions.size() > 1) + throw new ModuleException("mdl.no.unique.version.available", mid); + return versions.values().iterator().next(); + } else { + ModuleSymbol sym = versions.get(mid.version); + if (sym == null) + throw new ModuleException("mdl.required.version.not.available", mid); + return sym; + } + } + // where + private Map<Name, Map<Name, ModuleSymbol>> moduleTable; + + public boolean isPlatformName(CharSequence name) { + String n = name.toString(); + return n.equals("jdk") || n.startsWith("jdk."); // for now + } + + public String getDefaultPlatformModule() { + return "jdk@7-ea"; // for now + } + + private class ModuleException extends Exception { + private static final long serialVersionUID = 0; + ModuleException(String key, ModuleId moduleId) { + this.key = key; + this.moduleId = moduleId; + } + final String key; + final ModuleId moduleId; + } + + List<Node> getNodes(Iterable<? extends ModuleElement> elems) { + ListBuffer<Node> lb = new ListBuffer<Node>(); + for (ModuleElement elem: elems) { + ModuleSymbol sym = (ModuleSymbol) elem; + lb.add(getNode(sym)); + } + return lb.toList(); + } + + Node getNode(ModuleSymbol sym) { + Node node = nodeMap.get(sym); + if (node == null) + nodeMap.put(sym, (node = new Node(sym))); + return node; + } + // where + private Map<ModuleSymbol, Node> nodeMap= new HashMap<ModuleSymbol, Node>(); + + private class Node implements Comparable<Node> { + final ModuleSymbol sym; + SCC scc; + int index = -1; + int lowlink; + boolean active; + + Node(ModuleSymbol sym) { + this.sym = sym; + } + + Iterable<Node> getDependencies() { + DEBUG("ZeroMod.Node.getDependencies: " + sym + " " + sym.requires); + ListBuffer<Node> nodes = new ListBuffer<Node>(); + for (ModuleRequires mr: sym.requires.values()) { + if (isPlatformName(mr.moduleId.name)) { + DEBUG("ZeroMod.Node.getDependencies: ignore platform module " + mr.moduleId.name); + continue; + } + try { + nodes.add(getNode(getModule(mr.moduleId))); + } catch (ModuleException e) { + errorHandler.report(sym, e.moduleId, e.key, e.moduleId); + } + } + return nodes.toList(); + } + + @Override + public String toString() { + return sym.name + "@" + sym.version + "(index:" + index +",low:" + lowlink + ",active:" + active + ")" ; + } + + public int compareTo(Node o) { + return (index < o.index) ? -1 : (index == o.index) ? 0 : 1; + } + } + + private class SCC { + void add(Node node) { + nodes.add(node); + node.scc = this; + } + + Set<SCC> getChildren() { + if (children == null) { + children = new LinkedHashSet<SCC>(); + for (Node node: nodes) { + for (Node n: node.getDependencies()) { + n.scc.getClass(); // nullcheck + if (n.scc != this) + children.add(n.scc); + } + } + } + return children; + } + + @Override + public String toString() { + return nodes.toString(); + } + + private SortedSet<Node> nodes = new TreeSet<Node>(); + private Set<SCC> children; + } + + // Tarjan's algorithm to determine strongly connected components of a + // directed graph in linear time. + + void tarjan(Iterable<? extends Node> nodes) { + for (Node node: nodes) { + if (node.index == -1) + tarjan(node); + } + } + + void tarjan(Node v) { + v.index = index; + v.lowlink = index; + index++; + stack.add(0, v); + v.active = true; + for (Node n: v.getDependencies()) { + if (n.index == -1) { + tarjan(n); + v.lowlink = Math.min(v.lowlink, n.lowlink); + } else if (stack.contains(n)) { + v.lowlink = Math.min(v.lowlink, n.index); + } + } + if (v.lowlink == v.index) { + Node n; + SCC scc = new SCC(); + do { + n = stack.remove(0); + n.active = false; + scc.add(n); + } while (n != v); + } + } + + private int index = 0; + private ArrayList<Node> stack = new ArrayList<Node>(); + } +}
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Nov 06 13:20:18 2009 -0800 @@ -25,6 +25,10 @@ package com.sun.tools.javac.comp; +import java.util.Map; +import java.util.HashMap; +import javax.lang.model.element.ElementVisitor; + import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.code.*; @@ -40,10 +44,8 @@ import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.TypeTags.*; -import javax.lang.model.element.ElementVisitor; -import java.util.Map; -import java.util.HashMap; +import static com.sun.tools.javac.code.Flags.MODULE; // disambiguate /** Helper class for name resolution, used mostly by the attribution phase. * @@ -144,7 +146,7 @@ * @param c The class whose accessibility is checked. */ public boolean isAccessible(Env<AttrContext> env, TypeSymbol c) { - switch ((short)(c.flags() & AccessFlags)) { + switch ((int)(c.flags() & AccessFlags)) { case PRIVATE: return env.enclClass.sym.outermostClass() == @@ -160,6 +162,10 @@ // classes which would be inaccessible otherwise. env.enclMethod != null && (env.enclMethod.mods.flags & ANONCONSTR) != 0; + case MODULE: + return + env.toplevel.modle == c.modle(); + default: // error recovery case PUBLIC: return true; @@ -199,9 +205,9 @@ * @param sym The symbol. */ public boolean isAccessible(Env<AttrContext> env, Type site, Symbol sym) { - if (sym.name == names.init && sym.owner != site.tsym) return false; - ClassSymbol sub; - switch ((short)(sym.flags() & AccessFlags)) { + if (sym.name == names.init && sym.owner != site.tsym) + return false; + switch ((int)(sym.flags() & AccessFlags)) { case PRIVATE: return (env.enclClass.sym == sym.owner // fast special case @@ -221,6 +227,15 @@ sym.isInheritedIn(site.tsym, types) && notOverriddenIn(site, sym); + case MODULE: + return + (env.toplevel.modle == sym.modle()) + && + isAccessible(env, site) + && + sym.isInheritedIn(site.tsym, types) + && + notOverriddenIn(site, sym); case PROTECTED: return (env.toplevel.packge == sym.owner.owner // fast special case
--- a/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java Fri Nov 06 13:20:18 2009 -0800 @@ -73,6 +73,8 @@ protected abstract String inferBinaryName(Iterable<? extends File> path); + protected abstract String inferModuleTag(String binaryName); + protected static JavaFileObject.Kind getKind(String filename) { if (filename.endsWith(CLASS.extension)) return CLASS;
--- a/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Fri Nov 06 13:20:18 2009 -0800 @@ -55,7 +55,10 @@ import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.zip.ZipFile; @@ -63,10 +66,18 @@ import javax.lang.model.SourceVersion; import javax.tools.FileObject; import javax.tools.JavaFileManager; +import javax.tools.JavaFileManager.Location; import javax.tools.JavaFileObject; +import javax.tools.ModuleFileManager; import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; + +import static javax.tools.StandardLocation.*; import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.file.Paths.Path; +import com.sun.tools.javac.file.Paths.PathEntry; +import com.sun.tools.javac.file.Paths.PathLocation; import com.sun.tools.javac.file.RelativePath.RelativeFile; import com.sun.tools.javac.file.RelativePath.RelativeDirectory; import com.sun.tools.javac.main.JavacOption; @@ -79,7 +90,6 @@ import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Options; -import static javax.tools.StandardLocation.*; import static com.sun.tools.javac.main.OptionName.*; /** @@ -91,7 +101,7 @@ * This code and its internal interfaces are subject to change or * deletion without notice.</b> */ -public class JavacFileManager implements StandardJavaFileManager { +public class JavacFileManager implements StandardJavaFileManager, ModuleFileManager { boolean useZipFileIndex; @@ -398,6 +408,188 @@ return j < 0; } + private ModuleMode moduleMode; + + public ModuleMode getModuleMode() { + if (moduleMode == null) { + if (options.get(MODULEPATH) != null && options.get(CLASSPATH) == null) + moduleMode = ModuleMode.MULTIPLE; + else + moduleMode = ModuleMode.SINGLE; + } + return moduleMode; + } + + public Location getModuleLocation(Location locn, JavaFileObject fo, String pkgName) + throws InvalidLocationException, InvalidFileObjectException { + if (getModuleMode() == ModuleMode.SINGLE) + return locn; + else { + fo.getClass(); // null check + if (!(fo instanceof BaseFileObject)) + throw new IllegalArgumentException(); + + if (!hasLocation(locn)) + throw new InvalidLocationException(); + String tag = ((BaseFileObject) fo).inferModuleTag(pkgName); + if (tag == null) + throw new InvalidFileObjectException(); + return getModuleLocation(locn, tag); + } + } + + private Map<Location,Iterable<Location>> moduleLocations = + new LinkedHashMap<Location,Iterable<Location>>(); + + public Iterable<Location> getModuleLocations(Location locn) { + //System.err.println("JavacFileManager.getModuleLocations " + getModuleMode() + " " + locn); + + Iterable<Location> result = moduleLocations.get(locn); + if (result == null) { + Iterable<PathEntry> pathEntries = getEntriesForLocation(locn); + if (pathEntries == null) + result = List.<Location>nil(); + else { + Set<Location> locns = new LinkedHashSet<Location>(); + for (PathEntry pe: pathEntries) { + if (pe.file.isDirectory()) { + for (File f: pe.file.listFiles()) { + String tag = null; + if (f.isDirectory()) + tag = f.getName(); +// else if (isArchive(f)) { +// String name = f.getName(); +// tag = name.substring(0, name.lastIndexOf(".")); +// } + if (tag != null) + locns.add(getModuleLocation(locn, tag)); + } + } else { + // ignore archive files for now, these would be "module archive + // files", containing multiple modules in a new but obvious way + } + + } + result = locns; + } + } + +// System.err.println("JavacFileManager.getModuleLocations.result " + result); + return result; + } + + + private Map<String, Location> locationCache = new HashMap<String,Location>(); + + public Location join(Iterable<? extends Location> locations) + throws IllegalArgumentException { + StringBuilder sb = new StringBuilder("{"); + String sep = ""; + for (Location l: locations) { + if (l instanceof StandardLocation || l instanceof PathLocation) { + sb.append(sep); + sb.append(l.getName()); + sep = ","; + } else + throw new IllegalArgumentException(l.toString()); + } + sb.append("{"); + String name = sb.toString(); + + Location result = locationCache.get(name); + if (result == null) { + Path p = paths.new Path(); + for (Location l: locations) { + if (l instanceof StandardLocation) { + if (hasLocation(l)) { + Set<JavaFileObject.Kind> kinds = allKinds; + switch ((StandardLocation) l) { + case CLASS_PATH: + kinds = (hasLocation(SOURCE_PATH) ? noSourceKind : allKinds); + break; + case SOURCE_OUTPUT: + case SOURCE_PATH: + kinds = noClassKind; + break; + case ANNOTATION_PROCESSOR_PATH: + case PLATFORM_CLASS_PATH: + case CLASS_OUTPUT: + kinds = noSourceKind; + break; + } + p.addAll(getEntriesForLocation(l), kinds); + } + } else if (l instanceof PathLocation) { + p.addAll(((PathLocation) l).path); + } + } + result = new PathLocation(p, name); + locationCache.put(name, result); + } + +// System.err.println("JavacFileManager.join: " + toString(locations) + " = " + result); + return result; + } + + // Get a location for all the containers named "tag" on given location + // Containers may be either directories or archive files. + private Location getModuleLocation(Location location, String tag) { + // TODO: should reject bad use when location is already a module location + // TODO: should honor location.isOutput() + String name = location.getName() + "[" + tag + "]"; + Location result = locationCache.get(name); + if (result == null) { + Iterable<? extends PathEntry> pathEntries; + if (location instanceof StandardLocation) + pathEntries = getEntriesForLocation(location); + else if (location instanceof PathLocation) + pathEntries = ((PathLocation) location).path; + else + throw new IllegalArgumentException(location.getName()); + Path p = paths.new Path(); + if (pathEntries != null) { + for (PathEntry e: pathEntries) { + File dir = new File(e.file, tag); + if (dir.exists() && dir.isDirectory() || location.isOutputLocation()) + p.add(paths.new PathEntry(dir, e.kinds)); + else { + File jar = new File(e.file, tag + ".jar"); + if (jar.exists() && jar.isFile()) + p.add(paths.new PathEntry(dir, e.kinds)); + } + } + } + result = new PathLocation(p, name); + locationCache.put(name, result); + } + return result; + } + + private <T> String toString(Iterable<T> items) { + ArrayList<T> list = new ArrayList<T>(); + for (T t: items) + list.add(t); + return list.toString(); + } + + private boolean isArchive(File f) { + String name = f.getName(); + String extn = name.substring(name.lastIndexOf(".")).toLowerCase(); // safe if not found + return archiveExtns.contains(extn); + } + + private static final Set<String> archiveExtns = new HashSet<String>(Arrays.asList(".jar")); + + private static Set<JavaFileObject.Kind> allKinds, noSourceKind, noClassKind; + static { + allKinds = EnumSet.allOf(JavaFileObject.Kind.class); + noSourceKind = EnumSet.allOf(JavaFileObject.Kind.class); + noSourceKind.remove(JavaFileObject.Kind.SOURCE); + noClassKind = EnumSet.allOf(JavaFileObject.Kind.class); + noClassKind.remove(JavaFileObject.Kind.CLASS); + } + + /** * An archive provides a flat directory structure of a ZipFile by * mapping directory names to lists of files (basenames). @@ -799,14 +991,18 @@ nullCheck(packageName); nullCheck(kinds); - Iterable<? extends File> path = getLocation(location); - if (path == null) + Iterable<? extends PathEntry> entries = getEntriesForLocation(location); + if (entries == null) return List.nil(); RelativeDirectory subdirectory = RelativeDirectory.forPackage(packageName); ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>(); - for (File directory : path) - listDirectory(directory, subdirectory, kinds, recurse, results); + for (PathEntry e: entries) { + Set<JavaFileObject.Kind> s = EnumSet.copyOf(kinds); + s.retainAll(e.kinds); + if (!s.isEmpty()) + listDirectory(e.file, subdirectory, s, recurse, results); + } return results.toList(); } @@ -883,7 +1079,7 @@ nullCheck(kind); if (!sourceOrClass.contains(kind)) throw new IllegalArgumentException("Invalid kind " + kind); - return getFileForInput(location, RelativeFile.forClass(className, kind)); + return getFileForInput(location, RelativeFile.forClass(className, kind), kind); } public FileObject getFileForInput(Location location, @@ -899,15 +1095,28 @@ RelativeFile name = packageName.length() == 0 ? new RelativeFile(relativeName) : new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName); - return getFileForInput(location, name); + return getFileForInput(location, name, getKindForName(name.path)); } - private JavaFileObject getFileForInput(Location location, RelativeFile name) throws IOException { - Iterable<? extends File> path = getLocation(location); - if (path == null) + private JavaFileObject.Kind getKindForName(String name) { + for (JavaFileObject.Kind k: JavaFileObject.Kind.values()) { + if (k != JavaFileObject.Kind.OTHER && name.endsWith(k.extension)) { + return k; + } + } + return JavaFileObject.Kind.OTHER; + } + + private JavaFileObject getFileForInput(Location location, RelativeFile name, + JavaFileObject.Kind kind) throws IOException { + Iterable<? extends PathEntry> entries = getEntriesForLocation(location); + if (entries == null) return null; - for (File dir: path) { + for (PathEntry e: entries) { + if (kind != null && !e.kinds.contains(kind)) + continue; + File dir = e.file; if (dir.isDirectory()) { File f = name.getFile(dir); if (f.exists()) @@ -917,7 +1126,6 @@ if (a.contains(name)) { return a.getFileObject(name.dirname(), name.basename()); } - } } @@ -975,12 +1183,15 @@ } else if (location == SOURCE_OUTPUT) { dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir()); } else { - Iterable<? extends File> path = paths.getPathForLocation(location); dir = null; - for (File f: path) { - dir = f; - break; + Iterable<? extends PathEntry> path = getEntriesForLocation(location); + if (path != null) { + for (PathEntry e: path) { + dir = e.file; + break; + } } + //System.err.println("JavacFileManager.getFileForOutput location:" + location + " path:" + toString(path) + " dir:" + dir); } File file = fileName.getFile(dir); // null-safe @@ -1047,15 +1258,71 @@ return new File(arg); } - public Iterable<? extends File> getLocation(Location location) { + public Iterable<File> getLocation(Location location) { nullCheck(location); paths.lazy(); + if (location == CLASS_OUTPUT) { - return (getClassOutDir() == null ? null : List.of(getClassOutDir())); - } else if (location == SOURCE_OUTPUT) { - return (getSourceOutDir() == null ? null : List.of(getSourceOutDir())); - } else - return paths.getPathForLocation(location); + File dir = getClassOutDir(); + return (dir == null ? null : List.of(dir)); + } + + if (location == SOURCE_OUTPUT) { + File dir = getSourceOutDir(); + return (dir == null ? null : List.of(dir)); + } + + + final Iterable<? extends PathEntry> entries; + if (location instanceof PathLocation) + entries = ((PathLocation) location).path; + else + entries = paths.getPathForLocation(location); + + if (entries == null) + return null; + + // wrap the natural PathEntry iterator with one that just returns the file values + return new Iterable<File>() { + public Iterator<File> iterator() { + return new Iterator<File>() { + public boolean hasNext() { + return iter.hasNext(); + } + + public File next() { + return iter.next().file; + } + + public void remove() { + iter.remove(); + } + + final Iterator<? extends PathEntry> iter = entries.iterator(); + }; + } + }; + } + + Iterable<PathEntry> getEntriesForLocation(Location location) { + nullCheck(location); + + if (location instanceof PathLocation) + return ((PathLocation) location).path; + + paths.lazy(); + + if (location == CLASS_OUTPUT) { + File dir = getClassOutDir(); + return (dir == null ? null : List.of(paths.new PathEntry(dir))); + } + + if (location == SOURCE_OUTPUT) { + File dir = getSourceOutDir(); + return (dir == null ? null : List.of(paths.new PathEntry(dir))); + } + + return paths.getPathForLocation(location); } private File getClassOutDir() {
--- a/src/share/classes/com/sun/tools/javac/file/Paths.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/file/Paths.java Fri Nov 06 13:20:18 2009 -0800 @@ -27,15 +27,16 @@ import java.io.File; import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.Collection; -import java.util.Collections; import java.util.LinkedHashSet; import java.util.zip.ZipFile; import javax.tools.JavaFileManager.Location; +import javax.tools.JavaFileObject; import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.util.Context; @@ -131,6 +132,8 @@ p = computeAnnotationProcessorPath(); else if (location == SOURCE_PATH) p = computeSourcePath(); + else if (location == MODULE_PATH) + p = computeModulePath(); else // no defaults for other paths p = null; @@ -154,22 +157,6 @@ } } - public Collection<File> bootClassPath() { - lazy(); - return Collections.unmodifiableCollection(getPathForLocation(PLATFORM_CLASS_PATH)); - } - public Collection<File> userClassPath() { - lazy(); - return Collections.unmodifiableCollection(getPathForLocation(CLASS_PATH)); - } - public Collection<File> sourcePath() { - lazy(); - Path p = getPathForLocation(SOURCE_PATH); - return p == null || p.size() == 0 - ? null - : Collections.unmodifiableCollection(p); - } - boolean isBootClassPathRtJar(File file) { return file.equals(bootClassPathRtJar); } @@ -208,11 +195,84 @@ return entries; } - private class Path extends LinkedHashSet<File> { + static class PathLocation implements Location { + PathLocation(Path p) { + path = p; + name = "pathLocation#" + (count++) + p; + } + + PathLocation(Path p, String name) { + path = p; + this.name = name; + } + + final Path path; + + public String getName() { + return name; + } + + public boolean isOutputLocation() { + return false; + } + + @Override + public String toString() { + return getName(); + } + + final String name; + static int count; + } + + class PathEntry { + PathEntry(File file) { + this(file, allKinds); + } + + PathEntry(File file, Set<JavaFileObject.Kind> kinds) { + file.getClass(); // null check + kinds.getClass(); // null check + this.file = file; + this.canonFile = fsInfo.getCanonicalFile(file); + this.kinds = kinds; + } + + @Override + public boolean equals(Object other) { + if (this == other) + return true; + if (!(other instanceof PathEntry)) + return false; + PathEntry o = (PathEntry) other; + return canonFile.equals(o.canonFile) && kinds.equals(o.kinds); + } + + @Override + public int hashCode() { + return canonFile.hashCode() + kinds.hashCode(); + } + + @Override + public String toString() { + if (kinds.equals(allKinds)) + return file.getPath(); + else + return "" + file + kinds; + } + + final File file; + final File canonFile; + final Set<JavaFileObject.Kind> kinds; + } + + private static final Set<JavaFileObject.Kind> allKinds = + EnumSet.allOf(JavaFileObject.Kind.class); + + class Path extends LinkedHashSet<PathEntry> { private static final long serialVersionUID = 0; private boolean expandJarClassPaths = false; - private Set<File> canonicalValues = new HashSet<File>(); public Path expandJarClassPaths(boolean x) { expandJarClassPaths = x; @@ -227,8 +287,18 @@ return this; } - public Path() { super(); } + /** Notional set of acceptable file kinds for this type of path entry. */ + private Set<JavaFileObject.Kind> acceptedKinds = EnumSet.allOf(JavaFileObject.Kind.class); + public Path acceptKinds(Set<JavaFileObject.Kind> kinds) { + acceptedKinds = kinds; + return this; + } + + /** Add all the jar files found in one or more directories. + * @param dirs one or more directories separated by path separator char + * @param whether to generate a warning if a given directory does not exist + */ public Path addDirectories(String dirs, boolean warn) { if (dirs != null) for (File dir : getPathEntries(dirs)) @@ -236,10 +306,18 @@ return this; } + /** Add all the jar files found in one or more directories. + * Warnings about non-existent directories are given iff Paths.warn is set. + * @param dirs one or more directories separated by path separator char + */ public Path addDirectories(String dirs) { return addDirectories(dirs, warn); } + /** Add all the jar files found in a directory. + * @param dirs one or more directories separated by path separator char + * @param whether to generate a warning if a given directory does not exist + */ private void addDirectory(File dir, boolean warn) { if (!dir.isDirectory()) { if (warn) @@ -257,6 +335,10 @@ } } + /** Add directories and archive files. + * @param files one or more directories and archive files separated by path separator char + * @param whether to generate a warning if a given entry does not exist + */ public Path addFiles(String files, boolean warn) { if (files != null) for (File file : getPathEntries(files, emptyPathDefault)) @@ -264,13 +346,21 @@ return this; } + /** Add directories and archive files. + * Warnings about non-existent directories are given iff Paths.warn is set. + * @param files one or more directories and archive files separated by path separator char + */ public Path addFiles(String files) { return addFiles(files, warn); } + /** Add a directory or archive file. + * @param directory or archive file to be added + * @param whether to generate a warning if the file does not exist + */ public void addFile(File file, boolean warn) { - File canonFile = fsInfo.getCanonicalFile(file); - if (contains(file) || canonicalValues.contains(canonFile)) { + PathEntry entry = new PathEntry(file); + if (contains(entry)) { /* Discard duplicates and avoid infinite recursion */ return; } @@ -300,8 +390,7 @@ /* Now what we have left is either a directory or a file name confirming to archive naming convention */ - super.add(file); - canonicalValues.add(canonFile); + super.add(entry); if (expandJarClassPaths && fsInfo.exists(file) && fsInfo.isFile(file)) addJarClassPath(file, warn); @@ -320,6 +409,19 @@ log.error("error.reading.file", jarFile, e.getLocalizedMessage()); } } + + void addAll(Iterable<PathEntry> entries, Set<JavaFileObject.Kind> kinds) { + for (PathEntry e: entries) { + if (kinds.containsAll(e.kinds)) + add(e); + else { + Set<JavaFileObject.Kind> k = EnumSet.copyOf(kinds); + k.retainAll(e.kinds); + if (!k.isEmpty()) + add(new PathEntry(e.file, k)); + } + } + } } private Path computeBootClassPath() { @@ -388,6 +490,14 @@ return new Path().addFiles(sourcePathArg); } + private Path computeModulePath() { + String modulePathArg = options.get(MODULEPATH); + if (modulePathArg == null) + return null; + + return new Path().addFiles(modulePathArg); + } + private Path computeAnnotationProcessorPath() { String processorPathArg = options.get(PROCESSORPATH); if (processorPathArg == null) @@ -399,7 +509,7 @@ /** The actual effective locations searched for sources */ private Path sourceSearchPath; - public Collection<File> sourceSearchPath() { + Collection<PathEntry> sourceSearchPath() { if (sourceSearchPath == null) { lazy(); Path sourcePath = getPathForLocation(SOURCE_PATH); @@ -412,7 +522,7 @@ /** The actual effective locations searched for classes */ private Path classSearchPath; - public Collection<File> classSearchPath() { + Collection<PathEntry> classSearchPath() { if (classSearchPath == null) { lazy(); Path bootClassPath = getPathForLocation(PLATFORM_CLASS_PATH); @@ -427,7 +537,7 @@ /** The actual effective locations for non-source, non-class files */ private Path otherSearchPath; - Collection<File> otherSearchPath() { + Collection<PathEntry> otherSearchPath() { if (otherSearchPath == null) { lazy(); Path userClassPath = getPathForLocation(CLASS_PATH);
--- a/src/share/classes/com/sun/tools/javac/file/RegularFileObject.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/file/RegularFileObject.java Fri Nov 06 13:20:18 2009 -0800 @@ -39,6 +39,7 @@ import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetDecoder; +import java.util.Arrays; import javax.tools.JavaFileObject; /** @@ -167,6 +168,25 @@ return null; } + protected String inferModuleTag(String pkgName) { + File fn = file.getAbsoluteFile(); + //System.err.println("RegularFileObject.inferModuleTag.args " + fn + " '" + pkgName + "'"); + fn = fn.getParentFile(); + if (pkgName.length() > 0) { + String[] pn = pkgName.replace('/', '.').split("\\."); + //System.err.println("RegularFileObject.inferModuleTag.pn " + Arrays.asList(pn) + " " + pn.length); + for (int i = pn.length - 1; i >= 0; i--) { + String n = fn.getName(); + if (n.equalsIgnoreCase(pn[i])) + fn = fn.getParentFile(); + else + return null; + } + } + //System.err.println("RegularFileObject.inferModuleTag.result " + (fn == null ? null : fn.getName())); + return (fn == null ? null : fn.getName()); + } + @Override public boolean isNameCompatible(String cn, JavaFileObject.Kind kind) { cn.getClass();
--- a/src/share/classes/com/sun/tools/javac/file/ZipArchive.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/file/ZipArchive.java Fri Nov 06 13:20:18 2009 -0800 @@ -250,6 +250,12 @@ String entryName = entry.getName(); return removeExtension(entryName).replace('/', '.'); } + + @Override + protected String inferModuleTag(String binaryName) { + File zf = new File(zarch.zfile.getName()); + return removeExtension(zf.getName()); + } @Override public boolean isNameCompatible(String cn, JavaFileObject.Kind k) {
--- a/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java Fri Nov 06 13:20:18 2009 -0800 @@ -248,6 +248,9 @@ else return entry.getName(); } + protected String inferModuleTag(String binaryName) { + return removeExtension(zfIndex.getZipFile().getName()); + } } }
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java Fri Nov 06 13:20:18 2009 -0800 @@ -25,6 +25,11 @@ package com.sun.tools.javac.jvm; +import java.util.Locale; +import javax.lang.model.element.ModuleElement; + +import com.sun.tools.javac.api.Formattable; +import com.sun.tools.javac.api.Messages; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.util.Name; @@ -80,6 +85,7 @@ public final static int CONSTANT_Methodref = 10; public final static int CONSTANT_InterfaceMethodref = 11; public final static int CONSTANT_NameandType = 12; + public final static int CONSTANT_ModuleId = 13; public final static int MAX_PARAMETERS = 0xff; public final static int MAX_DIMENSIONS = 0xff; @@ -170,4 +176,53 @@ return name.hashCode() * type.hashCode(); } } + + // move to top level in code or jvm? + public static class ModuleId implements ModuleElement.ModuleId, Formattable { + public final Name name; + public final Name version; + + public ModuleId(Name name, Name version) { + this.name = name; + this.version = version; + } + + public CharSequence getName() { + return name; + } + + public CharSequence getVersion() { + return version; + } + + @Override + public boolean equals(Object other) { + return + other instanceof ModuleId && + name == ((ModuleId) other).name && + version.equals(((ModuleId) other).version); + } + + @Override + public int hashCode() { + if (version == null) + return name.hashCode(); + else + return name.hashCode() * version.hashCode(); + } + + @Override // for debugging + public String toString() { + return "ModuleId[" + name + (version == null ? "" : "@" + version) + "]"; + } + + @Override // for use in diagnostics + public String toString(Locale locale, Messages messages) { + return (version == null ? name.toString() : name + "@" + version); + } + + public String getKind() { + return "ModuleId"; + } + } }
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Nov 06 13:20:18 2009 -0800 @@ -32,6 +32,7 @@ import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import javax.lang.model.SourceVersion; @@ -100,6 +101,10 @@ */ boolean allowAnnotations; + /** Switch: allow modules + */ + boolean allowModules; + /** Switch: preserve parameter names from the variable table. */ public boolean saveParameterNames; @@ -261,6 +266,7 @@ allowGenerics = source.allowGenerics(); allowVarargs = source.allowVarargs(); allowAnnotations = source.allowAnnotations(); + allowModules = source.allowModules(); saveParameterNames = options.get("save-parameter-names") != null; cacheCompletionFailure = options.get("dev") == null; preferSource = "source".equals(options.get("-Xprefer")); @@ -419,6 +425,7 @@ case CONSTANT_NameandType: case CONSTANT_Integer: case CONSTANT_Float: + case CONSTANT_ModuleId: bp = bp + 4; break; case CONSTANT_Long: @@ -487,6 +494,11 @@ case CONSTANT_Double: poolObj[i] = new Double(getDouble(index + 1)); break; + case CONSTANT_ModuleId: + poolObj[i] = new ModuleId( + readInternalName(getChar(index + 1)), + readName(getChar(index + 3))); + break; default: throw badClassFile("bad.const.pool.tag", Byte.toString(tag)); } @@ -535,6 +547,29 @@ return (Name) (readPool(i)); } + /** Read module id. + */ + ModuleId readModuleId(int i) { + return (ModuleId) (readPool(i)); + } + + Name readInternalName(int i) { + int index = poolIdx[i]; + return names.fromUtf(internalize(buf, index + 3, getChar(index + 1))); + } + + /** Read module name. + * The module name is in a CONSTANT_Class_info, but we don't want to + * enter a class for it, so can't use readClassSymbol. + */ + Name readModuleInfoName(int i) { + int index = poolIdx[i]; + assert index != 0; + byte tag = buf[index]; + assert tag == CONSTANT_Class; + return readInternalName(getChar(index+1)); + } + /************************************************************************ * Reading Types ***********************************************************************/ @@ -1085,6 +1120,75 @@ } }, + // v51 module attributes + + new AttributeReader(names.Module, V51, CLASS_OR_MEMBER_ATTRIBUTE) { + @Override + boolean accepts(AttributeKind kind) { + return super.accepts(kind) && allowModules; + } + void read(Symbol sym, int attrLen) { + if (sym.kind == TYP && sym.owner.kind == MDL) { + ModuleSymbol msym = (ModuleSymbol) sym.owner; + ModuleId mid = readModuleId(nextChar()); + msym.name = msym.fullname = mid.name; + msym.version = mid.version; + } + } + }, + + new AttributeReader(names.ModulePermits, V51, CLASS_OR_MEMBER_ATTRIBUTE) { + @Override + boolean accepts(AttributeKind kind) { + return super.accepts(kind) && allowModules; + } + void read(Symbol sym, int attrLen) { + if (sym.kind == TYP && sym.owner.kind == MDL) { + ModuleSymbol msym = (ModuleSymbol) sym.owner; + int num = nextChar(); + for (int i = 0; i < num; i++) + msym.permits.append(readName(nextChar())); + } + } + }, + + new AttributeReader(names.ModuleProvides, V51, CLASS_OR_MEMBER_ATTRIBUTE) { + @Override + boolean accepts(AttributeKind kind) { + return super.accepts(kind) && allowModules; + } + void read(Symbol sym, int attrLen) { + if (sym.kind == TYP && sym.owner.kind == MDL) { + ModuleSymbol msym = (ModuleSymbol) sym.owner; + int num = nextChar(); + for (int i = 0; i < num; i++) + msym.provides.append(readModuleId(nextChar())); + } + } + }, + + new AttributeReader(names.ModuleRequires, V51, CLASS_OR_MEMBER_ATTRIBUTE) { + @Override + boolean accepts(AttributeKind kind) { + return super.accepts(kind) && allowModules; + } + void read(Symbol sym, int attrLen) { + if (sym.kind == TYP && sym.owner.kind == MDL) { + ModuleSymbol msym = (ModuleSymbol) sym.owner; + int numRequires = nextChar(); + for (int r = 0; r < numRequires; r++) { + ModuleId id = readModuleId(nextChar()); + ListBuffer<Name> flags = new ListBuffer<Name>(); + int numFlags = nextChar(); + for (int f = 0; f < numFlags; f++) { + flags.append(readName(nextChar())); + } + msym.requires.put(id, new ModuleRequires(id, flags.toList())); + } + } + } + }, + // v51 attributes new AttributeReader(names.RuntimeVisibleTypeAnnotations, V51, CLASS_OR_MEMBER_ATTRIBUTE) { void read(Symbol sym, int attrLen) { @@ -1992,11 +2096,20 @@ long flags = adjustClassFlags(nextChar()); if (c.owner.kind == PCK) c.flags_field = flags; - // read own class name and check that it matches - ClassSymbol self = readClassSymbol(nextChar()); - if (c != self) - throw badClassFile("class.file.wrong.class", - self.flatname); + if (c.owner.kind == MDL) { + //System.err.println("ClassReader.readClass getModuleInfoName"); + c.fullname = c.flatname = readModuleInfoName(nextChar()); + c.name = Convert.shortName(c.fullname); + assert c.name == names.module_info; + } else { + // read own class name and check that it matches + ClassSymbol self = readClassSymbol(nextChar()); + if (c != self) { + //System.err.println("ClassReader.readClass c=" + c + " self=" + self); + throw badClassFile("class.file.wrong.class", + self.flatname); + } + } // class attributes must be read before class // skip ahead to read class attributes @@ -2233,6 +2346,16 @@ } catch (IOException ex) { throw new CompletionFailure(sym, ex.getLocalizedMessage()).initCause(ex); } + } else if (sym.kind == MDL) { + //System.err.println("ClassReader.complete module " + sym + " " + sym.name); + ModuleSymbol msym = (ModuleSymbol) sym; + msym.permits = new ListBuffer<Name>(); + msym.provides = new ListBuffer<ModuleId>(); + msym.requires = new LinkedHashMap<ModuleId,ModuleRequires>(); + msym.module_info.members_field = new Scope(sym); // or Scope.empty? + fillIn(msym.module_info); + assert msym.name != null; + //System.err.println("ClassReader.completed module " + sym + " " + sym.name); } if (!filling && !suppressFlush) annotate.flush(); // finish attaching annotations @@ -2444,7 +2567,9 @@ * (2) we have one of the other kind, and the given class file * is older. */ - protected void includeClassFile(PackageSymbol p, JavaFileObject file) { + protected void includeClassFile(PackageSymbol p, JavaFileObject file, Name simpleName) { + boolean isPackageInfo = simpleName == names.package_info; + if ((p.flags_field & EXISTS) == 0) for (Symbol q = p; q != null && q.kind == PCK; q = q.owner) q.flags_field |= EXISTS; @@ -2454,18 +2579,14 @@ seen = CLASS_SEEN; else seen = SOURCE_SEEN; - String binaryName = fileManager.inferBinaryName(currentLoc, file); - int lastDot = binaryName.lastIndexOf("."); - Name classname = names.fromString(binaryName.substring(lastDot + 1)); - boolean isPkgInfo = classname == names.package_info; - ClassSymbol c = isPkgInfo - ? p.package_info - : (ClassSymbol) p.members_field.lookup(classname).sym; + ClassSymbol c = + isPackageInfo ? p.package_info + : (ClassSymbol) p.members_field.lookup(simpleName).sym; if (c == null) { - c = enterClass(classname, p); + c = enterClass(simpleName, p); if (c.classfile == null) // only update the file if's it's newly created c.classfile = file; - if (isPkgInfo) { + if (isPackageInfo) { p.package_info = c; } else { if (c.owner == p) // it might be an inner class @@ -2486,7 +2607,7 @@ * file or a class file when both are present. May be overridden * by subclasses. */ - protected JavaFileObject preferredFileObject(JavaFileObject a, + public JavaFileObject preferredFileObject(JavaFileObject a, JavaFileObject b) { if (preferSource) @@ -2513,10 +2634,14 @@ protected void extraFileActions(PackageSymbol pack, JavaFileObject fe) { } - protected Location currentLoc; // FIXME + public void setPathLocation(Location pathLocation) { + this.pathLocation = pathLocation; + } + private Location pathLocation; private boolean verbosePath = true; + /** Load directory of package into members scope. */ private void fillIn(PackageSymbol p) throws IOException { @@ -2531,6 +2656,16 @@ EnumSet.of(JavaFileObject.Kind.CLASS), false)); + if (pathLocation != null) { + //System.err.println("ClassReader.fillIn using pathLocation " + pathLocation); + fillIn(p, pathLocation, + fileManager.list(pathLocation, + packageName, + EnumSet.allOf(JavaFileObject.Kind.class), + false)); + return; + } + Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds); classKinds.remove(JavaFileObject.Kind.SOURCE); boolean wantClassFiles = !classKinds.isEmpty(); @@ -2597,18 +2732,17 @@ Location location, Iterable<JavaFileObject> files) { - currentLoc = location; for (JavaFileObject fo : files) { switch (fo.getKind()) { case CLASS: case SOURCE: { - // TODO pass binaryName to includeClassFile - String binaryName = fileManager.inferBinaryName(currentLoc, fo); + String binaryName = fileManager.inferBinaryName(location, fo); String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1); if (SourceVersion.isIdentifier(simpleName) || fo.getKind() == JavaFileObject.Kind.CLASS || - simpleName.equals("package-info")) - includeClassFile(p, fo); + simpleName.contentEquals(names.package_info)) { + includeClassFile(p, fo, names.fromString(simpleName)); + } break; } default: @@ -2638,7 +2772,6 @@ void complete(ClassSymbol sym) throws CompletionFailure; } - /** * A subclass of JavaFileObject for the sourcefile attribute found in a classfile. * The attribute is only the last component of the original filename, so is unlikely @@ -2721,6 +2854,11 @@ protected String inferBinaryName(Iterable<? extends File> path) { return flatname.toString(); } + + @Override + protected String inferModuleTag(String binaryName) { + return null; + } @Override public boolean isNameCompatible(String simpleName, JavaFileObject.Kind kind) {
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Fri Nov 06 13:20:18 2009 -0800 @@ -29,8 +29,8 @@ import java.util.Set; import java.util.HashSet; +import javax.tools.FileObject; import javax.tools.JavaFileManager; -import javax.tools.FileObject; import javax.tools.JavaFileObject; import com.sun.tools.javac.code.*; @@ -39,6 +39,9 @@ import com.sun.tools.javac.file.BaseFileObject; import com.sun.tools.javac.util.*; +import java.util.Map; +import javax.tools.JavaFileManager.Location; +import javax.tools.ModuleFileManager; import static com.sun.tools.javac.code.BoundKind.*; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; @@ -529,8 +532,18 @@ if (type.tag == CLASS) enterInner((ClassSymbol)type.tsym); poolbuf.appendByte(CONSTANT_Class); poolbuf.appendChar(pool.put(xClassName(type))); + } else if (value instanceof ModuleSymbol) { + ModuleSymbol sym = (ModuleSymbol) value; + poolbuf.appendByte(CONSTANT_ModuleId); + poolbuf.appendChar(pool.put(names.fromUtf(externalize(sym.flatName())))); + poolbuf.appendChar(sym.version == null ? 0 : pool.put(sym.version)); + } else if (value instanceof ModuleId) { + ModuleId mid = (ModuleId)value; + poolbuf.appendByte(CONSTANT_ModuleId); + poolbuf.appendChar(pool.put(mid.name)); + poolbuf.appendChar(mid.version == null ? 0 : pool.put(mid.version)); } else { - assert false : "writePool " + value; + throw new AssertionError("writePool " + value); } i++; } @@ -1006,6 +1019,76 @@ } /********************************************************************** + * Writing module attributes + **********************************************************************/ + + /** Write the Module attribute if needed. + * Returns the number of attributes written (0 or 1). + */ + int writeModuleAttribute(ClassSymbol c) { + if (c.modle == null) + return 0; + + int alenIdx = writeAttr(names.Module); + databuf.appendChar(pool.put(c.modle)); + endAttr(alenIdx); + return 1; + } + + int writeModuleMetadata(ModuleSymbol sym) { + int n = 0; + + if (sym.provides.size() > 0) { + int alenIdx = writeAttr(names.ModuleProvides); + databuf.appendChar(sym.provides.size()); + for (List<ModuleId> l = sym.provides.elems; l.nonEmpty(); l = l.tail) { + databuf.appendChar(pool.put(l.head)); + } + endAttr(alenIdx); + n++; + } + + if (sym.requires.size() > 0) { + int alenIdx = writeAttr(names.ModuleRequires); + databuf.appendChar(sym.requires.size()); + for (Map.Entry<ModuleId,ModuleRequires> e: sym.requires.entrySet()) { + ModuleId m = e.getKey(); + ModuleRequires mr = e.getValue(); + databuf.appendChar(pool.put(m)); + databuf.appendChar(mr.flags.size()); + for (List<Name> l = mr.flags; l.nonEmpty(); l = l.tail) { + databuf.appendChar(pool.put(l.head)); + } + } + endAttr(alenIdx); + n++; + } + + if (sym.permits.size() > 0) { + int alenIdx = writeAttr(names.ModulePermits); + databuf.appendChar(sym.permits.size()); + for (Name name: sym.permits) { + databuf.appendChar(pool.put(name)); + } + endAttr(alenIdx); + n++; + } + + if (sym.className != null) { + int alenIdx = writeAttr(names.ModuleClass); + databuf.appendChar(pool.put(sym.className)); + databuf.appendChar(sym.classFlags.size()); + for (Name name: sym.classFlags) { + databuf.appendChar(pool.put(name)); + } + endAttr(alenIdx); + n++; + } + + return n; + } + +/********************************************************************** * Writing Objects **********************************************************************/ @@ -1022,6 +1105,7 @@ if (c.type.tag != CLASS) return; // arrays if (pool != null && // pool might be null if called from xClassName c.owner.kind != PCK && + c.owner.kind != MDL && (innerClasses == null || !innerClasses.contains(c))) { // log.errWriter.println("enter inner " + c);//DEBUG if (c.owner.kind == TYP) enterInner((ClassSymbol)c.owner); @@ -1588,9 +1672,25 @@ public JavaFileObject writeClass(ClassSymbol c) throws IOException, PoolOverflow, StringOverflow { + String name = (c.owner.kind == MDL ? c.name : c.flatname).toString(); + + Location outLocn; + if (fileManager instanceof ModuleFileManager && fileManager.hasLocation(CLASS_OUTPUT)) { + ModuleFileManager mfm = (ModuleFileManager) fileManager; + String pkgName = c.owner.kind == MDL ? "" : c.packge().fullname.toString(); + try { + outLocn = mfm.getModuleLocation(CLASS_OUTPUT, c.sourcefile, pkgName); + } catch (IllegalArgumentException e) { + throw new AssertionError(); + } + } else + // Note: when CLASS_OUTPUT is not set, getJavaFileForOutput will + // default to writing the output in the same directory as the sourcefile + outLocn = CLASS_OUTPUT; + JavaFileObject outFile - = fileManager.getJavaFileForOutput(CLASS_OUTPUT, - c.flatname.toString(), + = fileManager.getJavaFileForOutput(outLocn, + name, JavaFileObject.Kind.CLASS, c.sourcefile); OutputStream out = outFile.openOutputStream(); @@ -1709,6 +1809,10 @@ acount += writeJavaAnnotations(c.getAnnotationMirrors()); acount += writeTypeAnnotations(c.typeAnnotations); acount += writeEnclosingMethodAttribute(c); + if (c.owner.kind == MDL) { + acount += writeModuleAttribute(c); + acount += writeModuleMetadata(c.modle); + } poolbuf.appendInt(JAVA_MAGIC); poolbuf.appendChar(target.minorVersion);
--- a/src/share/classes/com/sun/tools/javac/jvm/Target.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/jvm/Target.java Fri Nov 06 13:20:18 2009 -0800 @@ -306,4 +306,8 @@ public boolean hasEnclosingMethodAttribute() { return compareTo(JDK1_5) >= 0 || this == JSR14; } + + public boolean useModules() { + return compareTo(JDK1_7) >= 0; + } }
--- a/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Fri Nov 06 13:20:18 2009 -0800 @@ -575,8 +575,7 @@ */ protected JCCompilationUnit parse(JavaFileObject filename, CharSequence content) { long msec = now(); - JCCompilationUnit tree = make.TopLevel(List.<JCTree.JCAnnotation>nil(), - null, List.<JCTree>nil()); + JCCompilationUnit tree = make.TopLevel(List.<JCTree>nil()); if (content != null) { if (verbose) { printVerbose("parsing.started", filename); @@ -649,8 +648,7 @@ tree = (tree == null) ? make.Ident(names.fromString(s)) : make.Select(tree, names.fromString(s)); } - JCCompilationUnit toplevel = - make.TopLevel(List.<JCTree.JCAnnotation>nil(), null, List.<JCTree>nil()); + JCCompilationUnit toplevel = make.TopLevel(List.<JCTree>nil()); toplevel.packge = syms.unnamedPackage; return attr.attribIdent(tree, toplevel); } finally { @@ -708,11 +706,8 @@ /** Complete compiling a source file that has been accessed * by the class file reader. * @param c The class the source file of which needs to be compiled. - * @param filename The name of the source file. - * @param f An input stream that reads the source file. */ public void complete(ClassSymbol c) throws CompletionFailure { -// System.err.println("completing " + c);//DEBUG if (completionFailureName == c.fullname) { throw new CompletionFailure(c, "user-selected completion failure by class name"); } @@ -724,7 +719,7 @@ tree = parse(filename, filename.getCharContent(false)); } catch (IOException e) { log.error("error.reading.file", filename, e); - tree = make.TopLevel(List.<JCTree.JCAnnotation>nil(), null, List.<JCTree>nil()); + tree = make.TopLevel(List.<JCTree>nil()); } finally { log.useSource(prev); } @@ -742,17 +737,28 @@ } if (enter.getEnv(c) == null) { - boolean isPkgInfo = + boolean isPackageInfo = tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE); - if (isPkgInfo) { + boolean isModuleInfo = + tree.sourcefile.isNameCompatible("module-info", + JavaFileObject.Kind.SOURCE); + if (isPackageInfo) { if (enter.getEnv(tree.packge) == null) { JCDiagnostic diag = diagFactory.fragment("file.does.not.contain.package", c.location()); throw reader.new BadClassFile(c, filename, diag); } - } else { + } else if (isModuleInfo) { + if (enter.getEnv(tree.modle) == null) { + JCDiagnostic diag = + diagFactory.fragment("file.does.not.contain.module", + c.location()); + throw reader.new BadClassFile(c, filename, diag); + } + } + else { JCDiagnostic diag = diagFactory.fragment("file.doesnt.contain.class", c.getQualifiedName()); @@ -791,6 +797,7 @@ { if (processors != null && processors.iterator().hasNext()) explicitAnnotationProcessingRequested = true; + // as a JavaCompiler can only be used once, throw an exception if // it has been used before. if (hasBeenUsed) @@ -1128,7 +1135,7 @@ env.enclClass.sym.sourcefile : env.toplevel.sourcefile); try { - attr.attribClass(env.tree.pos(), env.enclClass.sym); + attr.analyze(env); compileStates.put(env, CompileState.ATTR); } finally { @@ -1287,7 +1294,7 @@ make.at(Position.FIRSTPOS); TreeMaker localMake = make.forToplevel(env.toplevel); - if (env.tree instanceof JCCompilationUnit) { + if (env.tree.getTag() == JCTree.TOPLEVEL || env.tree.getTag() == JCTree.MODULE) { if (!(stubOutput || sourceOutput || printFlat)) { if (shouldStop(CompileState.LOWER)) return;
--- a/src/share/classes/com/sun/tools/javac/main/Main.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/main/Main.java Fri Nov 06 13:20:18 2009 -0800 @@ -242,6 +242,7 @@ return null; String sourceString = options.get("-source"); + Source source = (sourceString != null) ? Source.lookup(sourceString) : Source.DEFAULT; @@ -511,6 +512,7 @@ public static void useRawMessages(boolean enable) { if (enable) { messages = new JavacMessages(javacBundleName) { + @Override public String getLocalizedString(String key, Object... args) { return key; }
--- a/src/share/classes/com/sun/tools/javac/main/OptionName.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/main/OptionName.java Fri Nov 06 13:20:18 2009 -0800 @@ -51,6 +51,7 @@ XBOOTCLASSPATH_PREPEND("-Xbootclasspath/p:"), XBOOTCLASSPATH_APPEND("-Xbootclasspath/a:"), XBOOTCLASSPATH("-Xbootclasspath:"), + MODULEPATH("-modulepath"), EXTDIRS("-extdirs"), DJAVA_EXT_DIRS("-Djava.ext.dirs="), ENDORSEDDIRS("-endorseddirs"),
--- a/src/share/classes/com/sun/tools/javac/main/RecognizedOptions.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/main/RecognizedOptions.java Fri Nov 06 13:20:18 2009 -0800 @@ -130,6 +130,7 @@ XBOOTCLASSPATH_PREPEND, XBOOTCLASSPATH_APPEND, XBOOTCLASSPATH, + MODULEPATH, EXTDIRS, DJAVA_EXT_DIRS, ENDORSEDDIRS, @@ -177,6 +178,7 @@ XBOOTCLASSPATH_PREPEND, XBOOTCLASSPATH_APPEND, XBOOTCLASSPATH, + MODULEPATH, EXTDIRS, DJAVA_EXT_DIRS, ENDORSEDDIRS, @@ -314,6 +316,15 @@ return super.process(options, "-bootclasspath", arg); } }, + new Option(MODULEPATH, "opt.arg.path", "opt.modulepath") { + // TEMP HACK FOR JIGSAW TO AUTO-DEFAULT -source TO 7 WHEN -modulepath + // IS USED. REMOVE WHEN -source 7 IS THE DEFAULT + @Override + public boolean process(Options options, String option, String arg) { + options.put("jigsaw.source", "7"); + return super.process(options, option, arg); + } + }, new Option(EXTDIRS, "opt.arg.dirs", "opt.extdirs"), new XOption(DJAVA_EXT_DIRS, "opt.arg.dirs", "opt.extdirs") { @Override @@ -588,6 +599,10 @@ helper.error("err.file.not.file", f); return true; } + // TEMP HACK FOR JIGSAW TO AUTO-DEFAULT -source TO 7 WHEN + // module-info.java USED. REMOVE WHEN -source 7 IS THE DEFAULT + if (f.getName().equals("module-info.java")) + options.put("jigsaw.source", "7"); helper.addFile(f); } else
--- a/src/share/classes/com/sun/tools/javac/model/JavacElements.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/model/JavacElements.java Fri Nov 06 13:20:18 2009 -0800 @@ -224,8 +224,8 @@ Symbol sym = cast(Symbol.class, e); class Vis extends JCTree.Visitor { List<JCAnnotation> result = null; - public void visitTopLevel(JCCompilationUnit tree) { - result = tree.packageAnnotations; + public void visitPackage(JCPackageDecl tree) { + result = tree.annots; } public void visitClassDef(JCClassDecl tree) { result = tree.mods.annotations;
--- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Nov 06 13:20:18 2009 -0800 @@ -133,6 +133,8 @@ this.allowAnnotations = source.allowAnnotations(); this.allowDiamond = source.allowDiamond(); this.allowTypeAnnotations = source.allowTypeAnnotations(); + this.allowModules = source.allowModules(); + this.allowImportsBeforePackage = source.allowImportsBeforePackage(); this.keepDocComments = keepDocComments; if (keepDocComments) docComments = new HashMap<JCTree,String>(); @@ -181,6 +183,14 @@ */ boolean allowTypeAnnotations; + /** Switch: should we recognize modules? + */ + boolean allowModules; + + /** Switch: should we recognize import before package? + */ + boolean allowImportsBeforePackage; + /** Switch: should we keep docComments? */ boolean keepDocComments; @@ -478,7 +488,7 @@ accept(IDENTIFIER); return names.error; } -} + } /** * Qualident = Ident { DOT Ident } @@ -494,6 +504,20 @@ } /** + * Qualident = Ident { DOT Ident } + * (used when we've had to lookahead at the first identifier) + */ + public JCExpression qualident(JCExpression head) { + JCExpression t = head; + while (S.token() == DOT) { + int pos = S.pos(); + S.nextToken(); + t = toP(F.at(pos).Select(t, ident())); + } + return t; + } + + /** * Literal = * INTLITERAL * | LONGLITERAL @@ -1642,7 +1666,7 @@ JCClassDecl body = null; if (S.token() == LBRACE) { int pos = S.pos(); - List<JCTree> defs = classOrInterfaceBody(names.empty, false); + List<JCTree> defs = classOrInterfaceBody(names.empty, CLASS); JCModifiers mods = F.at(Position.NOPOS).Modifiers(0); body = toP(F.at(pos).AnonymousClassDef(mods, defs)); } @@ -1729,7 +1753,7 @@ case MONKEYS_AT: case FINAL: { String dc = S.docComment(); - JCModifiers mods = modifiersOpt(); + JCModifiers mods = modifiersOpt(ModuleModifierKind.DISALLOWED); if (S.token() == INTERFACE || S.token() == CLASS || allowEnums && S.token() == ENUM) { @@ -1746,13 +1770,13 @@ } case ABSTRACT: case STRICTFP: { String dc = S.docComment(); - JCModifiers mods = modifiersOpt(); + JCModifiers mods = modifiersOpt(ModuleModifierKind.DISALLOWED); stats.append(classOrInterfaceOrEnumDeclaration(mods, dc)); break; } case INTERFACE: case CLASS: - stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), + stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(ModuleModifierKind.DISALLOWED), S.docComment())); break; case ENUM: @@ -1760,7 +1784,7 @@ if (allowEnums && S.token() == ENUM) { log.error(S.pos(), "local.enum"); stats. - append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), + append(classOrInterfaceOrEnumDeclaration(modifiersOpt(ModuleModifierKind.DISALLOWED), S.docComment())); break; } else if (allowAsserts && S.token() == ASSERT) { @@ -2066,7 +2090,7 @@ JCExpression t = term(EXPR | TYPE); if ((lastmode & TYPE) != 0 && (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM)) - return variableDeclarators(modifiersOpt(), t, stats).toList(); + return variableDeclarators(modifiersOpt(ModuleModifierKind.DISALLOWED), t, stats).toList(); else return moreStatementExpressions(pos, t, stats).toList(); } @@ -2108,15 +2132,23 @@ return List.convert(JCTypeAnnotation.class, annotations); } + enum ModuleModifierKind { DISALLOWED, LOOKAHEAD, ALLOWED }; + /** ModifiersOpt = { Modifier } * Modifier = PUBLIC | PROTECTED | PRIVATE | STATIC | ABSTRACT | FINAL * | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@" * | "@" Annotation */ - JCModifiers modifiersOpt() { - return modifiersOpt(null); + JCModifiers modifiersOpt(ModuleModifierKind mmk) { + return modifiersOpt(mmk, null, null); } - JCModifiers modifiersOpt(JCModifiers partial) { + + JCModifiers modifiersOpt(ModuleModifierKind mmk, Name constrName) { + return modifiersOpt(mmk, null, constrName); + } + + @SuppressWarnings("fallthrough") + JCModifiers modifiersOpt(ModuleModifierKind mmk, JCModifiers partial, Name constrName) { long flags = (partial == null) ? 0 : partial.flags; if (S.deprecatedFlag()) { flags |= Flags.DEPRECATED; @@ -2124,7 +2156,7 @@ } ListBuffer<JCAnnotation> annotations = new ListBuffer<JCAnnotation>(); if (partial != null) annotations.appendList(partial.annotations); - int pos = S.pos(); + int pos = (partial != null ? partial.pos : S.pos()); int lastPos = Position.NOPOS; loop: while (true) { @@ -2142,20 +2174,56 @@ case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break; case STRICTFP : flag = Flags.STRICTFP; break; case MONKEYS_AT : flag = Flags.ANNOTATION; break; + case IDENTIFIER: + if (S.name() != names.module) + break loop; + switch (mmk) { + case DISALLOWED: + break loop; + case LOOKAHEAD: { + if ((flags & (Flags.AccessFlags)) != 0) + break loop; + S.mark(); + try { + S.nextToken(); + if (S.token() == IDENTIFIER) { + Name ident = S.name(); + S.nextToken(); + switch (S.token()) { + case SEMI: + case EQ: + case LBRACKET: + break loop; + case LPAREN: + if (ident == constrName) + break; + break loop; + } + } + } finally { + S.reset(); + } + } + case ALLOWED: + break; + } + flag = Flags.MODULE; + break; default: break loop; } - if ((flags & flag) != 0) log.error(S.pos(), "repeated.modifier"); + if ((flags & flag) != 0) + log.error(S.pos(), "repeated.modifier"); lastPos = S.pos(); S.nextToken(); if (flag == Flags.ANNOTATION) { checkAnnotations(); if (S.token() != INTERFACE) { JCAnnotation ann = annotation(lastPos, AnnotationKind.DEFAULT_ANNO); - // if first modifier is an annotation, set pos to annotation's. - if (flags == 0 && annotations.isEmpty()) - pos = ann.pos; - annotations.append(ann); - lastPos = ann.pos; + // if first modifier is an annotation, set pos to annotation's. + if (flags == 0 && annotations.isEmpty()) + pos = ann.pos; + annotations.append(ann); + lastPos = ann.pos; flag = 0; } } @@ -2336,28 +2404,58 @@ return toP(F.at(pos).VarDef(mods, name, type, null)); } - /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration} + /** CompilationUnit = + * {ImportDeclaration} [ModuleDeclaration] + * [ { "@" Annotation } PACKAGE Qualident ";"] + * {ImportDeclaration} + * {TypeDeclaration} */ public JCTree.JCCompilationUnit parseCompilationUnit() { - int pos = S.pos(); - JCExpression pid = null; + ListBuffer<JCTree> defs = new ListBuffer<JCTree>(); + int cu_pos = S.pos(); + boolean seenImport = false; + + String toplevel_dc = S.docComment(); + + while (S.token() == IMPORT) { + defs.append(importDeclaration()); + seenImport = true; + } + String dc = S.docComment(); + JCModifiers mods = null; - List<JCAnnotation> packageAnnotations = List.nil(); - if (S.token() == MONKEYS_AT) - mods = modifiersOpt(); + if (S.token() == MONKEYS_AT) { + mods = modifiersOpt(ModuleModifierKind.DISALLOWED); + } + + if (S.token() == IDENTIFIER && S.name() == names.module) { + defs.append(moduleDecl(mods, dc)); + dc = null; + } + + if (mods == null && S.token() == MONKEYS_AT) { + dc = S.docComment(); + mods = modifiersOpt(ModuleModifierKind.DISALLOWED); + } if (S.token() == PACKAGE) { + int pos = S.pos(); + if (seenImport && !allowImportsBeforePackage) + log.error(pos, "imports.not.allowed.before.package.in.source", source.name); + List<JCAnnotation> annots = List.nil(); if (mods != null) { checkNoMods(mods.flags); - packageAnnotations = mods.annotations; + annots = mods.annotations; mods = null; + dc = null; } S.nextToken(); - pid = qualident(); + JCExpression pid = qualident(); accept(SEMI); + defs.append(toP(F.at(pos).Package(annots, pid))); } - ListBuffer<JCTree> defs = new ListBuffer<JCTree>(); + boolean checkForImports = true; while (S.token() != EOF) { if (S.pos() <= errorEndPos) { @@ -2369,17 +2467,19 @@ if (checkForImports && mods == null && S.token() == IMPORT) { defs.append(importDeclaration()); } else { - JCTree def = typeDeclaration(mods); + JCTree def = typeDeclaration(mods, dc); if (def instanceof JCExpressionStatement) def = ((JCExpressionStatement)def).expr; defs.append(def); if (def instanceof JCClassDecl) checkForImports = false; mods = null; + dc = null; } } - JCTree.JCCompilationUnit toplevel = F.at(pos).TopLevel(packageAnnotations, pid, defs.toList()); - attach(toplevel, dc); + + JCTree.JCCompilationUnit toplevel = F.at(cu_pos).TopLevel(defs.toList()); + attach(toplevel, toplevel_dc); if (defs.elems.isEmpty()) storeEnd(toplevel, S.prevEndPos()); if (keepDocComments) @@ -2389,6 +2489,152 @@ return toplevel; } + /** + * ModuleDecl = { "@" Annotation } MODULE ModuleId [ ModuleProvides ] '{' { ModuleMetadata } '}' + * ModuleProvides = PROVIDES ModuleIdList + * + * called after MODULE has been seen + */ + JCModuleDecl moduleDecl(JCModifiers mods, String dc) { + int pos = S.pos(); + if (!allowModules) + log.error(pos, "modules.not.supported.in.source", source.name); + List<JCAnnotation> annots = List.nil(); + if (mods != null) { + checkNoMods(mods.flags); + annots = mods.annotations; + mods = null; + } + S.nextToken(); + JCModuleId mid = moduleId(); + List<JCModuleId> provides = null; + List<JCModuleMetadata> metadataList = null; + + if (S.token() == IDENTIFIER && S.name() == names.provides) { + S.nextToken(); + provides = moduleIdList(); + } else + provides = List.nil(); + accept(LBRACE); + metadataList = moduleMetadataList(); + accept(RBRACE); + + JCModuleDecl result = toP(F.at(pos).Module(annots, mid, provides, metadataList)); + attach(result, dc); + return result; + } + + /** + * ModuleMetadataList = ModuleMetadata* + * ModuleMetadata = ModuleRequires | ModulePermits | ModuleProvides + * ModuleRequires = REQUIRES Identifier* ModuleId {',' ModuleId} + * ModulePermits = PERMITS QualifiedIdentifier {',' QualifiedIdentifier} + */ + List<JCModuleMetadata> moduleMetadataList() { + ListBuffer<JCModuleMetadata> defs = new ListBuffer<JCModuleMetadata>(); + + while (S.token() == IDENTIFIER || S.token() == CLASS) { + int pos = S.pos(); + if (S.token() == CLASS) { + S.nextToken(); + ListBuffer<Name> flags = new ListBuffer<Name>(); + JCExpression qualIdHead = null; + while (S.token() == IDENTIFIER) { + int id_pos = S.pos(); + Name id = S.name(); + S.nextToken(); + if (S.token() == DOT || S.token() == SEMI) { + qualIdHead = toP(F.at(id_pos).Ident(id)); + break; + } + flags.append(id); + } + if (qualIdHead == null) { + log.error(pos, "class.id.expected"); + } else { + JCExpression qualId = qualident(qualIdHead); + accept(SEMI); + defs.append(toP(F.at(pos).ModuleClass(flags.toList(), qualId))); + } + } else if (S.name() == names.requires) { + ListBuffer<Name> flags = new ListBuffer<Name>(); + List<JCModuleId> moduleIds; + S.nextToken(); + JCExpression moduleIdHead = null; + while (S.token() == IDENTIFIER || + S.token().name != null && Character.isLetter(S.token().name.charAt(0))) { + int id_pos = S.pos(); + Name id = S.name(); + S.nextToken(); + if (S.token() == DOT || S.token() == MONKEYS_AT || S.token() == COMMA || S.token() == SEMI) { + moduleIdHead = toP(F.at(id_pos).Ident(id)); + break; + } + flags.append(id); + } + if (moduleIdHead == null) { + log.error(pos, "module.id.expected"); + } else { + moduleIds = moduleIdList(moduleIdHead); + accept(SEMI); + defs.append(toP(F.at(pos).ModuleRequires(flags.toList(), moduleIds))); + } + } else if (S.name() == names.permits) { + S.nextToken(); + List<JCExpression> qualIds = qualidentList(); + accept(SEMI); + defs.append(toP(F.at(pos).ModulePermits(qualIds))); + } else + break; + } + + return defs.toList(); + } + + /** ModuleIdList = ModuleId {"," ModuleId} + */ + List<JCModuleId> moduleIdList() { + ListBuffer<JCModuleId> ts = new ListBuffer<JCModuleId>(); + ts.append(moduleId()); + while (S.token() == COMMA) { + S.nextToken(); + ts.append(moduleId()); + } + return ts.toList(); + } + + /** ModuleIdList = ModuleId {"," ModuleId} + * used when we've peeked ahead at the first identifier + */ + List<JCModuleId> moduleIdList(JCExpression head) { + ListBuffer<JCModuleId> ts = new ListBuffer<JCModuleId>(); + ts.append(moduleId(head)); + while (S.token() == COMMA) { + S.nextToken(); + ts.append(moduleId()); + } + return ts.toList(); + } + + JCModuleId moduleId() { + return moduleId(toP(F.at(S.pos()).Ident(ident()))); + } + + JCModuleId moduleId(JCExpression head) { + int pos = S.pos(); + JCTree qualId = qualident(head); + Name version = null; + if (S.token() == MONKEYS_AT) { + S.nextToken(); + if (S.token() == MODULEVERSIONLITERAL || S.token() == STRINGLITERAL) { + version = names.fromString(S.stringVal()); + } else + log.error(pos, "modules.version.literal.expected"); + S.nextToken(); + } + return toP(F.at(pos).ModuleId(qualId, version)); + } + /** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";" */ JCTree importDeclaration() { @@ -2419,14 +2665,17 @@ /** TypeDeclaration = ClassOrInterfaceOrEnumDeclaration * | ";" */ - JCTree typeDeclaration(JCModifiers mods) { + JCTree typeDeclaration(JCModifiers mods, String dc) { int pos = S.pos(); if (mods == null && S.token() == SEMI) { S.nextToken(); return toP(F.at(pos).Skip()); } else { - String dc = S.docComment(); - return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), dc); + if (mods == null) { + assert dc == null; + dc = S.docComment(); + } + return classOrInterfaceOrEnumDeclaration(modifiersOpt(ModuleModifierKind.ALLOWED, mods, null), dc); } } @@ -2496,7 +2745,7 @@ S.nextToken(); implementing = typeList(); } - List<JCTree> defs = classOrInterfaceBody(name, false); + List<JCTree> defs = classOrInterfaceBody(name, CLASS); JCClassDecl result = toP(F.at(pos).ClassDef( mods, name, typarams, extending, implementing, defs)); attach(result, dc); @@ -2520,7 +2769,7 @@ S.nextToken(); extending = typeList(); } - List<JCTree> defs = classOrInterfaceBody(name, true); + List<JCTree> defs = classOrInterfaceBody(name, INTERFACE); JCClassDecl result = toP(F.at(pos).ClassDef( mods, name, typarams, null, extending, defs)); attach(result, dc); @@ -2577,7 +2826,7 @@ S.nextToken(); while (S.token() != RBRACE && S.token() != EOF) { defs.appendList(classOrInterfaceBodyDeclaration(enumName, - false)); + ENUM)); if (S.pos() <= errorEndPos) { // error recovery skip(false, true, true, false); @@ -2609,7 +2858,7 @@ JCClassDecl body = null; if (S.token() == LBRACE) { JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM | Flags.STATIC); - List<JCTree> defs = classOrInterfaceBody(names.empty, false); + List<JCTree> defs = classOrInterfaceBody(names.empty, CLASS); body = toP(F.at(identPos).AnonymousClassDef(mods1, defs)); } if (args.isEmpty() && body == null) @@ -2639,7 +2888,7 @@ /** ClassBody = "{" {ClassBodyDeclaration} "}" * InterfaceBody = "{" {InterfaceBodyDeclaration} "}" */ - List<JCTree> classOrInterfaceBody(Name className, boolean isInterface) { + List<JCTree> classOrInterfaceBody(Name className, Token encl) { accept(LBRACE); if (S.pos() <= errorEndPos) { // error recovery @@ -2649,7 +2898,7 @@ } ListBuffer<JCTree> defs = new ListBuffer<JCTree>(); while (S.token() != RBRACE && S.token() != EOF) { - defs.appendList(classOrInterfaceBodyDeclaration(className, isInterface)); + defs.appendList(classOrInterfaceBodyDeclaration(className, encl)); if (S.pos() <= errorEndPos) { // error recovery skip(false, true, true, false); @@ -2676,14 +2925,15 @@ * | ModifiersOpt Type Ident * ( ConstantDeclaratorsRest | InterfaceMethodDeclaratorRest ";" ) */ - List<JCTree> classOrInterfaceBodyDeclaration(Name className, boolean isInterface) { + List<JCTree> classOrInterfaceBodyDeclaration(Name className, Token encl) { if (S.token() == SEMI) { S.nextToken(); return List.<JCTree>of(F.at(Position.NOPOS).Block(0, List.<JCStatement>nil())); } else { + boolean isInterface = (encl == INTERFACE); String dc = S.docComment(); int pos = S.pos(); - JCModifiers mods = modifiersOpt(); + JCModifiers mods = modifiersOpt(ModuleModifierKind.LOOKAHEAD, (encl == CLASS ? className : null)); if (S.token() == CLASS || S.token() == INTERFACE || allowEnums && S.token() == ENUM) { @@ -2923,7 +3173,7 @@ } JCModifiers optFinal(long flags) { - JCModifiers mods = modifiersOpt(); + JCModifiers mods = modifiersOpt(ModuleModifierKind.DISALLOWED); checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED)); mods.flags |= flags; return mods;
--- a/src/share/classes/com/sun/tools/javac/parser/Keywords.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/parser/Keywords.java Fri Nov 06 13:20:18 2009 -0800 @@ -26,7 +26,6 @@ package com.sun.tools.javac.parser; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Names; @@ -51,12 +50,10 @@ return instance; } - private final Log log; private final Names names; protected Keywords(Context context) { context.put(keywordsKey, this); - log = Log.instance(context); names = Names.instance(context); for (Token t : Token.values()) {
--- a/src/share/classes/com/sun/tools/javac/parser/Lexer.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/parser/Lexer.java Fri Nov 06 13:20:18 2009 -0800 @@ -139,4 +139,15 @@ * Sets the current token. */ void token(Token token); + + /** + * Very simple mark/reset support. At most one position may be marked. + */ + void mark(); + + /** + * Reset the lexer back to the last marked position. No-op if no position + * has been set. + */ + void reset(); }
--- a/src/share/classes/com/sun/tools/javac/parser/Scanner.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/parser/Scanner.java Fri Nov 06 13:20:18 2009 -0800 @@ -89,6 +89,59 @@ } } + static class Mark { + /** Save the observable state of scanner as updated by nextToken(). + */ + Mark(Scanner s) { + bp = s.bp; + ch = s.ch; + deprecatedFlag = s.deprecatedFlag; + docComment = s.docComment(); + endPos = s.endPos; + errPos = s.errPos; + name = s.name; + pos = s.pos; + prevEndPos = s.prevEndPos; + radix = s.radix; + stringVal = s.stringVal(); + token = s.token; + } + + void apply(Scanner s) { + s.bp = bp; + s.ch = ch; + s.deprecatedFlag = deprecatedFlag; + // currently, there is no way to reset the docComment, but for the + // limited context for mark/reset this is probably not an issue + //s.docComment = docComment; + s.endPos = endPos; + s.errPos = errPos; + s.name = name; + s.pos = pos; + s.prevEndPos = prevEndPos; + s.radix = radix; + assert stringVal.length() < s.sbuf.length; + s.sp = stringVal.length(); + for (int i = 0; i < s.sp; i++) + s.sbuf[i] = stringVal.charAt(i); + s.token = token; + + } + + final int bp; + final char ch; + final boolean deprecatedFlag; + final String docComment; + final int endPos; + final int errPos; + final Name name; + final int pos; + final int prevEndPos; + final int radix; + final String stringVal; + final Token token; + } + /* Output variables; set by nextToken(): */ @@ -162,6 +215,10 @@ */ private int unicodeConversionBp = -1; + /** The last marked position. + */ + private Mark mark; + /** The log to be used for error reporting. */ private final Log log; @@ -802,6 +859,35 @@ return; } + private void scanModuleVersion() { + do { + putChar(ch); + scanChar(); + switch (ch) { + case ' ': case '\t': + case FF: case CR: case LF: + case '\"': case '\'': case '\\': + case ',': case ';': + case EOI: + token = MODULEVERSIONLITERAL; + return; + } + } while(true); + } + + /** Return true if ch can be part of an operator. + */ + private boolean isModuleStart(char ch) { + switch (ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '(': case '[': case '<': case '=': case '>': + return true; + default: + return false; + } + } + /** The value of a literal token, recorded as a string. * For integers, leading 0x and 'l' suffixes are suppressed. */ @@ -858,46 +944,54 @@ scanIdent(); return; case '0': - scanChar(); - if (ch == 'x' || ch == 'X') { - scanChar(); - skipIllegalUnderscores(); - if (ch == '.') { - scanHexFractionAndSuffix(false); - } else if (digit(16) < 0) { - lexError("invalid.hex.number"); - } else { - scanNumber(16); - } - } else if (ch == 'b' || ch == 'B') { - if (!allowBinaryLiterals) { - lexError("unsupported.binary.lit", source.name); - allowBinaryLiterals = true; - } + if (token == MONKEYS_AT) { + scanModuleVersion(); + } else { scanChar(); - skipIllegalUnderscores(); - if (digit(2) < 0) { - lexError("invalid.binary.number"); - } else { - scanNumber(2); - } - } else { - putChar('0'); - if (ch == '_') { - int savePos = bp; - do { - scanChar(); - } while (ch == '_'); - if (digit(10) < 0) { - lexError(savePos, "illegal.underscore"); - } - } - scanNumber(8); + if (ch == 'x' || ch == 'X') { + scanChar(); + skipIllegalUnderscores(); + if (ch == '.') { + scanHexFractionAndSuffix(false); + } else if (digit(16) < 0) { + lexError("invalid.hex.number"); + } else { + scanNumber(16); + } + } else if (ch == 'b' || ch == 'B') { + if (!allowBinaryLiterals) { + lexError("unsupported.binary.lit", source.name); + allowBinaryLiterals = true; + } + scanChar(); + skipIllegalUnderscores(); + if (digit(2) < 0) { + lexError("invalid.binary.number"); + } else { + scanNumber(2); + } + } else { + putChar('0'); + if (ch == '_') { + int savePos = bp; + do { + scanChar(); + } while (ch == '_'); + if (digit(10) < 0) { + lexError(savePos, "illegal.underscore"); + } + } + scanNumber(8); + } } return; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - scanNumber(10); + if (token == MONKEYS_AT) { + scanModuleVersion(); + } else { + scanNumber(10); + } return; case '.': scanChar(); @@ -923,11 +1017,23 @@ case ';': scanChar(); token = SEMI; return; case '(': - scanChar(); token = LPAREN; return; + if (token == MONKEYS_AT) { + scanModuleVersion(); + } else { + scanChar(); + token = LPAREN; + } + return; case ')': scanChar(); token = RPAREN; return; case '[': - scanChar(); token = LBRACKET; return; + if (token == MONKEYS_AT) { + scanModuleVersion(); + } else { + scanChar(); + token = LBRACKET; + } + return; case ']': scanChar(); token = RBRACKET; return; case '{': @@ -1028,7 +1134,9 @@ } return; default: - if (isSpecial(ch)) { + if (token == MONKEYS_AT && isModuleStart(ch)) { + scanModuleVersion(); + } else if (isSpecial(ch)) { scanOperator(); } else { boolean isJavaIdentifierStart; @@ -1227,4 +1335,13 @@ return Position.makeLineMap(buf, buflen, false); } + public void mark() { + mark = new Mark(this); + } + + public void reset() { + if (mark != null) + mark.apply(this); + } + }
--- a/src/share/classes/com/sun/tools/javac/parser/Token.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/parser/Token.java Fri Nov 06 13:20:18 2009 -0800 @@ -149,6 +149,7 @@ GTGTEQ(">>="), GTGTGTEQ(">>>="), MONKEYS_AT("@"), + MODULEVERSIONLITERAL, CUSTOM; Token() { @@ -176,6 +177,8 @@ return "token.float"; case DOUBLELITERAL: return "token.double"; + case MODULEVERSIONLITERAL: + return "token.version"; case ERROR: return "token.bad-symbol"; case EOF:
--- a/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Fri Nov 06 13:20:18 2009 -0800 @@ -1213,9 +1213,19 @@ node.type = null; } public void visitTopLevel(JCCompilationUnit node) { + node.locn = null; + node.modle = null; node.packge = null; super.visitTopLevel(node); } + public void visitModuleDef(JCModuleDecl node) { + node.sym = null; + super.visitModuleDef(node); + } + public void visitPackageDef(JCPackageDecl node) { + node.sym = null; + super.visitPackageDef(node); + } public void visitClassDef(JCClassDecl node) { node.sym = null; super.visitClassDef(node);
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Nov 06 13:20:18 2009 -0800 @@ -502,6 +502,17 @@ compiler.err.var.might.be.assigned.in.loop=\ variable {0} might be assigned in loop +compiler.err.mdl.no.version.available=\ + no version available for module {0} +compiler.err.mdl.no.unique.version.available=\ + no unique version available for module {0} +compiler.err.mdl.required.version.not.available=\ + required version not available for module {0} +compiler.err.mdl.duplicate.definition=\ + duplicate definition of module {0} +compiler.err.mdl.file.in.wrong.directory=\ + file is not in the expected subdirectory within its package hierarchy + # In the following string, {1} will always be the detail message from # java.io.IOException. compiler.err.class.cant.write=\ @@ -827,6 +838,8 @@ <float> compiler.misc.token.double=\ <double> +compiler.misc.token.version=\ + <version> compiler.misc.token.bad-symbol=\ <bad symbol> compiler.misc.token.end-of-input=\ @@ -874,6 +887,9 @@ compiler.misc.unnamed.package=\ unnamed package +compiler.misc.unnamed.module=\ + unnamed module + ##### compiler.err.cant.access=\ @@ -1110,6 +1126,8 @@ class compiler.misc.kindname.package=\ package +compiler.misc.kindname.module=\ + module ##### compiler.misc.no.args=\ @@ -1232,6 +1250,10 @@ strings in switch are not supported in -source {0}\n\ (use -source 7 or higher to enable strings in switch) +compiler.err.modules.not.supported.in.source=\ + modules are not supported in -source {0}\n\ +(use -source 7 or higher to enable modules) + ######################################## # Diagnostics for where clause implementation # used by the RichDiagnosticFormatter.
--- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java Fri Nov 06 13:20:18 2009 -0800 @@ -31,6 +31,7 @@ import java.io.StringWriter; import javax.lang.model.element.Modifier; import javax.lang.model.type.TypeKind; +import javax.tools.JavaFileManager.Location; import javax.tools.JavaFileObject; import com.sun.tools.javac.util.*; @@ -314,9 +315,17 @@ public static final int DIV_ASG = MUL_ASG + 1; // /= public static final int MOD_ASG = DIV_ASG + 1; // %= + public static final int MODULE = MOD_ASG + 1; + public static final int MODULE_CLASS = MODULE + 1; + public static final int MODULE_ID = MODULE_CLASS + 1; + public static final int MODULE_PERMITS = MODULE_CLASS + 1; + public static final int MODULE_REQUIRES = MODULE_PERMITS + 1; + + public static final int PACKAGE = MODULE_PERMITS + 1; + /** A synthetic let expression, of type LetExpr. */ - public static final int LETEXPR = MOD_ASG + 1; // ala scheme + public static final int LETEXPR = PACKAGE + 1; // ala scheme /** The offset between assignment operators and normal operators. @@ -336,6 +345,7 @@ public abstract int getTag(); /** Convert a tree to a pretty-printed string. */ + @Override public String toString() { StringWriter s = new StringWriter(); try { @@ -371,10 +381,11 @@ /** Return a shallow copy of this tree. */ + @Override public Object clone() { try { return super.clone(); - } catch(CloneNotSupportedException e) { + } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } @@ -423,10 +434,10 @@ * Defined only if option -Xjcov is set. */ public static class JCCompilationUnit extends JCTree implements CompilationUnitTree { - public List<JCAnnotation> packageAnnotations; - public JCExpression pid; public List<JCTree> defs; public JavaFileObject sourcefile; + public ModuleSymbol modle; + public Location locn; public PackageSymbol packge; public Scope namedImportScope; public Scope starImportScope; @@ -434,15 +445,11 @@ public Position.LineMap lineMap = null; public Map<JCTree, String> docComments = null; public Map<JCTree, Integer> endPositions = null; - protected JCCompilationUnit(List<JCAnnotation> packageAnnotations, - JCExpression pid, - List<JCTree> defs, + protected JCCompilationUnit(List<JCTree> defs, JavaFileObject sourcefile, PackageSymbol packge, Scope namedImportScope, Scope starImportScope) { - this.packageAnnotations = packageAnnotations; - this.pid = pid; this.defs = defs; this.sourcefile = sourcefile; this.packge = packge; @@ -454,7 +461,8 @@ public Kind getKind() { return Kind.COMPILATION_UNIT; } public List<JCAnnotation> getPackageAnnotations() { - return packageAnnotations; + JCPackageDecl pd = TreeInfo.getPackage(this); + return pd == null ? List.<JCAnnotation>nil() : pd.getAnnotations(); } public List<JCImport> getImports() { ListBuffer<JCImport> imports = new ListBuffer<JCImport>(); @@ -466,7 +474,10 @@ } return imports.toList(); } - public JCExpression getPackageName() { return pid; } + public JCExpression getPackageName() { + JCPackageDecl pd = TreeInfo.getPackage(this); + return pd == null ? null : pd.getPackageId(); + } public JavaFileObject getSourceFile() { return sourcefile; } @@ -2041,6 +2052,225 @@ } } + public static class JCModuleDecl extends JCTree implements com.sun.source.tree.ModuleTree { + public List<JCAnnotation> annots; + public JCModuleId id; + public List<JCModuleId> provides; + public List<JCModuleMetadata> metadata; + public ModuleSymbol sym; + protected JCModuleDecl(List<JCAnnotation> annots, JCModuleId id, + List<JCModuleId> provides, List<JCModuleMetadata> metadata) { + this.annots = annots; + this.id = id; + this.provides = provides; + this.metadata = metadata; + } + @Override + public void accept(Visitor v) { v.visitModuleDef(this); } + + public Kind getKind() { + return Kind.MODULE; + } + + public List<JCAnnotation> getAnnotations() { + return annots; + } + + public JCModuleId getId() { + return id; + } + + public List<JCModuleId> getProvides() { + return provides; + } + + public List<JCModuleMetadata> getMetadataList() { + return metadata; + } + + @Override + public <R, D> R accept(TreeVisitor<R, D> v, D d) { + return v.visitModule(this, d); + } + + @Override + public int getTag() { + return MODULE; + } + } + + public static class JCModuleId extends JCTree implements com.sun.source.tree.ModuleIdTree { + public JCTree qualId; + public Name version; + protected JCModuleId(JCTree qualId, Name version) { + this.qualId = qualId; + this.version = version; + } + + @Override + public void accept(Visitor v) { v.visitModuleId(this); } + + public Kind getKind() { + return Kind.MODULE_ID; + } + + public JCTree getModuleName() { + return qualId; + } + + public Name getModuleVersion() { + return version; + } + + @Override + public <R, D> R accept(TreeVisitor<R, D> v, D d) { + return v.visitModuleId(this, d); + } + + @Override + public int getTag() { + return MODULE_ID; + } + } + + public static abstract class JCModuleMetadata extends JCTree { + + } + + public static class JCModuleClass extends JCModuleMetadata implements com.sun.source.tree.ModuleClassTree { + public JCTree qualId; + public List<Name> flags; + protected JCModuleClass(List<Name> flags, JCTree qualId) { + this.qualId = qualId; + this.flags = flags; + } + + @Override + public void accept(Visitor v) { v.visitModuleClass(this); } + + public Kind getKind() { + return Kind.MODULE_CLASS; + } + + public JCTree getClassName() { + return qualId; + } + + public List<Name> getFlags() { + return flags; + } + + @Override + public <R, D> R accept(TreeVisitor<R, D> v, D d) { + return v.visitModuleClass(this, d); + } + + @Override + public int getTag() { + return MODULE_ID; + } + } + + public static class JCModulePermits extends JCModuleMetadata + implements com.sun.source.tree.ModulePermitsTree { + public List<JCExpression> moduleNames; + + protected JCModulePermits(List<JCExpression> moduleNames) { + this.moduleNames = moduleNames; + } + + @Override + public void accept(Visitor v) { v.visitModulePermits(this); } + + public Kind getKind() { + return Kind.MODULE_PERMITS; + } + + @Override + public <R, D> R accept(TreeVisitor<R, D> v, D d) { + return v.visitModulePermits(this, d); + } + + public List<JCExpression> getModuleNames() { + return moduleNames; + } + + @Override + public int getTag() { + return MODULE_PERMITS; + } + } + + public static class JCModuleRequires extends JCModuleMetadata + implements com.sun.source.tree.ModuleRequiresTree { + public List<Name> flags; + public List<JCModuleId> moduleIds; + + protected JCModuleRequires(List<Name> flags, List<JCModuleId> moduleIds) { + this.flags = flags; + this.moduleIds = moduleIds; + } + + @Override + public void accept(Visitor v) { v.visitModuleRequires(this); } + + public Kind getKind() { + return Kind.MODULE_REQUIRES; + } + + @Override + public <R, D> R accept(TreeVisitor<R, D> v, D d) { + return v.visitModuleRequires(this, d); + } + + public List<Name> getFlags() { + return flags; + } + + public List<JCModuleId> getModuleIds() { + return moduleIds; + } + + @Override + public int getTag() { + return MODULE_REQUIRES; + } + } + + public static class JCPackageDecl extends JCTree implements com.sun.source.tree.PackageTree { + public List<JCAnnotation> annots; + public JCExpression packageId; + public PackageSymbol sym; + protected JCPackageDecl(List<JCAnnotation> annots, JCExpression packageId) { + this.annots = annots; + this.packageId = packageId; + } + @Override + public void accept(Visitor v) { v.visitPackageDef(this); } + + public Kind getKind() { + return Kind.PACKAGE; + } + + public List<JCAnnotation> getAnnotations() { + return annots; + } + + public JCExpression getPackageId() { + return packageId; + } + + @Override + public <R, D> R accept(TreeVisitor<R, D> v, D d) { + return v.visitPackage(this, d); + } + + @Override + public int getTag() { + return PACKAGE; + } + } + public static class JCErroneous extends JCExpression implements com.sun.source.tree.ErroneousTree { public List<? extends JCTree> errs; @@ -2093,9 +2323,7 @@ /** An interface for tree factories */ public interface Factory { - JCCompilationUnit TopLevel(List<JCAnnotation> packageAnnotations, - JCExpression pid, - List<JCTree> defs); + JCCompilationUnit TopLevel(List<JCTree> defs); JCImport Import(JCTree qualid, boolean staticImport); JCClassDecl ClassDef(JCModifiers mods, Name name, @@ -2172,6 +2400,10 @@ JCAnnotation Annotation(JCTree annotationType, List<JCExpression> args); JCModifiers Modifiers(long flags, List<JCAnnotation> annotations); JCErroneous Erroneous(List<? extends JCTree> errs); + JCModuleId ModuleId(JCTree qualId, Name version); + JCModuleMetadata ModuleClass(List<Name> flags, JCTree qualId); + JCModuleMetadata ModulePermits(List<JCExpression> qualIds); + JCModuleMetadata ModuleRequires(List<Name> flags, List<JCModuleId> moduleIds); LetExpr LetExpr(List<JCVariableDecl> defs, JCTree expr); } @@ -2227,6 +2459,12 @@ public void visitModifiers(JCModifiers that) { visitTree(that); } public void visitAnnotatedType(JCAnnotatedType that) { visitTree(that); } public void visitErroneous(JCErroneous that) { visitTree(that); } + public void visitModuleDef(JCModuleDecl that) { visitTree(that); } + public void visitModuleClass(JCModuleClass that) { visitTree(that); } + public void visitModuleId(JCModuleId that) { visitTree(that); } + public void visitModulePermits(JCModulePermits that) { visitTree(that); } + public void visitModuleRequires(JCModuleRequires that) { visitTree(that); } + public void visitPackageDef(JCPackageDecl that) { visitTree(that); } public void visitLetExpr(LetExpr that) { visitTree(that); } public void visitTree(JCTree that) { assert false; }
--- a/src/share/classes/com/sun/tools/javac/tree/Pretty.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/tree/Pretty.java Fri Nov 06 13:20:18 2009 -0800 @@ -329,33 +329,40 @@ * @param cdef The class definition, which is assumed to be part of the * toplevel tree. */ + @SuppressWarnings("fallthrough") public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException { docComments = tree.docComments; printDocComment(tree); - if (tree.pid != null) { - print("package "); - printExpr(tree.pid); - print(";"); - println(); - } - boolean firstImport = true; - for (List<JCTree> l = tree.defs; - l.nonEmpty() && (cdef == null || l.head.getTag() == JCTree.IMPORT); - l = l.tail) { - if (l.head.getTag() == JCTree.IMPORT) { - JCImport imp = (JCImport)l.head; - Name name = TreeInfo.name(imp.qualid); - if (name == name.table.names.asterisk || - cdef == null || - isUsed(TreeInfo.symbol(imp.qualid), cdef)) { - if (firstImport) { - firstImport = false; + boolean inImports = false; + for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { + switch (l.head.getTag()) { + case JCTree.IMPORT: + JCImport imp = (JCImport)l.head; + Name name = TreeInfo.name(imp.qualid); + if (name == name.table.names.asterisk || + cdef == null || + isUsed(TreeInfo.symbol(imp.qualid), cdef)) { + if (!inImports) { + inImports = true; + println(); + } + printStat(imp); + } + break; + + default: + if (cdef != null) + break; + // fall-through + + case JCTree.MODULE: + case JCTree.PACKAGE: + if (inImports) { + inImports = false; println(); } - printStat(imp); - } - } else { - printStat(l.head); + printStat(l.head); + break; } } if (cdef != null) { @@ -391,6 +398,89 @@ } } + public void visitModuleDef(JCModuleDecl tree) { + try { + printAnnotations(tree.annots); + print("module "); + printExpr(tree.id); + if (tree.metadata == null) { + print(";"); + } else { + if (tree.provides.nonEmpty()) { + print(" provides "); + printExprs(tree.provides); + print(" "); + } + printBlock(tree.metadata); + } + println(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitModuleId(JCModuleId tree) { + try { + printExpr(tree.qualId); + if (tree.version != null) { + print(" @ "); + print(tree.version); // JIGSAW FIXME -- CHECK IF QUOTES REQUIRED + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitModuleClass(JCModuleClass tree) { + try { + print("class "); + for (List<Name> l = tree.flags; l.nonEmpty(); l = l.tail ) { + print(l.head); + print(" "); + } + printExpr(tree.qualId); + print(";"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitModulePermits(JCModulePermits tree) { + try { + print("permits "); + printExprs(tree.moduleNames); + print(";"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitModuleRequires(JCModuleRequires tree) { + try { + print("requires "); + for (List<Name> l = tree.flags; l.nonEmpty(); l = l.tail ) { + print(l.head); + print(" "); + } + printExprs(tree.moduleIds); + print(";"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitPackageDef(JCPackageDecl tree) { + try { + printAnnotations(tree.annots); + print("package "); + printExpr(tree.packageId); + print(";"); + println(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + public void visitImport(JCImport tree) { try { print("import ");
--- a/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java Fri Nov 06 13:20:18 2009 -0800 @@ -29,6 +29,7 @@ import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Name; /** * Creates a copy of a tree, using a given TreeMaker. @@ -324,10 +325,8 @@ public JCTree visitCompilationUnit(CompilationUnitTree node, P p) { JCCompilationUnit t = (JCCompilationUnit) node; - List<JCAnnotation> packageAnnotations = copy(t.packageAnnotations, p); - JCExpression pid = copy(t.pid, p); List<JCTree> defs = copy(t.defs, p); - return M.at(t.pos).TopLevel(packageAnnotations, pid, defs); + return M.at(t.pos).TopLevel(defs); } public JCTree visitTry(TryTree node, P p) { @@ -405,6 +404,48 @@ return M.at(t.pos).Wildcard(kind, inner); } + public JCTree visitModule(ModuleTree node, P p) { + JCModuleDecl t = (JCModuleDecl) node; + List<JCAnnotation> annots = copy(t.annots, p); + JCModuleId moduleId = copy(t.id); + List<JCModuleId> provides = copy(t.provides); + List<JCModuleMetadata> metadataList = copy(t.metadata, p); + return M.at(t.pos).Module(annots, moduleId, provides, metadataList); + } + + public JCModuleClass visitModuleClass(ModuleClassTree node, P p) { + JCModuleClass t = (JCModuleClass) node; + JCTree qualId = copy(t.qualId, p); + return M.at(t.pos).ModuleClass(t.flags, qualId); + } + + public JCTree visitModuleId(ModuleIdTree node, P p) { + JCModuleId t = (JCModuleId) node; + JCTree qualId = copy(t.qualId, p); + Name version = t.version; + return M.at(t.pos).ModuleId(qualId, version); + } + + public JCModulePermits visitModulePermits(ModulePermitsTree node, P p) { + JCModulePermits t = (JCModulePermits) node; + List<JCExpression> moduleNames = copy(t.moduleNames, p); + return M.at(t.pos).ModulePermits(moduleNames); + } + + public JCModuleRequires visitModuleRequires(ModuleRequiresTree node, P p) { + JCModuleRequires t = (JCModuleRequires) node; + List<Name> flags = t.flags; + List<JCModuleId> moduleIds = copy(t.moduleIds, p); + return M.at(t.pos).ModuleRequires(flags, moduleIds); + } + + public JCTree visitPackage(PackageTree node, P p) { + JCPackageDecl t = (JCPackageDecl) node; + List<JCAnnotation> annots = copy(t.annots, p); + JCExpression packageId = copy(t.packageId); + return M.at(t.pos).Package(annots, packageId); + } + public JCTree visitOther(Tree node, P p) { JCTree tree = (JCTree) node; switch (tree.getTag()) {
--- a/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Fri Nov 06 13:20:18 2009 -0800 @@ -34,6 +34,7 @@ import com.sun.tools.javac.code.*; import com.sun.tools.javac.tree.JCTree.*; +import javax.tools.JavaFileObject; import static com.sun.tools.javac.code.Flags.*; /** Utility class containing inspector methods for trees. @@ -891,4 +892,40 @@ throw new AssertionError("Unexpected type tree: " + tree); } } + + public static boolean isModuleInfo(JCCompilationUnit tree) { + return tree.sourcefile.isNameCompatible("module-info", JavaFileObject.Kind.SOURCE); + } + + public static JCModuleDecl getModule(JCCompilationUnit t) { + for (JCTree def: t.defs) { + switch (def.getTag()) { + case JCTree.IMPORT: + continue; + case JCTree.MODULE: + return (JCModuleDecl) def; + default: + break; + } + } + return null; + } + + public static boolean isPackageInfo(JCCompilationUnit tree) { + return tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE); + } + + public static JCPackageDecl getPackage(JCCompilationUnit t) { + for (JCTree def: t.defs) { + switch (def.getTag()) { + case JCTree.IMPORT: + continue; + case JCTree.PACKAGE: + return (JCPackageDecl) def; + default: + break; + } + } + return null; + } }
--- a/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Fri Nov 06 13:20:18 2009 -0800 @@ -119,19 +119,19 @@ * Create given tree node at current position. * @param defs a list of ClassDef, Import, and Skip */ - public JCCompilationUnit TopLevel(List<JCAnnotation> packageAnnotations, - JCExpression pid, - List<JCTree> defs) { - assert packageAnnotations != null; + public JCCompilationUnit TopLevel(List<JCTree> defs) { for (JCTree node : defs) assert node instanceof JCClassDecl || node instanceof JCImport + || node instanceof JCPackageDecl + || node instanceof JCModuleDecl + || node instanceof JCModuleMetadata || node instanceof JCSkip || node instanceof JCErroneous || (node instanceof JCExpressionStatement && ((JCExpressionStatement)node).expr instanceof JCErroneous) : node.getClass().getSimpleName(); - JCCompilationUnit tree = new JCCompilationUnit(packageAnnotations, pid, defs, + JCCompilationUnit tree = new JCCompilationUnit(defs, null, null, null, null); tree.pos = pos; return tree; @@ -495,6 +495,43 @@ return tree; } + public JCModuleDecl Module(List<JCAnnotation> annots, JCModuleId moduleId, + List<JCModuleId> provides, List<JCModuleMetadata> metadata) { + JCModuleDecl tree = new JCModuleDecl(annots, moduleId, provides, metadata); + tree.pos = pos; + return tree; + } + + public JCModuleClass ModuleClass(List<Name> flags, JCTree qualId) { + JCModuleClass tree = new JCModuleClass(flags, qualId); + tree.pos = pos; + return tree; + } + + public JCModuleId ModuleId(JCTree qualId, Name version) { + JCModuleId tree = new JCModuleId(qualId, version); + tree.pos = pos; + return tree; + } + + public JCModulePermits ModulePermits(List<JCExpression> qualIds) { + JCModulePermits tree = new JCModulePermits(qualIds); + tree.pos = pos; + return tree; + } + + public JCModuleRequires ModuleRequires(List<Name> flags, List<JCModuleId> moduleIds) { + JCModuleRequires tree = new JCModuleRequires(flags, moduleIds); + tree.pos = pos; + return tree; + } + + public JCPackageDecl Package(List<JCAnnotation> annots, JCExpression packageId) { + JCPackageDecl tree = new JCPackageDecl(annots, packageId); + tree.pos = pos; + return tree; + } + public JCErroneous Erroneous() { return Erroneous(List.<JCTree>nil()); } @@ -675,10 +712,10 @@ /** Create a list of trees representing given list of types. */ public List<JCExpression> Types(List<Type> ts) { - ListBuffer<JCExpression> types = new ListBuffer<JCExpression>(); + ListBuffer<JCExpression> t = new ListBuffer<JCExpression>(); for (List<Type> l = ts; l.nonEmpty(); l = l.tail) - types.append(Type(l.head)); - return types.toList(); + t.append(Type(l.head)); + return t.toList(); } /** Create a variable definition from a variable symbol and an initializer
--- a/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java Fri Nov 06 13:20:18 2009 -0800 @@ -46,7 +46,8 @@ /** Visitor method: Scan a single node. */ public void scan(JCTree tree) { - if(tree!=null) tree.accept(this); + if (tree != null) + tree.accept(this); } /** Visitor method: scan a list of nodes. @@ -63,11 +64,35 @@ ****************************************************************************/ public void visitTopLevel(JCCompilationUnit tree) { - scan(tree.packageAnnotations); - scan(tree.pid); scan(tree.defs); } + public void visitModuleDef(JCModuleDecl tree) { + scan(tree.annots); + scan(tree.id); + } + + public void visitModuleId(JCModuleId tree) { + scan(tree.qualId); + } + + public void visitModuleClass(JCModuleClass tree) { + scan(tree.qualId); + } + + public void visitModulePermits(JCModulePermits tree) { + scan(tree.moduleNames); + } + + public void visitModuleRequires(JCModuleRequires tree) { + scan(tree.moduleIds); + } + + public void visitPackageDef(JCPackageDecl tree) { + scan(tree.annots); + scan(tree.packageId); + } + public void visitImport(JCImport tree) { scan(tree.qualid); }
--- a/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Fri Nov 06 13:20:18 2009 -0800 @@ -116,7 +116,6 @@ ****************************************************************************/ public void visitTopLevel(JCCompilationUnit tree) { - tree.pid = translate(tree.pid); tree.defs = translate(tree.defs); result = tree; }
--- a/src/share/classes/com/sun/tools/javac/util/Names.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javac/util/Names.java Fri Nov 06 13:20:18 2009 -0800 @@ -75,6 +75,7 @@ public final Name java_lang_Enum; public final Name java_dyn_MethodHandle; public final Name java_dyn_InvokeDynamic; + public final Name module_info; public final Name package_info; public final Name ConstantValue; public final Name LineNumberTable; @@ -148,6 +149,16 @@ public final Name getDeclaringClass; public final Name ex; public final Name finalize; + public final Name module; + public final Name Module; + public final Name requires; + public final Name provides; + public final Name permits; + public final Name synthetic; + public final Name ModuleClass; + public final Name ModulePermits; + public final Name ModuleProvides; + public final Name ModuleRequires; public final Name.Table table; @@ -184,6 +195,7 @@ java_lang_Enum = fromString("java.lang.Enum"); java_dyn_MethodHandle = fromString("java.dyn.MethodHandle"); java_dyn_InvokeDynamic = fromString("java.dyn.InvokeDynamic"); + module_info = fromString("module-info"); package_info = fromString("package-info"); serialVersionUID = fromString("serialVersionUID"); ConstantValue = fromString("ConstantValue"); @@ -263,6 +275,16 @@ getDeclaringClass = fromString("getDeclaringClass"); ex = fromString("ex"); finalize = fromString("finalize"); + module = fromString("module"); + Module = fromString("Module"); + requires = fromString("requires"); + provides = fromString("provides"); + permits = fromString("permits"); + synthetic = fromString("synthetic"); + ModuleClass = fromString("ModuleClass"); + ModulePermits = fromString("ModulePermits"); + ModuleProvides = fromString("ModuleProvides"); + ModuleRequires = fromString("ModuleRequires"); } protected Name.Table createTable(Options options) {
--- a/src/share/classes/com/sun/tools/javap/AttributeWriter.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javap/AttributeWriter.java Fri Nov 06 13:20:18 2009 -0800 @@ -25,6 +25,7 @@ package com.sun.tools.javap; +import java.util.Arrays; import java.util.Formatter; import com.sun.tools.classfile.AccessFlags; @@ -45,8 +46,10 @@ import com.sun.tools.classfile.LineNumberTable_attribute; import com.sun.tools.classfile.LocalVariableTable_attribute; import com.sun.tools.classfile.LocalVariableTypeTable_attribute; -import com.sun.tools.classfile.ModuleExportTable_attribute; -import com.sun.tools.classfile.ModuleMemberTable_attribute; +import com.sun.tools.classfile.ModuleClass_attribute; +import com.sun.tools.classfile.ModulePermits_attribute; +import com.sun.tools.classfile.ModuleProvides_attribute; +import com.sun.tools.classfile.ModuleRequires_attribute; import com.sun.tools.classfile.Module_attribute; import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute; import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute; @@ -373,9 +376,7 @@ } public Void visitModule(Module_attribute attr, Void ignore) { - print("Module: #" + attr.module_name); - tab(); - println("// " + getModuleName(attr)); + println(" Module: " + constantWriter.stringValue(attr.module_id_index)); return null; } @@ -387,46 +388,40 @@ } } - public Void visitModuleExportTable(ModuleExportTable_attribute attr, Void ignore) { - println("ModuleExportTable:"); - indent(+1); - println("Types: (" + attr.export_type_table.length + ")"); - for (int i = 0; i < attr.export_type_table.length; i++) { - print("#" + attr.export_type_table[i]); - tab(); - println("// " + getExportTypeName(attr, i)); + public Void visitModuleClass(ModuleClass_attribute attr, Void ignore) { + println(" ModuleClass: "); + println(" #" + attr.class_index + "," + Arrays.toString(attr.attributes) + + "\t// " + constantWriter.stringValues(attr.attributes, " ") + + " " + constantWriter.stringValue(attr.class_index)); + return null; + } + + public Void visitModulePermits(ModulePermits_attribute attr, Void ignore) { + println(" ModulePermits: "); + for (int i = 0; i < attr.permits_table.length; i++) { + int permits_index = attr.permits_table[i]; + println(" #" + permits_index + "\t// " + constantWriter.stringValue(permits_index)); } - indent(-1); return null; } - String getExportTypeName(ModuleExportTable_attribute attr, int index) { - try { - return attr.getExportTypeName(index, constant_pool); - } catch (ConstantPoolException e) { - return report(e); + public Void visitModuleProvides(ModuleProvides_attribute attr, Void ignore) { + println(" ModuleProvides: "); + for (int i = 0; i < attr.provides_table.length; i++) { + int provides_index = attr.provides_table[i]; + println(" #" + provides_index + "\t// " + constantWriter.stringValue(provides_index)); } - } - - public Void visitModuleMemberTable(ModuleMemberTable_attribute attr, Void ignore) { - println("ModuleMemberTable:"); - indent(+1); - println("Packages: (" + attr.package_member_table.length + ")"); - for (int i = 0; i < attr.package_member_table.length; i++) { - print("#" + attr.package_member_table[i]); - tab(); - println("// " + getPackageMemberName(attr, i)); - } - indent(-1); return null; } - String getPackageMemberName(ModuleMemberTable_attribute attr, int index) { - try { - return attr.getPackageMemberName(index, constant_pool); - } catch (ConstantPoolException e) { - return report(e); + public Void visitModuleRequires(ModuleRequires_attribute attr, Void ignore) { + println(" ModuleRequires: "); + for (ModuleRequires_attribute.Entry e: attr.requires_table) { + println(" #" + e.requires_index + "," + Arrays.toString(e.attributes) + + "\t// " + constantWriter.stringValues(e.attributes, " ") + + " " + constantWriter.stringValue(e.requires_index)); } + return null; } public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, Void ignore) {
--- a/src/share/classes/com/sun/tools/javap/ConstantWriter.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javap/ConstantWriter.java Fri Nov 06 13:20:18 2009 -0800 @@ -102,15 +102,22 @@ return 2; } - public Integer visitNameAndType(CONSTANT_NameAndType_info info, Void p) { - print("#" + info.name_index + ":#" + info.type_index); + public Integer visitMethodref(CONSTANT_Methodref_info info, Void p) { + print("#" + info.class_index + ".#" + info.name_and_type_index); tab(); println("// " + stringValue(info)); return 1; } - public Integer visitMethodref(CONSTANT_Methodref_info info, Void p) { - print("#" + info.class_index + ".#" + info.name_and_type_index); + public Integer visitModuleId(CONSTANT_ModuleId_info info, Void p) { + print("#" + info.name_index + ":#" + info.version_index); + tab(); + println("// " + stringValue(info)); + return 1; + } + + public Integer visitNameAndType(CONSTANT_NameAndType_info info, Void p) { + print("#" + info.name_index + ":#" + info.type_index); tab(); println("// " + stringValue(info)); return 1; @@ -207,6 +214,8 @@ return "InterfaceMethod"; case CONSTANT_NameAndType: return "NameAndType"; + case CONSTANT_ModuleId: + return "ModuleId"; default: return "(unknown tag)"; } @@ -221,6 +230,16 @@ } } + String stringValues(int[] constant_pool_indices, String sep) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < constant_pool_indices.length; i++) { + if (i > 0) + sb.append(sep); + sb.append(stringValue(constant_pool_indices[i])); + } + return sb.toString(); + } + String stringValue(CPInfo cpInfo) { return stringValueVisitor.visit(cpInfo); } @@ -268,6 +287,33 @@ return info.value + "l"; } + public String visitMethodref(CONSTANT_Methodref_info info, Void p) { + return visitRef(info, p); + } + + public String visitModuleId(CONSTANT_ModuleId_info info, Void p) { + if (info.version_index == 0) + return getCheckedName(info); + else + return getCheckedName(info) + "@" + getCheckedVersion(info); + } + + String getCheckedName(CONSTANT_ModuleId_info info) { + try { + return checkName(info.getName()); + } catch (ConstantPoolException e) { + return report(e); + } + } + + String getCheckedVersion(CONSTANT_ModuleId_info info) { + try { + return info.getVersion(); + } catch (ConstantPoolException e) { + return report(e); + } + } + public String visitNameAndType(CONSTANT_NameAndType_info info, Void p) { return getCheckedName(info) + ":" + getType(info); } @@ -288,10 +334,6 @@ } } - public String visitMethodref(CONSTANT_Methodref_info info, Void p) { - return visitRef(info, p); - } - public String visitString(CONSTANT_String_info info, Void p) { try { ClassFile classFile = classWriter.getClassFile();
--- a/src/share/classes/com/sun/tools/javap/JavapTask.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javap/JavapTask.java Fri Nov 06 13:20:18 2009 -0800 @@ -236,12 +236,6 @@ } }, - new Option(false, "-XDjsr277") { - void process(JavapTask task, String opt, String arg) { - task.options.jsr277 = true; - } - }, - new Option(false, "-XDdetails") { void process(JavapTask task, String opt, String arg) { task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class); @@ -586,7 +580,6 @@ sourceWriter.setFileManager(fileManager); attributeFactory.setCompat(options.compat); - attributeFactory.setJSR277(options.jsr277); boolean ok = true;
--- a/src/share/classes/com/sun/tools/javap/Options.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/com/sun/tools/javap/Options.java Fri Nov 06 13:20:18 2009 -0800 @@ -90,5 +90,4 @@ public int tabColumn = 40; // column number for comments public boolean compat; // bug-for-bug compatibility mode with old javap - public boolean jsr277; }
--- a/src/share/classes/javax/lang/model/element/Element.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/javax/lang/model/element/Element.java Fri Nov 06 13:20:18 2009 -0800 @@ -32,7 +32,6 @@ import java.util.List; import java.util.Set; -import javax.lang.model.element.Modifier; import javax.lang.model.type.*; import javax.lang.model.util.*;
--- a/src/share/classes/javax/lang/model/element/Modifier.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/javax/lang/model/element/Modifier.java Fri Nov 06 13:20:18 2009 -0800 @@ -59,7 +59,8 @@ /** The modifier {@code volatile} */ VOLATILE, /** The modifier {@code synchronized} */ SYNCHRONIZED, /** The modifier {@code native} */ NATIVE, - /** The modifier {@code strictfp} */ STRICTFP; + /** The modifier {@code strictfp} */ STRICTFP, + /** The modifier {@code module} */ MODULE; private String lowercase = null; // modifier name in lowercase
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/javax/lang/model/element/ModuleElement.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright 2006-2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.lang.model.element; + +import java.util.List; + +/** Interim API. */ +public interface ModuleElement extends Element { + interface ModuleId { + CharSequence getName(); + CharSequence getVersion(); + } + + interface ModuleRequires { + ModuleId getModuleId(); + List<? extends CharSequence> getFlags(); + } + + List<? extends ModuleRequires> getRequires(); + +}
--- a/src/share/classes/javax/lang/model/type/TypeKind.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/javax/lang/model/type/TypeKind.java Fri Nov 06 13:20:18 2009 -0800 @@ -134,6 +134,12 @@ EXECUTABLE, /** + * A pseudo-type corresponding to a module element. + * @see NoType + */ + MODULE, + + /** * An implementation-reserved type. * This is not the type you are looking for. */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/javax/lang/model/util/ModuleResolver.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.lang.model.util; +// TODO: reconsider this package -- perhaps it belongs in com.sun.tools.javac.api + +import javax.lang.model.element.ModuleElement; + +/** + * Module resolver for modules defined in the Java™ Programming Language. + * + * Given a set of root modules, and an overall set of modules, the resolver determines + * which modules are visible from the root modules. + */ +public interface ModuleResolver { + + class ResolutionException extends Exception { + private static final long serialVersionUID = -5294493995009985322L; + } + + /** + * Resolve a set of modules. The resolution may take additional modules into + * account, such as may be found in a system module library. + * @param roots The root modules whose dependencies need to be resolved + * @param modules A set of modules in which to find any dependencies. + * @throws ResolutionException if the resolution cannot be successfully completed. + */ + Iterable<? extends ModuleElement> resolve( + Iterable<? extends ModuleElement> roots, + Iterable<? extends ModuleElement> modules) + throws ResolutionException; + + /** + * Get the set of visible modules for a module. This method may be called + * after {@link #resolve} to get more specific information. + * @param module + * @return the visible modules + */ + Iterable<? extends ModuleElement> getVisibleModules(ModuleElement module) + throws IllegalStateException; + + boolean isPlatformName(CharSequence name); + + String getDefaultPlatformModule(); // should use a "platform" enum +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/javax/tools/ModuleFileManager.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.tools; + +public interface ModuleFileManager extends JavaFileManager { + class InvalidLocationException extends IllegalArgumentException { + private static final long serialVersionUID = 2115919242510692026L; + } + + class InvalidFileObjectException extends IllegalArgumentException { + private static final long serialVersionUID = 1234906668846471087L; + } + + enum ModuleMode { SINGLE, MULTIPLE }; + + ModuleMode getModuleMode(); + + Location getModuleLocation(Location location, JavaFileObject fo, String packageName) + throws IllegalArgumentException; + + Iterable<? extends Location> getModuleLocations(Location location); + + Location join(Iterable<? extends Location> locations); +}
--- a/src/share/classes/javax/tools/StandardLocation.java Mon Nov 02 21:36:59 2009 -0800 +++ b/src/share/classes/javax/tools/StandardLocation.java Fri Nov 06 13:20:18 2009 -0800 @@ -66,7 +66,12 @@ * Location to search for platform classes. Sometimes called * the boot class path. */ - PLATFORM_CLASS_PATH; + PLATFORM_CLASS_PATH, + + /** + * Location to search for existing module class files. + */ + MODULE_PATH; /** * Gets a location object with the given name. The following
--- a/test/tools/javac/T6232928.java Mon Nov 02 21:36:59 2009 -0800 +++ b/test/tools/javac/T6232928.java Fri Nov 06 13:20:18 2009 -0800 @@ -27,7 +27,7 @@ * @summary Interface package-info should be marked abstract and synthetic * @author Wei Tao * @compile T6232928.java - * @compile T6232928/package-info.java + * @compile -doe T6232928/package-info.java * @run main T6232928 */
--- a/test/tools/javac/T6341023.java Mon Nov 02 21:36:59 2009 -0800 +++ b/test/tools/javac/T6341023.java Fri Nov 06 13:20:18 2009 -0800 @@ -101,6 +101,26 @@ ok = ok & verify(k, i, i == WildcardTree.class); break; + case MODULE: + ok = ok & verify(k, i, i == ModuleTree.class); + break; + + case MODULE_CLASS: + ok = ok & verify(k, i, i == ModuleClassTree.class); + break; + + case MODULE_PERMITS: + ok = ok & verify(k, i, i == ModulePermitsTree.class); + break; + + case MODULE_REQUIRES: + ok = ok & verify(k, i, i == ModuleRequiresTree.class); + break; + + case PACKAGE: + ok = ok & verify(k, i, i == PackageTree.class); + break; + case OTHER: ok = ok & verify(k, i, i == null); break;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/modules/ModuleAccessTest01.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,264 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802521 + * @summary add support for modules: test basic use of module access modifier + */ + +import java.io.*; +import java.util.*; + +/* + * Test access to items in a module for combinations of: + * -- referencing module + * -- type of item being referenced + * As a control, we verify that access to the items fails + * when they have package access, but succeeds with module + * access. + * + * Verify that compilation errors are generated or that + * compilation is successful. + */ +public class ModuleAccessTest01 +{ + enum AccessKind { + PACKAGE(""), + MODULE("module"); + AccessKind(String s) { + text = s; + } + final String text; + } + + enum ItemKind { + CLASS("p.Ref.C r = null;"), + CONSTR("new p.Ref();"), + FIELD("int i = ref.field;"), + METHOD("int i = ref.method();"); + ItemKind(String s) { + text = s; + } + final String text; + }; + + enum ModuleKind { + M1("m1", "p1"), + M2("m2", "p2"), + UNNAMED("", ""); + ModuleKind(String m, String p) { + moduleName = m; + packageName = p; + } + String moduleDir() { return (moduleName.equals("") ? "anon" : moduleName) + "/"; } + String moduleDecl() { return "module " + moduleName + " { }"; } + String packageDir() { return (packageName.equals("") ? "" : packageName + "/"); } + String packageDecl() { return (packageName.equals("") ? "" : "package " + packageName + ";"); } + final String moduleName; + final String packageName; + }; + + public static void main(String... args) throws Exception { + new ModuleAccessTest01().run(); + } + + public void run() throws Exception { + for (ItemKind ik: ItemKind.values()) { + for (ModuleKind mk: ModuleKind.values()) { + for (AccessKind ak: AccessKind.values()) { + test(ik, mk, ak); + } + } + } + + if (errors == 0) + System.out.println(count + " tests passed"); + else + throw new Exception(errors + "/" + count + " tests failed"); + } + + void test(ItemKind ik, ModuleKind mk, AccessKind ak) throws Exception { + System.out.println("Test " + (++count) + ": " + ik + " " + mk + " " + ak); + + File testDir = new File("test" + count); + srcDir = new File(testDir, "src"); + classesDir = new File(testDir, "classes"); + resetDirs(srcDir, classesDir); + + List<File> files = new ArrayList<File>(); + + // create a reference class in module m1, package p + String[] refBody = { + "package p;", + "public class Ref {", + " " + ak.text + " Ref() { }", + " " + ak.text + " int field;", + " " + ak.text + " int method() { return 0; }", + " " + ak.text + " class C { }", + "}" + }; + files.add(createFile(srcDir, "m1/p/Ref.java", join(refBody))); + files.add(createFile(srcDir, "m1/module-info.java", "module m1 { }")); + + // create a test class in module mk.moduleName, package mk.packageName + String[] testBody = { + mk.packageDecl(), + "class Test {", + " void m(p.Ref ref) {", + " " + ik.text, + " }", + "}" + }; + files.add(createFile(srcDir, mk.moduleDir() + mk.packageDir() + "Test.java", join(testBody))); + switch (mk) { + case UNNAMED: // no module-info + case M1: // already generated for ref + break; + default: + files.add(createFile(srcDir, mk.moduleDir() + "module-info.java", mk.moduleDecl())); + } + + System.out.println("files: " + files); + + boolean expectError = (ak == AccessKind.PACKAGE || mk != ModuleKind.M1); + + compile(files, classesDir, Arrays.asList("-modulepath", classesDir.getPath()), expectError); + } + + void compile(List<File> files, File classOutDir, List<String> extraOpts, boolean expectError) { + List<String> options = new ArrayList<String>(); + options.add("-XDrawDiagnostics"); + options.addAll(Arrays.asList("-source", "7", "-d", classOutDir.getPath())); + if (extraOpts != null) + options.addAll(extraOpts); + for (File f: files) + options.add(f.getPath()); + + String[] opts = options.toArray(new String[options.size()]); + StringWriter sw = new StringWriter(); + PrintWriter out = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(opts, out); + out.close(); + + if (expectError) { + if (rc == 0) + error(files, "compilation succeeded unexpectedly"); + else { + //log(files, "compilation failed as expected", sw.toString()); + //log(files, "OK"); + } + } + else { + if (rc != 0) + error(files, "compilation failed unexpectedly", sw.toString()); + else { + //log(files, "OK"); + } + } + } + + /** + * Join lines with newline. + */ + String join(String... lines) { + StringBuilder sb = new StringBuilder(); + for (String s: lines) { + sb.append(s); + sb.append("\n"); + } + return sb.toString(); + } + + /** + * Create a test file with given content. + */ + File createFile(File dir, String path, String body) throws IOException { + File file = new File(dir, path); + file.getAbsoluteFile().getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + return file; + } + + /** + * Set up empty directories. + */ + void resetDirs(File... dirs) { + for (File dir: dirs) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + } + + /** + * Delete a file or a directory (including all its contents). + */ + boolean deleteAll(File file) { + if (file.isDirectory()) { + for (File f: file.listFiles()) + deleteAll(f); + } + return file.delete(); + } + + /** + * Report an error. + */ + void error(List<File> files, String msg, String... more) { + System.out.println("test " + files); + System.out.println("error: " + msg); + for (String s: more) + System.out.println(s); + errors++; + //throw new Error(msg); + } + + /** + * Report an error. + */ + void error(String msg, String... more) { + System.out.println("error: " + msg); + for (String s: more) + System.out.println(s); + errors++; + throw new Error(msg); + } + + /** + * Log a message. + */ + void log(List<File> files, String... msgs) { + System.out.println("test " + files); + for (String s: msgs) + System.out.println(s); + } + + int count; + int errors; + File srcDir; + File classesDir; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/modules/ModuleAttributeTest01.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,219 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802521 + * @summary add support for modules: test basic use of Module attribute + */ + +import java.io.*; +import java.util.*; +import com.sun.tools.classfile.*; + +public class ModuleAttributeTest01 { + /** Simple combinations of compilation units to test. */ + enum Kind { + NONE("package P; class C { }", null), + NAME("package P; class C { }", "module M { }"), + NAME_AND_VERSION("package P; class C { }", "module M@1.0 { }"); + Kind(String classBody, String moduleInfoBody) { + this.classBody = classBody; + this.moduleInfoBody = moduleInfoBody; + } + final String classBody; + final String moduleInfoBody; + }; + + + public static void main(String[] args) throws Exception { + new ModuleAttributeTest01().run(); + } + + void run() throws Exception { + for (Kind k: Kind.values()) { + try { + test(k); + } catch (Throwable t) { + t.printStackTrace(); + errors++; + } + } + + if (errors == 0) + System.out.println(count + " tests passed"); + else + throw new Exception(errors + "/" + count + " tests failed"); + } + + void test(Kind k) throws Exception { + System.out.println("Test " + (++count) + ": " + k); + + File testDir = new File("test" + count); + srcDir = new File(testDir, "src"); + classesDir = new File(testDir, "classes"); + resetDirs(srcDir, classesDir); + + String classBody = k.classBody; + String moduleInfoBody = k.moduleInfoBody; + + List<File> files = new ArrayList<File>(); + addFile(files, createFile("C.java", classBody)); + addFile(files, createFile("module-info.java", moduleInfoBody)); + compile(files); + String moduleId = getModuleId(moduleInfoBody); + checkModuleAttribute("P/C.class", null); // Module attribute no longer written in class file + if (moduleInfoBody != null) + checkModuleAttribute("module-info.class", moduleId); + } + + String getModuleId(String moduleBody) { + if (moduleBody == null) + return null; + String[] tokens = moduleBody.split(" +"); + return tokens[1]; + } + + void checkModuleAttribute(String file, String moduleId) throws IOException { + System.err.println("Checking " + file); + try { + ClassFile cf = ClassFile.read(new File(classesDir, file)); + Module_attribute attr = (Module_attribute) cf.getAttribute(Attribute.Module); + if (attr == null) { + if (moduleId != null) + error("Module attribute not found; expected " + moduleId); + } else { + if (moduleId == null) { + error("Unexpected module attribute found: " + attr); + } else { + String name, version; + int sep = moduleId.indexOf("@"); + if (sep == -1) { + name = moduleId; + version = null; + } else { + name = moduleId.substring(0, sep); + version = moduleId.substring(sep + 1); + } + ConstantPool cp = cf.constant_pool; + checkEqual("module name", name, attr.getModuleName(cp)); + checkEqual("module version", version, attr.getModuleVersion(cp)); + } + } + } catch (ConstantPoolException e) { + error("Error accessing constant pool " + file + ": " + e); + } catch (IOException e) { + error("Error reading " + file + ": " + e); + } + } + + <T> void checkEqual(String tag, T expect, T found) { + if (expect == null ? found == null : expect.equals(found)) + return; + error(tag + " mismatch", "expected " + expect, "found: " + found); + } + + /** + * Compile a list of files. + */ + void compile(List<File> files) { + List<String> options = new ArrayList<String>(); + options.addAll(Arrays.asList("-source", "7", "-d", classesDir.getPath())); + for (File f: files) + options.add(f.getPath()); + + String[] opts = options.toArray(new String[options.size()]); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(opts, pw); + pw.close(); + + String out = sw.toString(); + if (out.trim().length() > 0) + System.err.println(out); + if (rc != 0) + throw new Error("compilation failed: rc=" + rc); + } + + /** + * Add a file to a list if the file is not null. + */ + void addFile(List<File> files, File file) { + if (file != null) + files.add(file); + } + + + /** + * Create a test file with given content if the content is not null. + */ + File createFile(String path, String body) throws IOException { + if (body == null) + return null; + File file = new File(srcDir, path); + file.getAbsoluteFile().getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + return file; + } + + /** + * Set up empty directories. + */ + void resetDirs(File... dirs) { + for (File dir: dirs) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + } + + /** + * Delete a file or a directory (including all its contents). + */ + boolean deleteAll(File file) { + if (file.isDirectory()) { + for (File f: file.listFiles()) + deleteAll(f); + } + return file.delete(); + } + + /** + * Report an error. + */ + void error(String msg, String... more) { + System.err.println("error: " + msg); + for (String s: more) + System.err.println(s); + errors++; + } + + int count; + int errors; + File srcDir = new File("tmp", "src"); // use "tmp" to help avoid accidents + File classesDir = new File("tmp", "classes"); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/modules/ModuleClassAttributeTest01.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,227 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802521 + * @summary add support for modules: test basic use of ModuleClass attribute + */ + +import java.io.*; +import java.util.*; +import com.sun.tools.classfile.*; + +public class ModuleClassAttributeTest01 { + String[][] values = { + {"C"}, + {"main", "my.pckge.Main"}, + {"fx", "applet", "a.b.c.MyClass"} + }; + + public static void main(String[] args) throws Exception { + new ModuleClassAttributeTest01().run(); + } + + void run() throws Exception { + for (String[] v: values) { + try { + String[] flags = null; + String className = null; + if (v.length > 0) { + flags = new String[v.length - 1]; + System.arraycopy(v, 0, flags, 0, flags.length); + className = v[v.length - 1]; + } + System.err.println("Test " + Arrays.asList(flags) + " " + className); + test(flags, className); + } catch (Throwable t) { + t.printStackTrace(); + errors++; + } + } + + if (errors == 0) + System.out.println(count + " tests passed"); + else + throw new Exception(errors + "/" + count + " tests failed"); + } + + void test(String[] flags, String className) throws Exception { + count++; + reset(); + StringBuilder sb = new StringBuilder(); + sb.append("module M { "); + if (className != null) { + sb.append("class "); + for (String f: flags) + sb.append(f + " "); + sb.append(className); + sb.append("; "); + } + sb.append("}"); + String moduleInfoBody = sb.toString(); + + String classPath; // path name of the class + String classBody; + int dot = className.lastIndexOf('.'); + if (dot == -1) { + classBody = "public class " + className + " { }"; + classPath = className + ".java"; + } + else { + classBody = "package " + className.substring(0, dot) + "; public class " + className.substring(dot + 1) + " { }"; + classPath = className.substring(dot + 1) + ".java"; + } + + List<File> files = new ArrayList<File>(); + addFile(files, createFile(classPath, classBody)); + addFile(files, createFile("module-info.java", moduleInfoBody)); + compile(files); + checkModuleClassAttribute("module-info.class", flags, className.replace('.', '/')); + } + + void checkModuleClassAttribute(String file, String[] flags, String className) throws IOException { + System.err.println("Checking " + file); + try { + ClassFile cf = ClassFile.read(new File(classesDir, file)); + ModuleClass_attribute attr = (ModuleClass_attribute) cf.getAttribute(Attribute.ModuleClass); + if (attr == null) { + if (className != null) + error("ModuleClass attribute not found; expected " + Arrays.asList(flags) + " " + className); + } else { + if (className == null) { + error("Unexpected module attribute found: " + attr); + } else { + ConstantPool cp = cf.constant_pool; + checkEqual("class name", className, attr.getClassName(cp)); + checkEqual("class flags", flags, attr.getClassAttributes(cp)); + } + } + } catch (ConstantPoolException e) { + error("Error accessing constant pool " + file + ": " + e); + e.printStackTrace(); + } catch (IOException e) { + error("Error reading " + file + ": " + e); + } + } + + <T> void checkEqual(String tag, T expect, T found) { + if (expect == null ? found == null : expect.equals(found)) + return; + error(tag + " mismatch", "expected " + expect, "found: " + found); + } + + <T> void checkEqual(String tag, T[] expect, T[] found) { + if (expect == null ? found == null : Arrays.equals(expect, found)) + return; + error(tag + " mismatch", "expected " + Arrays.asList(expect), "found: " + Arrays.asList(found)); + } + + /** + * Compile a list of files. + */ + void compile(List<File> files) { + List<String> options = new ArrayList<String>(); + options.addAll(Arrays.asList("-source", "7", "-doe", "-d", classesDir.getPath())); + for (File f: files) + options.add(f.getPath()); + + String[] opts = options.toArray(new String[options.size()]); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(opts, pw); + pw.close(); + + String out = sw.toString(); + if (out.trim().length() > 0) + System.err.println(out); + if (rc != 0) + throw new Error("compilation failed: rc=" + rc); + } + + /** + * Add a file to a list if the file is not null. + */ + void addFile(List<File> files, File file) { + if (file != null) + files.add(file); + } + + + /** + * Create a test file with given content if the content is not null. + */ + File createFile(String path, String body) throws IOException { + if (body == null) + return null; + File file = new File(srcDir, path); + file.getAbsoluteFile().getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + return file; + } + + /** + * Set up empty src and classes directories for a test. + */ + void reset() { + resetDir(srcDir); + resetDir(classesDir); + } + + /** + * Set up an empty directory. + */ + void resetDir(File dir) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + + /** + * Delete a file or a directory (including all its contents). + */ + boolean deleteAll(File file) { + if (file.isDirectory()) { + for (File f: file.listFiles()) + deleteAll(f); + } + return file.delete(); + } + + /** + * Report an error. + */ + void error(String msg, String... more) { + System.err.println("error: " + msg); + for (String s: more) + System.err.println(s); + errors++; + } + + int count; + int errors; + File srcDir = new File("tmp", "src"); // use "tmp" to help avoid accidents + File classesDir = new File("tmp", "classes"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/modules/ModuleModifierTest01.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,238 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802521 + * @summary add support for modules: test basic use of module access modifier + */ + +import java.io.*; +import java.util.*; + +/* + * Test correct handling of module modifiers, including the cases + * involving lookahead, using combinations of + * -- class, interface or enum container + * -- different items to go in the container + */ +public class ModuleModifierTest01 +{ + enum ItemKind { + FIELD("module int field", " = 0;", ";"), + ARRAY1("module int array[]", " = { };", ";"), + ARRAY2("module int[] array", " = { };", ";"), + METHOD("module int method()", ";", " { return 0; }"), + AMBIG1("module Test()", ";", " { }"), // constr for class, err for enum + AMBIG2("module Test()", ";", " { return null; }"), // error for class, method for enum + AMBIG3("public module Test()", ";", " { return null; }"); // method for all + ItemKind(String decl, String intfTail, String classTail) { + this.decl = decl; + this.intfTail = intfTail; + this.classTail = classTail; + } + final String decl; + final String intfTail; + final String classTail; + }; + + enum ClassKind { + CLASS("class Test {"), + INTERFACE("interface Test {"), + ENUM("enum Test { e1 ;"); + ClassKind(String s) { + text = s; + } + final String text; + }; + + public static void main(String... args) throws Exception { + new ModuleModifierTest01().run(); + } + + public void run() throws Exception { + for (ClassKind ck: ClassKind.values()) { + for (ItemKind ik: ItemKind.values()) { + test(ck, ik); + } + } + + if (errors == 0) + System.out.println(count + " tests passed"); + else + throw new Exception(errors + "/" + count + " tests failed"); + } + + void test(ClassKind ck, ItemKind ik) throws Exception { + System.out.println("Test " + (++count) + ": " + ck + " " + ik); + + File testDir = new File("test" + count); + srcDir = new File(testDir, "src"); + classesDir = new File(testDir, "classes"); + resetDirs(srcDir, classesDir); + + boolean needModule; + switch (ik) { + case AMBIG1: needModule = (ck == ClassKind.INTERFACE); break; + case AMBIG2: needModule = (ck != ClassKind.CLASS); break; + case AMBIG3: needModule = true; break; + default: needModule = false; break; + } + + String[] testBody = { + "package p;", + " " + ck.text, + " " + ik.decl + (ck == ClassKind.INTERFACE ? ik.intfTail : ik.classTail), + "}", + (needModule ? "class module { }" : "") + }; + + String[] moduleInfoBody = { + "module m { }" + }; + + File test = createFile(srcDir, "Test.java", join(testBody)); + File module_info = createFile(srcDir, "module-info.java", join(moduleInfoBody)); + boolean expectError = + (ck == ClassKind.ENUM && ik == ItemKind.AMBIG1) + || (ck == ClassKind.CLASS && ik == ItemKind.AMBIG2); + + compile(Arrays.asList(test, module_info), classesDir, null, expectError); + } + + void compile(List<File> files, File classOutDir, List<String> extraOpts, boolean expectError) { + List<String> options = new ArrayList<String>(); + options.add("-XDrawDiagnostics"); + options.addAll(Arrays.asList("-source", "7", "-d", classOutDir.getPath())); + if (extraOpts != null) + options.addAll(extraOpts); + for (File f: files) + options.add(f.getPath()); + + String[] opts = options.toArray(new String[options.size()]); + StringWriter sw = new StringWriter(); + PrintWriter out = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(opts, out); + out.close(); + + if (expectError) { + if (rc == 0) + error(files, "compilation succeeded unexpectedly"); + else { + //log(files, "compilation failed as expected", sw.toString()); + //log(files, "OK"); + } + } + else { + if (rc != 0) + error(files, "compilation failed unexpectedly", sw.toString()); + else { + //log(files, "OK"); + } + } + } + + /** + * Join lines with newline. + */ + String join(String... lines) { + StringBuilder sb = new StringBuilder(); + for (String s: lines) { + sb.append(s); + sb.append("\n"); + } + return sb.toString(); + } + + /** + * Create a test file with given content. + */ + File createFile(File dir, String path, String body) throws IOException { + File file = new File(dir, path); + file.getAbsoluteFile().getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + return file; + } + + /** + * Set up empty directories. + */ + void resetDirs(File... dirs) { + for (File dir: dirs) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + } + + /** + * Delete a file or a directory (including all its contents). + */ + boolean deleteAll(File file) { + if (file.isDirectory()) { + for (File f: file.listFiles()) + deleteAll(f); + } + return file.delete(); + } + + /** + * Report an error. + */ + void error(List<File> files, String msg, String... more) { + System.out.println("test " + files); + System.out.println("error: " + msg); + for (String s: more) + System.out.println(s); + errors++; + //throw new Error(msg); + } + + /** + * Report an error. + */ + void error(String msg, String... more) { + System.out.println("error: " + msg); + for (String s: more) + System.out.println(s); + errors++; + throw new Error(msg); + } + + /** + * Log a message. + */ + void log(List<File> files, String... msgs) { + System.out.println("test " + files); + for (String s: msgs) + System.out.println(s); + } + + int count; + int errors; + File srcDir; + File classesDir; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/modules/ModulePathTest01.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,229 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802521 + * @summary add support for modules: test basic use of module resolution + */ + +import java.io.*; +import java.util.*; + +public class ModulePathTest01 +{ + enum ModuleKind { SINGLE, MULTIPLE }; + + enum FileKind { + CLASS("p", "A.java", "package p; class A { }"), + MODULE_INFO("", "module-info.java", "module M { }"); + FileKind(String pkgName, String path, String body) { + this.pkgName = pkgName; + this.path = path; + this.body = body; + } + final String pkgName; + final String path; + final String body; + } + + enum TestKind { GOOD, BAD }; + + public static void main(String... args) throws Exception { + new ModulePathTest01().run(); + } + + public void run() throws Exception { + for (ModuleKind mk: ModuleKind.values()) { + for (FileKind fk: FileKind.values()) { + for (TestKind tk: TestKind.values()) { + test(mk, fk, tk); + } + } + } + + if (errors == 0) + System.out.println(count + " tests passed"); + else + throw new Exception(errors + "/" + count + " tests failed"); + } + + void test(ModuleKind mk, FileKind fk, TestKind tk) throws IOException { + System.err.println("Test " + (++count) + ": moduleKind " + mk + ": fileKind " + fk + ": testKind " + tk); + + File testDir = new File("test" + count); + srcDir = new File(testDir, "src"); + modulesDir = new File(testDir, "modules"); + resetDirs(srcDir, modulesDir); + + String path = "m/" + (tk == TestKind.GOOD ? fk.pkgName : "BAD") + "/" + fk.path; + File srcFile = createFile(srcDir, path, fk.body); + + List<String> args = new ArrayList<String>(); + if (mk == ModuleKind.MULTIPLE) + append(args, "-modulepath", modulesDir.getPath()); + append(args, "-d", modulesDir.getPath()); + append(args, "-source", "7"); + append(args, "-XDrawDiagnostics"); + + String expectPath = null; // path name of expected output file + String expectDiag = null; // + if (mk == ModuleKind.SINGLE) + expectPath = (fk.pkgName.equals("") ? "" : fk.pkgName + "/") + replaceExtn(fk.path, ".class"); + else if (tk == TestKind.GOOD) + expectPath = "m/" + (fk.pkgName.equals("") ? "" : fk.pkgName + "/") + replaceExtn(fk.path, ".class"); + else if (fk == FileKind.MODULE_INFO) + expectPath = "BAD/module-info.class"; // cannot tell bad package dir from module tag dir + else + expectDiag = "file.in.wrong.directory"; + + Set<File> expectFiles = (expectPath == null) ? + Collections.<File>emptySet() : + Collections.singleton(new File(modulesDir, expectPath)); + + compile(args, Arrays.asList(srcFile), expectDiag); + + Set<File> files = listClasses(modulesDir); + + checkEqual("output files", expectFiles, files); + } + + <T> void append(List<T> list, T... items) { + list.addAll(Arrays.asList(items)); + } + + <T> void checkEqual(String tag, T expect, T found) { + if (expect == null ? found == null : expect.equals(found)) + return; + error(tag + " mismatch", "expected " + expect, "found: " + found); + } + + String replaceExtn(String path, String extn) { + int dot = path.lastIndexOf("."); + return path.substring(0, dot) + extn; + } + + /** + * Compile a list of files. + */ + boolean compile(List<String> opts, List<File> files, String diag) { + List<String> argList = new ArrayList<String>(opts); + for (File f: files) + argList.add(f.getPath()); + System.err.println("Compile: " + argList); + String[] args = argList.toArray(new String[argList.size()]); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(args, pw); + pw.close(); + + String out = sw.toString(); + if (out.trim().length() > 0) + System.err.println(out); + + if (diag == null) { + if (rc == 0) + return true; + else { + error("compilation failed unexpectedly: rc=" + rc); + return false; + } + } else { + if (rc == 0) { + error("compilation succeeded unexpectedly"); + return false; + } else if (!out.contains(diag)) { + error("compilation failed unexpectedly: rc=" + rc); + return false; + } else { + System.err.println("compilation failed as expected"); + return true; + } + } + } + + Set<File> listClasses(File dir) { + Set<File> files = new LinkedHashSet<File>(); + listClasses(dir, files); + return files; + } + // where + private void listClasses(File dir, Set<File> files) { + for (File f: dir.listFiles()) { + if (f.isDirectory()) + listClasses(f, files); + else if (f.getName().endsWith(".class")) + files.add(f); + } + } + + /** + * Create a test file with given content. + */ + File createFile(File dir, String path, String body) throws IOException { + File file = new File(dir, path); + file.getAbsoluteFile().getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + return file; + } + + /** + * Set up empty directories. + */ + void resetDirs(File... dirs) { + for (File dir: dirs) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + } + + /** + * Delete a file or a directory (including all its contents). + */ + boolean deleteAll(File file) { + if (file.isDirectory()) { + for (File f: file.listFiles()) + deleteAll(f); + } + return file.delete(); + } + + /** + * Report an error. + */ + void error(String msg, String... more) { + System.err.println("error: " + msg); + for (String s: more) + System.err.println(s); + errors++; + //throw new Error(msg); + } + + int count; + int errors; + File srcDir; + File modulesDir; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/modules/ModulePermitsAttributeTest01.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,237 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802521 + * @summary add support for modules: test basic use of ModulePermits attribute + */ + +import java.io.*; +import java.util.*; +import com.sun.tools.classfile.*; + +public class ModulePermitsAttributeTest01 { + enum Kind { LIST, DISTINCT }; + + public static void main(String[] args) throws Exception { + new ModulePermitsAttributeTest01().run(); + } + + void run() throws Exception { + for (Kind k: Kind.values()) { + try { + test(k); + } catch (Throwable t) { + t.printStackTrace(); + errors++; + } + } + + if (errors == 0) + System.out.println(count + " tests passed"); + else + throw new Exception(errors + "/" + count + " tests failed"); + } + + void test(Kind kind) throws Exception { + System.err.println("Test " + kind); + reset(); + try { + String[] modules = { "M1", "M2.N2", "M3.N3.O3@1.0", "M4@4.0" }; + + List<String> permitsList = new ArrayList<String>(); + for (String m: modules) { + test(kind, m, permitsList); + permitsList.add(getModuleName(m)); + } + } catch (Throwable t) { + t.printStackTrace(); + errors++; + } + + } + + void test(Kind kind, String moduleId, List<String> permitsList) throws Exception { + // do not reset on each test case so that we can reuse the previously + // generated module classes + count++; + File f = createFile(kind, moduleId, permitsList); + compile(Arrays.asList(f)); + checkPermitsAttribute(getModuleName(moduleId), permitsList); + } + + File createFile(Kind kind, String moduleId, List<String> permitsList) throws IOException { + StringBuilder sb = new StringBuilder(); + sb.append("module " + moduleId + " {"); + if (permitsList.size() > 0) { + switch (kind) { + case DISTINCT: + for (String p: permitsList) { + sb.append(" permits " + p + ";"); + } + break; + case LIST: + String sep = " permits "; + for (String p: permitsList) { + sb.append(sep); + sb.append(p); + sep = ", "; + } + sb.append("; "); + } + } + sb.append(" }"); + return createFile("module-info.java", sb.toString()); + } + + private static final char FS = File.separatorChar; + + void checkPermitsAttribute(String moduleName, List<String> permitsList) { + String file = "module-info.class"; + System.err.println("Checking " + file); + try { + ClassFile cf = ClassFile.read(new File(classesDir, file)); + ModulePermits_attribute attr = + (ModulePermits_attribute) cf.getAttribute(Attribute.ModulePermits); + if (attr == null) { + if (permitsList.size() > 0) + error("ModulePermits attribute not found; expected " + permitsList); + } else { + if (permitsList.size() == 0) { + error("Unexpected module attribute found: " + attr); + } else { + ConstantPool cp = cf.constant_pool; + List<String> attrList = new ArrayList<String>(); + for (int i = 0; i < attr.permits_length; i++) { + attrList.add(cp.getUTF8Value(attr.permits_table[i])); + } + checkEqual("permits", permitsList, attrList); + } + } + } catch (ConstantPoolException e) { + error("Error accessing constant pool " + file + ": " + e); + } catch (IOException e) { + error("Error reading " + file + ": " + e); + } + } + + static String getModuleId(String name, String version) { + return (version == null ? name : name + "@" + version); + } + + static String getModuleName(String moduleId) { + int sep = moduleId.indexOf("@"); + return (sep == -1 ? moduleId : moduleId.substring(0, sep).trim()); + } + + static String getModuleVersion(String moduleId) { + int sep = moduleId.indexOf("@"); + return (sep == -1 ? moduleId : moduleId.substring(sep+1).trim()); + } + + /** + * Create a test file with given content if the content is not null. + */ + File createFile(String path, String body) throws IOException { + if (body == null) + return null; + File file = new File(srcDir, path); + file.getAbsoluteFile().getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + return file; + } + + /** + * Compile a list of files. + */ + void compile(List<File> files) { + List<String> options = new ArrayList<String>(); + options.addAll(Arrays.asList("-source", "7", "-d", classesDir.getPath())); + for (File f: files) + options.add(f.getPath()); + + String[] opts = options.toArray(new String[options.size()]); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(opts, pw); + pw.close(); + + String out = sw.toString(); + if (out.trim().length() > 0) + System.err.println(out); + if (rc != 0) + throw new Error("compilation failed: rc=" + rc); + } + + <T> void checkEqual(String tag, T expect, T found) { + if (expect == null ? found == null : expect.equals(found)) + return; + error(tag + " mismatch", "expected " + expect, "found: " + found); + } + + /** + * Set up empty src and classes directories for a test. + */ + void reset() { + resetDir(srcDir); + resetDir(classesDir); + } + + /** + * Set up an empty directory. + */ + void resetDir(File dir) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + + /** + * Delete a file or a directory (including all its contents). + */ + boolean deleteAll(File file) { + if (file.isDirectory()) { + for (File f: file.listFiles()) + deleteAll(f); + } + return file.delete(); + } + + /** + * Report an error. + */ + void error(String msg, String... more) { + System.err.println("error: " + msg); + for (String s: more) + System.err.println(s); + errors++; + } + + int count; + int errors; + File srcDir = new File("tmp", "src"); // use "tmp" to help avoid accidents + File classesDir = new File("tmp", "classes"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/modules/ModuleProvidesAttributeTest01.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,219 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802521 + * @summary add support for modules: test basic use of ModuleProvides attribute + */ + +import java.io.*; +import java.util.*; +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.ConstantPool.CONSTANT_ModuleId_info; + + +public class ModuleProvidesAttributeTest01 { + + public static void main(String[] args) throws Exception { + new ModuleProvidesAttributeTest01().run(); + } + + void run() throws Exception { + reset(); + try { + String[] modules = { "M1", "M2.N2", "M3.N3.O3@1.0", "M4@4.0" }; + + List<String> providesList = new ArrayList<String>(); + for (String m: modules) { + test(m, providesList); + providesList.add(m); + } + } catch (Throwable t) { + t.printStackTrace(); + errors++; + } + + if (errors == 0) + System.out.println(count + " tests passed"); + else + throw new Exception(errors + "/" + count + " tests failed"); + } + + void test(String moduleId, List<String> providesList) throws Exception { + // do not reset on each test so that we can reuse the previously + // generated module classes + count++; + File f = createFile(moduleId, providesList); + compile(Arrays.asList(f)); + checkProvidesAttribute(getModuleName(moduleId), providesList); + } + + File createFile(String moduleId, List<String> providesList) throws IOException { + StringBuilder sb = new StringBuilder(); + sb.append("module " + moduleId); + if (providesList.size() > 0) { + String sep = " provides "; + for (String p: providesList) { + sb.append(sep); + sb.append(p); + sep = ", "; + } + } + sb.append(" { }"); + return createFile("module-info.java", sb.toString()); + } + + private static final char FS = File.separatorChar; + + void checkProvidesAttribute(String moduleName, List<String> providesList) { + String file = "module-info.class"; + System.err.println("Checking " + file); + try { + ClassFile cf = ClassFile.read(new File(classesDir, file)); + ModuleProvides_attribute attr = + (ModuleProvides_attribute) cf.getAttribute(Attribute.ModuleProvides); + if (attr == null) { + if (providesList.size() > 0) + error("ModuleProvides attribute not found; expected " + providesList); + } else { + if (providesList.size() == 0) { + error("Unexpected module attribute found: " + attr); + } else { + ConstantPool cp = cf.constant_pool; + List<String> attrList = new ArrayList<String>(); + for (int i = 0; i < attr.provides_length; i++) { + CONSTANT_ModuleId_info info = cp.getModuleIdInfo(attr.provides_table[i]); + String name = cp.getUTF8Value(info.name_index); + String version = (info.version_index == 0 ? null : cp.getUTF8Value(info.version_index)); + attrList.add(getModuleId(name, version)); + } + checkEqual("provides", providesList, attrList); + } + } + } catch (ConstantPoolException e) { + error("Error accessing constant pool " + file + ": " + e); + } catch (IOException e) { + error("Error reading " + file + ": " + e); + } + } + + static String getModuleId(String name, String version) { + return (version == null ? name : name + "@" + version); + } + + static String getModuleName(String moduleId) { + int sep = moduleId.indexOf("@"); + return (sep == -1 ? moduleId : moduleId.substring(0, sep).trim()); + } + + static String getModuleVersion(String moduleId) { + int sep = moduleId.indexOf("@"); + return (sep == -1 ? moduleId : moduleId.substring(sep+1).trim()); + } + + /** + * Create a test file with given content if the content is not null. + */ + File createFile(String path, String body) throws IOException { + if (body == null) + return null; + File file = new File(srcDir, path); + file.getAbsoluteFile().getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + return file; + } + + /** + * Compile a list of files. + */ + void compile(List<File> files) { + List<String> options = new ArrayList<String>(); + options.addAll(Arrays.asList("-source", "7", "-d", classesDir.getPath())); + for (File f: files) + options.add(f.getPath()); + + String[] opts = options.toArray(new String[options.size()]); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(opts, pw); + pw.close(); + + String out = sw.toString(); + if (out.trim().length() > 0) + System.err.println(out); + if (rc != 0) + throw new Error("compilation failed: rc=" + rc); + } + + <T> void checkEqual(String tag, T expect, T found) { + if (expect == null ? found == null : expect.equals(found)) + return; + error(tag + " mismatch", "expected " + expect, "found: " + found); + } + + /** + * Set up empty src and classes directories for a test. + */ + void reset() { + resetDir(srcDir); + resetDir(classesDir); + } + + /** + * Set up an empty directory. + */ + void resetDir(File dir) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + + /** + * Delete a file or a directory (including all its contents). + */ + boolean deleteAll(File file) { + if (file.isDirectory()) { + for (File f: file.listFiles()) + deleteAll(f); + } + return file.delete(); + } + + /** + * Report an error. + */ + void error(String msg, String... more) { + System.err.println("error: " + msg); + for (String s: more) + System.err.println(s); + errors++; + } + + int count; + int errors; + File srcDir = new File("tmp", "src"); // use "tmp" to help avoid accidents + File classesDir = new File("tmp", "classes"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/modules/ModuleRequiresAttributeTest01.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,280 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802521 + * @summary add support for modules: test basic use of ModuleRequires attribute + */ + +import java.io.*; +import java.util.*; +import com.sun.tools.classfile.*; + +public class ModuleRequiresAttributeTest01 { + enum Flag { PRIVATE, OPTIONAL, LOCAL; + static Flag of(String s) { + for (Flag f: values()) { + if (f.toString().toLowerCase().equals(s)) + return f; + } + return null; + }}; + enum MultiKind { LIST, DISTINCT }; + + public static void main(String[] args) throws Exception { + new ModuleRequiresAttributeTest01().run(); + } + + void run() throws Exception { + for (int i = 0; i < (1 << Flag.values().length); i++) { + Set<Flag> flags = new LinkedHashSet<Flag>(); + if ((i & 4) != 0) flags.add(Flag.PRIVATE); + if ((i & 2) != 0) flags.add(Flag.OPTIONAL); + if ((i & 1) != 0) flags.add(Flag.LOCAL); + for (MultiKind k: MultiKind.values()) { + try { + test(flags, k); + } catch (Throwable t) { + t.printStackTrace(); + errors++; + } + } + } + + if (errors == 0) + System.out.println(count + " tests passed"); + else + throw new Exception(errors + "/" + count + " tests failed"); + } + + void test(Set<Flag> flags, MultiKind kind) throws Exception { + System.err.println("Test group " + (++group) + " " + flags + " " + kind); + srcDir = new File("group" + group + "/src"); + modulesDir = new File("group" + group + "/modules"); + resetDirs(srcDir, modulesDir); + try { + String[] modules = { "M1", "M2.N2", "M3.N3.O3@1.0", "M4@4.0" }; + List<String> requiresList = new ArrayList<String>(); + for (String m: modules) { + test(flags, kind, m, requiresList); + requiresList.add(m); + } + } catch (Throwable t) { + t.printStackTrace(); + errors++; + } + + } + + void test(Set<Flag> flags, MultiKind kind, String moduleId, List<String> requiresList) throws Exception { + // do not reset on each test case so that we can reuse the previously + // generated module classes + System.err.println("Test " + (++count) + " " + moduleId + " " + requiresList); + File f = createFile(flags, kind, moduleId, requiresList); + compile(Arrays.asList(f)); + checkRequiresAttribute(getModuleName(moduleId), flags, requiresList); + } + + File createFile(Set<Flag> flags, MultiKind kind, String moduleId, List<String> requiresList) throws IOException { + StringBuilder sb = new StringBuilder(); + sb.append("module " + moduleId + " {"); + if (requiresList.size() > 0) { + switch (kind) { + case DISTINCT: + for (String p: requiresList) { + sb.append(" requires " + flags2String(flags) + p + ";"); + } + break; + case LIST: + String sep = " requires " + flags2String(flags); + for (String p: requiresList) { + sb.append(sep); + sb.append(p); + sep = ", "; + } + sb.append("; "); + } + } + sb.append(" }"); + return createFile("test" + count + "/module-info.java", sb.toString()); + } + + static String flags2String(Set<Flag> flags) { + StringBuilder sb = new StringBuilder(); + for (Flag f: flags) { + sb.append(f.toString().toLowerCase() + " "); + } + return sb.toString(); + } + + private static final char FS = File.separatorChar; + + void checkRequiresAttribute(String moduleName, Set<Flag> flags, List<String> requiresList) { + String file = "test" + count + "/module-info.class"; + System.err.println("Checking " + file); + try { + ClassFile cf = ClassFile.read(new File(modulesDir, file)); + ModuleRequires_attribute attr = + (ModuleRequires_attribute) cf.getAttribute(Attribute.ModuleRequires); + if (attr == null) { + if (requiresList.size() > 0) + error("ModuleRequires attribute not found; expected " + flags + " " + requiresList); + } else { + ConstantPool cp = cf.constant_pool; + List<String> attrList = new ArrayList<String>(); + for (int i = 0; i < attr.requires_length; i++) { + ModuleRequires_attribute.Entry e = attr.requires_table[i]; + if (isSynthetic(e, cp)) + continue; + ConstantPool.CONSTANT_ModuleId_info mid = cp.getModuleIdInfo(e.requires_index); + String mn = cp.getUTF8Value(mid.name_index); + String mvq = (mid.version_index == 0 ? null : cp.getUTF8Value(mid.version_index)); + attrList.add(getModuleId(mn, mvq)); + Set<Flag> attrFlags = new HashSet<Flag>(); + for (int f = 0; f < e.attributes_length; f++) + attrFlags.add(Flag.of(cp.getUTF8Value(e.attributes[f]))); + checkEqual("flags", flags, attrFlags); + } + checkEqual("requires", requiresList, attrList); + } + } catch (ConstantPoolException e) { + error("Error accessing constant pool " + file + ": " + e); + } catch (IOException e) { + error("Error reading " + file + ": " + e); + } + } + + static boolean isSynthetic(ModuleRequires_attribute.Entry e, ConstantPool cp) + throws ConstantPoolException { + for (int f = 0; f < e.attributes_length; f++) { + if (cp.getUTF8Value(e.attributes[f]).equals("synthetic")) + return true; + } + return false; + } + + static String getModuleId(String name, String version) { + return (version == null ? name : name + "@" + version); + } + + static String getModuleName(String moduleId) { + int sep = moduleId.indexOf("@"); + return (sep == -1 ? moduleId : moduleId.substring(0, sep).trim()); + } + + static String getModuleVersion(String moduleId) { + int sep = moduleId.indexOf("@"); + return (sep == -1 ? moduleId : moduleId.substring(sep+1).trim()); + } + + /** + * Create a test file with given content if the content is not null. + */ + File createFile(String path, String body) throws IOException { + if (body == null) + return null; + File file = new File(srcDir, path); + file.getAbsoluteFile().getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + return file; + } + + /** + * Compile a list of files. + */ + void compile(List<File> files) { + List<String> argList = new ArrayList<String>(); + argList.addAll(Arrays.asList("-source", "7", "-d", modulesDir.getPath(), "-modulepath", modulesDir.getPath())); + for (File f: files) + argList.add(f.getPath()); + + String[] args = argList.toArray(new String[argList.size()]); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(args, pw); + pw.close(); + + String out = sw.toString(); + if (out.trim().length() > 0) + System.err.println(out); + if (rc != 0) + throw new Error("compilation failed: rc=" + rc); + } + + <T> void checkEqual(String tag, T expect, T found) { + if (expect == null ? found == null : expect.equals(found)) + return; + error(tag + " mismatch", "expected " + expect, "found: " + found); + } + + /** + * Set up empty directories. + */ + void resetDirs(File... dirs) { + for (File dir: dirs) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + } + + /** + * Set up an empty directory. + */ + void resetDir(File dir) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + + /** + * Delete a file or a directory (including all its contents). + */ + boolean deleteAll(File file) { + if (file.isDirectory()) { + for (File f: file.listFiles()) + deleteAll(f); + } + return file.delete(); + } + + /** + * Report an error. + */ + void error(String msg, String... more) { + System.err.println("error: " + msg); + for (String s: more) + System.err.println(s); + errors++; + throw new Error(); + } + + int group; + int count; + int errors; + File srcDir; + File modulesDir; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/modules/ModuleResolverTest01.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,203 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802521 + * @summary add support for modules: test basic use of module resolution + */ + +import java.io.*; +import java.util.*; +import com.sun.tools.classfile.*; + +/* + * Test compilation of module-info.java on the command line + * and interaction with path options. + */ +public class ModuleResolverTest01 +{ + public static void main(String... args) throws Exception { + new ModuleResolverTest01().run(); + } + + public void run() throws Exception { + boolean[] values = { false, true }; + for (boolean modulepath : values) { + for (boolean classpath : values) { + for (boolean sourcepath : values) { + test(modulepath, classpath, sourcepath); + } + } + } + + if (errors == 0) + System.out.println(count + " tests passed"); + else + throw new Exception(errors + "/" + count + " tests failed"); + } + + void test(boolean mp, boolean cp, boolean sp) throws IOException { + System.err.println("Test " + (++count) + ": modulepath " + mp + " classpath " + cp + " sourcepath " + sp); + + File srcDir = new File("test" + count, "src"); + File classesDir = new File("test" + count, "classes"); + resetDirs(srcDir, classesDir); + + boolean modular = (mp && !cp); + + String moduleId = "M@1.0"; + File srcFile = createFile(srcDir, + modular ? "m/module-info.java" : "module-info.java", + "module " + moduleId + " { }"); + + List<String> args = new ArrayList<String>(); + if (cp) append(args, "-classpath", "."); + if (sp) append(args, "-sourcepath", "."); + if (mp) append(args, "-modulepath", "."); + append(args, "-d", classesDir.getPath()); + append(args, "-source", "7"); + compile(args, srcFile); + + checkModuleAttribute(classesDir, + modular ? "m/module-info.class" : "module-info.class", + moduleId); + } + + void checkModuleAttribute(File dir, String path, String moduleId) throws IOException { + System.err.println("Checking " + path); + try { + ClassFile cf = ClassFile.read(new File(dir, path)); + Module_attribute attr = (Module_attribute) cf.getAttribute(Attribute.Module); + if (attr == null) { + if (moduleId != null) + error("Module attribute not found; expected " + moduleId); + } else { + if (moduleId == null) { + error("Unexpected module attribute found: " + attr); + } else { + String name, version; + int sep = moduleId.indexOf("@"); + if (sep == -1) { + name = moduleId; + version = null; + } else { + name = moduleId.substring(0, sep); + version = moduleId.substring(sep + 1); + } + ConstantPool cp = cf.constant_pool; + checkEqual("module name", name, attr.getModuleName(cp)); + checkEqual("module version", version, attr.getModuleVersion(cp)); + } + } + } catch (ConstantPoolException e) { + error("Error accessing constant pool " + path + ": " + e); + } catch (FileNotFoundException e) { + error("File not found: " + path); + } catch (IOException e) { + error("Error reading " + path + ": " + e); + } + } + + void append(List<String> list, String... args) { + list.addAll(Arrays.asList(args)); + } + + <T> void checkEqual(String tag, T expect, T found) { + if (expect == null ? found == null : expect.equals(found)) + return; + error(tag + " mismatch", "expected " + expect, "found: " + found); + } + + /** + * Compile a list of files. + */ + void compile(List<String> opts, File... files) { + List<String> argList = new ArrayList<String>(opts); + for (File f: files) + argList.add(f.getPath()); + System.err.println("Compile: " + argList); + String[] args = argList.toArray(new String[argList.size()]); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(args, pw); + pw.close(); + + String out = sw.toString(); + if (out.trim().length() > 0) + System.out.println(out); + if (rc != 0) + throw new Error("compilation failed: rc=" + rc); + } + + /** + * Create a test file with given content. + */ + File createFile(File dir, String path, String body) throws IOException { + File file = new File(dir, path); + file.getAbsoluteFile().getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + return file; + } + + /** + * Set up empty directories. + */ + void resetDirs(File... dirs) { + for (File dir: dirs) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + } + + /** + * Delete a file or a directory (including all its contents). + */ + boolean deleteAll(File file) { + if (file.isDirectory()) { + for (File f: file.listFiles()) + deleteAll(f); + } + return file.delete(); + } + + /** + * Report an error. + */ + void error(String msg, String... more) { + System.err.println("error: " + msg); + for (String s: more) + System.err.println(s); + errors++; + throw new Error(msg); + } + + int count; + int errors; +} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/modules/ModuleResolverTest02.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,229 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802521 + * @summary add support for modules: test basic use of module resolution + */ + +import java.io.*; +import java.util.*; +import com.sun.tools.classfile.*; + +/* + * Test compilation of module-info.java on the command line + * and interaction with path options. + */ +public class ModuleResolverTest02 +{ + enum Kind { + CMD_LINE, + SOURCE_PATH, + CLASS_PATH, + MODULE_PATH + }; + + static final String moduleId = "M@1.0"; + + public static void main(String... args) throws Exception { + new ModuleResolverTest02().run(); + } + + public void run() throws Exception { + setup(); + + for (Kind mk: Kind.values()) { + for (Kind ak: Kind.values()) { + if (mk == Kind.CMD_LINE || ak == Kind.CMD_LINE) + test(mk, ak); + } + } + } + + // Initialize copies of src files and class files to be used in individual tests + void setup() throws IOException { + File srcDir = new File("ref", "src/m"); + File classesDir = new File("ref", "modules/m"); + resetDirs(srcDir, classesDir); + + File miFile = createFile(srcDir, "module-info.java", "module " + moduleId + " { }"); + File aFile = createFile(srcDir, "p/A.java", "package p; class A { }"); + + List<String> args = new ArrayList<String>(); + append(args, "-d", classesDir.getPath()); + append(args, "-source", "7"); + compile(args, miFile, aFile); + } + + void test(Kind mk, Kind ak) throws IOException { + System.err.println("Test " + (++count) + ": module_info " + mk + " class A " + ak); + File testDir = new File("test" + count); + File testOutDir = new File(testDir, "out"); + testOutDir.mkdirs(); + + List<String> args = new ArrayList<String>(); + List<File> files = new ArrayList<File>(); + + boolean multiModuleMode = (mk == Kind.MODULE_PATH || ak == Kind.MODULE_PATH); + + setup(testDir, mk, "module-info", args, files, multiModuleMode); + setup(testDir, ak, "p/A", args, files, multiModuleMode); + append(args, "-source", "7"); + append(args, "-d", testOutDir.getPath()); + + compile(args, files.toArray(new File[files.size()])); + + List<File> expect = new ArrayList<File>(); + if (ak == Kind.CMD_LINE) + expect.add(new File(testOutDir, (multiModuleMode ? "m/" : "") + "p/A.class")); + if (mk == Kind.CMD_LINE || mk == Kind.SOURCE_PATH) + expect.add(new File(testOutDir, (multiModuleMode ? "m/" : "") + "module-info.class")); + + for (File f: expect) { + if (!f.exists()) + error("File not found: " + f); + } + } + + void setup(File testDir, Kind kind, String base, + List<String> compileArgs, List<File> compileFiles, + boolean multiModuleMode) + throws IOException { + + switch (kind) { + case CMD_LINE: + compileFiles.add(new File("ref/src/m/" + base + ".java")); + break; + case SOURCE_PATH: + copy("src/m/" + base + ".java", testDir); + compileArgs.add("-sourcepath"); + compileArgs.add(testDir + "/src" + (multiModuleMode ? "" : "/m")); + break; + case CLASS_PATH: + copy("modules/m/" + base + ".class", testDir); + compileArgs.add("-classpath"); + compileArgs.add(testDir + "/modules/m"); + break; + case MODULE_PATH: + copy("modules/m/" + base + ".class", testDir); + compileArgs.add("-modulepath"); + compileArgs.add(testDir + "/modules"); + break; + } + } + + void copy(String path, File dest) throws IOException { + File from = new File("ref", path); + byte[] data = new byte[(int) from.length()]; + DataInputStream in = new DataInputStream(new FileInputStream(from)); + in.readFully(data); + in.close(); + + File to = new File(dest, path); + to.getParentFile().mkdirs(); + OutputStream out = new FileOutputStream(to); + out.write(data); + out.close(); + } + + void append(List<String> list, String... args) { + list.addAll(Arrays.asList(args)); + } + + <T> void checkEqual(String tag, T expect, T found) { + if (expect == null ? found == null : expect.equals(found)) + return; + error(tag + " mismatch", "expected " + expect, "found: " + found); + } + + /** + * Compile a list of files. + */ + void compile(List<String> opts, File... files) { + List<String> argList = new ArrayList<String>(opts); + for (File f: files) + argList.add(f.getPath()); + System.err.println("Compile: " + argList); + String[] args = argList.toArray(new String[argList.size()]); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(args, pw); + pw.close(); + + String out = sw.toString(); + if (out.trim().length() > 0) + System.err.println(out); + if (rc != 0) + throw new Error("compilation failed: rc=" + rc); + } + + /** + * Create a test file with given content. + */ + File createFile(File dir, String path, String body) throws IOException { + File file = new File(dir, path); + file.getAbsoluteFile().getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + return file; + } + + /** + * Set up empty directories. + */ + void resetDirs(File... dirs) { + for (File dir: dirs) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + } + + /** + * Delete a file or a directory (including all its contents). + */ + boolean deleteAll(File file) { + if (file.isDirectory()) { + for (File f: file.listFiles()) + deleteAll(f); + } + return file.delete(); + } + + /** + * Report an error. + */ + void error(String msg, String... more) { + System.out.println("error: " + msg); + for (String s: more) + System.out.println(s); + errors++; + throw new Error(msg); + } + + int count; + int errors; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/modules/ModuleResolverTest03.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,316 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802521 + * @summary add support for modules: test basic use of Module Resolver + */ + +import java.io.*; +import java.util.*; + +public class ModuleResolverTest03 { + static class Test { + Test(String desc, Unit... units) { + this.desc = desc; + this.units = units; + } + final String desc; + final Unit[] units; + }; + + // uugh can't static import these because this class is in unnamed package + Unit.Kind CMDLINE = Unit.Kind.CMDLINE; + Unit.Kind SRCPATH = Unit.Kind.SRCPATH; + + static class Unit { + enum Kind { CMDLINE, SRCPATH }; + Unit(Kind kind, String path, String text) { + this.kind = kind; + this.path = path; + this.text = text; + } + final Kind kind; + final String path; + final String text; + } + + Test[] tests = { + new Test( + "no versions; expect m1, m3, m5", + new Unit(CMDLINE, "m1/p/A.java", "package p; class A { q.B b; }"), + new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m3; }"), + new Unit(SRCPATH, "m2/module-info.java", "module m2 { requires m4; }"), + new Unit(SRCPATH, "m2/q/B.java", "ERROR"), + new Unit(SRCPATH, "m3/module-info.java", "module m3 { requires m5; }"), + new Unit(SRCPATH, "m4/module-info.java", "module m4 { }"), + new Unit(SRCPATH, "m4/q/B.java", "ERROR"), + new Unit(SRCPATH, "m5/module-info.java", "module m5 { }"), + new Unit(SRCPATH, "m5/q/B.java", "package q; public class B { }") + ), + + new Test( + "no versions; provides; expect m1, m3, m5", + new Unit(CMDLINE, "m1/p/A.java", "package p; class A { q.B b; }"), + new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m3; }"), + new Unit(SRCPATH, "m2/module-info.java", "module m2 { requires m4; }"), + new Unit(SRCPATH, "m2/q/B.java", "ERROR"), + new Unit(SRCPATH, "m3/module-info.java", "module mX provides m3 { requires m5; }"), + new Unit(SRCPATH, "m4/module-info.java", "module m4 { }"), + new Unit(SRCPATH, "m4/q/B.java", "ERROR"), + new Unit(SRCPATH, "m5/module-info.java", "module m5 { }"), + new Unit(SRCPATH, "m5/q/B.java", "package q; public class B { }") + ), + + new Test( + "no version in requires; single versions available; expect m1@1.0, m3@1.0, m5@1.0", + new Unit(CMDLINE, "m1/p/A.java", "package p; class A { q.B b; }"), + new Unit(SRCPATH, "m1/module-info.java", "module m1@1.0 { requires m3; }"), + new Unit(SRCPATH, "m2/module-info.java", "module m2@1.0 { requires m4; }"), + new Unit(SRCPATH, "m2/q/B.java", "ERROR"), + new Unit(SRCPATH, "m3/module-info.java", "module m3@1.0 { requires m5; }"), + new Unit(SRCPATH, "m4/module-info.java", "module m4@1.0 { }"), + new Unit(SRCPATH, "m4/q/B.java", "ERROR"), + new Unit(SRCPATH, "m5/module-info.java", "module m5@1.0 { }"), + new Unit(SRCPATH, "m5/q/B.java", "package q; public class B { }") + ), + + new Test( + "version in requires; multiple versions available; expect m1@1.0, m3@1.0, m5@1.0", + new Unit(CMDLINE, "m11/p/A.java", "package p; class A { q.B b; }"), + new Unit(SRCPATH, "m11/module-info.java", "module m1@1.0 { requires m3@1.0; }"), + new Unit(SRCPATH, "m21/module-info.java", "module m2@1.0 { requires m4@1.0; }"), + new Unit(SRCPATH, "m21/q/B.java", "ERROR"), + new Unit(SRCPATH, "m22/module-info.java", "module m2@2.0 { requires m4@2.0; }"), + new Unit(SRCPATH, "m22/q/B.java", "ERROR"), + new Unit(SRCPATH, "m31/module-info.java", "module m3@1.0 { requires m5@1.0; }"), + new Unit(SRCPATH, "m32/module-info.java", "module m3@2.0 { requires m5@2.0; }"), + new Unit(SRCPATH, "m41/module-info.java", "module m4@1.0 { }"), + new Unit(SRCPATH, "m41/q/B.java", "ERROR"), + new Unit(SRCPATH, "m42/module-info.java", "module m4@2.0 { }"), + new Unit(SRCPATH, "m42/q/B.java", "ERROR"), + new Unit(SRCPATH, "m51/module-info.java", "module m5@1.0 { }"), + new Unit(SRCPATH, "m51/q/B.java", "package q; public class B { }"), + new Unit(SRCPATH, "m52/module-info.java", "module m5@2.0 { }"), + new Unit(SRCPATH, "m52/q/B.java", "ERROR") + ), + + new Test( + "no versions, simple cycle (m3,m5); expect m1, m3, m5", + new Unit(CMDLINE, "m1/p/A.java", "package p; class A { q.B b; }"), + new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m3; }"), + new Unit(SRCPATH, "m2/module-info.java", "module m2 { requires m4; }"), + new Unit(SRCPATH, "m2/q/B.java", "ERROR"), + new Unit(SRCPATH, "m3/module-info.java", "module m3 { requires m5; }"), + new Unit(SRCPATH, "m4/module-info.java", "module m4 { }"), + new Unit(SRCPATH, "m4/q/B.java", "ERROR"), + new Unit(SRCPATH, "m5/module-info.java", "module m5 { requires m3;}"), + new Unit(SRCPATH, "m5/q/B.java", "package q; public class B { }") + ), + + new Test( + "no versions, bigger cycle (m3,m4,m5); expect m1, m3, m4, m5", + new Unit(CMDLINE, "m1/p/A.java", "package p; class A { q.B b; }"), + new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m3; }"), + new Unit(SRCPATH, "m2/module-info.java", "module m2 { requires m4; }"), + new Unit(SRCPATH, "m2/q/B.java", "ERROR"), + new Unit(SRCPATH, "m3/module-info.java", "module m3 { requires m4; }"), + new Unit(SRCPATH, "m4/module-info.java", "module m4 { requires m5; }"), + new Unit(SRCPATH, "m5/module-info.java", "module m5 { requires m3;}"), + new Unit(SRCPATH, "m5/q/B.java", "package q; public class B { }") + ), + + new Test( + "no versions, two cycles (m3,m4),(m5,m6); expect m1, m3, m4, m5,m6", + new Unit(CMDLINE, "m1/p/A.java", "package p; class A { q.B b; }"), + new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m3; }"), + new Unit(SRCPATH, "m2/module-info.java", "module m2 { requires m4; }"), + new Unit(SRCPATH, "m2/q/B.java", "ERROR"), + new Unit(SRCPATH, "m3/module-info.java", "module m3 { requires m4; requires m5; }"), + new Unit(SRCPATH, "m4/module-info.java", "module m4 { requires m3; }"), + new Unit(SRCPATH, "m5/module-info.java", "module m5 { requires m6;}"), + new Unit(SRCPATH, "m6/module-info.java", "module m6 { requires m5;}"), + new Unit(SRCPATH, "m6/q/B.java", "package q; public class B { }") + ), + + new Test( + "no versions, complex cycle (m3,m4,m5,m6); expect m1, m3, m4, m5,m6", + new Unit(CMDLINE, "m1/p/A.java", "package p; class A { q.B b; }"), + new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m3; }"), + new Unit(SRCPATH, "m2/module-info.java", "module m2 { requires m4; }"), + new Unit(SRCPATH, "m2/q/B.java", "ERROR"), + new Unit(SRCPATH, "m3/module-info.java", "module m3 { requires m4; requires m5; }"), + new Unit(SRCPATH, "m4/module-info.java", "module m4 { requires m3; }"), + new Unit(SRCPATH, "m5/module-info.java", "module m5 { requires m6;}"), + new Unit(SRCPATH, "m6/module-info.java", "module m6 { requires m3; requires m5;}"), + new Unit(SRCPATH, "m6/q/B.java", "package q; public class B { }") + ), + }; + + public static void main(String[] args) throws Exception { + new ModuleResolverTest03().run(); + } + + void run() throws Exception { + for (Test test: tests) { + try { + test(test); + } catch (Throwable t) { + t.printStackTrace(); + errors++; + } + } + + if (errors == 0) + System.out.println(count + " tests passed"); + else + throw new Exception(errors + "/" + count + " tests failed"); + } + + void test(Test t) throws IOException { + System.err.println("Test " + (++count) + " " + t.desc); + + File testDir = new File("test" + count); + srcDir = new File(testDir, "src"); + modulesDir = new File(testDir, "modules"); + resetDirs(srcDir, modulesDir); + + List<String> opts = new ArrayList<String>(); + add(opts, "-source", "7"); + add(opts, "-modulepath", modulesDir.getPath()); + add(opts, "-d", modulesDir.getPath()); + + boolean srcPath = false; + List<File> files = new ArrayList<File>(); + + for (Unit u: t.units) { + File f = createFile(u.path, u.text); + switch (u.kind) { + case CMDLINE: files.add(f); break; + case SRCPATH: srcPath = true; break; + } + } + + if (srcPath) + add(opts, "-sourcepath", srcDir.getPath()); + + compile(opts, files); + + for (Unit u: t.units) { + File f = new File(modulesDir, replaceExtension(u.path, ".class")); + if (u.text.equals("ERROR")) { + if (f.exists()) + error("unexpected output found: " + f); + } else { + if (!f.exists()) + error("expected file not found: " + f); + } + } + } + + <T> void add(List<T> list, T... items) { + for (T t: items) + list.add(t); + } + + String replaceExtension(String path, String extn) { + int dot = path.lastIndexOf("."); + return path.substring(0, dot) + extn; + } + + /** + * Compile a list of files. + */ + void compile(List<String> opts, List<File> files) { + List<String> argList = new ArrayList<String>(); + argList.addAll(opts); + for (File f: files) + argList.add(f.getPath()); + + System.err.println("compile: " + argList); + + String[] args = argList.toArray(new String[argList.size()]); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(args, pw); + pw.close(); + + String out = sw.toString(); + if (out.trim().length() > 0) + System.err.println(out); + if (rc != 0) + throw new Error("compilation failed: rc=" + rc); + } + + /** + * Create a test file with given content if the content is not null. + */ + File createFile(String path, String body) throws IOException { + if (body == null) + return null; + File file = new File(srcDir, path); + file.getAbsoluteFile().getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + return file; + } + + /** + * Set up empty directories. + */ + void resetDirs(File... dirs) { + for (File dir: dirs) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + } + + /** + * Delete a file or a directory (including all its contents). + */ + boolean deleteAll(File file) { + if (file.isDirectory()) { + for (File f: file.listFiles()) + deleteAll(f); + } + return file.delete(); + } + + /** + * Report an error. + */ + void error(String msg, String... more) { + System.err.println("error: " + msg); + for (String s: more) + System.err.println(s); + errors++; + } + + int count; + int errors; + File srcDir; + File modulesDir; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/modules/ModuleResolverTest04.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,257 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802521 + * @summary add support for modules: test basic use of Module Resolver + */ + +import java.io.*; +import java.util.*; + +public class ModuleResolverTest04 { + static class Test { + Test(String desc, String diag, Unit... units) { + this.desc = desc; + this.diag = diag; + this.units = units; + } + final String desc; + final String diag; + final Unit[] units; + }; + + // uugh can't static import these because this class is in unnamed package + Unit.Kind CMDLINE = Unit.Kind.CMDLINE; + Unit.Kind SRCPATH = Unit.Kind.SRCPATH; + + static class Unit { + enum Kind { CMDLINE, SRCPATH }; + Unit(Kind kind, String path, String text) { + this.kind = kind; + this.path = path; + this.text = text; + } + final Kind kind; + final String path; + final String text; + } + + Test[] tests = { + new Test( + "no version available", + "compiler.err.mdl.no.version.available", + new Unit(CMDLINE, "m1/p/A.java", "package p; class A { q.B b; }"), + new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m2; }"), + new Unit(SRCPATH, "m1/q/B.java", "package q; public class B { }") + ), + + new Test( + "no unique version available", + "compiler.err.mdl.no.unique.version.available", + new Unit(CMDLINE, "m1/p/A.java", "package p; class A { q.B b; }"), + new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m2; }"), + new Unit(SRCPATH, "m21/module-info.java", "module m2@1.0 { }"), + new Unit(SRCPATH, "m21/q/B.java", "package q; public class B { }"), + new Unit(SRCPATH, "m22/module-info.java", "module m2@2.0 { }"), + new Unit(SRCPATH, "m22/q/B.java", "package q; public class B { }") + ), + + new Test( + "required version not available", + "compiler.err.mdl.required.version.not.available", + new Unit(CMDLINE, "m1/p/A.java", "package p; class A { q.B b; }"), + new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m2@3.0; }"), + new Unit(SRCPATH, "m21/module-info.java", "module m2@1.0 { }"), + new Unit(SRCPATH, "m22/module-info.java", "module m2@2.0 { }") + ), + + new Test( + "duplicate versions available", + "compiler.err.mdl.duplicate.definition", + new Unit(CMDLINE, "m1/p/A.java", "package p; class A { q.B b; }"), + new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m2; }"), + new Unit(SRCPATH, "m21a/module-info.java", "module m2@1.0 { }"), + new Unit(SRCPATH, "m21a/q/B.java", "package q; public class B { }"), + new Unit(SRCPATH, "m21b/module-info.java", "module m2@1.0 { }"), + new Unit(SRCPATH, "m22a/q/B.java", "package q; public class B { }") + ), + + new Test( + "duplicate versions available (provides)", + "compiler.err.mdl.duplicate.definition", + new Unit(CMDLINE, "m1/p/A.java", "package p; class A { q.B b; }"), + new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m2@1.0; }"), + new Unit(SRCPATH, "m21/module-info.java", "module m2@1.0 { }"), + new Unit(SRCPATH, "m21/q/B.java", "package q; public class B { }"), + new Unit(SRCPATH, "m22/module-info.java", "module m2@2.0 provides m2@1.0 { }"), + new Unit(SRCPATH, "m22/q/B.java", "package q; public class B { }") + ) + }; + + public static void main(String[] args) throws Exception { + new ModuleResolverTest04().run(); + } + + void run() throws Exception { + for (Test test: tests) { + try { + test(test); + } catch (Throwable t) { + t.printStackTrace(); + errors++; + } + } + + if (errors == 0) + System.out.println(count + " tests passed"); + else + throw new Exception(errors + "/" + count + " tests failed"); + } + + void test(Test t) throws IOException { + System.err.println("Test " + (++count) + " " + t.desc); + + File testDir = new File("test" + count); + srcDir = new File(testDir, "src"); + modulesDir = new File(testDir, "modules"); + resetDirs(srcDir, modulesDir); + + List<String> opts = new ArrayList<String>(); + add(opts, "-source", "7"); + add(opts, "-modulepath", modulesDir.getPath()); + add(opts, "-d", modulesDir.getPath()); + add(opts, "-XDrawDiagnostics"); + + boolean srcPath = false; + List<File> files = new ArrayList<File>(); + + for (Unit u: t.units) { + File f = createFile(u.path, u.text); + switch (u.kind) { + case CMDLINE: files.add(f); break; + case SRCPATH: srcPath = true; break; + } + } + + if (srcPath) + add(opts, "-sourcepath", srcDir.getPath()); + + compile(opts, files, t.diag); + + for (File f: modulesDir.listFiles()) { + error("unexpected file found: " + f); + } + } + + <T> void add(List<T> list, T... items) { + for (T t: items) + list.add(t); + } + + String replaceExtension(String path, String extn) { + int dot = path.lastIndexOf("."); + return path.substring(0, dot) + extn; + } + + /** + * Compile a list of files. + */ + void compile(List<String> opts, List<File> files, String diag) { + List<String> argList = new ArrayList<String>(); + argList.addAll(opts); + for (File f: files) + argList.add(f.getPath()); + + System.err.println("compile: " + argList); + + String[] args = argList.toArray(new String[argList.size()]); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(args, pw); + pw.close(); + + String out = sw.toString(); + if (out.trim().length() > 0) + System.err.println(out); + + if (rc == 0) + throw new Error("compilation succeeded unexpectedly"); + else if (!out.contains(diag)) + throw new Error("compilation failed unexpectedly: rc=" + rc); + else + System.err.println("compilation failed as expected"); + } + + /** + * Create a test file with given content if the content is not null. + */ + File createFile(String path, String body) throws IOException { + if (body == null) + return null; + File file = new File(srcDir, path); + file.getAbsoluteFile().getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + return file; + } + + /** + * Set up empty directories. + */ + void resetDirs(File... dirs) { + for (File dir: dirs) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + } + + /** + * Delete a file or a directory (including all its contents). + */ + boolean deleteAll(File file) { + if (file.isDirectory()) { + for (File f: file.listFiles()) + deleteAll(f); + } + return file.delete(); + } + + /** + * Report an error. + */ + void error(String msg, String... more) { + System.err.println("error: " + msg); + for (String s: more) + System.err.println(s); + errors++; + } + + int count; + int errors; + File srcDir; + File modulesDir; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/modules/ModuleVersionTest01.java Fri Nov 06 13:20:18 2009 -0800 @@ -0,0 +1,215 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6802521 + * @summary add support for modules: test version strings + */ + +import java.io.*; +import java.util.*; +import com.sun.tools.classfile.*; + +public class ModuleVersionTest01 { + String[] values = { + "0", + "1", + "2.3", + "3.4alpha", + "(2:3]", + "[3:4]", + "<1", + "=2", + ">3", + "\"alpha\"", + "\"alpha beta\"", + "\"alpha,beta\"" + }; + + + public static void main(String[] args) throws Exception { + new ModuleVersionTest01().run(); + } + + void run() throws Exception { + for (String v: values) { + try { + System.err.println("Test " + v); + test(v); + } catch (Throwable t) { + t.printStackTrace(); + errors++; + } + } + + if (errors == 0) + System.out.println(count + " tests passed"); + else + throw new Exception(errors + "/" + count + " tests failed"); + } + + void test(String version) throws Exception { + count++; + reset(); + List<File> files = new ArrayList<File>(); + addFile(files, createFile("module-info.java", "module M @ " + version + " { }")); + compile(files); + String moduleId = "M@" + unquote(version); + checkModuleAttribute("module-info.class", moduleId); + } + + String unquote(String v) { + if (v.startsWith("\"") && v.endsWith("\"")) + return v.substring(1, v.length() - 1); + else + return v; + } + + void checkModuleAttribute(String file, String moduleId) throws IOException { + System.err.println("Checking " + file); + try { + ClassFile cf = ClassFile.read(new File(classesDir, file)); + Module_attribute attr = (Module_attribute) cf.getAttribute(Attribute.Module); + if (attr == null) { + if (moduleId != null) + error("Module attribute not found; expected " + moduleId); + } else { + if (moduleId == null) { + error("Unexpected module attribute found: " + attr); + } else { + String name, version; + int sep = moduleId.indexOf("@"); + if (sep == -1) { + name = moduleId; + version = null; + } else { + name = moduleId.substring(0, sep); + version = moduleId.substring(sep + 1); + } + ConstantPool cp = cf.constant_pool; + checkEqual("module name", name, attr.getModuleName(cp)); + checkEqual("module version", version, attr.getModuleVersion(cp)); + } + } + } catch (ConstantPoolException e) { + error("Error accessing constant pool " + file + ": " + e); + } catch (IOException e) { + error("Error reading " + file + ": " + e); + } + } + + <T> void checkEqual(String tag, T expect, T found) { + if (expect == null ? found == null : expect.equals(found)) + return; + error(tag + " mismatch", "expected " + expect, "found: " + found); + } + + /** + * Compile a list of files. + */ + void compile(List<File> files) { + List<String> options = new ArrayList<String>(); + options.addAll(Arrays.asList("-source", "7", "-d", classesDir.getPath())); + for (File f: files) + options.add(f.getPath()); + + String[] opts = options.toArray(new String[options.size()]); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javac.Main.compile(opts, pw); + pw.close(); + + String out = sw.toString(); + if (out.trim().length() > 0) + System.err.println(out); + if (rc != 0) + throw new Error("compilation failed: rc=" + rc); + } + + /** + * Add a file to a list if the file is not null. + */ + void addFile(List<File> files, File file) { + if (file != null) + files.add(file); + } + + + /** + * Create a test file with given content if the content is not null. + */ + File createFile(String path, String body) throws IOException { + if (body == null) + return null; + File file = new File(srcDir, path); + file.getAbsoluteFile().getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + out.write(body); + out.close(); + return file; + } + + /** + * Set up empty src and classes directories for a test. + */ + void reset() { + resetDir(srcDir); + resetDir(classesDir); + } + + /** + * Set up an empty directory. + */ + void resetDir(File dir) { + if (dir.exists()) + deleteAll(dir); + dir.mkdirs(); + } + + /** + * Delete a file or a directory (including all its contents). + */ + boolean deleteAll(File file) { + if (file.isDirectory()) { + for (File f: file.listFiles()) + deleteAll(f); + } + return file.delete(); + } + + /** + * Report an error. + */ + void error(String msg, String... more) { + System.err.println("error: " + msg); + for (String s: more) + System.err.println(s); + errors++; + } + + int count; + int errors; + File srcDir = new File("tmp", "src"); // use "tmp" to help avoid accidents + File classesDir = new File("tmp", "classes"); +}