The Scala Plugin Blog : Scala Plugin for IntelliJ IDEA and Android Studio | The JetBrains Blog https://blog.jetbrains.com Developer Tools for Professionals and Teams Tue, 13 Jun 2023 10:09:39 +0000 en-US hourly 1 https://blog.jetbrains.com/wp-content/uploads/2023/02/cropped-icon-512-32x32.png The Scala Plugin Blog : Scala Plugin for IntelliJ IDEA and Android Studio | The JetBrains Blog https://blog.jetbrains.com 32 32 IntelliJ Scala Plugin 2023.1 Is Out! https://blog.jetbrains.com/scala/2023/03/29/intellij-scala-plugin-2023-1-is-out/ Wed, 29 Mar 2023 14:25:56 +0000 https://blog.jetbrains.com/wp-content/uploads/2023/03/Screenshot-2023-03-15-at-14.14.47.png https://blog.jetbrains.com/?post_type=scala&p=332918 Improved support for braceless Scala syntax

IntelliJ IDEA can now desugar braceless Scala code properly, and it handles refactorings where the “fewer braces” feature is used. It also supports braceless syntax in worksheets and correctly interprets indentation when you move extensions methods up and down in your code.

The indentation of the extension method is carried over correctly
The indentation of the extension method is carried over correctly

Streamlined import management

If you use compiler-based highlighting, until now all imports have been marked as used. Scala 3.3, however, introduced a new compiler option, -Wunused:imports. The IDE can now identify unused imports if your project uses this option. We’ve also fixed the auto-import action for Enums.

The Scala plugin can now identify unused imports when you use compiler-based highlighting

Better support for sbt projects 

When you have an empty module and want to create the root directory for the source code, you can use the New Directory dialog, which contains some helpful suggestions. With v2023.1, this dialog is now available for sbt projects, as well.

You can also specify the sbt launcher’s parameters in Settings/Preferences | Build, Execution, Deployment | Build Tools | sbt.

You can now specify the sbt launcher’s parameters
You can now specify the sbt launcher’s parameters

On top of that, we improved support for sbt cross-built projects. Now you can use JVM/JS/Native code from shared sources – completion, navigation and code highlighting will work.

And the Find Usages action now searches for symbols in sbt files.

Code editing improvements for Scala 3

We’ve improved the performance of Scala 3 highlighting when many implicit parameters are imported and are needed to parse the code, for example, when the Cats library is being used. IntelliJ IDEA 2023.1 also features many syntax support improvements, such as the proper automatic generation of overriding methods with using clauses.

The hint shows types for the using clause inferred from the available given declaration
The hint shows types for the using clause inferred from the available given declaration

Upgraded Scala inspections

The Unused declaration inspection has received a number of fixes and improvements. IntelliJ IDEA can now detect symbol usage in your project’s XML files. The inspection also distinguishes between references to terms and references to types, not tagging the one as in use if it is actually the other that is. The Can be private inspection was updated, as well. For example, you will no longer see highlighting for top-level definitions in worksheets and local classes. For recursive calls, you will now see a gutter icon to the left of the line with the call.

The classes is marked as used because of its mention in pom.xml
The classes is marked as used because of its mention in pom.xml

Improvements for Scala 3 and Scala 2 decompilers

IntelliJ IDEA 2023.1 brings numerous fixes and improvements to the Scala 3 and Scala 2 decompilers. The output of decompiling Scala 2 and Scala 3 bytecode has been unified and is now easier to read.

As always, your feedback is very welcome. Please report any issues you find to YouTrack. If you have any questions, feel free to ask us on Discord.

Happy developing!

The IntelliJ Scala plugin team

]]>
Performance tips for IntelliJ Scala Plugin https://blog.jetbrains.com/scala/2023/02/09/performance-tips-for-intellij-scala-plugin/ Thu, 09 Feb 2023 08:54:56 +0000 https://blog.jetbrains.com/wp-content/uploads/2023/01/Screenshot-2023-01-31-at-13.44.14.png https://blog.jetbrains.com/?post_type=scala&p=315471 A full-blown IDE is one of the most complicated applications you can find on an average laptop. This is why we – the Scala plugin team at JetBrains – from time to time receive reports that our product lags in certain situations or works slowly in general. In some of these cases we can help, but in others – for example, when your codebase is big and complicated, or when your machine is old – there is not much we can do. Instead, there are some things you can try yourself to improve your IntelliJ IDEA and the Scala plugin experience, like implementing configuration tweaks and maintaining good coding practices. We will quickly go through some of them.

First, let’s talk about two main areas of IntelliJ IDEA where performance matters:

  1. One important moment is when we create or open a project. This one involves memory management.
  2. The second one relates to complex logic, meaning the CPU-heavy operations when the Scala plugin tries to identify and highlight errors and warnings or display tips on how to improve the code, and also when you perform one of the actions provided by the Scala plugin and have a large portion of your code edited automatically.

In both cases, we can improve performance in similar ways. We can:

  • give IntelliJ IDEA more resources,
  • disable inspections we don’t use,
  • improve our coding practices,
  • and disable some of the features.

Resources

Let’s start with resources, which in this case basically means providing more memory. However, before you do that, I’d suggest you enable the memory indicator. You can do this by right-clicking on the bottom panel of IntelliJ IDEA and then, when the menu pops up, clicking on that memory indicator line there. It will tell you how much memory your IntelliJ IDEA actually uses, and you will be able to set the memory size accordingly.

An average laptop today has 8 gigabytes of RAM or more, which generally should be enough for IntelliJ IDEA, your other applications, and the operating system to all perform well.

After you check your IntelliJ IDEA memory consumption, open the idea.vmoptions file – you can do so by opening the Help menu and choosing Edit Custom VM Options – and change the -Xmx setting to a value slightly bigger than what the memory indicator showed you. Please note that over a certain value, increasing -Xmx won’t improve the performance anymore. In my case, increasing it to 4 gigabytes had some effect, but beyond that the additional improvement was negligible.

In the case of the Scala plugin, increasing available memory may also speed up compilation if you decide to compile your app from within IntelliJ IDEA. To do that, go to Settings | Build, Execution and Deployment | Scala Compiler Server, and modify the VM options there.

Inspections

Moving to the CPU side, one of the most important features of the Scala plugin – and one that can use a lot of CPU – is its set of inspections. An inspection is a piece of logic that, well, inspects your code, looking for a specific type of problem. Some of the problems are very simple, like a private variable that is never modified and so can be replaced with an immutable value. Others, like an unused public field, may take a long time to investigate.

If you suspect some of those inspections are of no use to you, disabling them may improve highlighting speed. You can go to Settings | Editor | Inspections, look through the list of available inspections, and disable any that you don’t need. As a bonus, browsing the settings might present a good opportunity for you to learn what all the Scala plugin has to offer.

Next, we’ll take a closer look at 3 of the Scala plugin’s many inspections. Please note that even if you disable these 3 inspections, the performance boost will likely be negligible. Each inspection is only a small part of the plugin’s logic, and for every user it might have a different impact and be more or less valuable.

  1. Type check can be replaced by pattern matching

This inspection looks for type checks and type casts in a series of if-else statements and suggests replacing them with pattern matching. Please note that even the most complex inspections have quick paths for checking that they do not apply to the given piece of code (e.g. when there is no isInstanceOf in it). However, in certain cases, you might want to use code that looks like this, and if you want it to stay that way, you might consider disabling the inspection.

2. Scala 2 syntax can be replaced with Scala 3

This inspection works only if you have enabled the compiler option -Xsource:3. It reports Scala 2 syntax that can be replaced with its Scala 3 alternatives. If you use -Xsource:3 for compatibility, but you don’t need to rewrite your code, you can safely disable it.

3. “Declaration access can be weaker” and “Unused declaration” inspections

For every declaration in your code, these two inspections will try to check how the declaration is used. The first one will work if the declaration is public or protected. It will check whether it is indeed used outside the scope of its own class, trait, or object. If it isn’t, the inspection will display a hint that the declaration can be made private. The second one works for every declaration – it goes through the declaration’s scope and checks whether it is used at all.

Coding practices

Scala lets us write complex code in concise ways and we tend to take full advantage of this. But there are costs attached: the more we leave for the IDE to figure out, the less performant it will become. As you could notice in the examples above, in many cases if you enforce strict coding practices, some of the inspections in the Scala plugin might become unnecessary. In fact, what the Scala plugin inspections do is not so different from what you or I would do if we had to figure out whether a declaration is unused or whether a variable could be a value. We would look around within the scope. We would try to find other elements that we might suspect of being connected to this one. We would look for subclasses, implicit conversions, and so on.

If a reviewer struggled with the complexity of your code, this might be a sign that your code could be improved and made easier to analyze. In a similar way, if you see that your IntelliJ IDEA slows down because inspecting your code takes too long, consider adjusting your coding practices:

  1. Set proper access modifiers to classes, methods, and declarations, to narrow the scope.
  2. Don’t overuse type inference.
  3. Limit the use of implicits.
  4. Prefer loose rather than tight coupling for components, so that the logic of the inspection will not have to follow too many paths.
  5. And in large projects, consider splitting your code into modules and submodules, again to limit how much there is for the inspections to cover.

You can also go to the Performance tab in Settings | Languages & Frameworks | Scala, look at the controls there, and consider whether your project’s performance might suffer from one of the issues these controls address. For example, if you use a lot of implicit parameters, figuring them out may take a long time. Or if you use big files where for every class and method you have a documentation entry in the comments that uses code examples, the Scala plugin will try to highlight it properly. You can try disabling these functionalities, and a few others as well.

Features

All the hints we talked about so far may help you in some special cases. Usually, if your machine is good enough – and as I mentioned before, an average laptop is already good enough – IntelliJ IDEA’s performance should be just fine. Only if your project is especially demanding, should these hints be of use.

But it might be that for some reason you have to use IntelliJ IDEA on an old, weak computer. In such a case, you may try a few more things to make your experience a bit better. Go to Settings | Appearance & Behavior | Appearance, and disable antialiasing and smooth scrolling. Your fonts will appear less smooth, and when you scroll through the contents of your files, that will feel less smooth as well, but both of these features have some impact on performance. If that’s not enough, you can open the File menu and enable Power Save Mode. This will turn off a lot of IntelliJ IDEA’s features, so I suggest doing it only if nothing else helps.

If this is too extreme for you, you may try the Automatic Power Saver plugin, which you can install from JetBrains Marketplace. It will let you control when Power Save Mode should be automatically turned on and off, letting you still use IntelliJ IDEA’s more complex features when you need them.

Another option is to disable type-aware annotators. You can do it by clicking on the small “[T]” sign in the lower right corner of the IntelliJ IDEA main window.

It will stop the Scala plugin from checking types in your code. Note that it will not disable all errors checks, but only those where an error is caused because the types don’t much, like for example when you try to pass a String as an argument to a method that accepts an Int.

