Skip to content

Conversation

@trancexpress
Copy link
Contributor

See: #4707

@trancexpress
Copy link
Contributor Author

The working copy test fails with:

junit.framework.AssertionFailedError: Unexpected types in hierarchy expected:<[test1.B$1$1, java.lang.Object, test1.A]> but was:<[test1.A, java.lang.Object]>
	at junit.framework.Assert.fail(Assert.java:57)
	at junit.framework.Assert.failNotEquals(Assert.java:329)
	at junit.framework.Assert.assertEquals(Assert.java:78)
	at junit.framework.TestCase.assertEquals(TestCase.java:238)
	at org.eclipse.jdt.core.tests.model.TypeHierarchyLambdaTests.testWithWorkingCopy(TypeHierarchyLambdaTests.java:118)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at junit.framework.TestCase.runTest(TestCase.java:177)
	at org.eclipse.jdt.core.tests.junit.extension.TestCase.runTest(TestCase.java:970)
	at junit.framework.TestCase.runBare(TestCase.java:142)
	at junit.framework.TestResult$1.protect(TestResult.java:122)
	at junit.framework.TestResult.runProtected(TestResult.java:142)
	at junit.framework.TestResult.run(TestResult.java:125)
	at junit.framework.TestCase.run(TestCase.java:130)
	at junit.framework.TestSuite.runTest(TestSuite.java:241)
	at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite.runTest(SuiteOfTestCases.java:114)
	at junit.framework.TestSuite.run(TestSuite.java:236)
	at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite.superRun(SuiteOfTestCases.java:97)
	at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite$1.protect(SuiteOfTestCases.java:85)
	at junit.framework.TestResult.runProtected(TestResult.java:142)
	at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite.run(SuiteOfTestCases.java:94)
	at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:90)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:520)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:748)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:443)
	at org.eclipse.pde.internal.junit.runtime.RemotePluginTestRunner.main(RemotePluginTestRunner.java:126)
	at org.eclipse.pde.internal.junit.runtime.PlatformUITestHarness.lambda$0(PlatformUITestHarness.java:45)
	at org.eclipse.e4.ui.internal.workbench.swt.E4Testable.lambda$1(E4Testable.java:127)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:132)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:5084)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4549)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1147)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1038)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:153)
	at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:684)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:583)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:173)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:185)
	at org.eclipse.pde.internal.junit.runtime.NonUIThreadTestApplication.start(NonUIThreadTestApplication.java:58)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:219)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:149)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:115)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:467)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:298)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:615)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:563)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1415)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1387)

@trancexpress
Copy link
Contributor Author

I've adjusted the new tests to also run into the problem seen in #4704.

The two fails are now:

Java Model Exception: Error in Java Model (code 969): <anonymous #1> {key=Ltest1/B$168;} [in r() [in <lambda #1> [in t() [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]]]] does not exist
	at org.eclipse.jdt.internal.core.JavaModelOperation.runOperation(JavaModelOperation.java:812)
	at org.eclipse.jdt.internal.core.SourceType.newSupertypeHierarchy(SourceType.java:860)
	at org.eclipse.jdt.internal.core.SourceType.newSupertypeHierarchy(SourceType.java:811)
	at org.eclipse.jdt.core.tests.model.TypeHierarchyLambdaTests.testhAnonymousTypesWitohutWorkingCopy(TypeHierarchyLambdaTests.java:86)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at junit.framework.TestCase.runTest(TestCase.java:177)
	at org.eclipse.jdt.core.tests.junit.extension.TestCase.runTest(TestCase.java:970)
	at junit.framework.TestCase.runBare(TestCase.java:142)
	at junit.framework.TestResult$1.protect(TestResult.java:122)
	at junit.framework.TestResult.runProtected(TestResult.java:142)
	at junit.framework.TestResult.run(TestResult.java:125)
	at junit.framework.TestCase.run(TestCase.java:130)
	at junit.framework.TestSuite.runTest(TestSuite.java:241)
	at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite.runTest(SuiteOfTestCases.java:114)
	at junit.framework.TestSuite.run(TestSuite.java:236)
	at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite.superRun(SuiteOfTestCases.java:97)
	at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite$1.protect(SuiteOfTestCases.java:85)
	at junit.framework.TestResult.runProtected(TestResult.java:142)
	at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite.run(SuiteOfTestCases.java:94)
	at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:90)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:520)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:748)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:443)
	at org.eclipse.pde.internal.junit.runtime.RemotePluginTestRunner.main(RemotePluginTestRunner.java:126)
	at org.eclipse.pde.internal.junit.runtime.PlatformUITestHarness.lambda$0(PlatformUITestHarness.java:45)
	at org.eclipse.e4.ui.internal.workbench.swt.E4Testable.lambda$1(E4Testable.java:127)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:132)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:5084)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4549)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1147)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1038)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:153)
	at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:684)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:583)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:173)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:185)
	at org.eclipse.pde.internal.junit.runtime.NonUIThreadTestApplication.start(NonUIThreadTestApplication.java:58)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:219)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:149)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:115)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:467)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:298)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:615)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:563)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1415)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1387)

