--- a/src/share/classes/com/sun/source/tree/CompilationUnitTree.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/source/tree/CompilationUnitTree.java Fri Aug 01 08:43:27 2008 -0700
@@ -27,7 +27,6 @@ package com.sun.source.tree;
import java.util.List;
import javax.tools.JavaFileObject;
-import com.sun.source.tree.LineMap;
/**
* Represents the abstract syntax tree for compilation units (source
--- a/src/share/classes/com/sun/tools/classfile/ClassWriter.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/classfile/ClassWriter.java Fri Aug 01 08:43:27 2008 -0700
@@ -459,6 +459,9 @@ public class ClassWriter {
}
public Void visitModuleExportTable(ModuleExportTable_attribute attr, ClassOutputStream out) {
+ out.writeShort(attr.export_package_table.length);
+ for (int i: attr.export_package_table)
+ out.writeShort(i);
out.writeShort(attr.export_type_table.length);
for (int i: attr.export_type_table)
out.writeShort(i);
--- a/src/share/classes/com/sun/tools/classfile/ModuleExportTable_attribute.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/classfile/ModuleExportTable_attribute.java Fri Aug 01 08:43:27 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2007 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
@@ -38,27 +38,45 @@ public class ModuleExportTable_attribute
public class ModuleExportTable_attribute extends Attribute {
ModuleExportTable_attribute(ClassReader cr, int name_index, int length) throws IOException {
super(name_index, length);
+ int export_package_length = cr.readUnsignedShort();
+ export_package_table = new int[export_package_length];
+ for (int i = 0; i < export_package_table.length; i++)
+ export_package_table[i] = cr.readUnsignedShort();
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)
+ public ModuleExportTable_attribute(ConstantPool cp,
+ int[] export_package_table, int[] export_type_table)
throws ConstantPoolException {
- this(cp.getUTF8Index(Attribute.ModuleExportTable), export_type_table);
+ this(cp.getUTF8Index(Attribute.ModuleExportTable),
+ export_package_table, export_type_table);
}
- public ModuleExportTable_attribute(int name_index, int[] export_type_table) {
+ public ModuleExportTable_attribute(int name_index,
+ int[] export_package_table, int[] export_type_table) {
super(name_index, 2 * export_type_table.length);
+ this.export_package_table = export_package_table;
this.export_type_table = export_type_table;
+ }
+
+ public int getExportPackageCount() {
+ return export_package_table.length;
+ }
+
+ public String getExportPackageName(int index, ConstantPool constant_pool)
+ throws ConstantPoolException {
+ return constant_pool.getUTF8Value(export_package_table[index]);
}
public int getExportTypeCount() {
return export_type_table.length;
}
- public String getExportTypeName(int index, ConstantPool constant_pool) throws ConstantPoolException {
+ public String getExportTypeName(int index, ConstantPool constant_pool)
+ throws ConstantPoolException {
return constant_pool.getUTF8Value(export_type_table[index]);
}
@@ -66,5 +84,6 @@ public class ModuleExportTable_attribute
return visitor.visitModuleExportTable(this, p);
}
+ public final int[] export_package_table;
public final int[] export_type_table;
}
--- a/src/share/classes/com/sun/tools/javac/code/Flags.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Flags.java Fri Aug 01 08:43:27 2008 -0700
@@ -112,7 +112,10 @@ public class Flags {
* 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 @@ public class Flags {
/** 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 @@ public class Flags {
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);
@@ -282,6 +286,10 @@ public class Flags {
public static boolean isConstant(Symbol.VarSymbol symbol) {
return symbol.getConstValue() != null;
+ }
+
+ public static boolean isModuleAccess(Symbol symbol) {
+ return (symbol.flags() & MODULE) != 0;
}
public enum Flag {
@@ -303,6 +311,7 @@ public class Flags {
DEPRECATED("deprecated"),
HASINIT("hasinit"),
ENUM("enum"),
+ MODULE("module"),
IPROXY("iproxy"),
NOOUTERTHIS("noouterthis"),
EXISTS("exists"),
--- a/src/share/classes/com/sun/tools/javac/code/Kinds.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Kinds.java Fri Aug 01 08:43:27 2008 -0700
@@ -70,9 +70,13 @@ public class Kinds {
*/
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.
*/
@@ -101,7 +105,8 @@ public class Kinds {
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/Source.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Source.java Fri Aug 01 08:43:27 2008 -0700
@@ -150,6 +150,9 @@ public enum Source {
public boolean addBridges() {
return compareTo(JDK1_5) >= 0;
}
+ public boolean allowModules() {
+ return compareTo(JDK1_7) >= 0;
+ }
public boolean enforceMandatoryWarnings() {
return compareTo(JDK1_5) >= 0;
}
--- a/src/share/classes/com/sun/tools/javac/code/Symbol.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java Fri Aug 01 08:43:27 2008 -0700
@@ -44,6 +44,8 @@ import static com.sun.tools.javac.code.K
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,
* types, packages. Each subclass is represented as a static inner class
@@ -287,6 +289,12 @@ public abstract class Symbol implements
sym = sym.owner;
}
return (PackageSymbol) sym;
+ }
+
+ /** The module which indirectly owns this symbol.
+ */
+ public ModuleSymbol modle() {
+ return packge().modle;
}
/** Is this symbol a subclass of `base'? Only defined for ClassSymbols.
@@ -365,6 +373,19 @@ public abstract class Symbol implements
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;
}
}
@@ -586,6 +607,34 @@ public abstract class Symbol implements
}
}
+ /** A class for module symbols.
+ */
+ public static class ModuleSymbol extends TypeSymbol
+ /*implements ModuleElement*/ {
+ public Name fullname;
+
+ 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 String toString() {
+ return fullname.toString();
+ }
+
+ public Name getQualifiedName() {
+ return fullname;
+ }
+
+ public boolean isUnnamed() {
+ return name.isEmpty() && owner != null;
+ }
+
+ public ClassSymbol module_info;
+ }
+
/** A class for package symbols
*/
public static class PackageSymbol extends TypeSymbol
@@ -594,6 +643,9 @@ public abstract class Symbol implements
public Scope members_field;
public Name fullname;
public ClassSymbol package_info; // see bug 6443073
+
+ /** The module for all compilation units in this package. */
+ public ModuleSymbol modle;
public PackageSymbol(Name name, Type type, Symbol owner) {
super(0, name, type, owner);
--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java Fri Aug 01 08:43:27 2008 -0700
@@ -83,6 +83,14 @@ public class Symtab {
/** A symbol for the unnamed package.
*/
public final PackageSymbol unnamedPackage;
+
+ /** A symbol for the root module.
+ */
+ public final ModuleSymbol rootModule;
+
+ /** A symbol for the unnamed module.
+ */
+ public final ModuleSymbol unnamedModule;
/** A symbol that stands for a missing symbol.
*/
@@ -170,6 +178,12 @@ public class Symtab {
*/
public final Map<Name, ClassSymbol> classes = new HashMap<Name, ClassSymbol>();
+ /** A hashtable containing the encountered modules.
+ * The table should be updated from outside to reflect modules defined
+ * by compiled source files.
+ */
+ public final Map<Name, ModuleSymbol> modules = new HashMap<Name, ModuleSymbol>();
+
/** A hashtable containing the encountered packages.
* the table should be updated from outside to reflect packages defined
* by compiled source files.
@@ -284,13 +298,21 @@ public class Symtab {
unknownType = new Type(TypeTags.UNKNOWN, null);
// create the basic builtin symbols
+ final Messages messages = Messages.instance(context);
+ rootModule = new ModuleSymbol(names.empty, null);
+ unnamedModule = new ModuleSymbol(names.empty, rootModule) {
+ public String toString() {
+ return messages.getLocalizedString("compiler.misc.unnamed.module");
+ }
+ };
rootPackage = new PackageSymbol(names.empty, null);
- final Messages messages = Messages.instance(context);
+ rootPackage.modle = rootModule;
unnamedPackage = new PackageSymbol(names.empty, rootPackage) {
public String toString() {
return messages.getLocalizedString("compiler.misc.unnamed.package");
}
};
+ unnamedPackage.modle = unnamedModule;
noSymbol = new TypeSymbol(0, names.empty, Type.noType, rootPackage);
noSymbol.kind = Kinds.NIL;
--- a/src/share/classes/com/sun/tools/javac/code/Type.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Type.java Fri Aug 01 08:43:27 2008 -0700
@@ -935,6 +935,30 @@ public class Type implements PrimitiveTy
}
}
+ 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);
+ }
+
+ public String toString() {
+ return tsym.getQualifiedName().toString();
+ }
+
+ public TypeKind getKind() {
+ return TypeKind.MODULE;
+ }
+
+ 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.
@@ -1147,7 +1171,7 @@ public class Type implements PrimitiveTy
/** Represents VOID or NONE.
*/
- static class JCNoType extends Type implements NoType {
+ public static class JCNoType extends Type implements NoType {
public JCNoType(int tag) {
super(tag, null);
}
@@ -1262,6 +1286,7 @@ public class Type implements PrimitiveTy
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 Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/TypeTags.java Fri Aug 01 08:43:27 2008 -0700
@@ -90,9 +90,13 @@ public class TypeTags {
*/
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 Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java Fri Aug 01 08:43:27 2008 -0700
@@ -3210,6 +3210,7 @@ public class Types {
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 Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Aug 01 08:43:27 2008 -0700
@@ -589,6 +589,9 @@ public class Attr extends JCTree.Visitor
// If we override any other methods, check that we do so properly.
// 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.
@@ -713,6 +716,8 @@ public class Attr extends JCTree.Visitor
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) {
@@ -2697,6 +2702,9 @@ public class Attr extends JCTree.Visitor
chk.validate(tree.extending);
chk.validate(tree.implementing);
+ // 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 Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Fri Aug 01 08:43:27 2008 -0700
@@ -44,6 +44,7 @@ import static com.sun.tools.javac.code.F
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.
*
@@ -500,7 +501,7 @@ public class Check {
while (args.nonEmpty()) {
if (args.head.tag == WILDCARD)
return typeTagError(pos,
- log.getLocalizedString("type.req.exact"),
+ Log.getLocalizedString("type.req.exact"),
args.head);
args = args.tail;
}
@@ -584,7 +585,7 @@ public class Check {
}
/** 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.
@@ -599,8 +600,12 @@ public class Check {
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;
@@ -614,8 +619,12 @@ public class Check {
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;
}
@@ -643,13 +652,19 @@ public class Check {
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
@@ -669,8 +684,7 @@ public class Check {
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 ||
@@ -686,11 +700,15 @@ public class Check {
&&
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,
@@ -703,6 +721,15 @@ public class Check {
// skip
}
return flags & (mask | ~StandardFlags) | implicit;
+ }
+
+ /**
+ * Determine if module modifier is legal here.
+ */
+ void checkModuleModifier(DiagnosticPosition pos, Symbol sym) {
+ if (Flags.isModuleAccess(sym) && sym.packge().modle == syms.unnamedModule) {
+ log.error(pos, "module.not.allowed.here");
+ }
}
@@ -1503,8 +1530,8 @@ public class Check {
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 Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Enter.java Fri Aug 01 08:43:27 2008 -0700
@@ -26,7 +26,6 @@ package com.sun.tools.javac.comp;
package com.sun.tools.javac.comp;
import java.util.*;
-import java.util.Set;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileManager;
@@ -43,7 +42,6 @@ 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.*;
/** This class enters symbols for all encountered definitions into
* the symbol table. The pass consists of two phases, organized as
@@ -102,6 +100,7 @@ public class Enter extends JCTree.Visito
MemberEnter memberEnter;
Lint lint;
JavaFileManager fileManager;
+ Name.Table names;
private final Todo todo;
@@ -123,6 +122,7 @@ public class Enter extends JCTree.Visito
memberEnter = MemberEnter.instance(context);
annotate = Annotate.instance(context);
lint = Lint.instance(context);
+ names = Name.Table.instance(context);
predefClassDef = make.ClassDef(
make.Modifiers(PUBLIC),
@@ -271,12 +271,36 @@ public class Enter extends JCTree.Visito
public void visitTopLevel(JCCompilationUnit tree) {
JavaFileObject prev = log.useSource(tree.sourcefile);
boolean addEnv = false;
- boolean isPkgInfo = tree.sourcefile.isNameCompatible("package-info",
- JavaFileObject.Kind.SOURCE);
+ boolean isModuleInfo = TreeInfo.isModuleInfo(tree);
+ boolean isPackageInfo = TreeInfo.isPackageInfo(tree);
+
+ if (tree.mid != null) {
+ tree.modle = reader.enterModule(TreeInfo.fullName(tree.mid));
+ if (tree.moduleAnnotations.nonEmpty()) {
+ if (isModuleInfo) {
+ addEnv = true;
+ } else {
+ log.error(tree.moduleAnnotations.head.pos(),
+ "mdl.annotations.sb.in.module-info.java");
+ }
+ }
+ if (isPackageInfo) {
+ addEnv = true;
+ }
+ if (tree.pid == null) {
+ for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+ if (l.head.getTag() == JCTree.CLASSDEF) {
+ log.error(tree.pos(), "mdl.for.decls.in.unnamed.package");
+ continue;
+ }
+ }
+ }
+ }
+
if (tree.pid != null) {
tree.packge = reader.enterPackage(TreeInfo.fullName(tree.pid));
if (tree.packageAnnotations.nonEmpty()) {
- if (isPkgInfo) {
+ if (isPackageInfo) {
addEnv = true;
} else {
log.error(tree.packageAnnotations.head.pos(),
@@ -287,13 +311,45 @@ public class Enter extends JCTree.Visito
tree.packge = syms.unnamedPackage;
}
tree.packge.complete(); // Find all classes in package.
+
Env<AttrContext> env = topLevelEnv(tree);
- // Save environment of package-info.java file.
- if (isPkgInfo) {
+ if (isModuleInfo) {
+ if (tree.mid == null) {
+ log.error(tree, "modinfo.must.contain.module.decl");
+ tree.modle = new ModuleSymbol(names.empty, syms.rootModule);
+ }
+
+ // Save environment of module-info.java file.
+ Env<AttrContext> env0 = typeEnvs.get(tree.modle);
+ if (env0 == null) {
+ typeEnvs.put(tree.modle, env);
+ } else {
+ JCCompilationUnit tree0 = env0.toplevel;
+ if (!fileManager.isSameFile(tree.sourcefile, tree0.sourcefile)) {
+ log.warning(tree.mid != null ? tree.mid.pos()
+ : null,
+ "module-info.already.seen",
+ tree.modle);
+ if (addEnv || (tree0.moduleAnnotations.isEmpty() &&
+ tree.docComments != null &&
+ tree.docComments.get(tree) != null)) {
+ typeEnvs.put(tree.modle, env);
+ }
+ }
+ }
+ }
+
+ if (isPackageInfo) {
+ // Save environment of package-info.java file.
Env<AttrContext> env0 = typeEnvs.get(tree.packge);
if (env0 == null) {
typeEnvs.put(tree.packge, env);
+ tree.packge.package_info =
+ reader.enterClass(names.package_info, tree.packge);
+ if (tree.mid == null)
+ tree.modle = syms.unnamedModule;
+ tree.packge.modle = tree.modle;
} else {
JCCompilationUnit tree0 = env0.toplevel;
if (!fileManager.isSameFile(tree.sourcefile, tree0.sourcefile)) {
@@ -309,10 +365,13 @@ public class Enter extends JCTree.Visito
}
}
}
+
classEnter(tree.defs, env);
+
if (addEnv) {
todo.append(env);
}
+
log.useSource(prev);
result = null;
}
@@ -342,7 +401,9 @@ public class Enter extends JCTree.Visito
// 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.
@@ -459,6 +520,10 @@ public class Enter extends JCTree.Visito
try {
// enter all classes, and construct uncompleted list
classEnter(trees, null);
+
+ for (JCCompilationUnit tree: trees) {
+ initModule(tree);
+ }
// complete all uncompleted classes in memberEnter
if (memberEnter.completionEnabled) {
@@ -489,4 +554,35 @@ public class Enter extends JCTree.Visito
annotate.enterDone();
}
}
+
+ // Consistency checks between compilation units are handled elsewhere,
+ // in MemberEnter.visitTopLevel
+ void initModule(JCCompilationUnit tree) {
+ // The module for a package may be set during visitTopLevel from the
+ // package-info.java file. Otherwise it is set here.
+ if (tree.packge.modle == null) {
+ if (tree.packge.package_info != null) {
+ // if there is a package-info file, init from that
+ tree.packge.package_info.complete();
+ } else {
+ // otherwise, init from this compilation unit
+ if (tree.mid == null)
+ tree.packge.modle = syms.unnamedModule;
+ else
+ tree.packge.modle = tree.modle;
+ }
+ assert tree.packge.modle != null;
+ }
+
+ // The module for a compilation unit is set during visitTopLevel
+ // from the module declaration, if one is given, or if this is a
+ // package info file. Otherwise, it is initialized here, using the
+ // package module, if there was a package-info file.
+ if (tree.modle == null) {
+ if (tree.packge.package_info != null)
+ tree.modle = tree.packge.modle;
+ else
+ tree.modle = syms.unnamedModule;
+ }
+ }
}
--- a/src/share/classes/com/sun/tools/javac/comp/Lower.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java Fri Aug 01 08:43:27 2008 -0700
@@ -26,6 +26,7 @@ package com.sun.tools.javac.comp;
package com.sun.tools.javac.comp;
import java.util.*;
+import javax.tools.JavaFileObject;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.jvm.*;
@@ -1958,33 +1959,46 @@ public class Lower extends TreeTranslato
}
public void visitTopLevel(JCCompilationUnit tree) {
- if (tree.packageAnnotations.nonEmpty()) {
- Name name = names.package_info;
- 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;
- c.completer = null;
- c.members_field = new Scope(c);
- c.flags_field = flags;
- c.attributes_field = tree.packge.attributes_field;
- tree.packge.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);
- }
+ if (TreeInfo.isPackageInfo(tree)) {
+ createAnnotationsClass(tree.packge, names.package_info,
+ target.isPackageInfoSynthetic(),
+ tree.packageAnnotations, tree.packge.attributes_field,
+ tree.sourcefile);
+ }
+ if (TreeInfo.isModuleInfo(tree)) {
+ PackageSymbol packge = reader.enterPackage(tree.modle.flatName());
+ createAnnotationsClass(packge, names.module_info, true,
+ tree.moduleAnnotations, tree.modle.attributes_field,
+ tree.sourcefile);
+ tree.modle.attributes_field = List.nil();
+ }
+ }
+ // where
+ private void createAnnotationsClass(PackageSymbol packge, Name name, boolean synthetic,
+ List<JCAnnotation> annotations, List<Attribute.Compound> attributes_field,
+ JavaFileObject sourcefile) {
+ long flags = Flags.ABSTRACT | Flags.INTERFACE;
+ if (synthetic)
+ // package-info is marked SYNTHETIC in JDK 1.6 and later releases
+ flags = flags | Flags.SYNTHETIC;
+ JCClassDecl annotationsClass
+ = make.ClassDef(make.Modifiers(flags,
+ annotations),
+ name, List.<JCTypeParameter>nil(),
+ null, List.<JCExpression>nil(), List.<JCTree>nil());
+ ClassSymbol c = reader.enterClass(name, packge);
+ c.flatname = names.fromString(packge + "." + name);
+ c.sourcefile = sourcefile;
+ c.completer = null;
+ c.members_field = new Scope(c);
+ c.flags_field = flags;
+ c.attributes_field = attributes_field;
+ ClassType ctype = (ClassType) c.type;
+ ctype.supertype_field = syms.objectType;
+ ctype.interfaces_field = List.nil();
+ annotationsClass.sym = c;
+
+ translated.append(annotationsClass);
}
public void visitClassDef(JCClassDecl tree) {
--- a/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Fri Aug 01 08:43:27 2008 -0700
@@ -34,6 +34,7 @@ import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Symbol.*;
@@ -42,7 +43,7 @@ import static com.sun.tools.javac.code.F
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
@@ -72,6 +73,7 @@ public class MemberEnter extends JCTree.
private final Todo todo;
private final Annotate annotate;
private final Types types;
+ private final Source source;
private final Target target;
private final boolean skipAnnotations;
@@ -96,6 +98,7 @@ public class MemberEnter extends JCTree.
todo = Todo.instance(context);
annotate = Annotate.instance(context);
types = Types.instance(context);
+ source = Source.instance(context);
target = Target.instance(context);
skipAnnotations =
Options.instance(context).get("skipAnnotations") != null;
@@ -231,6 +234,8 @@ public class MemberEnter extends JCTree.
case 0:
case PROTECTED:
return sym.packge() == packge;
+ case MODULE:
+ return sym.modle() == packge.modle;
}
}
@@ -515,11 +520,27 @@ public class MemberEnter extends JCTree.
}
}
+ if (tree.pid != null && tree.modle != tree.packge.modle) {
+ log.error(tree.pos, "module.clashes.with.other.compunits.in.package",
+ tree.modle);
+ }
+
+ // process module annotations
+ annotateLater(tree.moduleAnnotations, env, tree.modle);
+
// process package annotations
annotateLater(tree.packageAnnotations, env, tree.packge);
// Import-on-demand java.lang.
importAll(tree.pos, reader.enterPackage(names.java_lang), env);
+
+ if (source.allowModules() && TreeInfo.isModuleInfo(tree)) {
+ // auto-import java.module.annotation.* in module-info.java
+ PackageSymbol p = reader.enterPackage(names.java_module_annotation);
+ p.complete();
+ if (p.exists())
+ importAll(tree.pos, p, env);
+ }
// Process all import clauses.
memberEnter(tree.defs, env);
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Aug 01 08:43:27 2008 -0700
@@ -40,6 +40,8 @@ import static com.sun.tools.javac.code.T
import static com.sun.tools.javac.code.TypeTags.*;
import javax.lang.model.element.ElementVisitor;
+import static com.sun.tools.javac.code.Flags.MODULE; // disambiguate
+
/** Helper class for name resolution, used mostly by the attribution phase.
*
* <p><b>This is NOT part of any API supported by Sun Microsystems. If
@@ -135,7 +137,7 @@ public class Resolve {
* @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() ==
@@ -151,6 +153,9 @@ public class Resolve {
// 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;
@@ -190,9 +195,10 @@ public class Resolve {
* @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
@@ -206,6 +212,13 @@ public class Resolve {
(env.toplevel.packge == sym.owner.owner // fast special case
||
env.toplevel.packge == sym.packge())
+ &&
+ isAccessible(env, site)
+ &&
+ sym.isInheritedIn(site.tsym, types);
+ case MODULE:
+ return
+ (env.toplevel.modle == sym.modle())
&&
isAccessible(env, site)
&&
@@ -654,7 +667,7 @@ public class Resolve {
return new AmbiguityError(m1, m2);
// both abstract, neither overridden; merge throws clause and result type
Symbol result;
- Type result2 = mt2.getReturnType();;
+ Type result2 = mt2.getReturnType();
if (mt2.tag == FORALL)
result2 = types.subst(result2, ((ForAll)mt2).tvars, ((ForAll)mt1).tvars);
if (types.isSubtype(mt1.getReturnType(), result2)) {
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Aug 01 08:43:27 2008 -0700
@@ -97,6 +97,10 @@ public class ClassReader extends ClassFi
*/
boolean allowAnnotations;
+ /** Switch: allow modules
+ */
+ boolean allowModules;
+
/** Switch: preserve parameter names from the variable table.
*/
public boolean saveParameterNames;
@@ -151,6 +155,10 @@ public class ClassReader extends ClassFi
*/
private Map<Name, PackageSymbol> packages;
+ /** A hashtable containing the encountered modules.
+ */
+ private Map<Name, ModuleSymbol> modules;
+
/** The current scope where type variables are entered.
*/
protected Scope typevars;
@@ -162,6 +170,10 @@ public class ClassReader extends ClassFi
/** The class or method currently being read.
*/
protected Symbol currentOwner = null;
+
+ /** The module read from the current class
+ */
+ protected ModuleSymbol classModule = null;
/** The buffer containing the currently read class file.
*/
@@ -193,22 +205,28 @@ public class ClassReader extends ClassFi
init(syms, true);
}
- /** Initialize classes and packages, optionally treating this as
+ /** Initialize classes, packages and modules, optionally treating this as
* the definitive classreader.
*/
private void init(Symtab syms, boolean definitive) {
if (classes != null) return;
if (definitive) {
+ assert modules == null || modules == syms.modules;
+ modules = syms.modules;
assert packages == null || packages == syms.packages;
packages = syms.packages;
assert classes == null || classes == syms.classes;
classes = syms.classes;
} else {
+ modules = new HashMap<Name, ModuleSymbol>();
packages = new HashMap<Name, PackageSymbol>();
classes = new HashMap<Name, ClassSymbol>();
}
+ modules.put(names.empty, syms.rootModule);
+ syms.rootModule.completer = this;
+ syms.unnamedModule.completer = this;
packages.put(names.empty, syms.rootPackage);
syms.rootPackage.completer = this;
syms.unnamedPackage.completer = this;
@@ -239,6 +257,7 @@ public class ClassReader extends ClassFi
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"));
@@ -502,6 +521,18 @@ public class ClassReader extends ClassFi
*/
Name readName(int i) {
return (Name) (readPool(i));
+ }
+
+ /** Read module name
+ */
+ ModuleSymbol readModuleSymbol(int i) {
+ int index = poolIdx[i];
+ if (buf[index] == CONSTANT_Class)
+ index = poolIdx[getChar(index + 1)];
+ assert buf[index] == CONSTANT_Utf8;
+ int len = getChar(index + 1);
+ int start = index + 3;
+ return enterModule(names.fromUtf(internalize(buf, start, len)));
}
/************************************************************************
@@ -1072,6 +1103,8 @@ public class ClassReader extends ClassFi
} finally {
readingClassAttr = false;
}
+ } else if (allowModules && attrName == names.Module) {
+ classModule = readModuleSymbol(nextChar());
} else {
readMemberAttr(c, attrName, attrLen);
}
@@ -1678,7 +1711,16 @@ public class ClassReader extends ClassFi
int ns = Integer.highestOneBit(bp) << 1;
signatureBuffer = new byte[ns];
}
+
+ classModule = syms.unnamedModule;
+
readClass(c);
+
+ PackageSymbol p = c.packge();
+ if (p.modle == null)
+ p.modle = classModule;
+ else if (p.modle != classModule)
+ throw badClassFile("class.has.inconsistent.module", classModule, p.modle);
}
/************************************************************************
@@ -1805,6 +1847,17 @@ public class ClassReader extends ClassFi
} catch (IOException ex) {
throw new CompletionFailure(sym, ex.getLocalizedMessage()).initCause(ex);
}
+ } else if (sym.kind == MDL) {
+ ModuleSymbol m = (ModuleSymbol)sym;
+ // Arguably, the only content to be completed is the module-info,
+ // but that is never referenced directly by the compiler. (What
+ // about annotation processors?)
+ // To access module-info, we could either leverage fillIn(PackageSymbol)
+ // and note module-info if we see it (this has side effect of making
+ // the package observable), or we could implement fillIn(ModuleSymbol)
+ // by calling fileManager.getFileForInput, modelling the path semantics
+ // seen in fillIn(PackageSymbol), and trying both Kind.SOURCE and
+ // Kind.CLASS.
}
if (!filling && !suppressFlush)
annotate.flush(); // finish attaching annotations
@@ -2016,7 +2069,7 @@ public class ClassReader extends ClassFi
* (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, String binaryName) {
if ((p.flags_field & EXISTS) == 0)
for (Symbol q = p; q != null && q.kind == PCK; q = q.owner)
q.flags_field |= EXISTS;
@@ -2026,7 +2079,6 @@ public class ClassReader extends ClassFi
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;
@@ -2084,8 +2136,6 @@ public class ClassReader extends ClassFi
*/
protected void extraFileActions(PackageSymbol pack, JavaFileObject fe) {
}
-
- protected Location currentLoc; // FIXME
private boolean verbosePath = true;
@@ -2169,17 +2219,16 @@ public class ClassReader extends ClassFi
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) ||
simpleName.equals("package-info"))
- includeClassFile(p, fo);
+ includeClassFile(p, fo, binaryName);
break;
}
default:
@@ -2187,6 +2236,25 @@ public class ClassReader extends ClassFi
}
}
}
+
+/************************************************************************
+ * Loading Modules
+ ***********************************************************************/
+
+ /** Make a module, given its fully qualified name.
+ */
+ public ModuleSymbol enterModule(Name fullname) {
+ ModuleSymbol m = modules.get(fullname);
+ if (m == null) {
+ assert !fullname.isEmpty() : "rootModule missing!";
+ m = new ModuleSymbol(
+ Convert.shortName(fullname),
+ enterModule(Convert.packagePart(fullname)));
+ m.completer = this;
+ modules.put(fullname, m);
+ }
+ return m;
+ }
/** Output for "-verbose" option.
* @param key The key to look up the correct internationalized string.
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Fri Aug 01 08:43:27 2008 -0700
@@ -26,7 +26,6 @@ package com.sun.tools.javac.jvm;
package com.sun.tools.javac.jvm;
import java.io.*;
-import java.util.*;
import java.util.Set;
import java.util.HashSet;
@@ -230,7 +229,9 @@ public class ClassWriter extends ClassFi
private final static String[] flagName = {
"PUBLIC", "PRIVATE", "PROTECTED", "STATIC", "FINAL",
"SUPER", "VOLATILE", "TRANSIENT", "NATIVE", "INTERFACE",
- "ABSTRACT", "STRICTFP"};
+ "ABSTRACT", "STRICTFP", "SYNTHETIC", "ANNOTATION", "ENUM",
+ "MODULE"
+ };
/******************************************************************
* Output routines
@@ -866,6 +867,30 @@ public class ClassWriter extends ClassFi
}
/**********************************************************************
+ * Writing module attributes
+ **********************************************************************/
+
+ /** Write the Module attribute if needed.
+ * Returns the number of attributes written (0 or 1).
+ */
+ int writeModuleAttribute(ClassSymbol c) {
+ PackageSymbol p = c.packge();
+ Name name;
+ if (c.name == names.module_info)
+ name = p.flatName();
+ else {
+ if (p.modle == null || p.modle == syms.unnamedModule)
+ return 0;
+ name = p.modle.flatName();
+ }
+
+ int alenIdx = writeAttr(names.Module);
+ databuf.appendChar(pool.put(names.fromUtf(externalize(name))));
+ endAttr(alenIdx);
+ return 1;
+ }
+
+/**********************************************************************
* Writing Objects
**********************************************************************/
@@ -1573,6 +1598,7 @@ public class ClassWriter extends ClassFi
acount += writeFlagAttrs(c.flags());
acount += writeJavaAnnotations(c.getAnnotationMirrors());
acount += writeEnclosingMethodAttribute(c);
+ acount += writeModuleAttribute(c);
poolbuf.appendInt(JAVA_MAGIC);
poolbuf.appendChar(target.minorVersion);
--- a/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Fri Aug 01 08:43:27 2008 -0700
@@ -359,6 +359,8 @@ public class JavaCompiler implements Cla
devVerbose = options.get("dev") != null;
processPcks = options.get("process.packages") != null;
+ dumpTree = options.get("dumptree") != null;
+
verboseCompilePolicy = options.get("verboseCompilePolicy") != null;
if (attrParseOnly)
@@ -425,6 +427,10 @@ public class JavaCompiler implements Cla
* CompilationTask.setProcessors?
*/
protected boolean explicitAnnotationProcessingRequested = false;
+
+ /** Dump tree after parsing
+ */
+ protected boolean dumpTree;
/**
* The policy for the order in which to perform the compilation
@@ -533,8 +539,10 @@ public class JavaCompiler implements Cla
*/
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.JCAnnotation>nil(), null,
+ List.<JCTree.JCAnnotation>nil(), null,
+ List.<JCTree>nil());
if (content != null) {
if (verbose) {
printVerbose("parsing.started", filename);
@@ -611,8 +619,10 @@ public class JavaCompiler implements Cla
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.JCAnnotation>nil(), null,
+ List.<JCTree.JCAnnotation>nil(), null,
+ List.<JCTree>nil());
toplevel.packge = syms.unnamedPackage;
return attr.attribIdent(tree, toplevel);
} finally {
@@ -686,7 +696,10 @@ public class JavaCompiler implements Cla
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.JCAnnotation>nil(), null,
+ List.<JCTree.JCAnnotation>nil(), null,
+ List.<JCTree>nil());
} finally {
log.useSource(prev);
}
@@ -837,8 +850,17 @@ public class JavaCompiler implements Cla
//parse all files
ListBuffer<JCCompilationUnit> trees = lb();
- for (JavaFileObject fileObject : fileObjects)
- trees.append(parse(fileObject));
+ for (JavaFileObject fileObject : fileObjects) {
+ JCCompilationUnit t = parse(fileObject);
+ if (dumpTree) {
+ try {
+ new Pretty(log.errWriter, true).printUnit(t, null);
+ } catch (IOException e) {
+ System.err.println(e);
+ }
+ }
+ trees.append(t);
+ }
return trees.toList();
}
--- a/src/share/classes/com/sun/tools/javac/parser/Lexer.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/parser/Lexer.java Fri Aug 01 08:43:27 2008 -0700
@@ -139,4 +139,15 @@ public interface Lexer {
* 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/Parser.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/parser/Parser.java Fri Aug 01 08:43:27 2008 -0700
@@ -141,6 +141,7 @@ public class Parser {
this.allowForeach = source.allowForeach();
this.allowStaticImport = source.allowStaticImport();
this.allowAnnotations = source.allowAnnotations();
+ this.allowModules = source.allowModules();
this.keepDocComments = keepDocComments;
if (keepDocComments) docComments = new HashMap<JCTree,String>();
this.errorTree = F.Erroneous();
@@ -173,6 +174,10 @@ public class Parser {
/** Switch: should we recognize annotations?
*/
boolean allowAnnotations;
+
+ /** Switch: should we recognize modules?
+ */
+ boolean allowModules;
/** Switch: should we keep docComments?
*/
@@ -1449,7 +1454,7 @@ public class Parser {
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));
}
@@ -1536,7 +1541,7 @@ public class Parser {
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) {
@@ -1553,13 +1558,13 @@ public class Parser {
}
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:
@@ -1567,7 +1572,7 @@ public class Parser {
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) {
@@ -1873,7 +1878,7 @@ public class Parser {
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();
}
@@ -1900,15 +1905,22 @@ public class Parser {
return buf.toList();
}
+ 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(JCModifiers partial) {
+ JCModifiers modifiersOpt(ModuleModifierKind mmk) {
+ return modifiersOpt(mmk, null, null);
+ }
+
+ JCModifiers modifiersOpt(ModuleModifierKind mmk, Name constrName) {
+ return modifiersOpt(mmk, null, constrName);
+ }
+
+ JCModifiers modifiersOpt(ModuleModifierKind mmk, JCModifiers partial, Name constrName) {
long flags = (partial == null) ? 0 : partial.flags;
if (S.deprecatedFlag()) {
flags |= Flags.DEPRECATED;
@@ -1934,6 +1946,41 @@ public class Parser {
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");
@@ -1942,12 +1989,12 @@ public class Parser {
if (flag == Flags.ANNOTATION) {
checkAnnotations();
if (S.token() != INTERFACE) {
- JCAnnotation ann = annotation(lastPos);
- // 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;
+ JCAnnotation ann = annotation(lastPos);
+ // 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;
}
}
@@ -2126,12 +2173,31 @@ public class Parser {
*/
public JCTree.JCCompilationUnit compilationUnit() {
int pos = S.pos();
+ JCExpression mid = null;
+ List<JCAnnotation> moduleAnnotations = List.nil();
JCExpression pid = null;
+ List<JCAnnotation> packageAnnotations = List.nil();
String dc = S.docComment();
JCModifiers mods = null;
- List<JCAnnotation> packageAnnotations = List.nil();
+
if (S.token() == MONKEYS_AT)
- mods = modifiersOpt();
+ mods = modifiersOpt(ModuleModifierKind.DISALLOWED);
+
+ if (S.token() == IDENTIFIER && S.name() == names.module) {
+ if (!allowModules)
+ log.error(S.pos(), "modules.not.supported.in.source", source.name);
+ if (mods != null) {
+ checkNoMods(mods.flags);
+ moduleAnnotations = mods.annotations;
+ mods = null;
+ }
+ S.nextToken();
+ mid = qualident();
+ accept(SEMI);
+ }
+
+ if (S.token() == MONKEYS_AT)
+ mods = modifiersOpt(ModuleModifierKind.DISALLOWED);
if (S.token() == PACKAGE) {
if (mods != null) {
@@ -2143,8 +2209,9 @@ public class Parser {
pid = qualident();
accept(SEMI);
}
+
ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
- boolean checkForImports = true;
+ boolean checkForImports = true;
while (S.token() != EOF) {
if (S.pos() <= errorEndPos) {
// error recovery
@@ -2164,7 +2231,10 @@ public class Parser {
mods = null;
}
}
- JCTree.JCCompilationUnit toplevel = F.at(pos).TopLevel(packageAnnotations, pid, defs.toList());
+ JCTree.JCCompilationUnit toplevel = F.at(pos).TopLevel(
+ moduleAnnotations, mid,
+ packageAnnotations, pid,
+ defs.toList());
attach(toplevel, dc);
if (defs.elems.isEmpty())
storeEnd(toplevel, S.prevEndPos());
@@ -2209,7 +2279,7 @@ public class Parser {
return toP(F.at(pos).Skip());
} else {
String dc = S.docComment();
- return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), dc);
+ return classOrInterfaceOrEnumDeclaration(modifiersOpt(ModuleModifierKind.ALLOWED, mods, null), dc);
}
}
@@ -2279,7 +2349,7 @@ public class Parser {
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);
@@ -2303,7 +2373,7 @@ public class Parser {
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);
@@ -2360,7 +2430,7 @@ public class Parser {
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);
@@ -2392,7 +2462,7 @@ public class Parser {
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)
@@ -2422,7 +2492,7 @@ public class Parser {
/** 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
@@ -2432,7 +2502,7 @@ public class Parser {
}
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);
@@ -2459,14 +2529,15 @@ public class Parser {
* | 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) {
@@ -2652,7 +2723,7 @@ public class Parser {
}
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/Scanner.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/parser/Scanner.java Fri Aug 01 08:43:27 2008 -0700
@@ -89,6 +89,59 @@ public class Scanner implements Lexer {
}
}
+ 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():
*/
@@ -149,6 +202,10 @@ public class Scanner implements Lexer {
/** The buffer index of the last converted unicode character
*/
private int unicodeConversionBp = -1;
+
+ /** The last marked position.
+ */
+ private Mark mark;
/** The log to be used for error reporting.
*/
@@ -1115,4 +1172,13 @@ public class Scanner implements Lexer {
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/processing/JavacProcessingEnvironment.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Fri Aug 01 08:43:27 2008 -0700
@@ -1169,6 +1169,7 @@ public class JavacProcessingEnvironment
}
public void visitTopLevel(JCCompilationUnit node) {
node.packge = null;
+ node.modle = null;
super.visitTopLevel(node);
}
public void visitClassDef(JCClassDecl node) {
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Aug 01 08:43:27 2008 -0700
@@ -296,6 +296,10 @@ compiler.err.mod.not.allowed.here=\
modifier {0} not allowed here
compiler.err.intf.not.allowed.here=\
interface not allowed here
+compiler.err.module.not.allowed.here=\
+ modifier module not allowed in unnamed module
+compiler.err.modinfo.must.contain.module.decl=\
+ module compilation unit must contain a module declaration
compiler.err.enums.must.be.static=\
enum declarations allowed only in static contexts
@@ -341,6 +345,12 @@ compiler.err.pkg.annotations.sb.in.packa
package annotations should be in file package-info.java
compiler.err.pkg.clashes.with.class.of.same.name=\
package {0} clashes with class of same name
+compiler.err.mdl.annotations.sb.in.module-info.java=\
+ module annotations should be in file module-info.java
+compiler.err.module.clashes.with.other.compunits.in.package=\
+ module {0} clashes with other module for other compilation units in the same package
+compiler.err.mdl.for.decls.in.unnamed.package=\
+ module specified for declarations in the unnamed package
# Errors related to annotation processing
@@ -669,6 +679,8 @@ compiler.warn.override.bridge=\
compiler.warn.pkg-info.already.seen=\
[package-info] a package-info.java file has already been seen for package {0}
+compiler.warn.module-info.already.seen=\
+ [module-info] a module-info.java file has already been seen for module {0}
compiler.warn.path.element.not.found=\
[path] bad path element "{0}": no such file or directory
compiler.warn.possible.fall-through.into.case=\
@@ -821,6 +833,9 @@ compiler.misc.anonymous.class=\
compiler.misc.unnamed.package=\
unnamed package
+
+compiler.misc.unnamed.module=\
+ unnamed module
#####
@@ -869,6 +884,8 @@ compiler.misc.undecl.type.var=\
undeclared type variable: {0}
compiler.misc.wrong.version=\
class file has wrong version {0}.{1}, should be {2}.{3}
+compiler.misc.class.has.inconsistent.module=\
+ class file names a module which is inconsistent with another class file in the same package
#####
@@ -1046,6 +1063,8 @@ compiler.misc.kindname.class=\
class
compiler.misc.kindname.package=\
package
+compiler.misc.kindname.module=\
+ module
#####
compiler.err.override.static=\
@@ -1133,3 +1152,7 @@ compiler.err.enums.not.supported.in.sour
compiler.err.enums.not.supported.in.source=\
enums are not supported in -source {0}\n\
(use -source 5 or higher to enable enums)
+
+compiler.err.modules.not.supported.in.source=\
+ modules are not supported in -source {0}\n\
+(use -source 7 or higher to enable enums)
--- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java Fri Aug 01 08:43:27 2008 -0700
@@ -424,6 +424,9 @@ public abstract class JCTree implements
* Defined only if option -Xjcov is set.
*/
public static class JCCompilationUnit extends JCTree implements CompilationUnitTree {
+ public List<JCAnnotation> moduleAnnotations;
+ public JCExpression mid;
+ public ModuleSymbol modle;
public List<JCAnnotation> packageAnnotations;
public JCExpression pid;
public List<JCTree> defs;
@@ -435,13 +438,17 @@ public abstract class JCTree implements
public Position.LineMap lineMap = null;
public Map<JCTree, String> docComments = null;
public Map<JCTree, Integer> endPositions = null;
- protected JCCompilationUnit(List<JCAnnotation> packageAnnotations,
+ protected JCCompilationUnit(List<JCAnnotation> moduleAnnotations,
+ JCExpression mid,
+ List<JCAnnotation> packageAnnotations,
JCExpression pid,
List<JCTree> defs,
JavaFileObject sourcefile,
PackageSymbol packge,
Scope namedImportScope,
Scope starImportScope) {
+ this.moduleAnnotations = moduleAnnotations;
+ this.mid = mid;
this.packageAnnotations = packageAnnotations;
this.pid = pid;
this.defs = defs;
@@ -467,6 +474,7 @@ public abstract class JCTree implements
}
return imports.toList();
}
+ public JCExpression getModuleName() { return mid; }
public JCExpression getPackageName() { return pid; }
public JavaFileObject getSourceFile() {
return sourcefile;
@@ -2043,7 +2051,9 @@ public abstract class JCTree implements
/** An interface for tree factories
*/
public interface Factory {
- JCCompilationUnit TopLevel(List<JCAnnotation> packageAnnotations,
+ JCCompilationUnit TopLevel(List<JCAnnotation> moduleAnnotations,
+ JCExpression mid,
+ List<JCAnnotation> packageAnnotations,
JCExpression pid,
List<JCTree> defs);
JCImport Import(JCTree qualid, boolean staticImport);
--- a/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java Fri Aug 01 08:43:27 2008 -0700
@@ -318,10 +318,12 @@ public class TreeCopier<P> implements Tr
public JCTree visitCompilationUnit(CompilationUnitTree node, P p) {
JCCompilationUnit t = (JCCompilationUnit) node;
+ List<JCAnnotation> moduleAnnotations = copy(t.moduleAnnotations, p);
+ JCExpression mid = copy(t.mid, p);
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(moduleAnnotations, mid, packageAnnotations, pid, defs);
}
public JCTree visitTry(TryTree node, P p) {
--- a/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Fri Aug 01 08:43:27 2008 -0700
@@ -25,17 +25,18 @@
package com.sun.tools.javac.tree;
+import java.util.Map;
+import javax.tools.JavaFileObject;
+
import com.sun.source.tree.Tree;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Env;
-import java.util.Map;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.tree.JCTree.*;
import static com.sun.tools.javac.code.Flags.*;
-import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
/** Utility class containing inspector methods for trees.
*
@@ -668,9 +669,10 @@ public class TreeInfo {
* pre: flags != 0
*/
public static long firstFlag(long flags) {
- int flag = 1;
- while ((flag & StandardFlags) != 0 && (flag & flags) == 0)
- flag = flag << 1;
+ long sflags = StandardFlags;
+ long flag;
+ while ((flag = Long.lowestOneBit(sflags)) != 0 && (flag & flags) == 0)
+ sflags &= ~flag;
return flag;
}
@@ -860,4 +862,12 @@ public class TreeInfo {
return null;
}
}
+
+ public static boolean isModuleInfo(JCCompilationUnit tree) {
+ return tree.sourcefile.isNameCompatible("module-info", JavaFileObject.Kind.SOURCE);
+ }
+
+ public static boolean isPackageInfo(JCCompilationUnit tree) {
+ return tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE);
+ }
}
--- a/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Fri Aug 01 08:43:27 2008 -0700
@@ -119,9 +119,12 @@ public class TreeMaker implements JCTree
* Create given tree node at current position.
* @param defs a list of ClassDef, Import, and Skip
*/
- public JCCompilationUnit TopLevel(List<JCAnnotation> packageAnnotations,
+ public JCCompilationUnit TopLevel(List<JCAnnotation> moduleAnnotations,
+ JCExpression mid,
+ List<JCAnnotation> packageAnnotations,
JCExpression pid,
List<JCTree> defs) {
+ assert moduleAnnotations != null;
assert packageAnnotations != null;
for (JCTree node : defs)
assert node instanceof JCClassDecl
@@ -131,8 +134,11 @@ public class TreeMaker implements JCTree
|| (node instanceof JCExpressionStatement
&& ((JCExpressionStatement)node).expr instanceof JCErroneous)
: node.getClass().getSimpleName();
- JCCompilationUnit tree = new JCCompilationUnit(packageAnnotations, pid, defs,
- null, null, null, null);
+ JCCompilationUnit tree = new JCCompilationUnit(
+ moduleAnnotations, mid,
+ packageAnnotations, pid,
+ defs,
+ null, null, null, null);
tree.pos = pos;
return tree;
}
--- a/src/share/classes/com/sun/tools/javac/util/Name.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/util/Name.java Fri Aug 01 08:43:27 2008 -0700
@@ -435,8 +435,10 @@ public class Name implements javax.lang.
java_lang_Object = fromString("java.lang.Object");
java_lang_Class = fromString("java.lang.Class");
java_lang_Cloneable = fromString("java.lang.Cloneable");
+ java_module_annotation = fromString("java.module.annotation");
java_io_Serializable = fromString("java.io.Serializable");
java_lang_Enum = fromString("java.lang.Enum");
+ module_info = fromString("module-info");
package_info = fromString("package-info");
serialVersionUID = fromString("serialVersionUID");
ConstantValue = fromString("ConstantValue");
@@ -511,6 +513,8 @@ public class Name implements javax.lang.
getDeclaringClass = fromString("getDeclaringClass");
ex = fromString("ex");
finalize = fromString("finalize");
+ module = fromString("module");
+ Module = fromString("Module");
}
public Table() {
@@ -569,8 +573,10 @@ public class Name implements javax.lang.
public final Name java_lang_Class;
public final Name java_lang_Cloneable;
public final Name java_io_Serializable;
+ public final Name java_module_annotation;
public final Name serialVersionUID;
public final Name java_lang_Enum;
+ public final Name module_info;
public final Name package_info;
public final Name ConstantValue;
public final Name LineNumberTable;
@@ -645,6 +651,8 @@ public class Name implements javax.lang.
public final Name getDeclaringClass;
public final Name ex;
public final Name finalize;
+ public final Name module;
+ public final Name Module;
}
public boolean isEmpty() {
--- a/src/share/classes/com/sun/tools/javap/AttributeWriter.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javap/AttributeWriter.java Fri Aug 01 08:43:27 2008 -0700
@@ -382,11 +382,23 @@ public class AttributeWriter extends Bas
public Void visitModuleExportTable(ModuleExportTable_attribute attr, Void ignore) {
println(" ModuleExportTable:");
+ println(" Packages: (" + attr.export_package_table.length + ")");
+ for (int i = 0; i < attr.export_package_table.length; i++) {
+ println(" #" + attr.export_package_table[i] + "\t// " + getExportPackageName(attr, i));
+ }
println(" Types: (" + attr.export_type_table.length + ")");
for (int i = 0; i < attr.export_type_table.length; i++) {
println(" #" + attr.export_type_table[i] + "\t// " + getExportTypeName(attr, i));
}
return null;
+ }
+
+ String getExportPackageName(ModuleExportTable_attribute attr, int index) {
+ try {
+ return attr.getExportPackageName(index, constant_pool);
+ } catch (ConstantPoolException e) {
+ return report(e);
+ }
}
String getExportTypeName(ModuleExportTable_attribute attr, int index) {
--- a/src/share/classes/com/sun/tools/javap/Options.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/com/sun/tools/javap/Options.java Fri Aug 01 08:43:27 2008 -0700
@@ -82,6 +82,6 @@ public class Options {
public boolean showAllAttrs;
public boolean compat; // bug-for-bug compatibility mode with old javap
- public boolean jsr277;
+ public boolean jsr277 = true;
public boolean ignoreSymbolFile; // file manager should ignore ct.sym
}
--- a/src/share/classes/javax/lang/model/element/Modifier.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/javax/lang/model/element/Modifier.java Fri Aug 01 08:43:27 2008 -0700
@@ -59,7 +59,8 @@ public enum Modifier {
/** 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
--- a/src/share/classes/javax/lang/model/type/TypeKind.java Mon Jul 28 10:22:10 2008 +0100
+++ b/src/share/classes/javax/lang/model/type/TypeKind.java Fri Aug 01 08:43:27 2008 -0700
@@ -134,6 +134,12 @@ public enum TypeKind {
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/test/tools/javac/modules/CompilationUnitTest01.java Fri Aug 01 08:43:27 2008 -0700
@@ -0,0 +1,275 @@
+/*
+ * 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 6665690
+ * @summary implement JSR 277 modules
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+/*
+ * Test correct handling of compilation units, for combinations of:
+ * -- type of compilation unit
+ * -- whether or not module and packaqge declarations have annotations
+ * -- whether or not there is a type declaration
+ *
+ * Verify either compilation error or that correct files are generated,
+ * with correct Module attribute.
+ */
+public class CompilationUnitTest01
+{
+ enum UnitKind {
+ MODULE("module-info.java"),
+ PACKAGE("package-info.java"),
+ STANDARD("A.java");
+ UnitKind(String path) {
+ this.path = path;
+ }
+ final String path;
+ };
+
+ enum MemberKind {
+ NONE(false, false),
+ NO_ANNOS(true, false),
+ ANNOS(true, true);
+ MemberKind(boolean member, boolean annos) {
+ this.member = member;
+ this.annos = annos;
+ }
+ String getText(String s) {
+ return member ? (annos ? "@Deprecated " : "") + s : "";
+ }
+ final boolean member;
+ final boolean annos;
+ };
+
+ enum ClassKind {
+ NONE(""),
+ CLASS_A("class A { }");
+ ClassKind(String text) {
+ this.text = text;
+ }
+ final String text;
+ }
+
+ public static void main(String[] args) throws Exception {
+ new CompilationUnitTest01().run();
+ }
+
+ public void run() throws Exception {
+ for (UnitKind uk: UnitKind.values()) {
+ for (MemberKind mk: MemberKind.values()) {
+ for (MemberKind pk: MemberKind.values()) {
+ for (ClassKind ck: ClassKind.values()) {
+ test(uk, mk, pk, ck);
+ }
+ }
+ }
+ }
+
+ if (errors == 0)
+ System.out.println(count + " tests passed");
+ else
+ throw new Exception(errors + "/" + count + " tests failed");
+ }
+
+ void test(UnitKind uk, MemberKind mk, MemberKind pk, ClassKind ck) throws IOException {
+ String body = mk.getText("module m; ") + pk.getText("package p; ") + ck.text;
+ if (body.equals(""))
+ return;
+
+ System.out.println("Test " + (++count) + ": " + uk + " " + body);
+ resetDirs(srcDir, classesDir);
+ File f = createFile(srcDir, uk.path, body);
+
+ boolean expectError =
+ (!mk.member && uk == UnitKind.MODULE) // module-info must have a module decl
+ || (mk.member && !pk.member && ck != ClassKind.NONE) // if there's a module decl and a type, there must be a package decl
+ || (pk.annos && uk != UnitKind.PACKAGE) // package annotations must be in package-info
+ || (mk.annos && uk != UnitKind.MODULE); // module annotations must be in module-info
+ boolean expectModuleInfo = (uk == UnitKind.MODULE && mk.annos && !expectError);
+ boolean expectPackageInfo = (uk == UnitKind.PACKAGE && (mk.member || pk.annos) && pk.member && !expectError);
+ boolean expectClass = (ck.text.length() > 0 && !expectError);
+
+ compile(Arrays.asList(f), classesDir, null, expectError);
+
+ checkClassFile("m/module-info.class", expectModuleInfo, mk.member);
+ checkClassFile("p/package-info.class", expectPackageInfo, mk.member);
+ checkClassFile((pk.member ? "p/" : "") + "A.class", expectClass, mk.member);
+ }
+
+ void checkClassFile(String path, boolean expectExists, boolean expectModuleAttr) {
+ File f = new File(classesDir, path);
+ if (f.exists()) {
+ if (!expectExists)
+ error(path + " found but not expected");
+ checkModuleAttribute(f, expectModuleAttr ? "m" : "");
+ } else {
+ if (expectExists)
+ error(path + " expected but not found");
+ }
+ }
+
+ /**
+ * Check the Module attribute in a class file.
+ * The Module attribute need not be present if expect is empty.
+ */
+ boolean checkModuleAttribute(File file, String expect) {
+ //System.out.println("check " + file + " " + expect);
+ try {
+ Attribute.Factory attrFactory = new Attribute.Factory();
+ attrFactory.setJSR277(true);
+ ClassFile cf = ClassFile.read(file, attrFactory);
+ Attribute attr = cf.getAttribute(Attribute.Module);
+ String attrName;
+ if (attr == null) {
+ if (expect.equals(""))
+ return true;
+ error("no module name in " + file + ": expected " + expect);
+ }
+ else if (attr instanceof Module_attribute) {
+ Module_attribute m = (Module_attribute) attr;
+ String name = m.getModuleName(cf.constant_pool);
+ if (name.equals(expect))
+ return true;
+ error("bad module name in " + file + ": " +
+ "expected " + expect + ", found " + name);
+ }
+ else
+ error("bad Module attribute in " + file);
+ } catch (ConstantPoolException e) {
+ error("Error accessing constant pool " + file + ": " + e);
+ } catch (IOException e) {
+ error("Error reading " + file + ": " + e);
+ }
+ return false;
+ }
+
+ 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");
+ }
+ }
+ }
+
+ /**
+ * 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 = 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/ImportTest01.java Fri Aug 01 08:43:27 2008 -0700
@@ -0,0 +1,268 @@
+/*
+ * 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 6665690
+ * @summary implement JSR 277 modules
+ */
+
+import java.io.*;
+import java.util.*;
+
+/*
+ * This test tries different combinations of imports
+ * against different declarations.
+ */
+public class ImportTest01
+{
+ enum AccessKind {
+ PUBLIC("public"),
+ MODULE("module"),
+ DEFAULT("");
+ AccessKind(String modifier) {
+ this.modifier = modifier;
+ }
+ final String modifier;
+ }
+
+ enum ItemKind {
+ // use %s for access modifier
+ CLASS("X", "%s class X { }"),
+ NESTED_CLASS("X.Y", "public class X { static %s class Y { } }"),
+ CLASS_CONST("X.y", "public class X { static %s int y = 0; }"),
+ ENUM("X", "%s enum X { x1 }"),
+ INTERFACE("X", "%s interface X { }"),
+ INTERFACE_CONST("X.y", "public interface X { %s int y = 0; }");
+ ItemKind(String name, String code) {
+ this.name = name;
+ this.code = code;
+ }
+ boolean isStatic() {
+ return Character.isLowerCase(name.charAt(name.length() - 1));
+ }
+ final String name;
+ final String code;
+ }
+
+ enum ModulePackageKind {
+ M1_P1("m1", "p1"),
+ M1_P2("m1", "p2"),
+ M2_P3("m2", "p3");
+ ModulePackageKind(String moduleName, String packageName) {
+ this.moduleName = moduleName;
+ this.packageName = packageName;
+ }
+ final String moduleName;
+ final String packageName;
+ }
+
+ enum ImportKind {
+ NAMED,
+ ON_DEMAND
+ }
+
+
+
+ public static void main(String[] args) throws Exception {
+ new ImportTest01().run();
+ }
+
+ /**
+ * Main work method to run all the test cases.
+ */
+ void run() throws Exception {
+ for (AccessKind ak: AccessKind.values()) {
+ for (ItemKind ik: ItemKind.values()) {
+ for (ModulePackageKind mpk: ModulePackageKind.values()) {
+ for (ImportKind imk: ImportKind.values()) {
+ test(ak, ik, mpk, imk);
+ }
+ }
+ }
+ }
+
+ if (errors == 0)
+ System.out.println(count + " tests passed");
+ else
+ throw new Exception(errors + "/" + count + " tests failed");
+ }
+
+ void test(AccessKind ak, ItemKind ik, ModulePackageKind mpk, ImportKind imk)
+ throws IOException {
+ System.out.println("Test " + (++count) + ": " + ak + " " + ik + " " + mpk + " " + imk);
+
+ resetDirs(srcDir, classesDir);
+
+ String[] xBody = {
+ "module m1;",
+ "package p1;",
+ String.format(ik.code, ak.modifier)
+ };
+ File x = createFile(srcDir, "X.java", join(xBody));
+
+ String[] testBody = {
+ "module " + mpk.moduleName + ";",
+ "package " + mpk.packageName + ";",
+ "import " + (ik.isStatic() ? "static" : "") + " p1." + ik.name + ";"
+ };
+ File test = createFile(srcDir, "Test.java", join(testBody));
+
+ boolean expectError;
+ switch (ak) {
+ case PUBLIC:
+ expectError = false;
+ break;
+ case MODULE:
+ expectError = !mpk.moduleName.equals("m1");
+ break;
+ case DEFAULT:
+ if (ik == ItemKind.INTERFACE_CONST) {
+ // public access
+ expectError = false;
+ } else {
+ // package access
+ expectError = !mpk.packageName.equals("p1");
+ }
+ break;
+ default:
+ throw new Error();
+ }
+
+ compile(Arrays.asList(test, x), 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);
+ error(msg, more);
+ }
+
+ /**
+ * 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 = 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/ModuleAccessTest01.java Fri Aug 01 08:43:27 2008 -0700
@@ -0,0 +1,240 @@
+/*
+ * 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 6665690
+ * @summary implement JSR 277 modules
+ */
+
+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("module m1; package p1;"),
+ M2("module m2; package p2;"),
+ UNNAMED("");
+ ModuleKind(String s) {
+ text = s;
+ }
+ final String text;
+ };
+
+ 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);
+ resetDirs(srcDir, classesDir);
+
+ String[] refBody = {
+ "module m1; package p;",
+ "public class Ref {",
+ " " + ak.text + " Ref() { }",
+ " " + ak.text + " int field;",
+ " " + ak.text + " int method() { return 0; }",
+ " " + ak.text + " class C { }",
+ "}"
+ };
+ File ref = createFile(srcDir, "Ref.java", join(refBody));
+
+ String[] testBody = {
+ mk.text,
+ "class Test {",
+ " void m(p.Ref ref) {",
+ " " + ik.text,
+ " }",
+ "}"
+ };
+ File test = createFile(srcDir, "Test.java", join(testBody));
+
+ boolean expectError = (ak == AccessKind.PACKAGE || mk != ModuleKind.M1);
+
+ compile(Arrays.asList(ref, test), 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 = 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/ModuleAttributeTest01.java Fri Aug 01 08:43:27 2008 -0700
@@ -0,0 +1,318 @@
+/*
+ * 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 6665690
+ * @summary implement JSR 277 modules
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+/*
+ * This test tries valid and invalid combinations of module membership
+ * declarations for package-info and other compilation units.
+ * For each combination, it tries compiling the files together via the
+ * javac command line, verifying that the compilation succeeds or not,
+ * as appropriate, and when it does, checking the Module attributes
+ * on the generated files.
+ */
+public class ModuleAttributeTest01
+{
+ enum Kind {
+ NO_FILE(null),
+ NO_MODULE(""),
+ MODULE_M1("m1"),
+ MODULE_M2("m2");
+ Kind(String moduleName) {
+ this.moduleName = moduleName;
+ }
+ final String moduleName;
+ }
+
+ public static void main(String[] args) throws Exception {
+ new ModuleAttributeTest01().run();
+ }
+
+ /**
+ * Main work method to run all the test cases.
+ */
+ void run() throws Exception {
+ for (Kind pkgInfoKind: Kind.values()) {
+ for (Kind aKind: Kind.values()) {
+ for (Kind bKind: Kind.values()) {
+ test(pkgInfoKind, aKind, bKind);
+ }
+ }
+ }
+
+ if (errors == 0)
+ System.out.println(count + " tests passed");
+ else
+ throw new Exception(errors + "/" + count + " tests failed");
+ }
+
+ /**
+ * Test an individual test case for a combination of file Kinds.
+ * Generate files according to each Kind, then try compiling them
+ * a couple of times with different orders on the javac command line,
+ * each time verifying the results.
+ */
+ void test(Kind pkgInfoKind, Kind aKind, Kind bKind) throws Exception {
+ reset();
+ List<File> files = new ArrayList<File>();
+ addFile(files, createFile("p/package-info.java", pkgInfoKind, ""));
+ addFile(files, createFile("p/A.java", aKind, "class A { }"));
+ addFile(files, createFile("p/B.java", bKind, "class B { }"));
+ if (files.size() == 0) // degenerate case
+ return;
+ System.out.println("Test " + (++count) + ": " + pkgInfoKind + " " + aKind + " " + bKind);
+ String expect = getExpectedModule(pkgInfoKind, aKind, bKind);
+ test(files, expect);
+
+ resetDir(classesDir);
+ Collections.reverse(files);
+ test(files, expect);
+ }
+
+ /**
+ * Compile a set of files and verify the result.
+ * If expect is null, the compilation should fail. Otherwise,
+ * the compilation should succeed and each generated class file
+ * should have a Module attribute set to the value of expect.
+ */
+ void test(List<File> files, String expect) {
+ //System.out.println("test: " + expect + " " + files);
+ List<String> options = new ArrayList<String>();
+ options.add("-XDrawDiagnostics");
+ 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 out = new PrintWriter(sw);
+ int rc = com.sun.tools.javac.Main.compile(opts, out);
+ out.close();
+
+ if (expect == null) {
+ if (rc == 0)
+ error(files, "compilation succeeded unexpectedly");
+ //else
+ // log(files, "OK");
+ }
+ else {
+ if (rc != 0)
+ error(files, "compilation failed unexpectedly", sw.toString());
+ else {
+ boolean ok = true;
+ for (File f: files)
+ ok = ok | checkModuleAttribute(getClassFile(f), expect);
+ //if (ok)
+ // log(files, "OK");
+ }
+ }
+ }
+
+ /**
+ * Check the Module attribute in a class file.
+ * The Module attribute need not be present if expect is empty.
+ * !!! CHECK THE JVMS SPEC IN CASE THE MODULE ATTRIBUTE MUST
+ * BE OMITTED FOR THE UNNAMED PACKAGE
+ */
+ boolean checkModuleAttribute(File file, String expect) {
+ //System.out.println("check " + file + " " + expect);
+ try {
+ Attribute.Factory attrFactory = new Attribute.Factory();
+ attrFactory.setJSR277(true);
+ ClassFile cf = ClassFile.read(file, attrFactory);
+ Attribute attr = cf.getAttribute(Attribute.Module);
+ String attrName;
+ if (attr == null) {
+ if (expect.equals(""))
+ return true;
+ error("no module name in " + file + ": expected " + expect);
+ }
+ else if (attr instanceof Module_attribute) {
+ Module_attribute m = (Module_attribute) attr;
+ String name = m.getModuleName(cf.constant_pool);
+ if (name.equals(expect))
+ return true;
+ error("bad module name in " + file + ": " +
+ "expected " + expect + ", found " + name);
+ }
+ else
+ error("bad Module attribute in " + file);
+ } catch (ConstantPoolException e) {
+ error("Error accessing constant pool " + file + ": " + e);
+ } catch (IOException e) {
+ error("Error reading " + file + ": " + e);
+ }
+ return false;
+ }
+
+ /**
+ * Given a set of test file Kinds, determine the expected
+ * value for a Module attribute, or null if the test files
+ * should cause a compilation error when compiler together.
+ */
+ String getExpectedModule(Kind pkgInfoKind, Kind... fileKinds) {
+ if (pkgInfoKind != Kind.NO_FILE) {
+ for (Kind k: fileKinds) {
+ switch (k) {
+ case NO_FILE:
+ case NO_MODULE:
+ continue;
+ default:
+ // for explicit module statements, if given
+ // it must agree with package-info module
+ if (k != pkgInfoKind)
+ return null;
+ }
+ }
+ return pkgInfoKind.moduleName;
+ }
+ Set<Kind> kinds = new HashSet<Kind>(Arrays.asList(fileKinds));
+ kinds.remove(Kind.NO_FILE);
+ return (kinds.size() > 1 ? null : kinds.iterator().next().moduleName);
+ }
+
+ /**
+ * Returns the primary class file for a given source file.
+ */
+ File getClassFile(File srcFile) {
+ String p = srcDir.toURI().relativize(srcFile.toURI()).toString();
+ p = p.substring(0, p.lastIndexOf(".")) + ".class";
+ return new File(classesDir, p);
+ }
+
+ /**
+ * 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 according to the test file Kind.
+ */
+ File createFile(String path, Kind kind, String body) throws IOException {
+ // package-info.class is not generated if it would be empty
+ // (i.e. has no annotations)
+ String annos = (path.indexOf("package-info") == -1 ? "" : "@Deprecated ");
+
+ switch (kind) {
+ case NO_FILE:
+ return null;
+
+ case NO_MODULE:
+ return createFile(path,
+ annos + "package p; " + body);
+
+ default:
+ return createFile(path,
+ "module " + kind.moduleName + "; " +
+ annos + "package p; " + body);
+ }
+ }
+
+ /**
+ * Create a test file with given content.
+ */
+ File createFile(String path, String body) throws IOException {
+ 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(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 = 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/ModuleAttributeTest02.java Fri Aug 01 08:43:27 2008 -0700
@@ -0,0 +1,352 @@
+/*
+ * 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 6665690
+ * @summary implement JSR 277 modules
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+/*
+ * This test tries compiling combinations of valid and
+ * invalid source files against combinations of valid
+ * class files.
+ */
+public class ModuleAttributeTest02
+{
+ enum Kind {
+ NO_FILE(null),
+ NO_MODULE(""),
+ MODULE_M1("m1"),
+ MODULE_M2("m2");
+ Kind(String moduleName) {
+ this.moduleName = moduleName;
+ }
+ final String moduleName;
+ }
+
+ enum Path {
+ CLASSPATH,
+ SOURCEPATH
+ }
+
+ public static void main(String[] args) throws Exception {
+ new ModuleAttributeTest02().run();
+ }
+
+ /**
+ * Main work method to run all the test cases.
+ */
+ void run() throws Exception {
+ Set<Kind> allExceptM2 = EnumSet.of(
+ Kind.NO_FILE, Kind.NO_MODULE, Kind.MODULE_M1);
+
+ for (Path path: Path.values()) {
+ for (Kind pkgInfoKind: allExceptM2) {
+ for (Kind classAKind: allExceptM2) {
+ // setup filters out degenerate and invalid cases
+ if (!setup(path, pkgInfoKind, classAKind))
+ continue;
+
+ for (Kind testPkgInfoKind: Kind.values()) {
+ for (Kind testClassBKind: Kind.values()) {
+ test(path, pkgInfoKind, classAKind,
+ testPkgInfoKind, testClassBKind);
+ }
+ }
+ }
+ }
+ }
+
+ if (errors == 0)
+ System.out.println(count + " tests passed");
+ else
+ throw new Exception(errors + "/" + count + " tests failed");
+ }
+
+ boolean setup(Path path, Kind pkgInfoKind, Kind classAKind) throws IOException {
+ // ignore degenerate case of no files
+ if (pkgInfoKind == Kind.NO_FILE && classAKind == Kind.NO_FILE)
+ return false;
+
+ // ignore cases with mismatched modules
+ if (pkgInfoKind != Kind.NO_FILE && classAKind != Kind.NO_FILE
+ && pkgInfoKind != classAKind)
+ return false;
+
+ resetDirs(refSrcDir);
+
+ List<File> files = new ArrayList<File>();
+ addFile(files, createFile(refSrcDir, "p/package-info.java", pkgInfoKind, ""));
+ addFile(files, createFile(refSrcDir, "p/A.java", classAKind, "class A { }"));
+
+ switch (path) {
+ case CLASSPATH:
+ resetDirs(refClassesDir);
+ compile(files, refClassesDir, null, false);
+ break;
+ case SOURCEPATH:
+ deleteAll(refClassesDir);
+ }
+
+ return true;
+ }
+
+ void test(Path path, Kind pkgInfoKind, Kind classAKind,
+ Kind testPkgInfoKind, Kind testClassBKind)
+ throws IOException {
+ if (testPkgInfoKind == Kind.NO_FILE && testClassBKind == Kind.NO_FILE)
+ return;
+
+ System.out.println("Test " + (++count) + ": " + path + " " + pkgInfoKind + " " + classAKind + "; " + testPkgInfoKind + " " + testClassBKind);
+
+ resetDirs(testSrcDir, testClassesDir);
+
+ List<File> files = new ArrayList<File>();
+ addFile(files, createFile(testSrcDir, "p/package-info.java", testPkgInfoKind, ""));
+ String refA = (classAKind == Kind.NO_FILE ? "" : "A a;");
+ addFile(files, createFile(testSrcDir, "p/B.java", testClassBKind,
+ "class B { " + refA + " }"));
+
+ String expectedModule;
+ Kind pk = (testPkgInfoKind == Kind.NO_FILE ? pkgInfoKind : testPkgInfoKind);
+ Kind bk = (testClassBKind == Kind.NO_MODULE && pk != Kind.NO_FILE ? pk : testClassBKind);
+ Kind ak = ((testClassBKind == Kind.NO_FILE) ? Kind.NO_FILE
+ : (path == Path.SOURCEPATH && classAKind == Kind.NO_MODULE && pk != Kind.NO_FILE) ? pk
+ : classAKind);
+ Set<Kind> kinds = EnumSet.of(ak, bk, pk);
+ //System.out.println("kinds ak=" + ak + " bk=" + bk + " pk=" + pk + " " + kinds);
+ kinds.remove(Kind.NO_FILE);
+ expectedModule = (kinds.size() == 1 ? kinds.iterator().next().moduleName : null);
+ //System.out.println("expect " + expectedModule);
+
+ boolean expectError = (expectedModule == null);
+ compile(files, testClassesDir, getOpts(path), expectError);
+
+ if (!expectError) {
+ for (File f: files)
+ checkModuleAttribute(getClassFile(testSrcDir, f, testClassesDir), expectedModule);
+ }
+ }
+
+ 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");
+ }
+ }
+ }
+
+ /**
+ * Check the Module attribute in a class file.
+ * The Module attribute need not be present if expect is empty.
+ */
+ boolean checkModuleAttribute(File file, String expect) {
+ //System.out.println("check " + file + " " + expect);
+ try {
+ Attribute.Factory attrFactory = new Attribute.Factory();
+ attrFactory.setJSR277(true);
+ ClassFile cf = ClassFile.read(file, attrFactory);
+ Attribute attr = cf.getAttribute(Attribute.Module);
+ String attrName;
+ if (attr == null) {
+ if (expect.equals(""))
+ return true;
+ error("no module name in " + file + ": expected " + expect);
+ }
+ else if (attr instanceof Module_attribute) {
+ Module_attribute m = (Module_attribute) attr;
+ String name = m.getModuleName(cf.constant_pool);
+ if (name.equals(expect))
+ return true;
+ error("bad module name in " + file + ": " +
+ "expected " + expect + ", found " + name);
+ }
+ else
+ error("bad Module attribute in " + file);
+ } catch (ConstantPoolException e) {
+ error("Error accessing constant pool " + file + ": " + e);
+ } catch (IOException e) {
+ error("Error reading " + file + ": " + e);
+ }
+ return false;
+ }
+
+ List<String> getOpts(Path path) {
+ switch (path) {
+ case CLASSPATH:
+ return Arrays.asList("-classpath", refClassesDir.getPath());
+ case SOURCEPATH:
+ return Arrays.asList("-sourcepath", refSrcDir.getPath());
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+ /**
+ * Returns the primary class file for a given source file.
+ */
+ File getClassFile(File srcDir, File srcFile, File classesDir) {
+ String p = srcDir.toURI().relativize(srcFile.toURI()).toString();
+ p = p.substring(0, p.lastIndexOf(".")) + ".class";
+ return new File(classesDir, p);
+ }
+
+ /**
+ * 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 according to the test file Kind.
+ */
+ File createFile(File dir, String path, Kind kind, String defs) throws IOException {
+ int baseIndex = path.lastIndexOf('/');
+ int dot = path.lastIndexOf(".java");
+ String pkgName = path.substring(0, baseIndex).replace('/', '.');
+ String className = path.substring(baseIndex + 1, dot);
+
+ // package-info.class is not generated if it would be empty
+ // (i.e. has no annotations)
+ String annos = (className.equals("package-info") ? "@Deprecated " :"");
+
+ String body = annos + "package " + pkgName + "; " + defs;
+
+ switch (kind) {
+ case NO_FILE:
+ return null;
+
+ case NO_MODULE:
+ return createFile(dir, path, body);
+
+ default:
+ return createFile(dir, path, "module " + kind.moduleName + "; " + body);
+ }
+ }
+
+ /**
+ * 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 refSrcDir = new File("tmp", "refSrc"); // use "tmp" to help avoid accidents
+ File refClassesDir = new File("tmp", "refClasses");
+ File testSrcDir = new File("tmp", "testSrc");
+ File testClassesDir = new File("tmp", "testClasses");
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModuleInfoTest01.java Fri Aug 01 08:43:27 2008 -0700
@@ -0,0 +1,235 @@
+/*
+ * 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 6665690
+ * @summary implement JSR 277 modules
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+/*
+ * Test different types of module-info files, with different
+ * combinations of doc comments and annotations, and check
+ * module-info.class is generated as necessary.
+ */
+public class ModuleInfoTest01
+{
+ public static void main(String[] args) throws Exception {
+ new ModuleInfoTest01().run();
+ }
+
+
+ /**
+ * Main work method to run all the test cases.
+ */
+ void run() throws Exception {
+ String[] docs = { "", "/** Doc */ " };
+ String[] annos = { "", "@Deprecated " };
+
+ for (String doc: docs) {
+ for (String anno: annos) {
+ test(doc, anno);
+ }
+ }
+
+ if (errors == 0)
+ System.out.println(count + " tests passed");
+ else
+ throw new Exception(errors + "/" + count + " tests failed");
+ }
+
+ void test(String doc, String anno) throws IOException {
+ System.out.println("Test " + (++count) + ": " + doc + anno + "module m;");
+ resetDirs(srcDir, classesDir);
+ File f = createFile(srcDir, "m/module-info.java", doc + anno + "module m;");
+ compile(Arrays.asList(f), classesDir, null, false);
+
+ boolean expectClass = (anno.length() > 0);
+ String expectedModule = "m";
+
+ File cf = getClassFile(srcDir, f, classesDir);
+ if (expectClass) {
+ if (cf.exists()) {
+ checkModuleAttribute(cf, expectedModule);
+ }
+ else {
+ error("class file expected but not found");
+ }
+ }
+ else {
+ if (cf.exists())
+ error("class file found but not expected");
+ }
+ }
+
+ 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");
+ }
+ }
+ }
+
+ /**
+ * Check the Module attribute in a class file.
+ * The Module attribute need not be present if expect is empty.
+ */
+ boolean checkModuleAttribute(File file, String expect) {
+ //System.out.println("check " + file + " " + expect);
+ try {
+ Attribute.Factory attrFactory = new Attribute.Factory();
+ attrFactory.setJSR277(true);
+ ClassFile cf = ClassFile.read(file, attrFactory);
+ Attribute attr = cf.getAttribute(Attribute.Module);
+ String attrName;
+ if (attr == null) {
+ if (expect.equals(""))
+ return true;
+ error("no module name in " + file + ": expected " + expect);
+ }
+ else if (attr instanceof Module_attribute) {
+ Module_attribute m = (Module_attribute) attr;
+ String name = m.getModuleName(cf.constant_pool);
+ if (name.equals(expect))
+ return true;
+ error("bad module name in " + file + ": " +
+ "expected " + expect + ", found " + name);
+ }
+ else
+ error("bad Module attribute in " + file);
+ } catch (ConstantPoolException e) {
+ error("Error accessing constant pool " + file + ": " + e);
+ } catch (IOException e) {
+ error("Error reading " + file + ": " + e);
+ }
+ return false;
+ }
+
+ /**
+ * Returns the primary class file for a given source file.
+ */
+ File getClassFile(File srcDir, File srcFile, File classesDir) {
+ String p = srcDir.toURI().relativize(srcFile.toURI()).toString();
+ p = p.substring(0, p.lastIndexOf(".")) + ".class";
+ return new File(classesDir, p);
+ }
+
+ /**
+ * 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 = 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 Aug 01 08:43:27 2008 -0700
@@ -0,0 +1,229 @@
+/*
+ * 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 6665690
+ * @summary implement JSR 277 modules
+ */
+
+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);
+ 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 = {
+ "module m; package p;",
+ " " + ck.text,
+ " " + ik.decl + (ck == ClassKind.INTERFACE ? ik.intfTail : ik.classTail),
+ "}",
+ (needModule ? "class module { }" : "")
+ };
+
+ File test = createFile(srcDir, "Test.java", join(testBody));
+ boolean expectError =
+ (ck == ClassKind.ENUM && ik == ItemKind.AMBIG1)
+ || (ck == ClassKind.CLASS && ik == ItemKind.AMBIG2);
+
+ compile(Arrays.asList(test), 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 = 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/PackageInfoTest01.java Fri Aug 01 08:43:27 2008 -0700
@@ -0,0 +1,235 @@
+/*
+ * 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 6665690
+ * @summary implement JSR 277 modules
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+/*
+ */
+public class PackageInfoTest01
+{
+ public static void main(String[] args) throws Exception {
+ new PackageInfoTest01().run();
+ }
+
+
+ /**
+ * Main work method to run all the test cases.
+ */
+ void run() throws Exception {
+ String[] docs = { "", "/** Doc */ " };
+ String[] modules = { "", "module m; " };
+ String[] annos = { "", "@Deprecated " };
+
+ for (String doc: docs) {
+ for (String module: modules) {
+ for (String anno: annos) {
+ test(doc, module, anno);
+ }
+ }
+ }
+
+ if (errors == 0)
+ System.out.println(count + " tests passed");
+ else
+ throw new Exception(errors + "/" + count + " tests failed");
+ }
+
+ void test(String doc, String module, String anno) throws IOException {
+ System.out.println("Test " + (++count) + ": " + doc + module + anno + "package p;");
+ resetDirs(srcDir, classesDir);
+ File f = createFile(srcDir, "p/package-info.java", doc + module + anno + "package p;");
+ compile(Arrays.asList(f), classesDir, null, false);
+
+ boolean expectClass = (anno.length() > 0 || module.length() > 0);
+ String expectedModule = (module.length() > 0 ? "m" : "");
+
+ File cf = getClassFile(srcDir, f, classesDir);
+ if (expectClass) {
+ if (cf.exists()) {
+ checkModuleAttribute(cf, expectedModule);
+ }
+ else {
+ error("class file expected but not found");
+ }
+ }
+ else {
+ if (cf.exists())
+ error("class file found but not expected");
+ }
+ }
+
+ 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");
+ }
+ }
+ }
+
+ /**
+ * Check the Module attribute in a class file.
+ * The Module attribute need not be present if expect is empty.
+ */
+ boolean checkModuleAttribute(File file, String expect) {
+ //System.out.println("check " + file + " " + expect);
+ try {
+ Attribute.Factory attrFactory = new Attribute.Factory();
+ attrFactory.setJSR277(true);
+ ClassFile cf = ClassFile.read(file, attrFactory);
+ Attribute attr = cf.getAttribute(Attribute.Module);
+ String attrName;
+ if (attr == null) {
+ if (expect.equals(""))
+ return true;
+ error("no module name in " + file + ": expected " + expect);
+ }
+ else if (attr instanceof Module_attribute) {
+ Module_attribute m = (Module_attribute) attr;
+ String name = m.getModuleName(cf.constant_pool);
+ if (name.equals(expect))
+ return true;
+ error("bad module name in " + file + ": " +
+ "expected " + expect + ", found " + name);
+ }
+ else
+ error("bad Module attribute in " + file);
+ } catch (ConstantPoolException e) {
+ error("Error accessing constant pool " + file + ": " + e);
+ } catch (IOException e) {
+ error("Error reading " + file + ": " + e);
+ }
+ return false;
+ }
+
+ /**
+ * Returns the primary class file for a given source file.
+ */
+ File getClassFile(File srcDir, File srcFile, File classesDir) {
+ String p = srcDir.toURI().relativize(srcFile.toURI()).toString();
+ p = p.substring(0, p.lastIndexOf(".")) + ".class";
+ return new File(classesDir, p);
+ }
+
+ /**
+ * 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 = new File("tmp", "src"); // use "tmp" to help avoid accidents
+ File classesDir = new File("tmp", "classes");
+}