-
Notifications
You must be signed in to change notification settings - Fork 347
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
Handle Java-only build targets #2520
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the contribution @Arthurm1 ! Sorry it took me so long to get to it.
We ignore java build targets mostly due to the fact that we can't do anything with them currently. We still haven't figured out how to properly interoperate with a Java Language Server. There is a related issue scalameta/metals-feature-requests#5 that we need to handle in order to properly support java projects.
Although, recently @olafurpg worked on a java compiler plugin that can easily produce semanticdb files:
https://github.com/sourcegraph/lsif-java
This would enable us to support references, renames, implementations and better go to definition. To include that plugin in Metals we would most likely make the changes that you made in this PR, so this is I think a good start. I will need to spend some time working on Bloop next couple of weeks, so I can also take a look at the javacOptions endpoint. With that in place we could add the sourcegraph plugin and at least enable the previously mentioned features.
We will still need to figure out how to provide completions, hovers, signature help etc. We could probably use JDT, but I am not sure how to do it properly yet. Alternatively, we could try to start a java language server alongside metals, but I haven't done any research yet in that area.
metals/src/main/scala/scala/meta/internal/metals/FileSystemSemanticdbs.scala
Outdated
Show resolved
Hide resolved
metals/src/main/scala/scala/meta/internal/metals/FileWatcher.scala
Outdated
Show resolved
Hide resolved
metals/src/main/scala/scala/meta/internal/metals/ImportedBuild.scala
Outdated
Show resolved
Hide resolved
metals/src/main/scala/scala/meta/internal/metals/MetalsLanguageServer.scala
Outdated
Show resolved
Hide resolved
metals/src/main/scala/scala/meta/internal/metals/debug/BuildTargetClasses.scala
Outdated
Show resolved
Hide resolved
metals/src/main/scala/scala/meta/internal/metals/SemanticdbIndexer.scala
Outdated
Show resolved
Hide resolved
@@ -97,6 +97,7 @@ object MetalsTestEnrichments { | |||
libraries.flatMap(_.classpath.entries).map(_.toURI.toString).asJava, | |||
"" | |||
) | |||
// TODO test javacOptions? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would probably be useful once we start testing
Thanks for reviewing. In my mind this was an early stage of a lot more stages for Java support. Those next stages are probably beyond my knowledge. The reason I wanted this is that I had a Bloop PR for some level of Gradle Android support. Without Bloop's support for javacOptions I couldn't see the targets in Intellij. This was one way to see the targets in a UI. Didn't know there was a SemanticDB plugin coming along for Java - that's great news - go Olafur! I'd eventually like to see more done with build targets e.g. highlighting of source/resource directories in VSCode file explorer, context menus in the file explorer for running tests, finer control over clean/compile per target, target info pages showing dependencies/classpath, new-scala-file (and new java file) restricted to source dirs. But those are all nice-to-haves. I'll keep the PR as draft until javacOptions is supported. Feel free to say if you think Java support needs to go in a completely different direction. |
I've converted to using JavacOptions (rather than faking them) and failing gracefully if BSP doesn't support it. I was going to have a look at Bloop to see if it's easy enough to get JavacOptions supported there unless you've already started? |
I haven't looked into it yet. I was mostly focused on zinc migration. |
I've taken the existing Bloop JavacOptions PR, deployed locally and tested against this PR. All Java-only projects get recognised as build targets. They appear in the "Doctor", get compiled on "Clean compile workspace" and are navigable in the Metals Tree View. I've also tested against Intellij+BSP. Intellij was fine before but now it doesn't complain that Bloop doesn't support JavacOptions and it doesn't have any issues now that Bloop does support JavacOptions The Bloop PR looks complete. I didn't need to change any code - it just needed a rebase which only has a single line conflict. I think it's ready to merge post-rebase. I'm not sure what the protocol is for taking another's PR - should I create my own PR with their commit? I asked the author back in Jan about the status and got no response - but I will try again. |
@Arthurm1 Since it's more important now I will contact the author today and try to get it merged. Maybe release |
The Bloop PR is merged, you can use |
@tgodzik |
That is is exactly the plan 😅 |
Has anyone started work on that part already? I thought I might give it a go. |
@tgodzik So I went ahead and implemented the The problem is that I'm getting weird highlighting in the Java files when I click on a class/interface name... Note that I clicked on Is this something I have to handle in Metals or would this be the LSIF plugin supplying wrong position range info - I wasn't sure if I should raise an issue with the LSIF project or whether I need to delve into the Metals code |
We planned to include it as part of GSoC, but it's fine to implement it before. There will be some work required to also include JDT, so we can focus on that there.
I think that might be the LSIF plugin. You can check the positions by using the Thanks for taking a look at that! |
@Arthurm1 That issue has been fixed in the latest SNAPSHOT of semanticdb-javac. We're planning to cut a new release this week so it should not be a problem soon :) Don't hesitate to report other similar issues to https://github.com/sourcegraph/lsif-java/ We're actively working on the project. |
BTW, the command |
Thanks @tgodzik I'll be stopping before JDT :-) I just wanted my java targets to appear in Metals and the existence of LSIF plugin was an added bonus - although I'm not entirely sure what parts of functionality the plugin on its own delivers to Metals - references but not code completion? Anything else? @olafurpg Thanks for fixing - preemptively :-) I'll report any more issues now I know where the Metals/LSIF line is drawn. |
References, implementation, anything that needs to operate on the entire codebase at once. We use semanticdb in those case for indexes. |
Linked to scalacenter/bloop/pull/1534 @tgodzik I was wondering whether you're happy with the way I've split out Also - I'm not sure where to go next. I assume there has to be some kind of Java equivalent to |
I will take a look at that, but most likely next week. From what I remember it looked good, but I last looked at it a while ago.
I actually played a bit with it and it seems to use JDT we need to setup OSGI inside Metals, it should be possible, but I haven't managed to make it work properly. It also seems we need to create the entire project hierarchy, which also doesn't seem too straightforward. That said, JDT has interfaces for completions, formatting etc. which we could use in Metals to at least provide the basic functionalities, so this is for sure good place to start looking. I was also thinking if we could actually use the Java language server somehow and redirect a subset of queries to it 🤔 - we would most likely need to generate eclipse files (that's what Java LSP uses) and maybe then start the other server inside Metals? This way we would at least have the same functionalities as the current server has and we wouldn't need to implement everything from scratch. We could even set it up as a separate server and use LSP to communicate with it (forward completions, fallback definition etc.) This might actually be more doable than using JDT explicitely, but I am not sure if it will all play nicely. We could have separate JavaPresentationCompiler that would just start the Java Language Server underneath and we would run This is all just my ideas, we need to check if any of that makes sense. I am kind of tempted to use Java Language Server, because we would not need to reimplement everything ourselves this way, but it's still a lot of work. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like there is too much classes here, could we reduce it to a main trait Target
and two subtraits ScalaTarget
and JavaTarget
, where scala can contain also javac options? I would then use the main trait wherever possible, otherwise I feel like we are not leveraging inheritance enough.
We could even return scalaVersion
for JavaTargets, which would be the fallbackScalaVersion
, since any scala file in there will be a standalone file.
metals/src/main/scala/scala/meta/internal/metals/BuildTargets.scala
Outdated
Show resolved
Hide resolved
metals/src/main/scala/scala/meta/internal/metals/ScalaOnlyTarget.scala
Outdated
Show resolved
Hide resolved
metals/src/main/scala/scala/meta/internal/metals/JavaTarget.scala
Outdated
Show resolved
Hide resolved
Alternatively, I would just have a single |
These classes are really just wrappers round the java BSP4J classes and designed to extract info from them. I've shifted the extraction to
|
Looks pretty good, let's wait until the Bloop PR merge and test it out again. When testing it were you able to navigate java files? I wonder if we need to do something on the client side to make it work, but maybe that's enough. |
Yes - in a Java file in VSCode you can now: Code completions don't work but I'm assuming that's because there's no presentation compiler. Nor do formatting and re-factoring but just being able to navigate symbols makes using Java files a lot easier. Error highlighting doesn't highlight the correct range (just highlights the start of the line) but that should be fixed when scalacenter/bloop#1477 is merged |
171a7f5
to
69d9e50
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! There are a view things we can improve on such as adding code lense and renames, but I would rather not have it as part of this PR.
Awesome work! I think we'll be aiming for a release early next year, so we should have time to test everything out.
It seems that the eclipse is bringing in jars compiled with JDK 11 :/ We might need to go further back. And there is an issue with sbt tests, I will take a look at those. |
The problem seems to be that all transitive dependencies in eclipse jars are defined using ranges. e.g.
Version 3.9 was the last one compiled under jdk1.8 and then 3.10 was compiled under jdk11. Version 4.0.0 doesn't even exist yet. But because of this range use, the valid jdk1.8 jar is ignored for a later version. So I can't go back to an earlier eclipse version as the transitive dependency will still be jdk11. As far as I can see - there's no way round this but having to specify the exact version of every transitive dependency that's declared using ranges. Unless you know a better way? I can see the same issue in the move from 11 -> 17 sometime in the future |
An explicit version is like an right open range starting at that version. You can try to specify a rage ending at the last version that still supports Java 8. |
I'd still have to specify a version for every transitive dependency wouldn't I? I've only got 1 dependency in the build:
Sometime in those versions there's a switch from compiling using jdk8 to jdk11. So I'd have to work out what the last version compiled for jdk8 was for all of these jars, specify it and then look at all their dependencies and so on until no more ranges. Or am I missing something here? I've not used ranges before. |
As far a I know, Eclipse 4.16 was the last release which was built for Java 8. The probably easiest way to figure out which versions belong to it, is to download a Eclipse 4.16 release zip and look what jars are into it. But yes, I think there is no other easy way to select compatible versions, as this fact is not a property of the dependency artifacts. |
I once compiled a list of artifacts which belong to Eclipse 4.16 to use in some other closed projects.Don't know if it is of any help to you: https://gist.github.com/lefou/71b574af75c1b42653b1be8440561a8b#file-build_eclipse_bundles-sc |
@@ -112,6 +112,23 @@ inThisBuild( | |||
resolvers += Resolver.sonatypeRepo("public"), | |||
resolvers += Resolver.sonatypeRepo("snapshot"), | |||
dependencyOverrides += V.guava, | |||
dependencyOverrides += "org.eclipse.platform" % "org.eclipse.ant.core" % "3.5.500", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uff, this is a lot, thanks for compiling the list!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've had more fun afternoons
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If possible can we add a note here as to why we are doing this? I can see later on someone jumping in here and looking at this and wondering what in the world we are doing here with all these overrides.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking of moving it later to a separate file and commenting. This PR is pretty huge and I don't want to add anything more right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I think you did another comment and I can't find it 😅 which is a good indicator that this got way to big. What do you think? Is it ok to do same follow ups later?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:) of course, a follow-up is totally fine.
For the other comment 😆 I deleted it. A couple weeks ago I started reviewing this and only got like half way through and didn't realize I had draft comments saved, so when I added this comment it also posted those. They aren't relevant anymore, so I just removed them. Sorry for the noise!
val resultOnJavacOptionsUnsupported = new JavacOptionsResult( | ||
List.empty[JavacOptionsItem].asJava | ||
) | ||
if (isSbt) Future.successful(resultOnJavacOptionsUnsupported) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Arthurm1 I added this check since it seems that sbt shuts down when unexpected request is made.
@Arthurm1 It's all green! feel free to merge, we can improve things further later on. |
What's the standard - should I squash or ...? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incredible work @Arthurm1 🚀
Wow, this is magnificent @Arthurm1! |
The idea here is to make Metals aware of Java-only (i.e. non-Scala) build targets, which it currently discards.
This would mean that Java targets would appear in the Metals Tree View and the Doctor, and would be included in the
clean compile workspace
command.Bloop currently doesn't support
buildTarget/JavacOptions
endpoint which is needed for this.There is a Pull Request here, but I'm not sure what the state of it is.
For now I'm faking
buildTarget/JavacOptions
inscala.meta.internal.metals.ImportedBuild
by translating them from the scalacOptions. This can be dropped and the javacOptions endpoint could be used if/when Bloop supports it.I see Intellij BSP attempts to ask Bloop for
buildTarget/JavacOptions
and gets an error.I was hoping for some feedback on whether this is the right approach to take and what Metals is trying to do in the 10 places I've commented with
TODO
so that I'll know whether to handle java-only targets there as I'm unfamiliar with the majority of the codebase.There's not much to the PR. Most of it is splitting
BuildTargets#allScala
intoBuildTargets#allScala
,BuildTargets#allJava
,BuildTargets#allCommon
and the fallout from that.