redhat-developer / vscode-java

Java Language Support for Visual Studio Code
Eclipse Public License 2.0
2.08k stars 442 forks source link

Remove duplicate listing of Symbols #3452

Closed rajinder-yadav closed 6 months ago

rajinder-yadav commented 10 months ago

Type: Bug

When searching for Symbols in workspace, IDE will show duplicates.

Open a Java source file, then perform a Symbol lookup in the workspace. Search for "ArrayList" and you will see several duplicates in the list.

snap-20240107-01

Extension version: 1.25.1 VS Code version: Code - Insiders 1.86.0-insider (9621add46007f7a1ab37d1fce9bcdcecca62aeb0, 2023-12-20T05:36:34.875Z) OS version: Linux x64 6.6.7-1-default Modes:

System Info |Item|Value| |---|---| |CPUs|AMD Ryzen 9 5900X 12-Core Processor (24 x 3998)| |GPU Status|2d_canvas: enabled
canvas_oop_rasterization: disabled_off
direct_rendering_display_compositor: disabled_off_ok
gpu_compositing: enabled
multiple_raster_threads: enabled_on
opengl: enabled_on
rasterization: enabled
raw_draw: disabled_off_ok
skia_graphite: disabled_off
video_decode: enabled
video_encode: disabled_software
vulkan: disabled_off
webgl: enabled
webgl2: enabled
webgpu: disabled_off| |Load (avg)|0, 1, 1| |Memory (System)|62.71GB (48.35GB free)| |Process Argv|/home/yadav/dev/docs/guides --crash-reporter-id 210d9130-10f4-4cf9-ad76-187d60112fd6| |Screen Reader|no| |VM|0%| |DESKTOP_SESSION|plasma5| |XDG_CURRENT_DESKTOP|KDE| |XDG_SESSION_DESKTOP|KDE| |XDG_SESSION_TYPE|x11|
A/B Experiments ``` vsliv695:30137379 vsins829:30139715 vsliv368:30146709 vsreu685:30147344 vspor879:30202332 vspor708:30202333 vspor363:30204092 vslsvsres303:30308271 vsc_aa:30263845 vshan820:30294714 vscod805cf:30301675 bridge0708:30335490 bridge0723:30353136 vsaa593cf:30376535 py29gd2263:30784851 vsclangdf:30492506 c4g48928:30535728 2i9eh265:30646982 pythongtdpath:30726887 i26e3531:30792625 welcomedialog:30812478 pythonidxpt:30768918 pythonnoceb:30776497 asynctok:30898717 dsvsc013:30777762 dsvsc014:30777825 dsvsc015:30821418 pythontestfixt:30866404 pythonregdiag2:30926734 pyreplss1:30879911 pythonmypyd1:30859725 pythoncet0:30859736 pythontbext0:30879054 accentitlementst:30870582 dsvsc016:30879898 dsvsc017:30880771 dsvsc018:30880772 aa_t_chat:30882232 cp7184t3:30927821 ```
rgrunber commented 10 months ago

I'm able to reproduce this by creating a multi-module Maven project where modules have different compiler requirements. For example, one project has source/target 1.8 while another has 17.

When I search for ArrayList, the 2 results (among others) coming from the language server are :

[
    ...
    ...
    {
        "name": "ArrayList",
        "kind": 5,
        "location": {
            "uri": "jdt://contents/rt.jar/java.util/ArrayList.class?=com.example.project-eight-my-app/%5C/usr%5C/lib%5C/jvm%5C/java-1.8.0-openjdk-1.8.0.392.b08-7.fc39.x86_64%5C/jre%5C/lib%5C/rt.jar=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/javase%5C/8%5C/docs%5C/api%5C/=/=/maven.pomderived=/true=/%3Cjava.util(ArrayList.class",
            "range": {
                "start": {
                    "line": 0,
                    "character": 0
                },
                "end": {
                    "line": 0,
                    "character": 0
                }
            }
        },
        "containerName": "java.util"
    },
    {
        "name": "ArrayList",
        "kind": 5,
        "location": {
            "uri": "jdt://contents/java.base/java.util/ArrayList.class?=com.example.project-two-my-app/%5C/usr%5C/lib%5C/jvm%5C/java-17-openjdk%5C/lib%5C/jrt-fs.jar%60java.base=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/en%5C/java%5C/javase%5C/17%5C/docs%5C/api%5C/=/=/maven.pomderived=/true=/%3Cjava.util(ArrayList.class",
            "range": {
                "start": {
                    "line": 0,
                    "character": 0
                },
                "end": {
                    "line": 0,
                    "character": 0
                }
            }
        },
        "containerName": "java.util"
    }
]

In your case, the paths probably look even more similar because in your case, the 2 JREs are above version 9 (so it'd be a module path).

If you can confirm that's what's happening in your case, I think this still raises a good point. If someone has 2 Types (or even visible member) coming from different libraries that look identical, we should probably add version information to how its displayed to make it more clear.

rajinder-yadav commented 10 months ago

My java project is based off a maven project, I am only using java 21.

As for a working solution, I makes sense to see items from the version used in the project. It's possible the local installed version of java could differ from the one the project is getting built with and run off. As a developer, I only care for what the version the project is based on, which could be:

I use SDKMAN to install different java versions, but I don't think this is the cause of what getting shown in vscode for symbols.

I'm not sure how VSCode determines where to find the java/jdk to use? I did a search from my environment variables. I know I am setting the values for JAVA_HOME and JRE_HOME is my .bashrc script to that of the SDKMAN install location.

Not sure what is setting JAVA_BINDIR, JAVA_ROOT value? or is VSCode even uses these values.

$ set|grep JAVA
JAVA_BINDIR=/usr/lib64/jvm/jre-openjdk/bin
JAVA_HOME=/home/yadav/.sdkman/candidates/java/current
JAVA_ROOT=/usr/lib64/jvm/jre-openjdk

$ set|grep JRE
JRE_HOME=/home/yadav/.sdkman/candidates/java/current/bin

SDKMAN version:

$ sdk current java

Using java version 21-tem

Current java version

$ java -version
openjdk version "21" 2023-09-19 LTS
OpenJDK Runtime Environment Temurin-21+35 (build 21+35-LTS)
OpenJDK 64-Bit Server VM Temurin-21+35 (build 21+35-LTS, mixed mode, sharing)

Maven POM

Project java version is set to 21

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.1</version>
    <relativePath /> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.ninja</groupId>
  <artifactId>collection</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>h2-jpa-maven</name>
  <description>Demo project for Spring Boot</description>
  <properties>
    <java.version>21</java.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <excludes>
            <exclude>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
            </exclude>
          </excludes>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

Let me know if there is any other investigation I can help with, like any log file or debug output vscode might show.

rgrunber commented 10 months ago

That ArrayListPointer symbol in your original screenshot would seem to be coming from an OpenJ9 JDK. Any chance that's the 2nd JDK being picked up ? One thing you could try is temporarily setting the java.trace.server to verbose (default is off). Go into VS Code's "Output" tab (often beside the "Problems" view), and select "Language Support for Java" from the dropdown. Now try to search for "ArrayList" using the workspace symbol search. Since the search is incremental, you'll want to look for an entry like :

[Trace - 16:14:10] Sending request 'workspace/symbol - (34)'.
Params: {
    "query": "ArrayList"
}

(you can search for "query": "ArrayList" as a search term, and everything below it should be elements that matched that query.)

You should probably see 2 entries (among a few others) whose "containerName" is "java.util", and whose "name" is "ArrayList". Look at their uri value and that should indicate which JDK is contributing them. For example, in my case it was :

"uri": "jdt://contents/rt.jar/java.util/ArrayList.class?=com.example.project-eight-my-app/%5C/usr%5C/lib%5C/jvm%5C/java-1.8.0-openjdk-1.8.0.392.b08-7.fc39.x86_64%5C/jre%5C/lib%5C/rt.jar=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/javase%5C/8%5C/docs%5C/api%5C/=/=/maven.pomderived=/true=/%3Cjava.util(ArrayList.class"

"uri": "jdt://contents/java.base/java.util/ArrayList.class?=com.example.project-two-my-app/%5C/usr%5C/lib%5C/jvm%5C/java-17-openjdk%5C/lib%5C/jrt-fs.jar%60java.base=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/en%5C/java%5C/javase%5C/17%5C/docs%5C/api%5C/=/=/maven.pomderived=/true=/%3Cjava.util(ArrayList.class"

which are clearly /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.392.b08-7.fc39.x86_64 & /usr/lib/jvm/java-17-openjdk

rajinder-yadav commented 10 months ago

Hi here is what I am seeing

{
        "name": "ArrayList",
        "kind": 5,
        "location": {
            "uri": "jdt://contents/java.base/java.util/ArrayList.class?=jdt.ls-java-project/%5C/home%5C/yadav%5C/.sdkman%5C/candidates%5C/java%5C/11.0.11.j9-adpt%5C/lib%5C/jrt-fs.jar%60java.base=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/en%5C/java%5C/javase%5C/11%5C/docs%5C/api%5C/=/%3Cjava.util(ArrayList.class",
            "range": {
                "start": {
                    "line": 0,
                    "character": 0
                },
                "end": {
                    "line": 0,
                    "character": 0
                }
            }
        },
        "containerName": "java.util"
    },
    {
        "name": "ArrayList",
        "kind": 5,
        "location": {
            "uri": "jdt://contents/java.base/java.util/Arrays$ArrayList.class?=jdt.ls-java-project/%5C/home%5C/yadav%5C/.sdkman%5C/candidates%5C/java%5C/11.0.11.j9-adpt%5C/lib%5C/jrt-fs.jar%60java.base=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/en%5C/java%5C/javase%5C/11%5C/docs%5C/api%5C/=/%3Cjava.util(Arrays$ArrayList.class",
            "range": {
                "start": {
                    "line": 0,
                    "character": 0
                },
                "end": {
                    "line": 0,
                    "character": 0
                }
            }
        },
        "containerName": "java.util.Arrays"
    },
rgrunber commented 9 months ago

The 2 entries aren't duplicates though. One is java.util.Arrays.ArrayList and the other is java.util.ArrayList. There must be a 2nd entry (among others) that is either java.util.ArrayList or java.util.Arrays.ArrayList. The uri of that one would give some more information. Both the above entries are coming from /home/yadav/.sdkman/candidates/java/11.0.11.j9-adpt

rajinder-yadav commented 9 months ago

So why does vscode show each 2 times in the snapshot? I've opened the same project in IntelliJ and it shows each once.

fbricon commented 9 months ago

@rajinder-yadav was the trace you pasted really complete? Please attach the entire json response

rgrunber commented 9 months ago

I can reproduce this. I took a single-module Maven project and simply set the compiler runtime to something other than 17. It's also reproducible with Gradle.

<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
{
        "name": "ArrayList",
        "kind": 5,
        "location": {
            "uri": "jdt://contents/java.base/java.util/ArrayList.class?=jdt.ls-java-project/%5C/usr%5C/lib%5C/jvm%5C/java-17-openjdk%5C/lib%5C/jrt-fs.jar%60java.base=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/en%5C/java%5C/javase%5C/17%5C/docs%5C/api%5C/=/%3Cjava.util(ArrayList.class",
            "range": {
                "start": {
                    "line": 0,
                    "character": 0
                },
                "end": {
                    "line": 0,
                    "character": 0
                }
            }
        },
        "containerName": "java.util"
    },
    ...
    ...
   {
        "name": "ArrayList",
        "kind": 5,
        "location": {
            "uri": "jdt://contents/java.base/java.util/ArrayList.class?=my-app/%5C/usr%5C/lib%5C/jvm%5C/java-11-openjdk-11.0.21.0.9-3.fc39.x86_64%5C/lib%5C/jrt-fs.jar%60java.base=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/en%5C/java%5C/javase%5C/11%5C/docs%5C/api%5C/=/=/maven.pomderived=/true=/%3Cjava.util(ArrayList.class",
            "range": {
                "start": {
                    "line": 0,
                    "character": 0
                },
                "end": {
                    "line": 0,
                    "character": 0
                }
            }
        },
        "containerName": "java.util"
    },
    ...
    ...

The interesting part is : ?=my-app/%5C/usr%5C/lib%5C/jvm%5C/java-11-openjdk-11.0.21.0.9-3.fc39.x86_64%5C/lib%5C/jrt-fs.jar vs. ?=jdt.ls-java-project/%5C/usr%5C/lib%5C/jvm%5C/java-17-openjdk%5C/lib%5C/jrt-fs.jar

You were right @fbricon , it looks like the default project's classpath is part of the search. I would guess it should be disabled when the project isn't invisible.. or it should also react to the change to keep everything the same.

I wouldn't mind having @rajinder-yadav post that extra symbol data to confirm but this is very likely the cause.

rajinder-yadav commented 9 months ago

@rajinder-yadav was the trace you pasted really complete? Please attach the entire json response

vscode-java-trade.txt

rgrunber commented 9 months ago

Thanks! Yup, it looks like the same issue. Your "collections" project is configured with Java 21 but the "default" project (jdt.ls-java-project) is set to Java 11.

{
      "name": "ArrayList",
      "kind": 5,
      "location": {
        "uri": "jdt://contents/java.base/java.util/ArrayList.class?=collections/%5C/home%5C/yadav%5C/.sdkman%5C/candidates%5C/java%5C/21-tem%5C/lib%5C/jrt-fs.jar%60java.base=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/en%5C/java%5C/javase%5C/20%5C/docs%5C/api%5C/=/=/maven.pomderived=/true=/%3Cjava.util(ArrayList.class",
        "range": {
          "start": {
            "line": 0,
            "character": 0
          },
          "end": {
            "line": 0,
            "character": 0
          }
        }
      },
      "containerName": "java.util"
    },
    ...
    ...
    {
      "name": "ArrayList",
      "kind": 5,
      "location": {
        "uri": "jdt://contents/java.base/java.util/ArrayList.class?=jdt.ls-java-project/%5C/home%5C/yadav%5C/.sdkman%5C/candidates%5C/java%5C/11.0.11.j9-adpt%5C/lib%5C/jrt-fs.jar%60java.base=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/en%5C/java%5C/javase%5C/11%5C/docs%5C/api%5C/=/%3Cjava.util(ArrayList.class",
        "range": {
          "start": {
            "line": 0,
            "character": 0
          },
          "end": {
            "line": 0,
            "character": 0
          }
        }
      },
      "containerName": "java.util"
    },
    ...
    ...

There's 2 things we should probably do as part of this :

1) Maybe set the default project to any project JDK that is in use, just to avoid the duplication. I considered disabling the default project during the symbol search lookup but that option doesn't seem too great 2) For any workspace symbol results originating from the same library, we should add some version number into the label to make it more obvious what's happening.