Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-9807

Static compile of dynamically generated code produces different output in a top-level class and a nested class

    XMLWordPrintableJSON

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Critical
    • Resolution: Fixed
    • Affects Version/s: 3.0.6
    • Fix Version/s: 4.0.0-alpha-3
    • Component/s: Static compilation
    • Labels:
      None
    • Environment:
      openjdk version "1.8.0_242"
      OpenJDK Runtime Environment (build 1.8.0_242-8u242-b08-0ubuntu3~18.04-b08)
      OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode)

      Description

      I have encountered an issue when trying to generate code, containing chained method calls, at runtime (without source code) and compiling using CompileStatic.
      What I am trying to achieve is produce code similar to:

      public StringBuilder test() {
          StringBuilder sb = new StringBuilder().append("testString");
          return sb;
      }
      

      I create the appropriate AST nodes, statements, expressions, etc.
      Everything works fine if I add a method like the one shown in a top-level class (the class is also dynamically generated at runtime). However, if I try to add the exact same method to a nested class, it seems like the groovy compiler gets somehow confused and, judging by the decompiler output, produces something like:

      public StringBuilder test() {
          StringBuilder sb = ((StringBuilder)((Closure)this).getThisObject()).append("testString");
          return sb;
      }
      

      Naturally, this does not work.

      Here's how I try to generate the method:

      ClassNode topLevelClass = ClassHelper.make(
          "com.example.groovycompiler.test.TopLevelClass");
      InnerClassNode nestedClass = new InnerClassNode(
          topLevelClass,
          "com.example.groovycompiler.test.TopLevelClass$NestedClass",
          Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
          ClassHelper.OBJECT_TYPE);
      ClassNode stringBuilderClass = ClassHelper.make(StringBuilder.class);
      nestedClass.addMethod(
          "test",
          Opcodes.ACC_PUBLIC,
          stringBuilderClass,
          Parameter.EMPTY_ARRAY,
          ClassNode.EMPTY_ARRAY,
          block(
              declS(
                  varX("sb", stringBuilderClass),
                  callX(ctorX(stringBuilderClass), "append",
                      args(constX("testString")))),
              returnS(
                  varX("sb", stringBuilderClass))
          )
      );
      

      Perhaps I am missing something, in which case I will be very happy to receive some pointers.
      I have created a github repo with a maven project containing a unit test that demonstrates the issue: https://github.com/l-atanasov/groovy-static-compile-issue
      Note, that I have extended the CompilationUnit a little to allow to run the static compiler without source.

      Also, if I am not using the static compiler, everything works as expected.

      Update: reformatted code for readability

        Attachments

          Activity

            People

            • Assignee:
              emilles Eric Milles
              Reporter:
              latanasov Lyuben Atanasov
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Time Tracking

                Estimated:
                Original Estimate - Not Specified
                Not Specified
                Remaining:
                Remaining Estimate - 0h
                0h
                Logged:
                Time Spent - 1h 20m
                1h 20m