Skip to content

[Bug]: Can't parse inner classes located in methods #6614

@hunterpayne

Description

@hunterpayne

Describe the bug

Java allows inner classes inside of methods now. It appears that Spoon won't parse this construct correctly yet. Is this supported yet? Is this on the roadmap?

Source code you are trying to analyze/transform

public class Foo {
   private static final Stats$1 extractStats$1(final String line, final Regex apacheLogRegex$1) {
      Option var3 = apacheLogRegex$1.findFirstIn(line);

      class Stats$1 implements Serializable {
         private final int count;
         private final int numBytes;

         public int count() {
            return this.count;
         }

         public int numBytes() {
            return this.numBytes;
         }

         public Stats$1 merge(final Stats$1 other) {
            return new Stats$1(this.count() + other.count(), this.numBytes() + other.numBytes());
         }

         public String toString() {
            return StringOps$.MODULE$.format$extension(Predef$.MODULE$.augmentString("bytes=%s\tn=%s"), ScalaRunTime$.MODULE$.genericWrapArray(new Object[]{BoxesRunTime.boxToInteger(this.numBytes()), BoxesRunTime.boxToInteger(this.count())}));
         }

         public Stats$1(final int count, final int numBytes) {
            this.count = count;
            this.numBytes = numBytes;
         }
      }

      if (var3 instanceof Some) {
         Some var4 = (Some)var3;
         String var5 = (String)var4.value();
         if (var5 != null) {
            Option var6 = apacheLogRegex$1.unapplySeq(var5);
            if (!var6.isEmpty() && var6.get() != null && ((List)var6.get()).lengthCompare(9) == 0) {
               String bytes = (String)((LinearSeqOps)var6.get()).apply(6);
               return new Stats$1(1, StringOps$.MODULE$.toInt$extension(Predef$.MODULE$.augmentString(bytes)));
            }
         }
      }

      return new Stats$1(1, 0);
   }
}

Source code for your Spoon processing

// load the provided LogQuery$.java file
String logQuerySourceText = ...
CtClass cls = Launcher.parseClass(logQuerySourceText);
System.out.println(cls.getMethodsByName("extractStats$1").get(0).toString);

Actual output

    private static final org.apache.spark.examples.Stats$1 extractStats$1(final java.lang.String line, final scala.util.matching.Regex apacheLogRegex$1) {
        scala.Option var3 = apacheLogRegex$1.findFirstIn(line);
         {
            private final int count;

            private final int numBytes;

            public int count() {
                return this.count;
            }

            public int numBytes() {
                return this.numBytes;
            }

            public org.apache.spark.examples.LogQuery$$1 merge(final org.apache.spark.examples.LogQuery$$1 other) {
                return new org.apache.spark.examples.LogQuery$$1(this.count() + other.count(), this.numBytes() + other.numBytes());
            }

            public java.lang.String toString() {
                return scala.collection.StringOps$.MODULE$.format$extension(scala.Predef$.MODULE$.augmentString("bytes=%s\tn=%s"), scala.runtime.ScalaRunTime$.MODULE$.genericWrapArray(new java.lang.Object[]{ scala.runtime.BoxesRunTime.boxToInteger(this.numBytes()), scala.runtime.BoxesRunTime.boxToInteger(this.count()) }));
            }

            public 1(final int count, final int numBytes) {
                this.count = count;
                this.numBytes = numBytes;
            }
        }
        if (var3 instanceof scala.Some) {
            scala.Some var4 = ((scala.Some) (var3));
            java.lang.String var5 = ((java.lang.String) (var4.value()));
            if (var5 != null) {
                scala.Option var6 = apacheLogRegex$1.unapplySeq(var5);
                if (((!var6.isEmpty()) && (var6.get() != null)) && (((scala.collection.immutable.List) (var6.get())).lengthCompare(9) == 0)) {
                    java.lang.String bytes = ((java.lang.String) (((scala.collection.LinearSeqOps) (var6.get())).apply(6)));
                    return new org.apache.spark.examples.LogQuery$$1(1, scala.collection.StringOps$.MODULE$.toInt$extension(scala.Predef$.MODULE$.augmentString(bytes)));
                }
            }
        }
        return new org.apache.spark.examples.LogQuery$$1(1, 0);
    }

Expected output

   private static final Stats$1 extractStats$1(final String line, final Regex apacheLogRegex$1) {
      Option var3 = apacheLogRegex$1.findFirstIn(line);

      class Stats$1 implements Serializable {
         private final int count;
         private final int numBytes;

         public int count() {
            return this.count;
         }

         public int numBytes() {
            return this.numBytes;
         }

         public Stats$1 merge(final Stats$1 other) {
            return new Stats$1(this.count() + other.count(), this.numBytes() + other.numBytes());
         }

         public String toString() {
            return StringOps$.MODULE$.format$extension(Predef$.MODULE$.augmentString("bytes=%s\tn=%s"), ScalaRunTime$.MODULE$.genericWrapArray(new Object[]{BoxesRunTime.boxToInteger(this.numBytes()), BoxesRunTime.boxToInteger(this.count())}));
         }

         public Stats$1(final int count, final int numBytes) {
            this.count = count;
            this.numBytes = numBytes;
         }
      }

      if (var3 instanceof Some) {
         Some var4 = (Some)var3;
         String var5 = (String)var4.value();
         if (var5 != null) {
            Option var6 = apacheLogRegex$1.unapplySeq(var5);
            if (!var6.isEmpty() && var6.get() != null && ((List)var6.get()).lengthCompare(9) == 0) {
               String bytes = (String)((LinearSeqOps)var6.get()).apply(6);
               return new Stats$1(1, StringOps$.MODULE$.toInt$extension(Predef$.MODULE$.augmentString(bytes)));
            }
         }
      }

      return new Stats$1(1, 0);
   }

Spoon Version

11.2.1

JVM Version

JDK 17

What operating system are you using?

Ubuntu

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions