8335989: Implement JEP 494: Module Import Declarations (Second Preview)
Reviewed-by: vromero, abimpoudis, mcimadamore, alanb
This commit is contained in:
parent
e7d90b941f
commit
1e97c1c913
@ -1896,6 +1896,11 @@ public class CreateSymbols {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ed.packageName.equals("jdk/internal/javac")) {
|
||||
//keep jdk/internal/javac untouched. It is used to determine participates in preview:
|
||||
continue;
|
||||
}
|
||||
|
||||
Set<String> usingModules = package2ModulesUsingIt.getOrDefault(ed.packageName(), Set.of());
|
||||
|
||||
ed.to.retainAll(usingModules);
|
||||
|
@ -77,7 +77,7 @@ public @interface PreviewFeature {
|
||||
@JEP(number=466, title="ClassFile API", status="Second Preview")
|
||||
CLASSFILE_API,
|
||||
STREAM_GATHERERS,
|
||||
@JEP(number=476, title="Module Import Declarations", status="Preview")
|
||||
@JEP(number=494, title="Module Import Declarations", status="Second Preview")
|
||||
MODULE_IMPORTS,
|
||||
@JEP(number=478, title="Key Derivation Function API", status="Preview")
|
||||
KEY_DERIVATION,
|
||||
|
@ -31,6 +31,7 @@ import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.module.InvalidModuleDescriptorException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Builder;
|
||||
@ -189,6 +190,7 @@ public final class ModuleInfo {
|
||||
|
||||
int minor_version = in.readUnsignedShort();
|
||||
int major_version = in.readUnsignedShort();
|
||||
boolean isPreview = minor_version == ClassFile.PREVIEW_MINOR_VERSION;
|
||||
if (!VM.isSupportedModuleDescriptorVersion(major_version, minor_version)) {
|
||||
throw invalidModuleDescriptor("Unsupported major.minor version "
|
||||
+ major_version + "." + minor_version);
|
||||
@ -248,7 +250,7 @@ public final class ModuleInfo {
|
||||
|
||||
switch (attribute_name) {
|
||||
case MODULE :
|
||||
builder = readModuleAttribute(in, cpool, major_version);
|
||||
builder = readModuleAttribute(in, cpool, major_version, isPreview);
|
||||
break;
|
||||
|
||||
case MODULE_PACKAGES :
|
||||
@ -344,7 +346,8 @@ public final class ModuleInfo {
|
||||
* Reads the Module attribute, returning the ModuleDescriptor.Builder to
|
||||
* build the corresponding ModuleDescriptor.
|
||||
*/
|
||||
private Builder readModuleAttribute(DataInput in, ConstantPool cpool, int major)
|
||||
private Builder readModuleAttribute(DataInput in, ConstantPool cpool, int major,
|
||||
boolean isPreview)
|
||||
throws IOException
|
||||
{
|
||||
// module_name
|
||||
@ -405,14 +408,23 @@ public final class ModuleInfo {
|
||||
throw invalidModuleDescriptor("The requires entry for java.base"
|
||||
+ " has ACC_SYNTHETIC set");
|
||||
}
|
||||
// requires transitive java.base is illegal unless:
|
||||
// - the major version is 53 (JDK 9), or:
|
||||
// - the classfile is a preview classfile, or:
|
||||
// - the module is deemed to be participating in preview
|
||||
// (i.e. the module is a java.* module)
|
||||
// requires static java.base is illegal unless:
|
||||
// - the major version is 53 (JDK 9), or:
|
||||
if (major >= 54
|
||||
&& (mods.contains(Requires.Modifier.TRANSITIVE)
|
||||
&& ((mods.contains(Requires.Modifier.TRANSITIVE)
|
||||
&& !isPreview
|
||||
&& !"java.se".equals(mn))
|
||||
|| mods.contains(Requires.Modifier.STATIC))) {
|
||||
String flagName;
|
||||
if (mods.contains(Requires.Modifier.TRANSITIVE)) {
|
||||
flagName = "ACC_TRANSITIVE";
|
||||
} else {
|
||||
if (mods.contains(Requires.Modifier.STATIC)) {
|
||||
flagName = "ACC_STATIC_PHASE";
|
||||
} else {
|
||||
flagName = "ACC_TRANSITIVE";
|
||||
}
|
||||
throw invalidModuleDescriptor("The requires entry for java.base"
|
||||
+ " has " + flagName + " set");
|
||||
|
@ -154,6 +154,7 @@ module java.base {
|
||||
exports jdk.internal.javac to
|
||||
java.compiler,
|
||||
java.desktop, // for ScopedValue
|
||||
java.se, // for ParticipatesInPreview
|
||||
jdk.compiler,
|
||||
jdk.incubator.vector, // participates in preview features
|
||||
jdk.jartool, // participates in preview features
|
||||
|
@ -23,6 +23,8 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import jdk.internal.javac.ParticipatesInPreview;
|
||||
|
||||
/**
|
||||
* Defines the API of the Java SE Platform.
|
||||
*
|
||||
@ -38,7 +40,9 @@
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
@ParticipatesInPreview
|
||||
module java.se {
|
||||
requires transitive java.base;
|
||||
requires transitive java.compiler;
|
||||
requires transitive java.datatransfer;
|
||||
requires transitive java.desktop;
|
||||
|
@ -87,12 +87,26 @@ public class JavacScope implements com.sun.source.tree.Scope {
|
||||
} else {
|
||||
// synthesize an outermost "star-import" scope
|
||||
return new JavacScope(env) {
|
||||
public boolean isStarImportScope() {
|
||||
return true;
|
||||
@Override
|
||||
public ScopeType getScopeType() {
|
||||
return ScopeType.STAR_IMPORT;
|
||||
}
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public JavacScope getEnclosingScope() {
|
||||
return null;
|
||||
return new JavacScope(env) {
|
||||
@Override
|
||||
public ScopeType getScopeType() {
|
||||
return ScopeType.MODULE_IMPORT;
|
||||
}
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public JavacScope getEnclosingScope() {
|
||||
return null;
|
||||
}
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public Iterable<? extends Element> getLocalElements() {
|
||||
return env.toplevel.moduleImportScope.getSymbols(VALIDATOR);
|
||||
}
|
||||
};
|
||||
}
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public Iterable<? extends Element> getLocalElements() {
|
||||
@ -122,21 +136,27 @@ public class JavacScope implements com.sun.source.tree.Scope {
|
||||
return env;
|
||||
}
|
||||
|
||||
public boolean isStarImportScope() {
|
||||
return false;
|
||||
public ScopeType getScopeType() {
|
||||
return ScopeType.ORDINARY;
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
return other instanceof JavacScope javacScope
|
||||
&& env.equals(javacScope.env)
|
||||
&& isStarImportScope() == javacScope.isStarImportScope();
|
||||
&& getScopeType()== javacScope.getScopeType();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return env.hashCode() + (isStarImportScope() ? 1 : 0);
|
||||
return env.hashCode() + getScopeType().hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "JavacScope[env=" + env + ",starImport=" + isStarImportScope() + "]";
|
||||
return "JavacScope[env=" + env + ", scope type=" + getScopeType() + "]";
|
||||
}
|
||||
|
||||
private enum ScopeType {
|
||||
ORDINARY,
|
||||
STAR_IMPORT,
|
||||
MODULE_IMPORT;
|
||||
}
|
||||
}
|
||||
|
@ -1402,6 +1402,7 @@ public class JavacTrees extends DocTrees {
|
||||
jcCompilationUnit.namedImportScope = new NamedImportScope(psym);
|
||||
jcCompilationUnit.packge = psym;
|
||||
jcCompilationUnit.starImportScope = new StarImportScope(psym);
|
||||
jcCompilationUnit.moduleImportScope = new StarImportScope(psym);
|
||||
jcCompilationUnit.toplevelScope = WriteableScope.create(psym);
|
||||
return new TreePath(jcCompilationUnit);
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ package com.sun.tools.javac.code;
|
||||
|
||||
import com.sun.tools.javac.code.Lint.LintCategory;
|
||||
import com.sun.tools.javac.code.Source.Feature;
|
||||
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
|
||||
import com.sun.tools.javac.jvm.Target;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Errors;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Warnings;
|
||||
@ -133,11 +134,23 @@ public class Preview {
|
||||
return true;
|
||||
}
|
||||
|
||||
return participatesInPreview(syms, s.packge().modle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if module {@code m} is deemed to participate in the preview, and
|
||||
* therefore no warnings or errors will be produced.
|
||||
*
|
||||
* @param syms the symbol table
|
||||
* @param m the module to check
|
||||
* @return true if {@code m} is participating in the preview of {@code previewSymbol}
|
||||
*/
|
||||
public boolean participatesInPreview(Symtab syms, ModuleSymbol m) {
|
||||
// If java.base's jdk.internal.javac package is exported to s's module then
|
||||
// s participates in the preview API
|
||||
return syms.java_base.exports.stream()
|
||||
.filter(ed -> ed.packge.fullname == names.jdk_internal_javac)
|
||||
.anyMatch(ed -> ed.modules.contains(s.packge().modle));
|
||||
.anyMatch(ed -> ed.modules.contains(m));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -211,6 +224,7 @@ public class Preview {
|
||||
case FLEXIBLE_CONSTRUCTORS -> true;
|
||||
case PRIMITIVE_PATTERNS -> true;
|
||||
case MODULE_IMPORTS -> true;
|
||||
case JAVA_BASE_TRANSITIVE -> true;
|
||||
//Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
|
||||
//When real preview features will be added, this method can be implemented to return 'true'
|
||||
//for those selected features, and 'false' for all the others.
|
||||
|
@ -262,6 +262,7 @@ public enum Source {
|
||||
PRIMITIVE_PATTERNS(JDK23, Fragments.FeaturePrimitivePatterns, DiagKind.PLURAL),
|
||||
FLEXIBLE_CONSTRUCTORS(JDK22, Fragments.FeatureFlexibleConstructors, DiagKind.NORMAL),
|
||||
MODULE_IMPORTS(JDK23, Fragments.FeatureModuleImports, DiagKind.PLURAL),
|
||||
JAVA_BASE_TRANSITIVE(JDK24, Fragments.FeatureJavaBaseTransitive, DiagKind.PLURAL),
|
||||
PRIVATE_MEMBERS_IN_PERMITS_CLAUSE(JDK19),
|
||||
ERASE_POLY_SIG_RETURN_TYPE(JDK24),
|
||||
;
|
||||
|
@ -223,6 +223,7 @@ public class Enter extends JCTree.Visitor {
|
||||
tree.toplevelScope = WriteableScope.create(tree.packge);
|
||||
tree.namedImportScope = new NamedImportScope(tree.packge);
|
||||
tree.starImportScope = new StarImportScope(tree.packge);
|
||||
tree.moduleImportScope = new StarImportScope(tree.packge);
|
||||
localEnv.info.scope = tree.toplevelScope;
|
||||
localEnv.info.lint = lint;
|
||||
return localEnv;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -64,8 +64,11 @@ import com.sun.tools.javac.code.Directive.RequiresFlag;
|
||||
import com.sun.tools.javac.code.Directive.UsesDirective;
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import com.sun.tools.javac.code.Flags.Flag;
|
||||
import com.sun.tools.javac.code.Kinds;
|
||||
import com.sun.tools.javac.code.Lint;
|
||||
import com.sun.tools.javac.code.Lint.LintCategory;
|
||||
import com.sun.tools.javac.code.ModuleFinder;
|
||||
import com.sun.tools.javac.code.Preview;
|
||||
import com.sun.tools.javac.code.Source;
|
||||
import com.sun.tools.javac.code.Source.Feature;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
@ -74,6 +77,7 @@ import com.sun.tools.javac.code.Symbol.Completer;
|
||||
import com.sun.tools.javac.code.Symbol.CompletionFailure;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.ModuleFlags;
|
||||
import com.sun.tools.javac.code.Symbol.ModuleResolutionFlags;
|
||||
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.PackageSymbol;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
@ -99,6 +103,7 @@ import com.sun.tools.javac.tree.JCTree.Tag;
|
||||
import com.sun.tools.javac.tree.TreeInfo;
|
||||
import com.sun.tools.javac.util.Assert;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.ListBuffer;
|
||||
@ -112,14 +117,9 @@ import static com.sun.tools.javac.code.Flags.ENUM;
|
||||
import static com.sun.tools.javac.code.Flags.PUBLIC;
|
||||
import static com.sun.tools.javac.code.Flags.UNATTRIBUTED;
|
||||
|
||||
import com.sun.tools.javac.code.Kinds;
|
||||
|
||||
import static com.sun.tools.javac.code.Kinds.Kind.ERR;
|
||||
import static com.sun.tools.javac.code.Kinds.Kind.MDL;
|
||||
import static com.sun.tools.javac.code.Kinds.Kind.MTH;
|
||||
import com.sun.tools.javac.code.Lint;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol.ModuleResolutionFlags;
|
||||
|
||||
import static com.sun.tools.javac.code.TypeTag.CLASS;
|
||||
|
||||
@ -141,6 +141,7 @@ public class Modules extends JCTree.Visitor {
|
||||
private final Symtab syms;
|
||||
private final Attr attr;
|
||||
private final Check chk;
|
||||
private final Preview preview;
|
||||
private final DeferredLintHandler deferredLintHandler;
|
||||
private final TypeEnvs typeEnvs;
|
||||
private final Types types;
|
||||
@ -150,6 +151,7 @@ public class Modules extends JCTree.Visitor {
|
||||
private final Target target;
|
||||
private final boolean allowModules;
|
||||
private final boolean allowAccessIntoSystem;
|
||||
private final boolean allowRequiresTransitiveJavaBase;
|
||||
|
||||
public final boolean multiModuleMode;
|
||||
|
||||
@ -192,6 +194,7 @@ public class Modules extends JCTree.Visitor {
|
||||
syms = Symtab.instance(context);
|
||||
attr = Attr.instance(context);
|
||||
chk = Check.instance(context);
|
||||
preview = Preview.instance(context);
|
||||
deferredLintHandler = DeferredLintHandler.instance(context);
|
||||
typeEnvs = TypeEnvs.instance(context);
|
||||
moduleFinder = ModuleFinder.instance(context);
|
||||
@ -203,6 +206,12 @@ public class Modules extends JCTree.Visitor {
|
||||
Options options = Options.instance(context);
|
||||
|
||||
allowAccessIntoSystem = options.isUnset(Option.RELEASE);
|
||||
|
||||
Preview preview = Preview.instance(context);
|
||||
|
||||
allowRequiresTransitiveJavaBase =
|
||||
Feature.JAVA_BASE_TRANSITIVE.allowedInSource(source) &&
|
||||
(!preview.isPreview(Feature.JAVA_BASE_TRANSITIVE) || preview.isEnabled());
|
||||
lintOptions = options.isUnset(Option.XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option);
|
||||
|
||||
multiModuleMode = fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH);
|
||||
@ -249,7 +258,12 @@ public class Modules extends JCTree.Visitor {
|
||||
|
||||
public boolean enter(List<JCCompilationUnit> trees, ClassSymbol c) {
|
||||
Assert.check(rootModules != null || inInitModules || !allowModules);
|
||||
return enter(trees, modules -> {}, c);
|
||||
return enter(trees, modules -> {
|
||||
//make sure java.base is completed in all cases before continuing.
|
||||
//the next steps may query if the current module participates in preview,
|
||||
//and that requires a completed java.base:
|
||||
syms.java_base.complete();
|
||||
}, c);
|
||||
}
|
||||
|
||||
private boolean enter(List<JCCompilationUnit> trees, Consumer<Set<ModuleSymbol>> init, ClassSymbol c) {
|
||||
@ -807,11 +821,16 @@ public class Modules extends JCTree.Visitor {
|
||||
allRequires.add(msym);
|
||||
Set<RequiresFlag> flags = EnumSet.noneOf(RequiresFlag.class);
|
||||
if (tree.isTransitive) {
|
||||
if (msym == syms.java_base && source.compareTo(Source.JDK10) >= 0) {
|
||||
log.error(tree.pos(), Errors.ModifierNotAllowedHere(names.transitive));
|
||||
} else {
|
||||
flags.add(RequiresFlag.TRANSITIVE);
|
||||
if (msym == syms.java_base &&
|
||||
!allowRequiresTransitiveJavaBase &&
|
||||
!preview.participatesInPreview(syms, sym)) {
|
||||
if (source.compareTo(Source.JDK10) >= 0) {
|
||||
log.error(DiagnosticFlag.SOURCE_LEVEL,
|
||||
tree.pos(),
|
||||
Feature.JAVA_BASE_TRANSITIVE.error(source.name));
|
||||
}
|
||||
}
|
||||
flags.add(RequiresFlag.TRANSITIVE);
|
||||
}
|
||||
if (tree.isStaticPhase) {
|
||||
if (msym == syms.java_base && source.compareTo(Source.JDK10) >= 0) {
|
||||
|
@ -2149,23 +2149,32 @@ public class Resolve {
|
||||
return null;
|
||||
};
|
||||
|
||||
private final RecoveryLoadClass starImportScopeRecovery = (env, name) -> {
|
||||
Scope importScope = env.toplevel.starImportScope;
|
||||
Symbol existing = importScope.findFirst(Convert.shortName(name),
|
||||
sym -> sym.kind == TYP && sym.flatName() == name);
|
||||
private final RecoveryLoadClass starImportScopeRecovery =
|
||||
onDemandImportScopeRecovery(false);
|
||||
|
||||
if (existing != null) {
|
||||
try {
|
||||
existing = finder.loadClass(existing.packge().modle, name);
|
||||
private final RecoveryLoadClass moduleImportScopeRecovery =
|
||||
onDemandImportScopeRecovery(true);
|
||||
|
||||
return new InvisibleSymbolError(env, true, existing);
|
||||
} catch (CompletionFailure cf) {
|
||||
//ignore
|
||||
private RecoveryLoadClass onDemandImportScopeRecovery(boolean moduleImportScope) {
|
||||
return (env, name) -> {
|
||||
Scope importScope = moduleImportScope ? env.toplevel.moduleImportScope
|
||||
: env.toplevel.starImportScope;
|
||||
Symbol existing = importScope.findFirst(Convert.shortName(name),
|
||||
sym -> sym.kind == TYP && sym.flatName() == name);
|
||||
|
||||
if (existing != null) {
|
||||
try {
|
||||
existing = finder.loadClass(existing.packge().modle, name);
|
||||
|
||||
return new InvisibleSymbolError(env, true, existing);
|
||||
} catch (CompletionFailure cf) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
Symbol lookupPackage(Env<AttrContext> env, Name name) {
|
||||
PackageSymbol pack = syms.lookupPackage(env.toplevel.modle, name);
|
||||
@ -2433,6 +2442,11 @@ public class Resolve {
|
||||
sym = findGlobalType(env, env.toplevel.starImportScope, name, starImportScopeRecovery);
|
||||
if (sym.exists()) return sym;
|
||||
else bestSoFar = bestOf(bestSoFar, sym);
|
||||
|
||||
sym = findGlobalType(env, env.toplevel.moduleImportScope, name, moduleImportScopeRecovery);
|
||||
if (sym.exists()) return sym;
|
||||
|
||||
else bestSoFar = bestOf(bestSoFar, sym);
|
||||
}
|
||||
|
||||
return bestSoFar;
|
||||
|
@ -220,6 +220,7 @@ public class TypeEnter implements Completer {
|
||||
chk.checkImportedPackagesObservable(toplevel);
|
||||
toplevel.namedImportScope.finalizeScope();
|
||||
toplevel.starImportScope.finalizeScope();
|
||||
toplevel.moduleImportScope.finalizeScope();
|
||||
} catch (CompletionFailure cf) {
|
||||
chk.completionError(toplevel.pos(), cf);
|
||||
} finally {
|
||||
@ -331,7 +332,7 @@ public class TypeEnter implements Completer {
|
||||
throw new Abort();
|
||||
}
|
||||
importAll(make.at(tree.pos()).Import(make.Select(make.QualIdent(javaLang.owner), javaLang), false),
|
||||
javaLang, env);
|
||||
javaLang, env, false);
|
||||
|
||||
List<JCTree> defs = tree.getTypeDecls();
|
||||
boolean isImplicitClass = !defs.isEmpty() &&
|
||||
@ -341,7 +342,7 @@ public class TypeEnter implements Completer {
|
||||
doModuleImport(make.ModuleImport(make.QualIdent(syms.java_base)));
|
||||
if (peekTypeExists(syms.ioType.tsym)) {
|
||||
doImport(make.Import(make.Select(make.QualIdent(syms.ioType.tsym),
|
||||
names.asterisk), true));
|
||||
names.asterisk), true), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -413,7 +414,7 @@ public class TypeEnter implements Completer {
|
||||
if (imp instanceof JCModuleImport mimp) {
|
||||
doModuleImport(mimp);
|
||||
} else {
|
||||
doImport((JCImport) imp);
|
||||
doImport((JCImport) imp, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -438,7 +439,7 @@ public class TypeEnter implements Completer {
|
||||
annotate.annotateLater(tree.annotations, env, env.toplevel.packge, tree.pos());
|
||||
}
|
||||
|
||||
private void doImport(JCImport tree) {
|
||||
private void doImport(JCImport tree, boolean fromModuleImport) {
|
||||
JCFieldAccess imp = tree.qualid;
|
||||
Name name = TreeInfo.name(imp);
|
||||
|
||||
@ -450,16 +451,20 @@ public class TypeEnter implements Completer {
|
||||
if (name == names.asterisk) {
|
||||
// Import on demand.
|
||||
chk.checkCanonical(imp.selected);
|
||||
if (tree.staticImport)
|
||||
if (tree.staticImport) {
|
||||
Assert.check(!fromModuleImport);
|
||||
importStaticAll(tree, p, env);
|
||||
else
|
||||
importAll(tree, p, env);
|
||||
} else {
|
||||
importAll(tree, p, env, fromModuleImport);
|
||||
}
|
||||
} else {
|
||||
// Named type import.
|
||||
if (tree.staticImport) {
|
||||
Assert.check(!fromModuleImport);
|
||||
importNamedStatic(tree, p, name, localEnv);
|
||||
chk.checkCanonical(imp.selected);
|
||||
} else {
|
||||
Assert.check(!fromModuleImport);
|
||||
Type importedType = attribImportType(imp, localEnv);
|
||||
Type originalType = importedType.getOriginalType();
|
||||
TypeSymbol c = originalType.hasTag(CLASS) ? originalType.tsym : importedType.tsym;
|
||||
@ -506,7 +511,7 @@ public class TypeEnter implements Completer {
|
||||
JCImport nestedImport = make.at(tree.pos)
|
||||
.Import(make.Select(make.QualIdent(pkg), names.asterisk), false);
|
||||
|
||||
doImport(nestedImport);
|
||||
doImport(nestedImport, true);
|
||||
}
|
||||
|
||||
for (RequiresDirective requires : currentModule.requires) {
|
||||
@ -542,8 +547,13 @@ public class TypeEnter implements Completer {
|
||||
*/
|
||||
private void importAll(JCImport imp,
|
||||
final TypeSymbol tsym,
|
||||
Env<AttrContext> env) {
|
||||
env.toplevel.starImportScope.importAll(types, tsym.members(), typeImportFilter, imp, cfHandler);
|
||||
Env<AttrContext> env,
|
||||
boolean fromModuleImport) {
|
||||
StarImportScope targetScope =
|
||||
fromModuleImport ? env.toplevel.moduleImportScope
|
||||
: env.toplevel.starImportScope;
|
||||
|
||||
targetScope.importAll(types, tsym.members(), typeImportFilter, imp, cfHandler);
|
||||
}
|
||||
|
||||
/** Import all static members of a class or package on demand.
|
||||
|
@ -199,6 +199,9 @@ public class ClassReader {
|
||||
/** The minor version number of the class file being read. */
|
||||
int minorVersion;
|
||||
|
||||
/** true if the class file being read is a preview class file. */
|
||||
boolean previewClassFile;
|
||||
|
||||
/** UTF-8 validation level */
|
||||
Convert.Validation utf8validation;
|
||||
|
||||
@ -1200,7 +1203,9 @@ public class ClassReader {
|
||||
ModuleSymbol rsym = poolReader.getModule(nextChar());
|
||||
Set<RequiresFlag> flags = readRequiresFlags(nextChar());
|
||||
if (rsym == syms.java_base && majorVersion >= V54.major) {
|
||||
if (flags.contains(RequiresFlag.TRANSITIVE)) {
|
||||
if (flags.contains(RequiresFlag.TRANSITIVE) &&
|
||||
(majorVersion != Version.MAX().major || !previewClassFile) &&
|
||||
!preview.participatesInPreview(syms, msym)) {
|
||||
throw badClassFile("bad.requires.flag", RequiresFlag.TRANSITIVE);
|
||||
}
|
||||
if (flags.contains(RequiresFlag.STATIC_PHASE)) {
|
||||
@ -3185,7 +3190,7 @@ public class ClassReader {
|
||||
majorVersion = nextChar();
|
||||
int maxMajor = Version.MAX().major;
|
||||
int maxMinor = Version.MAX().minor;
|
||||
boolean previewClassFile =
|
||||
previewClassFile =
|
||||
minorVersion == ClassFile.PREVIEW_MINOR_VERSION;
|
||||
if (majorVersion > maxMajor ||
|
||||
majorVersion * 1000 + minorVersion <
|
||||
|
@ -921,10 +921,6 @@ compiler.misc.unexpected.ret.val=\
|
||||
compiler.err.mod.not.allowed.here=\
|
||||
modifier {0} not allowed here
|
||||
|
||||
# 0: name
|
||||
compiler.err.modifier.not.allowed.here=\
|
||||
modifier {0} not allowed here
|
||||
|
||||
compiler.err.intf.not.allowed.here=\
|
||||
interface not allowed here
|
||||
|
||||
@ -3252,6 +3248,9 @@ compiler.misc.feature.flexible.constructors=\
|
||||
compiler.misc.feature.module.imports=\
|
||||
module imports
|
||||
|
||||
compiler.misc.feature.java.base.transitive=\
|
||||
transitive modifier for java.base
|
||||
|
||||
compiler.warn.underscore.as.identifier=\
|
||||
as of release 9, ''_'' is a keyword, and may not be used as an identifier
|
||||
|
||||
|
@ -538,6 +538,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public NamedImportScope namedImportScope;
|
||||
/** A scope for all import-on-demands. */
|
||||
public StarImportScope starImportScope;
|
||||
/** A scope for all single module imports. */
|
||||
public StarImportScope moduleImportScope;
|
||||
/** Line starting positions, defined only if option -g is set. */
|
||||
public Position.LineMap lineMap = null;
|
||||
/** A table that stores all documentation comments indexed by the tree
|
||||
|
@ -1138,26 +1138,17 @@ public class TreeMaker implements JCTree.Factory {
|
||||
sym.owner.kind == MTH || sym.owner.kind == VAR) {
|
||||
return true;
|
||||
} else if (sym.kind == TYP && toplevel != null) {
|
||||
Iterator<Symbol> it = toplevel.namedImportScope.getSymbolsByName(sym.name).iterator();
|
||||
if (it.hasNext()) {
|
||||
Symbol s = it.next();
|
||||
return
|
||||
s == sym &&
|
||||
!it.hasNext();
|
||||
}
|
||||
it = toplevel.packge.members().getSymbolsByName(sym.name).iterator();
|
||||
if (it.hasNext()) {
|
||||
Symbol s = it.next();
|
||||
return
|
||||
s == sym &&
|
||||
!it.hasNext();
|
||||
}
|
||||
it = toplevel.starImportScope.getSymbolsByName(sym.name).iterator();
|
||||
if (it.hasNext()) {
|
||||
Symbol s = it.next();
|
||||
return
|
||||
s == sym &&
|
||||
!it.hasNext();
|
||||
for (Scope scope : new Scope[] {toplevel.namedImportScope,
|
||||
toplevel.packge.members(),
|
||||
toplevel.starImportScope,
|
||||
toplevel.moduleImportScope}) {
|
||||
Iterator<Symbol> it = scope.getSymbolsByName(sym.name).iterator();
|
||||
if (it.hasNext()) {
|
||||
Symbol s = it.next();
|
||||
return
|
||||
s == sym &&
|
||||
!it.hasNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
return sym.kind == TYP && sym.isImplicit();
|
||||
|
@ -31,10 +31,13 @@
|
||||
* @summary Test parsing of module-info.class with different class file versions
|
||||
*/
|
||||
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.module.InvalidModuleDescriptorException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Requires.Modifier;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
|
||||
@ -46,6 +49,8 @@ import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class ClassFileVersionsTest {
|
||||
private static final int PREVIEW_MINOR_VERSION =
|
||||
ClassFile.PREVIEW_MINOR_VERSION;
|
||||
private static final int FEATURE;
|
||||
static {
|
||||
FEATURE = Runtime.version().feature();
|
||||
@ -56,26 +61,34 @@ public class ClassFileVersionsTest {
|
||||
@DataProvider(name = "supported")
|
||||
public Object[][] supported() {
|
||||
/*
|
||||
* There are four test cases for JDK 9 and then one test case
|
||||
* There are four test cases for JDK 9, one test case
|
||||
* for each subsequent JDK version from JDK 10 to the current
|
||||
* feature release for a total of (4 + (FEATURE - 9) ) =>
|
||||
* (feature - 5) rows.
|
||||
* feature release, and two tests for the current release with
|
||||
* a preview flag set, for a total of (4 + (FEATURE - 9) + 2)
|
||||
* rows.
|
||||
*/
|
||||
Object[][] result = new Object[(FEATURE - 5)][];
|
||||
List<Object[]> result = new ArrayList<>(4 + (FEATURE - 9) + 2);
|
||||
|
||||
// Class file version of JDK 9 is 53.0
|
||||
result[0] = new Object[]{ 53, 0, Set.of()};
|
||||
result[1] = new Object[]{ 53, 0, Set.of(STATIC) };
|
||||
result[2] = new Object[]{ 53, 0, Set.of(TRANSITIVE) };
|
||||
result[3] = new Object[]{ 53, 0, Set.of(STATIC, TRANSITIVE) };
|
||||
result.add(new Object[]{ 53, 0, Set.of()});
|
||||
result.add(new Object[]{ 53, 0, Set.of(STATIC) });
|
||||
result.add(new Object[]{ 53, 0, Set.of(TRANSITIVE) });
|
||||
result.add(new Object[]{ 53, 0, Set.of(STATIC, TRANSITIVE) });
|
||||
|
||||
// Major class file version of JDK N is 44 + n. Create rows
|
||||
// for JDK 10 through FEATURE.
|
||||
for (int i = 4; i < (FEATURE - 5) ; i++) {
|
||||
result[i] = new Object[]{i + 50, 0, Set.of()};
|
||||
for (int i = 10; i <= FEATURE; i++) {
|
||||
result.add(new Object[]{ 44 + i, 0, Set.of()});
|
||||
}
|
||||
|
||||
return result;
|
||||
result.add(new Object[]{ 44 + FEATURE,
|
||||
PREVIEW_MINOR_VERSION,
|
||||
Set.of()});
|
||||
result.add(new Object[]{ 44 + FEATURE,
|
||||
PREVIEW_MINOR_VERSION,
|
||||
Set.of(TRANSITIVE) });
|
||||
|
||||
return result.toArray(s -> new Object[s][]);
|
||||
}
|
||||
|
||||
// major, minor, modifiers for requires java.base
|
||||
@ -84,27 +97,34 @@ public class ClassFileVersionsTest {
|
||||
/*
|
||||
* There are three test cases for releases prior to JDK 9,
|
||||
* three test cases for each JDK version from JDK 10 to the
|
||||
* current feature release, plus one addition test case for
|
||||
* the next release for a total of (3 + (FEATURE - 9) * 3 + 1)
|
||||
* current feature release, two tests for the current release with
|
||||
* the preview flag set, plus one addition test case for
|
||||
* the next release for a total of (3 + (FEATURE - 9) * 3 + 2 + 1)
|
||||
* rows.
|
||||
*/
|
||||
int unsupportedCount = 3 + (FEATURE - 9)*3 + 1;
|
||||
Object[][] result = new Object[unsupportedCount][];
|
||||
List<Object[]> result = new ArrayList<>(3 + (FEATURE - 9) * 3 + 2 + 1);
|
||||
|
||||
result[0] = new Object[]{50, 0, Set.of()}; // JDK 6
|
||||
result[1] = new Object[]{51, 0, Set.of()}; // JDK 7
|
||||
result[2] = new Object[]{52, 0, Set.of()}; // JDK 8
|
||||
result.add(new Object[]{50, 0, Set.of()}); // JDK 6
|
||||
result.add(new Object[]{51, 0, Set.of()}); // JDK 7
|
||||
result.add(new Object[]{52, 0, Set.of()}); // JDK 8
|
||||
|
||||
for (int i = 10; i <= FEATURE ; i++) {
|
||||
int base = 3 + (i-10)*3;
|
||||
// Major class file version of JDK N is 44+n
|
||||
result[base] = new Object[]{i + 44, 0, Set.of(STATIC)};
|
||||
result[base + 1] = new Object[]{i + 44, 0, Set.of(TRANSITIVE)};
|
||||
result[base + 2] = new Object[]{i + 44, 0, Set.of(STATIC, TRANSITIVE)};
|
||||
result.add(new Object[]{i + 44, 0, Set.of(STATIC)});
|
||||
result.add(new Object[]{i + 44, 0, Set.of(TRANSITIVE)});
|
||||
result.add(new Object[]{i + 44, 0, Set.of(STATIC, TRANSITIVE)});
|
||||
}
|
||||
|
||||
result[unsupportedCount - 1] = new Object[]{FEATURE+1+44, 0, Set.of()};
|
||||
return result;
|
||||
result.add(new Object[]{FEATURE + 44,
|
||||
PREVIEW_MINOR_VERSION,
|
||||
Set.of(STATIC)});
|
||||
result.add(new Object[]{FEATURE + 44,
|
||||
PREVIEW_MINOR_VERSION,
|
||||
Set.of(STATIC, TRANSITIVE)});
|
||||
|
||||
result.add(new Object[]{FEATURE+1+44, 0, Set.of()});
|
||||
|
||||
return result.toArray(s -> new Object[s][]);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "supported")
|
||||
|
@ -61,6 +61,8 @@ import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
|
||||
import jdk.internal.access.JavaLangModuleAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.ClassFileVersion;
|
||||
import java.lang.classfile.ClassTransform;
|
||||
import java.lang.classfile.attribute.ModuleAttribute;
|
||||
import java.lang.constant.PackageDesc;
|
||||
import java.lang.constant.ModuleDesc;
|
||||
@ -1522,4 +1524,68 @@ public class ModuleDescriptorTest {
|
||||
assertTrue(s.contains("p1"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = InvalidModuleDescriptorException.class)
|
||||
public void testRequiresTransitiveJavaBaseNotPermitted1() throws Exception {
|
||||
ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo")
|
||||
.requires(Set.of(Modifier.TRANSITIVE), "java.base")
|
||||
.build();
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ModuleInfoWriter.write(descriptor, baos);
|
||||
ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
|
||||
|
||||
ModuleDescriptor.read(bb, () -> Set.of("p", "q"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = InvalidModuleDescriptorException.class)
|
||||
public void testRequiresTransitiveJavaBaseNotPermitted2() throws Exception {
|
||||
ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo")
|
||||
.requires(Set.of(Modifier.TRANSITIVE), "java.base")
|
||||
.build();
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ModuleInfoWriter.write(descriptor, baos);
|
||||
byte[] bytecode = baos.toByteArray();
|
||||
ByteBuffer bb = ByteBuffer.wrap(bytecode);
|
||||
setClassFileVersion(bb, ClassFile.JAVA_21_VERSION, -1);
|
||||
|
||||
ModuleDescriptor.read(bb, () -> Set.of("p", "q"));
|
||||
}
|
||||
|
||||
public void testRequiresTransitiveJavaBasePermitted() throws Exception {
|
||||
ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo")
|
||||
.requires(Set.of(Modifier.TRANSITIVE), "java.base")
|
||||
.build();
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ModuleInfoWriter.write(descriptor, baos);
|
||||
byte[] bytecode = baos.toByteArray();
|
||||
ByteBuffer bb = ByteBuffer.wrap(bytecode);
|
||||
setClassFileVersion(bb, -1, ClassFile.PREVIEW_MINOR_VERSION);
|
||||
|
||||
descriptor = ModuleDescriptor.read(bb, () -> Set.of("p", "q"));
|
||||
|
||||
assertEquals(descriptor.requires().size(), 1);
|
||||
Requires javaBase = descriptor.requires().iterator().next();
|
||||
assertEquals(javaBase.name(), "java.base");
|
||||
assertEquals(javaBase.modifiers(), Set.of(Modifier.TRANSITIVE));
|
||||
}
|
||||
|
||||
/**Change the classfile versions of the provided classfile to the provided
|
||||
* values.
|
||||
*
|
||||
* @param bytecode the classfile content to modify
|
||||
* @param major the major classfile version to set,
|
||||
* -1 if the existing version should be kept
|
||||
* @param minor the minor classfile version to set,
|
||||
* -1 if the existing version should be kept
|
||||
*/
|
||||
private void setClassFileVersion(ByteBuffer bb, int major, int minor) {
|
||||
if (minor != (-1)) {
|
||||
bb.putShort(4, (short) minor);
|
||||
}
|
||||
if (major != (-1)) {
|
||||
bb.putShort(6, (short) major);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,32 +26,32 @@
|
||||
|
||||
class Test {
|
||||
void m1(int m1_arg) {
|
||||
String x = "Test; 0; 0";
|
||||
String y = "Test; 0; 0";
|
||||
String z = "Test; 0; 0";
|
||||
String x = "Test; 0; 0; 0";
|
||||
String y = "Test; 0; 0; 0";
|
||||
String z = "Test; 0; 0; 0";
|
||||
Object o = new Object() {
|
||||
public boolean equals(Object other) {
|
||||
String p = "-; Test; 0; 0";
|
||||
String q = "-; Test; 0; 0";
|
||||
String r = "-; Test; 0; 0";
|
||||
String p = "-; Test; 0; 0; 0";
|
||||
String q = "-; Test; 0; 0; 0";
|
||||
String r = "-; Test; 0; 0; 0";
|
||||
return (this == other);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
String s = "Test; 0; 0";
|
||||
String s = "Test; 0; 0; 0";
|
||||
|
||||
boolean b = new Object() {
|
||||
public boolean equals(Object other) {
|
||||
String p = "-; Test; 0; 0";
|
||||
String q = "-; Test; 0; 0";
|
||||
String r = "-; Test; 0; 0";
|
||||
String p = "-; Test; 0; 0; 0";
|
||||
String q = "-; Test; 0; 0; 0";
|
||||
String r = "-; Test; 0; 0; 0";
|
||||
return (this == other);
|
||||
}
|
||||
|
||||
}.equals(null);
|
||||
|
||||
class Test2 {
|
||||
String s = "Test.Test2; Test; 0; 0";
|
||||
String s = "Test.Test2; Test; 0; 0; 0";
|
||||
}
|
||||
}
|
||||
|
@ -23,29 +23,29 @@
|
||||
|
||||
import java.util.List;
|
||||
import java.io.*;
|
||||
//TOPLEVEL_SCOPE:List, Test2, Test; java.io.*, java.lang.*
|
||||
//TOPLEVEL_SCOPE:List, Test2, Test; java.io.*, java.lang.*;
|
||||
class Test {
|
||||
void m1(int m1_arg) {
|
||||
String x = "x, m1_arg, super, this; List, Test2, Test; java.io.*, java.lang.*";
|
||||
String y = "y, x, m1_arg, super, this; List, Test2, Test; java.io.*, java.lang.*";
|
||||
String z = "z, y, x, m1_arg, super, this; List, Test2, Test; java.io.*, java.lang.*";
|
||||
String x = "x, m1_arg, super, this; List, Test2, Test; java.io.*, java.lang.*;";
|
||||
String y = "y, x, m1_arg, super, this; List, Test2, Test; java.io.*, java.lang.*;";
|
||||
String z = "z, y, x, m1_arg, super, this; List, Test2, Test; java.io.*, java.lang.*;";
|
||||
Object o = new Object() {
|
||||
public boolean equals(Object other) {
|
||||
String p = "p, other, super, this; -, o, z, y, x, m1_arg, super, this; List, Test2, Test; java.io.*, java.lang.*";
|
||||
String q = "q, p, other, super, this; -, o, z, y, x, m1_arg, super, this; List, Test2, Test; java.io.*, java.lang.*";
|
||||
String r = "r, q, p, other, super, this; -, o, z, y, x, m1_arg, super, this; List, Test2, Test; java.io.*, java.lang.*";
|
||||
String p = "p, other, super, this; -, o, z, y, x, m1_arg, super, this; List, Test2, Test; java.io.*, java.lang.*;";
|
||||
String q = "q, p, other, super, this; -, o, z, y, x, m1_arg, super, this; List, Test2, Test; java.io.*, java.lang.*;";
|
||||
String r = "r, q, p, other, super, this; -, o, z, y, x, m1_arg, super, this; List, Test2, Test; java.io.*, java.lang.*;";
|
||||
return (this == other);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
String s = "super, this; List, Test2, Test; java.io.*, java.lang.*";
|
||||
String s = "super, this; List, Test2, Test; java.io.*, java.lang.*;";
|
||||
|
||||
boolean b = new Object() {
|
||||
public boolean equals(Object other) {
|
||||
String p = "p, other, super, this; -, super, this; List, Test2, Test; java.io.*, java.lang.*";
|
||||
String q = "q, p, other, super, this; -, super, this; List, Test2, Test; java.io.*, java.lang.*";
|
||||
String r = "r, q, p, other, super, this; -, super, this; List, Test2, Test; java.io.*, java.lang.*";
|
||||
String p = "p, other, super, this; -, super, this; List, Test2, Test; java.io.*, java.lang.*;";
|
||||
String q = "q, p, other, super, this; -, super, this; List, Test2, Test; java.io.*, java.lang.*;";
|
||||
String r = "r, q, p, other, super, this; -, super, this; List, Test2, Test; java.io.*, java.lang.*;";
|
||||
return (this == other);
|
||||
}
|
||||
|
||||
|
@ -25,32 +25,32 @@
|
||||
|
||||
class Test {
|
||||
void m1(int m1_arg) {
|
||||
String x = "m1; 0; 0";
|
||||
String y = "m1; 0; 0";
|
||||
String z = "m1; 0; 0";
|
||||
String x = "m1; 0; 0; 0";
|
||||
String y = "m1; 0; 0; 0";
|
||||
String z = "m1; 0; 0; 0";
|
||||
Object o = new Object() {
|
||||
public boolean equals(Object other) {
|
||||
String p = "equals; m1; 0; 0";
|
||||
String q = "equals; m1; 0; 0";
|
||||
String r = "equals; m1; 0; 0";
|
||||
String p = "equals; m1; 0; 0; 0";
|
||||
String q = "equals; m1; 0; 0; 0";
|
||||
String r = "equals; m1; 0; 0; 0";
|
||||
return (this == other);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
String s = "0; 0; 0";
|
||||
String s = "0; 0; 0; 0";
|
||||
|
||||
boolean b = new Object() {
|
||||
public boolean equals(Object other) {
|
||||
String p = "equals; 0; 0; 0";
|
||||
String q = "equals; 0; 0; 0";
|
||||
String r = "equals; 0; 0; 0";
|
||||
String p = "equals; 0; 0; 0; 0";
|
||||
String q = "equals; 0; 0; 0; 0";
|
||||
String r = "equals; 0; 0; 0; 0";
|
||||
return (this == other);
|
||||
}
|
||||
|
||||
}.equals(null);
|
||||
|
||||
class Test2 {
|
||||
String s = "0; 0; 0; 0";
|
||||
String s = "0; 0; 0; 0; 0";
|
||||
}
|
||||
}
|
||||
|
@ -218,28 +218,14 @@ public class ImportModule extends TestRunner {
|
||||
List<String> actualErrors;
|
||||
List<String> expectedErrors;
|
||||
|
||||
actualErrors =
|
||||
new JavacTask(tb)
|
||||
.options("--enable-preview", "--release", SOURCE_VERSION,
|
||||
"-XDrawDiagnostics")
|
||||
.outdir(classes)
|
||||
.files(tb.findJavaFiles(src))
|
||||
.run(Task.Expect.FAIL)
|
||||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.DIRECT);
|
||||
|
||||
expectedErrors = List.of(
|
||||
"Test.java:5:5: compiler.err.ref.ambiguous: Logger, kindname.interface, java.lang.System.Logger, java.lang.System, kindname.class, java.util.logging.Logger, java.util.logging",
|
||||
"- compiler.note.preview.filename: Test.java, DEFAULT",
|
||||
"- compiler.note.preview.recompile",
|
||||
"1 error"
|
||||
);
|
||||
|
||||
if (!Objects.equals(expectedErrors, actualErrors)) {
|
||||
throw new AssertionError("Incorrect Output, expected: " + expectedErrors +
|
||||
", actual: " + out);
|
||||
|
||||
}
|
||||
new JavacTask(tb)
|
||||
.options("--enable-preview", "--release", SOURCE_VERSION,
|
||||
"-XDrawDiagnostics")
|
||||
.outdir(classes)
|
||||
.files(tb.findJavaFiles(src))
|
||||
.run(Task.Expect.SUCCESS)
|
||||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.DIRECT);
|
||||
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
@ -793,7 +779,7 @@ public class ImportModule extends TestRunner {
|
||||
|
||||
if (!Objects.equals(expectedErrors, actualErrors)) {
|
||||
throw new AssertionError("Incorrect Output, expected: " + expectedErrors +
|
||||
", actual: " + out);
|
||||
", actual: " + actualErrors);
|
||||
|
||||
}
|
||||
}
|
||||
@ -843,4 +829,94 @@ public class ImportModule extends TestRunner {
|
||||
}
|
||||
}
|
||||
|
||||
public void testPackageImportDisambiguates(Path base) throws Exception {
|
||||
Path current = base.resolve(".");
|
||||
Path src = current.resolve("src");
|
||||
Path classes = current.resolve("classes");
|
||||
Path ma = src.resolve("ma");
|
||||
tb.writeJavaFiles(ma,
|
||||
"""
|
||||
module ma {
|
||||
exports ma.p1;
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package ma.p1;
|
||||
public class A {}
|
||||
""");
|
||||
Path mb = src.resolve("mb");
|
||||
tb.writeJavaFiles(mb,
|
||||
"""
|
||||
module mb {
|
||||
exports mb.p1;
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package mb.p1;
|
||||
public class A {}
|
||||
""");
|
||||
Path test = src.resolve("test");
|
||||
tb.writeJavaFiles(test,
|
||||
"""
|
||||
module test {
|
||||
requires ma;
|
||||
requires mb;
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package test;
|
||||
import module ma;
|
||||
import module mb;
|
||||
public class Test {
|
||||
A a;
|
||||
}
|
||||
""");
|
||||
|
||||
Files.createDirectories(classes);
|
||||
|
||||
List<String> actualErrors = new JavacTask(tb)
|
||||
.options("-XDrawDiagnostics",
|
||||
"--enable-preview", "--release", SOURCE_VERSION,
|
||||
"--module-source-path", src.toString())
|
||||
.outdir(classes)
|
||||
.files(tb.findJavaFiles(src))
|
||||
.run(Task.Expect.FAIL)
|
||||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.DIRECT);
|
||||
|
||||
List<String> expectedErrors = List.of(
|
||||
"Test.java:5:5: compiler.err.ref.ambiguous: A, kindname.class, mb.p1.A, mb.p1, kindname.class, ma.p1.A, ma.p1",
|
||||
"- compiler.note.preview.filename: Test.java, DEFAULT",
|
||||
"- compiler.note.preview.recompile",
|
||||
"1 error"
|
||||
);
|
||||
|
||||
if (!Objects.equals(expectedErrors, actualErrors)) {
|
||||
throw new AssertionError("Incorrect Output, expected: " + expectedErrors +
|
||||
", actual: " + actualErrors);
|
||||
|
||||
}
|
||||
|
||||
tb.writeJavaFiles(test,
|
||||
"""
|
||||
package test;
|
||||
import module ma;
|
||||
import module mb;
|
||||
import mb.p1.*;
|
||||
public class Test {
|
||||
A a;
|
||||
}
|
||||
""");
|
||||
|
||||
Files.createDirectories(classes);
|
||||
|
||||
new JavacTask(tb)
|
||||
.options("-XDrawDiagnostics",
|
||||
"--enable-preview", "--release", SOURCE_VERSION,
|
||||
"--module-source-path", src.toString())
|
||||
.outdir(classes)
|
||||
.files(tb.findJavaFiles(src))
|
||||
.run(Task.Expect.SUCCESS)
|
||||
.writeAll();
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,9 @@ import com.sun.tools.javac.tree.JCTree.JCCase;
|
||||
import com.sun.tools.javac.tree.JCTree.JCStatement;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.Context.Factory;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import static javax.tools.JavaFileObject.Kind.SOURCE;
|
||||
|
||||
@ -89,6 +92,7 @@ public class TestGetScopeResult {
|
||||
new TestGetScopeResult().testLocalRecordAnnotation();
|
||||
new TestGetScopeResult().testRuleCases();
|
||||
new TestGetScopeResult().testNestedSwitchExpression();
|
||||
new TestGetScopeResult().testModuleImportScope();
|
||||
}
|
||||
|
||||
public void run() throws IOException {
|
||||
@ -823,6 +827,64 @@ public class TestGetScopeResult {
|
||||
}
|
||||
}
|
||||
|
||||
void testModuleImportScope() throws IOException {
|
||||
JavacTool c = JavacTool.create();
|
||||
try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) {
|
||||
String code = """
|
||||
import module java.compiler;
|
||||
import java.util.*;
|
||||
import java.lang.System;
|
||||
class Test {
|
||||
}
|
||||
""";
|
||||
Context ctx = new Context();
|
||||
TestAnalyzer.preRegister(ctx);
|
||||
JavaFileObject input =
|
||||
SimpleJavaFileObject.forSource(URI.create("myfo:///Test.java"), code);
|
||||
JavacTask t = (JavacTask) c.getTask(null, fm, null, null, null,
|
||||
List.of(input),
|
||||
ctx);
|
||||
CompilationUnitTree cut = t.parse().iterator().next();
|
||||
t.analyze();
|
||||
|
||||
TreePath topLevelClass = new TreePath(new TreePath(cut), cut.getTypeDecls().get(0));
|
||||
Scope scope = Trees.instance(t).getScope(topLevelClass);
|
||||
|
||||
if (scope.getEnclosingClass() == null) {
|
||||
throw new AssertionError("Expected an enclosing class.");
|
||||
}
|
||||
|
||||
scope = scope.getEnclosingScope();
|
||||
|
||||
if (scope.getEnclosingClass() != null) {
|
||||
throw new AssertionError("Did not expect an enclosing class.");
|
||||
}
|
||||
|
||||
asssertScopeContainsTypeWithFQN(scope, "java.lang.System");
|
||||
asssertScopeContainsTypeWithFQN(scope, "Test");
|
||||
|
||||
scope = scope.getEnclosingScope();
|
||||
|
||||
if (scope.getEnclosingClass() != null) {
|
||||
throw new AssertionError("Did not expect an enclosing class.");
|
||||
}
|
||||
|
||||
asssertScopeContainsTypeWithFQN(scope, "java.util.List");
|
||||
|
||||
scope = scope.getEnclosingScope();
|
||||
|
||||
if (scope.getEnclosingClass() != null) {
|
||||
throw new AssertionError("Did not expect an enclosing class.");
|
||||
}
|
||||
|
||||
asssertScopeContainsTypeWithFQN(scope, "javax.tools.ToolProvider");
|
||||
|
||||
if (scope.getEnclosingScope() != null) {
|
||||
throw new AssertionError("Did not expect an enclosing scope.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> dumpScope(Scope scope) {
|
||||
List<String> content = new ArrayList<>();
|
||||
while (scope.getEnclosingClass() != null) {
|
||||
@ -833,4 +895,17 @@ public class TestGetScopeResult {
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
private void asssertScopeContainsTypeWithFQN(Scope scope, String fqn) {
|
||||
for (TypeElement type : ElementFilter.typesIn(scope.getLocalElements())) {
|
||||
if (type.getQualifiedName().contentEquals(fqn)) {
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionError("Expected to find: " + fqn +
|
||||
" in: " + scope.getLocalElements() +
|
||||
", but it is missing.");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,7 +21,8 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.err.modifier.not.allowed.here
|
||||
// key: compiler.err.feature.not.supported.in.source.plural
|
||||
// key: compiler.misc.feature.java.base.transitive
|
||||
|
||||
module m {
|
||||
requires transitive java.base;
|
||||
|
@ -432,6 +432,40 @@ public class ConvenientAccessErrorsTest extends ModuleTestBase {
|
||||
throw new Exception("expected output not found; actual: " + log);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInModuleImport(Path base) throws Exception {
|
||||
Path src = base.resolve("src");
|
||||
Path src_m1 = src.resolve("m1x");
|
||||
tb.writeJavaFiles(src_m1,
|
||||
"module m1x { }",
|
||||
"package api; public class Api { public String test() { return null; } }");
|
||||
Path src_m2 = src.resolve("m2x");
|
||||
tb.writeJavaFiles(src_m2,
|
||||
"module m2x { requires m1x; }",
|
||||
"package test; import module m1x; public class Test { Api api; { api.test().length(); } }");
|
||||
Path classes = base.resolve("classes");
|
||||
tb.createDirectories(classes);
|
||||
|
||||
List<String> log = new JavacTask(tb)
|
||||
.options("-XDrawDiagnostics",
|
||||
"--enable-preview", "--source", System.getProperty("java.specification.version"),
|
||||
"--module-source-path", src.toString())
|
||||
.outdir(classes)
|
||||
.files(findJavaFiles(src))
|
||||
.run(Task.Expect.FAIL)
|
||||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.DIRECT);
|
||||
|
||||
List<String> expected = Arrays.asList(
|
||||
"Test.java:1:54: compiler.err.cant.resolve.location: kindname.class, Api, , , (compiler.misc.location: kindname.class, test.Test, null)",
|
||||
"- compiler.note.preview.filename: Test.java, DEFAULT",
|
||||
"- compiler.note.preview.recompile",
|
||||
"1 error");
|
||||
|
||||
if (!expected.equals(log))
|
||||
throw new Exception("expected output not found; actual: " + log);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnusedImportOnDemand2(Path base) throws Exception {
|
||||
Path src = base.resolve("src");
|
||||
|
@ -73,6 +73,9 @@ import com.sun.tools.javac.api.JavacTaskImpl;
|
||||
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
import javax.lang.model.element.ModuleElement.DirectiveKind;
|
||||
|
||||
import toolbox.JarTask;
|
||||
import toolbox.JavacTask;
|
||||
@ -1153,4 +1156,90 @@ public class EdgeCases extends ModuleTestBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJavaSEHasRequiresTransitiveJavaBase(Path base) throws Exception {
|
||||
Path src = base.resolve("src");
|
||||
Path a = src.resolve("a");
|
||||
tb.writeJavaFiles(a,
|
||||
"module a { requires java.se; }",
|
||||
"""
|
||||
package test;
|
||||
import module java.se;
|
||||
public class Test {
|
||||
ArrayList<String> l;
|
||||
}
|
||||
""");
|
||||
Path classes = base.resolve("classes");
|
||||
tb.createDirectories(classes);
|
||||
|
||||
AtomicBoolean seenJavaSEDependency = new AtomicBoolean();
|
||||
|
||||
List<String> log;
|
||||
|
||||
log = new JavacTask(tb)
|
||||
.outdir(classes)
|
||||
.options("-XDrawDiagnostics", "-XDshould-stop.at=FLOW")
|
||||
.callback(verifyJavaSEDependency(true, seenJavaSEDependency))
|
||||
.files(findJavaFiles(src))
|
||||
.run(Task.Expect.FAIL)
|
||||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.DIRECT);
|
||||
|
||||
List<String> expected = List.of(
|
||||
"Test.java:2:8: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.module.imports)",
|
||||
"1 error");
|
||||
|
||||
if (!expected.equals(log))
|
||||
throw new Exception("expected output not found: " + log);
|
||||
|
||||
if (!seenJavaSEDependency.get()) {
|
||||
throw new AssertionError("Didn't find the java.se dependency!");
|
||||
}
|
||||
|
||||
seenJavaSEDependency.set(false);
|
||||
|
||||
new JavacTask(tb)
|
||||
.outdir(classes)
|
||||
.options("--enable-preview",
|
||||
"--source", System.getProperty("java.specification.version"))
|
||||
.callback(verifyJavaSEDependency(true, seenJavaSEDependency))
|
||||
.files(findJavaFiles(src))
|
||||
.run(Task.Expect.SUCCESS)
|
||||
.writeAll()
|
||||
.getOutputLines(Task.OutputKind.DIRECT);
|
||||
|
||||
if (!seenJavaSEDependency.get()) {
|
||||
throw new AssertionError("Didn't find the java.se dependency!");
|
||||
}
|
||||
}
|
||||
private Consumer<com.sun.source.util.JavacTask> verifyJavaSEDependency(
|
||||
boolean expectedTransitive,
|
||||
AtomicBoolean seenJavaSEDependency) {
|
||||
return t -> {
|
||||
t.addTaskListener(new TaskListener() {
|
||||
@Override
|
||||
public void finished(TaskEvent e) {
|
||||
if (e.getKind() == TaskEvent.Kind.ANALYZE) {
|
||||
ModuleElement javaBase =
|
||||
t.getElements().getModuleElement("java.base");
|
||||
ModuleElement javaSE =
|
||||
t.getElements().getModuleElement("java.se");
|
||||
RequiresDirective requiresJavaBase =
|
||||
javaSE.getDirectives()
|
||||
.stream()
|
||||
.filter(d -> d.getKind() == DirectiveKind.REQUIRES)
|
||||
.map(d -> (RequiresDirective) d)
|
||||
.filter(d -> d.getDependency() == javaBase)
|
||||
.findAny()
|
||||
.orElseThrow();
|
||||
if (requiresJavaBase.isTransitive() != expectedTransitive) {
|
||||
throw new AssertionError("Expected: " + expectedTransitive + ", " +
|
||||
"but got: " + requiresJavaBase.isTransitive());
|
||||
}
|
||||
seenJavaSEDependency.set(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8193125 8196623
|
||||
* @bug 8193125 8196623 8335989
|
||||
* @summary test modifiers with java.base
|
||||
* @library /tools/lib
|
||||
* @enablePreview
|
||||
@ -49,6 +49,7 @@ import java.lang.classfile.attribute.*;
|
||||
|
||||
import com.sun.tools.javac.jvm.Target;
|
||||
import com.sun.tools.javac.platform.JDKPlatformProvider;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import toolbox.JavacTask;
|
||||
import toolbox.Task;
|
||||
@ -56,6 +57,8 @@ import toolbox.ToolBox;
|
||||
|
||||
public class JavaBaseTest {
|
||||
|
||||
private static final String CURRENT_VERSION = System.getProperty("java.specification.version");
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
JavaBaseTest t = new JavaBaseTest();
|
||||
t.run();
|
||||
@ -75,13 +78,11 @@ public class JavaBaseTest {
|
||||
|
||||
void run() throws Exception {
|
||||
Set<String> targets = new LinkedHashSet<>();
|
||||
StreamSupport.stream(new JDKPlatformProvider().getSupportedPlatformNames()
|
||||
.spliterator(),
|
||||
false)
|
||||
.filter(p -> Integer.parseInt(p) >= 9)
|
||||
.forEach(targets::add);
|
||||
//run without --release:
|
||||
targets.add("9");
|
||||
targets.add("10");
|
||||
targets.add("21");
|
||||
targets.add("current");
|
||||
targets.add("current-preview");
|
||||
for (List<String> mods : modifiers) {
|
||||
for (String target : targets) {
|
||||
for (Mode mode : Mode.values()) {
|
||||
@ -119,15 +120,43 @@ public class JavaBaseTest {
|
||||
tb.writeJavaFiles(src,
|
||||
"module m { requires " + String.join(" ", mods) + " java.base; }");
|
||||
Path modules = Files.createDirectories(base.resolve("modules"));
|
||||
boolean expectOK = target.equals("9");
|
||||
boolean expectOK;
|
||||
|
||||
JavacTask jct = new JavacTask(tb)
|
||||
.outdir(modules);
|
||||
|
||||
if (target.equals("current"))
|
||||
jct.options("-XDrawDiagnostics");
|
||||
else
|
||||
jct.options("-XDrawDiagnostics", "--release", target);
|
||||
List<String> options = new ArrayList<>();
|
||||
|
||||
switch (target) {
|
||||
case "current":
|
||||
options.add("--release");
|
||||
options.add(CURRENT_VERSION);
|
||||
expectOK = false;
|
||||
break;
|
||||
case "current-preview":
|
||||
options.add("--enable-preview");
|
||||
options.add("--release");
|
||||
options.add(CURRENT_VERSION);
|
||||
expectOK = true;
|
||||
break;
|
||||
case "9":
|
||||
options.add("--release");
|
||||
options.add(target);
|
||||
expectOK = true;
|
||||
break;
|
||||
default:
|
||||
options.add("--release");
|
||||
options.add(target);
|
||||
expectOK = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mods.contains("static") && !"9".equals(target)) {
|
||||
expectOK = false;
|
||||
}
|
||||
|
||||
options.add("-XDrawDiagnostics");
|
||||
jct.options(options);
|
||||
|
||||
String log = jct.files(tb.findJavaFiles(src))
|
||||
.run(expectOK ? Task.Expect.SUCCESS : Task.Expect.FAIL)
|
||||
@ -138,9 +167,9 @@ public class JavaBaseTest {
|
||||
boolean foundErrorMessage = false;
|
||||
for (String mod : mods) {
|
||||
String key = mod.equals("static")
|
||||
? "compiler.err.mod.not.allowed.here"
|
||||
: "compiler.err.modifier.not.allowed.here";
|
||||
String message = "module-info.java:1:12: " + key + ": " + mod;
|
||||
? "compiler.err.mod.not.allowed.here: " + mod
|
||||
: "compiler.err.feature.not.supported.in.source.plural: (compiler.misc.feature.java.base.transitive)";
|
||||
String message = "module-info.java:1:12: " + key;
|
||||
if (log.contains(message)) {
|
||||
foundErrorMessage = true;
|
||||
}
|
||||
@ -152,18 +181,57 @@ public class JavaBaseTest {
|
||||
}
|
||||
|
||||
void testClass(Path base, List<String> mods, String target) throws Exception {
|
||||
createClass(base, mods, target);
|
||||
boolean expectOK;
|
||||
List<String> options = new ArrayList<>();
|
||||
|
||||
switch (target) {
|
||||
case "current":
|
||||
options.add("--release");
|
||||
options.add(CURRENT_VERSION);
|
||||
expectOK = false;
|
||||
break;
|
||||
case "current-preview":
|
||||
options.add("--enable-preview");
|
||||
options.add("--release");
|
||||
options.add(CURRENT_VERSION);
|
||||
expectOK = true;
|
||||
break;
|
||||
case "9":
|
||||
options.add("--release");
|
||||
options.add(target);
|
||||
expectOK = true;
|
||||
break;
|
||||
default:
|
||||
options.add("--release");
|
||||
options.add(target);
|
||||
expectOK = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mods.contains("static") && !"9".equals(target)) {
|
||||
expectOK = false;
|
||||
}
|
||||
|
||||
createClass(base, mods, options);
|
||||
|
||||
List<String> testOptions = new ArrayList<>();
|
||||
|
||||
testOptions.add("-XDrawDiagnostics");
|
||||
testOptions.add("--module-path"); testOptions.add(base.resolve("test-modules").toString());
|
||||
|
||||
if (options.contains("--enable-preview")) {
|
||||
testOptions.add("--enable-preview");
|
||||
testOptions.add("--source"); testOptions.add(CURRENT_VERSION);
|
||||
}
|
||||
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src,
|
||||
"module mx { requires m; }");
|
||||
Path modules = Files.createDirectories(base.resolve("modules"));
|
||||
|
||||
boolean expectOK = target.equals("9");
|
||||
String log = new JavacTask(tb)
|
||||
.outdir(modules)
|
||||
.options("-XDrawDiagnostics",
|
||||
"--module-path", base.resolve("test-modules").toString())
|
||||
.options(testOptions)
|
||||
.files(tb.findJavaFiles(src))
|
||||
.run(expectOK ? Task.Expect.SUCCESS : Task.Expect.FAIL)
|
||||
.writeAll()
|
||||
@ -188,7 +256,7 @@ public class JavaBaseTest {
|
||||
}
|
||||
}
|
||||
|
||||
void createClass(Path base, List<String> mods, String target) throws Exception {
|
||||
void createClass(Path base, List<String> mods, List<String> options) throws Exception {
|
||||
Path src1 = base.resolve("interim-src");
|
||||
tb.writeJavaFiles(src1,
|
||||
"module m { requires java.base; }");
|
||||
@ -197,9 +265,7 @@ public class JavaBaseTest {
|
||||
JavacTask jct = new JavacTask(tb)
|
||||
.outdir(modules1);
|
||||
|
||||
if (!target.equals("current")) {
|
||||
jct.options("--release", target);
|
||||
}
|
||||
jct.options(options);
|
||||
|
||||
jct.files(tb.findJavaFiles(src1))
|
||||
.run(Task.Expect.SUCCESS);
|
||||
@ -226,6 +292,8 @@ public class JavaBaseTest {
|
||||
requires.set(i, e2);
|
||||
}
|
||||
|
||||
boolean preview = options.contains("--enable-preview");
|
||||
|
||||
ModuleAttribute modAttr2 = ModuleAttribute.of(
|
||||
modAttr1.moduleName(),
|
||||
modAttr1.moduleFlagsMask(),
|
||||
@ -237,8 +305,14 @@ public class JavaBaseTest {
|
||||
modAttr1.provides());
|
||||
Path modInfo = base.resolve("test-modules").resolve("module-info.class");
|
||||
Files.createDirectories(modInfo.getParent());
|
||||
byte[] newBytes = ClassFile.of().transformClass(cm1, ClassTransform.dropping(ce -> ce instanceof ModuleAttribute).
|
||||
andThen(ClassTransform.endHandler(classBuilder -> classBuilder.with(modAttr2))));
|
||||
ClassTransform replace = (builder, element) -> {
|
||||
switch (element) {
|
||||
case ClassFileVersion cfv when preview -> builder.withVersion(cfv.majorVersion(), 0xFFFF);
|
||||
case ModuleAttribute _ -> builder.with(modAttr2);
|
||||
default -> builder.with(element);
|
||||
}
|
||||
};
|
||||
byte[] newBytes = ClassFile.of().transformClass(cm1, replace);
|
||||
try (OutputStream out = Files.newOutputStream(modInfo)) {
|
||||
out.write(newBytes);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user