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

Find reference triggers project recompilation under certain conditions #6348

Open
ghostbuster91 opened this issue Apr 25, 2024 · 0 comments
Open

Comments

@ghostbuster91
Copy link
Collaborator

ghostbuster91 commented Apr 25, 2024

Describe the bug

This is quite a complex issue, my apologies for a lengthy description. I am not submitting it as multiple issues because they are problematic only when combined.

Consider a simple project with two scala modules:

val moduleA = project
  .in(file("moduleA"))
  .settings(
    scalaVersion := "3.3.3"
  )

val moduleB = project
  .in(file("moduleB"))
  .settings(
    scalaVersion := "3.3.3",
  )

val root = project.in(file(".")).aggregate(moduleA, moduleB)

Let's assume that there is a method definition in module A:

object Person{
  def fromList(list: List[Any])={
    println(list)
  }
}

And some code that doesn't compile in module B.

If we call find references on Person.fromList we will see in the logs that a compilation request was issued for module B:

2024.04.25 19:31:20 INFO  compiling moduleb (1 scala source and 1 java source)
2024.04.25 19:31:20 INFO  time: compiled moduleB in 31ms
Apr 25, 2024 7:31:21 PM org.eclipse.lsp4j.jsonrpc.RemoteEndpoint handleCancellation
WARNING: Unmatched cancel notification for request id 204

Issue 1

I believe that this is incorrect as there is no dependency between module B and module A so there is no need to recompile it for the find reference request.

Issue 2

If we keep calling "find refenrences" metals will keep asking for a recompilation. Luckily, thanks to the incremental compilation this is usually fast.

Issue 3

Let's add following java code into module B:
src/main/java/com/example/Service.java:

package com.example;

import java.util.List;

public class Service {
	void create(List<Object> args) {
		var second = (java.util.Optional<String>) args.get(2);
		System.out.println(second);
	}
}

There is an unchecked cast in here.
Let's now remove the invalid scala code from this module and turn on fatal warnings together with linting for unchecked casts in the module B:

val moduleB = project
  .in(file("moduleB"))
  .settings(
    scalaVersion := "3.3.3",
    scalacOptions ++= Seq(
      "-Xfatal-warnings"
    ),
    javacOptions ++= Seq(
      "-Xlint:unchecked"
    )
  )

The interesting thing is that the project compiles now from both sbt and bloop.
It reports the detected unchecked cast in sbt as a warning:

[warn] /home/kghost/workspace/demos/moduleB/src/main/java/com/example/Service.java:8:1: unchecked cast
[warn]   required: java.util.Optional<java.lang.String>
[warn]   found:    java.lang.Object
[warn] args.get(2)

(call clean compile from metals before moving forward)

However in metals this is reported as an error:
image

[Trace - 07:51:31 PM] Sending notification 'textDocument/publishDiagnostics'
Params: {
  "uri": "file:///home/kghost/workspace/demos/moduleB/src/main/java/com/example/Service.java",
  "diagnostics": [
    {
      "range": {
        "start": {
          "line": 7,
          "character": 52
        },
        "end": {
          "line": 7,
          "character": 52
        }
      },
      "severity": 1,
      "source": "bloop",
      "message": " [unchecked] unchecked cast",
      "data": {
        "actions": []
      }
    }
  ]
}

If we now try to call find references on fromList metals will issue compilation request for module B and it will also do it on every subsequent invocation. This is probably due to module B being recognized as "broken".

If we now compile the project with bloop: bloop compile root it will compile fine (as mentioned previously) but from now on, metals won't issue recompile request for module B when calling find references on fromList.

Calling metals "clean compile" brings us back to the previous state.

This might not seem as a big deal, but at work we have a project with several sbt modules, one of them with more than a couple of thousands java classes, unchecked casts and fatal warnings enabled.

Calling find references in one module that is not connected with anything else cause recompilation of several other modules including the big one and is freezing my laptop. Every single time.

image

Full project to reproduce the behavior can be found here

Bloop version: 1.5.17

Expected behavior

First of all, I would expect "find references" not to trigger compilation of modules that aren't related.

Second, I would expect broken module not to be recompiled over and over again if nothing changed there.

And last, handling of fatal warnings + "-Xlint:unchecked" from java should be consistent among all tools. I am not sure which is the correct way.

Operating system

Linux

Editor/Extension

Nvim (nvim-metals)

Version of Metals

1.3.0

Extra context or search terms

java
fatal-warnings
lint-unchecked

@tgodzik tgodzik added this to Triage in Metals Issue Board via automation Apr 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

No branches or pull requests

1 participant