mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
101 lines
3.8 KiB
HTML
101 lines
3.8 KiB
HTML
<html>
|
|
<body>
|
|
Reports incorrect companion objects' usage in <a href="https://plugins.jetbrains.com/docs/intellij/plugin-extensions.html">extensions</a>.
|
|
<p>
|
|
Kotlin companion object is always created once you try to load its containing class, and extension point implementations are supposed to be cheap to create.
|
|
Excessive classloading in plugins is a huge problem for IDE startup.
|
|
</p>
|
|
<p>Bad pattern:</p>
|
|
<pre><code lang="kotlin">
|
|
class KotlinDocumentationProvider : AbstractDocumentationProvider(), ExternalDocumentationProvider {
|
|
|
|
companion object {
|
|
private val LOG = Logger.getInstance(KotlinDocumentationProvider::class.java)
|
|
private val javaDocumentProvider = JavaDocumentationProvider()
|
|
}
|
|
}
|
|
</code></pre>
|
|
<p>
|
|
Here <code>KotlinDocumentationProvider</code> is an extension registered in <code>plugin.xml</code>:
|
|
</p>
|
|
<pre><code lang="xml">
|
|
<lang.documentationProvider language="kotlin"
|
|
implementationClass="org.jetbrains.kotlin.idea.KotlinDocumentationProvider"
|
|
order="first"/>
|
|
</code></pre>
|
|
<p>
|
|
In this example <code>JavaDocumentationProvider</code> will be loaded from disk once someone just calls <code>new KotlinDocumentationProvider()</code>.
|
|
</p>
|
|
<p>
|
|
Kotlin companion objects in extension point implementation can only contain a logger and simple constants.
|
|
Other declarations may cause excessive classloading or early initialization of heavy resources (e.g., <code>TokenSet</code>, Regex, etc.)
|
|
when the extension class is loaded.
|
|
Note that even declarations marked with <code>@JvmStatic</code> still produce an extra class for the companion object, potentially causing expensive computations.
|
|
</p>
|
|
<p>
|
|
Instead of being stored in the companion object, these declarations must be top-level or stored in an object.
|
|
</p>
|
|
<h3>FAQ</h3>
|
|
<h4>How to rewrite run ConfigurationType?</h4>
|
|
<p>Move the declaration to top-level:</p>
|
|
<pre><code lang="kotlin">
|
|
// DO, use top level fun
|
|
internal fun mnRunConfigurationType(): MnRunConfigurationType = runConfigurationType<MnRunConfigurationType>()
|
|
|
|
internal class MnRunConfigurationType : ConfigurationType {
|
|
companion object { // DON'T
|
|
fun getInstance(): MnRunConfigurationType = runConfigurationType<MnRunConfigurationType>()
|
|
}
|
|
...
|
|
</code></pre>
|
|
<h4>How to rewrite FileType?</h4>
|
|
<p>Before:</p>
|
|
<pre><code lang="kotlin">
|
|
internal class SpringBootImportsFileType : LanguageFileType(SPILanguage.INSTANCE, true) {
|
|
companion object {
|
|
val FILE_TYPE = SpringBootImportsFileType()
|
|
...
|
|
</code></pre>
|
|
<p>After:</p>
|
|
<pre><code lang="kotlin">
|
|
internal object SpringBootImportsFileType : LanguageFileType(SPILanguage.INSTANCE, true) {
|
|
...
|
|
</code></pre>
|
|
<p>Use <code>INSTANCE</code> fieldName in <code>plugin.xml</code>:</p>
|
|
<pre><code lang="xml">
|
|
<fileType name="Spring Boot Imports"
|
|
fieldName="INSTANCE"
|
|
implementationClass="com.intellij.spring.boot.spi.SpringBootImportsFileType"/>
|
|
</code></pre>
|
|
<h4>How to rewrite CounterUsagesCollector?
|
|
</h4>
|
|
<h5>Internal API</h5>
|
|
<p>Before:</p>
|
|
<pre><code lang="kotlin">
|
|
class AntActionsUsagesCollector : CounterUsagesCollector() {
|
|
override fun getGroup(): EventLogGroup = GROUP
|
|
|
|
companion object {
|
|
private val GROUP = EventLogGroup("build.ant.actions", 1)
|
|
|
|
@JvmField
|
|
val runSelectedBuildAction = GROUP.registerEvent("RunSelectedBuild")
|
|
}
|
|
}
|
|
</code></pre>
|
|
<p>After:</p>
|
|
<pre><code lang="kotlin">
|
|
object AntActionsUsagesCollector : CounterUsagesCollector() {
|
|
override fun getGroup(): EventLogGroup = GROUP
|
|
|
|
private val GROUP = EventLogGroup("build.ant.actions", 1)
|
|
|
|
@JvmField
|
|
val runSelectedBuildAction = GROUP.registerEvent("RunSelectedBuild")
|
|
}
|
|
</code></pre>
|
|
|
|
<!-- tooltip end -->
|
|
<p><small>New in 2023.3</small>
|
|
</body>
|
|
</html> |