groovy / groovy-eclipse

Eclipse Groovy Development Tools
656 stars 193 forks source link

Problems with static inner classes and static imports #1292

Closed kriegaex closed 3 years ago

kriegaex commented 3 years ago

Situation

I have a Spock 1.3, Groovy 2.5 playground project in which for many years I have used Groovy-Eclipse as a Maven Compiler back-end. the project contains many example classes and Spock tests, mostly results of me supporting other users on StackOverflow concerning Spock and Geb. The compiler source and target levels are Java 8, the JDK running the Maven builds was also 8.

Lately, I wanted to upgrade some dependencies to more recent versions and also see if I could run the build on Java 16, but still with source/target 8. What I upgraded was:

Problem 1: cannot use static import of Java enum constant

I have this Java enum:

package de.scrum_master.stackoverflow;

import org.togglz.core.Feature;
import org.togglz.core.annotation.EnabledByDefault;
import org.togglz.core.context.FeatureContext;
import org.togglz.core.manager.FeatureManager;
import org.togglz.core.metadata.FeatureMetaData;
import org.togglz.core.repository.FeatureState;

public enum PocToggle implements Feature {
  @EnabledByDefault
  USE_MY_FEATURE;

  private FeatureManager customFeatureManager;

  void setFeatureManager(FeatureManager featureManager) {
    this.customFeatureManager = featureManager;
  }

  public boolean isActive() {
    FeatureManager featureManager = customFeatureManager != null
      ? customFeatureManager
      : FeatureContext.getFeatureManager();

    try {
      return featureManager.isActive(this);
    } catch (RuntimeException ignored) {
      System.err.println(String.format("Failed to retrieve feature '%s' state", this.name()));
      FeatureMetaData metaData = featureManager.getMetaData(this);
      FeatureState featureState = metaData.getDefaultFeatureState();
      return featureState.isEnabled();
    }
  }
}

In a Spock test (same package, but in src/test/groovy, not in src/main/java), I use this import:

import static PocToggle.USE_MY_FEATURE

This yields the compile error:

Compilation failure
Failure executing groovy-eclipse compiler:
----------
1. ERROR in C:\Users\alexa\Documents\java-src\GebSpockSamples\geb-spock-samples-powermock\src\test\groovy\de\scrum_master\stackoverflow\PocToggleTest.groovy (at line 15)
    import static PocToggle.USE_MY_FEATURE
                  ^^^^^^^^^
Groovy:unable to resolve class PocToggle
----------
1 problem (1 error)

If I replace the static import by direct enum value references, compilation passes. Before I upgraded Groovy and Groovy-Eclipse, this was not a problem-

Problem 2: cannot use static inner class

package de.scrum_master.testing

import geb.spock.GebReportingSpec
import org.openqa.selenium.WebElement
import org.openqa.selenium.interactions.*
import org.openqa.selenium.interactions.internal.Locatable
import spock.lang.Requires

import java.time.Duration

import static org.openqa.selenium.interactions.PointerInput.MouseButton.LEFT
import static spock.util.matcher.HamcrestMatchers.closeTo

class VisJsExampleIT extends GebReportingSpec {

  static class DragDropWorkaround {
    Actions dragAndDropBy(WebElement source, int xOffset, int yOffset) {
      if (isBuildingActions()) {
        action.addAction(new ClickAndHoldAction(jsonMouse, (Locatable) source))
        // The next line is a workaround for Chrome, Opera, Edge
        // but currently does not work for Chrome 75 anymore
        action.addAction(new MoveToOffsetAction(jsonMouse, null, -100, -100))
        action.addAction(new MoveToOffsetAction(jsonMouse, null, xOffset, yOffset))
        action.addAction(new ButtonReleaseAction(jsonMouse, null))
      }

      return moveInTicks(source, 0, 0)
        .tick(defaultMouse.createPointerDown(LEFT.asArg()))
        .tick(defaultMouse.createPointerMove(Duration.ofMillis(250), PointerInput.Origin.pointer(), xOffset, yOffset))
        .tick(defaultMouse.createPointerUp(LEFT.asArg()))
    }
  }

  def setupSpec() {
    Actions.mixin DragDropWorkaround
  }

}

The compiler complains:

Compilation failure
Failure executing groovy-eclipse compiler:
----------
1. ERROR in C:\Users\alexa\Documents\java-src\GebSpockSamples\geb-spock-samples\src\test\groovy\de\scrum_master\testing\VisJsExampleIT.groovy (at line 19)
    action.addAction(new ClickAndHoldAction(jsonMouse, (Locatable) source))
    ^^^^^^