(#4704)

junit.framework.AssertionFailedError: Unexpected anonymous types in hierarchy expected:<[test1.B$1$1]> but was:<[]>
	at junit.framework.Assert.fail(Assert.java:57)
	at junit.framework.Assert.failNotEquals(Assert.java:329)
	at junit.framework.Assert.assertEquals(Assert.java:78)
	at junit.framework.TestCase.assertEquals(TestCase.java:238)
	at org.eclipse.jdt.core.tests.model.TypeHierarchyLambdaTests.testhAnonymousTypesWithWorkingCopy(TypeHierarchyLambdaTests.java:138)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at junit.framework.TestCase.runTest(TestCase.java:177)
	at org.eclipse.jdt.core.tests.junit.extension.TestCase.runTest(TestCase.java:970)
	at junit.framework.TestCase.runBare(TestCase.java:142)
	at junit.framework.TestResult$1.protect(TestResult.java:122)
	at junit.framework.TestResult.runProtected(TestResult.java:142)
	at junit.framework.TestResult.run(TestResult.java:125)
	at junit.framework.TestCase.run(TestCase.java:130)
	at junit.framework.TestSuite.runTest(TestSuite.java:241)
	at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite.runTest(SuiteOfTestCases.java:114)
	at junit.framework.TestSuite.run(TestSuite.java:236)
	at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite.superRun(SuiteOfTestCases.java:97)
	at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite$1.protect(SuiteOfTestCases.java:85)
	at junit.framework.TestResult.runProtected(TestResult.java:142)
	at org.eclipse.jdt.core.tests.model.SuiteOfTestCases$Suite.run(SuiteOfTestCases.java:94)
	at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:90)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:520)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:748)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:443)
	at org.eclipse.pde.internal.junit.runtime.RemotePluginTestRunner.main(RemotePluginTestRunner.java:126)
	at org.eclipse.pde.internal.junit.runtime.PlatformUITestHarness.lambda$0(PlatformUITestHarness.java:45)
	at org.eclipse.e4.ui.internal.workbench.swt.E4Testable.lambda$1(E4Testable.java:127)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:132)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:5084)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4549)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1147)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1038)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:153)
	at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:684)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:583)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:173)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:185)
	at org.eclipse.pde.internal.junit.runtime.NonUIThreadTestApplication.start(NonUIThreadTestApplication.java:58)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:219)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:149)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:115)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:467)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:298)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:615)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:563)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1415)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1387)

(#4707)

@trancexpress trancexpress force-pushed the gh4707 branch 2 times, most recently from 82665bb to 07ddcac Compare December 23, 2025 14:41
@trancexpress
Copy link
Contributor Author

trancexpress commented Dec 23, 2025

When I check how the other types in the computed hierarchy are found in JavaModelCache, it seems its via matching hashCode().

For test1.A, the hierarchy contains a ResolvedSourceType object:

class A {key=Ltest1/A;} [in A.java [in test1 [in src [in WithSubtypeInLambda]]]]
  A()
  void m()

The cache has a corresponding SourceType in childrenCache:

class A [in A.java [in test1 [in src [in WithSubtypeInLambda]]]]
  A()
  void m()

Both have hashCode() -1574894051, so an info is found for the element and JavaElement.exists() returns true.

For the anonymous type in the lambda, the hierarchy als contains a ResolvedSourceType object:

<anonymous #1> (not open) {key=Ltest1/B$168;} [in r() [in <lambda #1> [in t() [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]]]]

childrenCache contains nothing for the anonymous type.

This leads to calling JavaElement.openWhenClosed() on the anonymous type, filling newElements with a SourceType object:

class <anonymous #1> [in t() [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]]=Info for class <anonymous #1> [in t() [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]]

hashCode() values however are 676026636 for the ResolvedSourceType and -1767983205 for the SourceType in newElements. So no info is found.

The hashCode() value is a combination of the element name (which is empty for the anonymous type) and the parents hashCode().

The ResolvedSourceType in the hierarchy has the LambdaMethod R.r() as parent:

r() (not open) [in <lambda #1> [in t() [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]]]

The SourceType in newElements has the B as parent:

class B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]
  interface R
    void r()
  void t()
    class <anonymous #1>

Note that I also see this SourceMethod as a parent, in another other debug session:

void t() [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]
  class <anonymous #1>

From what I can tell, the (expected) LambdaMethod parent is set at this stack trace:

"main" #1 [141220] prio=6 os_prio=0 cpu=3212.12ms elapsed=415.09s tid=0x00007f435401b0e0 nid=141220 at breakpoint [0x00007f435b1fc000]
   java.lang.Thread.State: RUNNABLE
        at org.eclipse.jdt.internal.core.SourceType.<init>(SourceType.java:55)
        at org.eclipse.jdt.internal.core.Member.getType(Member.java:394)
        at org.eclipse.jdt.internal.core.Member.getType(Member.java:1)
        at org.eclipse.jdt.internal.core.util.HandleFactory.createElement(HandleFactory.java:226)
        at org.eclipse.jdt.internal.core.util.HandleFactory.createElement(HandleFactory.java:173)
        at org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver.rememberAllTypes(HierarchyResolver.java:529)
        at org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver.resolve(HierarchyResolver.java:871)
        at org.eclipse.jdt.internal.core.hierarchy.IndexBasedHierarchyBuilder.buildForProject(IndexBasedHierarchyBuilder.java:251)
        at org.eclipse.jdt.internal.core.hierarchy.IndexBasedHierarchyBuilder.buildFromPotentialSubtypes(IndexBasedHierarchyBuilder.java:361)
        at org.eclipse.jdt.internal.core.hierarchy.IndexBasedHierarchyBuilder.build(IndexBasedHierarchyBuilder.java:152)
        at org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy.compute(TypeHierarchy.java:305)
        at org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy.refresh(TypeHierarchy.java:1263)
        - locked <0x000000071d71c390> (a org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy)
        at org.eclipse.jdt.internal.core.CreateTypeHierarchyOperation.executeOperation(CreateTypeHierarchyOperation.java:94)
        at org.eclipse.jdt.internal.core.JavaModelOperation.run(JavaModelOperation.java:751)
        at org.eclipse.jdt.internal.core.JavaModelOperation.runOperation(JavaModelOperation.java:816)
        at org.eclipse.jdt.internal.core.SourceType.newTypeHierarchy(SourceType.java:952)
        at org.eclipse.jdt.internal.core.SourceType.newTypeHierarchy(SourceType.java:909)
        at org.eclipse.jdt.core.tests.model.TypeHierarchyLambdaTests.testhAnonymousTypesWithoutWorkingCopy(TypeHierarchyLambdaTests.java:74)

This SourceType is used to obtain the parent of the ResolvedSourceType for the anonymous type, here:

"main" #1 [141220] prio=6 os_prio=0 cpu=3214.08ms elapsed=446.50s tid=0x00007f435401b0e0 nid=141220 at breakpoint [0x00007f435b1fc000]
   java.lang.Thread.State: RUNNABLE
        at org.eclipse.jdt.internal.core.ResolvedSourceType.<init>(ResolvedSourceType.java:34)
        at org.eclipse.jdt.internal.core.SourceType.resolved(SourceType.java:957)
        at org.eclipse.jdt.internal.core.hierarchy.HierarchyBuilder.getHandle(HierarchyBuilder.java:209)
        at org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver.reportHierarchy(HierarchyResolver.java:609)
        at org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver.resolve(HierarchyResolver.java:891)
        at org.eclipse.jdt.internal.core.hierarchy.IndexBasedHierarchyBuilder.buildForProject(IndexBasedHierarchyBuilder.java:251)
        at org.eclipse.jdt.internal.core.hierarchy.IndexBasedHierarchyBuilder.buildFromPotentialSubtypes(IndexBasedHierarchyBuilder.java:361)
        at org.eclipse.jdt.internal.core.hierarchy.IndexBasedHierarchyBuilder.build(IndexBasedHierarchyBuilder.java:152)
        at org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy.compute(TypeHierarchy.java:305)
        at org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy.refresh(TypeHierarchy.java:1263)
        - locked <0x000000071d71c390> (a org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy)
        at org.eclipse.jdt.internal.core.CreateTypeHierarchyOperation.executeOperation(CreateTypeHierarchyOperation.java:94)
        at org.eclipse.jdt.internal.core.JavaModelOperation.run(JavaModelOperation.java:751)
        at org.eclipse.jdt.internal.core.JavaModelOperation.runOperation(JavaModelOperation.java:816)
        at org.eclipse.jdt.internal.core.SourceType.newTypeHierarchy(SourceType.java:952)
        at org.eclipse.jdt.internal.core.SourceType.newTypeHierarchy(SourceType.java:909)
        at org.eclipse.jdt.core.tests.model.TypeHierarchyLambdaTests.testhAnonymousTypesWithoutWorkingCopy(TypeHierarchyLambdaTests.java:74)

The unexpected SourceMethod parent in newElements is set with this stack trace:

"main" #1 [157818] prio=6 os_prio=0 cpu=3333.41ms elapsed=293.92s tid=0x00007fc74801b0e0 nid=157818 at breakpoint [0x00007fc74f5fb000]
   java.lang.Thread.State: RUNNABLE
        at org.eclipse.jdt.internal.core.SourceType.<init>(SourceType.java:52)
        at org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor.createTypeHandle(CompilationUnitStructureRequestor.java:258)
        at org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor.enterType(CompilationUnitStructureRequestor.java:529)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:771)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier$LocalDeclarationVisitor.visit(SourceElementNotifier.java:61)
        at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.traverse(TypeDeclaration.java:1691)
        at org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression.traverse(QualifiedAllocationExpression.java:669)
        at org.eclipse.jdt.internal.compiler.ast.LambdaExpression.traverse(LambdaExpression.java:783)
        at org.eclipse.jdt.internal.compiler.ast.LocalDeclaration.traverse(LocalDeclaration.java:412)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.visitIfNeeded(SourceElementNotifier.java:959)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:403)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:818)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:491)
        at org.eclipse.jdt.internal.compiler.SourceElementParser.parseCompilationUnit(SourceElementParser.java:989)
        at org.eclipse.jdt.internal.core.CompilationUnit.buildStructure(CompilationUnit.java:279)
        at org.eclipse.jdt.internal.core.Openable.generateInfos(Openable.java:250)
        at org.eclipse.jdt.internal.core.SourceRefElement.generateInfos(SourceRefElement.java:127)
        at org.eclipse.jdt.internal.core.JavaElement.openWhenClosed(JavaElement.java:564)
        at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:284)
        at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:270)
        at org.eclipse.jdt.internal.core.JavaElement.exists(JavaElement.java:187)
        at org.eclipse.jdt.core.tests.model.TypeHierarchyLambdaTests.testhAnonymousTypesWithoutWorkingCopy(TypeHierarchyLambdaTests.java:78)

