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

ECJ writes incorrect enclosing method for doubly-nested anonymous class #1905

Closed
nsadeveloper789 opened this issue Jan 24, 2024 · 2 comments · Fixed by #1906
Closed

ECJ writes incorrect enclosing method for doubly-nested anonymous class #1905

nsadeveloper789 opened this issue Jan 24, 2024 · 2 comments · Fixed by #1906
Assignees
Labels
bug Something isn't working
Milestone

Comments

@nsadeveloper789
Copy link

The following test crashes in Eclipse 2023-12 with java.lang.InternalError: Enclosing method not found:

public class BugTest {
	@Test
	public void testGetEnclosingMethod() {
		var outer = new Object() {
			Object inner = new Object() {};
		};
		assertEquals(null, outer.inner.getClass().getEnclosingMethod());
	}
}

My version of JDT is 3.19.300.v20231201-0110.
Eclipse is running on JDK-21: org.eclipse.justj.openjdk.hotspot.jre.full.linux.x86_64_21.0.1.v20231028-0937
The test is running on JDK-17: org.eclipse.justj.openjdk.hotspot.jre.full.linux.x86_64_17.0.3.v20220515-1416

The test passes (I believe correctly) when compiled and run with javac (pick either from the above JDKs).

If I open the innermost class file (BugTest$1$1.class) generated by each of ecj and javac in Eclipse's raw class viewer, I see that ecj has a different value for the enclosing method:

javac's:

// Compiled from BugTest.java (version 17 : 61.0, super bit)
class bug.BugTest$1$1 {
  
  // Field descriptor #6 Lbug/BugTest$1;
  final synthetic bug.BugTest$1 this$1;
  
  // Method descriptor #13 (Lbug/BugTest$1;)V
  // Stack: 2, Locals: 2
  BugTest$1$1(new bug.BugTest(){} this$1);
     0  aload_0 [this]
     1  aload_1 [this$1]
     2  putfield bug.BugTest$1$1.this$1 : new bug.BugTest(){} [1]
     5  aload_0 [this]
     6  invokespecial java.lang.Object() [7]
     9  return
      Line numbers:
        [pc: 0, line: 14]
      Local variable table:
        [pc: 0, pc: 10] local: this index: 0 type: new new bug.BugTest(){}(){}
        [pc: 0, pc: 10] local: this$1 index: 1 type: new bug.BugTest(){}

  Inner classes:
    [inner class info: #22 bug/BugTest$1, outer class info: #0
     inner name: #0, accessflags: 0 default],
    [inner class info: #2 bug/BugTest$1$1, outer class info: #0
     inner name: #0, accessflags: 0 default]
  Enclosing Method: #22  #0 bug/BugTest$1

Nest Host: #25 bug/BugTest
}

ecj's:

// Compiled from BugTest.java (version 17 : 61.0, super bit)
class bug.BugTest$1$1 {
  
  // Field descriptor #6 Lbug/BugTest$1;
  final synthetic bug.BugTest$1 this$1;
  
  // Method descriptor #8 (Lbug/BugTest$1;)V
  // Stack: 2, Locals: 2
  BugTest$1$1(new bug.BugTest(){} arg0);
     0  aload_0 [this]
     1  aload_1 [arg0]
     2  putfield bug.BugTest$1$1.this$1 : new bug.BugTest(){} [10]
     5  aload_0 [this]
     6  invokespecial java.lang.Object() [12]
     9  return
      Line numbers:
        [pc: 0, line: 14]
      Local variable table:
        [pc: 0, pc: 10] local: this index: 0 type: new new bug.BugTest(){}(){}

  Inner classes:
    [inner class info: #22 bug/BugTest$1, outer class info: #0
     inner name: #0, accessflags: 0 default],
    [inner class info: #1 bug/BugTest$1$1, outer class info: #0
     inner name: #0, accessflags: 0 default]
  Enclosing Method: #22  #24 bug/BugTest$1.testGetEnclosingMethod()V

Nest Host: #28 bug/BugTest
}
@iloveeclipse iloveeclipse added the bug Something isn't working label Jan 24, 2024
@iloveeclipse
Copy link
Member

iloveeclipse commented Jan 24, 2024

Simple version (without any dependencies):

public class X {
	public static void main(String[] args) {
		var outer = new Object() {
			Object inner = new Object() {
				// 
			};
		};
		System.out.println(outer.inner.getClass().getEnclosingMethod());
	}
}

Javac from 17 / 21 is fine with that:

/usr/lib/jvm/java-21/bin/java BugTest.java
null

Ecj as of today master (also running on same Java 21):

Exception in thread "main" java.lang.InternalError: Enclosing method not found
	at java.base/java.lang.Class.getEnclosingMethod(Class.java:1518)
	at X.main(X.java:8)

ecj encodes wrong outer class name that contains method name:

class X$1$1 {

  // compiled from: X.java
  NESTHOST X
  OUTERCLASS X$1 main (String[]) : void

expected:

class X$1$1 {

  // compiled from: X.java
  NESTHOST X
  OUTERCLASS X$1

@srikanth-sankaran
Copy link
Contributor

JLS 4.7.7 The EnclosingMethod Attribute

The EnclosingMethod attribute is a fixed-length attribute in the attributes table
of a ClassFile structure (§4.1). A class must have an EnclosingMethod attribute
if and only if it represents a local class or an anonymous class (JLS §14.3, JLS
§15.9.5).
There may be at most one EnclosingMethod attribute in the attributes table of
a ClassFile structure.

...

If the current class is not immediately enclosed by a method or constructor,
then the value of the method_index item must be zero.
In particular, method_index must be zero if the current class was immediately enclosed
in source code by an instance initializer, static initializer, instance variable initializer, or
class variable initializer. (The first two concern both local classes and anonymous classes,
while the last two concern anonymous classes declared on the right hand side of a field
assignment.)

srikanth-sankaran added a commit that referenced this issue Jan 25, 2024
…ss (#1906)

* Do not traverse past enclosing type declaration to compute enclosing
method

* Fixes #1905
@iloveeclipse iloveeclipse added this to the 4.31 M2 milestone Jan 25, 2024
robstryker pushed a commit to robstryker/eclipse.jdt.core that referenced this issue Jul 18, 2024
…ss (eclipse-jdt#1906)

* Do not traverse past enclosing type declaration to compute enclosing
method

* Fixes eclipse-jdt#1905
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
3 participants