Groovy:Apparent variable 'action' was found in a static scope but doesn't refer to a local variable, static field or class.
----------
2. ERROR in C:\Users\alexa\Documents\java-src\GebSpockSamples\geb-spock-samples\src\test\groovy\de\scrum_master\testing\VisJsExampleIT.groovy (at line 19)
    action.addAction(new ClickAndHoldAction(jsonMouse, (Locatable) source))
                                            ^^^^^^^^^
Groovy:Apparent variable 'jsonMouse' was found in a static scope but doesn't refer to a local variable, static field or class.
----------
3. ERROR in C:\Users\alexa\Documents\java-src\GebSpockSamples\geb-spock-samples\src\test\groovy\de\scrum_master\testing\VisJsExampleIT.groovy (at line 22)
    action.addAction(new MoveToOffsetAction(jsonMouse, null, -100, -100))
    ^^^^^^
Groovy:Apparent variable 'action' was found in a static scope but doesn't refer to a local variable, static field or class.
----------
4. ERROR in C:\Users\alexa\Documents\java-src\GebSpockSamples\geb-spock-samples\src\test\groovy\de\scrum_master\testing\VisJsExampleIT.groovy (at line 22)
    action.addAction(new MoveToOffsetAction(jsonMouse, null, -100, -100))
                                            ^^^^^^^^^
Groovy:Apparent variable 'jsonMouse' was found in a static scope but doesn't refer to a local variable, static field or class.
----------
5. ERROR in C:\Users\alexa\Documents\java-src\GebSpockSamples\geb-spock-samples\src\test\groovy\de\scrum_master\testing\VisJsExampleIT.groovy (at line 23)
    action.addAction(new MoveToOffsetAction(jsonMouse, null, xOffset, yOffset))
    ^^^^^^
Groovy:Apparent variable 'action' was found in a static scope but doesn't refer to a local variable, static field or class.
----------
6. ERROR in C:\Users\alexa\Documents\java-src\GebSpockSamples\geb-spock-samples\src\test\groovy\de\scrum_master\testing\VisJsExampleIT.groovy (at line 23)
    action.addAction(new MoveToOffsetAction(jsonMouse, null, xOffset, yOffset))
                                            ^^^^^^^^^
Groovy:Apparent variable 'jsonMouse' was found in a static scope but doesn't refer to a local variable, static field or class.
----------
7. ERROR in C:\Users\alexa\Documents\java-src\GebSpockSamples\geb-spock-samples\src\test\groovy\de\scrum_master\testing\VisJsExampleIT.groovy (at line 24)
    action.addAction(new ButtonReleaseAction(jsonMouse, null))
    ^^^^^^
Groovy:Apparent variable 'action' was found in a static scope but doesn't refer to a local variable, static field or class.
----------
8. ERROR in C:\Users\alexa\Documents\java-src\GebSpockSamples\geb-spock-samples\src\test\groovy\de\scrum_master\testing\VisJsExampleIT.groovy (at line 24)
    action.addAction(new ButtonReleaseAction(jsonMouse, null))
                                             ^^^^^^^^^
Groovy:Apparent variable 'jsonMouse' was found in a static scope but doesn't refer to a local variable, static field or class.
----------
9. ERROR in C:\Users\alexa\Documents\java-src\GebSpockSamples\geb-spock-samples\src\test\groovy\de\scrum_master\testing\VisJsExampleIT.groovy (at line 28)
    .tick(defaultMouse.createPointerDown(LEFT.asArg()))
          ^^^^^^^^^^^^
Groovy:Apparent variable 'defaultMouse' was found in a static scope but doesn't refer to a local variable, static field or class.
----------
10. ERROR in C:\Users\alexa\Documents\java-src\GebSpockSamples\geb-spock-samples\src\test\groovy\de\scrum_master\testing\VisJsExampleIT.groovy (at line 29)
    .tick(defaultMouse.createPointerMove(Duration.ofMillis(250), PointerInput.Origin.pointer(), xOffset, yOffset))
          ^^^^^^^^^^^^
Groovy:Apparent variable 'defaultMouse' was found in a static scope but doesn't refer to a local variable, static field or class.
----------
11. ERROR in C:\Users\alexa\Documents\java-src\GebSpockSamples\geb-spock-samples\src\test\groovy\de\scrum_master\testing\VisJsExampleIT.groovy (at line 30)
    .tick(defaultMouse.createPointerUp(LEFT.asArg()))
          ^^^^^^^^^^^^
Groovy:Apparent variable 'defaultMouse' was found in a static scope but doesn't refer to a local variable, static field or class.
----------
11 problems (11 errors)

If I move the inner static class to outside the Geb specification and place it in the same source file, but as a "sibling" of the test class rather than a "child" like this: compilation succeeds:

package de.scrum_master.testing

import geb.spock.GebReportingSpec
import org.openqa.selenium.WebElement
import org.openqa.selenium.interactions.*
import org.openqa.selenium.interactions.internal.Locatable
import spock.lang.Requires

import java.time.Duration

import static org.openqa.selenium.interactions.PointerInput.MouseButton.LEFT
import static spock.util.matcher.HamcrestMatchers.closeTo

class VisJsExampleIT extends GebReportingSpec {

  def setupSpec() {
    Actions.mixin DragDropWorkaround
  }

}

class DragDropWorkaround {
  Actions dragAndDropBy(WebElement source, int xOffset, int yOffset) {
    if (isBuildingActions()) {
      action.addAction(new ClickAndHoldAction(jsonMouse, (Locatable) source))
      // The next line is a workaround for Chrome, Opera, Edge
      // but currently does not work for Chrome 75 anymore
      action.addAction(new MoveToOffsetAction(jsonMouse, null, -100, -100))
      action.addAction(new MoveToOffsetAction(jsonMouse, null, xOffset, yOffset))
      action.addAction(new ButtonReleaseAction(jsonMouse, null))
    }

    return moveInTicks(source, 0, 0)
      .tick(defaultMouse.createPointerDown(LEFT.asArg()))
      .tick(defaultMouse.createPointerMove(Duration.ofMillis(250), PointerInput.Origin.pointer(), xOffset, yOffset))
      .tick(defaultMouse.createPointerUp(LEFT.asArg()))
  }
}

After applying those two workaround, I can build with JDK 16 with Maven.

Problem 3: problems compiling in IntelliJ IDEA

I still cannot compile when building in IntelliJ IDEA. I am not sure it is related to the other issues or out of scope (see IDEA-275889), but I want to mention it: I guess the root cause is that IDEA somehow does not pass through source/target correctly, producing Java 16 class files (major 60) which the ASM version contained in the Groovy compiler does not recognise.

Groovyc: While compiling [tests of geb-spock-samples]: Groovyc stub generation failed
Groovyc: While compiling [tests of geb-spock-samples]: java.lang.IllegalArgumentException: Unsupported class file major version 60
    at groovyjarjarasm.asm.ClassReader.<init>(ClassReader.java:196)
    at groovyjarjarasm.asm.ClassReader.<init>(ClassReader.java:177)
    at groovyjarjarasm.asm.ClassReader.<init>(ClassReader.java:163)
    at groovyjarjarasm.asm.ClassReader.<init>(ClassReader.java:284)
    at org.codehaus.groovy.ast.decompiled.AsmDecompiler.parseClass(AsmDecompiler.java:81)
    at org.codehaus.groovy.control.ClassNodeResolver.findDecompiled(ClassNodeResolver.java:251)
    at org.codehaus.groovy.control.ClassNodeResolver.tryAsLoaderClassOrScript(ClassNodeResolver.java:189)
    at org.codehaus.groovy.control.ClassNodeResolver.findClassNode(ClassNodeResolver.java:169)
    at org.codehaus.groovy.control.ClassNodeResolver.resolveName(ClassNodeResolver.java:125)
    at org.codehaus.groovy.control.ResolveVisitor.resolveToOuter(ResolveVisitor.java:853)
    at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:467)
    at org.codehaus.groovy.control.ResolveVisitor.resolveFromDefaultImports(ResolveVisitor.java:629)
    at org.codehaus.groovy.control.ResolveVisitor.resolveFromDefaultImports(ResolveVisitor.java:612)
    at org.codehaus.groovy.control.ResolveVisitor.resolveFromDefaultImports(ResolveVisitor.java:586)
    at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:465)
    at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:428)
    at org.codehaus.groovy.control.ResolveVisitor.resolveOrFail(ResolveVisitor.java:343)
    at org.codehaus.groovy.control.ResolveVisitor.resolveOrFail(ResolveVisitor.java:424)
    at org.codehaus.groovy.control.ResolveVisitor.visitConstructorOrMethod(ResolveVisitor.java:246)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitMethod(ClassCodeVisitorSupport.java:132)
    at org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:1103)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClass(ClassCodeVisitorSupport.java:54)
    at org.codehaus.groovy.control.ResolveVisitor.visitClass(ResolveVisitor.java:1465)
    at org.codehaus.groovy.control.ResolveVisitor.startResolving(ResolveVisitor.java:230)
    at org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit$1.call(JavaAwareCompilationUnit.java:74)
    at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1084)
    at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:640)
    at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:618)
    at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:595)
    at org.jetbrains.groovy.compiler.rt.GroovyCompilerWrapper.compile(GroovyCompilerWrapper.java:48)
    at org.jetbrains.groovy.compiler.rt.DependentGroovycRunner.runGroovyc(DependentGroovycRunner.java:118)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.jetbrains.groovy.compiler.rt.GroovycRunner.intMain2(GroovycRunner.java:81)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.jetbrains.jps.incremental.groovy.InProcessGroovyc.runGroovycInThisProcess(InProcessGroovyc.java:167)
    at org.jetbrains.jps.incremental.groovy.InProcessGroovyc.lambda$runGroovyc$0(InProcessGroovyc.java:77)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    at java.base/java.lang.Thread.run(Thread.java:831)