In SourceElementNotifier.visitIfNeeded(AbstractMethodDeclaration), the method contents are:

public void t() {
  R r = () -> new A() {
};
}

AbstractMethodDeclaration.statements contains this:

[R r = () -> new A() {
};]

But at CompilationUnitStructureRequestor.enterType(TypeInfo), CompilationUnitStructureRequestor.handleStack is missing the LambdaMethod, that HandleFactory.createElement() seems to know about:

B.java [in test1 [in src [in WithSubtypeInLambda]]]
B (not open) [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]
t() (not open) [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]

@trancexpress
Copy link
Contributor Author

This highlights the difference and why we don't find the anonymous type in the types created on open():

public void testTemporary() throws CoreException {
	String a =
			"""
			package test1;
			public abstract class A {
				public A() {}
				public void m() {}
			}
			""";
	String b =
			"""
			package test1;
			public class B {
				interface R {
					public void r();
				}
				public void t() {
					R r = () -> new A() {};
				}
			}
			""";
	String projectName = "WithSubtypeInLambda";
	try {
		createJavaProject(projectName, new String[] { "src" }, new String[] { "JCL_21_LIB" }, "bin", "21");
		IPackageFragmentRoot sourceFolder = getPackageFragmentRoot(projectName, "src");
		IPackageFragment pack1 = sourceFolder.createPackageFragment("test1", false, null);
		ICompilationUnit cuA = pack1.getCompilationUnit("A.java");
		ICompilationUnit cuB = pack1.getCompilationUnit("B.java");
		IType type = cuA.createType(a, null, true, null);
		IType B = cuB.createType(b, null, true, null);
		ITypeHierarchy hierarchy = type.newTypeHierarchy(null);
		IType[] allTypes= hierarchy.getAllTypes();
		IType anonymousTypeFromHierarchy = null;
		for (IType hierarchyType : allTypes) {
			if (hierarchyType.isAnonymous()) {
				anonymousTypeFromHierarchy = hierarchyType;
				break;
			}
		}
		System.out.println("From hierarchy, parent: " + anonymousTypeFromHierarchy.getParent());
		IJavaElement anonymousTypeFromType = null;
		Deque<IJavaElement> q = new LinkedList<>();
		q.add(B);
		while (!q.isEmpty()) {
			IJavaElement e = q.removeFirst();
			if (e instanceof IType t && t.isAnonymous()) {
				anonymousTypeFromType = e;
				break;
			}
			if (e instanceof IParent p) {
				q.addAll(Arrays.asList(p.getChildren()));
			}
		}
		System.out.println("From type, parent: " + anonymousTypeFromType.getParent());
	} finally {
		deleteProject(projectName);
	}
}

Output:

From hierarchy, parent: r() (not open) [in <lambda #1> [in t() [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]]]
From type, parent: void t() [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]
  class <anonymous #1>

Note that if I traverse B first (see the queue code) and then create the hierarchy, the anonymous type is not present in the hierarchy...

@trancexpress
Copy link
Contributor Author

trancexpress commented Dec 24, 2025

@stephan-herrmann could you give your opinion here?

I have those two classes:

package test1;
public abstract class A {
    public A() {}
    public void m() {}
}
package test1;
public class B {
    interface R {
        public void r();
    }
    public void t() {
        R r = () -> new A() {};
    }
}

What do you think should be the parent of the anonymous type in B.t()?

CompilationUnit.buildStructure() says its B.t().

Parser.dietParse() in HierarchyResolver.resolve() says its R.r().

If I would replace the lambda declaration with an anonymous subtype of R, I assume it would be R.r():

package test1;
public class B {
    interface R {
        public void r();
    }
    public void t() {
        new R() {
            @Override
            public void r() {
                new A() {};
            }
        };
    }
}

But with the lambda I don't know. And without knowing, I'm not sure in which code I should be analyzing the problem further.

@stephan-herrmann
Copy link
Contributor

What do you think should be the parent of the anonymous type in B.t()?
CompilationUnit.buildStructure() says its B.t().
Parser.dietParse() in HierarchyResolver.resolve() says its R.r().

With "parent" you mean the enclosing IJavaElement? (I'm asking because in the context of type hierarchies the term "parent" could mean "super type").

I vaguely recall that integrating LambdaMethod into the Java Model required some tricks. Looking at the history of that class @jarthana and @srikanth-sankaran have best chances of remembering (if anybody -- aside from noise in the git history all this hasn't been touched since 2014).

Some quick ideas from afar:

  • seeing mentioning of dietParse: perhaps some (intermediate) containing expression doesn't exist in this mode?
  • do handle mementos play a role? Their encoding should ensure safe round trip between memento and resolved element, but this, too, is a fragile mechanism in some situations.
  • R.r() certainly does not contain the anonymous type, it is the function type implemented by the lambda, which then contains the anonymous type. The following would be true: the anon type is contained in an implementation of B.r().

@trancexpress
Copy link
Contributor Author

With "parent" you mean the enclosing IJavaElement? (I'm asking because in the context of type hierarchies the term "parent" could mean "super type").

The object returned by getParent(). Its used as part of hashing and doesn't match for the local type in question (when comparing the type hierarchy object vs. the elements created when opening the local type).

seeing mentioning of dietParse: perhaps some (intermediate) containing expression doesn't exist in this mode?

Not that I see, actually the dietParse() code does some extra resolving afterwards, if there are local types. And it finds more structure than the regular parsing code called on open.

do handle mementos play a role?

No, I don't see any on the stack trace. Unless I missed anything; but I think everything is computed on-the-fly. Especially with the code in the new tests.

R.r() certainly does not contain the anonymous type, it is the function type implemented by the lambda, which then contains the anonymous type. The following would be true: the anon type is contained in an implementation of B.r().

What the hierarchy code has as parents of the local type is:

r() (not open) [in <lambda #1> [in t() [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]]], class=class org.eclipse.jdt.internal.core.LambdaMethod
<lambda #1> (not open) [in t() [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]], class=class org.eclipse.jdt.internal.core.LambdaExpression
t() (not open) [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]], class=class org.eclipse.jdt.internal.core.SourceMethod
B (not open) [in B.java [in test1 [in src [in WithSubtypeInLambda]]]], class=class org.eclipse.jdt.internal.core.SourceType

The lambda itself is also a parent here. Neither the lambda nor r() are in the parents of the local type, when calling IJavaElement.open() (when opening creates all the types leading up to the local element).

Alright, I'll keep looking at this code then:

        at org.eclipse.jdt.internal.core.SourceType.<init>(SourceType.java:52)
        at org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor.createTypeHandle(CompilationUnitStructureRequestor.java:258)
        at org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor.enterType(CompilationUnitStructureRequestor.java:529)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:771)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier$LocalDeclarationVisitor.visit(SourceElementNotifier.java:61)
        at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.traverse(TypeDeclaration.java:1691)
        at org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression.traverse(QualifiedAllocationExpression.java:669)
        at org.eclipse.jdt.internal.compiler.ast.LambdaExpression.traverse(LambdaExpression.java:783)
        at org.eclipse.jdt.internal.compiler.ast.LocalDeclaration.traverse(LocalDeclaration.java:412)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.visitIfNeeded(SourceElementNotifier.java:959)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:403)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:818)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:491)
        at org.eclipse.jdt.internal.compiler.SourceElementParser.parseCompilationUnit(SourceElementParser.java:989)
        at org.eclipse.jdt.internal.core.CompilationUnit.buildStructure(CompilationUnit.java:279)

I think LambdaExpression should push some elements on CompilationUnitStructureRequestor.handleStack... Which doesn't look simple.

@trancexpress
Copy link
Contributor Author

Hi @srikanth-sankaran ,

could you take a look here?

If you check this PR out and run org.eclipse.jdt.core.tests.model.TypeHierarchyLambdaTests.testTemporary(), you will see the following on the command line:

From hierarchy, parent: r() (not open) [in <lambda #1> [in t() [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]]]
From type, parent: void t() [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]
  class <anonymous #1>

It looks like the the anonymous type in B.java has a few parents missing in the JDT model. Best I can tell, those parents are not present in CompilationUnitStructureRequestor.handleStack, while the this code is called:

"main" #1 [35544] prio=6 os_prio=0 cpu=3204.22ms elapsed=170.37s tid=0x00007f52bc01b0c0 nid=35544 at breakpoint [0x00007f52c37fb000]
   java.lang.Thread.State: RUNNABLE
        at org.eclipse.jdt.internal.core.SourceType.<init>(SourceType.java:52)
        at org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor.createTypeHandle(CompilationUnitStructureRequestor.java:258)
        at org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor.enterType(CompilationUnitStructureRequestor.java:529)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:771)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier$LocalDeclarationVisitor.visit(SourceElementNotifier.java:61)
        at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.traverse(TypeDeclaration.java:1691)
        at org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression.traverse(QualifiedAllocationExpression.java:669)
        at org.eclipse.jdt.internal.compiler.ast.LambdaExpression.traverse(LambdaExpression.java:783)
        at org.eclipse.jdt.internal.compiler.ast.LocalDeclaration.traverse(LocalDeclaration.java:412)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.visitIfNeeded(SourceElementNotifier.java:959)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:403)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:818)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:491)
        at org.eclipse.jdt.internal.compiler.SourceElementParser.parseCompilationUnit(SourceElementParser.java:989)
        at org.eclipse.jdt.internal.core.CompilationUnit.buildStructure(CompilationUnit.java:279)
        at org.eclipse.jdt.internal.core.Openable.generateInfos(Openable.java:250)
        at org.eclipse.jdt.internal.core.JavaElement.openWhenClosed(JavaElement.java:571)
        at org.eclipse.jdt.internal.core.CompilationUnit.makeConsistent(CompilationUnit.java:1262)
        at org.eclipse.jdt.internal.core.CompilationUnit.makeConsistent(CompilationUnit.java:1242)
        at org.eclipse.jdt.internal.core.Openable.save(Openable.java:490)
        at org.eclipse.jdt.internal.core.CompilationUnit.save(CompilationUnit.java:1478)
        at org.eclipse.jdt.internal.core.CreateElementInCUOperation.executeOperation(CreateElementInCUOperation.java:134)
        at org.eclipse.jdt.internal.core.JavaModelOperation.run(JavaModelOperation.java:751)
        at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2505)
        at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2533)
        at org.eclipse.jdt.internal.core.JavaModelOperation.runOperation(JavaModelOperation.java:821)
        at org.eclipse.jdt.internal.core.CompilationUnit.createType(CompilationUnit.java:604)
        at org.eclipse.jdt.core.tests.model.TypeHierarchyLambdaTests.testTemporary(TypeHierarchyLambdaTests.java:224)

