eclipse-jdt / eclipse.jdt.core

Eclipse Public License 2.0
164 stars 130 forks source link

randomly Broken imports - type from JDK cannot be resolved #2877

Open andreasdc opened 2 months ago

andreasdc commented 2 months ago

I often get errors about not detected classes, for example: java.util.IdentityHashMap cannot be resolved to a type today I even had error on System.out. Cleaning or refreshing doesn't help, but restarting Eclipse fixes that.

jukzi commented 2 months ago

I experienced the same in the last months some times. However i do not know how to reproduce :-( For me it was always only about the classes in JDK. - and yes only restarting helped - reliably.

andreasdc commented 2 months ago

I experienced the same in the last months some times. However i do not know how to reproduce :-( For me it was always only about the classes in JDK. - and yes only restarting helped - reliably.

"The type java.io.PrintStream cannot be resolved. It is indirectly referenced from required type java.lang.System" I just did something in another project after restart and I see this error in couple projects.

jnsmiles commented 2 months ago

I also have been confronted to that random bug since a long time (more than 3 years).

Here is a protocol to try to reproduce that bug:

Code context project0 package pkg0

unit MyNestClassA.java

public class MyNestClassA {
  public static class MyMemberClassB {
    // MyMemberClassB is widely used across multiple projects
  }
}

unit MyNestClassC.java

public class MyNestClassC {
}

project1 package pkg1

unit D.java

import javax.annotations.Generated
import pkg0.MyNestClassA.MyMemberClassB;

@Generated("","")
public class D {
  // ...
  public void myIndirectUsageOfClassB() {
     MyMemberClassB b = ...
     // ...
  }
}

unit E.java

public class E extends class D {
}

Update operations: 1) cut code of MyMemberClassB from MyNestClassA and paste it into MyNestClassC 2) run control+B command (rebuild all projects in workspace) 3) look for classes that have compilation error flags

Expected behaviour:

The result:

This bug appears randomly and with potentially any JRE API (I got it with Float, Boolean, StandardCharsets, IllegalArgumentException) and only JRE APIs.

jnsmiles commented 2 months ago

Console error log as attachement eclipse-random-api-disparition-1.txt eclipse-random-api-disparition-2.txt eclipse-random-api-disparition-3.txt eclipse-random-api-disparition-4.txt

stephan-herrmann commented 2 months ago
  • cut code of MyMemberClassB from MyNestClassA and paste it into MyNestClassC
  • run control+B command (rebuild all projects in workspace)
jnsmiles commented 2 months ago
  • cut code of MyMemberClassB from MyNestClassA and paste it into MyNestClassC
  • so MyMemberClassB will become an inner class of MyNestClassC?

Yes

  • do you save files immediately, individually, or with save all, or never?

Most of the time I save files one by one, some times all in a set, some times on prompt when launching build command, but it seems not relevant to the bug.

  • run control+B command (rebuild all projects in workspace)
  • should we assume that "build automatically" is disabled?

Yes

andreasdc commented 1 month ago

I exported 1 jar from 1 project, I was checking something in 2 projects, the non exported project that I have open has broken import. The type java.io.PrintStream cannot be resolved. It is indirectly referenced from required type java.lang.System

stephan-herrmann commented 1 month ago

Do we have a start date, since when this problem occurs?

Given that we have some more or less recent changes in JRT handling, perhaps a start date would help find a bad commit?

jukzi commented 1 month ago

Do we have a start date, since when this problem occurs?

I think i have seen it ~3 months ago (i.e. ~ 6/2024) myself but have not reported it since i have seen random "cannot be resolved" for years in libraries. But now it's always jdk classes.

andreasdc commented 1 month ago

Do we have a start date, since when this problem occurs?

I think i have seen it ~3 months ago (i.e. ~ 6/2024) myself but have not reported it since i have seen random "cannot be resolved" for years in libraries. But now it's always jdk classes.

Yup I have this for similar time.

stephan-herrmann commented 1 month ago

Given the time frame and given that the broken state is "cached" somehow, could https://github.com/eclipse-jdt/eclipse.jdt.core/pull/2376 have a finger in the pie?

jukzi commented 1 month ago

That change introduced org.eclipse.jdt.internal.compiler.util.JRTUtil.JRT_FILE_SYSTEMS the ConcurrentHashMap looks sane. It caches instances of jdk.internal.jrtfs.JrtFileSystem which documents no thread-safe properties. On a first glance the use of an not synchronized JrtFileSystem.image looks inherently unsafe. However it also looks like it tries to be somewhat thread-safe. i don't know.

@HannesWell @iloveeclipse?

jukzi commented 1 month ago

@stephan-herrmann would it help to have a Heap-Dump if it occurs again? i would not know where to look at.

HannesWell commented 1 month ago

It caches instances of jdk.internal.jrtfs.JrtFileSystem which documents no thread-safe properties. On a first glance the use of an not synchronized JrtFileSystem.image looks inherently unsafe. However it also looks like it tries to be somewhat thread-safe. i don't know.

The abstract class java.nio.file.FileSystem says the following in its java-doc and since jdk.internal.jrtfs.JrtFileSystem inherits from it, it should follow that too:

File systems are safe for use by multiple concurrent threads. The {@link #close close}
method may be invoked at any time to close a file system but
whether a file system is <i>asynchronously closeable</i> is provider specific
and therefore unspecified. In other words, if a thread is accessing an
object in a file system, and another thread invokes the {@code close} method
then it may require to block until the first operation is complete. Closing
a file system causes all open channels, watch services, and other {@link
Closeable closeable} objects associated with the file system to be closed.

And since it looks like all JRT-filesystems created and cached in JRTUtil.JRT_FILE_SYSTEMS concurrency should not be an issue.

Unless something outside of JDT obtains a file-system from JRTUtil.JRT_FILE_SYSTEMS and closes it? But outside of JDT I'm only aware of org.eclipse.pde.api.tools.internal.model.ArchiveApiTypeContainer and it doesn't look like it's closing something.

jnsmiles commented 1 month ago

Do we have a start date, since when this problem occurs?

Given that we have some more or less recent changes in JRT handling, perhaps a start date would help find a bad commit?

For my part, I have had this problem since a very long time, may be 2021 or even 2020.

jukzi commented 1 month ago

today bizarr error: Problems show no error, but "java.lang.ThreadDeath" not found: image

jukzi commented 1 month ago

and after restart is was found again: image

iloveeclipse commented 1 month ago

today bizarr error

Could it be, your index is broken? Go to Preferences -> Java and click on "Rebuild Index".

stephan-herrmann commented 1 month ago

Given that some people see the problem kind-of frequently, and given that it stays until a restart of Eclipse, I think we have a chance to understand the problem:

I don't think this will directly reveal the bug, but at least it should show, where the incomplete information is cached. Is it JavaModel, JrtFileSystem, or ...?

stephan-herrmann commented 1 month ago

Those affected could for a while run Eclipse with remote debugging enabled (but suspend=n).

Here's how I prepare for switching between modes to invoke Eclipse:

jukzi commented 1 month ago
  • Set breakpoints in relevant implementations of INameEnvironment.findType(), perhaps with a condition to stop only for the specific type that is not found.

i am trying to prepare such environment. which exactly is the relevant findType()? org.eclipse.jdt.internal.core.NameLookup.findType(String, IPackageFragment, boolean, int, boolean, boolean) ? i guess org.eclipse.jdt.internal.core.ClassFile.existsUsingJarTypeCache() is supposed to return true, so i could put a breakpoint there?