eric-milles commented 3 years ago

import static de.scrum_master.stackoverflow.PocToggle.USE_MY_FEATURE should take care of Problem 1.

For Problem 2, where is "action" or "getAction()" declared? Is it from the mixin? The static verification of Groovy compiler is stronger and does not account for mixins.

For Problem 3, Groovy 2.5 cannot read code targeted for Java 16. The best it can do is Java 15. It may be the small eval scripts that the compiler runs to help understand the code or there may be an improper code generation somewhere that is resulting in Java 16 class files.

eric-milles commented 3 years ago

For the Java 16 issue, it is the AsmDecompiler/DecompiledClassNode that are the source of the issue. Part of the Groovy compiler uses ASM to translate Java class files into Groovy ClassNode instances. You would need the compiler process to run with Java 15 or lower to be able to parse JDK types.

eric-milles commented 3 years ago

It is possible to run your IDE with Java 16 and compile against Java 8-15 if you don't use a compiler config script or the ASTTest transform. There may be other features like this that parse some groovy source within the compiler process. For IDEA you need to be sure that the target JDK is passed as classpath arguments. The eclipse GroovyClassLoaderFactory ensures separation for project compilation but batch compilation may not be as well supported.

kriegaex commented 3 years ago

import static de.scrum_master.stackoverflow.PocToggle.USE_MY_FEATURE should take care of Problem 1.

It does. Actually, I had a copy & paste error in my question. Of course, my original code was not import static PocToggle.PocToggle.USE_MY_FEATURE but import static PocToggle.USE_MY_FEATURE. After using the fully qualified class name, it works.

Is that documented somewhere in a migration guide or in release notes? Something like: "Even if your classes are in the same package, you cannot use import static MyClass.MY_CONSTANT anymore, but now need to use import static fully.qualified.MyClass.MY_CONSTANT."

For Problem 2, where is "action" or "getAction()" declared? Is it from the mixin? The static verification of Groovy compiler is stronger and does not account for mixins.

It is declared in class org.openqa.selenium.interactions.Actions as a protected CompositeAction action field. So, it is not declared in the mix-in (category) class, but in the target class of the mix-in process.

For Problem 3, Groovy 2.5 cannot read code targeted for Java 16. The best it can do is Java 15.

I am aware of that. But I verified that IDEA compiles the Java classes correctly to target 8, so the Java 16 class files must come from somewhere else. Unfortunately, the not particularly helpful error message in the stack trace does not bother to tell us its name.

It may be the small eval scripts that the compiler runs to help understand the code or there may be an improper code generation somewhere that is resulting in Java 16 class files.

I am not a groovy buff, so I have to trust you on that.

For the Java 16 issue, it is the AsmDecompiler/DecompiledClassNode that are the source of the issue.

Yes, like I said in my original question: The version of ASM embedded in the Groovy compiler is too old to understand Java 16 class files. (Current ASM 9.2 understands Java 18, BTW.) So far, so non-surprising. What did surprise me, though, is that the compiler needs to actually deal with Java 16 files at all, because neither Javac nor Groovyc should create any.

Part of the Groovy compiler uses ASM to translate Java class files into Groovy ClassNode instances. You would need the compiler process to run with Java 15 or lower to be able to parse JDK types.

OK, there we go! Groovyc parses JDK types. I was not aware of that. That would explain why it does not work, if the result was the same when using Groovyc to also compile Java files. Because then it works, both from Maven and from the IDE. You can easily test that if you clone https://github.com/kriegaex/IDEA-275889, which I created yesterday for the IDEA issue, which I am no longer sure about being an IDEA issue at all. Maybe it is rather a Groovyc issue, but we need more information first. I really want to pinpoint it.

kriegaex commented 3 years ago

It is possible to run your IDE with Java 16 and compile against Java 8-15 if you don't use a compiler config script or the ASTTest transform.

Actually, I do not understand this remark. I am unaware of having configured anything. I do not even know what the ASTTest transform is. Therefore, I am clueless about where and what I would need to change in the compiler settings.

There may be other features like this that parse some groovy source within the compiler process.

But the Groovy source code is not Java 16. So how can that be a problem?

For IDEA you need to be sure that the target JDK is passed as classpath arguments.

You mean boot classpath (BCP), probably, don't you? Passing an older JDK on the BCP would be equivalent with using the --release N compiler option, correct? Is that what you are advising me to do? But actually, this option is active for both Javac and Groovy-Eclipse in IDEA. Maybe it is not passed through correctly, or maybe your next remark is the root cause. I do not fully understand it, though:

The eclipse GroovyClassLoaderFactory ensures separation for project compilation but batch compilation may not be as well supported.

Would you be able to investigate that, using my reproducer repository as a starting point? I know, you said in the past that you never use IntelliJ IDEA, but maybe you can figure out what it does to yield that kind of result. Or maybe we can reproduce it by reconfiguring Maven to only compile Groovy files with Groovy-Eclipse Batch and Java files with Javac, just like I have set up IDEA to do. Maybe then, it also happens in Maven. I am just thinking aloud here, hoping for more insights from you.

kriegaex commented 3 years ago

Or maybe we can reproduce it by reconfiguring Maven to only compile Groovy files with Groovy-Eclipse Batch and Java files with Javac, just like I have set up IDEA to do. Maybe then, it also happens in Maven.

That seems to be a dead end. I just added commit a0bcefd2 to a new branch groovyc-compile-only-tests. Quoting the commit message:

Change Maven Compiler config compile Java vs Groovy files separately

Now, the Java application classes are compiled by Javac, while the Groovy (Spock) test classes are compiled by Groovy-Eclipse.

I was hoping that this would reproduce the IDEA problem in Maven, because in IDEA I configured the project to also compile Java files with Javac. But the Maven build still passes. I.e., somehow IDEA must compile the Groovy files in a different way than Maven.

eric-milles commented 3 years ago

Problem 2 is a bug in the groovy compiler's static verification. GROOVY-9678 GROOVY-10200

Is Actions.mixin DragDropWorkaround a reference to the extension method mixin? I'm trying to understand and create a small example. But that method does not add field references. Here is a small example of its usage: https://blog.mrhaki.com/2009/10/groovy-goodness-mixin-functionality-to.html

eric-milles commented 3 years ago

Your example project is not compiling the groovy source as-is. I needed to enable the groovy source folder. After that, it compiles and executes the test. Execution within maven proceeds through GroovyEclipseCompiler/InternalCompiler [1] as expected. The GroovyClassLoaderFactory captures a classpath that includes the Java 16 JDK modules. AsmDecompiler is not hit for this simple case.

It is difficult to say why the standalone maven compile succeeds when the in-process IntelliJ execution of groovy-eclipse-batch [2] fails with ASM processing errors. It is possible that the ClassLoader chain is quite different. Also, I don't know what compiler arguments are being passed in the IntelliJ case so that is one more set of unknowns.

[1] https://github.com/groovy/groovy-eclipse/tree/master/extras/groovy-eclipse-compiler/src/main/java/org/codehaus/groovy/eclipse/compiler [2] https://github.com/JetBrains/intellij-community/blob/master/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GreclipseMain.java

kriegaex commented 3 years ago

Is Actions.mixin DragDropWorkaround a reference to the extension method mixin?

Yes.

I'm trying to understand and create a small example.

package de.scrum_master.testing

import spock.lang.Specification

class MixinUsingTargetClassFieldTest extends Specification {
  def setupSpec() {
    Target.mixin MyMixin
  }

  static class MyMixin {
    String nameToUpper() {
      name.toUpperCase()
    }
  }

  def test() {
    expect:
    new Target(name: "John Doe").nameToUpper() == "JOHN DOE"
  }
}

class Target {
  protected String name
}

Of course, you can reduce it even further by removing all the Spock stuff.

eric-milles commented 3 years ago

Oh, so Actions is indeed your target. I assumed it was the other way for some reason. And you expect the code of dragAndDropBy to execute within the context of an Actions instance, so the extension would have access to the fields and methods of Actions.

kriegaex commented 3 years ago

Yes. A while ago, I tested a workaround for testing drag & drop and double-clicks, because in vanilla Geb it was not working as expected, at least not on pages like https://visjs.github.io/vis-timeline/examples/timeline/interaction/animateWindow.html. But that is just FYI, not really relevant for the problem at hand. Better focus on my minimal example above. 🙂

kriegaex commented 3 years ago

Your example project is not compiling the groovy source as-is. I needed to enable the groovy source folder. After that, it compiles and executes the test.

I just cloned https://github.com/kriegaex/IDEA-275889 again into a new IntelliJ IDEA project and could not reproduce your problem. The Maven project for me is imported correctly, immediately marking src/main/java and src/test/groovy as source folders and compiling correctly with Groovy-Eclipse. Only in order to reproduce the problem, I had to switch the Java compiler to Javac in the IDEA settings, as shown in my screenshots in the JetBrains issue.

eric-milles commented 3 years ago

I think we are looking at different things for Problem 3. I was able to clone your project and compile with maven command line (with small modification as I noted). I have not imported your project into Eclipse or IntelliJ. I am confident that it would also compile and run from eclipse as I have tested similar projects this way. But that would not help you with IntelliJ compatibility.

Each of your reports here and in IDEA-275889 refer to javac and groovyc. groovyc is definitely going to need to parse class files into ClassNode instances. groovy-eclipse-batch uses the JDT tooling to do this, so it is capable of reading a wider range of class files. But there are times where it does something through the groovy tooling like parse and run a small script that triggers some of the ASM decompilation.

kriegaex commented 3 years ago

Your example project is not compiling the groovy source as-is. I needed to enable the groovy source folder. After that, it compiles and executes the test.

I just cloned https://github.com/kriegaex/IDEA-275889 again into a new IntelliJ IDEA project and could not reproduce your problem.

Oh, I am stupid and ugly! Of course the Maven build works, but is skipping test compilation and execution. I added a dummy file in src/test/java in order to mitigate that. It is on both branches now. IDEA recognised src/test/groovy automatically, but not Maven + Groovy-Eclipse without a little nudge. I really forgot about that requirement, because the project in which the problem occurred contains mixed Java and Groovy test content.

kriegaex commented 3 years ago

Each of your reports here and in IDEA-275889 refer to javac and groovyc. groovyc is definitely going to need to parse class files into ClassNode instances. groovy-eclipse-batch uses the JDT tooling to do this, so it is capable of reading a wider range of class files. But there are times where it does something through the groovy tooling like parse and run a small script that triggers some of the ASM decompilation.

Could it be that IDEA actually uses a compiler other than Groovy-Eclipse if it is not configured as the Java compiler? If it is, everything works fine, like I said. Only when I say "use Javac as Java compiler" in order to avoid IDEA's Greclipse + Lombok problems, do these errors occur. Can you recognise anything from my IDEA build log which could be a clue as to which compiler it actually uses? I see no org.codehaus.groovy.eclipse on the stack trace when stub generation fails. Either this means that IDEA somehow skips Greclipse (and JDT tooling) in this case, or that, like you said, this is a build step in which Greclipse uses tooling other than JDT, i.e. would be unable to recognise more recent class files. I would like to know what to tell the JetBrains people about how they should adjust their build in order to make it work like it does in Maven. Or are you talking to them? I would not be able to explain as well as you could, anyway.

kriegaex commented 3 years ago

When running the build on branch groovyc-compile-only-tests with <verbose>true</verbose>, I see this:

[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ IDEA-275889 ---
[INFO] Changes detected - recompiling the module!
[INFO] Using Groovy-Eclipse compiler to compile both Java and Groovy files
[INFO] Classpath: C:\Users\alexa\Documents\java-src\IDEA-275889\target\test-classes;C:\Users\alexa\Documents\java-src\IDEA-275889\target\classes;C:\Users\alexa\.m2\repository\junit\junit\4.13.2\junit-4.13.2.jar;C:\Users\alexa\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy\2.5.14\groovy-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-ant\2.5.14\groovy-ant-2.5.14.jar;C:\Users\alexa\.m2\repository\org\apache\ant\ant\1.9.15\ant-1.9.15.jar;C:\Users\alexa\.m2\repository\org\apache\ant\ant-junit\1.9.15\ant-junit-1.9.15.jar;C:\Users\alexa\.m2\repository\org\apache\ant\ant-launcher\1.9.15\ant-launcher-1.9.15.jar;C:\Users\alexa\.m2\repository\org\apache\ant\ant-antlr\1.9.15\ant-antlr-1.9.15.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-cli-commons\2.5.14\groovy-cli-commons-2.5.14.jar;C:\Users\alexa\.m2\repository\commons-cli\commons-cli\1.4\commons-cli-1.4.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-cli-picocli\2.5.14\groovy-cli-picocli-2.5.14.jar;C:\Users\alexa\.m2\repository\info\picocli\picocli\4.3.2\picocli-4.3.2.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-console\2.5.14\groovy-console-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-datetime\2.5.14\groovy-datetime-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-docgenerator\2.5.14\groovy-docgenerator-2.5.14.jar;C:\Users\alexa\.m2\repository\com\thoughtworks\qdox\qdox\1.12.1\qdox-1.12.1.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-groovydoc\2.5.14\groovy-groovydoc-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-groovysh\2.5.14\groovy-groovysh-2.5.14.jar;C:\Users\alexa\.m2\repository\jline\jline\2.14.6\jline-2.14.6.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-jmx\2.5.14\groovy-jmx-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-json\2.5.14\groovy-json-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-jsr223\2.5.14\groovy-jsr223-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-macro\2.5.14\groovy-macro-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-nio\2.5.14\groovy-nio-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-servlet\2.5.14\groovy-servlet-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-sql\2.5.14\groovy-sql-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-swing\2.5.14\groovy-swing-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-templates\2.5.14\groovy-templates-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-test\2.5.14\groovy-test-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-xml\2.5.14\groovy-xml-2.5.14.jar;C:\Users\alexa\.m2\repository\org\spockframework\spock-core\1.3-groovy-2.5\spock-core-1.3-groovy-2.5.jar;C:\Users\alexa\.m2\repository\cglib\cglib-nodep\3.2.5\cglib-nodep-3.2.5.jar;C:\Users\alexa\.m2\repository\org\objenesis\objenesis\2.5.1\objenesis-2.5.1.jar;
[INFO] Modulepath: 
[INFO] Compiler arguments: [-verbose, -cp, C:\Users\alexa\Documents\java-src\IDEA-275889\target\test-classes;C:\Users\alexa\Documents\java-src\IDEA-275889\target\classes;C:\Users\alexa\.m2\repository\junit\junit\4.13.2\junit-4.13.2.jar;C:\Users\alexa\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy\2.5.14\groovy-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-ant\2.5.14\groovy-ant-2.5.14.jar;C:\Users\alexa\.m2\repository\org\apache\ant\ant\1.9.15\ant-1.9.15.jar;C:\Users\alexa\.m2\repository\org\apache\ant\ant-junit\1.9.15\ant-junit-1.9.15.jar;C:\Users\alexa\.m2\repository\org\apache\ant\ant-launcher\1.9.15\ant-launcher-1.9.15.jar;C:\Users\alexa\.m2\repository\org\apache\ant\ant-antlr\1.9.15\ant-antlr-1.9.15.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-cli-commons\2.5.14\groovy-cli-commons-2.5.14.jar;C:\Users\alexa\.m2\repository\commons-cli\commons-cli\1.4\commons-cli-1.4.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-cli-picocli\2.5.14\groovy-cli-picocli-2.5.14.jar;C:\Users\alexa\.m2\repository\info\picocli\picocli\4.3.2\picocli-4.3.2.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-console\2.5.14\groovy-console-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-datetime\2.5.14\groovy-datetime-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-docgenerator\2.5.14\groovy-docgenerator-2.5.14.jar;C:\Users\alexa\.m2\repository\com\thoughtworks\qdox\qdox\1.12.1\qdox-1.12.1.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-groovydoc\2.5.14\groovy-groovydoc-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-groovysh\2.5.14\groovy-groovysh-2.5.14.jar;C:\Users\alexa\.m2\repository\jline\jline\2.14.6\jline-2.14.6.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-jmx\2.5.14\groovy-jmx-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-json\2.5.14\groovy-json-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-jsr223\2.5.14\groovy-jsr223-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-macro\2.5.14\groovy-macro-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-nio\2.5.14\groovy-nio-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-servlet\2.5.14\groovy-servlet-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-sql\2.5.14\groovy-sql-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-swing\2.5.14\groovy-swing-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-templates\2.5.14\groovy-templates-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-test\2.5.14\groovy-test-2.5.14.jar;C:\Users\alexa\.m2\repository\org\codehaus\groovy\groovy-xml\2.5.14\groovy-xml-2.5.14.jar;C:\Users\alexa\.m2\repository\org\spockframework\spock-core\1.3-groovy-2.5\spock-core-1.3-groovy-2.5.jar;C:\Users\alexa\.m2\repository\cglib\cglib-nodep\3.2.5\cglib-nodep-3.2.5.jar;C:\Users\alexa\.m2\repository\org\objenesis\objenesis\2.5.1\objenesis-2.5.1.jar;, -d, C:\Users\alexa\Documents\java-src\IDEA-275889\target\test-classes, -s, C:\Users\alexa\Documents\java-src\IDEA-275889\target\generated-test-sources\test-annotations, -g, -encoding, UTF-8, -source, 1.8, -target, 1.8, -nowarn, C:\Users\alexa\Documents\java-src\IDEA-275889\src\test\groovy\org\example\PersonTest.groovy]
[INFO] 0 files left.
[INFO] Compilation complete.  Compiled 1 files.
[INFO] [parsing    C:\Users\alexa\Documents\java-src\IDEA-275889\src\test\groovy\org\example\PersonTest.groovy - #1/1]
[reading    java/math/BigDecimal.class]
[reading    java/math/BigInteger.class]
[reading    spock/lang/Specification.class]
[reading    spock/mock/MockingApi.class]
[reading    org/spockframework/lang/SpecInternals.class]
[reading    java/lang/Object.class]
[reading    spock/mock/MockFactory.class]
[reading    groovy/lang/GroovyObject.class]
[reading    java/lang/String.class]
[reading    groovy/lang/MetaClass.class]
[reading    groovy/transform/Generated.class]
[analyzing  C:\Users\alexa\Documents\java-src\IDEA-275889\src\test\groovy\org\example\PersonTest.groovy - #1/1]
[reading    groovy/lang/Closure.class]
[reading    java/lang/Class.class]
[reading    java/util/Map.class]
[reading    java/lang/Throwable.class]
[reading    groovy/lang/DelegatesTo$Target.class]
[reading    groovy/lang/DelegatesTo.class]
[reading    groovy/transform/stc/ClosureParams.class]
[reading    groovy/transform/NamedParams.class]
[reading    org/spockframework/lang/ISpecificationContext.class]
[reading    org/spockframework/mock/MockImplementation.class]
[reading    org/spockframework/mock/MockNature.class]
[reading    java/lang/reflect/Type.class]
[reading    org/example/Person.class]
[writing    org\example\PersonTest.class - #1]
[completed  C:\Users\alexa\Documents\java-src\IDEA-275889\src\test\groovy\org\example\PersonTest.groovy - #1/1]
[1 unit compiled]
[1 .class file generated]

Are the JDK files listed here the ones that ClassNodeResolver trips over when using the old ASM in the IDEA use case? There must be a way for IDEA to avoid that, just like the Maven plugin (extension) obviously can.

eric-milles commented 3 years ago

If groovy-eclipse-batch is used by IntelliJ you should see org.eclipse.jdt.internal.compiler.batch.Main in the stack trace.

The class logging comes from https://github.com/groovy/groovy-eclipse/blob/master/jdt-patch/e420/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java#L313

kriegaex commented 3 years ago

Well, I don't - see above. Hmm... 🤔

kriegaex commented 3 years ago

Why was the issue closed? Have you established beyond doubt that this is an IDEA issue? Would it be possible that you connect to the JetBrains team, maybe piggy-backing onto my issue, in order to help them resolve this ASAP, in the interest of both products? I think it should be in the interest of Groovy-Eclipse to make sure that the most relevant IDEs properly support it. I am sure that with your expertise, it is much more likely to get this solved than it is with my humble body of knowledge.

kriegaex commented 2 years ago

Please note that I just today I created GROOVY-10503 and a corresponding pull request which fixes problem 3 in Groovy 2.5.x. If the PR is accepted, it might become part of release 2.5.16. The fix was actually trivial.