Only this is on the stack:

B.java [in test1 [in src [in WithSubtypeInLambda]]]
B (not open) [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]
t() (not open) [in B [in B.java [in test1 [in src [in WithSubtypeInLambda]]]]]

Shouldn't there be more?

Likewise values are on stack when retrieving the element info of the anonymous type:

"main" #1 [35544] prio=6 os_prio=0 cpu=3269.96ms elapsed=253.40s tid=0x00007f52bc01b0c0 nid=35544 at breakpoint [0x00007f52c37fb000]
   java.lang.Thread.State: RUNNABLE
        at org.eclipse.jdt.internal.core.SourceType.<init>(SourceType.java:52)
        at org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor.createTypeHandle(CompilationUnitStructureRequestor.java:258)
        at org.eclipse.jdt.internal.core.CompilationUnitStructureRequestor.enterType(CompilationUnitStructureRequestor.java:529)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:771)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier$LocalDeclarationVisitor.visit(SourceElementNotifier.java:61)
        at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.traverse(TypeDeclaration.java:1691)
        at org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression.traverse(QualifiedAllocationExpression.java:669)
        at org.eclipse.jdt.internal.compiler.ast.LambdaExpression.traverse(LambdaExpression.java:783)
        at org.eclipse.jdt.internal.compiler.ast.LocalDeclaration.traverse(LocalDeclaration.java:412)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.visitIfNeeded(SourceElementNotifier.java:959)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:403)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:818)
        at org.eclipse.jdt.internal.compiler.SourceElementNotifier.notifySourceElementRequestor(SourceElementNotifier.java:491)
        at org.eclipse.jdt.internal.compiler.SourceElementParser.parseCompilationUnit(SourceElementParser.java:989)
        at org.eclipse.jdt.internal.core.CompilationUnit.buildStructure(CompilationUnit.java:279)
        at org.eclipse.jdt.internal.core.Openable.generateInfos(Openable.java:250)
        at org.eclipse.jdt.internal.core.SourceRefElement.generateInfos(SourceRefElement.java:127)
        at org.eclipse.jdt.internal.core.JavaElement.openWhenClosed(JavaElement.java:571)
        at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:294)
        at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:280)
        at org.eclipse.jdt.internal.core.JavaElement.getChildren(JavaElement.java:235)
        at org.eclipse.jdt.core.tests.model.TypeHierarchyLambdaTests.testTemporary(TypeHierarchyLambdaTests.java:245)

Best regards,
Simeon

@srikanth-sankaran
Copy link
Contributor

Hi @trancexpress I will study this but it will take some time to wrap up the things I am working on.

In the meanwhile CCing @jarthana who is our model expert.

@trancexpress
Copy link
Contributor Author

Thank you! I don't think we are in a rush here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants