diff options
author | Stephan Herrmann | 2019-06-07 14:58:30 +0000 |
---|---|---|
committer | Stephan Herrmann | 2019-07-02 14:25:31 +0000 |
commit | 1fbf13c28311e9090a4ae402b14adbc440f874ec (patch) | |
tree | 9a25525de352e1b137729d7186177b0a19878a8b | |
parent | 5d58390bf2fb018a53c69e075d1416a113301107 (diff) | |
download | eclipse.jdt.core-1fbf13c28311e9090a4ae402b14adbc440f874ec.tar.gz eclipse.jdt.core-1fbf13c28311e9090a4ae402b14adbc440f874ec.tar.xz eclipse.jdt.core-1fbf13c28311e9090a4ae402b14adbc440f874ec.zip |
Bug 547181 - [9][impl] Reconsider representation and lookup of packages
(SplitPackageBinding)
- early creation of plain PB into MB.declaredPackages:
- from CUS.buildTypeBindins() -> PVS.resolvePackageReference()
- includes early application of add-exports
- later add all (plain) packages with CUs associated to this module
- avoid passing elements of MD.declaredPackages to clients
- let MD.analyseReferencedPackages be responsible for error reporting
- unify severity determination after bug 521497
- sketch of package scanning for auto modules (may be incomplete)
- add a search for inaccessible package/type for better error reporting
- when limit-modules present distinguish inaccessible vs. unobservable
- improve package scan in ClasspathMultiDirectory
- refactoring to avoid some "instanceof SplitPackageBinding"
- apply add-reads early, too
- throw ISE if reentrance still happens in package lookup (TESTING)
- throw ISE if add-reads is applied when packages already exist
- remove MB.isPackageLookupActive and related code
Refactoring: introduce PlainPackageBinding for more precise typechecking
Change-Id: I5f96bc7a487adfff75737a66096598e1c638c4d9
41 files changed, 920 insertions, 402 deletions
diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/Factory.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/Factory.java index c865529a65..8ea41f0242 100644 --- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/Factory.java +++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/Factory.java @@ -52,7 +52,6 @@ import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.SplitPackageBinding; import org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; @@ -392,8 +391,8 @@ public class Factory { */ public PackageElement newPackageElement(PackageBinding binding) { - if (binding instanceof SplitPackageBinding && binding.enclosingModule != null) { - binding = ((SplitPackageBinding) binding).getIncarnation(binding.enclosingModule); + if (binding != null && binding.enclosingModule != null) { + binding = binding.getIncarnation(binding.enclosingModule); } if (binding == null) { return null; diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/ModuleElementImpl.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/ModuleElementImpl.java index 86183925d5..62e8caedee 100644 --- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/ModuleElementImpl.java +++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/model/ModuleElementImpl.java @@ -55,10 +55,7 @@ public class ModuleElementImpl extends ElementImpl implements ModuleElement { } private PackageBinding getModulesPackageBinding(PackageBinding binding) { - if (binding instanceof SplitPackageBinding) { - return ((SplitPackageBinding) binding).getIncarnation(this.binding); - } - return binding; + return binding.getIncarnation(this.binding); } @Override @@ -85,9 +82,8 @@ public class ModuleElementImpl extends ElementImpl implements ModuleElement { @Override public List<? extends Element> getEnclosedElements() { ModuleBinding module = this.binding; - PackageBinding[] packs = module.declaredPackages.valueTable; Set<PackageBinding> unique = new HashSet<>(); - for (PackageBinding p : packs) { + for (PackageBinding p : module.declaredPackages.values()) { if (p == null) continue; if (p instanceof SplitPackageBinding) { @@ -111,12 +107,10 @@ public class ModuleElementImpl extends ElementImpl implements ModuleElement { unique.add(def); } } else { - packs = this.binding.getExports(); - for (PackageBinding pBinding : packs) { + for (PackageBinding pBinding : this.binding.getExports()) { unique.add(getModulesPackageBinding(pBinding)); } - packs = this.binding.getOpens(); - for (PackageBinding pBinding : packs) { + for (PackageBinding pBinding : this.binding.getOpens()) { unique.add(getModulesPackageBinding(pBinding)); } } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InMemoryNameEnvironment9.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InMemoryNameEnvironment9.java index c329fba5f7..8464c36880 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InMemoryNameEnvironment9.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InMemoryNameEnvironment9.java @@ -71,8 +71,13 @@ public class InMemoryNameEnvironment9 extends InMemoryNameEnvironment implements } @Override - public char[][] getModulesDeclaringPackage(char[][] parentPackageName, char[] name, char[] moduleName) { - return collect(env -> env.getModulesDeclaringPackage(parentPackageName, name, moduleName), char[][]::new); + public char[][] getModulesDeclaringPackage(char[][] packageName, char[] moduleName) { + return collect(env -> env.getModulesDeclaringPackage(packageName, moduleName), char[][]::new); + } + + @Override + public char[][] listPackages(char[] moduleName) { + return collect(env -> env.listPackages(moduleName), char[][]::new); } @Override diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java index cddbcf6388..b69c75b599 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ModuleCompilationTests.java @@ -1086,8 +1086,8 @@ public class ModuleCompilationTests extends AbstractBatchCompilerTest { "----------\n" + "1. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/src/mod.two/q/Y.java (at line 3)\n" + " java.sql.Connection con = p.X.getConnection();\n" + - " ^\n" + - "p cannot be resolved\n" + + " ^^^\n" + + "The type p.X is not accessible\n" + "----------\n" + "1 problem (1 error)\n", false, @@ -5393,4 +5393,54 @@ public void testBug521362_emptyFile() { runConformModuleTest(files, buffer, "Could not invoke method java.lang.module.ModuleDescriptor.Version.parse(), cannot validate module version.\n", "", false); } } + public void testPackageTypeConflict2() { + File outputDirectory = new File(OUTPUT_DIR); + Util.flushDirectoryContent(outputDirectory); + String out = "bin"; + String directory = OUTPUT_DIR + File.separator + "src"; + + String moduleLoc = directory + File.separator + "mod.one"; + List<String> files = new ArrayList<>(); + writeFileCollecting(files, moduleLoc, "module-info.java", + "module mod.one { \n" + + " exports p1.p2;\n" + + "}"); + writeFileCollecting(files, moduleLoc + File.separator + "p1" + File.separator + "p2", "t3.java", + "package p1.p2;\n" + + "public class t3 {\n" + + "}\n"); + + moduleLoc = directory + File.separator + "mod.two"; + writeFileCollecting(files, moduleLoc, "module-info.java", + "module mod.two { \n" + + " exports p1.p2.t3;\n" + + " requires mod.one;\n" + + "}"); + writeFileCollecting(files, moduleLoc + File.separator + "p1" + File.separator + "p2" + File.separator + "t3", "t4.java", + "package p1.p2.t3;\n" + + "public class t4 {\n" + + "}\n"); + + StringBuffer buffer = new StringBuffer(); + buffer.append("-d " + OUTPUT_DIR + File.separator + out ) + .append(" -9 ") + .append(" -classpath \"") + .append(Util.getJavaClassLibsAsString()) + .append("\" ") + .append(" --module-source-path " + "\"" + directory + "\""); + + runNegativeModuleTest( + files, + buffer, + "", + "----------\n" + + "1. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/src/mod.two/p1/p2/t3/t4.java (at line 1)\n" + + " package p1.p2.t3;\n" + + " ^^^^^^^^\n" + + "The package p1.p2.t3 collides with a type\n" + + "----------\n" + + "1 problem (1 error)\n", + false, + "package p1.p2.t3 clashes with class of same name"); + } } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PackageBindingTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PackageBindingTest.java index b8e7a88340..61a6e061d9 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PackageBindingTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PackageBindingTest.java @@ -20,6 +20,7 @@ import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; +import org.eclipse.jdt.internal.compiler.lookup.PlainPackageBinding; import org.eclipse.jdt.internal.core.INameEnvironmentWithProgress; public class PackageBindingTest extends AbstractCompilerTest @@ -36,7 +37,7 @@ public class PackageBindingTest extends AbstractCompilerTest public void _test01() { NameEnvironmentDummy nameEnv = new NameEnvironmentDummy(true); - PackageBinding packageBinding = new PackageBinding(new LookupEnvironment(null, new CompilerOptions(), null, nameEnv)); + PlainPackageBinding packageBinding = new PlainPackageBinding(new LookupEnvironment(null, new CompilerOptions(), null, nameEnv)); Binding resultBinding = packageBinding.getTypeOrPackage("java.lang".toCharArray(), null, false); assertNotNull(resultBinding); @@ -53,7 +54,7 @@ public class PackageBindingTest extends AbstractCompilerTest NameEnvironmentDummy nameEnv = new NameEnvironmentDummy(false); LookupEnvironment environment = new LookupEnvironment(null, new CompilerOptions(), null, nameEnv); - PackageBinding packageBinding = new PackageBinding(environment); + PlainPackageBinding packageBinding = new PlainPackageBinding(environment); Binding resultBinding = packageBinding.getTypeOrPackage("java.lang.String".toCharArray(), environment.module, false); assertNull(resultBinding); // (not implemented) diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java index 5b8459fd96..897233965f 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java @@ -4238,8 +4238,8 @@ public class ModuleBuilderTests extends ModifyingResourceTests { getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null); IMarker[] markers = p3.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); assertMarkers("Unexpected markers", - "The project was not built since its build path is incomplete. Cannot find the class file for org.astro.World. Fix the build path then try building this project\n" + - "The type org.astro.World cannot be resolved. It is indirectly referenced from required .class files", + "Name of automatic module \'test\' is unstable, it is derived from the module\'s file name.\n" + + "The type org.astro.World is not accessible", markers); } finally { this.deleteProject("test"); @@ -8704,6 +8704,80 @@ public class ModuleBuilderTests extends ModifyingResourceTests { deleteProject(prjB); } } + public void testBug547181() throws CoreException { + IJavaProject prjA = createJava9Project("A"); + IJavaProject prjB = createJava9Project("B"); + IJavaProject prjC = createJava9Project("C"); + IJavaProject prjD = createJava9Project("D"); + try { + createFile("A/src/module-info.java", + "module A {\n" + + " exports p1.p2;\n" + + "}\n"); + createFolder("A/src/p1/p2"); + createFile("A/src/p1/p2/X.java", + "package p1.p2;\n" + + "public class X {\n" + + "}\n"); + + addModularProjectEntry(prjB, prjA); + addModularProjectEntry(prjD, prjA); + addModularProjectEntry(prjD, prjB); + addModularProjectEntry(prjD, prjC); + + createFile("B/src/module-info.java", + "module B {\n" + + " requires A;\n" + + " exports p1;\n" + + "}\n"); + createFolder("B/src/p1"); + createFile("B/src/p1/Y.java", + "package p1;\n" + + "import p1.p2.X;\n" + + "public class Y {\n" + + " private void f(X x) {}\n" + + "}\n"); + + createFile("C/src/module-info.java", + "module C {\n" + + " exports p1.p2;\n" + + "}\n"); + createFolder("C/src/p1/p2"); + createFile("C/src/p1/p2/X.java", + "package p1.p2;\n" + + "public class X {\n" + + "}\n"); + + createFile("D/src/module-info.java", + "module D {\n" + + " requires B;\n" + + " requires C;\n" + + "}\n"); + + createFolder("D/src/usage"); + createFile("D/src/usage/AAA.java", + "package usage;\n" + + "import p1.Y;\n" + + "public class AAA {\n" + + " Y y;\n" + + "}\n"); + createFile("D/src/usage/Usage.java", + "package usage;\n" + + "import p1.p2.X;\n" + + "public class Usage {\n" + + " X x;\n" + + "}\n"); + + getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null); + assertNoErrors(); + + } finally { + deleteProject(prjA); + deleteProject(prjB); + deleteProject(prjC); + deleteProject(prjD); + } + } protected void assertNoErrors() throws CoreException { for (IProject p : getWorkspace().getRoot().getProjects()) { int maxSeverity = p.findMaxProblemSeverity(null, true, IResource.DEPTH_INFINITE); diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests9.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests9.java index 2a2db521a0..25fff8343f 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests9.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests9.java @@ -851,4 +851,97 @@ public void testBug544306() throws Exception { deleteProject(p2); } } +public void testBug547113() throws CoreException { + IJavaProject unnamed = createJava9Project("unnamed"); + IJavaProject a = createJava9Project("a"); + IJavaProject b = createJava9Project("b"); + IJavaProject c = createJava9Project("c"); + try { + createFolder("a/src/com/example/a"); + createFile("a/src/com/example/Base.java", + "package com.example;\n" + + "\n" + + "public class Base {}\n"); + createFile("a/src/com/example/a/A.java", + "package com.example.a;\n" + + "\n" + + "public class A {}\n"); + createFile("a/src/module-info.java", + "open module com.example.a {\n" + + " exports com.example;\n" + + " exports com.example.a;\n" + + " \n" + + " requires unnamed;\n" + + "}\n"); + addModularProjectEntry(a, unnamed); + + createFolder("b/src/com/example/b"); + createFile("b/src/com/example/b/B.java", + "package com.example.b;\n" + + "\n" + + "import com.example.Base;\n" + + "import com.example.a.A;\n" + + "\n" + + "public class B {\n" + + "\n" + + " public void a(A a) {\n" + + " System.out.println(a);\n" + + " }\n" + + "\n" + + " public void base(Base base) {\n" + + " System.out.println(base);\n" + + " }\n" + + "\n" + + "}\n"); + createFile("b/src/module-info.java", + "open module com.example.b {\n" + + " exports com.example.b;\n" + + " requires transitive com.example.a;\n" + + "}\n"); + addModularProjectEntry(b, a); + addModularProjectEntry(b, unnamed); + + createFolder("c/src/com/example/c"); + String cSource = "package com.example.c;\n" + + "\n" + + "import com.example.Base;\n" + + "import com.example.a.A;\n" + + "import com.example.b.B;\n" + + "\n" + + "public class C {\n" + + "\n" + + " public static void main(String[] args) {\n" + + " new B().a(new A());\n" + + " new B().base(new Base());\n" + + " System.out.println(\"done.\");\n" + + " }\n" + + "}\n"; + createFile("c/src/com/example/c/C.java", cSource); + createFile("c/src/module-info.java", + "open module com.example.c {\n" + + " exports com.example.c;\n" + + " requires com.example.b;\n" + + "}\n"); + addModularProjectEntry(c, a); + addModularProjectEntry(c, b); + addModularProjectEntry(c, unnamed); + + waitForAutoBuild(); + + this.workingCopy.discardWorkingCopy(); + this.problemRequestor.initialize(cSource.toCharArray()); + this.workingCopy = getCompilationUnit("c/src/com/example/c/C.java").getWorkingCopy(this.wcOwner, null); + this.problemRequestor.initialize(this.workingCopy.getSource().toCharArray()); + this.workingCopy.reconcile(AST_INTERNAL_JLS11, true, this.wcOwner, null); + assertProblems("Expecting no problems", + "----------\n" + + "----------\n", + this.problemRequestor); + } finally { + deleteProject(unnamed); + deleteProject(a); + deleteProject(b); + deleteProject(c); + } +} } diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java index afeb890b2e..0d14e13c06 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java @@ -39,6 +39,13 @@ import org.eclipse.jdt.internal.compiler.util.Util; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; @@ -329,6 +336,27 @@ public boolean hasCUDeclaringPackage(String qualifiedPackageName, Function<Compi return hasDeclaration; }); } + +@Override +public char[][] listPackages() { + Set<String> packageNames = new HashSet<>(); + try { + Path basePath = FileSystems.getDefault().getPath(this.path); + Files.walkFileTree(basePath, new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + if (file.toString().toLowerCase().endsWith(SUFFIX_STRING_class)) { + packageNames.add(file.getParent().relativize(basePath).toString().replace('/', '.')); + } + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + // treat as if files are missing + } + return packageNames.stream().map(String::toCharArray).toArray(char[][]::new); +} + @Override public void reset() { super.reset(); diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java index cb607ad7d5..93d48e6ff4 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java @@ -260,6 +260,19 @@ public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName } return false; } + +@Override +public char[][] listPackages() { + Set<String> packageNames = new HashSet<>(); + for (Enumeration<? extends ZipEntry> e = this.zipFile.entries(); e.hasMoreElements(); ) { + String fileName = e.nextElement().getName(); + int lastSlash = fileName.lastIndexOf('/'); + if (lastSlash != -1 && fileName.toLowerCase().endsWith(SUFFIX_STRING_class)) + packageNames.add(fileName.substring(0, lastSlash).replace('/', '.')); + } + return packageNames.stream().map(String::toCharArray).toArray(char[][]::new); +} + @Override public void reset() { super.reset(); diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java index 7a08126d5b..7828c82a9c 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java @@ -19,6 +19,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.InvalidPathException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -168,6 +169,9 @@ public class FileSystem implements IModuleAwareNameEnvironment, SuffixConstants /** Tasks resulting from --add-reads or --add-exports command line options. */ Map<String,UpdatesByKind> moduleUpdates = new HashMap<>(); + + private boolean hasLimitModules = false; + static final boolean isJRE12Plus; static { isJRE12Plus = CompilerOptions.VERSION_12.equals(System.getProperty("java.specification.version")); //$NON-NLS-1$ @@ -184,6 +188,7 @@ protected FileSystem(String[] classpathNames, String[] initialFileNames, String final int classpathSize = classpathNames.length; this.classpaths = new Classpath[classpathSize]; int counter = 0; + this.hasLimitModules = limitModules != null && !limitModules.isEmpty(); for (int i = 0; i < classpathSize; i++) { Classpath classpath = getClasspath(classpathNames[i], encoding, null, null, null); try { @@ -204,6 +209,7 @@ protected FileSystem(Classpath[] paths, String[] initialFileNames, boolean annot final int length = paths.length; int counter = 0; this.classpaths = new FileSystem.Classpath[length]; + this.hasLimitModules = limitedModules != null && !limitedModules.isEmpty(); for (int i = 0; i < length; i++) { final Classpath classpath = paths[i]; try { @@ -558,8 +564,8 @@ public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName, cha } @Override -public char[][] getModulesDeclaringPackage(char[][] parentPackageName, char[] packageName, char[] moduleName) { - String qualifiedPackageName = new String(CharOperation.concatWith(parentPackageName, packageName, '/')); +public char[][] getModulesDeclaringPackage(char[][] packageName, char[] moduleName) { + String qualifiedPackageName = new String(CharOperation.concatWith(packageName, '/')); String moduleNameString = String.valueOf(moduleName); LookupStrategy strategy = LookupStrategy.get(moduleName); @@ -576,6 +582,7 @@ public char[][] getModulesDeclaringPackage(char[][] parentPackageName, char[] pa } // search the entire environment and answer which modules declare that package: char[][] allNames = null; + boolean hasUnobserable = false; for (Classpath cp : this.classpaths) { if (strategy.matches(cp, Classpath::hasModule)) { if (strategy == LookupStrategy.Unnamed) { @@ -585,6 +592,10 @@ public char[][] getModulesDeclaringPackage(char[][] parentPackageName, char[] pa } else { char[][] declaringModules = cp.getModulesDeclaringPackage(qualifiedPackageName, null); if (declaringModules != null) { + if (cp instanceof ClasspathJrt && this.hasLimitModules) { + declaringModules = filterModules(declaringModules); + hasUnobserable |= declaringModules == null; + } if (allNames == null) allNames = declaringModules; else @@ -593,8 +604,16 @@ public char[][] getModulesDeclaringPackage(char[][] parentPackageName, char[] pa } } } + if (allNames == null && hasUnobserable) + return new char[][] { ModuleBinding.UNOBSERVABLE }; return allNames; } +private char[][] filterModules(char[][] declaringModules) { + char[][] filtered = Arrays.stream(declaringModules).filter(m -> this.moduleLocations.containsKey(new String(m))).toArray(char[][]::new); + if (filtered.length == 0) + return null; + return filtered; +} private Parser getParser() { Map<String,String> opts = new HashMap<String, String>(); opts.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_9); @@ -676,6 +695,19 @@ public char[][] getAllAutomaticModules() { return set.toArray(new char[set.size()][]); } +@Override +public char[][] listPackages(char[] moduleName) { + switch (LookupStrategy.get(moduleName)) { + case Named: + Classpath classpath = this.moduleLocations.get(new String(moduleName)); + if (classpath != null) + return classpath.listPackages(); + return CharOperation.NO_CHAR_CHAR; + default: + throw new UnsupportedOperationException("can list packages only of a named module"); //$NON-NLS-1$ + } +} + void addModuleUpdate(String moduleName, Consumer<IUpdatableModule> update, UpdateKind kind) { UpdatesByKind updates = this.moduleUpdates.get(moduleName); if (updates == null) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java index 0b189519c1..ff81ca577f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java @@ -37,10 +37,9 @@ import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; +import org.eclipse.jdt.internal.compiler.lookup.PlainPackageBinding; import org.eclipse.jdt.internal.compiler.lookup.Scope; import org.eclipse.jdt.internal.compiler.lookup.SourceModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.SplitPackageBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; import org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit; @@ -195,7 +194,7 @@ public class ModuleDeclaration extends ASTNode implements ReferenceContext { this.hasResolvedPackageDirectives = true; - Set<PackageBinding> exportedPkgs = new HashSet<>(); + Set<PlainPackageBinding> exportedPkgs = new HashSet<>(); for (int i = 0; i < this.exportsCount; i++) { ExportsStatement ref = this.exports[i]; if (ref != null && ref.resolve(cuScope)) { @@ -283,16 +282,21 @@ public class ModuleDeclaration extends ASTNode implements ReferenceContext { private void analyseReferencedPackages(CompilationUnitScope skope) { if (this.exports != null) { - for (ExportsStatement export : this.exports) { - PackageBinding pb = export.resolvedPackage; - if (pb == null) - continue; - if (pb instanceof SplitPackageBinding) - pb = ((SplitPackageBinding) pb).getIncarnation(this.binding); - if (pb.hasCompilationUnit(true)) - continue; - skope.problemReporter().invalidPackageReference(IProblem.PackageDoesNotExistOrIsEmpty, export); - } + analyseSomeReferencedPackages(this.exports, skope); + } + if (this.opens != null) { + analyseSomeReferencedPackages(this.opens, skope); + } + } + + private void analyseSomeReferencedPackages(PackageVisibilityStatement[] stats, CompilationUnitScope skope) { + for (PackageVisibilityStatement stat : stats) { + PlainPackageBinding pb = stat.resolvedPackage; + if (pb == null) + continue; + if (pb.hasCompilationUnit(true)) + continue; + skope.problemReporter().invalidPackageReference(IProblem.PackageDoesNotExistOrIsEmpty, stat); } } @@ -301,8 +305,7 @@ public class ModuleDeclaration extends ASTNode implements ReferenceContext { // collect transitively: Map<String, Set<ModuleBinding>> pack2mods = new HashMap<>(); for (ModuleBinding requiredModule : this.binding.getAllRequiredModules()) { - for (PackageBinding exportedPackage : requiredModule.getExports()) { - exportedPackage = exportedPackage.getVisibleFor(requiredModule, true); + for (PlainPackageBinding exportedPackage : requiredModule.getExports()) { if (this.binding.canAccess(exportedPackage)) { String packName = String.valueOf(exportedPackage.readableName()); Set<ModuleBinding> mods = pack2mods.get(packName); @@ -331,7 +334,7 @@ public class ModuleDeclaration extends ASTNode implements ReferenceContext { private void analyseOneDependency(RequiresStatement requiresStat, ModuleBinding requiredModule, CompilationUnitScope skope, Map<String, Set<ModuleBinding>> pack2mods) { - for (PackageBinding pack : requiredModule.getExports()) { + for (PlainPackageBinding pack : requiredModule.getExports()) { Set<ModuleBinding> mods = pack2mods.get(String.valueOf(pack.readableName())); if (mods != null && mods.size() > 1) { CompilerOptions compilerOptions = skope.compilerOptions(); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OpensStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OpensStatement.java index 0565524a34..e1da2b772b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OpensStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OpensStatement.java @@ -13,6 +13,7 @@ *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; +import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; public class OpensStatement extends PackageVisibilityStatement { @@ -24,8 +25,13 @@ public class OpensStatement extends PackageVisibilityStatement { super(pkgRef, targets); } @Override - protected int computeSeverity(int problemId) { - return ProblemSeverities.Warning; + public int computeSeverity(int problemId) { + switch (problemId) { + case IProblem.PackageDoesNotExistOrIsEmpty: + return ProblemSeverities.Warning; + default: + return ProblemSeverities.Error; + } } @Override public StringBuffer print(int indent, StringBuffer output) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PackageVisibilityStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PackageVisibilityStatement.java index f5e7470035..b4bdbf8364 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PackageVisibilityStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PackageVisibilityStatement.java @@ -17,7 +17,7 @@ package org.eclipse.jdt.internal.compiler.ast; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; +import org.eclipse.jdt.internal.compiler.lookup.PlainPackageBinding; import org.eclipse.jdt.internal.compiler.lookup.Scope; import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; @@ -26,7 +26,7 @@ public abstract class PackageVisibilityStatement extends ModuleStatement { public ImportReference pkgRef; public ModuleReference[] targets; public char[] pkgName; - public PackageBinding resolvedPackage; + public PlainPackageBinding resolvedPackage; public PackageVisibilityStatement(ImportReference pkgRef, ModuleReference[] targets) { this.pkgRef = pkgRef; @@ -58,27 +58,15 @@ public abstract class PackageVisibilityStatement extends ModuleStatement { } return !errorsExist; } - protected int computeSeverity(int problemId) { + public int computeSeverity(int problemId) { return ProblemSeverities.Error; } - protected PackageBinding resolvePackageReference(Scope scope) { + protected PlainPackageBinding resolvePackageReference(Scope scope) { if (this.resolvedPackage != null) return this.resolvedPackage; ModuleDeclaration exportingModule = scope.compilationUnitScope().referenceContext.moduleDeclaration; ModuleBinding src = exportingModule.binding; - this.resolvedPackage = src != null ? src.getVisiblePackage(this.pkgRef.tokens) : null; - int problemId = IProblem.PackageDoesNotExistOrIsEmpty; - if (this.resolvedPackage == null) { - // TODO: need a check for empty package as well - scope.problemReporter().invalidPackageReference(problemId, this, computeSeverity(problemId)); - } else { - if (!this.resolvedPackage.isDeclaredIn(src)) { - this.resolvedPackage = null; - // TODO(SHMOD): specific error? - scope.problemReporter().invalidPackageReference(problemId, this, computeSeverity(problemId)); - } - } - + this.resolvedPackage = src != null ? src.getOrCreateDeclaredPackage(this.pkgRef.tokens) : null; return this.resolvedPackage; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java index e9d9103f26..cec0657f7c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java @@ -1000,7 +1000,12 @@ public StringBuffer printExpression(int indent, StringBuffer output) { * Normal field binding did not work, try to bind to a field of the delegate receiver. */ public TypeBinding reportError(BlockScope scope) { - if (this.binding instanceof ProblemFieldBinding) { + Binding inaccessible = scope.environment().getInaccessibleBinding(this.tokens, scope.module()); + if (inaccessible instanceof TypeBinding) { + this.indexOfFirstFieldBinding = -1; + this.binding = inaccessible; + scope.problemReporter().invalidType(this, (TypeBinding) this.binding); + } else if (this.binding instanceof ProblemFieldBinding) { scope.problemReporter().invalidField(this, (FieldBinding) this.binding); } else if (this.binding instanceof ProblemReferenceBinding || this.binding instanceof MissingTypeBinding) { scope.problemReporter().invalidType(this, (TypeBinding) this.binding); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java index 8178dec1f9..8a6cb02b57 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java @@ -124,7 +124,7 @@ public class QualifiedTypeReference extends TypeReference { int typeStart = packageBinding == null ? 0 : packageBinding.compoundName.length; if (packageBinding != null) { - PackageBinding uniquePackage = packageBinding.getVisibleFor(scope.module(), false); + PackageBinding uniquePackage = packageBinding.getVisibleFor(scope.module(), false, false); if (uniquePackage instanceof SplitPackageBinding) { CompilerOptions compilerOptions = scope.compilerOptions(); boolean inJdtDebugCompileMode = compilerOptions.enableJdtDebugCompileMode; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModuleAwareNameEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModuleAwareNameEnvironment.java index b7b81f466a..539caaba7c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModuleAwareNameEnvironment.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModuleAwareNameEnvironment.java @@ -15,6 +15,7 @@ package org.eclipse.jdt.internal.compiler.env; import java.util.function.Predicate; +import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; import org.eclipse.jdt.internal.compiler.util.SimpleSetOfCharArray; @@ -101,15 +102,15 @@ public interface IModuleAwareNameEnvironment extends INameEnvironment { } @Override default boolean isPackage(char[][] parentPackageName, char[] packageName) { - return getModulesDeclaringPackage(parentPackageName, packageName, ModuleBinding.ANY) != null; + return getModulesDeclaringPackage(CharOperation.arrayConcat(parentPackageName, packageName), ModuleBinding.ANY) != null; } NameEnvironmentAnswer findType(char[][] compoundName, char[] moduleName); /** Answer a type identified by the given names. moduleName may be one of the special names from ModuleBinding (ANY, ANY_NAMED, UNNAMED). */ NameEnvironmentAnswer findType(char[] typeName, char[][] packageName, char[] moduleName); - char[][] getModulesDeclaringPackage(char[][] parentPackageName, char[] name, char[] moduleName); - default char[][] getUniqueModulesDeclaringPackage(char[][] parentPackageName, char[] name, char[] moduleName) { - char[][] allNames = getModulesDeclaringPackage(parentPackageName, name, moduleName); + char[][] getModulesDeclaringPackage(char[][] packageName, char[] moduleName); + default char[][] getUniqueModulesDeclaringPackage(char[][] packageName, char[] moduleName) { + char[][] allNames = getModulesDeclaringPackage(packageName, moduleName); if (allNames != null && allNames.length > 1) { SimpleSetOfCharArray set = new SimpleSetOfCharArray(allNames.length); for (char[] oneName : allNames) @@ -139,4 +140,12 @@ public interface IModuleAwareNameEnvironment extends INameEnvironment { * @param kind selects what kind of updates should be performed */ default void applyModuleUpdates(IUpdatableModule module, IUpdatableModule.UpdateKind kind) { /* default: do nothing */ } + + /** + * Lists all packages in the module identified by the given, real module name + * (i.e., this method is implemented only for {@link LookupStrategy#Named}). + * @param moduleName + * @return array of flat, dot-separated package names + */ + char[][] listPackages(char[] moduleName); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModulePathEntry.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModulePathEntry.java index 562c1aef79..86f24f73a0 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModulePathEntry.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModulePathEntry.java @@ -75,6 +75,14 @@ public interface IModulePathEntry { boolean hasCompilationUnit(String qualifiedPackageName, String moduleName); /** + * Lists all packages in this modulepath entry. + * @return array of flat, dot-separated package names + */ + default char[][] listPackages() { + return CharOperation.NO_CHAR_CHAR; + } + + /** * Specifies whether this entry represents an automatic module. * * @return true if this is an automatic module, false otherwise diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IUpdatableModule.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IUpdatableModule.java index 4082b28482..0704eefe9f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IUpdatableModule.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IUpdatableModule.java @@ -43,7 +43,6 @@ public interface IUpdatableModule { } @Override public void accept(IUpdatableModule t) { - // TODO Auto-generated method stub t.addExports(this.name, this.targets); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ITypeRequestor.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ITypeRequestor.java index 248e0afd76..2ad85cd4c2 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ITypeRequestor.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ITypeRequestor.java @@ -23,7 +23,6 @@ import org.eclipse.jdt.internal.compiler.env.ISourceType; import org.eclipse.jdt.internal.compiler.lookup.BinaryModuleBinding; import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; public interface ITypeRequestor { @@ -57,13 +56,9 @@ public interface ITypeRequestor { */ default void accept(IModule module, LookupEnvironment environment) { if (module instanceof ISourceModule) { - try { - ICompilationUnit compilationUnit = ((ISourceModule) module).getCompilationUnit(); - if (compilationUnit != null) { - accept(compilationUnit, null); - } - } catch (AbortCompilation abort) { - // silent + ICompilationUnit compilationUnit = ((ISourceModule) module).getCompilationUnit(); + if (compilationUnit != null) { + accept(compilationUnit, null); } } else { // handles IBinaryModule and IModule.AutoModule: diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryModuleBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryModuleBinding.java index 080b8f8a89..5102e9ca15 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryModuleBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryModuleBinding.java @@ -32,6 +32,7 @@ public class BinaryModuleBinding extends ModuleBinding { private static class AutomaticModuleBinding extends ModuleBinding { boolean autoNameFromManifest; + boolean hasScannedPackages; public AutomaticModuleBinding(IModule module, LookupEnvironment existingEnvironment) { super(module.name(), existingEnvironment); @@ -40,7 +41,8 @@ public class BinaryModuleBinding extends ModuleBinding { this.autoNameFromManifest = module.isAutoNameFromManifest(); this.requires = Binding.NO_MODULES; this.requiresTransitive = Binding.NO_MODULES; - this.exportedPackages = Binding.NO_PACKAGES; + this.exportedPackages = Binding.NO_PLAIN_PACKAGES; + this.hasScannedPackages = false; } @Override public boolean hasUnstableAutoName() { @@ -58,6 +60,17 @@ public class BinaryModuleBinding extends ModuleBinding { return this.requiresTransitive; } @Override + PlainPackageBinding getDeclaredPackage(char[] flatName) { + if (!this.hasScannedPackages) { + for (char[] packageName : (((IModuleAwareNameEnvironment)this.environment.nameEnvironment).listPackages(nameForCUCheck()))) { + getOrCreateDeclaredPackage(CharOperation.splitOn('.', packageName)); + } + this.hasScannedPackages = true; + } + return this.declaredPackages.get(flatName); + } + + @Override public char[] nameForLookup() { return ANY_NAMED; } @@ -155,73 +168,51 @@ public class BinaryModuleBinding extends ModuleBinding { } @Override - public PackageBinding[] getExports() { + public PlainPackageBinding[] getExports() { if (this.exportedPackages == null && this.unresolvedExports != null) resolvePackages(); return super.getExports(); } @Override - public PackageBinding[] getOpens() { + public PlainPackageBinding[] getOpens() { if (this.openedPackages == null && this.unresolvedOpens != null) resolvePackages(); return super.getOpens(); } private void resolvePackages() { - this.exportedPackages = new PackageBinding[this.unresolvedExports.length]; + this.exportedPackages = new PlainPackageBinding[this.unresolvedExports.length]; int count = 0; for (int i = 0; i < this.unresolvedExports.length; i++) { IPackageExport export = this.unresolvedExports[i]; - PackageBinding declaredPackage = forcedGetExportedPackage(CharOperation.splitOn('.', export.name())); - if (declaredPackage != null) { - this.exportedPackages[count++] = declaredPackage; - if (declaredPackage instanceof SplitPackageBinding) - declaredPackage = ((SplitPackageBinding) declaredPackage).getIncarnation(this); - if (declaredPackage != null) { - declaredPackage.isExported = Boolean.TRUE; - recordExportRestrictions(declaredPackage, export.targets()); - } - } + // when resolving "exports" in a binary module we simply assume the package must exist, + // since this has been checked already when compiling that module. + PlainPackageBinding declaredPackage = getOrCreateDeclaredPackage(CharOperation.splitOn('.', export.name())); + this.exportedPackages[count++] = declaredPackage; + declaredPackage.isExported = Boolean.TRUE; + recordExportRestrictions(declaredPackage, export.targets()); } if (count < this.exportedPackages.length) - System.arraycopy(this.exportedPackages, 0, this.exportedPackages = new PackageBinding[count], 0, count); + System.arraycopy(this.exportedPackages, 0, this.exportedPackages = new PlainPackageBinding[count], 0, count); - this.openedPackages = new PackageBinding[this.unresolvedOpens.length]; + this.openedPackages = new PlainPackageBinding[this.unresolvedOpens.length]; count = 0; for (int i = 0; i < this.unresolvedOpens.length; i++) { IPackageExport opens = this.unresolvedOpens[i]; - PackageBinding declaredPackage = getVisiblePackage(CharOperation.splitOn('.', opens.name())); - if (declaredPackage != null) { - this.openedPackages[count++] = declaredPackage; - if (declaredPackage instanceof SplitPackageBinding) - declaredPackage = ((SplitPackageBinding) declaredPackage).getIncarnation(this); - if (declaredPackage != null) { - recordOpensRestrictions(declaredPackage, opens.targets()); - } - } else { - // TODO(SHMOD): report incomplete module path? - } + PlainPackageBinding declaredPackage = getOrCreateDeclaredPackage(CharOperation.splitOn('.', opens.name())); + this.openedPackages[count++] = declaredPackage; + recordOpensRestrictions(declaredPackage, opens.targets()); } if (count < this.openedPackages.length) - System.arraycopy(this.openedPackages, 0, this.openedPackages = new PackageBinding[count], 0, count); + System.arraycopy(this.openedPackages, 0, this.openedPackages = new PlainPackageBinding[count], 0, count); } - - PackageBinding forcedGetExportedPackage(char[][] compoundName) { - // when resolving "exports" in a binary module we simply assume the package must exist, - // since this has been checked already when compiling that module. - PackageBinding binding = getVisiblePackage(compoundName); - if (binding != null) - return binding; - if (compoundName.length > 1) { - PackageBinding parent = forcedGetExportedPackage(CharOperation.subarray(compoundName, 0, compoundName.length-1)); - binding = new PackageBinding(compoundName, parent, this.environment, this); - parent.addPackage(binding, this); - return binding; - } - binding = new PackageBinding(compoundName[0], this.environment, this); - addPackage(binding, true); - return binding; + + @Override + PlainPackageBinding getDeclaredPackage(char[] flatName) { + getExports(); // triggers initialization of exported packages into declaredPackages + completeIfNeeded(UpdateKind.PACKAGE); + return super.getDeclaredPackage(flatName); } @Override diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java index 01703e059b..72394d2962 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. + * Copyright (c) 2000, 2010 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -50,6 +50,7 @@ public abstract class Binding { // Shared binding collections public static final ModuleBinding[] NO_MODULES = new ModuleBinding[0]; public static final PackageBinding[] NO_PACKAGES = new PackageBinding[0]; + public static final PlainPackageBinding[] NO_PLAIN_PACKAGES = new PlainPackageBinding[0]; public static final TypeBinding[] NO_TYPES = new TypeBinding[0]; public static final ReferenceBinding[] NO_REFERENCE_TYPES = new ReferenceBinding[0]; public static final TypeBinding[] NO_PARAMETERS = new TypeBinding[0]; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java index cdd7675932..7c579d457a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java @@ -410,15 +410,9 @@ public class ClassScope extends Scope { char[][] className = CharOperation.deepCopy(enclosingType.compoundName); className[className.length - 1] = CharOperation.concat(className[className.length - 1], this.referenceContext.name, '$'); - ReferenceBinding existingType = packageBinding.getType0(className[className.length - 1]); - if (existingType != null) { - if (existingType instanceof UnresolvedReferenceBinding) { - // its possible that a BinaryType referenced the member type before its enclosing source type was built - // so just replace the unresolved type with a new member type - } else { - // report the error against the parent - its still safe to answer the member type - this.parent.problemReporter().duplicateNestedType(this.referenceContext); - } + if (packageBinding.hasType0Any(className[className.length - 1])) { + // report the error against the parent - its still safe to answer the member type + this.parent.problemReporter().duplicateNestedType(this.referenceContext); } this.referenceContext.binding = new MemberTypeBinding(className, this, enclosingType); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java index b42355e16d..e2bf18d278 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java @@ -30,6 +30,7 @@ import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.*; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; +import org.eclipse.jdt.internal.compiler.env.IUpdatableModule; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; import org.eclipse.jdt.internal.compiler.util.*; @@ -162,11 +163,8 @@ void buildTypeBindings(AccessRestriction accessRestriction) { TypeDeclaration typeDecl = types[i]; if (this.environment.root.isProcessingAnnotations && this.environment.isMissingType(typeDecl.name)) throw new SourceTypeCollisionException(); // resolved a type ref before APT generated the type - ReferenceBinding typeBinding = this.fPackage.getType0(typeDecl.name); - if (Binding.isValid(typeBinding) && this.fPackage instanceof SplitPackageBinding && !this.environment.module.canAccess(typeBinding.fPackage)) - typeBinding = null; recordSimpleReference(typeDecl.name); // needed to detect collision cases - if (Binding.isValid(typeBinding) && !(typeBinding instanceof UnresolvedReferenceBinding)) { + if (this.fPackage.hasType0Any(typeDecl.name)) { // if its an unresolved binding - its fixed up whenever its needed, see UnresolvedReferenceBinding.resolve() if (this.environment.root.isProcessingAnnotations) throw new SourceTypeCollisionException(); // resolved a type ref before APT generated the type @@ -197,6 +195,12 @@ void buildTypeBindings(AccessRestriction accessRestriction) { // shrink topLevelTypes... only happens if an error was reported if (count != this.topLevelTypes.length) System.arraycopy(this.topLevelTypes, 0, this.topLevelTypes = new SourceTypeBinding[count], 0, count); + + if (this.referenceContext.moduleDeclaration != null) { + this.module().completeIfNeeded(IUpdatableModule.UpdateKind.MODULE); + this.referenceContext.moduleDeclaration.resolvePackageDirectives(this); + this.module().completeIfNeeded(IUpdatableModule.UpdateKind.PACKAGE); + } } void checkAndSetImports() { // TODO(SHMOD): verify: this block moved here from buildTypeBindings. @@ -428,7 +432,7 @@ void faultInImports() { continue nextImport; } if (importBinding instanceof PackageBinding) { - PackageBinding uniquePackage = ((PackageBinding)importBinding).getVisibleFor(module(), false); + PackageBinding uniquePackage = ((PackageBinding)importBinding).getVisibleFor(module(), false, false); if (uniquePackage instanceof SplitPackageBinding && !inJdtDebugCompileMode) { SplitPackageBinding splitPackage = (SplitPackageBinding) uniquePackage; problemReporter().conflictingPackagesFromModules(splitPackage, module(), importReference.sourceStart, importReference.sourceEnd); @@ -472,7 +476,7 @@ void faultInImports() { // re-get to find a possible split package: importedPackage = (PackageBinding) findImport(importedPackage.compoundName, false, true); if (importedPackage != null) - importedPackage = importedPackage.getVisibleFor(module(), true); + importedPackage = importedPackage.getVisibleFor(module(), true, false); if (importedPackage instanceof SplitPackageBinding && !inJdtDebugCompileMode) { SplitPackageBinding splitPackage = (SplitPackageBinding) importedPackage; int sourceEnd = (int) importReference.sourcePositions[splitPackage.compoundName.length-1]; @@ -516,7 +520,6 @@ void faultInImports() { public void faultInTypes() { faultInImports(); if (this.referenceContext.moduleDeclaration != null) { - this.referenceContext.moduleDeclaration.resolvePackageDirectives(this); this.referenceContext.moduleDeclaration.resolveTypeDirectives(this); } else if (this.referenceContext.currentPackage != null) { this.referenceContext.currentPackage.checkPackageConflict(this); @@ -554,7 +557,7 @@ private Binding findImport(char[][] compoundName, int length) { break foundNothingOrType; } if (!(binding instanceof PackageBinding)) { - PackageBinding visibleFor = packageBinding.getVisibleFor(module, false); // filter out empty parent-packages + PackageBinding visibleFor = packageBinding.getVisibleFor(module, false, false); // filter out empty parent-packages if (visibleFor instanceof SplitPackageBinding) return visibleFor; break foundNothingOrType; @@ -569,6 +572,11 @@ private Binding findImport(char[][] compoundName, int length) { ReferenceBinding type; if (binding == null) { + if (!module.isUnnamed()) { + Binding inaccessible = this.environment.getInaccessibleBinding(compoundName, module); + if (inaccessible != null) + return inaccessible; + } if (compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) return problemType(compoundName, i, null); type = findType(compoundName[0], this.environment.defaultPackage, this.environment.defaultPackage); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java index 426e30218c..46aba9e14c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java @@ -162,7 +162,7 @@ public LookupEnvironment(ITypeRequestor typeRequestor, CompilerOptions globalOpt this.typeRequestor = typeRequestor; this.globalOptions = globalOptions; this.problemReporter = problemReporter; - this.defaultPackage = new PackageBinding(this); // assume the default package always exists + this.defaultPackage = new PlainPackageBinding(this); // assume the default package always exists this.defaultImports = null; this.nameEnvironment = nameEnvironment; this.knownPackages = new HashtableOfPackage(); @@ -187,7 +187,7 @@ LookupEnvironment(LookupEnvironment rootEnv, ModuleBinding module) { this.typeRequestor = rootEnv.typeRequestor; this.globalOptions = rootEnv.globalOptions; this.problemReporter = rootEnv.problemReporter; - this.defaultPackage = new PackageBinding(this); // assume the default package always exists + this.defaultPackage = new PlainPackageBinding(this); // assume the default package always exists this.defaultImports = null; this.nameEnvironment = rootEnv.nameEnvironment; this.knownPackages = new HashtableOfPackage(); @@ -316,8 +316,7 @@ ReferenceBinding askForType(PackageBinding packageBinding, char[] name, ModuleBi if (answerModule != null) { if (!answerPackage.isDeclaredIn(answerModule)) continue; // this answer is not reachable via the packageBinding - if (answerPackage instanceof SplitPackageBinding) - answerPackage = ((SplitPackageBinding) answerPackage).getIncarnation(answerModule); + answerPackage = answerPackage.getIncarnation(answerModule); } if (answer.isResolvedBinding()) { candidate = combine(candidate, answer.getResolvedBinding(), clientModule); @@ -741,7 +740,7 @@ private PackageBinding computePackageFrom(char[][] constantPoolName, boolean isM if (packageBinding == null || packageBinding == TheNotFoundPackage) { if (this.useModuleSystem) { if (this.module.isUnnamed()) { - char[][] declaringModules = ((IModuleAwareNameEnvironment) this.nameEnvironment).getUniqueModulesDeclaringPackage(null, constantPoolName[0], ModuleBinding.ANY); + char[][] declaringModules = ((IModuleAwareNameEnvironment) this.nameEnvironment).getUniqueModulesDeclaringPackage(new char[][] {constantPoolName[0]}, ModuleBinding.ANY); if (declaringModules != null) { for (char[] mod : declaringModules) { ModuleBinding declaringModule = this.root.getModule(mod); @@ -754,7 +753,7 @@ private PackageBinding computePackageFrom(char[][] constantPoolName, boolean isM } } if (packageBinding == null || packageBinding == TheNotFoundPackage) { - packageBinding = new PackageBinding(constantPoolName[0], this, this.module); + packageBinding = new PlainPackageBinding(constantPoolName[0], this, this.module); } if (isMissing) packageBinding.tagBits |= TagBits.HasMissingType; this.knownPackages.put(constantPoolName[0], packageBinding); // TODO: split? @@ -765,7 +764,8 @@ private PackageBinding computePackageFrom(char[][] constantPoolName, boolean isM if ((packageBinding = parent.getPackage0(constantPoolName[i])) == null || packageBinding == TheNotFoundPackage) { if (this.useModuleSystem) { if (this.module.isUnnamed()) { - char[][] declaringModules = ((IModuleAwareNameEnvironment) this.nameEnvironment).getModulesDeclaringPackage(parent.compoundName, constantPoolName[i], ModuleBinding.ANY); + char[][] declaringModules = ((IModuleAwareNameEnvironment) this.nameEnvironment).getModulesDeclaringPackage( + CharOperation.arrayConcat(parent.compoundName, constantPoolName[i]), ModuleBinding.ANY); if (declaringModules != null) { for (char[] mod : declaringModules) { ModuleBinding declaringModule = this.root.getModule(mod); @@ -778,7 +778,7 @@ private PackageBinding computePackageFrom(char[][] constantPoolName, boolean isM } } if (packageBinding == null || packageBinding == TheNotFoundPackage) { - packageBinding = new PackageBinding(CharOperation.subarray(constantPoolName, 0, i + 1), parent, this, this.module); + packageBinding = new PlainPackageBinding(CharOperation.subarray(constantPoolName, 0, i + 1), parent, this, this.module); } if (isMissing) { packageBinding.tagBits |= TagBits.HasMissingType; @@ -1086,13 +1086,19 @@ public MissingTypeBinding createMissingType(PackageBinding packageBinding, char[ * 3. Create the method bindings */ public PackageBinding createPackage(char[][] compoundName) { - PackageBinding packageBinding = getPackage0(compoundName[0]); - if (packageBinding == null || packageBinding == TheNotFoundPackage) { - packageBinding = new PackageBinding(compoundName[0], this, this.module); - this.knownPackages.put(compoundName[0], packageBinding); - if (this.module != null) { - packageBinding = this.module.addPackage(packageBinding, true); - this.knownPackages.put(compoundName[0], packageBinding); // update in case of split package + PackageBinding packageBinding = this.module.getDeclaredPackage(CharOperation.concatWith(compoundName, '.')); + if (packageBinding != null && packageBinding.isValidBinding()) { + // restart from the toplevel package to proceed with clash analysis below + packageBinding = this.getTopLevelPackage(compoundName[0]); + } else { + packageBinding = getPackage0(compoundName[0]); + if (packageBinding == null || packageBinding == TheNotFoundPackage) { + packageBinding = new PlainPackageBinding(compoundName[0], this, this.module); + this.knownPackages.put(compoundName[0], packageBinding); + if (this.module != null) { + packageBinding = this.module.addPackage(packageBinding, true); + this.knownPackages.put(compoundName[0], packageBinding); // update in case of split package + } } } @@ -1103,8 +1109,7 @@ public PackageBinding createPackage(char[][] compoundName) { // unless its an unresolved type which is referenced from an inconsistent class file // NOTE: empty packages are not packages according to changes in JLS v2, 7.4.3 // so not all types cause collision errors when they're created even though the package did exist - ReferenceBinding type = packageBinding.getType0(compoundName[i]); - if (type != null && type != TheNotFoundType && !(type instanceof UnresolvedReferenceBinding)) + if (packageBinding.hasType0Any(compoundName[i])) return null; PackageBinding parent = packageBinding; @@ -1125,21 +1130,18 @@ public PackageBinding createPackage(char[][] compoundName) { return null; } } - if (parent instanceof SplitPackageBinding) { + PackageBinding singleParent = parent.getIncarnation(this.module); + if (singleParent != parent && singleParent != null) { // parent.getPackage0() may have been too shy, so drill into the split: - PackageBinding singleParent = ((SplitPackageBinding) parent).getIncarnation(this.module); - if (singleParent != null) - packageBinding = singleParent.getPackage0(compoundName[i]); + packageBinding = singleParent.getPackage0(compoundName[i]); } if (packageBinding == null) { - packageBinding = new PackageBinding(CharOperation.subarray(compoundName, 0, i + 1), parent, this, this.module); + packageBinding = new PlainPackageBinding(CharOperation.subarray(compoundName, 0, i + 1), parent, this, this.module); packageBinding = parent.addPackage(packageBinding, this.module); } } } - if (packageBinding instanceof SplitPackageBinding) - packageBinding = ((SplitPackageBinding) packageBinding).getIncarnation(this.module); - return packageBinding; + return packageBinding.getIncarnation(this.module); } public ParameterizedGenericMethodBinding createParameterizedGenericMethod(MethodBinding genericMethod, RawTypeBinding rawType) { @@ -1474,6 +1476,10 @@ public ReferenceBinding getCachedType0(char[][] compoundName) { PackageBinding packageBinding = getPackage0(compoundName[0]); if (packageBinding == null || packageBinding == TheNotFoundPackage) return null; + // we should be asking via the correct LE, so peel any SPB at the root: + packageBinding = packageBinding.getIncarnation(this.module); + if (packageBinding == null || packageBinding == TheNotFoundPackage) + return null; for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++) if ((packageBinding = packageBinding.getPackage0Any(compoundName[i])) == null || packageBinding == TheNotFoundPackage) @@ -1645,7 +1651,7 @@ PackageBinding getTopLevelPackage(char[] name) { packageBinding = this.module.getTopLevelPackage(name); } else { if (this.nameEnvironment.isPackage(null, name)) { - this.knownPackages.put(name, packageBinding = new PackageBinding(name, this, this.module)); + this.knownPackages.put(name, packageBinding = new PlainPackageBinding(name, this, this.module)); } } if (packageBinding != null) { @@ -2130,7 +2136,7 @@ public void reset() { this.module = this.UnNamedModule; this.JavaBaseModule = null; - this.defaultPackage = new PackageBinding(this); // assume the default package always exists + this.defaultPackage = new PlainPackageBinding(this); // assume the default package always exists this.defaultImports = null; this.knownPackages = new HashtableOfPackage(); this.accessRestrictions = new HashMap(3); @@ -2241,4 +2247,44 @@ public boolean containsNullTypeAnnotation(AnnotationBinding[] typeAnnotations) { } return false; } + +public Binding getInaccessibleBinding(char[][] compoundName, ModuleBinding clientModule) { + if (this.root != this) + return this.root.getInaccessibleBinding(compoundName, clientModule); + if (this.nameEnvironment instanceof IModuleAwareNameEnvironment) { + IModuleAwareNameEnvironment moduleEnv = (IModuleAwareNameEnvironment) this.nameEnvironment; + int length = compoundName.length; + for (int j=length; j>0; j--) { + char[][] candidateName = CharOperation.subarray(compoundName, 0, j); + char[][] moduleNames = moduleEnv.getModulesDeclaringPackage(candidateName, ModuleBinding.ANY); + if (moduleNames != null) { + // in some module a package named candidateName exists, verify observability & inaccessibility: + PackageBinding inaccessiblePackage = null; + for (char[] moduleName : moduleNames) { + if (moduleName == ModuleBinding.UNOBSERVABLE) + continue; + ModuleBinding mod = getModule(moduleName); + if (mod != null) { + PackageBinding pack = mod.getVisiblePackage(candidateName); + if (pack != null && pack.isValidBinding()) { + if (clientModule.canAccess(pack)) + return null; + inaccessiblePackage = pack; + } + } + } + if (inaccessiblePackage == null) + return null; + if (j < length) { + // does the package even contain a type of the next name segment? + TypeBinding type = inaccessiblePackage.getType(compoundName[j], inaccessiblePackage.enclosingModule); + if (type instanceof ReferenceBinding && type.isValidBinding()) + return new ProblemReferenceBinding(compoundName, (ReferenceBinding) type, ProblemReasons.NotAccessible); + } + return new ProblemPackageBinding(candidateName, ProblemReasons.NotAccessible, this); + } + } + } + return null; +} } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ModuleBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ModuleBinding.java index 642fe17b1a..a32ae2d34f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ModuleBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ModuleBinding.java @@ -58,6 +58,8 @@ public class ModuleBinding extends Binding implements IUpdatableModule { public static final char[] ANY = "".toCharArray(); //$NON-NLS-1$ /** Module name for package/type lookup that should look into all named modules. */ public static final char[] ANY_NAMED = "".toCharArray(); //$NON-NLS-1$ + /** Module name for an unobservable module */ + public static final char[] UNOBSERVABLE = "".toCharArray(); //$NON-NLS-1$ public static class UnNamedModule extends ModuleBinding { @@ -93,6 +95,20 @@ public class ModuleBinding extends Binding implements IUpdatableModule { return pkg.isDeclaredIn(this) && pkg.hasCompilationUnit(false); } @Override + PlainPackageBinding getDeclaredPackage(char[] flatName) { + PlainPackageBinding declaredPackage = super.getDeclaredPackage(flatName); + if (declaredPackage == null && this.environment.useModuleSystem) { + IModuleAwareNameEnvironment moduleEnv = (IModuleAwareNameEnvironment) this.environment.nameEnvironment; + char[][] compoundName = CharOperation.splitOn('.', flatName); + char[][] declaringModuleNames = moduleEnv.getUniqueModulesDeclaringPackage(compoundName, nameForLookup()); + if (declaringModuleNames != null && CharOperation.containsEqual(declaringModuleNames, this.moduleName)) { + declaredPackage = getOrCreateDeclaredPackage(compoundName); + this.declaredPackages.put(flatName, declaredPackage); + } + } + return declaredPackage; + } + @Override public boolean isUnnamed() { return true; } @@ -116,10 +132,10 @@ public class ModuleBinding extends Binding implements IUpdatableModule { public char[] moduleName; protected ModuleBinding[] requires; protected ModuleBinding[] requiresTransitive; - protected PackageBinding[] exportedPackages; - private Map<PackageBinding,SimpleSetOfCharArray> exportRestrictions; // RHS is unresolved names, because unresolvable names are legal in this position - protected PackageBinding[] openedPackages; - private Map<PackageBinding,SimpleSetOfCharArray> openRestrictions; // RHS is unresolved names, because unresolvable names are legal in this position + protected PlainPackageBinding[] exportedPackages; + private Map<PlainPackageBinding,SimpleSetOfCharArray> exportRestrictions; // RHS is unresolved names, because unresolvable names are legal in this position + protected PlainPackageBinding[] openedPackages; + private Map<PlainPackageBinding,SimpleSetOfCharArray> openRestrictions; // RHS is unresolved names, because unresolvable names are legal in this position protected TypeBinding[] uses; protected TypeBinding[] services; public Map<TypeBinding,TypeBinding[]> implementations; @@ -133,7 +149,6 @@ public class ModuleBinding extends Binding implements IUpdatableModule { boolean isAuto = false; private boolean[] isComplete = new boolean[UpdateKind.values().length]; private Set<ModuleBinding> transitiveRequires; - boolean isPackageLookupActive = false; // to prevent cyclic lookup caused by synthetic reads edges on behalf of auto-modules. SimpleLookupTable storedAnnotations = null; /** @@ -141,8 +156,16 @@ public class ModuleBinding extends Binding implements IUpdatableModule { * We consider a package as declared in a module, * if a compilation unit associated with the module * declares the package or a subpackage thereof. + * <p> + * A package in this structures is always represented by a {@link PlainPackageBinding}, + * as opposed to {@link SplitPackageBinding}, which are only maintained in the trees + * below {@link LookupEnvironment#knownPackages}. + * <p> + * This structure is populated early during compilation with all packages that + * are referenced in exports and opens directives, plus their parent packages. + * </p> */ - public HashtableOfPackage declaredPackages; + public HashtableOfPackage<PlainPackageBinding> declaredPackages; /** Constructor for the unnamed module. */ private ModuleBinding(LookupEnvironment env) { @@ -150,9 +173,9 @@ public class ModuleBinding extends Binding implements IUpdatableModule { this.environment = env; this.requires = Binding.NO_MODULES; this.requiresTransitive = Binding.NO_MODULES; - this.exportedPackages = Binding.NO_PACKAGES; - this.openedPackages = Binding.NO_PACKAGES; - this.declaredPackages = new HashtableOfPackage(0); + this.exportedPackages = Binding.NO_PLAIN_PACKAGES; + this.openedPackages = Binding.NO_PLAIN_PACKAGES; + this.declaredPackages = new HashtableOfPackage<PlainPackageBinding>(); Arrays.fill(this.isComplete, true); } /* For error binding and sub class SourceModuleBinding. */ @@ -160,11 +183,11 @@ public class ModuleBinding extends Binding implements IUpdatableModule { this.moduleName = moduleName; this.requires = Binding.NO_MODULES; this.requiresTransitive = Binding.NO_MODULES; - this.exportedPackages = Binding.NO_PACKAGES; - this.openedPackages = Binding.NO_PACKAGES; + this.exportedPackages = Binding.NO_PLAIN_PACKAGES; + this.openedPackages = Binding.NO_PLAIN_PACKAGES; this.uses = Binding.NO_TYPES; this.services = Binding.NO_TYPES; - this.declaredPackages = new HashtableOfPackage(5); + this.declaredPackages = new HashtableOfPackage<PlainPackageBinding>(5); } /* For sub class BinaryModuleBinding */ @@ -173,10 +196,10 @@ public class ModuleBinding extends Binding implements IUpdatableModule { this.requires = Binding.NO_MODULES; this.requiresTransitive = Binding.NO_MODULES; this.environment = new LookupEnvironment(existingEnvironment.root, this); - this.declaredPackages = new HashtableOfPackage(5); + this.declaredPackages = new HashtableOfPackage<PlainPackageBinding>(5); } - public PackageBinding[] getExports() { + public PlainPackageBinding[] getExports() { completeIfNeeded(UpdateKind.PACKAGE); return this.exportedPackages; } @@ -192,7 +215,7 @@ public class ModuleBinding extends Binding implements IUpdatableModule { } return CharOperation.NO_STRINGS; } - public PackageBinding[] getOpens() { + public PlainPackageBinding[] getOpens() { completeIfNeeded(UpdateKind.PACKAGE); return this.openedPackages; } @@ -231,7 +254,7 @@ public class ModuleBinding extends Binding implements IUpdatableModule { return this.services; } - private void completeIfNeeded(IUpdatableModule.UpdateKind kind) { + void completeIfNeeded(IUpdatableModule.UpdateKind kind) { if (!this.isComplete[kind.ordinal()]) { this.isComplete[kind.ordinal()] = true; if (this.environment.nameEnvironment instanceof IModuleAwareNameEnvironment) { @@ -257,23 +280,10 @@ public class ModuleBinding extends Binding implements IUpdatableModule { this.environment.problemReporter.missingModuleAddReads(requiredModuleName); return; } - // update known packages: - HashtableOfPackage knownPackages = this.environment.knownPackages; - for (int i = 0; i < knownPackages.valueTable.length; i++) { - PackageBinding packageBinding = knownPackages.valueTable[i]; - if (packageBinding == null) continue; - PackageBinding newBinding = requiredModule.getVisiblePackage(packageBinding.compoundName); - newBinding = SplitPackageBinding.combine(newBinding, packageBinding, this); - if (packageBinding != newBinding) { - knownPackages.valueTable[i] = newBinding; - if (this.declaredPackages.containsKey(newBinding.readableName())) - this.declaredPackages.put(newBinding.readableName(), newBinding); - } - } } @Override public void addExports(char[] packageName, char[][] targetModules) { - PackageBinding declaredPackage = getVisiblePackage(CharOperation.splitOn('.', packageName)); + PlainPackageBinding declaredPackage = getOrCreateDeclaredPackage(CharOperation.splitOn('.', packageName)); if (declaredPackage != null && declaredPackage.isValidBinding()) addResolvedExport(declaredPackage, targetModules); } @@ -293,9 +303,9 @@ public class ModuleBinding extends Binding implements IUpdatableModule { public char[][] getPackageNamesForClassFile() { if (this.packageNames == null) return null; - for (PackageBinding packageBinding : this.exportedPackages) + for (PlainPackageBinding packageBinding : this.exportedPackages) this.packageNames.add(packageBinding.readableName()); - for (PackageBinding packageBinding : this.openedPackages) + for (PlainPackageBinding packageBinding : this.openedPackages) this.packageNames.add(packageBinding.readableName()); if (this.implementations != null) for (TypeBinding[] types : this.implementations.values()) @@ -306,38 +316,57 @@ public class ModuleBinding extends Binding implements IUpdatableModule { // --- - public void addResolvedExport(PackageBinding declaredPackage, char[][] targetModules) { - int len = this.exportedPackages.length; + public PlainPackageBinding getOrCreateDeclaredPackage(char[][] compoundName) { + char[] flatName = CharOperation.concatWith(compoundName, '.'); + PlainPackageBinding pkgBinding = this.declaredPackages.get(flatName); + if (pkgBinding != null) + return pkgBinding; + if (compoundName.length > 1) { + PlainPackageBinding parent = getOrCreateDeclaredPackage(CharOperation.subarray(compoundName, 0, compoundName.length-1)); + pkgBinding = new PlainPackageBinding(compoundName, parent, this.environment, this); + parent.addPackage(pkgBinding, this); + } else { + pkgBinding = new PlainPackageBinding(compoundName[0], this.environment, this); + PackageBinding problemPackage = this.environment.getPackage0(compoundName[0]); + if (problemPackage == LookupEnvironment.TheNotFoundPackage) + this.environment.knownPackages.put(compoundName[0], null); // forget TheNotFoundPackage if package was detected late (e.g. with APT in the loop) + } + this.declaredPackages.put(flatName, pkgBinding); + return pkgBinding; + } + + public void addResolvedExport(PlainPackageBinding declaredPackage, char[][] targetModules) { if (declaredPackage == null || !declaredPackage.isValidBinding()) { // TODO(SHMOD) use a problem binding (if needed by DOM clients)? See https://bugs.eclipse.org/518794#c13 return; } - if (len == 0) { - this.exportedPackages = new PackageBinding[] { declaredPackage }; + if (this.exportedPackages == null || this.exportedPackages.length == 0) { + this.exportedPackages = new PlainPackageBinding[] { declaredPackage }; } else { - System.arraycopy(this.exportedPackages, 0, this.exportedPackages = new PackageBinding[len+1], 0, len); + int len = this.exportedPackages.length; + System.arraycopy(this.exportedPackages, 0, this.exportedPackages = new PlainPackageBinding[len+1], 0, len); this.exportedPackages[len] = declaredPackage; } declaredPackage.isExported = Boolean.TRUE; recordExportRestrictions(declaredPackage, targetModules); } - public void addResolvedOpens(PackageBinding declaredPackage, char[][] targetModules) { + public void addResolvedOpens(PlainPackageBinding declaredPackage, char[][] targetModules) { int len = this.openedPackages.length; if (declaredPackage == null || !declaredPackage.isValidBinding()) { // TODO(SHMOD) use a problem binding (if needed by DOM clients)? See https://bugs.eclipse.org/518794#c13 return; } if (len == 0) { - this.openedPackages = new PackageBinding[] { declaredPackage }; + this.openedPackages = new PlainPackageBinding[] { declaredPackage }; } else { - System.arraycopy(this.openedPackages, 0, this.openedPackages = new PackageBinding[len+1], 0, len); + System.arraycopy(this.openedPackages, 0, this.openedPackages = new PlainPackageBinding[len+1], 0, len); this.openedPackages[len] = declaredPackage; } recordOpensRestrictions(declaredPackage, targetModules); } - protected void recordExportRestrictions(PackageBinding exportedPackage, char[][] targetModules) { + protected void recordExportRestrictions(PlainPackageBinding exportedPackage, char[][] targetModules) { if (targetModules != null && targetModules.length > 0) { SimpleSetOfCharArray targetModuleSet = null; if (this.exportRestrictions != null) { @@ -355,7 +384,7 @@ public class ModuleBinding extends Binding implements IUpdatableModule { } } - protected void recordOpensRestrictions(PackageBinding openedPackage, char[][] targetModules) { + protected void recordOpensRestrictions(PlainPackageBinding openedPackage, char[][] targetModules) { if (targetModules != null && targetModules.length > 0) { SimpleSetOfCharArray targetModuleSet = null; if (this.openRestrictions != null) { @@ -472,12 +501,7 @@ public class ModuleBinding extends Binding implements IUpdatableModule { */ public boolean isPackageExportedTo(PackageBinding pkg, ModuleBinding client) { // TODO(SHMOD): cache the result? - PackageBinding resolved = null; - if (pkg instanceof SplitPackageBinding) { - resolved = ((SplitPackageBinding) pkg).getIncarnation(this); - } else if (pkg.enclosingModule == this) { - resolved = pkg; - } + PackageBinding resolved = pkg.getIncarnation(this); if (resolved != null) { if (this.isAuto) { // all packages are exported by an automatic module return pkg.enclosingModule == this; // no transitive export @@ -515,11 +539,8 @@ public class ModuleBinding extends Binding implements IUpdatableModule { * </p> */ public PackageBinding getTopLevelPackage(char[] name) { - // check caches: - PackageBinding binding = this.declaredPackages.get(name); - if (binding != null) - return binding; - binding = this.environment.getPackage0(name); + // check cache: + PackageBinding binding = this.environment.getPackage0(name); if (binding != null) return binding; binding = getVisiblePackage(null, name, true); @@ -533,31 +554,14 @@ public class ModuleBinding extends Binding implements IUpdatableModule { return binding; } - PackageBinding getDeclaredPackage(char[][] parentName, char[] name) { - // check caches: - char[][] subPkgCompoundName = CharOperation.arrayConcat(parentName, name); - char[] fullFlatName = CharOperation.concatWith(subPkgCompoundName, '.'); - PackageBinding pkg = this.declaredPackages.get(fullFlatName); - if (pkg != null) - return pkg; - PackageBinding parent = parentName.length == 0 ? null : getVisiblePackage(parentName); - PackageBinding binding = new PackageBinding(subPkgCompoundName, parent, this.environment, this); - // remember - this.declaredPackages.put(fullFlatName, binding); - if (parent == null) { - this.environment.knownPackages.put(name, binding); - } - return binding; + PlainPackageBinding getDeclaredPackage(char[] flatName) { + return this.declaredPackages.get(flatName); } + // Given parent is visible in this module, see if there is sub package named name visible in this module PackageBinding getVisiblePackage(PackageBinding parent, char[] name, boolean considerRequiredModules) { - // check caches: - char[][] parentName = parent == null ? CharOperation.NO_CHAR_CHAR : parent.compoundName; - char[][] subPkgCompoundName = CharOperation.arrayConcat(parentName, name); - char[] fullFlatName = CharOperation.concatWith(subPkgCompoundName, '.'); - PackageBinding pkg = this.declaredPackages.get(fullFlatName); - if (pkg != null) - return pkg; + // check caches in PackageBinding/LookupEnvironment, which contain the full SplitPackageBinding if appropriate: + PackageBinding pkg; if (parent != null) pkg = parent.getPackage0(name); else @@ -569,33 +573,37 @@ public class ModuleBinding extends Binding implements IUpdatableModule { return addPackage(pkg, false); } - PackageBinding binding = null; + // check cached plain PackageBinding in declaredPackages (which may need combining with siblings): + char[][] parentName = parent == null ? CharOperation.NO_CHAR_CHAR : parent.compoundName; + char[][] subPkgCompoundName = CharOperation.arrayConcat(parentName, name); + char[] fullFlatName = CharOperation.concatWith(subPkgCompoundName, '.'); + PackageBinding binding = this.declaredPackages.get(fullFlatName); + char[][] declaringModuleNames = null; boolean packageMayBeIncomplete = !considerRequiredModules; if (this.environment.useModuleSystem) { IModuleAwareNameEnvironment moduleEnv = (IModuleAwareNameEnvironment) this.environment.nameEnvironment; - declaringModuleNames = moduleEnv.getUniqueModulesDeclaringPackage(parentName, name, nameForLookup()); - if (declaringModuleNames != null) { - if (CharOperation.containsEqual(declaringModuleNames, this.moduleName)) { - if (parent instanceof SplitPackageBinding) { - // parent.getPackage0() may have been too shy, so drill into the split: - PackageBinding singleParent = ((SplitPackageBinding) parent).getIncarnation(this); - if (singleParent != null) - binding = singleParent.getPackage0(name); - } - if (binding == null) { - // declared here, not yet known, so create it now: - binding = new PackageBinding(subPkgCompoundName, parent, this.environment, this); - } - } else if (considerRequiredModules) { - // visible but foreign (when current is unnamed or auto): - for (char[] declaringModuleName : declaringModuleNames) { - ModuleBinding declaringModule = this.environment.root.getModule(declaringModuleName); - if (declaringModule != null) { - if (declaringModule.isPackageLookupActive) { - packageMayBeIncomplete = true; - } else { - PackageBinding declaredPackage = declaringModule.getDeclaredPackage(parentName, name); + declaringModuleNames = moduleEnv.getUniqueModulesDeclaringPackage(subPkgCompoundName, nameForLookup()); + if (binding == null) { + if (declaringModuleNames != null) { + if (CharOperation.containsEqual(declaringModuleNames, this.moduleName)) { + if (parent != null) { + PackageBinding singleParent = parent.getIncarnation(this); + if (singleParent != null && singleParent != parent) { + // parent.getPackage0() may have been too shy, so drill into the split: + binding = singleParent.getPackage0(name); + } + } + if (binding == null) { + // declared here, not yet known, so create it now: + binding = new PlainPackageBinding(subPkgCompoundName, parent, this.environment, this); + } + } else if (considerRequiredModules) { + // visible but foreign (when current is unnamed or auto): + for (char[] declaringModuleName : declaringModuleNames) { + ModuleBinding declaringModule = this.environment.root.getModule(declaringModuleName); + if (declaringModule != null) { + PlainPackageBinding declaredPackage = declaringModule.getDeclaredPackage(fullFlatName); if (declaredPackage != null) { // don't add foreign package to 'parent' (below), but to its own parent: if (declaredPackage.parent != null) @@ -611,7 +619,7 @@ public class ModuleBinding extends Binding implements IUpdatableModule { } } else { if (this.environment.nameEnvironment.isPackage(parentName, name)) - binding = new PackageBinding(subPkgCompoundName, parent, this.environment, this); + binding = new PlainPackageBinding(subPkgCompoundName, parent, this.environment, this); } // enrich with split-siblings from visible modules: @@ -716,11 +724,11 @@ public class ModuleBinding extends Binding implements IUpdatableModule { char[][] declaringModuleNames = null; if (isUnnamed()) { IModuleAwareNameEnvironment moduleEnv = (IModuleAwareNameEnvironment) this.environment.nameEnvironment; - declaringModuleNames = moduleEnv.getUniqueModulesDeclaringPackage(null, packageName, ANY); + declaringModuleNames = moduleEnv.getUniqueModulesDeclaringPackage(new char[][] {packageName}, ANY); } packageBinding = combineWithPackagesFromOtherRelevantModules(packageBinding, packageBinding.compoundName, declaringModuleNames); } - this.declaredPackages.put(packageName, packageBinding); + this.declaredPackages.put(packageName, packageBinding.getIncarnation(this)); if (packageBinding.parent == null) { this.environment.knownPackages.put(packageName, packageBinding); } @@ -729,23 +737,11 @@ public class ModuleBinding extends Binding implements IUpdatableModule { } private PackageBinding combineWithPackagesFromOtherRelevantModules(PackageBinding currentBinding, char[][] compoundName, char[][] declaringModuleNames) { - boolean save = this.isPackageLookupActive; - this.isPackageLookupActive = true; - try { - char[] singleName = compoundName[compoundName.length-1]; - PackageBinding parent = currentBinding != null ? currentBinding.parent : null; - for (ModuleBinding moduleBinding : otherRelevantModules(declaringModuleNames)) { - if (!moduleBinding.isPackageLookupActive) { - PackageBinding nextBinding = parent != null - ? moduleBinding.getVisiblePackage(parent, singleName, false) - : moduleBinding.getVisiblePackage(compoundName, false); - currentBinding = SplitPackageBinding.combine(nextBinding, currentBinding, this); - } - } - return currentBinding; - } finally { - this.isPackageLookupActive = save; + for (ModuleBinding moduleBinding : otherRelevantModules(declaringModuleNames)) { + PlainPackageBinding nextBinding = moduleBinding.getDeclaredPackage(CharOperation.concatWith(compoundName, '.')); + currentBinding = SplitPackageBinding.combine(nextBinding, currentBinding, this); } + return currentBinding; } List<ModuleBinding> otherRelevantModules(char[][] declaringModuleNames) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java index 0bd0e50cbb..de338d86be 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java @@ -25,7 +25,7 @@ import org.eclipse.jdt.internal.compiler.env.IModuleAwareNameEnvironment; import org.eclipse.jdt.internal.compiler.util.HashtableOfPackage; import org.eclipse.jdt.internal.compiler.util.HashtableOfType; -public class PackageBinding extends Binding implements TypeConstants { +public abstract class PackageBinding extends Binding implements TypeConstants { public long tagBits = 0; // See values in the interface TagBits below public char[][] compoundName; @@ -35,7 +35,7 @@ public class PackageBinding extends Binding implements TypeConstants { /** Types in this map are either uniquely visible in the current module or ProblemReferenceBindings. */ public HashtableOfType knownTypes; /** All visible member packages, i.e. observable packages associated with modules read by the current module. */ - HashtableOfPackage knownPackages; + HashtableOfPackage<PackageBinding> knownPackages; // code representing the default that has been defined for this package (using @NonNullByDefault) // one of Binding.{NO_NULL_DEFAULT,NULL_UNSPECIFIED_BY_DEFAULT,NONNULL_BY_DEFAULT} @@ -46,12 +46,12 @@ public class PackageBinding extends Binding implements TypeConstants { /** Is this package exported from its module? NB: to query this property use {@link #isExported()} to ensure initialization. */ Boolean isExported; -protected PackageBinding() { +protected PackageBinding(char[][] compoundName, LookupEnvironment environment) { // for creating problem package + this.compoundName = compoundName; + this.environment = environment; } -public PackageBinding(char[] topLevelPackageName, LookupEnvironment environment, ModuleBinding enclosingModule) { - this(new char[][] {topLevelPackageName}, null, environment, enclosingModule); -} + /* Create a normal package. */ public PackageBinding(char[][] compoundName, PackageBinding parent, LookupEnvironment environment, ModuleBinding enclosingModule) { @@ -59,7 +59,7 @@ public PackageBinding(char[][] compoundName, PackageBinding parent, LookupEnviro this.parent = parent; this.environment = environment; this.knownTypes = null; // initialized if used... class counts can be very large 300-600 - this.knownPackages = new HashtableOfPackage(3); // sub-package counts are typically 0-3 + this.knownPackages = new HashtableOfPackage<PackageBinding>(3); // sub-package counts are typically 0-3 if (compoundName != CharOperation.NO_CHAR_CHAR) checkIfNullAnnotationPackage(); @@ -73,9 +73,6 @@ public PackageBinding(char[][] compoundName, PackageBinding parent, LookupEnviro throw new IllegalStateException("Package should have an enclosing module"); //$NON-NLS-1$ } -public PackageBinding(LookupEnvironment environment) { - this(CharOperation.NO_CHAR_CHAR, null, environment, environment.module); -} protected void addNotFoundPackage(char[] simpleName) { if (!this.environment.suppressImportErrors) this.knownPackages.put(simpleName, LookupEnvironment.TheNotFoundPackage); @@ -226,6 +223,17 @@ ReferenceBinding getType0(char[] name) { return null; return this.knownTypes.get(name); } + +/** + * Test if this package (or any of its incarnations in case of a SplitPackageBinding) has recorded + * an actual, resolved type of the given name (based on answers from getType0()). + * Useful for clash detection. + */ +boolean hasType0Any(char[] name) { + ReferenceBinding type0 = getType0(name); + return type0 != null && type0 != LookupEnvironment.TheNotFoundType && !(type0 instanceof UnresolvedReferenceBinding); +} + /* Answer the package or type named name; ask the oracle if it is not in the cache. * Answer null if it could not be resolved. * @@ -258,8 +266,8 @@ public Binding getTypeOrPackage(char[] name, ModuleBinding mod, boolean splitPac PackageBinding packageBinding = getPackage0(name); if (packageBinding != null && packageBinding != LookupEnvironment.TheNotFoundPackage) { - if (!splitPackageAllowed && packageBinding instanceof SplitPackageBinding) { - return ((SplitPackageBinding) packageBinding).getVisibleFor(mod, false); + if (!splitPackageAllowed) { + return packageBinding.getVisibleFor(mod, false, false); } return packageBinding; } @@ -284,8 +292,8 @@ public Binding getTypeOrPackage(char[] name, ModuleBinding mod, boolean splitPac if (packageBinding == null) { // have not looked for it before if ((packageBinding = findPackage(name, mod)) != null) { - if (!splitPackageAllowed && packageBinding instanceof SplitPackageBinding) { - return ((SplitPackageBinding) packageBinding).getVisibleFor(mod, false); + if (!splitPackageAllowed) { + return packageBinding.getVisibleFor(mod, false, false); } return packageBinding; } @@ -433,15 +441,23 @@ public boolean isExported() { } /** * If this package is uniquely visible to 'module' return a plain PackageBinding. - * In case of a conflict between a local package and foreign package - * the plain local package is returned, because this conflict will more - * appropriately be reported against the package declaration, not its references. + * In case of a conflict between a local package and foreign package flag <b>preferLocal</b> + * will select the behavior: + * <ul> + * <li>if {@code true} the plain local package is returned, because this conflict will more + * appropriately be reported against the package declaration, not its references.</li> + * <li>if {@code false} a conflict local vs. foreign will be treated just like any other conflict, + * see next.</li> + * </ul> * In case of multiple accessible foreign packages a SplitPackageBinding is returned * to indicate a conflict. */ -public PackageBinding getVisibleFor(ModuleBinding module, boolean preferLocal) { +public PackageBinding getVisibleFor(ModuleBinding module, boolean preferLocal, boolean skipCUcheck) { return this; } + +public abstract PlainPackageBinding getIncarnation(ModuleBinding moduleBinding); + public boolean hasCompilationUnit(boolean checkCUs) { if (this.knownTypes != null) { for (ReferenceBinding knownType : this.knownTypes.valueTable) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PlainPackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PlainPackageBinding.java new file mode 100644 index 0000000000..97ea1a2bef --- /dev/null +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PlainPackageBinding.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2019 GK Software SE, and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Stephan Herrmann - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.core.compiler.CharOperation; + +/** A package binding that is known not to be a {@link SplitPackageBinding}. */ +public class PlainPackageBinding extends PackageBinding { + + /** Create a toplevel package. */ + public PlainPackageBinding(char[] topLevelPackageName, LookupEnvironment environment, ModuleBinding enclosingModule) { + super(new char[][] {topLevelPackageName}, null, environment, enclosingModule); + } + + /** Create a default package. */ + public PlainPackageBinding(LookupEnvironment environment) { + super(CharOperation.NO_CHAR_CHAR, null, environment, environment.module); + } + + /** Create a normal package. */ + public PlainPackageBinding(char[][] compoundName, PackageBinding parent, LookupEnvironment environment, ModuleBinding enclosingModule) { + super(compoundName, parent, environment, enclosingModule); + } + + protected PlainPackageBinding(char[][] compoundName, LookupEnvironment environment) { + // for problem bindings + super(compoundName, environment); + } + + @Override + public PlainPackageBinding getIncarnation(ModuleBinding moduleBinding) { + if (this.enclosingModule == moduleBinding) + return this; + return null; + } +} diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemPackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemPackageBinding.java index d531a62baa..efe9f8b301 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemPackageBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemPackageBinding.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -13,23 +13,22 @@ *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; -public class ProblemPackageBinding extends PackageBinding { +public class ProblemPackageBinding extends PlainPackageBinding { private int problemId; // NOTE: must only answer the subset of the name related to the problem ProblemPackageBinding(char[][] compoundName, int problemId, LookupEnvironment environment) { - this.compoundName = compoundName; + super(compoundName, environment); this.problemId = problemId; - this.environment = environment; } ProblemPackageBinding(char[] name, int problemId, LookupEnvironment environment) { this(new char[][] {name}, problemId, environment); } -/* API -* Answer the problem id associated with the receiver. -* NoError if the receiver is a valid binding. -*/ - +/** + * API + * Answer the problem id associated with the receiver. + * NoError if the receiver is a valid binding. + */ @Override public final int problemId() { return this.problemId; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceModuleBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceModuleBinding.java index ee5fd9a20e..76d92b2830 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceModuleBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceModuleBinding.java @@ -119,14 +119,14 @@ public class SourceModuleBinding extends ModuleBinding { } @Override - public PackageBinding[] getExports() { + public PlainPackageBinding[] getExports() { // don't rely on "if (this.exportedPackages == Binding.NO_PACKAGES)" - could have been modified by completeIfNeeded() this.scope.referenceContext.moduleDeclaration.resolvePackageDirectives(this.scope); return super.getExports(); } @Override - public PackageBinding[] getOpens() { + public PlainPackageBinding[] getOpens() { // don't rely on "if (this.openedPackages == Binding.NO_PACKAGES)" - could have been modified by completeIfNeeded() this.scope.referenceContext.moduleDeclaration.resolvePackageDirectives(this.scope); return super.getOpens(); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SplitPackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SplitPackageBinding.java index 8bb5266322..44bab26bc9 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SplitPackageBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SplitPackageBinding.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 GK Software SE, and others. + * Copyright (c) 2017, 2019 GK Software SE, and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -21,7 +21,7 @@ import org.eclipse.jdt.core.compiler.CharOperation; public class SplitPackageBinding extends PackageBinding { Set<ModuleBinding> declaringModules; - public Set<PackageBinding> incarnations; + public Set<PlainPackageBinding> incarnations; /** * Combine two potential package bindings, answering either the better of those if the other has a problem, @@ -71,14 +71,14 @@ public class SplitPackageBinding extends PackageBinding { if (packageBinding instanceof SplitPackageBinding) { SplitPackageBinding split = (SplitPackageBinding) packageBinding; this.declaringModules.addAll(split.declaringModules); - for(PackageBinding incarnation: split.incarnations) { + for(PlainPackageBinding incarnation: split.incarnations) { if(this.incarnations.add(incarnation)) { incarnation.addWrappingSplitPackageBinding(this); } } - } else { + } else if (packageBinding instanceof PlainPackageBinding) { this.declaringModules.add(packageBinding.enclosingModule); - if(this.incarnations.add(packageBinding)) { + if(this.incarnations.add((PlainPackageBinding) packageBinding)) { packageBinding.addWrappingSplitPackageBinding(this); } } @@ -92,31 +92,32 @@ public class SplitPackageBinding extends PackageBinding { PackageBinding visible = this.knownPackages.get(simpleName); visible = SplitPackageBinding.combine(element, visible, this.enclosingModule); this.knownPackages.put(simpleName, visible); - PackageBinding incarnation = getIncarnation(element.enclosingModule); - if (incarnation != null) - incarnation.addPackage(element, module); + + // also record the PPB's as parent-child: + PlainPackageBinding incarnation = getIncarnation(element.enclosingModule); + if (incarnation != null) { + // avoid adding an SPB as a child of a PPB: + PlainPackageBinding elementIncarnation = element.getIncarnation(element.enclosingModule); + if (elementIncarnation != null) + incarnation.addPackage(elementIncarnation, module); + } return element; } PackageBinding combineWithSiblings(PackageBinding childPackage, char[] name, ModuleBinding module) { - ModuleBinding primaryModule = childPackage != null ? childPackage.enclosingModule : this.enclosingModule; + ModuleBinding primaryModule = childPackage.enclosingModule; // see if other incarnations contribute to the child package, too: - boolean activeSave = primaryModule.isPackageLookupActive; - primaryModule.isPackageLookupActive = true; - try { - for (PackageBinding incarnation : this.incarnations) { - ModuleBinding moduleBinding = incarnation.enclosingModule; - if (moduleBinding == module) - continue; - if (childPackage.isDeclaredIn(moduleBinding)) - continue; - PackageBinding next = moduleBinding.getVisiblePackage(incarnation, name, false); - childPackage = combine(next, childPackage, primaryModule); - } - return childPackage; - } finally { - primaryModule.isPackageLookupActive = activeSave; + char[] flatName = CharOperation.concatWith(childPackage.compoundName, '.'); + for (PackageBinding incarnation : this.incarnations) { + ModuleBinding moduleBinding = incarnation.enclosingModule; + if (moduleBinding == module) + continue; + if (childPackage.isDeclaredIn(moduleBinding)) + continue; + PlainPackageBinding next = moduleBinding.getDeclaredPackage(flatName); + childPackage = combine(next, childPackage, primaryModule); } + return childPackage; } @Override @@ -190,8 +191,9 @@ public class SplitPackageBinding extends PackageBinding { return result; } - public PackageBinding getIncarnation(ModuleBinding requestedModule) { - for (PackageBinding incarnation : this.incarnations) { + @Override + public PlainPackageBinding getIncarnation(ModuleBinding requestedModule) { + for (PlainPackageBinding incarnation : this.incarnations) { if (incarnation.enclosingModule == requestedModule) return incarnation; } @@ -209,27 +211,15 @@ public class SplitPackageBinding extends PackageBinding { } @Override - ReferenceBinding getType0(char[] name) { - ReferenceBinding knownType = super.getType0(name); - if (knownType != null && !(knownType instanceof UnresolvedReferenceBinding)) - return knownType; + boolean hasType0Any(char[] name) { + if (super.hasType0Any(name)) + return true; - ReferenceBinding candidate = null; for (PackageBinding incarnation : this.incarnations) { - ReferenceBinding next = incarnation.getType0(name); - if (next != null) { - if (next.isValidBinding() && !(knownType instanceof UnresolvedReferenceBinding)) { - if (candidate != null) - return null; // unable to disambiguate without a module context - candidate = next; - } - } - } - if (candidate != null) { - addType(candidate); + if (incarnation.hasType0Any(name)) + return true; } - - return candidate; + return false; } /** Similar to getType0() but now we have a module and can ask the specific incarnation! */ @@ -266,11 +256,11 @@ public class SplitPackageBinding extends PackageBinding { } @Override - public PackageBinding getVisibleFor(ModuleBinding clientModule, boolean preferLocal) { + public PackageBinding getVisibleFor(ModuleBinding clientModule, boolean preferLocal, boolean skipCUcheck) { int visibleCount = 0; - PackageBinding unique = null; - for (PackageBinding incarnation : this.incarnations) { - if (incarnation.hasCompilationUnit(false)) { + PlainPackageBinding unique = null; + for (PlainPackageBinding incarnation : this.incarnations) { + if (skipCUcheck || incarnation.hasCompilationUnit(false)) { if (preferLocal && incarnation.enclosingModule == clientModule) { return incarnation; } else { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java index 56cdae73b7..ab054e000d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -10954,12 +10954,12 @@ public void invalidOpensStatement(OpensStatement statement, ModuleDeclaration mo statement.declarationSourceStart, statement.declarationSourceEnd); } public void invalidPackageReference(int problem, PackageVisibilityStatement ref) { - invalidPackageReference(problem, ref, ProblemSeverities.Error); -} -public void invalidPackageReference(int problem, PackageVisibilityStatement ref, int severity) { - this.handle(problem, NoArgument, 0, new String[] { CharOperation.charToString(ref.pkgName) }, severity, - ref.pkgRef.sourceStart, ref.pkgRef.sourceEnd, this.referenceContext, - this.referenceContext == null ? null : this.referenceContext.compilationResult()); + this.handle(problem, + NoArgument, + new String[] { CharOperation.charToString(ref.pkgName) }, + ref.computeSeverity(problem), + ref.pkgRef.sourceStart, + ref.pkgRef.sourceEnd); } public void duplicateModuleReference(int problem, ModuleReference ref) { this.handle(problem, diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfPackage.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfPackage.java index c504b70791..abdfce15b5 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfPackage.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfPackage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -13,13 +13,17 @@ *******************************************************************************/ package org.eclipse.jdt.internal.compiler.util; +import java.util.Arrays; +import java.util.Objects; +import java.util.stream.Collectors; + import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -public final class HashtableOfPackage { +public final class HashtableOfPackage<P extends PackageBinding> { // to avoid using Enumerations, walk the individual tables skipping nulls public char[] keyTable[]; - public PackageBinding valueTable[]; + private PackageBinding valueTable[]; public int elementSize; // number of elements in the table int threshold; @@ -35,6 +39,12 @@ public HashtableOfPackage(int size) { this.keyTable = new char[extraRoom][]; this.valueTable = new PackageBinding[extraRoom]; } +public Iterable<P> values() { + return Arrays.stream(this.valueTable) + .filter(Objects::nonNull) + .map(p -> { @SuppressWarnings("unchecked") P theP = (P)p; return theP; }) + .collect(Collectors.toList()); +} public boolean containsKey(char[] key) { int length = this.keyTable.length, index = CharOperation.hashCode(key) % length; @@ -49,14 +59,17 @@ public boolean containsKey(char[] key) { } return false; } -public PackageBinding get(char[] key) { +public P get(char[] key) { int length = this.keyTable.length, index = CharOperation.hashCode(key) % length; int keyLength = key.length; char[] currentKey; while ((currentKey = this.keyTable[index]) != null) { - if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) - return this.valueTable[index]; + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) { + @SuppressWarnings("unchecked") + P p = (P) this.valueTable[index]; + return p; + } if (++index == length) { index = 0; } @@ -84,7 +97,7 @@ public PackageBinding put(char[] key, PackageBinding value) { return value; } private void rehash() { - HashtableOfPackage newHashtable = new HashtableOfPackage(this.elementSize * 2); // double the number of expected elements + HashtableOfPackage<P> newHashtable = new HashtableOfPackage<P>(this.elementSize * 2); // double the number of expected elements char[] currentKey; for (int i = this.keyTable.length; --i >= 0;) if ((currentKey = this.keyTable[i]) != null) diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java index 5595856759..ec2e0476d2 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java @@ -887,20 +887,11 @@ private void findPackagesFromRequires(char[] prefix, boolean isMatchAllPrefix, I } /** - * @see org.eclipse.jdt.internal.compiler.env.IModuleAwareNameEnvironment#getModulesDeclaringPackage(char[][], char[], char[]) + * @see org.eclipse.jdt.internal.compiler.env.IModuleAwareNameEnvironment#getModulesDeclaringPackage(char[][], char[]) */ @Override - public char[][] getModulesDeclaringPackage(char[][] parentPackageName, char[] name, char[] moduleName) { - String[] pkgName; - if (parentPackageName == null) - pkgName = new String[] {new String(name)}; - else { - int length = parentPackageName.length; - pkgName = new String[length+1]; - for (int i = 0; i < length; i++) - pkgName[i] = new String(parentPackageName[i]); - pkgName[length] = new String(name); - } + public char[][] getModulesDeclaringPackage(char[][] packageName, char[] moduleName) { + String[] pkgName = Arrays.stream(packageName).map(String::new).toArray(String[]::new); LookupStrategy strategy = LookupStrategy.get(moduleName); switch (strategy) { case Named: @@ -1145,4 +1136,26 @@ private void findPackagesFromRequires(char[] prefix, boolean isMatchAllPrefix, I return Arrays.copyOf(sourceRoots, count); return sourceRoots; } + + @Override + public char[][] listPackages(char[] moduleName) { + switch (LookupStrategy.get(moduleName)) { + case Named: + IPackageFragmentRoot[] packageRoots = findModuleContext(moduleName); + Set<String> packages = new HashSet<>(); + for (IPackageFragmentRoot packageRoot : packageRoots) { + try { + for (IJavaElement javaElement : packageRoot.getChildren()) { + if (javaElement instanceof IPackageFragment && !((IPackageFragment) javaElement).isDefaultPackage()) + packages.add(javaElement.getElementName()); + } + } catch (JavaModelException e) { + Util.log(e, "Failed to retrieve packages from " + packageRoot); //$NON-NLS-1$ + } + } + return packages.stream().map(String::toCharArray).toArray(char[][]::new); + default: + throw new UnsupportedOperationException("can list packages only of a named module"); //$NON-NLS-1$ + } + } } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java index 3e01d29d8a..bffce17c78 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java @@ -14,10 +14,13 @@ package org.eclipse.jdt.internal.core.builder; import java.io.IOException; +import java.util.HashSet; +import java.util.Set; import java.util.function.Predicate; import java.util.zip.ZipFile; import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; @@ -254,4 +257,21 @@ public NameEnvironmentAnswer findClass(String typeName, String qualifiedPackageN return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false, null); } +@Override +public char[][] listPackages() { + Set<String> packageNames = new HashSet<>(); + IPath basePath = this.binaryFolder.getFullPath(); + try { + this.binaryFolder.accept(r -> { + if (r instanceof IFile && SuffixConstants.EXTENSION_class.equals(r.getFileExtension().toLowerCase())) { + packageNames.add(r.getParent().getFullPath().makeRelativeTo(basePath).toString().replace('/', '.')); + } + return true; + }); + } catch (CoreException e) { + Util.log(e, "Failed to scan packages of "+this.binaryFolder); //$NON-NLS-1$ + } + return packageNames.stream().map(String::toCharArray).toArray(char[][]::new); +} + } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java index 27c8f298b1..c03f8a1ffe 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java @@ -18,6 +18,7 @@ package org.eclipse.jdt.internal.core.builder; import java.io.File; import java.io.IOException; +import java.util.Arrays; import java.util.Date; import java.util.Enumeration; import java.util.function.Predicate; @@ -323,13 +324,15 @@ public boolean isPackage(String qualifiedPackageName, String moduleName) { } @Override public boolean hasCompilationUnit(String pkgName, String moduleName) { - for (Enumeration<? extends ZipEntry> e = this.zipFile.entries(); e.hasMoreElements(); ) { - String fileName = e.nextElement().getName(); - if (fileName.startsWith(pkgName) - && fileName.toLowerCase().endsWith(SuffixConstants.SUFFIX_STRING_class) - && fileName.indexOf('/', pkgName.length()+1) == -1) - return true; - } + if (scanContent()) { + for (Enumeration<? extends ZipEntry> e = this.zipFile.entries(); e.hasMoreElements(); ) { + String fileName = e.nextElement().getName(); + if (fileName.startsWith(pkgName) + && fileName.toLowerCase().endsWith(SuffixConstants.SUFFIX_STRING_class) + && fileName.indexOf('/', pkgName.length()+1) == -1) + return true; + } + } return false; } @@ -399,4 +402,20 @@ public Manifest getManifest() { } return null; } +@Override +public char[][] listPackages() { + if (!scanContent()) // ensure zipFile is initialized + return null; + char[][] result = new char[this.knownPackageNames.elementSize][]; + int count = 0; + for (int i=0; i<this.knownPackageNames.values.length; i++) { + String string = (String) this.knownPackageNames.values[i]; + if (string != null &&!string.isEmpty()) { + result[count++] = string.replace('/', '.').toCharArray(); + } + } + if (count < result.length) + return Arrays.copyOf(result, count); + return result; +} } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java index 52cd7e0c31..891aedec64 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java @@ -25,6 +25,7 @@ import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; +import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; import org.eclipse.jdt.internal.compiler.env.IModule; @@ -186,4 +187,7 @@ public char[][] singletonModuleNameIf(boolean condition) { return new char[][] { this.module.name() }; return new char[][] { ModuleBinding.UNNAMED }; } +public char[][] listPackages() { + return CharOperation.NO_CHAR_CHAR; +} } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java index 8137e61ea8..9c6865e4a6 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java @@ -82,12 +82,31 @@ String[] directoryList(String qualifiedPackageName) { IResource[] members = ((IContainer) container).members(); dirList = new String[members.length]; int index = 0; - for (int i = 0, l = members.length; i < l; i++) { - IResource m = members[i]; - String name = m.getName(); - if (m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name)) { - // add exclusion pattern check here if we want to hide .class files - dirList[index++] = name; + if (members.length > 0) { + for (int i = 0, l = members.length; i < l; i++) { + IResource m = members[i]; + String name = m.getName(); + if (m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name)) { + // add exclusion pattern check here if we want to hide .class files + dirList[index++] = name; + } + } + } else { + container = this.sourceFolder.findMember(qualifiedPackageName); + if (container instanceof IContainer) { + members = ((IContainer) container).members(); + if (members.length > 0) { + dirList = new String[members.length]; + index = 0; + for (int i = 0, l = members.length; i < l; i++) { + IResource m = members[i]; + String name = m.getName(); + if (m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(name)) { + // FIXME: check if .java file has any declarations? + dirList[index++] = name; + } + } + } } } if (index < dirList.length) diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModulePathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModulePathEntry.java index 61161cc2ea..f3332ed0b8 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModulePathEntry.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModulePathEntry.java @@ -121,6 +121,18 @@ public class ModulePathEntry implements IModulePathEntry { return false; } + @Override + public char[][] listPackages() { + char[][] packages = CharOperation.NO_CHAR_CHAR; + if (this.isAutomaticModule) { + for (ClasspathLocation cp : this.locations) { + packages = CharOperation.arrayConcat(packages, cp.listPackages()); + } + return packages; + } + return packages; + } + /** * Combines an IMultiModuleEntry with further locations in order to support patch-module. * Implemented by adding IMultiModuleEntry functionality to ModulePathEntry. diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java index ba00f5f45c..d94b9ac094 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java @@ -561,8 +561,8 @@ public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName, cha } @Override -public char[][] getModulesDeclaringPackage(char[][] parentPackageName, char[] name, char[] moduleName) { - String pkgName = new String(CharOperation.concatWith(parentPackageName, name, '/')); +public char[][] getModulesDeclaringPackage(char[][] packageName, char[] moduleName) { + String pkgName = new String(CharOperation.concatWith(packageName, '/')); String modName = new String(moduleName); LookupStrategy strategy = LookupStrategy.get(moduleName); switch (strategy) { @@ -685,7 +685,19 @@ public boolean isPackage(String qualifiedPackageName, char[] moduleName) { } return false; } - +@Override +public char[][] listPackages(char[] moduleName) { + LookupStrategy strategy = LookupStrategy.get(moduleName); + switch (strategy) { + case Named: + IModulePathEntry entry = this.modulePathEntries.get(String.valueOf(moduleName)); + if (entry == null) + return CharOperation.NO_CHAR_CHAR; + return entry.listPackages(); + default: + throw new UnsupportedOperationException("can list packages only of a named module"); //$NON-NLS-1$ + } +} void setNames(String[] typeNames, SourceFile[] additionalFiles) { // convert the initial typeNames to a set if (typeNames == null) { diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java index 8d5a4c6045..722ce5b7f2 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2017 IBM Corporation and others. + * Copyright (c) 2005, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -45,8 +45,8 @@ import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.PlainPackageBinding; import org.eclipse.jdt.internal.compiler.lookup.PolymorphicMethodBinding; import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; @@ -500,7 +500,7 @@ public class BindingKeyResolver extends BindingKeyParser { @Override public void consumePackage(char[] pkgName) { this.compoundName = CharOperation.splitOn('/', pkgName); - this.compilerBinding = new PackageBinding(this.compoundName, null, this.environment, this.environment.module); //TODO(SHMOD) enclosingModule + this.compilerBinding = new PlainPackageBinding(this.compoundName, null, this.environment, this.environment.module); //TODO(SHMOD) enclosingModule } @Override diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java index db613ca5a3..083fbc04f5 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java @@ -328,8 +328,8 @@ public NameEnvironmentAnswer findType(char[][] compoundName, char[] moduleName) } @Override -public char[][] getModulesDeclaringPackage(char[][] parentPackageName, char[] packageName, char[] moduleName) { - String qualifiedPackageName = String.valueOf(CharOperation.concatWith(parentPackageName, packageName, '/')); +public char[][] getModulesDeclaringPackage(char[][] packageName, char[] moduleName) { + String qualifiedPackageName = String.valueOf(CharOperation.concatWith(packageName, '/')); LookupStrategy strategy = LookupStrategy.get(moduleName); if (strategy == LookupStrategy.Named) { if (this.moduleToClassPathLocations != null) { @@ -359,6 +359,22 @@ public char[][] getModulesDeclaringPackage(char[][] parentPackageName, char[] pa } @Override +public char[][] listPackages(char[] moduleName) { LookupStrategy strategy = LookupStrategy.get(moduleName); + switch (strategy) { + case Named: + if (this.moduleLocations != null) { + ClasspathLocation location = this.moduleLocations.get(String.valueOf(moduleName)); + if (location == null) + return CharOperation.NO_CHAR_CHAR; + return location.listPackages(); + } + return CharOperation.NO_CHAR_CHAR; + default: + throw new UnsupportedOperationException("can list packages only of a named module"); //$NON-NLS-1$ + } +} + +@Override public boolean hasCompilationUnit(char[][] qualifiedPackageName, char[] moduleName, boolean checkCUs) { String qualifiedPackageNameString = String.valueOf(CharOperation.concatWith(qualifiedPackageName, '/')); LookupStrategy strategy = LookupStrategy.get(moduleName); |