Tell us about your issue

Last but not least, if you experience slow performance, especially in some specific situations that you can reproduce, this might be pointing to a problem within the Scala plugin. Please write to us about it. Even better, install the Performance Testing plugin, capture a performance snapshot, create a ticket in the JetBrains YouTrack system, and upload the snapshot there. Your feedback will help us identify the causes of the problem and fix them, making the Scala plugin more efficient and more enjoyable for all of us.

]]>
https://blog.jetbrains.com/zh-hans/scala/2023/02/09/performance-tips-for-intellij-scala-plugin/ https://blog.jetbrains.com/ko/scala/2023/02/09/performance-tips-for-intellij-scala-plugin/
IntelliJ Scala Plugin 2022.3 Is Out! https://blog.jetbrains.com/scala/2022/11/30/intellij-scala-plugin-2022-3-is-out/ Wed, 30 Nov 2022 18:39:05 +0000 https://blog.jetbrains.com/wp-content/uploads/2022/11/1_Improved_Scala3_Support-1.png https://blog.jetbrains.com/?post_type=scala&p=296734 This release has been again focused on Scala 3, but there are also quite a few other improvements.

Better Scala 3 support

In v2022.3, we’ve introduced a large number of upgrades to provide better Scala 3 support. The IDE now supports parameter untupling and quoted patterns, and it features many improvements to the support for match types and type variables. There is now type inference for type variables, and they are parsed correctly for pattern-matching purposes. Named arguments in the trait constructor are now correctly handled, and you can use an action to quickly create a Scala 3 enum file or just an empty Scala file for top-level definitions. We also have numerous TASTy Reader enhancements, resulting in better highlighting accuracy and improved editor performance.

Quickly create a Scala 3 enum file or just an empty Scala file for top-level definitions

Parameter types and context bounds

Parameter info is now displayed for type parameters (previously it was only displayed for value parameters), and it is now smarter. Formerly, you may have seen that in the Parameter Info popup, the context bounds were desugared, showing implicit parameters. Now the code in the prompt is resugared and more readable. This might be especially useful for maintainers of libraries that use higher-kinded types.

The code in the prompt is resugared and more readable

New Can be private inspection

Sometimes it is possible to make a public class, method, or field private or protected. When the code is complex, however, it can be challenging to know whether this is the case. A new Can be private inspection now helps you be sure, and it will also propose a quick-fix. By actually marking members that can be private as private, you can keep interfaces separate from implementation details, making it easier to understand the code. This also reduces the noise during autocompletion, making the process of using it easier and faster, with less cognitive load incurred. It even improves the performance of the compiler and of the IDE.

“Can be private” may help you make sure you can change the access

Create parameter from usage

If you have an unresolved symbol inside a method, there is now a new quick-fix that lets you add this symbol to the list of the method’s parameters.

A new quick-fix lets you add a symbol to the list of the method’s parameters

But wait, there’s more!

If your project requires the compile order to be first Java, then Scala, and you use SBT or Maven, you might have encountered an issue where after refreshing the project from the build script, the order is automatically changed to “Mixed”. This is fixed now.We now have previews for quick-fixes displayed by default when it’s applicable, we support the new Settings Sync plugin, and we made performance improvements to actions such as checking if a class member has overrides, expensive lookups of elements, and to the compile server’s performance.

We now have previews for quick-fixes displayed by default

Dropped features

We dropped support for some old and unused elements of the Scala ecosystem:

  • Scala scripts
  • Scala Server Pages
  • Lift framework

As always, your feedback is very welcome. Please report any issues you find to YouTrack. If you have any questions, feel free to ask us on Discord.

Happy developing!

The IntelliJ Scala plugin team

]]>
IntelliJScala @ ScalaCon 2022 https://blog.jetbrains.com/scala/2022/10/18/intellijscala-scalacon-2022/ Tue, 18 Oct 2022 09:25:09 +0000 https://blog.jetbrains.com/wp-content/uploads/2022/10/scalacon.jpg https://blog.jetbrains.com/?post_type=scala&p=287668 ScalaCon 2022 has come and gone. It started on Tuesday, October 4, and over the course of 4 days, the audience had the chance to enjoy 21 talks and 2 keynotes. JetBrains was a Gold Sponsor of the event, which meant that we, the Scala Plugin team, had the opportunity to participate, present a lightning talk, and answer questions from attendees who came to our virtual booth.

In our lightning talk, we shared tips for improving the performance of IntelliJ IDEA and the Scala plugin. In most cases, your laptop should be perfectly capable of running them. Still, there are certain situations where a trick or two could help with slow initialization or lagging when highlighting warnings and errors, or could simply improve your overall experience with IntelliJ IDEA. The talk was pre-recorded, so if you missed it, you can still watch it here.

Among the other talks we enjoyed were Martin Odersky’s keynote, Simply Scala, and Josep Prat’s Preparing Apache Kafka for Scala 3. In both of them, the speakers promoted simple, concise code that is well-planned and written in a way that allows future maintainers to work with it easily. In the Scala plugin team, we believe that our work helps developers do just that.

And what about you? What talks did you like? You can find us on Twitter or Discord and share your thoughts.

]]>
IntelliJ Scala Plugin 2022.2 Is Out! https://blog.jetbrains.com/scala/2022/07/26/intellij-scala-plugin-2022-2-is-out/ Tue, 26 Jul 2022 14:18:36 +0000 https://blog.jetbrains.com/wp-content/uploads/2022/07/ScalaPlugin_2022_2_Whats_New_BetterScala3.png https://blog.jetbrains.com/?post_type=scala&p=266825 This release has been again focused on improving Scala 3 support, but there are also a few other improvements.

Better Scala 3 support

As of v.2022.2, IntelliJ IDEA can read match types from .tasty files, properly parse them, resolve type variables, use them as type arguments, support inspections, and show types as text.

On top of that, we’ve added support for Option-less extractors, type lambdas and polymorphic function types, type-level compiler intrinsics, and ? as a wildcard together with _ in Scala 2.13.9 and 2.12.16. Copy-pasted code is also now properly indented.

Compiler-based highlighting for Scala

Configuring a new compiler-based highlighting has been tuned for better resource usage. The IDE now respects the file highlighting settings defined by the user.  Compilation is now triggered in fewer cases and uses fewer background threads. The compilation scope has been reduced to the relevant module and source scope.

New Scala inspections

IntelliJ IDEA 2022.2 now warns you when a return keyword is being used inside an anonymous function to jump out of the function without executing all the code inside it. This is usually not an intended usage, and can lead to leaky implementation and hidden performance costs. 

There’s a new warning triggered when a private or class parameter shadows a superclass variable. Additionally, an error is displayed when you try to override a variable in a way that is forbidden by the compiler. These new warnings can be configured to be displayed if their respective compiler options (-Xlint:nonlocal-return and -Xlint:private-shadow) are present.

Safe Delete is now available for type parameters

The Safe Delete action removes an element from the definition and all of its calls. This action now also works for type parameters.

Splitting a comma-separated list of elements into separate lines

If you have a line of code that is excessively long because it contains a list of arguments or elements in a collection, you can now use the Put arguments on separate lines action from the popup menu to quickly split the list into multiple lines. The opposite is also possible – if you think a multi-line list is short enough, you can use the Put arguments on one line action to make them one line.

As always, your feedback is very welcome. Please report any issues you find to YouTrack. If you have any questions, feel free to ask us on Discord.

Happy developing!

The IntelliJ Scala plugin team

]]>
IntelliJ Scala Plugin 2022.1 Is Out! https://blog.jetbrains.com/scala/2022/04/12/intellij-scala-plugin-2022-1/ Tue, 12 Apr 2022 15:41:38 +0000 https://blog.jetbrains.com/wp-content/uploads/2020/07/IntelliJScala5.png https://blog.jetbrains.com/?post_type=scala&p=207106 This release has been focused on improving Scala 3 support. There are also several new features to help with day-to-day Scala programming. Let’s take a closer look:

1. Scala 3 support improvements
2. New Scala project wizard
3. Alias exports
4. Unused declaration inspection
5. Scala debugger upgrades

Scala 3 support improvements

This release includes many Scala 3 support improvements:

  • It is now possible to autocomplete extension methods (to see methods from other objects, press Ctrl+Alt+Space twice).
  • The editor offers to import extension methods and given instances automatically.
  • New inspections for the infix modifier and @targetName annotation can help you maintain a consistent code style.
  • We’ve significantly improved the performance of the .tasty reader, so indexing Scala 3 libraries is now up to twice as fast.

New Scala project wizard

Configuring a new Scala project just got easier! With the updated New Project wizard, you can select a JDK, desired build system, and Scala version for your project in a single step:

Alias exports

Most things in Scala are aliases, including String, Seq, List, Set, and Map. This affects syntax highlighting, GoTo, Quick Documentation, Quick Definition, Find Usages, Optimize Imports, and other IDE features, because they act on aliases rather than actual definitions. To improve the user experience, the editor now treats aliases in the standard library as transparent exports, so, for example, List implies scala.collection.immutable.List rather than scala.List:

Unused declaration inspection

Previously, the detection of unused declarations was limited to private bindings. Now the Unused declaration inspection supports public bindings introduced by classes, methods, variables, parameters, and so on:

Currently, this functionality has to be enabled in the inspection settings (Settings | Editor | Inspections | Scala | General | Unused declaration), but we will enable the feature by default in the bug-fix release.

Scala debugger upgrades

In this release, we’ve made an effort to revamp and streamline the Scala debugger. We’ve upgraded the handling of objects, primary constructor parameters, value classes, Arrays, lazy vals, and collections, in addition to improving expression evaluation:

As always, your feedback is very welcome. Please report any issues you find to YouTrack. If you have any questions, feel free to ask us on Discord.

Happy developing!

The IntelliJ Scala plugin team

]]>
IntelliJ Scala Plugin 2021.3 Is Out! https://blog.jetbrains.com/scala/2021/11/30/intellij-scala-plugin-2021-3/ Tue, 30 Nov 2021 17:55:00 +0000 https://blog.jetbrains.com/wp-content/uploads/2020/07/IntelliJScala5.png https://blog.jetbrains.com/?post_type=scala&p=207105 This release brings more improvements to Scala 3 support. There are also several new features to help with day-to-day Scala programming. Let’s take a closer look:

1. Scala 3 support improvements
2. Open cross-compiled projects as Scala 2
3. Data flow analysis for Scala
4. Autocomplete for Scala compiler options
5. Inlay hints for ranges

Scala 3 support improvements

Our main focus in this release has been Scala 3 support:

  • We’ve added highlighting, navigation, and autocompletion for end markers.
  • Autocompletion is now provided for the given, using, and export keywords, soft keywords, and the quiet syntax.
  • The TASTy reader can now parse package objects, as well as variance and bounds in higher-kinded types.
  • The highlighting of lexer and parser errors is now significantly faster.
  • There are more inspections that are compatible with Scala 3.
  • We’ve improved the resolution of given imports and implemented support for final top-level members and abstract lazy vals.

Because Scala 3 support is actively being developed, we recommend using the nightly plugin builds to benefit from the new improvements. To do that, select Nightly builds in Settings | Languages | Scala | Updates | Channel (you can revert to an earlier build in the same place at any time).

While everyone in the IntelliJ Scala team has been focusing on Scala 3, we have attracted interns to implement other features, such as the Data Flow Analysis in this release or the Package Search Integration in the previous one. We’d like to thank them for all the work they’ve done to improve the plugin!

Open cross-compiled projects as Scala 2

Many projects that should be compiled for both Scala 2 and Scala 3 are modeled as Scala 3 projects cross-compiled for Scala 2, even though technically they are Scala 2 projects. (Please don’t confuse cross-compiled projects with mixed Scala 3 / Scala 2 projects, where each module is either Scala 2 or Scala 3, but not both.) Opening such projects as Scala 2 allows the IDE to use the technically correct Scala version and is more reliable:

If you look at the scala3-cross.g8 template, you can see that crossScalaVersions includes both scala2Version and scala3Version, while scalaVersion is set to scala3Version Why does the default Scala version matter? If you only need to build the project, the default Scala version isn’t important. However, if you open the project in an IDE, there are a couple key differences.

Scala 3 libraries store public APIs in .tasty files rather than in .class files. Even if there are no Scala 3 features in those APIs, the IDE has to use Scala 3 algorithms. There are many more IDE features that are necessary for Scala 3 but that are not optimal for Scala 2. It’s wise to use battle-tested and well-optimized implementations when working with Scala 2 code.

If the IDE thinks that a project contains Scala 3, it may actually use Scala 3 features on editing, code generation, and refactoring, even though these features must not be used when compiling the code for Scala 2. Thus, opening a cross-compiled project as Scala 2 is technically more correct. You can configure which version of Scala is used in cross-compiled projects at any time in Settings | Build Tools | sbt.

Data flow analysis for Scala

The Scala plugin now supports data flow analysis, which can help you detect programming errors more easily:

You can read our recent blog post for more details.

Autocomplete for Scala compiler options

There are tons of different options in the Scala compiler, though very few programmers learn them all by heart. Furthermore, those options vary depending on the Scala version in use.

You can now autocomplete the applicable options and see quick documentation for each of them:

Inlay hints for ranges

Have you ever wondered whether 1 to 3 is an inclusive or exclusive range? What about 1 until 3? Or Range(1, 3)? No need to worry – now the answer is clear:

As always, we welcome your feedback. Please report any issues you find to YouTrack. If you have any questions, feel free to ask us on Gitter.

Happy developing!

The IntelliJ Scala Plugin team

]]>
Dataflow Analysis for Scala https://blog.jetbrains.com/scala/2021/10/28/dataflow-analysis-for-scala/ Thu, 28 Oct 2021 16:24:02 +0000 https://blog.jetbrains.com/wp-content/uploads/2021/10/Screenshot-from-2021-10-28-18-03-27.png https://blog.jetbrains.com/?post_type=scala&p=196208 One of the things IntelliJ IDEA is most famous for is its huge variety of helpful inspections and warnings. They make the lives of programmers significantly easier, frequently showing them errors in logic or style that they wouldn’t have noticed otherwise.

Those inspections come in various shapes and sizes, ranging from simple pattern searches to highly sophisticated inspections that require tons of complex static code analysis behind the scenes. Among the most advanced examples of the latter are those offered with the help of dataflow analysis.

These inspections have been available for Java for a long time and have proved invaluable in finding numerous obscure bugs. However, no such inspections have ever been implemented for Scala. This became the focus of my internship with the IntelliJ Scala team this summer, and now we’re happy to announce that we’re bringing dataflow-based inspections to Scala developers.

They come enriched with special support for many important Scala-specific structures, like case classes or sequences. You can already try them out in our regular Nightly builds or wait until the next major IntelliJ IDEA release at the end of November 2021.

Dataflow analysis in a nutshell

Dataflow analysis consists of two major phases: control flow building and proper dataflow analysis.

Control flow building

First, we transform the abstract syntax tree of the program into something that will give us more information about its actual execution flow – the control flow graph. In IntelliJ IDEA, we represent control flow using our own stack-based intermediate representation, which is similar to Java bytecode. In short, we compile the user code into this bytecode-like representation.

Proper dataflow analysis

Each method is then analyzed separately. We partially execute its body, using the body’s control flow representation and keeping track of useful semantic information, especially possible variable values. However, most of those are unknown and will only become known at runtime (e.g. values of method parameters). That is why often we can only obtain and process abstract information like “x is even and greater than 10” or “y is an immutable list with five elements. For this reason, this procedure is called abstract interpretation.

Once we collect all of that dataflow information, we can analyze it to identify suspicious places and possible bugs in the code, like a complex expression that always evaluates to the same value or an access to a collection with an index larger than its size.

How it works

To illustrate this more concretely, let’s have a look at this very simple piece of code.

When we analyze the first method, we know everything about x. The condition 2 > 3 is always false, so x will always be 7. We can propagate this information and use it later when we see x again in the code – in this case in the returned expression.

In the second method however, we don’t know much about y. The values of a and b are unknown, so there are two possible paths: y can either be 5 or 7, but we don’t know which one.  But this is already a lot of information – we can’t say anything about y == 7, but we can confidently say that y > 4 is always true in any possible program execution scenario.

This example is very simple, but the power of dataflow analysis lies in the fact that we can choose to track many different kinds of information about those variables. Those pieces of information can then be combined with each other, leading us to powerful insights about the code being analyzed. Let’s briefly take a look at several examples of what Scala DFA is capable of in its current state.


Current capabilities of Scala DFA

Tracking relations

One cool thing about the IntelliJ DFA framework, on top of which we built our Scala DFA, is that it can track relations between variables, even if nothing else is known about them.

In the first example, dataflow analysis is able to figure out the relation between the otherwise unknown a and c by applying transitivity to the information it has collected from the outer condition. In the second one, it knows that inside the body of the else branch, !(a != b), which means a == b, and therefore a – b == 0.

A major advantage of this DFA is that many of its features easily extend to all types, not just simple ones like Int.

Support for known methods

A number of Scala-specific methods, including some standard math functions, receive their own special support in Scala DFA.

Support for Scala collections

We have also added special support for Scala collections. Dataflow analysis can, for example, tell you that two sequences cannot be equal because they’re of different sizes, or that your collection access will produce an IndexOutOfBoundsException or NoSuchElementException.

Several of the most common sequence methods are supported as well.

Interprocedural analysis 

Java DFA

Dataflow analysis in IntelliJ IDEA analyzes the body of each method separately. As such, it inherently doesn’t support interprocedural analysis. This means that code like this won’t be fully analyzed in Java (the analysis won’t go inside absoluteDifference).

To be fair, the team responsible for Java DFA has been trying to overcome this limitation in many creative and efficient ways, like through static constant evaluation, getter inlining, contracts, etc., but in the vast majority of cases, it won’t do any interprocedural analysis.

Scala DFA

In Scala, a fundamentally functional language, this is a much more significant limitation, and we decided we needed to overcome it. We’ve laid a solid foundation for interprocedural analysis that, in the current state, supports two major features: interprocedural analysis for invocations of private and final methods (including methods in final classes and objects) and tracking class parameters. In effect, if we translate the above code to Scala, Scala DFA will go inside the external method and analyze it completely.

Another advantage of our analysis is that it supports all of the many kinds of Scala invocations and their syntactic sugars, like infix notation, apply methods, right-associativity, or named and default parameters. So it will still work if you do something like this.

As mentioned before, our DFA can also process and track class parameters.

Architecture and Invocation Info

The overall scope of the Scala DFA project is large. A lot has already been done, but the number of potential additions or improvements is even greater. That is why, from the very beginning, one of our main focuses was to lay a strong foundation that would make it easy to add new things in the future. Along the way, we encountered several major challenges, and many of the design ideas we came up with to overcome them are very interesting in their own right. Probably the best example of this is Invocation Info.

The challenge

The problem we faced was that, in Scala, a huge variety of things are some kind of method invocation. In Java, a method invocation is always either something.method(arg1, arg2) or Something.method(arg1, arg2). In Scala, both of these are present as well, but all of the following are also method invocations.

This is nice for a programmer who uses the language, but it is a nightmare for any compiler programmer, especially if you add named, default, and implicit parameters, multiple parameter lists, varargs, etc. Imagine needing to extract precise information about an invocation while having to remember and depend on every possible variant of this syntax in every possible place where we’re dealing with invocations.

The solution

This is why we designed and implemented an abstraction called Invocation Info. We have a factory that takes any possible invocation as its input, in any syntactic variant, and produces an InvocationInfo instance.

This class represents all possible Scala invocations in a standardized, convenient, and syntax-agnostic way. All sugared and desugared versions of equivalent invocations (like 3 + 8 and 3.+(8)) generate the same InvocationInfo. There are some fine details here, for example x :: list is almost equivalent to list.::(x) (because :: is right-associative), but argument expressions in Scala are always evaluated from left to right and this creates a slight difference in the semantics of these two expressions.

Invocation Info is designed to collect and offer all necessary information about the original invocation, including multiple argument lists, by-name arguments, evaluation order, this argument, etc.

The details of Invocation Info’s design and how it is used in the control flow builder and the analysis itself would make for another long and interesting article. But the key takeaway is that implementing all of that special support for various methods would have been impossible without it. We strongly believe that this tool and our control flow builder are so useful that they may find many different applications outside of dataflow analysis in the future development of the Scala plugin.

Learn more about DFA

I highly recommend watching the IntelliJ IDEA Conf talk by Tagir Valeev, which summarizes how our dataflow analysis in IntelliJ IDEA works behind the scenes, what it can do, and how we manipulate it to extract as many useful insights and high-quality inspections as possible.

If you’re curious about what kinds of bugs dataflow analysis can help you find, read Tagir’s JetBrains Blog article, where he discusses lots of real-life examples.

Credits

Special thanks to Tobias Kahlert who supervised my project, in particular for a great theoretical and practical introduction to the DFA field and many really fruitful design discussions and ideas.

Achieving such good results also wouldn’t have been possible if I hadn’t built on the existing, robust, and extensible IntelliJ DFA framework. Most of it has been created by Tagir Valeev, with whom I’ve also had several helpful discussions throughout my project. Tagir has also been implementing DFA for Kotlin, which was helpful for me as a reference in the early stages of my work.

Feedback

