Call for testing: Dead code analysis mode in VSCode

Hi!

Together with @cristianoc I’ve been developing a “Dead code analysis mode” for the ReScript VSCode extension, and we’re now looking for people interested in helping out with testing.

In a nutshell, it lets you activate a mode in the editor where dead code analysis is continuously run (using reanalyze), reporting all dead code in the problems pane, and highlighting it inside of the editor itself. It also provides code actions for suppressing the dead code warnings.

Here’s a GIF showing how it works:

A note - this is highly experimental, and it’s not guaranteed that this will make it into the official VSCode extension. However, testing and making sure it works well will surely increase the likelihood.

Instructions

  1. Download and install the vsix including the feature from here. You can install the vsix by opening it in VSCode, or by right clicking it when viewed via VSCode’s folder structure, and selecting “Install Extension VSIX”.
  2. Open up the command palette, and run > ReScript: Start dead code analysis. This starts the dead code analysis mode, and you should now see any dead code highlighted.
  3. You can turn off the dead code analysis (and clear any errors reported) at any time via “Stop Dead Code Analysis mode” in the bottom right status bar.
  4. You can uninstall the VSCode package and revert back to the officially published extension version at any time.

Report any issues or feedback here. We’re especially interested in someone using Windows trying this out.

Thank you for trying it out!

11 Likes

This feature looks very promising, great work by the both of you :clap:

I just tried running this on our project and it seems to work, but I have a source folder with generated code in it since I use rescript-relay :wink:

And that leads to a lot of “false” positives for the dead code analysis, so is there a way to make it ignore folders?

1 Like

Quick input from testing this. It would be nice if the command to start the dead code analysis would turn into a stop command when it’s running. I know you can click the button at the bottom of the UI, but my initial reach was for the command palette:

I think I’m getting a false dead code analysis in this case where I have a custom compare Module:

module ArticleCmp = Belt.Id.MakeComparable({
  type t = article
  let cmp = (a1, b1) => compare(a1.name, b1.name)
})

Which is later used like this:

let articleSet = allArticles->Belt.Set.Dict.fromArray(~cmp=ArticleCmp.cmp)

The analysis say that ArticleCmp.cmp is never used, which it is.

But other than that I found a lot of dead code I never realised we had, thanks!

1 Like

Great! I’d say we can discuss the false positives internally at rescript-relay, there’s ongoing work to suppress all of those false positives. False positives can be a problem for a lot of apps that use codegen or PPX:es in any way, so it needs to be addressed at “the source”.

Anyway, as for configuration, me and @cristianoc spoke about it being a good idea for reanalyze to accept config in bsconfig.json or similar, which would then make it possible to configure reanalyze project wide. That would make the extension able to pick up the configuration.

I’ll look up whether that’s already possible with reanalyze, and if not, file a ticket for it.

1 Like

Any idea how this would work in a monorepo using workspaces, with many subpackages? (but a single root bsconfig.json and pinned packages).

Could you try it and see what happens? It’d be interesting to see.

It works by invoking reanalyze in the directory of the current file you’re in when starting it. Reanalyze then walks up until it finds a bsconfig. Maybe @cristianoc has more specifics on exactly how it’d work in the scenario you describe.

Hmm yes. In this case we have 2 levels of bsconfig.json files (one at the root of the monorepo, and one for each package).

I have incorrect dead code analysis on functors that are actually used (whole functor and its contents are marked as dead). And also if I apply a functor like this:

module Tabs = Tabs.Tabs(Messages)

Event though MyModule.Tabs is used directly, it is marked as dead.

Other than that it looks to work well inside of a monorepo!
It doesn’t work in a monorepo with pinned packages. That would be a killer feature though, because interdependent packages have a lot of “dead” code in isolation.
It now kind of arbitrarily picks one of the packages in the monorepo, and reports the dead code analysis on that one.

I think that this might be better to report on the reanalyze issue tracker together with a reproduction, if you don’t mind.

Ahh, interesting! The way it initiates dead code analysis now, which needs to be made much more clear, is by taking the file the command is ran from, and look for the closest bsconfig. So, just for testing purposes, I’m curious as to what happens if you open the monorepo bsconfig and run the command? That should make reanalyze use the monorepo’s bsconfig, hopefully.

Other than that maybe @cristianoc can comment on compability of reanalyze and monorepos/pinned packages. I agree it would be a great/vital feature for monorepos.

For me it did not start in a monorepo at all.
EDIT: @zth I also tried to open it from the root bsconfig.json as you suggested, but no luck. Nothing happens.

Due to certain constraints in reanalyze, monorepos can’t be properly analysed. Can’t even tell what work would be needed to make it work, so we will put a disclaimer about this detail in the README.

@zth work will be shipped in the upcoming release. Thanks for the great work!

4 Likes

If I understood it correctly, reanalyze uses a json file produced by the compiler to figure out what locations it should read artifacts from for the analysis. The compiler does not produce a file like that for the entire monorepo. So, for reanalyze to be able to work, the compiler would need to produce a file like that for the entire monorepo.

2 Likes

Amazing clarification. Would it be possible to create a ticket in the compiler with a technical description of the work necessary as a starting point for an open source contribution. There might be some people at companies that can pick this up as it’s a super valuable tool when it supports monorepos.

2 Likes

I’m doing educated guesses here, so we’d need comments from @cristianoc and/or @Hongbo for how hard this would be and what would be needed, but from doing some research I gathered this:

I guess to test the solution, without making any compiler changes, you could try creating that file synthetically by concatenating and transforming each .sourcedirs.json from each monorepo package, into a single .sourcedirs.json in the appropriate location of the monorepo root. And then run reanalyze in the monorepo root and see what happens.

3 Likes

Hi, I would suggest you have a look at the format of .bsbuild. It is stable and has all the info you need.

2 Likes

Out of curiosity, could this extension support reanalyze’s exception analysis? It would be amazing to see unhandled exception warnings directly in VSCode.

This is actually already possible. You can configure reanalyze to run exception analysis: https://github.com/rescript-lang/rescript-vscode#configuring-the-code-analyzer

As soon as we’ve stabilized the integration of reanalyze in the extension, and possibly extended it a bit more, we’re planning on doing some material on how to make as much use of reanalyze and the integration of it in the extension as possible.

2 Likes

I installed the latest vsix from https://github.com/zth/rescript-vscode-dead-code-analysis-vsix/tree/main , however getting an error when I try to run the ‘ReScript: Start Code Analyzer’ command:

Command ‘ReScript: Start Code Analyzer’ resulted in an error (command ‘rescript-vscode.start_code_analysis’ not found)

It’s OK, I’ll wait a bit for this to mature :slight_smile: