<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: pyltsin</title>
    <description>The latest articles on DEV Community by pyltsin (@pyltsinm).</description>
    <link>https://dev.to/pyltsinm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F698144%2Fe934e947-23e3-476f-baa4-e4d9125e6c49.png</url>
      <title>DEV Community: pyltsin</title>
      <link>https://dev.to/pyltsinm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pyltsinm"/>
    <language>en</language>
    <item>
      <title>How to write your own language plugin for IDEA (part 2)</title>
      <dc:creator>pyltsin</dc:creator>
      <pubDate>Tue, 26 Apr 2022 18:22:23 +0000</pubDate>
      <link>https://dev.to/pyltsinm/how-to-write-your-own-language-plugin-for-idea-part-2-50g5</link>
      <guid>https://dev.to/pyltsinm/how-to-write-your-own-language-plugin-for-idea-part-2-50g5</guid>
      <description>&lt;p&gt;Disclaimer: I don't work for JetBrains, so there may be and most likely there will be inaccuracies and errors in the article and code.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/pyltsinm/how-to-write-your-own-language-plugin-for-idea-part-1-24ea-temp-slug-5129265"&gt;previous article&lt;/a&gt;, I showed the process of creating a framework for a language plugin. Well-known plugins for &lt;a href="https://github.com/JetBrains/intellij-community" rel="noopener noreferrer"&gt;Java&lt;/a&gt;, &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin" rel="noopener noreferrer"&gt;go&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege" rel="noopener noreferrer"&gt;Frege&lt;/a&gt; were used as examples. There are also examples from the plugin for the Monkey language, which I developed while I was figuring out how everything works. Since my goal was not to cover everything, the plugin covers a limited subset of the language. The interpreter for Monkey can be found &lt;a href="https://github.com/pyltsin/monkey-source" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Formatting
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://plugins.jetbrains.com/docs/intellij/code-formatting.html" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;, examples from &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/tree/master/src/com/goide/formatter" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/formatter/MonkeyFormattingModelBuilder.kt" rel="noopener noreferrer"&gt;monkey&lt;/a&gt;.&lt;br&gt;
As always, everything starts from an extension point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;lang.formatter&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;
&lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.formatter.MonkeyFormattingModelBuilder"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A class must implement the next interface&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;FormattingModelBuilder&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="nd"&gt;@NotNull&lt;/span&gt; 
&lt;span class="nc"&gt;FormattingModel&lt;/span&gt; &lt;span class="nf"&gt;createModel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;FormattingContext&lt;/span&gt; &lt;span class="n"&gt;formattingContext&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nd"&gt;@Nullable&lt;/span&gt; 
&lt;span class="nc"&gt;TextRange&lt;/span&gt; &lt;span class="nf"&gt;getRangeAffectingIndent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PsiFile&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                  &lt;span class="nc"&gt;ASTNode&lt;/span&gt; &lt;span class="n"&gt;elementAtOffset&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most important method is the first one. It returns a formatting model, which is built on formatting blocks. To simplify it, you can use  &lt;code&gt;FormattingModelProvider.createFormattingModelForPsiFile&lt;/code&gt; method&lt;/p&gt;

&lt;p&gt;Let's take a look at what a formatting block is. In IDEA, a formatting block is represented as an interface &lt;code&gt;com.intellij.formatting.Block&lt;/code&gt;. It is some range of text (often corresponding to some PSI element) which is formatted according to some rules. The formatting blocks are nested into each other and create a tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Block&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
  &lt;span class="nc"&gt;TextRange&lt;/span&gt; &lt;span class="nf"&gt;getTextRange&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
  &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Block&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getSubBlocks&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@Nullable&lt;/span&gt;
  &lt;span class="nc"&gt;Wrap&lt;/span&gt; &lt;span class="nf"&gt;getWrap&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@Nullable&lt;/span&gt;
  &lt;span class="nc"&gt;Indent&lt;/span&gt; &lt;span class="nf"&gt;getIndent&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@Nullable&lt;/span&gt;
  &lt;span class="nc"&gt;Alignment&lt;/span&gt; &lt;span class="nf"&gt;getAlignment&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@Nullable&lt;/span&gt;
  &lt;span class="nc"&gt;Spacing&lt;/span&gt; &lt;span class="nf"&gt;getSpacing&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Nullable&lt;/span&gt; &lt;span class="nc"&gt;Block&lt;/span&gt; &lt;span class="n"&gt;child1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Block&lt;/span&gt; &lt;span class="n"&gt;child2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
  &lt;span class="nc"&gt;ChildAttributes&lt;/span&gt; &lt;span class="nf"&gt;getChildAttributes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;newChildIndex&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;/// some methods are skipped&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to visualize this tree you can use PSI-Viewer &lt;br&gt;
 (Tools-&amp;gt;View PSI Structure, tab "Block Structure")&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8xnh5et8g6nljt6wh4d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8xnh5et8g6nljt6wh4d.png" alt="Visualization formatting blocks"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To simplify the implementation, you can use the &lt;code&gt;AbstractBlock&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;getSpacing&lt;/code&gt; - determines the number of spaces or line breaks between the specified child elements. To simplify the implementation of this logic, you can use the &lt;code&gt;com.intellij.formatting.SpacingBuilder&lt;/code&gt; class, which provides a convenient API to describe rules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//an extraction from plugin for Golang&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Spacing&lt;/span&gt; &lt;span class="nf"&gt;getSpacing&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Nullable&lt;/span&gt; &lt;span class="nc"&gt;Block&lt;/span&gt; &lt;span class="n"&gt;child1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Block&lt;/span&gt; &lt;span class="n"&gt;child2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SpacingBuilder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;GoLanguage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INSTANCE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;before&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;COMMA&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;spaceIf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;after&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;COMMA&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;spaceIf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;betweenInside&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SEMICOLON&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;SEMICOLON&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;FOR_CLAUSE&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;spaces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;before&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SEMICOLON&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;spaceIf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;after&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SEMICOLON&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;spaceIf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;beforeInside&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DOT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;IMPORT_SPEC&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;none&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;afterInside&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DOT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;IMPORT_SPEC&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;spaces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="c1"&gt;//and more rules&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSpacing&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Structure view
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://plugins.jetbrains.com/docs/intellij/structure-view.html" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;. Examples of implementation in &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/tree/GoStructureViewFactory.java" rel="noopener noreferrer"&gt;plugin-go&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/editor/MonkeyStructureViewFactory.kt" rel="noopener noreferrer"&gt;Monkey&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this section we will talk about filling this panel:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa95josqqdn6nk17vbsel.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa95josqqdn6nk17vbsel.png" alt="Structure view panel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next extension point is responsible for that&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;lang.psiStructureViewFactory&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;
&lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.editor.MonkeyStructureViewFactory"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your class must implement the next interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@FunctionalInterface&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PsiStructureViewFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@Nullable&lt;/span&gt;
  &lt;span class="nc"&gt;StructureViewBuilder&lt;/span&gt; &lt;span class="nf"&gt;getStructureViewBuilder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiFile&lt;/span&gt; &lt;span class="n"&gt;psiFile&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For implementation &lt;code&gt;StructureViewBuilder&lt;/code&gt; you can also  use prepared classes: &lt;code&gt;com.intellij.ide.structureView.TreeBasedStructureViewBuilder&lt;/code&gt;, &lt;code&gt;com.intellij.ide.structureView.StructureViewModelBase&lt;/code&gt; and &lt;code&gt;com.intellij.ide.structureView.impl.common.PsiTreeElementBase&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Working with &lt;code&gt;PsiTreeElementBase&lt;/code&gt; is similar to working with formatting blocks.&lt;/p&gt;

&lt;h1&gt;
  
  
  Caches, indexes, stub and goto
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Caches
&lt;/h2&gt;

&lt;p&gt;Let's start with the caches. IDEA asks extensions several times. If the extension is doing some time-consuming work, then the best solution is to cache the result of this work. IDEA provides many wrappers for this. For example, this is how the type of Go expression is calculated in the plugin-go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;  &lt;span class="nd"&gt;@Nullable&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;GoType&lt;/span&gt; &lt;span class="nf"&gt;getGoType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;GoExpression&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@Nullable&lt;/span&gt; &lt;span class="nc"&gt;ResolveState&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;RecursionManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doPreventingRecursion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;unwrapParType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;CachedValuesManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCachedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;CachedValueProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Result&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unwrapParType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;createContextOnElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)),&lt;/span&gt; &lt;span class="nc"&gt;PsiModificationTracker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MODIFICATION_COUNT&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;});&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2 different managers are used here. The first is the &lt;code&gt;CachedValuesManager&lt;/code&gt;, which caches the result for the psi element, and the second is the &lt;code&gt;Recursion Manager&lt;/code&gt;, which helps to prevent infinite recursion and &lt;code&gt;StackOverflowError&lt;/code&gt;. There is also a specialized cache &lt;code&gt;com.intellij.psi.impl.source.resolve.ResolveCache&lt;/code&gt;, which is used for resolving elements (this will be specified below).&lt;/p&gt;

&lt;h2&gt;
  
  
  Indexes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tbqgf6qmcxnxf8xe2gw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tbqgf6qmcxnxf8xe2gw.png" alt="About indexing from Reddit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://plugins.jetbrains.com/docs/intellij/indexing-and-psi-stubs.html#indexes" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;We all know how IDEA likes to index everything. Let's see what it is and how it can be used.&lt;/p&gt;

&lt;p&gt;Indexes in IDEA provide the opportunity to quickly find a necessary file or a psi element (for example, by the name of the annotation, you can find all the places where it is used).&lt;/p&gt;

&lt;p&gt;You can view existing indexes using the &lt;a href="https://plugins.jetbrains.com/plugin/13029-index-viewer" rel="noopener noreferrer"&gt;Index viewer&lt;/a&gt; plugin.&lt;/p&gt;

&lt;p&gt;IDEA supports two types of indexes - File-based and Stub. File-based indexes work with the contents of a file, Stub indexes work with Stub-tree, which is built on the basis of PSI-tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  File-based indexes
&lt;/h2&gt;

&lt;p&gt;An example of use can be found in the &lt;a href="https://github.com/carymrobbins/intellij-haskforce" rel="noopener noreferrer"&gt;hackforce plugin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We, as usual, start from the extension point&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;fileBasedIndex&lt;/span&gt; &lt;span class="na"&gt;implementation=&lt;/span&gt;&lt;span class="s"&gt;"com.haskforce.index.HaskellModuleIndex"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Class must extend &lt;code&gt;FileBasedIndexExtension&lt;/code&gt;. To get result of indexing you can use &lt;code&gt;FileBasedIndex.getInstance()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The hack force plugin, for example, uses this type of index to get all the files within the module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;VirtualFile&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getVirtualFilesByModuleName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;moduleName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;GlobalSearchScope&lt;/span&gt; &lt;span class="n"&gt;searchScope&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;FileBasedIndex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getContainingFiles&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;HASKELL_MODULE_INDEX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;moduleName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;searchScope&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Stub indexes
&lt;/h2&gt;

&lt;p&gt;It seems to me that this type of indexes is used more often because it allows you to search through PSI elements (or rather through stub, which represents the required part of the psi tree). Stubs are used only for named psi elements (which implement the &lt;code&gt;PsiNamedElement&lt;/code&gt; interface). They will be described in more detail in the Reference section&lt;/p&gt;

&lt;p&gt;To declare a new index, the following extension point is used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;stubIndex&lt;/span&gt; &lt;span class="na"&gt;implementation=&lt;/span&gt;
&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.stubs.MonkeyVarNameIndex"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your class must implement &lt;code&gt;StubIndexExtension&lt;/code&gt;.&lt;br&gt;
Example from the plugin for Monkey:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MonkeyVarNameIndex&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StringStubIndexExtension&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MonkeyNamedElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getVersion&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getVersion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;VERSION&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getKey&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;StubIndexKey&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MonkeyNamedElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;KEY&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StubIndexKey&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MonkeyNamedElement&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="nc"&gt;StubIndexKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createIndexKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"monkey.var.name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;VERSION&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Examples from &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/stubs/index/GoAllPublicNamesIndex.java" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/tree/master/src/main/kotlin/com/plugin/frege/stubs/index" rel="noopener noreferrer"&gt;frege&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we need to teach IDEA how to create a tree of Stubs and save the necessary elements under the desired index.&lt;/p&gt;

