Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dependent Projects with multiple source and output folders not handled (on Mars SR 1) #162

Closed
hennito opened this issue Jan 18, 2016 · 6 comments

Comments

@hennito
Copy link

hennito commented Jan 18, 2016

On a big project that consists of many projects each having different source folders and each source folder having its own output folder.
The groovy compiler only has access to the default output folder of each project. This leads to class not found exceptions in projects depending on classes that are not found in the default output folder.

Steps to reproduce:

The attached zip file contains 2 eclipse projects spock-concept and spock-concept-sub. Import them in eclipse (I used Mars SR1). And try to run
/spock-concept-sub/src/test/java/sub/ValueHolderUserSpec.groovy
This project has an internal groovy compiler error because it does not find the trait ValueHolderAware from its separate output source folder of the dependent project.

groovy-eclipse-issue.zip

@eric-milles
Copy link
Member

I pulled this project down and made some tweaks to the .classpath and .project files so there is a true dependency between them. I tried to upload that but the form won't recognize my zip file...

What I am seeing is that the Java sources work correctly, finding classes from multiple output locations. The Groovy source in the dependent project however is running into this error:

Internal Groovy Error --- exception in phase 'canonicalization' in source unit 'C:\Users\U0076777\pde-workspaceg\eclipse-space\spock-concept-sub\src\test\java\sub\ValueHolderUserSpec.groovy' JDTClassNode.getTypeClass() cannot locate class for core.ValueHolderAware using transform loader groovy.lang.GroovyClassLoader@50293e16

!ENTRY org.eclipse.jdt.core 4 4 BUG! exception in phase 'canonicalization' in source unit 'C:\Users\U0076777\pde-workspaceg\eclipse-space\spock-concept-sub\src\test\java\sub\ValueHolderUserSpec.groovy' JDTClassNode.getTypeClass() cannot locate class for core.ValueHolderAware using transform loader groovy.lang.GroovyClassLoader@50293e16
    at org.codehaus.jdt.groovy.internal.compiler.ast.JDTClassNode.getTypeClass(JDTClassNode.java:716)
    at org.codehaus.groovy.ast.ClassNode.getTypeClass(ClassNode.java:1501)
    at org.codehaus.groovy.transform.trait.Traits.findHelpers(Traits.java:128)
    at org.codehaus.groovy.transform.trait.TraitComposer.doExtendTraits(TraitComposer.java:104)
    at org.codehaus.groovy.control.CompilationUnit$11.call(CompilationUnit.java:216)
    at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1201)
    at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:665)
    at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:643)
    at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:620)
    at org.codehaus.jdt.groovy.internal.compiler.ast.GroovyCompilationUnitDeclaration.processToPhase(GroovyCompilationUnitDeclaration.java:214)
    at org.codehaus.jdt.groovy.internal.compiler.ast.GroovyCompilationUnitDeclaration.analyseCode(GroovyCompilationUnitDeclaration.java:718)
    at org.eclipse.jdt.internal.compiler.Compiler.process(Compiler.java:932)
    at org.eclipse.jdt.internal.compiler.ProcessTaskManager.run(ProcessTaskManager.java:141)
    at java.lang.Thread.run(Thread.java:745)

Is this the same error you have run into? Or do you have a different error?

@eric-milles
Copy link
Member

I'm looking at CompilerUtils in the JDT core project, and that does indeed look like the right place to make a change. Andy commented in there that multiple output paths should be handled but were not. Within computeDependenciesFromProject, source classpath entries from the dependent project are explicitly skipped. I think that is the bit that needs alteration. Although it is not 100% clear what to do since the exported attribute on the project sourcepath entries is false.

@eric-milles
Copy link
Member

eric-milles commented Nov 17, 2016

Your change does look correct. If you don't mind, I incorporated the check into the classpath entry loop. Could I go with this version and you close your merge request?

    private static void computeDependenciesFromProject(IProject baseProject, String otherProject, Set<String> accumulatedPathEntries)
            throws JavaModelException {

        IProject iproject = baseProject.getWorkspace().getRoot().getProject(otherProject);
        IJavaProject iJavaProject = JavaCore.create(iproject);

        // add the project's output location
        accumulatedPathEntries.add(pathToString(iJavaProject.getOutputLocation(), iproject));

        IClasspathEntry[] cpes = iJavaProject.getResolvedClasspath(true);
        if (cpes != null) {
            for (IClasspathEntry cpe : cpes) {
                if (cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE && cpe.getOutputLocation() != null) {
                    // add the source folder's output location (if different from the project's)
                    accumulatedPathEntries.add(pathToString(cpe.getOutputLocation(), iproject));
                } else if (cpe.isExported()) {
                    IPath cpePath = cpe.getPath();
                    String segmentZero = cpePath.segment(0);
                    if (segmentZero != null && segmentZero.equals(otherProject)) {
                        accumulatedPathEntries.add(iproject.getFile(cpePath.removeFirstSegments(1)).getRawLocation().toOSString());
                    } else if (cpe.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
                        // segmentZero is a project name
                        computeDependenciesFromProject(baseProject, segmentZero, accumulatedPathEntries);
                    } else {
                        String otherPathElement = null;
                        if (segmentZero != null && segmentZero.equals(iproject.getName())) {
                            otherPathElement = iproject.getFile(cpePath.removeFirstSegments(1)).getRawLocation().toOSString();
                        } else {
                            otherPathElement = cpePath.toOSString();
                        }
                        accumulatedPathEntries.add(otherPathElement);
                    }
                }
            }
        }
    }

@hennito
Copy link
Author

hennito commented Nov 18, 2016

Thanks a lot for taking care of this one :)

This looks good to me, please go ahead with your solution. I'll close the pull request.

@eric-milles
Copy link
Member

Can you try with the latest snapshot and close if resolved?

@hennito
Copy link
Author

hennito commented Nov 21, 2016

This looks good, the code compiles now.
Thanks a bunch!

@hennito hennito closed this as completed Nov 21, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants