KT-57468 Kotlin assignment plugin: operation name cannot be found

The problem results in broken import quick fix and import optimizer on
the IDE side [1].

`AssignResolutionAltererExtension` introduced a possibility to override
 resolution of assignment statements. The inconsistency though is
 that `KtSimpleNameReference.getResolvesByNames` doesn't return a name
 for the overridden `=`. Kotlin as a language doesn't support this [2].

This commit eliminates the drawback above:
1. It fixes the name `assign` the `=` can be resolved to [3].
   This eliminates the need to search for the name, bypassing the
   plugins.
2. `KtSimpleNameReference.getResolvesByNames` returns `assign` among
   other names in case it deals with binary `=` and assignment is
   resolved.
3. `KtCompilerPluginsProvider` was extended to check plugins' presence.
   K1 implementation added.

----------------------------------------------------------------
[1]: https://youtrack.jetbrains.com/issue/KTIJ-24390
[2]: OperatorConventions.getNameForOperationSymbol
     https://kotlinlang.org/docs/operator-overloading.html#augmented-assignments
[3]: OperatorConventions#ASSIGN_METHOD + AssignmentPluginNames
This commit is contained in:
Andrei Klunnyi
2023-03-08 10:57:51 +01:00
committed by Space Team
parent 4c1a66b7d6
commit 1e0115aef8
16 changed files with 83 additions and 22 deletions
+2
View File
@@ -7,6 +7,8 @@ dependencies {
implementation(project(":compiler:psi"))
implementation(project(":analysis:light-classes-base"))
implementation(intellijCore())
implementation(project(":analysis:analysis-api-providers"))
implementation(project(":analysis:project-structure"))
compileOnly(commonDependency("com.google.guava:guava"))
}
@@ -7,14 +7,14 @@ package org.jetbrains.kotlin.references.fe10
import com.intellij.psi.PsiElement
import com.intellij.util.SmartList
import org.jetbrains.kotlin.references.fe10.base.KtFe10Reference
import org.jetbrains.kotlin.references.fe10.base.KtFe10ReferenceResolutionHelper
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.readWriteAccess
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
import org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.references.fe10.base.KtFe10Reference
import org.jetbrains.kotlin.references.fe10.base.KtFe10ReferenceResolutionHelper
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
@@ -98,4 +98,4 @@ class KtFe10SimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleNa
}
return null
}
}
}
@@ -5,8 +5,12 @@
package org.jetbrains.kotlin.idea.references
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.project.structure.KtCompilerPluginsProvider
import org.jetbrains.kotlin.analysis.project.structure.KtCompilerPluginsProvider.CompilerPluginType
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -14,6 +18,9 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.types.expressions.OperatorConventions.ASSIGN_METHOD
import org.jetbrains.kotlin.utils.addToStdlib.runIf
import org.jetbrains.kotlin.analysis.project.structure.getKtModule
abstract class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleReference<KtSimpleNameExpression>(expression) {
// Extension point used by deprecated android extensions.
@@ -65,7 +72,12 @@ abstract class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSim
if (tokenType != null) {
val name = OperatorConventions.getNameForOperationSymbol(
tokenType, element.parent is KtUnaryExpression, element.parent is KtBinaryExpression
) ?: return emptyList()
)
?: (expression.parent as? KtBinaryExpression)?.let {
runIf(it.operationToken == KtTokens.EQ && isAssignmentResolved(element.project, it)) { ASSIGN_METHOD }
}
?: return emptyList()
val counterpart = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS[tokenType]
return if (counterpart != null) {
val counterpartName = OperatorConventions.getNameForOperationSymbol(counterpart, false, true)!!
@@ -80,4 +92,13 @@ abstract class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSim
}
abstract fun getImportAlias(): KtImportAlias?
}
private fun isAssignmentResolved(project: Project, binaryExpression: KtBinaryExpression): Boolean {
val sourceModule = binaryExpression.getKtModule(element.project) as? KtSourceModule ?: return false
val reference = binaryExpression.operationReference.reference ?: return false
val pluginPresenceService = project.getService(KtCompilerPluginsProvider::class.java)
?: error("KtAssignResolutionPresenceService is not available as a service")
return pluginPresenceService.isPluginOfTypeRegistered(sourceModule, CompilerPluginType.ASSIGNMENT)
&& (reference.resolve() as? KtNamedFunction)?.nameAsName == ASSIGN_METHOD
}
}