&lt;p&gt;For each element type that we want to save as a Stub, we create a Stub definition. In this case, the root of all Stubs should be &lt;code&gt;FileStub&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example from the plugin for Monkey:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MonkeyFileStub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MonkeyFile&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PsiFileStubImpl&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MonkeyFile&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MonkeyVarDefinitionStub&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;NamedStubBase&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MonkeyVarDefinition&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StubElement&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;?,&lt;/span&gt; &lt;span class="n"&gt;elementType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;IStubElementType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StringRef&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;elementType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StubElement&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;?,&lt;/span&gt; &lt;span class="n"&gt;elementType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;IStubElementType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;elementType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Examples from go-plugin (&lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/stubs/GoFileStub.java" rel="noopener noreferrer"&gt;file&lt;/a&gt;, &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/stubs/GoFieldDefinitionStub.java" rel="noopener noreferrer"&gt;element&lt;/a&gt;), Frege (&lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/kotlin/com/plugin/frege/stubs/FregeFileStub.kt" rel="noopener noreferrer"&gt;file&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/kotlin/com/plugin/frege/stubs/FregeClassStub.kt" rel="noopener noreferrer"&gt;element&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The next step is to create a description of the element type for each Stub. (For automatically generated PSI elements with  Grammar-Kit plugin, descriptions of each type of element are created automatically following &lt;code&gt;elementTypeHolderClass&lt;/code&gt; and &lt;code&gt;elementTypeClass&lt;/code&gt; parameters). The &lt;code&gt;ElementType&lt;/code&gt; for the file must extend &lt;code&gt;IStubFileElementType&lt;/code&gt;, for the element - &lt;code&gt;IStubElementType&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;IStubElementType&lt;/code&gt; requires the implementation of the following methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getExternalId&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;serialize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;stub&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;StubOutputStream&lt;/span&gt; &lt;span class="n"&gt;dataStream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@NotNull&lt;/span&gt;
&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;deserialize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;StubInputStream&lt;/span&gt; &lt;span class="n"&gt;dataStream&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;P&lt;/span&gt; &lt;span class="n"&gt;parentStub&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;indexStub&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;stub&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;IndexSink&lt;/span&gt; &lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;PsiT&lt;/span&gt; &lt;span class="nf"&gt;createPsi&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;StubT&lt;/span&gt; &lt;span class="n"&gt;stub&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;StubT&lt;/span&gt; &lt;span class="nf"&gt;createStub&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiT&lt;/span&gt; &lt;span class="n"&gt;psi&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StubElement&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;parentStub&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;shouldCreateStub&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ASTNode&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How to index Stubs is specified in the index Sub method. For example, in Monkey I used this implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;indexStub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;IndexSink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;occurrence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MonkeyVarNameIndex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementation of other methods can be found in the examples - &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/stubs/types/MonkeyVarDefinitionStubElementType.kt" rel="noopener noreferrer"&gt;plugin for Monkey&lt;/a&gt;, &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/stubs/types/GoMethodDeclarationStubElementType.java" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/kotlin/com/plugin/frege/stubs/types/FregeMethodElementType.kt" rel="noopener noreferrer"&gt;Frege&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now our stubs need to be connected to the parser. This can be done in 2 steps.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Step 1: define your element type factory for which we have made &lt;code&gt;IStubElementType&lt;/code&gt;, for example as
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;MonkeyElementTypeFactory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@JvmStatic&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;IElementType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"VAR_DEFINITION"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;MonkeyVarDefinitionStubElementType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;RuntimeException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unknown element type: $name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and specify in &lt;code&gt;bnf&lt;/code&gt; file that it should be used for some PSI elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;elementTypeFactory("var_definition")=
"com.github.pyltsin.monkeyplugin.psi.impl.MonkeyElementTypeFactory.factory"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Step 2. Specify that these PSI elements should extend &lt;code&gt;StubBasedPsiElementBase&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's consider everything together. During indexing, &lt;code&gt;StubBasedPsiElementBase&lt;/code&gt; is created, then a Stub is created using &lt;code&gt;IStubElementType.createStub&lt;/code&gt;. This stub can be serialized and a reference to it is saved in the index(&lt;code&gt;indexStub&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Client code which works with Stubs should call only those methods that have enough stored information to execute. Therefore, it is necessary to include in a stub all the information that may be needed later in the analysis. To get the PSI element, you can call the &lt;code&gt;getNode()&lt;/code&gt; method, but it is expensive because it requires file parsing.&lt;/p&gt;

&lt;p&gt;An example of saving information can be found in &lt;code&gt;com.intellij.psi.impl.java.stubbs.impl.PsiAnnotationStubImpl#getPsiElement&lt;/code&gt;, which uses text from ASTNode.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using stub indexes
&lt;/h3&gt;

&lt;p&gt;Indexes are widely used for go-to functions. For example, they are used for this panel:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkuzhq4cx878sb07siv5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkuzhq4cx878sb07siv5b.png" alt="Goto panel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simplified go-to implementation for symbols based on stub indexes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;plugin.xml
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;gotoSymbolContributor&lt;/span&gt; &lt;span class="na"&gt;implementation=&lt;/span&gt;
&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.usages.MonkeySymbolContributor"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;MonkeySymbolContributor:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MonkeySymbolContributor&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ChooseByNameContributorEx&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="n"&gt;myIndexKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;listOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MonkeyVarNameIndex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;KEY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;override&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;processNames&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;processor:&lt;/span&gt; &lt;span class="nc"&gt;Processor&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;scope:&lt;/span&gt; &lt;span class="nc"&gt;GlobalSearchScope&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;filter:&lt;/span&gt; &lt;span class="nc"&gt;IdFilter&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;myIndexKeys&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;ProgressManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;checkCanceled&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="nc"&gt;StubIndex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;processAllKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;filter&lt;/span&gt;
            &lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;override&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;processElementsWithName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;name:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;processor:&lt;/span&gt; &lt;span class="nc"&gt;Processor&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="nc"&gt;NavigationItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;parameters:&lt;/span&gt; &lt;span class="nc"&gt;FindSymbolParameters&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;myIndexKeys&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;ProgressManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;checkCanceled&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="nc"&gt;StubIndex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;processElements&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;searchScope&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;idFilter&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="nl"&gt;MonkeyNamedElement:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;java&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;processor&lt;/span&gt;
            &lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Many custom plugins also use indexes widely. For example, &lt;a href="https://plugins.jetbrains.com/plugin/9567-request-mapper" rel="noopener noreferrer"&gt;Request mapper&lt;/a&gt; (currently not supported, since the same functionality appeared in IDEA), which helps to search for REST method declaration points&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firals054zd5nxdzgvtt8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firals054zd5nxdzgvtt8.png" alt="Request mapper"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx1ixilm2amunrhp1neb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx1ixilm2amunrhp1neb.png" alt="Example from IDEA"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Request Mapper uses this code under the hood:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//JavaAnnotationIndex - the usual Subindexbindex for Java for annotations&lt;/span&gt;
&lt;span class="nc"&gt;JavaAnnotationIndex&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;annotationName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;GlobalSearchScope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;projectScope&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asSequence&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://plugins.jetbrains.com/docs/intellij/declarations-and-references.html" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the moment, the API is being changed, so there may be inaccuracies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnl98k46er8llmqojzkyt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnl98k46er8llmqojzkyt.gif" alt="Example of using references"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;References create links between elements. When you press &lt;code&gt;Ctrl+B&lt;/code&gt;, you will go to the element to which this link refers. By pressing Ctrl+B again, you will see all the elements that link to this element.&lt;/p&gt;

&lt;p&gt;Only the element that defines a name should implement &lt;code&gt;PsiNamedElement&lt;/code&gt; (or better &lt;code&gt;PsiNameIdentifierOwner&lt;/code&gt;, you can see their use in the Rename section)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@JvmStatic&lt;/span&gt;
&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;expr:&lt;/span&gt; &lt;span class="nc"&gt;MonkeySimpleRefExpr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;name:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="nl"&gt;e:&lt;/span&gt; &lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MonkeyElementTextFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createStatementFromText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"$name + 1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;//newLetExpr must implement PsiNamedElement&lt;/span&gt;
  &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="n"&gt;newLetExpr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PsiTreeUtil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findChildOfType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;MonkeySimpleRefExpr:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;java&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newLetExpr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newLetExpr&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;expr&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order for the PSI element to provide a link, you need to implement the methods&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;PsiReference&lt;/span&gt; &lt;span class="nf"&gt;getReference&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;PsiReference&lt;/span&gt; &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;getReferences&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nd"&gt;@Experimental&lt;/span&gt;
&lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Iterable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiSymbolReference&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getOwnReferences&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;emptyList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To simplify the implementation of the &lt;code&gt;PsiReference interface&lt;/code&gt;, you can use the &lt;code&gt;PsiReferenceBase&lt;/code&gt;. You have to implement the method &lt;code&gt;PsiElement resolve()&lt;/code&gt; or &lt;code&gt;ResolveResult [] multiResolve(boolean incompleteCode)&lt;/code&gt;, which return the referenced elements. When implementing this method, it makes sense to use a specialized cache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;override&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;multiResolve&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;incompleteCode:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ResolveResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResolveCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;psiElement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;resolveWithCaching&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;referenceBase&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;referenceBase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resolveInner&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;PsiElementResolveResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toTypedArray&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;},&lt;/span&gt;
        &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the implementation of this part, IDEA will already be able to provide navigation to the referenced element and back.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rename
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://plugins.jetbrains.com/docs/intellij/rename-refactoring.html" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Renaming is one of the most popular refactorings (Shift+F6)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbay546db7ai9hs4tng2s.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbay546db7ai9hs4tng2s.gif" alt="Renaming"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2 extension points are responsible for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;lang.refactoringSupport&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;
                         &lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.refactor.MonkeyRefactoringSupportProvider"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;renameInputValidator&lt;/span&gt; &lt;span class="na"&gt;implementation=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.refactor.MonkeyRenameInputValidator"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;renameInputValidator&lt;/code&gt; must implement &lt;code&gt;RenameInputValidator&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;refactoringSupport&lt;/code&gt; must extend &lt;code&gt;RefactoringSupportProvider&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This class also contains methods to support other types of refactorings. At the moment we are interested in a method that indicates whether in-place editing is supported.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isMemberInplaceRenameAvailable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@Nullable&lt;/span&gt; &lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it is required to implement renaming methods. As mentioned before, the PSI element that defines the name should implement the &lt;code&gt;PsiNamedElement&lt;/code&gt; interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PsiNamedElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NlsSafe&lt;/span&gt; &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IncorrectOperationException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are interested in &lt;code&gt;setName&lt;/code&gt; method here. One of the easiest ways to implement this method is to create a new PSI element from text, like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createFileFromText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;MonkeyFile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;PsiFileFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createFileFromText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A.monkey"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MonkeyLanguage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;INSTANCE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;MonkeyFile&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And replace the element&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newLetExpr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It remains to implement the renaming of elements that refer to our named PSI element. To do this, you need to implement the method from &lt;code&gt;PsiReference&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="nf"&gt;handleElementRename&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;newElementName&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 
&lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IncorrectOperationException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or you can use &lt;code&gt;com.intellij.psi.PsiReferenceBase&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Markers
&lt;/h3&gt;

&lt;p&gt;IDEA widely uses hints in the form of markers&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft99xx2n25djskxsw16w1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft99xx2n25djskxsw16w1.png" alt="An example of a marker"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Examples from &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/marker/GoRecursiveCallMarkerProvider.java" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/kotlin/com/plugin/frege/linemarker/related/FregeRelatedItemLineMarkerProvider.kt" rel="noopener noreferrer"&gt;Frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/editor/MonkeyFunctionLineMarkerProvider.kt" rel="noopener noreferrer"&gt;monkey&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The required extension point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;codeInsight.lineMarkerProvider&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;
&lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.editor.MonkeyFunctionLineMarkerProvider"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file must implement &lt;code&gt;LineMarkerProvider&lt;/code&gt; interface, whose methods return &lt;code&gt;LineMarkerInfo&lt;/code&gt; object. Please note that markers should be linked only to the leaves of the PSI-tree.&lt;/p&gt;

&lt;h3&gt;
  
  
  Autocompletion
&lt;/h3&gt;

&lt;p&gt;I think everyone who uses IDEA likes how it works with hints. It is very difficult to write a good autocompletion mechanism. But at the same time, you can implement some autocompletion relatively quickly, for example, these:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzz8kut9vlutdnlqghnfc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzz8kut9vlutdnlqghnfc.gif" alt="Autocompletion with Monkey"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This completion is implemented with &lt;code&gt;PsiReference.getVariants&lt;/code&gt; method, which returns all visible suitable values. Filtering by characters is performed by IDEA itself.&lt;/p&gt;

