Skip to content

Commit

Permalink
[BUG] [JSR-199] ECJ cannot resolve JPMS modules if using a user-provided
Browse files Browse the repository at this point in the history
file manager

+ make ClasspathJsr199 capable of handling sources
+ consistently extract module and pass it into CUs and class readers
+ implement module extraction from JavaFileObject (src & class)
+ implement ClasspathJsr199.listPackages() using JavaFileObjects
+ detect initial / duplicate source files by JavaFileObject, not path
+ fix arg passing in ProblemReporter.invalidPackageReference()
+ implement package matching in InMemoryJavaFileManager.list() (test)

TODO:
+ exception handling
+ encoding? (currently hardcodes UTF-8)

Fixes #958
  • Loading branch information
stephan-herrmann committed Dec 24, 2024
1 parent c16af25 commit de490a0
Show file tree
Hide file tree
Showing 12 changed files with 251 additions and 91 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2021 IBM Corporation and others.
* Copyright (c) 2017, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2021 IBM Corporation and others.
* Copyright (c) 2021, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -191,7 +191,16 @@ public Iterable<JavaFileObject> list(Location location, String packageName, Set<
throws IOException {
List<JavaFileObject> result = new ArrayList<>();
if (location == StandardLocation.SOURCE_PATH && kinds.contains(Kind.SOURCE)) {
result.addAll(sources);
for (InMemoryJavaSourceFileObject sourceFileObject : sources) {
String name = sourceFileObject.getAbsClassName();
int lastDot = name.lastIndexOf('.');
if (lastDot == -1)
continue;
String packName = name.substring(0, lastDot-1);
boolean match = recurse ? packName.startsWith(packageName) : packName.equals(packageName);
if (match)
result.add(sourceFileObject);
}
}
if (super.hasLocation(location)) {
Iterable<JavaFileObject> superResult = super.list(location, packageName, kinds, recurse);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2006, 2018 BEA Systems, Inc.
* Copyright (c) 2006, 2024 BEA Systems, Inc.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -19,6 +19,7 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.HashSet;
import javax.annotation.processing.Filer;
import javax.annotation.processing.FilerException;
Expand All @@ -28,8 +29,12 @@
import javax.tools.JavaFileManager;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.StandardLocation;
import org.eclipse.jdt.internal.compiler.batch.ClasspathJsr199;
import org.eclipse.jdt.internal.compiler.batch.Main;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.IModule;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;

/**
Expand All @@ -43,13 +48,30 @@ public class BatchFilerImpl implements Filer {
protected final BatchProcessingEnvImpl _env;
protected final JavaFileManager _fileManager;
protected final HashSet<URI> _createdFiles;
protected String _moduleName;

public BatchFilerImpl(BaseAnnotationProcessorManager dispatchManager, BatchProcessingEnvImpl env)
public BatchFilerImpl(BaseAnnotationProcessorManager dispatchManager, BatchProcessingEnvImpl env, Main main)
{
this._dispatchManager = dispatchManager;
this._fileManager = env._fileManager;
this._env = env;
this._createdFiles = new HashSet<>();
if (this._fileManager.hasLocation(StandardLocation.SOURCE_PATH)) {
try {
for (JavaFileObject javaFileObject : this._fileManager.list(StandardLocation.SOURCE_PATH, "", //$NON-NLS-1$
Collections.singleton(Kind.SOURCE), false)) {
if (javaFileObject.getName().equals(IModule.MODULE_INFO_JAVA)) {
IModule module = ClasspathJsr199.extractModuleFromFileObject(javaFileObject, main::getNewParser, null);
if (module != null)
this._moduleName = String.valueOf(module.name());
break;
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

public void addNewUnit(ICompilationUnit unit) {
Expand All @@ -74,7 +96,7 @@ public JavaFileObject createClassFile(CharSequence name,
}

this._createdFiles.add(uri);
return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this);
return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this, this._moduleName);
}

/* (non-Javadoc)
Expand Down Expand Up @@ -146,7 +168,13 @@ public JavaFileObject createSourceFile(CharSequence name,
if (typeElement != null) {
throw new FilerException("Source file already exists : " + moduleAndPkgString); //$NON-NLS-1$
}
Location location = mod == null ? StandardLocation.SOURCE_OUTPUT : this._fileManager.getLocationForModule(StandardLocation.SOURCE_OUTPUT, mod);
Location location;
if (mod == null) {
location = StandardLocation.SOURCE_OUTPUT;
mod = this._moduleName;
} else {
location = this._fileManager.getLocationForModule(StandardLocation.SOURCE_OUTPUT, mod);
}
JavaFileObject jfo = this._fileManager.getJavaFileForOutput(location, name.toString(), JavaFileObject.Kind.SOURCE, null);
URI uri = jfo.toUri();
if (this._createdFiles.contains(uri)) {
Expand All @@ -155,7 +183,7 @@ public JavaFileObject createSourceFile(CharSequence name,

this._createdFiles.add(uri);
// hook the file object's writers to create compilation unit and add to addedUnits()
return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this);
return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this, mod);
}

/* (non-Javadoc)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2006, 2023 BEA Systems, Inc.
* Copyright (c) 2006, 2024 BEA Systems, Inc.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -89,7 +89,7 @@ public BatchProcessingEnvImpl(BaseAnnotationProcessorManager dispatchManager, Ma
this._fileManager = manager;
}
this._processorOptions = Collections.unmodifiableMap(parseProcessorOptions(commandLineArguments));
this._filer = new BatchFilerImpl(this._dispatchManager, this);
this._filer = new BatchFilerImpl(this._dispatchManager, this, this._compilerOwner);
this._messager = new BatchMessagerImpl(this, this._compilerOwner);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2006, 2023 BEA Systems, Inc. and others
* Copyright (c) 2006, 2024 BEA Systems, Inc. and others
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -200,11 +200,14 @@ public String toString() {

private final String _typeName;

public HookedJavaFileObject(JavaFileObject fileObject, String fileName, String typeName, BatchFilerImpl filer) {
private final String _moduleName;

public HookedJavaFileObject(JavaFileObject fileObject, String fileName, String typeName, BatchFilerImpl filer, String module) {
super(fileObject);
this._filer = filer;
this._fileName = fileName;
this._typeName = typeName;
this._moduleName = module;
}

@SuppressWarnings("resource") // ForwardingOutputStream forwards close() too
Expand All @@ -225,8 +228,19 @@ protected void closed() {
//TODO: support encoding
switch(this.getKind()) {
case SOURCE :
CompilationUnit unit = new CompilationUnit(null, this._fileName, null /* encoding */, null, this._filer._env.shouldIgnoreOptionalProblems(this._fileName.toCharArray()), null);
this._filer.addNewUnit(unit);
try {
CompilationUnit unit = new CompilationUnit(
getCharContent(false).toString().toCharArray(),
this._fileName,
null /* encoding */,
null /* destination path */,
this._filer._env.shouldIgnoreOptionalProblems(this._fileName.toCharArray()),
this._moduleName);
this._filer.addNewUnit(unit);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case CLASS :
IBinaryType binaryType = null;
Expand Down
Loading

0 comments on commit de490a0

Please sign in to comment.