Skip to content

Commit 3e46a17

Browse files
NaiveASTFlattener causes ClassCastException for target modules (eclipse-jdt#4261)
In NaiveASTFlattener visit methods(ExportsDirective, OpensDirective and ProvidesDirective causes ClassCastException for target modules Fixes: eclipse-jdt#4234
1 parent e9f2f83 commit 3e46a17

2 files changed

Lines changed: 150 additions & 19 deletions

File tree

org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterTest2.java

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import java.io.IOException;
1717
import java.util.Arrays;
18+
import java.util.HashMap;
1819
import java.util.Hashtable;
1920
import java.util.Iterator;
2021
import java.util.List;
@@ -31,6 +32,7 @@
3132
import org.eclipse.jdt.core.tests.model.ReconcilerTests;
3233
import org.eclipse.jdt.core.tests.util.Util;
3334
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
35+
import org.eclipse.jdt.internal.core.dom.NaiveASTFlattener;
3436

3537
@SuppressWarnings({"rawtypes", "unchecked"})
3638
public class ASTConverterTest2 extends ConverterTestSetup {
@@ -5514,4 +5516,122 @@ public void test0610() throws CoreException {
55145516
}
55155517
}
55165518

5519+
public void testBug4234_01() throws CoreException {
5520+
String source = """
5521+
module a {
5522+
exports pack to b;
5523+
}
5524+
""";
5525+
5526+
ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
5527+
parser.setKind(ASTParser.K_COMPILATION_UNIT);
5528+
parser.setUnitName("module-info.java");
5529+
5530+
Map<String, String> options = new HashMap<>();
5531+
options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.latestSupportedJavaVersion());
5532+
options.put(JavaCore.COMPILER_SOURCE, JavaCore.latestSupportedJavaVersion());
5533+
options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.latestSupportedJavaVersion());
5534+
parser.setCompilerOptions(options);
5535+
5536+
parser.setSource(source.toCharArray());
5537+
parser.setResolveBindings(false);
5538+
parser.setStatementsRecovery(false);
5539+
parser.setBindingsRecovery(false);
5540+
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
5541+
ModuleDeclaration module = cu.getModule();
5542+
5543+
ExportsDirective export = null;
5544+
for (Object directive : module.moduleStatements()) {
5545+
if (directive instanceof ExportsDirective) {
5546+
export = (ExportsDirective) directive;
5547+
break;
5548+
}
5549+
}
5550+
assertNotNull("ExportsDirective not found", export);
5551+
5552+
NaiveASTFlattener flattener = new NaiveASTFlattener();
5553+
export.accept(flattener);
5554+
assertEquals("exports pack to b;\n", flattener.getResult());
5555+
}
5556+
5557+
public void testBug4234_02() throws CoreException {
5558+
String source = """
5559+
module a {
5560+
opens pack to b;
5561+
}
5562+
""";
5563+
5564+
ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
5565+
parser.setKind(ASTParser.K_COMPILATION_UNIT);
5566+
parser.setUnitName("module-info.java");
5567+
5568+
Map<String, String> options = new HashMap<>();
5569+
options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.latestSupportedJavaVersion());
5570+
options.put(JavaCore.COMPILER_SOURCE, JavaCore.latestSupportedJavaVersion());
5571+
options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.latestSupportedJavaVersion());
5572+
parser.setCompilerOptions(options);
5573+
5574+
parser.setSource(source.toCharArray());
5575+
parser.setResolveBindings(false);
5576+
parser.setStatementsRecovery(false);
5577+
parser.setBindingsRecovery(false);
5578+
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
5579+
ModuleDeclaration module = cu.getModule();
5580+
5581+
OpensDirective opens = null;
5582+
for (Object directive : module.moduleStatements()) {
5583+
if (directive instanceof OpensDirective) {
5584+
opens = (OpensDirective) directive;
5585+
break;
5586+
}
5587+
}
5588+
assertNotNull("OpensDirective not found", opens);
5589+
5590+
NaiveASTFlattener flattener = new NaiveASTFlattener();
5591+
opens.accept(flattener);
5592+
assertEquals("opens pack to b;\n", flattener.getResult());
5593+
}
5594+
5595+
public void testBug4234_03() throws CoreException {
5596+
String source = """
5597+
module a {
5598+
provides java.util.spi.ResourceBundleProvider
5599+
with com.example.MyProvider, com.example.AltProvider;
5600+
}
5601+
""";
5602+
5603+
ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
5604+
parser.setKind(ASTParser.K_COMPILATION_UNIT);
5605+
parser.setUnitName("module-info.java");
5606+
5607+
Map<String, String> options = new HashMap<>();
5608+
options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.latestSupportedJavaVersion());
5609+
options.put(JavaCore.COMPILER_SOURCE, JavaCore.latestSupportedJavaVersion());
5610+
options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.latestSupportedJavaVersion());
5611+
parser.setCompilerOptions(options);
5612+
5613+
parser.setSource(source.toCharArray());
5614+
parser.setResolveBindings(false);
5615+
parser.setStatementsRecovery(false);
5616+
parser.setBindingsRecovery(false);
5617+
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
5618+
ModuleDeclaration module = cu.getModule();
5619+
5620+
ProvidesDirective provides = null;
5621+
for (Object directive : module.moduleStatements()) {
5622+
if (directive instanceof ProvidesDirective) {
5623+
provides = (ProvidesDirective) directive;
5624+
break;
5625+
}
5626+
}
5627+
assertNotNull("ProvidesDirective not found", provides);
5628+
5629+
NaiveASTFlattener flattener = new NaiveASTFlattener();
5630+
provides.accept(flattener);
5631+
5632+
// Note: Flattener output has no newlines
5633+
String expected = "provides java.util.spi.ResourceBundleProvider with com.example.MyProvider, com.example.AltProvider;\n";
5634+
assertEquals(expected, flattener.getResult());
5635+
}
5636+
55175637
}

org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -243,19 +243,6 @@ void printModifiers(List ext) {
243243
}
244244
}
245245

246-
private void printTypes(List<Type> types, String prefix) {
247-
if (types.size() > 0) {
248-
this.buffer.append(" " + prefix + " ");//$NON-NLS-1$ //$NON-NLS-2$
249-
Type type = types.get(0);
250-
type.accept(this);
251-
for (int i = 1, l = types.size(); i < l; ++i) {
252-
this.buffer.append(","); //$NON-NLS-1$
253-
type = types.get(0);
254-
type.accept(this);
255-
}
256-
}
257-
}
258-
259246
/**
260247
* reference node helper function that is common to all
261248
* the difference reference nodes.
@@ -1231,12 +1218,23 @@ public boolean visit(ModuleModifier node) {
12311218
}
12321219

12331220
private boolean visit(ModulePackageAccess node, String keyword) {
1234-
printIndent();
12351221
this.buffer.append(keyword);
1236-
this.buffer.append(" ");//$NON-NLS-1$
1237-
node.getName().accept(this);
1238-
printTypes(node.modules(), "to"); //$NON-NLS-1$
1239-
this.buffer.append(";\n");//$NON-NLS-1$
1222+
if (node.getName() != null) {
1223+
this.buffer.append(' ');
1224+
node.getName().accept(this);
1225+
}
1226+
// Handle target modules as Names instead of Types
1227+
if (!node.modules().isEmpty()) {
1228+
this.buffer.append(" to "); //$NON-NLS-1$
1229+
for (Iterator it = node.modules().iterator(); it.hasNext(); ) {
1230+
Name moduleName = (Name) it.next();
1231+
moduleName.accept(this);
1232+
if (it.hasNext()) {
1233+
this.buffer.append(","); //$NON-NLS-1$
1234+
}
1235+
}
1236+
this.buffer.append(";\n"); //$NON-NLS-1$
1237+
}
12401238
return false;
12411239
}
12421240

@@ -1359,7 +1357,20 @@ public boolean visit(ProvidesDirective node) {
13591357
this.buffer.append("provides");//$NON-NLS-1$
13601358
this.buffer.append(" ");//$NON-NLS-1$
13611359
node.getName().accept(this);
1362-
printTypes(node.implementations(), "with"); //$NON-NLS-1$
1360+
1361+
// Replace printTypes() with proper Name handling
1362+
List implementations = node.implementations();
1363+
if (!implementations.isEmpty()) {
1364+
this.buffer.append(" with ");//$NON-NLS-1$
1365+
for (Iterator it = implementations.iterator(); it.hasNext(); ) {
1366+
Name implName = (Name) it.next();
1367+
implName.accept(this);
1368+
if (it.hasNext()) {
1369+
this.buffer.append(", ");//$NON-NLS-1$
1370+
}
1371+
}
1372+
}
1373+
13631374
this.buffer.append(";\n");//$NON-NLS-1$
13641375
return false;
13651376
}

0 commit comments

Comments
 (0)