&lt;p&gt;For more complex cases, you can use the extension point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;completion.contributor&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;                         &lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.completion.MonkeyKeywordCompletionContributor"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your class must implement &lt;code&gt;CompletionContributor&lt;/code&gt; abstract class.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://plugins.jetbrains.com/docs/intellij/code-completion.html" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;. Examples of implementation from &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/completion/GoKeywordCompletionContributor.java" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/kotlin/com/plugin/frege/completion/FregeKeywordCompletionContributor.kt" rel="noopener noreferrer"&gt;frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/completion/MonkeyKeywordCompletionContributor.kt" rel="noopener noreferrer"&gt;monkey&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://plugins.jetbrains.com/docs/intellij/writing-tests-for-plugins.html" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In IDEA, tests are often several files with the source code of the language that show the state BEFORE and AFTER the action. &lt;code&gt;BasePlatformTestCase&lt;/code&gt; class is usually used for it. Usually tests look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;myFixture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;configureByFiles&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"RenameTestData.monkey"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;myFixture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;renameElementAtCaret&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;myFixture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;checkResultByFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"RenameTestData.monkey"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"RenameTestDataAfter.monkey"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;RenameTestData.monkey&lt;/code&gt; and &lt;code&gt;RenameTestDataAfter.monkey&lt;/code&gt; are source code files before and after renaming.&lt;/p&gt;

&lt;h1&gt;
  
  
  The conclusion
&lt;/h1&gt;

&lt;p&gt;This is the end of the story about creating a language plugin for IDEA. Good luck in setting up your IDE for yourself!&lt;/p&gt;

</description>
      <category>java</category>
      <category>kotlin</category>
      <category>idea</category>
      <category>jetbrains</category>
    </item>
    <item>
      <title>How to write your own language plugin for IDEA (part 1)</title>
      <dc:creator>pyltsin</dc:creator>
      <pubDate>Tue, 26 Apr 2022 18:22:12 +0000</pubDate>
      <link>https://dev.to/pyltsinm/how-to-write-your-own-language-plugin-for-idea-part-1-mfd</link>
      <guid>https://dev.to/pyltsinm/how-to-write-your-own-language-plugin-for-idea-part-1-mfd</guid>
      <description>&lt;p&gt;Disclaimer: I don't work for JetBrains, so there will be and most likely there may be inaccuracies and errors in the article and code.&lt;/p&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;I am working as a backend developer, and sometimes I am tired of the work routine. Going deep into some opensource helps me, besides I am keen on Jetbrains' product and IDEA. IDEA can be customized with plugins, which you can write yourself.&lt;br&gt;
The biggest part of IDEA's code is open-source. Developers from Jetbrains always help you to make pull requests and improve your main tool.&lt;br&gt;
I have already written an article about how to write &lt;a href="https://dev.to/pyltsinm/how-to-create-a-new-inspecion-for-idea-10i1"&gt;a small plugin&lt;/a&gt; with one inspection. But if you want to understand how IDEA works, you should try to write a language plugin.&lt;br&gt;
Let's do this.&lt;br&gt;
As a "guinea pig" we will take a simple  language - &lt;a href="https://monkeylang.org/" rel="noopener noreferrer"&gt;Monkey&lt;/a&gt;, the interpreter and compiler for which are described in the &lt;a href="https://interpreterbook.com/" rel="noopener noreferrer"&gt;books on Golang&lt;/a&gt;. Since my goal was not to cover everything, the plugin covers a limited subset of this language. The interpreter can be found &lt;a href="https://github.com/pyltsin/monkey-source" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Example of calculating the Fibonacci number on Monkey:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;let&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
                        &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                    &lt;span class="o"&gt;}&lt;/span&gt;
                    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
                            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                        &lt;span class="o"&gt;}&lt;/span&gt;
                        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
                            &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                        &lt;span class="o"&gt;};&lt;/span&gt;
                    &lt;span class="o"&gt;};&lt;/span&gt;
&lt;span class="o"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will write this plugin with Java and Kotlin (JVM)&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;p&gt;The easiest way to create a new plugin is to use &lt;a href="https://github.com/JetBrains/intellij-platform-plugin-template" rel="noopener noreferrer"&gt;the template&lt;/a&gt;. It is being actively developed and had already included the most needed features.&lt;/p&gt;

&lt;p&gt;Also, we need DevKit plugin, which you can enable in IDEA&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frkhd07pkgcjxijj7rzc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frkhd07pkgcjxijj7rzc6.png" alt="Where you can find DevKit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://plugins.jetbrains.com/plugin/6606-grammar-kit" rel="noopener noreferrer"&gt;Grammar-Kit&lt;/a&gt; plugin will be used to generate a lexer and parser&lt;/p&gt;

&lt;p&gt;Examples of other plugins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/JetBrains/intellij-community" rel="noopener noreferrer"&gt;Java&lt;/a&gt; (in the code of IDEA)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin.git" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt; (now this plugin is known as Goland)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/carymrobbins/intellij-haskforce" rel="noopener noreferrer"&gt;Haskell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ignatov/intellij-erlang/blob/master/grammars/erlang.bnf" rel="noopener noreferrer"&gt;Erlang&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/IntelliJ-Frege" rel="noopener noreferrer"&gt;Frege&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/pyltsin/monkey-plugin" rel="noopener noreferrer"&gt;Monkey plugin&lt;/a&gt; (in this article)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Creating the basis of a language plugin
&lt;/h1&gt;

