[kotlin] KTIJ-24390 Assignment plugin: imports are not recognized

Note that this commit depends on changes made for KT-57468.

The problem affected `ImportOptimizer` (correct import statement was
recognized as unused) and `Import[Quick]Fix` (missing import was not
suggested). Both were mostly caused by the inability to provide
a `Name` of the function for overridden assignment [1].

This commit introduces the following changes:
1. Module `kotlin.compiler-plugins.assignment.common` was split to
   manage K1 and K2 dependencies properly. Extensions we re-registered
   accordingly [2].
2. K1- and K2- plugin specific import quick fixes introduced [3]
3. K2 plugin added to bundled (so far, it's the way to make it active) [4]
4. Support for `KtCompilerPluginsProvider` extension [5]
5. Tests for import quick fixes and unused import inspection.

--------------------------------------------------------------------
[1]: KtSimpleNameReference.getResolvesByNames
[2]: IdeAssignPluginResolutionAltererExtension and
     IdeAssignmentContainerContributor
[3]: AssignmentPluginImportFix, FirAssignmentPluginQuickFixRegistrar
[4]: KotlinK2BundledCompilerPlugins
[5]: KtCompilerPluginsProviderIdeImpl, KtFe10CompilerPluginsProvider

^KTIJ-24390 fixed

GitOrigin-RevId: 8fec44b5c43b11aa6741c3d9cac1549886645433
This commit is contained in:
Andrei Klunnyi
2023-03-08 10:59:43 +01:00
committed by intellij-monorepo-bot
parent aaea26aaa9
commit deffb78794
37 changed files with 292 additions and 29 deletions

View File

@@ -3,6 +3,7 @@
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
@@ -19,5 +20,9 @@
<orderEntry type="module" module-name="kotlin.compiler-plugins.compiler-plugin-support.common" />
<orderEntry type="module" module-name="intellij.platform.core.impl" />
<orderEntry type="module" module-name="intellij.java.psi" />
<orderEntry type="module" module-name="kotlin.base.fe10.code-insight" />
<orderEntry type="module" module-name="kotlin.idea" />
<orderEntry type="module" module-name="kotlin.code-insight.api" />
<orderEntry type="module" module-name="kotlin.base.fe10.analysis" />
</component>
</module>

View File

@@ -0,0 +1,7 @@
<idea-plugin package="org.jetbrains.kotlin.idea.compilerPlugin.assignment.k1">
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<assignResolutionAltererExtension implementation="org.jetbrains.kotlin.idea.compilerPlugin.assignment.k1.IdeAssignPluginResolutionAltererExtension"/>
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.idea.compilerPlugin.assignment.k1.IdeAssignmentContainerContributor"/>
<quickFixContributor implementation="org.jetbrains.kotlin.idea.compilerPlugin.assignment.k1.AssignmentPluginQuickFixContributor"/>
</extensions>
</idea-plugin>

View File

@@ -1,5 +1,5 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.compilerPlugin.assignment
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.compilerPlugin.assignment.k1
import com.intellij.openapi.components.Service
import com.intellij.openapi.module.Module

View File

@@ -0,0 +1,38 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.compilerPlugin.assignment.k1
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.quickfix.AbstractImportFix
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtOperationReferenceExpression
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
import org.jetbrains.kotlin.types.expressions.OperatorConventions
/**
* The idea behind this plugin specific import fix is to convey to the outer logic that import suggestions should be made based on an
* assumption that the call type is actually `CallTypeAndReceiver.DOT` (as it is under the cover) but not `CallTypeAndReceiver.OPERATOR`
* (as it is in the source code).
*/
class AssignmentPluginImportFix(expression: KtOperationReferenceExpression): AbstractImportFix(expression, MyFactory) {
companion object MyFactory : FactoryWithUnresolvedReferenceQuickFix() {
override fun areActionsAvailable(diagnostic: Diagnostic): Boolean {
val expression = extractExpression(diagnostic)
return expression != null && expression.references.isNotEmpty()
}
override fun createImportAction(diagnostic: Diagnostic): AssignmentPluginImportFix? =
extractExpression(diagnostic)?.let(::AssignmentPluginImportFix)
private fun extractExpression(diagnostic: Diagnostic): KtOperationReferenceExpression? =
diagnostic.psiElement as? KtOperationReferenceExpression
}
override fun getCallTypeAndReceiver(): CallTypeAndReceiver<*, *>? {
return element?.let { CallTypeAndReceiver.DOT(it.getReceiverExpression()!!) }
}
override val importNames: Collection<Name>
get() = listOf(OperatorConventions.ASSIGN_METHOD)
}

View File

@@ -0,0 +1,13 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.compilerPlugin.assignment.k1
import org.jetbrains.kotlin.assignment.plugin.diagnostics.ErrorsAssignmentPlugin
import org.jetbrains.kotlin.idea.quickfix.QuickFixContributor
import org.jetbrains.kotlin.idea.quickfix.QuickFixes
class AssignmentPluginQuickFixContributor: QuickFixContributor {
override fun registerQuickFixes(quickFixes: QuickFixes) {
quickFixes.register(ErrorsAssignmentPlugin.NO_APPLICABLE_ASSIGN_METHOD, AssignmentPluginImportFix)
}
}

View File

@@ -1,6 +1,6 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.compilerPlugin.assignment
package org.jetbrains.kotlin.idea.compilerPlugin.assignment.k1
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project

View File

@@ -1,6 +1,6 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.compilerPlugin.assignment
package org.jetbrains.kotlin.idea.compilerPlugin.assignment.k1
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="kotlin.plugin.k2" scope="TEST" />
<orderEntry type="library" name="kotlinc.kotlin-stdlib" level="project" />
<orderEntry type="module" module-name="kotlin.code-insight.api" />
<orderEntry type="library" name="kotlinc.high-level-api-fir" level="project" />
<orderEntry type="library" name="kotlinc.kotlin-compiler-common" level="project" />
<orderEntry type="module" module-name="kotlin.base.analysis-api.utils" />
<orderEntry type="module" module-name="kotlin.fir" />
<orderEntry type="library" name="kotlinc.high-level-api" level="project" />
<orderEntry type="module" module-name="intellij.platform.core.impl" />
<orderEntry type="module" module-name="intellij.platform.analysis" />
<orderEntry type="module" module-name="intellij.java.psi" />
</component>
</module>

View File

@@ -0,0 +1,5 @@
<idea-plugin package="org.jetbrains.kotlin.idea.compilerPlugin.assignment">
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<codeinsight.quickfix.registrar implementation="org.jetbrains.kotlin.idea.compilerPlugin.assignment.FirAssignmentPluginQuickFixRegistrar"/>
</extensions>
</idea-plugin>

View File

@@ -0,0 +1,49 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.compilerPlugin.assignment
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KtFirDiagnostic
import org.jetbrains.kotlin.analysis.project.structure.KtCompilerPluginsProvider
import org.jetbrains.kotlin.analysis.project.structure.KtCompilerPluginsProvider.CompilerPluginType
import org.jetbrains.kotlin.analysis.project.structure.getKtModuleOfType
import org.jetbrains.kotlin.idea.base.analysis.api.utils.KtSymbolFromIndexProvider
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.KotlinQuickFixRegistrar
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.KotlinQuickFixesList
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.KtQuickFixesListBuilder
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.diagnosticFixFactory
import org.jetbrains.kotlin.idea.quickfix.fixes.ImportQuickFix.Companion.createImportNameFix
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.types.expressions.OperatorConventions
internal class FirAssignmentPluginQuickFixRegistrar : KotlinQuickFixRegistrar() {
private val fixes = KtQuickFixesListBuilder.registerPsiQuickFix {
registerApplicator(FACTORY)
}
override val list: KotlinQuickFixesList = KotlinQuickFixesList.createCombined(fixes)
}
private val FACTORY = diagnosticFixFactory(KtFirDiagnostic.UnresolvedReference::class) { diagnostic ->
val element = diagnostic.psi
val project = element.project
val quickFix = if (element is KtBinaryExpression
&& element.operationToken == KtTokens.EQ
&& isAssignmentPluginEnabled(project, element)
) {
val indexProvider = KtSymbolFromIndexProvider(project)
createImportNameFix(indexProvider, element.operationReference, OperatorConventions.ASSIGN_METHOD)
} else {
null
}
listOfNotNull(quickFix)
}
private fun isAssignmentPluginEnabled(project: Project, element: PsiElement): Boolean =
project.getService(KtCompilerPluginsProvider::class.java)
.isPluginOfTypeRegistered(element.getKtModuleOfType(project), CompilerPluginType.ASSIGNMENT)

View File

@@ -13,4 +13,4 @@
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
<projectResolve implementation="org.jetbrains.kotlin.idea.compilerPlugin.assignment.gradleJava.AssignmentProjectResolverExtension" order="last"/>
</extensions>
</idea-plugin>
</idea-plugin>