eclipse-jdt / eclipse.jdt.core

Eclipse Public License 2.0
166 stars 130 forks source link

[BUG] [JSR-199] ECJ cannot resolve JPMS modules if using a user-provided file manager #958

Open ascopes opened 1 year ago

ascopes commented 1 year ago

It appears that when using ClasspathJSR199 (i.e. when a provided file manager does not implement StandardFileManager, only JavaFileManager), using a module-info.java in the root of the compilation sources does not work correctly. Automatic modules that are mentioned in requires entries are not being added to the module lookup table within the compiler, leading to errors such as the following:

module org.example {
  exports org.example;

  requires io.avaje.inject;  /* automatic module that is a JAR on both the CLASS_PATH and MODULE_PATH */

  provides io.avaje.inject.spi.Module with org.example.ExampleModule;
}
 - [ERROR] 8389908

       Cannot bind message for problem (id: 1300) "{0} cannot be resolved to a module" with arguments: {}

 - [ERROR] 16777218

       io cannot be resolved to a type

 - [ERROR] 268435846

       The import jakarta cannot be resolved

 - [ERROR] 16777218

       Singleton cannot be resolved to a type

 - [ERROR] 268435846

       The import jakarta cannot be resolved

This appears to be some sort of bug, since I can get the exact same configuration to compile successfully under Javac using the exact same configuration. If I remove the module-info.java from my test project, then this will get past this step, so it seems to be a bug in the module resolution in ECJ somewhere.

ECJ appears to be using a ClasspathJsr199 object if the FileManager is not an instance of EclipseFileManager or StandardFileManager, and my guess is that when using this flow rather than the default file manager the compiler would usually create when invoked as a standalone process, the wrong logic is being invoked to handle JARs that have an Automatic-Module-Name entry in their META-INF/MANIFEST.MF.

Thus, to replicate this, you'll need to use a JavaFileManager object that does not implement EclipseFileManager or StandardFileManager, otherwise this logic appears to be skipped.


Minimal working example (Maven project)

ecj-bugs.tar.gz

./mvnw clean package and observe the failure.

This fails because ECJ doesn't seem to support automatic module detection properly in the ClasspathJsr199 class, and this is only enabled if the StandardJavaFileManager ECJ provides is not used by the looks.

I tricked ECJ into doing this by hiding the regular standard file manager behind one that does not implement StandardJavaFileManager at all.

ascopes commented 1 year ago

Updated issue with simple working reproduction now. Can confirm it affects the ECJ file manager if you wrap it in a JavaFileManager delegate that doesn't implement StandardJavaFileManager.

ascopes commented 1 year ago

The issue seems to be that ClasspathJsr199 just delegates to the JRT to find any modules, meaning that a ClasspathJsr199 will never report that it holds modules. Seems the EclipseFileManager deals with this logic in a special way normally, which is not going to be applicable to custom file manager implementations.

Ideally, I would probably expect ClasspathJsr199 to be using the ModuleFinder to find the appropriate modules and automatic modules, or to use the file manager itself with listLocationForModules.

ascopes commented 4 months ago

Bumping to prevent this being closed from inactivity, as it is still an outstanding issue.