&lt;p&gt;The first stages of creating a language plugin are well described in &lt;a href="https://plugins.jetbrains.com/docs/intellij/language-and-filetype.html" rel="noopener noreferrer"&gt;the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is required to declare a new language (examples in &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/GoLanguage.java" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/java/com/plugin/frege/FregeLanguage.java" rel="noopener noreferrer"&gt;frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/MonkeyLanguage.kt" rel="noopener noreferrer"&gt;monkey&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example for Monkey:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.lang.Language&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MonkeyLanguage&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Language&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@JvmStatic&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;INSTANCE&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MonkeyLanguage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Declare an icon (examples in &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/GoIcons.java" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/java/com/plugin/frege/FregeIcons.java" rel="noopener noreferrer"&gt;frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/MonkeyIcons.kt" rel="noopener noreferrer"&gt;monkey&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Declare a new file type and combine everything together (examples in &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/GoFileType.java" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/java/com/plugin/frege/FregeFileType.java" rel="noopener noreferrer"&gt;frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/MonkeyFileType.kt" rel="noopener noreferrer"&gt;monkey&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example for Monkey&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.fileTypes.LanguageFileType&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.swing.Icon&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MonkeyFileType&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LanguageFileType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MonkeyLanguage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;INSTANCE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Monkey File"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getDescription&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Monkey language file"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getDefaultExtension&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"monkey"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getIcon&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Icon&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;MonkeyIcons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FILE&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@JvmStatic&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;INSTANCE&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MonkeyFileType&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, you need to enable a new file type via the extension point. All the features that plugins provide are enabled through one or more extension points. They must be declared in the file plugin.xml (example for &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/resources/META-INF/gogland.xml" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/resources/META-INF/plugin.xml" rel="noopener noreferrer"&gt;frege&lt;/a&gt;). Other examples of using extension points will be given below or can be checked in the &lt;a href="https://plugins.jetbrains.com/docs/intellij/welcome.html" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Example for Monkey (resources/META-INF/plugin.xml)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;extensions&lt;/span&gt; &lt;span class="na"&gt;defaultExtensionNs=&lt;/span&gt;&lt;span class="s"&gt;"com.intellij"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;fileType&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Monkey File"&lt;/span&gt;
            &lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.MonkeyFileType"&lt;/span&gt;
            &lt;span class="na"&gt;fieldName=&lt;/span&gt;&lt;span class="s"&gt;"INSTANCE"&lt;/span&gt;
            &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;
            &lt;span class="na"&gt;extensions=&lt;/span&gt;&lt;span class="s"&gt;"monkey"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/extensions&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Creation PSI-tree
&lt;/h1&gt;

&lt;p&gt;It is impossible to describe the whole theory that is required to parse the code in one article. Fundamental knowledge for this topic can be found in the "&lt;a href="https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools" rel="noopener noreferrer"&gt;Dragon Book&lt;/a&gt;"&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flpwld9cljps0mxiiyaje.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flpwld9cljps0mxiiyaje.png" alt="Cover of "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;According to this book, the process of the compiler working with the code consists of the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lexical Analyzer&lt;/li&gt;
&lt;li&gt;Syntax Analyzer&lt;/li&gt;
&lt;li&gt;Semantic Analyzer&lt;/li&gt;
&lt;li&gt;Intermediate Code Generator&lt;/li&gt;
&lt;li&gt;Machine-Independent Code Optimizer&lt;/li&gt;
&lt;li&gt;Code Generator&lt;/li&gt;
&lt;li&gt;Machine-Dependent Code Optimizer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is required to implement the first 3 analyzers for any IDE to work successfully:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lexical analyzer (to read a stream of characters and to group them into tokens)&lt;/li&gt;
&lt;li&gt;Parser (to receive a stream of tokens and to build a syntax tree from them - &lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree" rel="noopener noreferrer"&gt;AST&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Semantic analyzer (to use a tree to verify the source code according to some rules).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In IDEA, an analog called &lt;code&gt;PSI tree&lt;/code&gt; (Program structure Interface) is used instead of an AST tree.&lt;/p&gt;

&lt;p&gt;The process of creating a PSI tree is well shown in the illustration from the &lt;a href="https://plugins.jetbrains.com/docs/intellij/implementing-parser-and-psi.html" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frxsh8l8bige992uw2dv6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frxsh8l8bige992uw2dv6.png" alt="PSI tree"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to see PSI-tree, you can use the &lt;a href="https://www.jetbrains.com/help/idea/psi-viewer.html" rel="noopener noreferrer"&gt;PSI Viewer&lt;/a&gt; (Tools-&amp;gt;View PSI structure)&lt;br&gt;
 &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5v6k2btlp1ioooqgana3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5v6k2btlp1ioooqgana3.png" alt="Example of usage of PSI Viewer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In IDEA, the abstract TreeElement class is mainly used to implement the PSI tree&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TreeElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ElementBase&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ASTNode&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Cloneable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;TreeElement&lt;/span&gt; &lt;span class="n"&gt;myNextSibling&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;TreeElement&lt;/span&gt; &lt;span class="n"&gt;myPrevSibling&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;CompositeElement&lt;/span&gt; &lt;span class="n"&gt;myParent&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In IDEA, you can use the &lt;a href="https://plugins.jetbrains.com/plugin/6606-grammar-kit" rel="noopener noreferrer"&gt;GrammarKit&lt;/a&gt; plugin to create a lexer and a parser.&lt;/p&gt;

&lt;h1&gt;
  
  
  Lexer
&lt;/h1&gt;

&lt;p&gt;Perhaps, the easiest way to create a lexer for IDEA is to use &lt;a href="https://jflex.de/" rel="noopener noreferrer"&gt;JFlex&lt;/a&gt;. The GrammarKit plugin already contains implementation and allows you to generate a lexer from &lt;code&gt;.bnf&lt;/code&gt; file or from &lt;code&gt;.flex&lt;/code&gt; file (with more customization options). An example for the Monkey language can be viewed &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/java/com/github/pyltsin/monkeyplugin/Monkey.flex" rel="noopener noreferrer"&gt;here&lt;/a&gt;, a more complex one for Frege - &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/java/com/plugin/frege/lexer/FregeLexer.flex" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To generate Lexer, you need to configure the Gradle plugin or use the context menu in .flex file - "Run JFlex Generator".&lt;/p&gt;

&lt;p&gt;After that, you need to declare a class that implements &lt;code&gt;com.intellij.lexer.Lexer&lt;/code&gt;. There is already an adapter for the generated JFlex lexer - &lt;code&gt;com.intellij.lexer.FlexAdapter&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Parser
&lt;/h1&gt;

&lt;p&gt;In IDEA, code generation by the GrammarKit plugin is mainly used to create a parser. Unfortunately, there is not much documentation about it and it is only presented in &lt;a href="https://github.com/JetBrains/Grammar-Kit/blob/master/TUTORIAL.md" rel="noopener noreferrer"&gt;Tutorial&lt;/a&gt; and &lt;a href="https://github.com/JetBrains/Grammar-Kit/blob/master/HOWTO.md" rel="noopener noreferrer"&gt;HOWTO&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The grammar of the language is described in &lt;a href="https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form" rel="noopener noreferrer"&gt;BNF&lt;/a&gt;. The only difference that is used is &lt;code&gt;::=&lt;/code&gt; as "is".&lt;/p&gt;

&lt;p&gt;Example grammar for expressions can be found &lt;a href="https://github.com/JetBrains/Grammar-Kit/blob/master/testData/generator/ExprParser.bnf" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the bnf file consists of 2 parts: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the first part describes the meta-information (and the description of tokens, if flex files are not used)&lt;/li&gt;
&lt;li&gt;the second part describes the grammar itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's consider some parts of the meta-information:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;parserClass&lt;/code&gt; - name and location of the generated parser class&lt;/p&gt;

&lt;p&gt;&lt;code&gt;parserUtilClass&lt;/code&gt; - a reference to a class containing a set of additional methods for the parser (usually the &lt;code&gt;com.intellij.lang.parser.GeneratedParserUtilBase&lt;/code&gt; class or its inheritors)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;extends = &amp;lt;some class&amp;gt;&lt;/code&gt; - a reference to the base class from which all PSI elements (tree nodes) will be inherited. Usually &lt;code&gt;com.intellij.extapi.psi.ASTWrapperPsiElement&lt;/code&gt; or its inheritors.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;extends(&amp;lt;regexp for tree nodes&amp;gt;) = &amp;lt;psi-element&amp;gt;&lt;/code&gt; (for example: &lt;code&gt;extends(".*expr")=expr&lt;/code&gt;) - all psi elements will be inherited from the specified psi element.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;psiClassPrefix&lt;/code&gt;, &lt;code&gt;psiImplClassSuffix&lt;/code&gt; - respectively the prefix for classes and interfaces (usually by the name of the language) and the suffix for implementing interfaces (usually - &lt;code&gt;Impl&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;psiPackage&lt;/code&gt; and &lt;code&gt;psiImplPackage&lt;/code&gt; are respectively a package for interfaces and their implementations.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;implements&lt;/code&gt; - similar to &lt;code&gt;extends&lt;/code&gt;, but for interfaces&lt;/p&gt;

&lt;p&gt;&lt;code&gt;elementTypeHolderClass&lt;/code&gt; - a generated storage for all types of elements&lt;/p&gt;

&lt;p&gt;&lt;code&gt;elementTypeClass&lt;/code&gt; - a class for types of elements (not generated, inheritors to &lt;code&gt;com.intellij.psi.tree.IElementType&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;elementTypeFactory&lt;/code&gt; - creating a factory for generating element types (used for Stub - about them below)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;psiImplUtilClass&lt;/code&gt; - a class with a set of static methods that are used as an implementation of the required methods for psi elements. &lt;br&gt;
Let's suppose we have such lines (from go-plugin)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ImportSpec&lt;/span&gt; &lt;span class="o"&gt;::=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="sc"&gt;'.'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;identifier&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;ImportString&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;stubClass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"com.goide.stubs.GoImportSpecStub"&lt;/span&gt;
  &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;&lt;span class="n"&gt;getAlias&lt;/span&gt; &lt;span class="n"&gt;getLocalPackageName&lt;/span&gt; &lt;span class="n"&gt;shouldGoDeeper&lt;/span&gt; &lt;span class="n"&gt;isForSideEffects&lt;/span&gt; &lt;span class="n"&gt;isDot&lt;/span&gt; &lt;span class="n"&gt;getPath&lt;/span&gt; &lt;span class="n"&gt;getName&lt;/span&gt; &lt;span class="n"&gt;isCImport&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For that, we need to declare and implement a static method with the same name in &lt;code&gt;psiImplUtilClass&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getAlias&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;GoImportSpec&lt;/span&gt; &lt;span class="n"&gt;importSpec&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that &lt;code&gt;getAlias&lt;/code&gt; will be generated as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getAlias&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;GoPsiImplUtil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAlias&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's move on to the &lt;code&gt;bnf&lt;/code&gt; rules themselves. Modifiers can be used for each rule (for example, &lt;code&gt;private&lt;/code&gt;, &lt;code&gt;fake&lt;/code&gt;, and so on). Their description is given &lt;a href="https://github.com/JetBrains/Grammar-Kit#rule-modifiers" rel="noopener noreferrer"&gt;here&lt;/a&gt;. So, for example &lt;code&gt;private&lt;/code&gt; in&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;boolean_group&lt;/span&gt; &lt;span class="o"&gt;::=&lt;/span&gt; &lt;span class="n"&gt;xor_expr&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;between_expr&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;is_not_expr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;indicates that the PSI element for &lt;code&gt;boolean_group&lt;/code&gt; will not be generated.&lt;/p&gt;

&lt;p&gt;If it is not possible to describe the grammar in a &lt;code&gt;bnf&lt;/code&gt; file correctly, then it will be useful to describe it in code using external rules.&lt;/p&gt;

&lt;p&gt;One of the important parts of grammar is the rules of dealing with errors. Two keywords are used for this: &lt;code&gt;pin&lt;/code&gt; and &lt;code&gt;recoverWhile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pin&lt;/code&gt; - indicates the token number. As soon as we get to it, the parser starts waiting only for the current declaration. For example, declaring a structure in Golang&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Struct&lt;/span&gt; &lt;span class="nc"&gt;Type&lt;/span&gt; &lt;span class="o"&gt;::=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="sc"&gt;'{'&lt;/span&gt; &lt;span class="nc"&gt;Fields&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="sc"&gt;'}'&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;recoverWhile&lt;/code&gt; - specifies which tokens can be consumed only after matching with all rules is completed. Recommendations for the use of this attribute are described &lt;a href="https://github.com/JetBrains/Grammar-Kit/blob/master/HOWTO.md#22-using-recoverwhile-attribute" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You should also pay attention to the &lt;a href="https://github.com/JetBrains/Grammar-Kit/blob/master/HOWTO.md#24-compact-expression-parsing-with-priorities" rel="noopener noreferrer"&gt;recommendations&lt;/a&gt; for parsing expressions based on priority.&lt;/p&gt;

&lt;p&gt;It seems to me that creating correct and convenient grammar rules for future work is one of the most difficult parts of implementing a plugin for a language. To get started, you can use examples: &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/grammars/go.bnf" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/java/com/plugin/frege/Frege.bnf" rel="noopener noreferrer"&gt;Frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/java/com/github/pyltsin/monkeyplugin/Monkey.bnf" rel="noopener noreferrer"&gt;Monkey&lt;/a&gt; (for Monkey, only a subset of this language is implemented for simplification).&lt;/p&gt;

&lt;p&gt;After creating a &lt;code&gt;bnf&lt;/code&gt; file and generating a parser from it, you need to define the class for &lt;code&gt;File&lt;/code&gt; (inheritor from &lt;code&gt;com.intellij.extapi.psi.PsiFileBase&lt;/code&gt;) (examples from &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/psi/GoFile.java" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/kotlin/com/plugin/frege/psi/FregeFile.kt" rel="noopener noreferrer"&gt;Frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/psi/MonkeyFile.kt" rel="noopener noreferrer"&gt;Monkey&lt;/a&gt;) and the definition class for your parser (heir from &lt;code&gt;com.intellij.lang.ParserDefinition&lt;/code&gt;) (example from &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/GoParserDefinition.java" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/java/com/plugin/frege/parser/FregeParserDefinition.java" rel="noopener noreferrer"&gt;Frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/parser/MonkeyParserDefinition.kt" rel="noopener noreferrer"&gt;Monkey&lt;/a&gt;), and then enable it via the extension point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;lang.parserDefinition&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;
&lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.parser.MonkeyParserDefinition"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Annotators
&lt;/h1&gt;

&lt;p&gt;In the previous parts, we looked at how a lexer and a parser are created. Now let's move on to the third part - semantic analysis. Studying the code of IDEA and its plugins, I found two ways to implement it (excluding inspections).&lt;/p&gt;

&lt;p&gt;The first way is used in a plugin for Java language. Consider the following invalid code:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk354nf0ikebcp9zdzqnl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk354nf0ikebcp9zdzqnl.png" alt="Example of invalid code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;IDEA highlighted it and said &lt;code&gt;Operator'-'cannot be applied to 'java.lang.String', 'java.lang.String'&lt;/code&gt;. It works thanks to the following extension point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;highlightVisitor&lt;/span&gt; &lt;span class="na"&gt;implementation=&lt;/span&gt;
&lt;span class="s"&gt;"com.intellij.codeInsight.daemon.impl.analysis.HighlightVisitorImpl"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class must implement &lt;code&gt;com.intellij.codeInsight.daemon.impl.HighlightVisitor&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;HighlightVisitor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;suitableForFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiFile&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;analyze&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiFile&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                  &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;updateWholeFile&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                  &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;HighlightInfoHolder&lt;/span&gt; &lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                  &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Runnable&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use the method &lt;code&gt;analyze&lt;/code&gt; to configure, launch (&lt;code&gt;action.run()&lt;/code&gt;) and close resources&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//From HighlightVisitorImpl&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// some code&lt;/span&gt;
      &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// some code&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//Example for ClsJavaModuleImpl&lt;/span&gt;
  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiElementVisitor&lt;/span&gt; &lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;JavaElementVisitor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;JavaElementVisitor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;visitModule&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visitElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Visitor_pattern" rel="noopener noreferrer"&gt;visitor&lt;/a&gt; pattern is used there.&lt;br&gt;
&lt;code&gt;HighlightVisitorImpl&lt;/code&gt; extends &lt;code&gt;JavaElementVisitor&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JavaElementVisitor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;PsiElementVisitor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;visitAnonymousClass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PsiAnonymousClass&lt;/span&gt; &lt;span class="n"&gt;aClass&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;visitClass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aClass&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;visitArrayAccessExpression&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PsiArrayAccessExpression&lt;/span&gt; &lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;visitExpression&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;visitArrayInitializerExpression&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PsiArrayInitializerExpression&lt;/span&gt; &lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;visitExpression&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second way is applied in go-plugin and Frege.&lt;br&gt;
I used it too in the Monkey plugin. It uses an annotator extension point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;annotator&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;
&lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.annotator.MonkeyWarningAnnotator"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your class must implement the next interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Annotator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;annotate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;AnnotationHolder&lt;/span&gt; &lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An error message can be registered with next way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newAnnotation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HighlightSeverity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ERROR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errorMsg&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;range&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Examples for &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/kotlin/com/plugin/frege/annotator/FregeWarningAnnotator.kt" rel="noopener noreferrer"&gt;Frege&lt;/a&gt;, &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/highlighting/GoAnnotator.java" rel="noopener noreferrer"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/annotator/MonkeyWarningAnnotator.kt" rel="noopener noreferrer"&gt;Monkey&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For Monkey language, I have currently implemented 2 rules - the inability to resolve links (resolve references - about them below) and the simple type check (via &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/psi/impl/TypeResolver.kt" rel="noopener noreferrer"&gt;DSL&lt;/a&gt;).&lt;/p&gt;

&lt;h1&gt;
  
  
  Highlighting brackets
&lt;/h1&gt;

&lt;p&gt;In this part, we'll look at a couple more extension points.&lt;/p&gt;

&lt;p&gt;The first point of extension: &lt;code&gt;lang.braceMatcher&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;lang.braceMatcher&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;
&lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.editor.MonkeyBraceMatcher"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This extension point enables highlighting a pair of brackets and adding a closing bracket&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flt2y18zszc5gel1s2zej.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flt2y18zszc5gel1s2zej.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The class must implement &lt;code&gt;com.intellij.lang interface.PairedBraceMatcher&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The implementation that I made for the Monkey language can be viewed &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/editor/MonkeyBraceMatcher.kt" rel="noopener noreferrer"&gt;here&lt;/a&gt;, for the go-plugin &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/editor/GoBraceMatcher.java" rel="noopener noreferrer"&gt;here&lt;/a&gt;, for Java - &lt;a href="https://github.com/JetBrains/intellij-community/blob/master/java/java-impl/src/com/intellij/codeInsight/highlighting/JavaBraceMatcher.java" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://github.com/JetBrains/intellij-community/blob/master/java/java-impl/src/com/intellij/codeInsight/highlighting/JavaPairedBraceMatcher.java" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The second point of extension: &lt;code&gt;highlightVisitor&lt;/code&gt;. I have already mentioned it when we were creating a semantic analyzer. I didn't use it in my plugin, but it is used in the popular &lt;a href="https://plugins.jetbrains.com/plugin/10080-rainbow-brackets" rel="noopener noreferrer"&gt;Rainbow Brackets&lt;/a&gt; plugin, which colors pairs of brackets in unique colors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4ue69d4j0p19q960b22.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4ue69d4j0p19q960b22.png" alt="Rainbow Brackets"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you look in his plugin.xml, then you can find this line&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;highlightVisitor&lt;/span&gt; &lt;span class="na"&gt;implementation=&lt;/span&gt;&lt;span class="s"&gt;"com.github.izhangzhihao.rainbow.brackets.visitor.DefaultRainbowVisitor"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class implements the interface - &lt;code&gt;com.intellij.CodeInsight.daemon.impl.HighlightVisitor&lt;/code&gt;. The implementation can be viewed &lt;a href="https://github.com/izhangzhihao/intellij-rainbow-brackets/blob/2020.3/src/main/kotlin/com/github/izhangzhihao/rainbow/brackets/visitor/DefaultRainbowVisitor.kt" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The coloring takes place in the &lt;code&gt;com.github.izhangzhihao.rainbow.brackets method.visitor.RainbowHighlightVisitor#setHighlightInfo&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HighlightInfo&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newHighlightInfo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rainbowElement&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;textAttributes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;range&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Continuation &lt;a href="https://dev.to/pyltsinm/how-to-write-your-own-language-plugin-for-idea-part-2-9g2-temp-slug-7793113"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>kotlin</category>
      <category>idea</category>
      <category>jetbrains</category>
    </item>
    <item>
      <title>How to write your own language plugin for IDEA (part 1)</title>
      <dc:creator>pyltsin</dc:creator>
      <pubDate>Sun, 17 Apr 2022 17:27:32 +0000</pubDate>
      <link>https://dev.to/pyltsinm/how-to-write-your-own-language-plugin-for-idea-part-1-die</link>
      <guid>https://dev.to/pyltsinm/how-to-write-your-own-language-plugin-for-idea-part-1-die</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;I am working as a backend-developer, and sometimes I am tired of work routine. Deeping into some opensource helps me and I really keen on Jetbrains' product and IDEA. IDEA can be customized with plugins, which you can write yourself.&lt;br&gt;
The most part of IDEA's code is open-source. Developers from Jetbrains always help you to make pull request and improve your main tool.&lt;br&gt;
I already have the article about how to write &lt;a href="https://dev.to/pyltsinm/how-to-create-a-new-inspecion-for-idea-10i1"&gt;a small plugin&lt;/a&gt; with one inspection. But if you want to understand how IDEA works, you should try to write a language plugin.&lt;br&gt;
Let's do this.&lt;br&gt;
As a "guinea pig" we will take the simple  language - &lt;a href="https://monkeylang.org/"&gt;Monkey&lt;/a&gt;, the interpreter and compiler for it is described in the &lt;a href="https://interpreterbook.com/"&gt;books on Golang&lt;/a&gt;. Since my goal was not to cover everything, the plugin covers some limited subset of this language. The interpreter can be found &lt;a href="https://github.com/pyltsin/monkey-source"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Example of calculating the Fibonacci number on Monkey:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;let&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
                        &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                    &lt;span class="o"&gt;}&lt;/span&gt;
                    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
                            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                        &lt;span class="o"&gt;}&lt;/span&gt;
                        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
                            &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                        &lt;span class="o"&gt;};&lt;/span&gt;
                    &lt;span class="o"&gt;};&lt;/span&gt;
&lt;span class="o"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will write this plugin with Java and Kotlin (JVM)&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;p&gt;The easiest way to create a new plugin is using &lt;a href="https://github.com/JetBrains/intellij-platform-plugin-template"&gt;the template&lt;/a&gt;. It is being actively developing and had already included most needed features.&lt;/p&gt;

&lt;p&gt;Also we need DevKit plugin, which you can enable in IDEA&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H7k7OJN3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rkhd07pkgcjxijj7rzc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H7k7OJN3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rkhd07pkgcjxijj7rzc6.png" alt="Image description" width="880" height="596"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://plugins.jetbrains.com/plugin/6606-grammar-kit"&gt;Grammar-Kit&lt;/a&gt; plugin will be used to generate a lexer and parser&lt;/p&gt;

&lt;p&gt;Examples of other plugins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/JetBrains/intellij-community"&gt;Java&lt;/a&gt; (in the code of IDEA)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin.git"&gt;go-plugin&lt;/a&gt; (now this plugin is known as Goland)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/carymrobbins/intellij-haskforce"&gt;Haskell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ignatov/intellij-erlang/blob/master/grammars/erlang.bnf"&gt;Erlang&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/IntelliJ-Frege"&gt;Frege&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/pyltsin/monkey-plugin"&gt;Monkey plugin&lt;/a&gt; (in this article)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Creating the basis of a language plugin
&lt;/h1&gt;

&lt;p&gt;The first stages of creating a language plugin are well described in &lt;a href="https://plugins.jetbrains.com/docs/intellij/language-and-filetype.html"&gt;the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is required to declare a new language (examples in &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/GoLanguage.java"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/java/com/plugin/frege/FregeLanguage.java"&gt;frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/MonkeyLanguage.kt"&gt;monkey&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example for Monkey:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.lang.Language&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MonkeyLanguage&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Language&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@JvmStatic&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;INSTANCE&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MonkeyLanguage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Declare an icon (examples in &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/GoIcons.java"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/java/com/plugin/frege/FregeIcons.java"&gt;frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/MonkeyIcons.kt"&gt;monkey&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Declare a new file type and combine everything together (examples in &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/GoFileType.java"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/java/com/plugin/frege/FregeFileType.java"&gt;frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/MonkeyFileType.kt"&gt;monkey&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example for Monkey&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.fileTypes.LanguageFileType&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.swing.Icon&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MonkeyFileType&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LanguageFileType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MonkeyLanguage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;INSTANCE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Monkey File"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getDescription&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Monkey language file"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getDefaultExtension&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"monkey"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getIcon&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Icon&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;MonkeyIcons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FILE&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@JvmStatic&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;INSTANCE&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MonkeyFileType&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, you need to enable a new file type via the extension point. All the features that plugins provide are enabled through one or more extension points. They must be declared in the file plugin.xml (example for &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/resources/META-INF/gogland.xml"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/resources/META-INF/plugin.xml"&gt;frege&lt;/a&gt;). Other examples of using extension points will be given below or can be checked in the &lt;a href="https://plugins.jetbrains.com/docs/intellij/welcome.html"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Example for Monkey (resources/META-INF/plugin.xml)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;extensions&lt;/span&gt; &lt;span class="na"&gt;defaultExtensionNs=&lt;/span&gt;&lt;span class="s"&gt;"com.intellij"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;fileType&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Monkey File"&lt;/span&gt;
            &lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.MonkeyFileType"&lt;/span&gt;
            &lt;span class="na"&gt;fieldName=&lt;/span&gt;&lt;span class="s"&gt;"INSTANCE"&lt;/span&gt;
            &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;
            &lt;span class="na"&gt;extensions=&lt;/span&gt;&lt;span class="s"&gt;"monkey"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/extensions&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Creation PSI-tree
&lt;/h1&gt;

&lt;p&gt;Unfortunately, it is impossible to describe the whole theory that is required to parse the code in one article. Fundamental knowledge for this topic can be found in the "&lt;a href="https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools"&gt;Dragon Book&lt;/a&gt;"&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vSIwDte5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lpwld9cljps0mxiiyaje.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vSIwDte5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lpwld9cljps0mxiiyaje.png" alt="Image description" width="220" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;According to this book, the process of the compiler working with the code consists of the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lexical Analyzer&lt;/li&gt;
&lt;li&gt;Syntax Analyzer&lt;/li&gt;
&lt;li&gt;Semantic Analyzer&lt;/li&gt;
&lt;li&gt;Intermediate Code Generator&lt;/li&gt;
&lt;li&gt;Machine-Independent Code Optimizer&lt;/li&gt;
&lt;li&gt;Code Generator&lt;/li&gt;
&lt;li&gt;Machine-Dependent Code Optimizer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For any IDE to work successfully, it is required to implement the first 3 analyzers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lexical analyzer (to read a stream of characters and to group them into tokens)&lt;/li&gt;
&lt;li&gt;Parser (to receive a stream of tokens and to build a syntax tree from them - &lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;AST&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Semantic analyzer (to use a tree to verify the source code according to some rules).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In IDEA, instead of an AST tree, an analog is used - a PSI tree (Program structure Interface).&lt;/p&gt;

&lt;p&gt;The process of creating a PSI tree is well shown in the illustration from the &lt;a href="https://plugins.jetbrains.com/docs/intellij/implementing-parser-and-psi.html"&gt;documentation&lt;/a&gt;:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P_XGeyDC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rxsh8l8bige992uw2dv6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P_XGeyDC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rxsh8l8bige992uw2dv6.png" alt="Image description" width="758" height="965"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to see PSI-tree, you can use the &lt;a href="https://www.jetbrains.com/help/idea/psi-viewer.html"&gt;PSI Viewer&lt;/a&gt; (Tools-&amp;gt;View PSI structure)&lt;br&gt;
 &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Jai_6Pp_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5v6k2btlp1ioooqgana3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Jai_6Pp_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5v6k2btlp1ioooqgana3.png" alt="Image description" width="861" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In IDEA, the abstract TreeElement class is mainly used to implement the PSI tree&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TreeElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ElementBase&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ASTNode&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Cloneable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;TreeElement&lt;/span&gt; &lt;span class="n"&gt;myNextSibling&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;TreeElement&lt;/span&gt; &lt;span class="n"&gt;myPrevSibling&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;CompositeElement&lt;/span&gt; &lt;span class="n"&gt;myParent&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In IDEA, you can use the &lt;a href="https://plugins.jetbrains.com/plugin/6606-grammar-kit"&gt;GrammarKit&lt;/a&gt; plugin to create a lexer and a parser.&lt;/p&gt;

&lt;h1&gt;
  
  
  Lexer
&lt;/h1&gt;

&lt;p&gt;Perhaps, the easiest way to create a lexer for IDEA is to use &lt;a href="https://jflex.de/"&gt;JFlex&lt;/a&gt;. The GrammarKit plugin already contains an implementation and allows you to generate a lexer from .bnf file or from .flex file (with more customization options). An example for the Monkey language can be viewed &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/java/com/github/pyltsin/monkeyplugin/Monkey.flex"&gt;here&lt;/a&gt;, a more complex one for Frege - &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/java/com/plugin/frege/lexer/FregeLexer.flex"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To generate Lexer, you need to configure the Gradle plugin or use the context menu in .flex file - "Run JFlex Generator".&lt;/p&gt;

&lt;p&gt;After that, you need to declare a class that implements &lt;code&gt;com.intellij.lexer.Lexer&lt;/code&gt;. There is already an adapter for the generated JFlex lexer - &lt;code&gt;com.intellij.lexer.FlexAdapter&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Parser
&lt;/h1&gt;

&lt;p&gt;In IDEA, code generation by the GrammarKit plugin is mainly used to create a parser. Unfortunately, there is not much documentation about it and it is only presented in &lt;a href="https://github.com/JetBrains/Grammar-Kit/blob/master/TUTORIAL.md"&gt;Tutorial&lt;/a&gt; and &lt;a href="https://github.com/JetBrains/Grammar-Kit/blob/master/HOWTO.md"&gt;HOWTO&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The grammar of the language is described in &lt;a href="https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form"&gt;BNF&lt;/a&gt;. The only difference that is used is &lt;code&gt;::=&lt;/code&gt; as "is".&lt;/p&gt;

&lt;p&gt;Example grammar for expressions you can find &lt;a href="https://github.com/JetBrains/Grammar-Kit/blob/master/testData/generator/ExprParser.bnf"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the bnf file consists of 2 parts: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the first part describes the meta information (and the description of tokens, if flex files are not used)&lt;/li&gt;
&lt;li&gt;the second part describes the grammar itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's consider some part of the meta-information:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;parserClass&lt;/code&gt; - name and location of the generated parser class&lt;/p&gt;

&lt;p&gt;&lt;code&gt;parserUtilClass&lt;/code&gt; - a reference to a class containing a set of additional methods for the parser (usually the &lt;code&gt;com.intellij.lang.parser.GeneratedParserUtilBase&lt;/code&gt; class or its inheritors)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;extends = &amp;lt;some class&amp;gt;&lt;/code&gt; - a reference to the base class from which all PSI elements (tree nodes) will be inherited. Usually &lt;code&gt;com.intellij.extapi.psi.ASTWrapperPsiElement&lt;/code&gt; or its inheritors.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;extends(&amp;lt;regexp for tree nodes&amp;gt;) = &amp;lt;psi-element&amp;gt;&lt;/code&gt; (for example: &lt;code&gt;extends(".*expr")=expr&lt;/code&gt;) - all psi elements will be inherited from the specified psi element.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;psiClassPrefix&lt;/code&gt;, &lt;code&gt;psiImplClassSuffix&lt;/code&gt; - respectively the prefix for classes and interfaces (usually by the name of the language) and the suffix for implementing interfaces (usually - &lt;code&gt;Impl&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;psiPackage&lt;/code&gt; and &lt;code&gt;psiImplPackage&lt;/code&gt; are respectively a package for interfaces and their implementations.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;implements&lt;/code&gt; - similar to &lt;code&gt;extends&lt;/code&gt;, but for interfaces&lt;/p&gt;

&lt;p&gt;&lt;code&gt;elementTypeHolderClass&lt;/code&gt; - a generated storage for all types of elements&lt;/p&gt;

&lt;p&gt;&lt;code&gt;elementTypeClass&lt;/code&gt; - a class for types of elemets (not generated, inheritors to &lt;code&gt;com.intellij.psi.tree.IElementType&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;elementTypeFactory&lt;/code&gt; - creating a factory for generating element types (used for Stub - about them below)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;psiImplUtilClass&lt;/code&gt; - a class with a set of static methods that are used as an implementation of the required methods for psi elements. &lt;br&gt;
Let's suppose we have such lines (from go-plugin)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ImportSpec&lt;/span&gt; &lt;span class="o"&gt;::=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="sc"&gt;'.'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;identifier&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;ImportString&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;stubClass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"com.goide.stubs.GoImportSpecStub"&lt;/span&gt;
  &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;&lt;span class="n"&gt;getAlias&lt;/span&gt; &lt;span class="n"&gt;getLocalPackageName&lt;/span&gt; &lt;span class="n"&gt;shouldGoDeeper&lt;/span&gt; &lt;span class="n"&gt;isForSideEffects&lt;/span&gt; &lt;span class="n"&gt;isDot&lt;/span&gt; &lt;span class="n"&gt;getPath&lt;/span&gt; &lt;span class="n"&gt;getName&lt;/span&gt; &lt;span class="n"&gt;isCImport&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For that, we need declare and implement static method with the same name in  &lt;code&gt;psiImplUtilClass&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getAlias&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;GoImportSpec&lt;/span&gt; &lt;span class="n"&gt;importSpec&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that &lt;code&gt;getAlias&lt;/code&gt; will be generated as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getAlias&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;GoPsiImplUtil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAlias&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's move on to the bnf rules themselves. Modifiers can be used for each rule (for example, &lt;code&gt;private&lt;/code&gt;, &lt;code&gt;fake&lt;/code&gt;, and so on). Their description is given &lt;a href="https://github.com/JetBrains/Grammar-Kit#rule-modifiers"&gt;here&lt;/a&gt;. So for example &lt;code&gt;private&lt;/code&gt; in&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;boolean_group&lt;/span&gt; &lt;span class="o"&gt;::=&lt;/span&gt; &lt;span class="n"&gt;xor_expr&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;between_expr&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;is_not_expr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;indicates that the PSI element for &lt;code&gt;boolean_group&lt;/code&gt; will not be generated.&lt;/p&gt;

&lt;p&gt;If it is not possible to correctly describe the grammar in a bnf file, then it will be useful to describe it in code using external rules.&lt;/p&gt;

&lt;p&gt;One of the important parts of grammar is the rules for dealing with errors. Two keywords are used for this: &lt;code&gt;pin&lt;/code&gt; and &lt;code&gt;recoverWhile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pin&lt;/code&gt; - indicates the token number, as soon as we get to which, the parser starts waiting only for the current declaration. For example, declaring a structure in Golang&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Struct&lt;/span&gt; &lt;span class="nc"&gt;Type&lt;/span&gt; &lt;span class="o"&gt;::=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="sc"&gt;'{'&lt;/span&gt; &lt;span class="nc"&gt;Fields&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="sc"&gt;'}'&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;recoverWhile&lt;/code&gt; - specifies which tokens can be consumed after matching with all rules is completed. Recommendations for the use of this attribute are described &lt;a href="https://github.com/JetBrains/Grammar-Kit/blob/master/HOWTO.md#22-using-recoverwhile-attribute"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You should also pay attention to the &lt;a href="https://github.com/JetBrains/Grammar-Kit/blob/master/HOWTO.md#24-compact-expression-parsing-with-priorities"&gt;recommendations&lt;/a&gt; for parsing expressions based on priority.&lt;/p&gt;

&lt;p&gt;It seems to me that creating a correct and convenient grammar rules for future work is one of the most difficult parts of implementing a plugin for a language. To get started, you can use examples: &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/grammars/go.bnf"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/java/com/plugin/frege/Frege.bnf"&gt;Frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/java/com/github/pyltsin/monkeyplugin/Monkey.bnf"&gt;Monkey&lt;/a&gt; (for Monkey, only a subset of this language is implemented for simplification).&lt;/p&gt;

&lt;p&gt;After creating a bnf  and generating a parser from it, you need to define the class for &lt;code&gt;File&lt;/code&gt; (heir from &lt;code&gt;com.intellij.extapi.psi.PsiFileBase&lt;/code&gt;) (examples from &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/psi/GoFile.java"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/kotlin/com/plugin/frege/psi/FregeFile.kt"&gt;Frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/psi/MonkeyFile.kt"&gt;Monkey&lt;/a&gt;) and the definition class for your parser (heir from &lt;code&gt;com.intellij.lang.ParserDefinition&lt;/code&gt;) (example from &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/GoParserDefinition.java"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/java/com/plugin/frege/parser/FregeParserDefinition.java"&gt;Frege&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/parser/MonkeyParserDefinition.kt"&gt;Monkey&lt;/a&gt;), and then enable it via the extension point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;lang.parserDefinition&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;
&lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.parser.MonkeyParserDefinition"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Annotators
&lt;/h1&gt;

&lt;p&gt;In the previous parts, we looked at how a lexer and a parser are created. Now let's move on to the third part - semantic analysis. Studying the code of IDEA and its plugins, I found two ways to implement it (excluding inspections).&lt;/p&gt;

&lt;p&gt;The first way is used in a plugin for the Java language. Consider the following invalid code:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RNKrJXNc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k354nf0ikebcp9zdzqnl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RNKrJXNc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k354nf0ikebcp9zdzqnl.png" alt="Image description" width="234" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;IDEA, of course, highlighted it and said &lt;code&gt;Operator'-'cannot be applied to 'java.lang.String', 'java.lang.String'&lt;/code&gt;. It works thanks to the following extension point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;highlightVisitor&lt;/span&gt; &lt;span class="na"&gt;implementation=&lt;/span&gt;
&lt;span class="s"&gt;"com.intellij.codeInsight.daemon.impl.analysis.HighlightVisitorImpl"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class must implement &lt;code&gt;com.intellij.codeInsight.daemon.impl.HighlightVisitor&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;HighlightVisitor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;suitableForFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiFile&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;analyze&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiFile&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                  &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;updateWholeFile&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                  &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;HighlightInfoHolder&lt;/span&gt; &lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                  &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Runnable&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use the method &lt;code&gt;analyze&lt;/code&gt; to configure, launch (&lt;code&gt;action.run()&lt;/code&gt;) and close resources&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//From HighlightVisitorImpl&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// some code&lt;/span&gt;
      &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// some code&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//Example for ClsJavaModuleImpl&lt;/span&gt;
  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiElementVisitor&lt;/span&gt; &lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;JavaElementVisitor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;JavaElementVisitor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;visitModule&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visitElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is used the &lt;a href="https://en.wikipedia.org/wiki/Visitor_pattern"&gt;visitor&lt;/a&gt; pattern.&lt;br&gt;
&lt;code&gt;HighlightVisitorImpl&lt;/code&gt; extends &lt;code&gt;JavaElementVisitor&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JavaElementVisitor&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;PsiElementVisitor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;visitAnonymousClass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PsiAnonymousClass&lt;/span&gt; &lt;span class="n"&gt;aClass&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;visitClass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aClass&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;visitArrayAccessExpression&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PsiArrayAccessExpression&lt;/span&gt; &lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;visitExpression&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;visitArrayInitializerExpression&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PsiArrayInitializerExpression&lt;/span&gt; &lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;visitExpression&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second way is applied in go-plugin and Frege.&lt;br&gt;
In the Monkey plugin, I used it too. It uses annotator extension point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;annotator&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;
&lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.annotator.MonkeyWarningAnnotator"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your class must implement the next interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Annotator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;annotate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;AnnotationHolder&lt;/span&gt; &lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An error message can be registered with next way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newAnnotation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HighlightSeverity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ERROR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errorMsg&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;range&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Examples for &lt;a href="https://github.com/IntelliJ-Frege/intellij-frege/blob/master/src/main/kotlin/com/plugin/frege/annotator/FregeWarningAnnotator.kt"&gt;Frege&lt;/a&gt;, &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/highlighting/GoAnnotator.java"&gt;go-plugin&lt;/a&gt;, &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/annotator/MonkeyWarningAnnotator.kt"&gt;Monkey&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For the Monkey language, I have currently implemented 2 rules - the inability to resolve links (resolve references - about them below) and a simple type check (via &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/psi/impl/TypeResolver.kt"&gt;DSL&lt;/a&gt;).&lt;/p&gt;

&lt;h1&gt;
  
  
  Highlighting brackets
&lt;/h1&gt;

&lt;p&gt;In this part, we'll look at a couple more extension points.&lt;/p&gt;

&lt;p&gt;The first point of extension: &lt;code&gt;lang.braceMatcher&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;lang.braceMatcher&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"Monkey"&lt;/span&gt;
&lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.monkeyplugin.editor.MonkeyBraceMatcher"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This extension point enable highlighting a pair of brackets and adding a closing bracket&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OtOAwOXK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lt2y18zszc5gel1s2zej.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OtOAwOXK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lt2y18zszc5gel1s2zej.png" alt="Image description" width="614" height="95"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The class must implement &lt;code&gt;com.intellij.lang interface.PairedBraceMatcher&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The implementation that I made for the Monkey language can be viewed &lt;a href="https://github.com/pyltsin/monkey-plugin/blob/main/src/main/kotlin/com/github/pyltsin/monkeyplugin/editor/MonkeyBraceMatcher.kt"&gt;here&lt;/a&gt;, for the go-plugin &lt;a href="https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/src/com/goide/editor/GoBraceMatcher.java"&gt;here&lt;/a&gt;, for Java - &lt;a href="https://github.com/JetBrains/intellij-community/blob/master/java/java-impl/src/com/intellij/codeInsight/highlighting/JavaBraceMatcher.java"&gt;here&lt;/a&gt; and &lt;a href="https://github.com/JetBrains/intellij-community/blob/master/java/java-impl/src/com/intellij/codeInsight/highlighting/JavaPairedBraceMatcher.java"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The second point of extension: &lt;code&gt;highlightVisitor&lt;/code&gt;. I have already mentioned it when we were creating a semantic analyzer. I didn't use it in my plugin, but it is used in the popular &lt;a href="https://plugins.jetbrains.com/plugin/10080-rainbow-brackets"&gt;Rainbow Brackets&lt;/a&gt; plugin, which colors pairs of brackets in unique colors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BAURNTX1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e4ue69d4j0p19q960b22.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BAURNTX1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e4ue69d4j0p19q960b22.png" alt="Image description" width="880" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you look in his plugin.xml, then you can find this line&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;highlightVisitor&lt;/span&gt; &lt;span class="na"&gt;implementation=&lt;/span&gt;&lt;span class="s"&gt;"com.github.izhangzhihao.rainbow.brackets.visitor.DefaultRainbowVisitor"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class implements the interface - &lt;code&gt;com.intellij.CodeInsight.daemon.impl.HighlightVisitor&lt;/code&gt;. The implementation can be viewed &lt;a href="https://github.com/izhangzhihao/intellij-rainbow-brackets/blob/2020.3/src/main/kotlin/com/github/izhangzhihao/rainbow/brackets/visitor/DefaultRainbowVisitor.kt"&gt;here&lt;/a&gt;. The coloring takes place in the &lt;code&gt;com.github.izhangzhihao.rainbow.brackets method.visitor.RainbowHighlightVisitor#setHighlightInfo&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HighlightInfo&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newHighlightInfo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rainbowElement&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;textAttributes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;range&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Continuation here.&lt;/p&gt;

</description>
      <category>java</category>
      <category>kotlin</category>
      <category>idea</category>
      <category>jetbrains</category>
    </item>
    <item>
      <title>From Java to Kotlin. There and back again</title>
      <dc:creator>pyltsin</dc:creator>
      <pubDate>Fri, 01 Apr 2022 20:08:38 +0000</pubDate>
      <link>https://dev.to/pyltsinm/from-java-to-kotlin-there-and-back-again-5h8a</link>
      <guid>https://dev.to/pyltsinm/from-java-to-kotlin-there-and-back-again-5h8a</guid>
      <description>&lt;p&gt;In this article, I would like to consider the problems and their solutions, which we encountered during the migration of our small microservice from Java to Kotlin. &lt;/p&gt;

&lt;h2&gt;
  
  
  Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Java 11&lt;/li&gt;
&lt;li&gt;Spring Web MVC (в рамках Spring Boot)&lt;/li&gt;
&lt;li&gt;Spring Data JPA&lt;/li&gt;
&lt;li&gt;Map Struct&lt;/li&gt;
&lt;li&gt;Lombok&lt;/li&gt;
&lt;li&gt;Maven&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Beginning
&lt;/h2&gt;

&lt;p&gt;Firstly, I would recommend anyone, who wants to put Kotlin in your project to start from tests. During this process, we configure almost all you need. You go through these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure the project&lt;/li&gt;
&lt;li&gt;Add necessary libraries&lt;/li&gt;
&lt;li&gt;Catch many errors&lt;/li&gt;
&lt;li&gt;And, finally, migrate a part of your test.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the same time, the main code responsible for the business logic is not affected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add kotlin
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Maven
&lt;/h3&gt;

&lt;p&gt;As usual, we start from  &lt;a href="https://start.spring.io/"&gt;https://start.spring.io/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's compare 2 pom.xml - one for Java and one for Kotlin.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add Kotlin version
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
 ....
  &lt;span class="nt"&gt;&amp;lt;kotlin.version&amp;gt;&lt;/span&gt;1.5.31&lt;span class="nt"&gt;&amp;lt;/kotlin.version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add the standard library for Kotlin and Jackson
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.fasterxml.jackson.module&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;jackson-module-kotlin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.jetbrains.kotlin&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;kotlin-reflect&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.jetbrains.kotlin&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;kotlin-stdlib-jdk8&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add build section
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;    &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;sourceDirectory&amp;gt;&lt;/span&gt;${project.basedir}/src/main/kotlin&lt;span class="nt"&gt;&amp;lt;/sourceDirectory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;testSourceDirectory&amp;gt;&lt;/span&gt;${project.basedir}/src/test/kotlin&lt;span class="nt"&gt;&amp;lt;/testSourceDirectory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
          .....
            &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.jetbrains.kotlin&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;kotlin-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;args&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;arg&amp;gt;&lt;/span&gt;-Xjsr305=strict&lt;span class="nt"&gt;&amp;lt;/arg&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/args&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;compilerPlugins&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;spring&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;jpa&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/compilerPlugins&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.jetbrains.kotlin&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;kotlin-maven-allopen&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${kotlin.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.jetbrains.kotlin&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;kotlin-maven-noarg&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${kotlin.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More information about &lt;code&gt;kotlin-maven-plugin&lt;/code&gt; you can find &lt;a href="https://kotlinlang.org/docs/maven.html"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But this configuration is not appropriate if you want to use Java with Kotlin. In this case you need to configure maven-compiler-plugin (&lt;a href="https://kotlinlang.org/docs/maven.html#compile-kotlin-and-java-sources"&gt;documentation&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
    .....
    &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.jetbrains.kotlin&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;kotlin-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;compile&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;compile&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;sourceDirs&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;sourceDir&amp;gt;&lt;/span&gt;${project.basedir}/src/main/kotlin&lt;span class="nt"&gt;&amp;lt;/sourceDir&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;sourceDir&amp;gt;&lt;/span&gt;${project.basedir}/src/main/java&lt;span class="nt"&gt;&amp;lt;/sourceDir&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/sourceDirs&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;test-compile&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;test-compile&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;sourceDirs&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;sourceDir&amp;gt;&lt;/span&gt;${project.basedir}/src/test/kotlin&lt;span class="nt"&gt;&amp;lt;/sourceDir&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;sourceDir&amp;gt;&lt;/span&gt;${project.basedir}/src/test/java&lt;span class="nt"&gt;&amp;lt;/sourceDir&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/sourceDirs&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;args&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;arg&amp;gt;&lt;/span&gt;-Xjsr305=strict&lt;span class="nt"&gt;&amp;lt;/arg&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/args&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;compilerPlugins&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;spring&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;jpa&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/compilerPlugins&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.jetbrains.kotlin&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;kotlin-maven-allopen&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${kotlin.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.jetbrains.kotlin&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;kotlin-maven-noarg&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${kotlin.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-compiler-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Replacing default-compile as it is treated specially by maven --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;default-compile&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;none&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Replacing default-testCompile as it is treated specially by maven --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;default-testCompile&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;none&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;java-compile&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;compile&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;compile&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;java-test-compile&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;test-compile&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;testCompile&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some information about plugins &lt;code&gt;All-open&lt;/code&gt; and &lt;code&gt;No-arg&lt;/code&gt; you can find below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kotlin plugins
&lt;/h2&gt;

&lt;p&gt;Kotlin uses &lt;a href="https://kotlinlang.org/docs/all-open-plugin.html"&gt;compiler plugins&lt;/a&gt; to change ast-tree during compilation. By default, spring-initializer adds 2 plugins: &lt;code&gt;all-open&lt;/code&gt; and &lt;code&gt;no-arg&lt;/code&gt;. Also, kapt and the plugin for Lombok are popular.&lt;/p&gt;

&lt;h3&gt;
  
  
  all-open
&lt;/h3&gt;

&lt;p&gt;By default, all classes in Kotlin are final and they can not be overridden, so Spring can't use them to create proxy-class. &lt;code&gt;All-open&lt;/code&gt; plugin adds &lt;code&gt;open&lt;/code&gt; to classes with specified annotations. &lt;/p&gt;

&lt;p&gt;For spring there is a pre-configured &lt;a href="https://kotlinlang.org/docs/all-open-plugin.html#spring-support"&gt;kotlin-spring&lt;/a&gt; plugin. &lt;br&gt;
It works only with these annotations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;@Component&lt;/li&gt;
&lt;li&gt;@Async&lt;/li&gt;
&lt;li&gt;@Transactional&lt;/li&gt;
&lt;li&gt;@Cacheable&lt;/li&gt;
&lt;li&gt;@SpringBootTest&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to work with your custom annotations, you need to configure &lt;code&gt;kotlin-allopen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also, I would like to highlight, that there are no JPA annotations, and you have to add them if you use JPA repositories.&lt;/p&gt;
&lt;h3&gt;
  
  
  No-arg
&lt;/h3&gt;

&lt;p&gt;This plugin adds an empty constructor to each class. For JPA there is &lt;a href="https://kotlinlang.org/docs/no-arg-plugin.html#jpa-support"&gt;kotlin-jpa&lt;/a&gt;. It works with annotations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;@Entity&lt;/li&gt;
&lt;li&gt;@Embeddable&lt;/li&gt;
&lt;li&gt;@MappedSuperclass&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it doesn't add &lt;code&gt;open&lt;/code&gt; to these classes.&lt;/p&gt;
&lt;h3&gt;
  
  
  Kapt
&lt;/h3&gt;

&lt;p&gt;It is an adapter for annotation processors (&lt;a href="https://kotlinlang.org/docs/kapt.html"&gt;documentation&lt;/a&gt;). It is used, for example, by mapstruct to generate code for mappers with Kotlin.&lt;/p&gt;

&lt;p&gt;Example, how you can add kapt plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.jetbrains.kotlin&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;kotlin-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${kotlin.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;kapt&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;kapt&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;sourceDirs&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;sourceDir&amp;gt;&lt;/span&gt;src/main/kotlin&lt;span class="nt"&gt;&amp;lt;/sourceDir&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;sourceDir&amp;gt;&lt;/span&gt;src/main/java&lt;span class="nt"&gt;&amp;lt;/sourceDir&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/sourceDirs&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;annotationProcessorPaths&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;annotationProcessorPath&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.mapstruct&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;mapstruct-processor&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${mapstruct.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/annotationProcessorPath&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/annotationProcessorPaths&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
  ...
  &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
  ....
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my experience, this plugin can break your build, if you use  Lombok because the plugin can't parse java-file where Lombok methods are used.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lombok plugin
&lt;/h3&gt;

&lt;p&gt;This plugin is used to cope with this problem, but it still has only beta versions and doesn't support &lt;code&gt;@Builder&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cook Spring
&lt;/h2&gt;

&lt;p&gt;Spring is an awesome framework, and, of course, it supports &lt;br&gt;
 Kotlin. But there are some interesting features.&lt;/p&gt;

&lt;p&gt;Some presentations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.jetbrains.com/kotlin/2020/08/the-state-of-kotlin-support-in-spring/"&gt;from Jetbrains&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=tt4cxR5onQU"&gt;from Spring&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;the main entry point with Kotlin:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SpringBootApplication&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DemoKotlinApplication&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;runApplication&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DemoKotlinApplication&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;&lt;p&gt;some new extension-methods for Kotlin were added, like  &lt;a href="https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/kotlin/org/springframework/web/client/RestOperationsExtensions.kt"&gt;RestOperationsExtensions.kt&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;it is recommended to use &lt;code&gt;val&lt;/code&gt; arguments with constructor&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;YourBean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;mongoTemplate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MongoTemplate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;solrClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SolrClient&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;but there are some other options, for example, you can use &lt;code&gt;latenin&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;YourBean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;mongoTemplate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MongoTemplate&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;solrClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SolrClient&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is similar to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;YourBean&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;MongoTemplate&lt;/span&gt; &lt;span class="n"&gt;mongoTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SolrClient&lt;/span&gt; &lt;span class="n"&gt;solrClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, you can use injection with set-methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HelloService&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
        &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
        &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
            &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You can create properties classes with &lt;code&gt;@ConstructorBinding&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@ConstructorBinding&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or with &lt;code&gt;lateinit&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;if you want to generate meta-information, you should configure &lt;code&gt;spring-boot-configuration-processor&lt;/code&gt; with &lt;code&gt;kapt&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Kotlin with Hibernate
&lt;/h2&gt;

&lt;p&gt;The main errors and problems are described in the &lt;a href="https://www.jpa-buddy.com/blog/best-practices-and-common-pitfalls/"&gt;Haulmont article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once again, I will draw your attention that you need to configure &lt;code&gt;no-args&lt;/code&gt; and &lt;code&gt;all-open&lt;/code&gt; plugins and implement &lt;code&gt;hashCode&lt;/code&gt; and &lt;code&gt;equals&lt;/code&gt; methods.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kotlin with Jackson
&lt;/h2&gt;

&lt;p&gt;You should add &lt;a href="https://github.com/FasterXML/jackson-module-kotlin"&gt;Jackson Module Kotlin&lt;/a&gt; in your project. After that, you can't specify a type of object explicitly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.fasterxml.jackson.module.kotlin.jacksonObjectMapper&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.fasterxml.jackson.module.kotlin.readValue&lt;/span&gt;

&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;MyStateObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;mapper&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;jacksonObjectMapper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;state&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readValue&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyStateObject&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// or&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MyStateObject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// or&lt;/span&gt;
&lt;span class="n"&gt;myMemberWithType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Kotlin with MapStruct
&lt;/h2&gt;

&lt;p&gt;MapStruct works through the annotation processor. Therefore, it is necessary to configure &lt;code&gt;kapt&lt;/code&gt; correctly. At the same time, if models use Lombok annotations, then there could be problems with mappers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.jetbrains.kotlin&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;kotlin-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${kotlin.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;kapt&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;kapt&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;sourceDirs&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;sourceDir&amp;gt;&lt;/span&gt;src/main/kotlin&lt;span class="nt"&gt;&amp;lt;/sourceDir&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;sourceDir&amp;gt;&lt;/span&gt;src/main/java&lt;span class="nt"&gt;&amp;lt;/sourceDir&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/sourceDirs&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;annotationProcessorPaths&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;annotationProcessorPath&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.mapstruct&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;mapstruct-processor&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${mapstruct.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/annotationProcessorPath&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/annotationProcessorPaths&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
  ...
  &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
  ....
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Kotlin with Lombok
&lt;/h2&gt;

&lt;p&gt;Honestly, it is a pain.&lt;br&gt;
Of course, you can try to use &lt;a href="https://kotlinlang.org/docs/lombok.html"&gt;Lombok compiler plugin&lt;/a&gt;, but often if you use Kapt and Lombok at the same time, you may encounter many problems.&lt;br&gt;
By default, kapt uses all annotation processors and disables their work with javac, but for lombok it doesn't work correctly and you need to disable this behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-compiler-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.5.1&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;source&amp;gt;&lt;/span&gt;1.8&lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;target&amp;gt;&lt;/span&gt;1.8&lt;span class="nt"&gt;&amp;lt;/target&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;annotationProcessorPaths&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;annotationProcessorPath&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;lombok&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${lombok.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/annotationProcessorPath&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/annotationProcessorPaths&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the same time, Lombok works correctly with kapt only if the annotation processor, which is used by kapt, does not depend on Lombok. In our case, it was not true. It was the reason, why we had to translate the entire domain model to Kotlin in the first step. Also one of the options is to use Delombok.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kotlin with Mockito
&lt;/h2&gt;

&lt;p&gt;Mockito does not work correctly with Kotlin types out of the box. Spring recommends using &lt;a href="https://mockk.io/"&gt;Mockk&lt;/a&gt;. There is also a special module for Mockito, which adds support for Kotlin - &lt;a href="https://github.com/mockito/mockito-kotlin"&gt;Mockito-Kotlin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In our project we used Mockito-Kotlin. We found only one problem: you need to be careful, because many methods are duplicated in different modules, for example, &lt;code&gt;any()&lt;/code&gt; will now be in 2 places - &lt;code&gt;org.mockito.kotlin&lt;/code&gt; and &lt;code&gt;org.mockito.Mockito&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kotlin and logging
&lt;/h2&gt;

&lt;p&gt;We chose &lt;a href="https://github.com/MicroUtils/kotlin-logging"&gt;kotlin-logging&lt;/a&gt;. It is a really convenient library and you can use it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;mu.KotlinLogging&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KotlinLogging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; 
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FooWithLogging&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"world"&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"hello $message"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusions
&lt;/h1&gt;

&lt;p&gt;I would like to finish the article with brief conclusions. Using Java and Kotlin together in one project requires additional settings, but almost everything is solved and we get the opportunity to use 2 languages in one project. The biggest problem for us was incompatibility Lombok and Kotlin.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kotlinlang.org/docs/home.html"&gt;Kotlin references&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.jetbrains.com/kotlin/2020/08/the-state-of-kotlin-support-in-spring/"&gt;Video from Jetbrains. Kotlin and Spring
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=tt4cxR5onQU"&gt;Video. Kotlin and Spring from Spring team
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-framework/docs/current/reference/html/languages.html#kotlin-resources"&gt;Kotlin and Spring. References&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-boot/docs/2.5.5/reference/htmlsingle/#features.kotlin"&gt;Kotlin and Spring Boot. References&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mapstruct/mapstruct-examples/tree/master/mapstruct-kotlin"&gt;MapStruct and Kotlin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/FasterXML/jackson-module-kotlin"&gt;Jackson and Kotlin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mockito/mockito-kotlin"&gt;Mockito and Kotlin
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/MicroUtils/kotlin-logging"&gt;kotlin-logging&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>kotlin</category>
      <category>spring</category>
    </item>
    <item>
      <title>How to create a new inspecion for IDEA</title>
      <dc:creator>pyltsin</dc:creator>
      <pubDate>Tue, 15 Mar 2022 07:48:53 +0000</pubDate>
      <link>https://dev.to/pyltsinm/how-to-create-a-new-inspecion-for-idea-10i1</link>
      <guid>https://dev.to/pyltsinm/how-to-create-a-new-inspecion-for-idea-10i1</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclaimer: I don't work for JetBrains, so my code may have some errors and it is only an example.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pzUP5JOJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7bw1q8fi82j86vghsmsy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pzUP5JOJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7bw1q8fi82j86vghsmsy.png" alt="Image description" width="580" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Every large company has its code style. And it is necessary to make people use it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jWJbBaLL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qflb04oxrusnpt0lnzlh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jWJbBaLL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qflb04oxrusnpt0lnzlh.png" alt="Image description" width="500" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's why all checks should be automated (ideally, with CI). For me, the most useful tool is your IDE. We are going to write a simple inspection for IDEA (might be the most popular IDE for Java)&lt;/p&gt;

&lt;p&gt;Every IDEA is a base part and a set of plugins for it. Almost every feature can be considered as a plugin, so adding a new one is easy;&lt;/p&gt;

&lt;h1&gt;
  
  
  Technical specification
&lt;/h1&gt;

&lt;p&gt;One of the most popular questions in a technical interview is about &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html"&gt;HashMap &lt;/a&gt;and &lt;code&gt;equals and hashCode&lt;/code&gt; (links for &lt;a href="https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()"&gt;hashCode&lt;/a&gt;, &lt;a href="http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/a006fa0a9e8f/src/share/classes/java/util/HashMap.java#l143"&gt;HashMap&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IvSxWcu3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oxsys3c00noi2vbjfzqc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IvSxWcu3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oxsys3c00noi2vbjfzqc.jpg" alt="Image description" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So in our company, we have the rule, that every class which we use as a key in HashMap (HashCode) must override &lt;code&gt;equals&lt;/code&gt;and &lt;code&gt;hashCode&lt;/code&gt;. Unfortunately, IDEA doesn't contain an inspection for that (&lt;a href="https://youtrack.jetbrains.com/issue/IDEA-38577"&gt;issue&lt;/a&gt;), but we can fix it!&lt;/p&gt;

&lt;p&gt;We are going to support the next expressions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;new HashMap&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;new HashSet&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.collect(Collectors.toSet());&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.collect(Collectors.toMap());&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Where do we begin?
&lt;/h1&gt;

&lt;p&gt;The start points are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://plugins.jetbrains.com/docs/intellij/welcome.html"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/JetBrains/intellij-community"&gt;Source code of IDEA&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we have a great &lt;a href="https://github.com/JetBrains/intellij-platform-plugin-template"&gt;template &lt;/a&gt;, which contains a useful todo list&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Template ToDo list&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[x] Create a new [IntelliJ Platform Plugin Template][template] project.&lt;/li&gt;
&lt;li&gt;[ ] Verify the &lt;a href="///gradle.properties"&gt;pluginGroup&lt;/a&gt;, &lt;a href="///src/main/resources/META-INF/plugin.xml"&gt;plugin ID&lt;/a&gt; and &lt;a href="https://dev.to/src/main/kotlin"&gt;sources package&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;[ ] Review the &lt;a href="https://plugins.jetbrains.com/docs/marketplace/legal-agreements.html"&gt;Legal Agreements&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;[ ] &lt;a href="https://plugins.jetbrains.com/docs/intellij/publishing-plugin.html?from=IJPluginTemplate"&gt;Publish a plugin manually&lt;/a&gt; for the first time.&lt;/li&gt;
&lt;li&gt;[ ] Set the Plugin ID in the above README badges.&lt;/li&gt;
&lt;li&gt;[ ] Set the &lt;a href="https://plugins.jetbrains.com/docs/marketplace/plugin-upload.html"&gt;Deployment Token&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;[ ] Click the Watch button on the top of the [IntelliJ Platform Plugin Template][template] to be notified about releases containing new features and fixes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also, there are several simple &lt;a href="https://github.com/JetBrains/intellij-sdk-code-samples"&gt;examples&lt;/a&gt;, which help us to figure out how all is working.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementation
&lt;/h1&gt;

&lt;p&gt;The source code of the plugin is &lt;a href="https://github.com/pyltsin/sniffer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Every plugin for IDEA must contain a file &lt;code&gt;resources/META-INF/plugin.xml&lt;/code&gt;, which describes used extension points. if we want to create a new inspection, we have to use &lt;code&gt;localInspection&lt;/code&gt; and implement &lt;a href="https://upsource.jetbrains.com/idea-ce/file/idea-ce-ba0c8fc9ab9bf23a71a6a963cd84fc89b09b9fc8/platform/analysis-api/src/com/intellij/codeInspection/LocalInspectionTool.java"&gt;LocalInspectionTool&lt;/a&gt; or &lt;code&gt;AbstractBaseJavaLocalInspectionTool&lt;/code&gt; for Java)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;extensions&lt;/span&gt; &lt;span class="na"&gt;defaultExtensionNs=&lt;/span&gt;&lt;span class="s"&gt;"com.intellij"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;localInspection&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"JAVA"&lt;/span&gt;
                   &lt;span class="na"&gt;displayName=&lt;/span&gt;&lt;span class="s"&gt;"Sniffer: Using HashMap with default hashcode"&lt;/span&gt;
                   &lt;span class="na"&gt;groupPath=&lt;/span&gt;&lt;span class="s"&gt;"Java"&lt;/span&gt;
                   &lt;span class="na"&gt;groupBundle=&lt;/span&gt;&lt;span class="s"&gt;"messages.SnifferInspectionsBundle"&lt;/span&gt;
                   &lt;span class="na"&gt;groupKey=&lt;/span&gt;&lt;span class="s"&gt;"group.names.sniffer.probable.bugs"&lt;/span&gt;
                   &lt;span class="na"&gt;enabledByDefault=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
                   &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"WEAK WARNING"&lt;/span&gt;
                   &lt;span class="na"&gt;implementationClass=&lt;/span&gt;&lt;span class="s"&gt;"com.github.pyltsin.sniffer.EqualsHashCodeOverrideInspection"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/extensions&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The necessary method is &lt;code&gt;buildVisitor&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;PsiElementVisitor&lt;/span&gt; &lt;span class="nf"&gt;buildVisitor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ProblemsHolder&lt;/span&gt; &lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;isOnTheFly&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                                        &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;LocalInspectionToolSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is an example of &lt;a href="https://en.wikipedia.org/wiki/Visitor_pattern"&gt;Visitor pattern&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To work with your code, IDEA creates PSI Tree (PSI - Program Structure Interface). You can see this tree, using &lt;a href="https://www.jetbrains.com/help/idea/psi-viewer.html"&gt;PSI Viewer&lt;/a&gt; (Tools-&amp;gt;View PSI Structure)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sKvIn8FD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d6f5gnccy9ddq1baavr1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sKvIn8FD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d6f5gnccy9ddq1baavr1.png" alt="Image description" width="880" height="601"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to read more about PSI you have to use the &lt;a href="https://plugins.jetbrains.com/docs/intellij/implementing-parser-and-psi.html"&gt;documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our visitor will go through all leaves of the tree and decide if it contains something wrong or not. &lt;br&gt;
Let's start with an easy case:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uU5e6ojY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3of2716xsags65s7b6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uU5e6ojY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3of2716xsags65s7b6g.png" alt="Image description" width="786" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The leaf &lt;code&gt;new HashMap&amp;lt;&amp;gt;()&lt;/code&gt; matches &lt;code&gt;PsiNewExpression&lt;/code&gt;, so we have to override this method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;buildVisitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ProblemsHolder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;isOnTheFly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LocalInspectionToolSession&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;PsiElementVisitor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="err"&gt;: &lt;/span&gt;&lt;span class="nc"&gt;JavaElementVisitor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;visitNewExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PsiNewExpression&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visitNewExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IDEA contains a lot of useful utils classes, methods, constants, for example, &lt;code&gt;PsiReferenceUtil&lt;/code&gt;, &lt;code&gt;PsiTypesUtil&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Firstly, I need to check if this leaf implements &lt;code&gt;HashMap&lt;/code&gt;or &lt;code&gt;HashSet&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;classOrAnonymousClassReference&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;qualifiedName&lt;/span&gt; 
&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JAVA_UTIL_HASH_MAP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JAVA_UTIL_HASH_SET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;JAVA_UTIL_HASH_MAP&lt;/code&gt;, &lt;code&gt;JAVA_UTIL_HASH_SET&lt;/code&gt;- String constants from &lt;code&gt;com.intellij.psi.CommonClassNames&lt;/code&gt;. This class contains almost all important names.&lt;/p&gt;

&lt;p&gt;Secondly, I need to get a class of the key. Thank IDEA, it has already been done for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;keyType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PsiType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;classOrAnonymousClassReference&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;parameterList&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;typeArguments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I need to check this class if it overrides hashCode and equals method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;hasOverrideHashCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;psiType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PsiType&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// get PsiClass&lt;/span&gt;
  &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;psiClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PsiTypesUtil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPsiClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;psiType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
   &lt;span class="c1"&gt;// get similar methods by name&lt;/span&gt;
  &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PsiMethod&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;psiClass&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;findMethodsByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HardcodedMethodConstants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HASH_CODE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="nf"&gt;arrayOf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;// check, if it is hashCode&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;MethodUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isHashCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, I have to register the problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerProblem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"hashCode is not overriden"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's consider an example with Stream:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Clazz2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Clazz2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collect1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Clazz2&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Clazz2&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--etjbim0q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/id66fx22vxgqpocevudj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--etjbim0q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/id66fx22vxgqpocevudj.png" alt="Image description" width="745" height="706"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case we work with &lt;code&gt;PsiMethodCallExpression&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;visitMethodCallExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PsiMethodCallExpression&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the first check CallMatcher is useful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;matcher&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CallMatcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instanceCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JAVA_UTIL_STREAM_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"collect"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;isCollect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;matcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, Collectors.toMap() must be checked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val collectorExpression = expression.argumentList.expressions[0]
val isToMap = CallMatcher.staticCall(JAVA_UTIL_STREAM_COLLECTORS, "toMap")
  .matches(collectorExpression)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get class the next method can be applied:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;psiType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;methodExpression&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, we can reuse our previous code to check overriden equals and hashCode.&lt;/p&gt;

&lt;p&gt;For tests, Idea has &lt;code&gt;LightJavaInspectionTestCase&lt;/code&gt;class. (&lt;a href="https://github.com/JetBrains/intellij-community"&gt;examples&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Finally, our result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PfbxEHF4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1vo9bcaueq3w2ltz8u3k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PfbxEHF4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1vo9bcaueq3w2ltz8u3k.png" alt="Image description" width="878" height="108"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, you can simply enhance these ideas for other cases.&lt;/p&gt;

&lt;p&gt;It is really important to get to know your tools!&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>java</category>
      <category>idea</category>
      <category>jetbrains</category>
    </item>
  </channel>
</rss>