We need your feedback! If you encounter any bugs in this feature, please report them to our YouTrack. If you have any questions, feel free to ask them in our Gitter.

]]>
BSP Support for Bazel https://blog.jetbrains.com/scala/2021/08/24/bsp-support-for-bazel/ Tue, 24 Aug 2021 09:18:36 +0000 https://blog.jetbrains.com/?post_type=scala&p=175052 The Build Server Protocol (BSP), a protocol initially developed by the Scala Center and JetBrains, enables the easy integration of IDEs and build tools. To give users even more options in the BSP ecosystem, we decided to add support for Bazel. 

While there is already a Bazel plugin for IntelliJ-based IDEs, it is often not up to date with the latest releases. Bazel BSP, on the other hand, works out of the box and can be used with any version of IntelliJ IDEA that supports BSP. Currently this is implemented in the Scala plugin.

The first commits for Bazel BSP date back to October 2019, and since then the project has gone through multiple hands to become a fully working product that we are happy to present. It originally started as a proof of concept, but it has evolved to its current state through the implementation of additional features and improvements to its robustness, maintainability, and extensibility.

Current state

Currently, the server supports BSP for Java, Scala, and Kotlin, and we are working on C++. This means that any Bazel project written in those languages can be successfully imported and edited in your IDE if it supports the protocol and relevant extensions.

To make working with monorepos possible and more enjoyable, the ProjectView files mechanism has been adapted from the Bazel plugin, which makes switching between the plugins very easy. It allows you to choose the targets and directories that should be included and excluded during the import, so you do not have to work on the entire codebase. 

Usage

Installation

First you will need to have Coursier.

Then, to install the server inside your project, simply run: 

cs launch org.jetbrains.bsp:bazel-bsp:1.0.0 -M org.jetbrains.bsp.bazel.install.Install

More information and installation options can be found in the README file in the repository.

Further steps in IntelliJ IDEA

Currently, the Scala plugin is required for importing projects through BSP.

Create a new project
Choose BSP as the import option
Then the import process starts.
And it ends.

Project Views

If you also added the projectview.bazelproject file to the project, the imported project will contain the specified folders and targets and will not contain the excluded ones.

General architecture

The architecture consists of 3 main logical components. The BSP server is responsible for communicating with the client (an IDE).

When the BSP server receives a request, it invokes a Bazel command with the appropriate parameters. Some requests (for example, asking for the list of sources) are pure queries – they don’t involve building the project. In such cases, the BSP server prepares a Bazel invocation that utilizes Bazel’s built-in query language and after that they are processed by the parser.

A different approach is used for non-pure requests, such as requests to build a file or run a test. Bazel can dynamically output information about the ongoing build in the form of a stream of protocol buffer messages. It uses another Bazel-specific protocol called the Build Event Protocol (BEP). The purpose of the BEP server is to subscribe to such a stream and to convert BEP events into BSP notifications, which can be fed into the IDE.

Authors’ contributions

The foundation of the Bazel BSP project was laid out by Daniel Wagner-Hall, who made several initial commits in October 2019.The project was then largely developed by André Rocha between July and September 2020. Later, development was taken over by Marcin Abramowicz, Magdalena Augustyńska, Gerard Dróżdż, and Andrzej Głuszak as part of their collaborative Bachelor’s thesis. André also collaborated actively during this time, contributing, discussing solutions, exchanging code reviews, and more. Now the implementation has been improved, new features have been added, and a fully working product has been created.

]]>
IntelliJ Scala Plugin 2021.2 Is Out! https://blog.jetbrains.com/scala/2021/07/27/intellij-scala-plugin-2021-2/ Tue, 27 Jul 2021 17:06:07 +0000 https://blog.jetbrains.com/wp-content/uploads/2020/07/IntelliJScala5.png https://blog.jetbrains.com/?post_type=scala&p=166540 This release has been focused on significantly improving our plugin’s Scala 3 support. There are also several new features, including a Package Search integration and optional compiler-based error highlighting.

Better Scala 3 support

Indexing of Scala 3 libraries is now fast, precise, and version-agnostic. You can now create both sbt and .idea-based Scala 3 projects, and create Scala 3 SDKs the normal way:

The editor can handle significant indentation better:

There are improvements in the debugger, formatter, REPL, auto-import, enums, extension methods, and many other areas:

That said, please keep in mind Scala 3 support is still a work in progress and not yet perfect.

-Xsource:3 option in Scala 2

The Scala plugin now supports Scala 3 constructs in Scala 2 projects – the -Xsource:3 compiler option (more info):

While this option is intended primarily to enable cross-compilation, you can use it for a gentle translation to Scala 3, or to future-proof your Scala 2 code.

Package Search for sbt

IntelliJ IDEA now comes with the Package Search plugin and sbt projects are supported. You can locate, add, upgrade, or remove library dependencies using the Dependencies tool window:

The integration also provides completion for dependencies, and can tell you when a new version of a library is available:

You can read more about Package Search support in our previous blog post.

Compiler-based highlighting

As is customary in the IntelliJ Platform, the Scala plugin has built-in error highlighting. It’s fast, lightweight, and supports all the standard IntelliJ IDEA features. However, because the Scala type system is so complex, the algorithm can sometimes report false errors. Although we’re constantly working on improving the implementation, the ability to use the Scala compiler for error highlighting may come in useful in some code bases:

Please note that, even though the compiler-based approach is more precise, it is slower, requires more resources, and doesn’t support features such as type diffs, quick-fixes, and inspections. So unless there are lots of false errors in the code, the built-in error highlighting is recommended.

Your feedback is very welcome, as always. Please report any issues you find to YouTrack. If you have any questions, feel free to ask us on Gitter.

Sincerely,

The IntelliJ Scala Plugin team

]]>
IntelliJ Scala Plugin 2021.2 EAP: Package Search Integration https://blog.jetbrains.com/scala/2021/07/09/package-search-integration/ Fri, 09 Jul 2021 14:02:03 +0000 https://blog.jetbrains.com/wp-content/uploads/2021/07/package-search-plugin-overview-1.png https://blog.jetbrains.com/?post_type=scala&p=159586 Package Search is a service developed by JetBrains that supports searching for libraries from multiple repositories such as Maven Central, Google Maven, and others.

Since its introduction at the end of 2019, the Package Search plugin has made searching for and managing dependencies for Maven and Gradle projects more convenient. Starting with the Scala plugin 2021.2 release, the Package Search plugin features will also be available for sbt projects. In addition, the Package Search APIs are integrated to help users manage library dependencies directly from the IntelliJ IDEA editor.

From the Package Search plugin window, we can see the list of the library dependencies being used by an sbt main project and its subproject(s):

Add a new dependency

Follow these three simple steps to add a new dependency to your project:

  1. Select the desired module.
  2. Search for the new dependency using the Package Search plugin’s search bar.
  3. After finding the suitable dependency in the Search Results list, click Add to open the pop-up window that allows you to select where to add the dependency.

Another (much simpler) way to add a new dependency to a project is to use the auto-completion feature from IntelliJ IDEA’s code editor (the data used for this feature comes from the Package Search APIs):

Newer stable version suggestions

When newer stable versions are available for your library dependencies, an inspection will underline your older version string and give you the option to update it with just one click:

Scala version auto-completion

With the help of the Package Search APIs, it is now easy to look up the list of available Scala versions when filling in scalaVersion:

As these features are still under development, you need to be using IntelliJ IDEA 2021.2 EAP and have the Scala plugin’s update channel set to EAP in order to try them out. In addition, the Package Search plugin, which comes bundled with IntelliJ IDEA 2021.2, needs to be enabled.

Your feedback is always welcome. If you encounter any issues with these features, please report them to YouTrack, and feel free to ask any questions you may have on our Gitter.

Happy coding!

The IntelliJ Scala plugin team

]]>
IntelliJ Scala Plugin 2021.1 Is Out! https://blog.jetbrains.com/scala/2021/04/07/intellij-scala-plugin-2021-1/ Wed, 07 Apr 2021 13:01:10 +0000 https://blog.jetbrains.com/wp-content/uploads/2020/07/IntelliJScala5.png https://blog.jetbrains.com/?post_type=scala&p=132049 With this major version, we’ve focused primarily on the performance and overall quality of the plugin. We’ve still added a number of new features to help with day-to-day Scala programming. Let’s take a closer look.

1. Kinds in type diffs
2. Machine learning completion
3. Phases and units in compilation charts
4. Scala 3.0.0-RC2 support
5. IntelliJ Platform plugin template
6. And more!

Kinds in type diffs

Scala developers don’t always use higher-kinded types, but when they do, they like to do it with style. The type diff tooltip now supports kinds:

Because type constructors, kinds, and higher-kinded types are somewhat advanced topics in Scala, having a down-to-earth explanation of a kind mismatch can be helpful (and is particularly relevant when you work with libraries that heavily use type classes, such as Cats or Scalaz).

Machine learning completion

This release introduces Scala code completion based on machine learning. You can enable the feature in Settings | Editor | Code Completion | ML | Scala:

The Machine Learning Code Completion plugin must be enabled for the feature to be available. You may choose to Mark position changes in completion popup to see how ML affects the order of elements. (Please note that this feature is experimental, so ranking may not change noticeably.) Read this IntelliJ IDEA blog post to learn more about ML completion.

Phases and units in compilation charts

In addition to modules, compilation charts can now show phases and units, so you can gain even deeper insight into your compilation – open the Build tool window, select the Chart node, and choose the desired Level of detail.

You can use Phases to estimate how compiler plugins, implicit resolution, and macro expansion affect project compilation time:

Units are helpful for detecting source files that take a long time to compile:

To speed up incremental compilation and reduce memory consumption, you may want to split large source files into several smaller ones. However, because compilation time depends on many factors, not just lines of code, it’s not easy to predict how the files should be split by guesswork. That’s where the detailed chart can prove particularly useful.

Scala 3.0.0-RC2 support

Can we support Scala 3.0.0-RC2, given that it has been released just days ago? Yes, we can! Feel free to open the scala-3-example-project using IntelliJ IDEA:

What’s more, we’re already using Scala 3 ourselves in the intellij-scala project!

IntelliJ Platform plugin template

The sbt-idea-plugin makes it possible to develop IntelliJ Platform plugins using Scala and sbt. There’s now a built-in Project Wizard template to make the process even easier (this feature depends on the Plugin DevKit):

The template project is also available on GitHub.

To learn more about the IntelliJ Platform, take a look at:

And more!

In addition to all the above, there are lots of small but important improvements, such as better handling of escape sequences in raw strings and in multi-line interpolated strings, string conversion improvements, better handling of SAM conversions and eta-expansions, proper handling of javac options in sbt, and much more!

Your feedback, as always, is very welcome. Please report any issues you find to YouTrack. And if you have any questions, feel free to ask them in our Gitter.

Sincerely,
The IntelliJ Scala Plugin team

]]>