eclipse-jdt / eclipse.jdt.core

Eclipse Public License 2.0
156 stars 123 forks source link

ASTParser sometimes failing at resolving package with modules #2301

Open mickaelistria opened 5 months ago

mickaelistria commented 5 months ago

Add this to ModuleBuilderTests

    public void testAutoModule3_ASTParser() throws Exception {
        IJavaProject javaProject = null, auto = null;
        try {
            auto = createJava9Project("auto", new String[] {"src"});
            createFolder("auto/src/p/a");
            createFile("auto/src/p/a/X.java",
                "package p.a;\n" +
                "public class X {}\n;");
            createFolder("auto/META-INF");
            createFile("auto/META-INF/MANIFEST.MF",
                "Manifest-Version: 1.0\n" +
                "Automatic-Module-Name: org.eclipse.lib.x\n");

            javaProject = createJava9Project("mod.one", new String[] {"src"});
            IClasspathAttribute[] attributes = { JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true") };
            addClasspathEntry(javaProject, JavaCore.newProjectEntry(auto.getPath(), null, false, attributes, false));

            String srcMod =
                "module mod.one { \n" +
                "   requires org.eclipse.lib.x;\n" + // from manifest attribute
                "}";
            createFile("/mod.one/src/module-info.java",
                srcMod);
            createFolder("mod.one/src/q");
            String srcX =
                "package q;\n" +
                "public class X {\n" +
                "   p.a.X f;\n" +
                "}";
            createFile("/mod.one/src/q/X.java", srcX);
            auto.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);

            ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
            parser.setResolveBindings(true);
            parser.setProject(javaProject);
            parser.setSource(getWorkingCopy("/mod.one/src/q/X.java", srcX, true));
            CompilationUnit unit = (CompilationUnit) parser.createAST(null);
            assertArrayEquals(new IProblem[0], unit.getProblems());
        } finally {
            if (javaProject != null)
                deleteProject(javaProject);
            if (auto != null)
                deleteProject(auto);
        }
    }

and see it wrongly fail with

array lengths differed, expected.length=0 actual.length=1; arrays first differed at element [0]; expected:<end of array> but was:<Pb(1450) The type p.a.X is not accessible>
    at org.junit.internal.ComparisonCriteria.arrayEquals(ComparisonCriteria.java:89)
    at org.junit.internal.ComparisonCriteria.arrayEquals(ComparisonCriteria.java:28)
    at org.junit.Assert.internalArrayEquals(Assert.java:534)
    at org.junit.Assert.assertArrayEquals(Assert.java:285)
    at org.junit.Assert.assertArrayEquals(Assert.java:300)
    at org.eclipse.jdt.core.tests.model.ModuleBuilderTests.testAutoModule3_ASTParser(ModuleBuilderTests.java:5331)

When working on this with #2300, the proposed quickfix was causing a StackOverflowError that can be reproduced when applying the patch and running this from ResolveTests9

    public void testModuleInfo_ASTParser() throws CoreException {
        IFile providesFile = createFile("/Resolve/src/provides.java", "public class provides {}");
        IFile modInfo = null;
        try {
            getWorkingCopy(
                    "/Resolve/src/test/ITest.java",
                    "public interface ITest {}\n");
            getWorkingCopy(
                    "/Resolve/src/test/TestClass.java",
                    "public class TestClass implements ITest {}\n");

            this.wc = getWorkingCopy(
                    "/Resolve/src/module-info.java",
                    "module com.test {\n" +
                    "  provides p1.Y with ResolveInterface;\n" +
                    "}\n");

            ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
            parser.setResolveBindings(true);
            parser.setProject(this.currentProject);
            parser.setSource(this.wc);
            CompilationUnit unit = (CompilationUnit) parser.createAST(null);
            assertArrayEquals(new IProblem[0], unit.getProblems());
        } finally {
            deleteResource(providesFile);
            if (modInfo != null)
                deleteResource(modInfo);
        }
    }
mickaelistria commented 5 months ago

Here is another example, which can be run from ReconcilerTests9

public void testBug544306_ASTParser() throws Exception {
    if (!isJRE9)
        return;
    IJavaProject p1 = createJava9Project("p1");
    IJavaProject p2 = createJava9Project("p2");
    try {
        createFolder("p1/src/p1");
        createFile("p1/src/p1/P1.java",
                "package p1;\n" +
                "public class P1 {\n" +
                "}\n");
        createFile("p1/src/module-info.java",
                "module p1 {\n" +
                "   exports p1;\n" +
                "}\n");

        IClasspathAttribute[] testAttrs = { JavaCore.newClasspathAttribute("test", "true") };
        addClasspathEntry(p2, JavaCore.newProjectEntry(p1.getPath(), null, false, testAttrs, false));
        addClasspathEntry(p2, JavaCore.newSourceEntry(new Path("/p2/src-test"), null, null, new Path("/p2/bin-test"), testAttrs));
        createFolder("p2/src/p2");
        createFolder("p2/src-test/p2");

        createFile("p2/src/module-info.java",
                "module p2 {\n" +
                "}\n");
        String testSource = "package p2;\n" +
        "import p1.P1;\n" +
        "class Test extends P1{ }";

        createFile("p2/src-test/p2/Test.java", testSource);
        waitForAutoBuild();
        IMarker[] markers = p1.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
        assertMarkers("Unexpected markers",
                "",  markers);

        this.workingCopy.discardWorkingCopy();
        this.workingCopy = getCompilationUnit("p2/src-test/p2/Test.java").getWorkingCopy(this.wcOwner, null);
        ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
        parser.setResolveBindings(true);
        parser.setSource(this.workingCopy);
        parser.setWorkingCopyOwner(this.wcOwner);
        CompilationUnit unit = (CompilationUnit)parser.createAST(null);
        assertArrayEquals(new IProblem[0], unit.getProblems());
        this.workingCopy.discardWorkingCopy();
    } finally {
        deleteProject(p1);
        deleteProject(p2);
    }
}