mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 11:34:38 +02:00
8152911: javac assertion error when compiling overlay sources
Avoid creating ModuleSymbols with unspecified name, to avoid conflicts with predefined ModuleSymbol for the java.base module. Reviewed-by: jjg
This commit is contained in:
parent
16bf17a9a7
commit
c58a8aae3e
11 changed files with 303 additions and 89 deletions
|
@ -31,6 +31,7 @@ import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import javax.tools.JavaFileManager;
|
import javax.tools.JavaFileManager;
|
||||||
import javax.tools.JavaFileManager.Location;
|
import javax.tools.JavaFileManager.Location;
|
||||||
|
@ -38,10 +39,14 @@ import javax.tools.JavaFileObject;
|
||||||
import javax.tools.JavaFileObject.Kind;
|
import javax.tools.JavaFileObject.Kind;
|
||||||
import javax.tools.StandardLocation;
|
import javax.tools.StandardLocation;
|
||||||
|
|
||||||
|
import com.sun.tools.javac.code.Symbol.Completer;
|
||||||
import com.sun.tools.javac.code.Symbol.CompletionFailure;
|
import com.sun.tools.javac.code.Symbol.CompletionFailure;
|
||||||
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
|
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
|
||||||
|
import com.sun.tools.javac.jvm.ModuleNameReader;
|
||||||
|
import com.sun.tools.javac.jvm.ModuleNameReader.BadClassFile;
|
||||||
import com.sun.tools.javac.resources.CompilerProperties.Errors;
|
import com.sun.tools.javac.resources.CompilerProperties.Errors;
|
||||||
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
|
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
|
||||||
|
import com.sun.tools.javac.util.Assert;
|
||||||
import com.sun.tools.javac.util.Context;
|
import com.sun.tools.javac.util.Context;
|
||||||
import com.sun.tools.javac.util.JCDiagnostic;
|
import com.sun.tools.javac.util.JCDiagnostic;
|
||||||
import com.sun.tools.javac.util.JCDiagnostic.Fragment;
|
import com.sun.tools.javac.util.JCDiagnostic.Fragment;
|
||||||
|
@ -50,7 +55,6 @@ import com.sun.tools.javac.util.ListBuffer;
|
||||||
import com.sun.tools.javac.util.Log;
|
import com.sun.tools.javac.util.Log;
|
||||||
import com.sun.tools.javac.util.Name;
|
import com.sun.tools.javac.util.Name;
|
||||||
import com.sun.tools.javac.util.Names;
|
import com.sun.tools.javac.util.Names;
|
||||||
import com.sun.tools.javac.util.StringUtils;
|
|
||||||
|
|
||||||
import static com.sun.tools.javac.code.Kinds.Kind.*;
|
import static com.sun.tools.javac.code.Kinds.Kind.*;
|
||||||
|
|
||||||
|
@ -84,6 +88,10 @@ public class ModuleFinder {
|
||||||
|
|
||||||
private final JCDiagnostic.Factory diags;
|
private final JCDiagnostic.Factory diags;
|
||||||
|
|
||||||
|
private ModuleNameReader moduleNameReader;
|
||||||
|
|
||||||
|
public ModuleInfoSourceFileCompleter sourceFileCompleter;
|
||||||
|
|
||||||
/** Get the ModuleFinder instance for this invocation. */
|
/** Get the ModuleFinder instance for this invocation. */
|
||||||
public static ModuleFinder instance(Context context) {
|
public static ModuleFinder instance(Context context) {
|
||||||
ModuleFinder instance = context.get(moduleFinderKey);
|
ModuleFinder instance = context.get(moduleFinderKey);
|
||||||
|
@ -182,6 +190,8 @@ public class ModuleFinder {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean inFindSingleModule;
|
||||||
|
|
||||||
public ModuleSymbol findSingleModule() {
|
public ModuleSymbol findSingleModule() {
|
||||||
try {
|
try {
|
||||||
JavaFileObject src_fo = getModuleInfoFromLocation(StandardLocation.SOURCE_PATH, Kind.SOURCE);
|
JavaFileObject src_fo = getModuleInfoFromLocation(StandardLocation.SOURCE_PATH, Kind.SOURCE);
|
||||||
|
@ -194,26 +204,41 @@ public class ModuleFinder {
|
||||||
if (fo == null) {
|
if (fo == null) {
|
||||||
msym = syms.unnamedModule;
|
msym = syms.unnamedModule;
|
||||||
} else {
|
} else {
|
||||||
// Note: the following may trigger a re-entrant call to Modules.enter
|
switch (fo.getKind()) {
|
||||||
// msym = new ModuleSymbol();
|
case SOURCE:
|
||||||
// ClassSymbol info = new ClassSymbol(Flags.MODULE, names.module_info, msym);
|
if (!inFindSingleModule) {
|
||||||
// info.modle = msym;
|
try {
|
||||||
// info.classfile = fo;
|
inFindSingleModule = true;
|
||||||
// info.members_field = WriteableScope.create(info);
|
// Note: the following will trigger a re-entrant call to Modules.enter
|
||||||
// msym.module_info = info;
|
msym = sourceFileCompleter.complete(fo);
|
||||||
msym = ModuleSymbol.create(null, names.module_info);
|
|
||||||
msym.module_info.classfile = fo;
|
msym.module_info.classfile = fo;
|
||||||
msym.completer = sym -> classFinder.fillIn(msym.module_info);
|
} finally {
|
||||||
// // TODO: should we do the following here, or as soon as we find the name in
|
inFindSingleModule = false;
|
||||||
// // the source or class file?
|
}
|
||||||
// // Consider the case when the class/source path module shadows one on the
|
} else {
|
||||||
// // module source path
|
//the module-info.java does not contain a module declaration,
|
||||||
// if (syms.modules.get(msym.name) != null) {
|
//avoid infinite recursion:
|
||||||
// // error: module already defined
|
msym = syms.unnamedModule;
|
||||||
// System.err.println("ERROR: module already defined: " + msym);
|
}
|
||||||
// } else {
|
break;
|
||||||
// syms.modules.put(msym.name, msym);
|
case CLASS:
|
||||||
// }
|
Name name;
|
||||||
|
try {
|
||||||
|
name = names.fromString(readModuleName(fo));
|
||||||
|
} catch (BadClassFile | IOException ex) {
|
||||||
|
//fillIn will report proper errors:
|
||||||
|
name = names.error;
|
||||||
|
}
|
||||||
|
msym = syms.enterModule(name);
|
||||||
|
msym.module_info.classfile = fo;
|
||||||
|
msym.completer = Completer.NULL_COMPLETER;
|
||||||
|
classFinder.fillIn(msym.module_info);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Assert.error();
|
||||||
|
msym = syms.unnamedModule;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msym.classLocation = StandardLocation.CLASS_OUTPUT;
|
msym.classLocation = StandardLocation.CLASS_OUTPUT;
|
||||||
|
@ -224,6 +249,12 @@ public class ModuleFinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String readModuleName(JavaFileObject jfo) throws IOException, ModuleNameReader.BadClassFile {
|
||||||
|
if (moduleNameReader == null)
|
||||||
|
moduleNameReader = new ModuleNameReader();
|
||||||
|
return moduleNameReader.readModuleName(jfo);
|
||||||
|
}
|
||||||
|
|
||||||
private JavaFileObject getModuleInfoFromLocation(Location location, Kind kind) throws IOException {
|
private JavaFileObject getModuleInfoFromLocation(Location location, Kind kind) throws IOException {
|
||||||
if (!fileManager.hasLocation(location))
|
if (!fileManager.hasLocation(location))
|
||||||
return null;
|
return null;
|
||||||
|
@ -332,4 +363,8 @@ public class ModuleFinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface ModuleInfoSourceFileCompleter {
|
||||||
|
public ModuleSymbol complete(JavaFileObject file);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -916,7 +916,6 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a ModuleSymbol with an associated module-info ClassSymbol.
|
* Create a ModuleSymbol with an associated module-info ClassSymbol.
|
||||||
* The name of the module may be null, if it is not known yet.
|
|
||||||
*/
|
*/
|
||||||
public static ModuleSymbol create(Name name, Name module_info) {
|
public static ModuleSymbol create(Name name, Name module_info) {
|
||||||
ModuleSymbol msym = new ModuleSymbol(name, null);
|
ModuleSymbol msym = new ModuleSymbol(name, null);
|
||||||
|
@ -930,6 +929,7 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||||
|
|
||||||
public ModuleSymbol(Name name, Symbol owner) {
|
public ModuleSymbol(Name name, Symbol owner) {
|
||||||
super(MDL, 0, name, null, owner);
|
super(MDL, 0, name, null, owner);
|
||||||
|
Assert.checkNonNull(name);
|
||||||
this.type = new ModuleType(this);
|
this.type = new ModuleType(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -764,17 +764,6 @@ public class Symtab {
|
||||||
return msym;
|
return msym;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enterModule(ModuleSymbol msym, Name name) {
|
|
||||||
Assert.checkNull(modules.get(name));
|
|
||||||
Assert.checkNull(msym.name);
|
|
||||||
msym.name = name;
|
|
||||||
addRootPackageFor(msym);
|
|
||||||
ClassSymbol info = msym.module_info;
|
|
||||||
info.fullname = msym.name.append('.', names.module_info);
|
|
||||||
info.flatname = info.fullname;
|
|
||||||
modules.put(name, msym);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModuleSymbol getModule(Name name) {
|
public ModuleSymbol getModule(Name name) {
|
||||||
return modules.get(name);
|
return modules.get(name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,13 +293,10 @@ public class Modules extends JCTree.Visitor {
|
||||||
ModuleSymbol sym;
|
ModuleSymbol sym;
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
sym = (ModuleSymbol) c.owner;
|
sym = (ModuleSymbol) c.owner;
|
||||||
if (sym.name == null) {
|
Assert.checkNonNull(sym.name);
|
||||||
//ModuleFinder.findSingleModule creates a stub of a ModuleSymbol without a name,
|
Name treeName = TreeInfo.fullName(decl.qualId);
|
||||||
//fill the name here after the module-info.java has been parsed
|
if (sym.name != treeName) {
|
||||||
//also enter the ModuleSymbol among modules:
|
log.error(decl.pos(), Errors.ModuleNameMismatch(name, sym.name));
|
||||||
syms.enterModule(sym, name);
|
|
||||||
} else {
|
|
||||||
// TODO: validate name
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sym = syms.enterModule(name);
|
sym = syms.enterModule(name);
|
||||||
|
@ -1006,6 +1003,10 @@ public class Modules extends JCTree.Visitor {
|
||||||
return new Symbol.Completer() {
|
return new Symbol.Completer() {
|
||||||
@Override
|
@Override
|
||||||
public void complete(Symbol sym) throws CompletionFailure {
|
public void complete(Symbol sym) throws CompletionFailure {
|
||||||
|
if (inInitModules) {
|
||||||
|
sym.completer = this;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
ModuleSymbol msym = (ModuleSymbol) sym;
|
ModuleSymbol msym = (ModuleSymbol) sym;
|
||||||
Set<ModuleSymbol> allModules = allModules();
|
Set<ModuleSymbol> allModules = allModules();
|
||||||
for (ModuleSymbol m : allModules) {
|
for (ModuleSymbol m : allModules) {
|
||||||
|
|
|
@ -80,6 +80,7 @@ import com.sun.tools.javac.util.DefinedBy;
|
||||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||||
import com.sun.tools.javac.util.ListBuffer;
|
import com.sun.tools.javac.util.ListBuffer;
|
||||||
import com.sun.tools.javac.util.Log;
|
import com.sun.tools.javac.util.Log;
|
||||||
|
import com.sun.tools.javac.jvm.ModuleNameReader;
|
||||||
import com.sun.tools.javac.util.Pair;
|
import com.sun.tools.javac.util.Pair;
|
||||||
import com.sun.tools.javac.util.StringUtils;
|
import com.sun.tools.javac.util.StringUtils;
|
||||||
|
|
||||||
|
|
|
@ -2396,12 +2396,15 @@ public class ClassReader {
|
||||||
} else {
|
} else {
|
||||||
c.flags_field = flags;
|
c.flags_field = flags;
|
||||||
Name modInfoName = readModuleInfoName(nextChar());
|
Name modInfoName = readModuleInfoName(nextChar());
|
||||||
if (c.owner.name == null) {
|
|
||||||
syms.enterModule((ModuleSymbol) c.owner, Convert.packagePart(modInfoName));
|
|
||||||
} else {
|
|
||||||
// TODO: validate name
|
|
||||||
}
|
|
||||||
currentModule = (ModuleSymbol) c.owner;
|
currentModule = (ModuleSymbol) c.owner;
|
||||||
|
if (currentModule.name.append('.', names.module_info) != modInfoName) {
|
||||||
|
//strip trailing .module-info, if exists:
|
||||||
|
int modInfoStart = modInfoName.length() - names.module_info.length();
|
||||||
|
modInfoName = modInfoName.subName(modInfoStart, modInfoName.length()) == names.module_info &&
|
||||||
|
modInfoName.charAt(modInfoStart - 1) == '.' ?
|
||||||
|
modInfoName.subName(0, modInfoStart - 1) : modInfoName;
|
||||||
|
throw badClassFile("module.name.mismatch", modInfoName, currentModule.name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// class attributes must be read before class
|
// class attributes must be read before class
|
||||||
|
|
|
@ -22,13 +22,15 @@
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
package com.sun.tools.javac.file;
|
package com.sun.tools.javac.jvm;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import javax.tools.JavaFileObject;
|
||||||
|
|
||||||
import com.sun.tools.javac.jvm.ClassFile;
|
import com.sun.tools.javac.jvm.ClassFile;
|
||||||
|
|
||||||
import static com.sun.tools.javac.jvm.ClassFile.*;
|
import static com.sun.tools.javac.jvm.ClassFile.*;
|
||||||
|
@ -44,7 +46,7 @@ import static com.sun.tools.javac.jvm.ClassFile.*;
|
||||||
* notice.</b>
|
* notice.</b>
|
||||||
*/
|
*/
|
||||||
public class ModuleNameReader {
|
public class ModuleNameReader {
|
||||||
static class BadClassFile extends Exception {
|
public static class BadClassFile extends Exception {
|
||||||
private static final long serialVersionUID = 0;
|
private static final long serialVersionUID = 0;
|
||||||
BadClassFile(String msg) {
|
BadClassFile(String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
|
@ -61,20 +63,27 @@ public class ModuleNameReader {
|
||||||
*/
|
*/
|
||||||
private int bp;
|
private int bp;
|
||||||
|
|
||||||
/** The objects of the constant pool.
|
|
||||||
*/
|
|
||||||
private Object[] poolObj;
|
|
||||||
|
|
||||||
/** For every constant pool entry, an index into buf where the
|
/** For every constant pool entry, an index into buf where the
|
||||||
* defining section of the entry is found.
|
* defining section of the entry is found.
|
||||||
*/
|
*/
|
||||||
private int[] poolIdx;
|
private int[] poolIdx;
|
||||||
|
|
||||||
ModuleNameReader() {
|
public ModuleNameReader() {
|
||||||
}
|
}
|
||||||
|
|
||||||
String readModuleName(Path p) throws IOException, BadClassFile {
|
public String readModuleName(Path p) throws IOException, BadClassFile {
|
||||||
try (InputStream in = Files.newInputStream(p)) {
|
try (InputStream in = Files.newInputStream(p)) {
|
||||||
|
return readModuleName(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String readModuleName(JavaFileObject jfo) throws IOException, BadClassFile {
|
||||||
|
try (InputStream in = jfo.openInputStream()) {
|
||||||
|
return readModuleName(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String readModuleName(InputStream in) throws IOException, BadClassFile {
|
||||||
bp = 0;
|
bp = 0;
|
||||||
buf = readInputStream(buf, in);
|
buf = readInputStream(buf, in);
|
||||||
|
|
||||||
|
@ -90,7 +99,6 @@ public class ModuleNameReader {
|
||||||
int accessflags = nextChar();
|
int accessflags = nextChar();
|
||||||
return readModuleInfoName(nextChar());
|
return readModuleInfoName(nextChar());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** Extract a character at position bp from buf.
|
/** Extract a character at position bp from buf.
|
||||||
*/
|
*/
|
||||||
|
@ -120,7 +128,6 @@ public class ModuleNameReader {
|
||||||
*/
|
*/
|
||||||
void indexPool() throws BadClassFile {
|
void indexPool() throws BadClassFile {
|
||||||
poolIdx = new int[nextChar()];
|
poolIdx = new int[nextChar()];
|
||||||
poolObj = new Object[poolIdx.length];
|
|
||||||
int i = 1;
|
int i = 1;
|
||||||
while (i < poolIdx.length) {
|
while (i < poolIdx.length) {
|
||||||
poolIdx[i++] = bp;
|
poolIdx[i++] = bp;
|
|
@ -37,6 +37,7 @@ import java.util.MissingResourceException;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import javax.annotation.processing.Processor;
|
import javax.annotation.processing.Processor;
|
||||||
import javax.lang.model.SourceVersion;
|
import javax.lang.model.SourceVersion;
|
||||||
|
@ -67,7 +68,9 @@ import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||||
import com.sun.tools.javac.tree.JCTree.JCLambda;
|
import com.sun.tools.javac.tree.JCTree.JCLambda;
|
||||||
import com.sun.tools.javac.tree.JCTree.JCMemberReference;
|
import com.sun.tools.javac.tree.JCTree.JCMemberReference;
|
||||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||||
|
import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
|
||||||
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||||
|
import com.sun.tools.javac.tree.JCTree.Tag;
|
||||||
import com.sun.tools.javac.util.*;
|
import com.sun.tools.javac.util.*;
|
||||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||||
import com.sun.tools.javac.util.JCDiagnostic.Factory;
|
import com.sun.tools.javac.util.JCDiagnostic.Factory;
|
||||||
|
@ -341,6 +344,13 @@ public class JavaCompiler {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
protected final ModuleFinder.ModuleInfoSourceFileCompleter moduleInfoSourceFileCompleter =
|
||||||
|
fo -> (ModuleSymbol) readSourceFile(parseImplicitFile(fo), null, tl -> {
|
||||||
|
return tl.defs.nonEmpty() && tl.defs.head.hasTag(Tag.MODULEDEF) ?
|
||||||
|
((JCModuleDecl) tl.defs.head).sym.module_info :
|
||||||
|
syms.defineClass(names.module_info, syms.errModule);
|
||||||
|
}).owner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command line options.
|
* Command line options.
|
||||||
*/
|
*/
|
||||||
|
@ -411,6 +421,7 @@ public class JavaCompiler {
|
||||||
diags = Factory.instance(context);
|
diags = Factory.instance(context);
|
||||||
|
|
||||||
finder.sourceCompleter = sourceCompleter;
|
finder.sourceCompleter = sourceCompleter;
|
||||||
|
moduleFinder.sourceFileCompleter = moduleInfoSourceFileCompleter;
|
||||||
|
|
||||||
options = Options.instance(context);
|
options = Options.instance(context);
|
||||||
|
|
||||||
|
@ -779,6 +790,19 @@ public class JavaCompiler {
|
||||||
readSourceFile(null, c);
|
readSourceFile(null, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private JCTree.JCCompilationUnit parseImplicitFile(JavaFileObject filename) {
|
||||||
|
JavaFileObject prev = log.useSource(filename);
|
||||||
|
try {
|
||||||
|
JCTree.JCCompilationUnit t = parse(filename, filename.getCharContent(false));
|
||||||
|
return t;
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("error.reading.file", filename, JavacFileManager.getMessage(e));
|
||||||
|
return make.TopLevel(List.<JCTree>nil());
|
||||||
|
} finally {
|
||||||
|
log.useSource(prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Compile a ClassSymbol from source, optionally using the given compilation unit as
|
/** Compile a ClassSymbol from source, optionally using the given compilation unit as
|
||||||
* the source tree.
|
* the source tree.
|
||||||
* @param tree the compilation unit in which the given ClassSymbol resides,
|
* @param tree the compilation unit in which the given ClassSymbol resides,
|
||||||
|
@ -789,20 +813,20 @@ public class JavaCompiler {
|
||||||
if (completionFailureName == c.fullname) {
|
if (completionFailureName == c.fullname) {
|
||||||
throw new CompletionFailure(c, "user-selected completion failure by class name");
|
throw new CompletionFailure(c, "user-selected completion failure by class name");
|
||||||
}
|
}
|
||||||
JavaFileObject filename = c.classfile;
|
|
||||||
JavaFileObject prev = log.useSource(filename);
|
|
||||||
|
|
||||||
if (tree == null) {
|
if (tree == null) {
|
||||||
try {
|
tree = parseImplicitFile(c.classfile);
|
||||||
tree = parse(filename, filename.getCharContent(false));
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("error.reading.file", filename, JavacFileManager.getMessage(e));
|
|
||||||
tree = make.TopLevel(List.<JCTree>nil());
|
|
||||||
} finally {
|
|
||||||
log.useSource(prev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readSourceFile(tree, c, cut -> c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ClassSymbol readSourceFile(JCCompilationUnit tree,
|
||||||
|
ClassSymbol expectedSymbol,
|
||||||
|
Function<JCCompilationUnit, ClassSymbol> symbolGetter)
|
||||||
|
throws CompletionFailure {
|
||||||
|
Assert.checkNonNull(tree);
|
||||||
|
|
||||||
if (!taskListener.isEmpty()) {
|
if (!taskListener.isEmpty()) {
|
||||||
TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
|
TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
|
||||||
taskListener.started(e);
|
taskListener.started(e);
|
||||||
|
@ -814,18 +838,20 @@ public class JavaCompiler {
|
||||||
// Note that if module resolution failed, we may not even
|
// Note that if module resolution failed, we may not even
|
||||||
// have enough modules available to access java.lang, and
|
// have enough modules available to access java.lang, and
|
||||||
// so risk getting FatalError("no.java.lang") from MemberEnter.
|
// so risk getting FatalError("no.java.lang") from MemberEnter.
|
||||||
if (!modules.enter(List.of(tree), c)) {
|
if (!modules.enter(List.of(tree), expectedSymbol)) {
|
||||||
throw new CompletionFailure(c, diags.fragment("cant.resolve.modules"));
|
throw new CompletionFailure(symbolGetter.apply(tree),
|
||||||
|
diags.fragment("cant.resolve.modules"));
|
||||||
}
|
}
|
||||||
|
|
||||||
enter.complete(List.of(tree), c);
|
enter.complete(List.of(tree), expectedSymbol);
|
||||||
|
|
||||||
if (!taskListener.isEmpty()) {
|
if (!taskListener.isEmpty()) {
|
||||||
TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
|
TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
|
||||||
taskListener.finished(e);
|
taskListener.finished(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enter.getEnv(c) == null) {
|
ClassSymbol sym = symbolGetter.apply(tree);
|
||||||
|
if (sym == null || enter.getEnv(sym) == null) {
|
||||||
boolean isPkgInfo =
|
boolean isPkgInfo =
|
||||||
tree.sourcefile.isNameCompatible("package-info",
|
tree.sourcefile.isNameCompatible("package-info",
|
||||||
JavaFileObject.Kind.SOURCE);
|
JavaFileObject.Kind.SOURCE);
|
||||||
|
@ -836,24 +862,26 @@ public class JavaCompiler {
|
||||||
if (enter.getEnv(tree.modle) == null) {
|
if (enter.getEnv(tree.modle) == null) {
|
||||||
JCDiagnostic diag =
|
JCDiagnostic diag =
|
||||||
diagFactory.fragment("file.does.not.contain.module");
|
diagFactory.fragment("file.does.not.contain.module");
|
||||||
throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory);
|
throw new ClassFinder.BadClassFile(sym, tree.sourcefile, diag, diagFactory);
|
||||||
}
|
}
|
||||||
} else if (isPkgInfo) {
|
} else if (isPkgInfo) {
|
||||||
if (enter.getEnv(tree.packge) == null) {
|
if (enter.getEnv(tree.packge) == null) {
|
||||||
JCDiagnostic diag =
|
JCDiagnostic diag =
|
||||||
diagFactory.fragment("file.does.not.contain.package",
|
diagFactory.fragment("file.does.not.contain.package",
|
||||||
c.location());
|
sym.location());
|
||||||
throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory);
|
throw new ClassFinder.BadClassFile(sym, tree.sourcefile, diag, diagFactory);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
JCDiagnostic diag =
|
JCDiagnostic diag =
|
||||||
diagFactory.fragment("file.doesnt.contain.class",
|
diagFactory.fragment("file.doesnt.contain.class",
|
||||||
c.getQualifiedName());
|
sym.getQualifiedName());
|
||||||
throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory);
|
throw new ClassFinder.BadClassFile(sym, tree.sourcefile, diag, diagFactory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicitSourceFilesRead = true;
|
implicitSourceFilesRead = true;
|
||||||
|
|
||||||
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Track when the JavaCompiler has been used to compile something. */
|
/** Track when the JavaCompiler has been used to compile something. */
|
||||||
|
|
|
@ -2770,6 +2770,10 @@ compiler.err.unnamed.pkg.not.allowed.named.modules=\
|
||||||
compiler.err.module.name.mismatch=\
|
compiler.err.module.name.mismatch=\
|
||||||
module name {0} does not match expected name {1}
|
module name {0} does not match expected name {1}
|
||||||
|
|
||||||
|
# 0: name, 1: name
|
||||||
|
compiler.misc.module.name.mismatch=\
|
||||||
|
module name {0} does not match expected name {1}
|
||||||
|
|
||||||
compiler.err.module.decl.sb.in.module-info.java=\
|
compiler.err.module.decl.sb.in.module-info.java=\
|
||||||
module declarations should be in a file named module-info.java
|
module declarations should be in a file named module-info.java
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,7 @@ compiler.misc.kindname.type.variable
|
||||||
compiler.misc.kindname.type.variable.bound
|
compiler.misc.kindname.type.variable.bound
|
||||||
compiler.misc.kindname.value
|
compiler.misc.kindname.value
|
||||||
compiler.misc.incompatible.eq.lower.bounds # cannot happen?
|
compiler.misc.incompatible.eq.lower.bounds # cannot happen?
|
||||||
|
compiler.misc.module.name.mismatch
|
||||||
compiler.misc.no.unique.minimal.instance.exists
|
compiler.misc.no.unique.minimal.instance.exists
|
||||||
compiler.misc.no.unique.maximal.instance.exists # cannot happen?
|
compiler.misc.no.unique.maximal.instance.exists # cannot happen?
|
||||||
compiler.misc.resume.abort # prompt for a response
|
compiler.misc.resume.abort # prompt for a response
|
||||||
|
|
|
@ -58,6 +58,8 @@ import com.sun.tools.javac.code.Symbol.ModuleSymbol;
|
||||||
import toolbox.JarTask;
|
import toolbox.JarTask;
|
||||||
import toolbox.JavacTask;
|
import toolbox.JavacTask;
|
||||||
import toolbox.Task;
|
import toolbox.Task;
|
||||||
|
import toolbox.Task.Expect;
|
||||||
|
import toolbox.Task.OutputKind;
|
||||||
|
|
||||||
public class EdgeCases extends ModuleTestBase {
|
public class EdgeCases extends ModuleTestBase {
|
||||||
|
|
||||||
|
@ -304,4 +306,147 @@ public class EdgeCases extends ModuleTestBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImplicitJavaBase(Path base) throws Exception {
|
||||||
|
Path src = base.resolve("src");
|
||||||
|
Path src_java_base = src.resolve("java.base");
|
||||||
|
Files.createDirectories(src_java_base);
|
||||||
|
tb.writeJavaFiles(src_java_base, "module java.base { exports java.lang; }");
|
||||||
|
tb.writeJavaFiles(src_java_base,
|
||||||
|
"package java.lang; public class Object {}");
|
||||||
|
Path classes = base.resolve("classes");
|
||||||
|
tb.createDirectories(classes);
|
||||||
|
|
||||||
|
//module-info from source:
|
||||||
|
new JavacTask(tb)
|
||||||
|
.options("-sourcepath", src_java_base.toString())
|
||||||
|
.outdir(classes)
|
||||||
|
.files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
|
||||||
|
.run()
|
||||||
|
.writeAll();
|
||||||
|
|
||||||
|
//module-info from class:
|
||||||
|
if (!Files.exists(classes.resolve("module-info.class"))) {
|
||||||
|
throw new AssertionError("module-info.class not created!");
|
||||||
|
}
|
||||||
|
|
||||||
|
new JavacTask(tb)
|
||||||
|
.outdir(classes)
|
||||||
|
.files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
|
||||||
|
.run()
|
||||||
|
.writeAll();
|
||||||
|
|
||||||
|
//broken module-info.class:
|
||||||
|
Files.newOutputStream(classes.resolve("module-info.class")).close();
|
||||||
|
|
||||||
|
List<String> log = new JavacTask(tb)
|
||||||
|
.options("-XDrawDiagnostics")
|
||||||
|
.outdir(classes)
|
||||||
|
.files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
|
||||||
|
.run(Expect.FAIL)
|
||||||
|
.writeAll()
|
||||||
|
.getOutputLines(OutputKind.DIRECT);
|
||||||
|
|
||||||
|
List<String> expected = Arrays.asList(
|
||||||
|
"- compiler.err.cant.access: <error>.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.illegal.start.of.class.file))",
|
||||||
|
"1 error");
|
||||||
|
|
||||||
|
if (!expected.equals(log)) {
|
||||||
|
throw new AssertionError("Unexpected output: " + log);
|
||||||
|
}
|
||||||
|
|
||||||
|
//broken module-info.java:
|
||||||
|
Files.delete(classes.resolve("module-info.class"));
|
||||||
|
|
||||||
|
try (Writer out = Files.newBufferedWriter(src_java_base.resolve("module-info.java"))) {
|
||||||
|
out.write("class Broken {}");
|
||||||
|
}
|
||||||
|
|
||||||
|
log = new JavacTask(tb)
|
||||||
|
.options("-sourcepath", src_java_base.toString(),
|
||||||
|
"-XDrawDiagnostics")
|
||||||
|
.outdir(classes)
|
||||||
|
.files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
|
||||||
|
.run(Expect.FAIL)
|
||||||
|
.writeAll()
|
||||||
|
.getOutputLines(OutputKind.DIRECT);
|
||||||
|
|
||||||
|
expected = Arrays.asList("X");
|
||||||
|
|
||||||
|
if (expected.equals(log)) {
|
||||||
|
throw new AssertionError("Unexpected output: " + log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testModuleInfoNameMismatchSource(Path base) throws Exception {
|
||||||
|
Path src = base.resolve("src");
|
||||||
|
Path m1 = src.resolve("m1");
|
||||||
|
Files.createDirectories(m1);
|
||||||
|
tb.writeJavaFiles(m1, "module other { }",
|
||||||
|
"package test; public class Test {}");
|
||||||
|
Path classes = base.resolve("classes");
|
||||||
|
tb.createDirectories(classes);
|
||||||
|
|
||||||
|
List<String> log = new JavacTask(tb)
|
||||||
|
.options("--module-source-path", src.toString(),
|
||||||
|
"-XDrawDiagnostics")
|
||||||
|
.outdir(classes)
|
||||||
|
.files(findJavaFiles(m1.resolve("test").resolve("Test.java")))
|
||||||
|
.run(Expect.FAIL)
|
||||||
|
.writeAll()
|
||||||
|
.getOutputLines(OutputKind.DIRECT);
|
||||||
|
|
||||||
|
List<String> expected = Arrays.asList(
|
||||||
|
"module-info.java:1:1: compiler.err.module.name.mismatch: other, m1",
|
||||||
|
"- compiler.err.cant.access: m1.module-info, (compiler.misc.cant.resolve.modules)",
|
||||||
|
"2 errors");
|
||||||
|
|
||||||
|
if (!expected.equals(log)) {
|
||||||
|
throw new AssertionError("Unexpected output: " + log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testModuleInfoNameMismatchClass(Path base) throws Exception {
|
||||||
|
Path src = base.resolve("src");
|
||||||
|
Files.createDirectories(src);
|
||||||
|
tb.writeJavaFiles(src, "module other { }",
|
||||||
|
"package test; public class Test {}");
|
||||||
|
Path classes = base.resolve("classes");
|
||||||
|
Path m1Classes = classes.resolve("m1");
|
||||||
|
tb.createDirectories(m1Classes);
|
||||||
|
|
||||||
|
new JavacTask(tb)
|
||||||
|
.outdir(m1Classes)
|
||||||
|
.files(findJavaFiles(src))
|
||||||
|
.run()
|
||||||
|
.writeAll()
|
||||||
|
.getOutputLines(OutputKind.DIRECT);
|
||||||
|
|
||||||
|
Path src2 = base.resolve("src2");
|
||||||
|
Files.createDirectories(src2);
|
||||||
|
tb.writeJavaFiles(src2, "module use { requires m1; }");
|
||||||
|
|
||||||
|
Path classes2 = base.resolve("classes2");
|
||||||
|
tb.createDirectories(classes2);
|
||||||
|
|
||||||
|
List<String> log = new JavacTask(tb)
|
||||||
|
.options("--module-path", classes.toString(),
|
||||||
|
"-XDrawDiagnostics")
|
||||||
|
.outdir(classes2)
|
||||||
|
.files(findJavaFiles(src2))
|
||||||
|
.run(Expect.FAIL)
|
||||||
|
.writeAll()
|
||||||
|
.getOutputLines(OutputKind.DIRECT);
|
||||||
|
|
||||||
|
List<String> expected = Arrays.asList(
|
||||||
|
"- compiler.err.cant.access: m1.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.module.name.mismatch: other, m1))",
|
||||||
|
"1 error");
|
||||||
|
|
||||||
|
if (!expected.equals(log)) {
|
||||||
|
throw new AssertionError("Unexpected output: " + log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue