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

    • Bug
    • Status: Closed
    • Critical
    • Resolution: Fixed
    • 3.0.6
    • 4.0.0-alpha-3, 2.5.16, 3.0.10
    • Static compilation
    • None
    • 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

            emilles Eric Milles
            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