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:
committed by
Space Team
parent
4c1a66b7d6
commit
1e0115aef8
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtCompilerPluginsProvider
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
|
||||
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
|
||||
import org.jetbrains.kotlin.extensions.internal.InternalNonStableExtensionPoints
|
||||
import org.jetbrains.kotlin.resolve.extensions.AssignResolutionAltererExtension
|
||||
|
||||
@Suppress("unused")
|
||||
class KtFe10CompilerPluginsProvider : KtCompilerPluginsProvider() {
|
||||
override fun <T : Any> getRegisteredExtensions(module: KtSourceModule, extensionType: ProjectExtensionDescriptor<T>): List<T> {
|
||||
return extensionType.getInstances(module.project)
|
||||
}
|
||||
|
||||
@OptIn(InternalNonStableExtensionPoints::class)
|
||||
override fun isPluginOfTypeRegistered(module: KtSourceModule, pluginType: CompilerPluginType): Boolean {
|
||||
val extension = when (pluginType) {
|
||||
CompilerPluginType.ASSIGNMENT -> AssignResolutionAltererExtension
|
||||
else -> return false
|
||||
}
|
||||
return extension.getInstances(module.project).isNotEmpty()
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ dependencies {
|
||||
api(project(":compiler:fir:checkers:checkers.js"))
|
||||
api(project(":compiler:fir:checkers:checkers.native"))
|
||||
api(project(":compiler:fir:java"))
|
||||
api(project(":compiler:fir:entrypoint"))
|
||||
api(project(":analysis:low-level-api-fir"))
|
||||
api(project(":analysis:analysis-api"))
|
||||
api(project(":analysis:analysis-api-impl-base"))
|
||||
|
||||
@@ -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"))
|
||||
}
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+22
-1
@@ -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
|
||||
}
|
||||
}
|
||||
+2
@@ -12,4 +12,6 @@ import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
|
||||
internal object NoOpKtCompilerPluginsProvider : KtCompilerPluginsProvider() {
|
||||
override fun <T : Any> getRegisteredExtensions(module: KtSourceModule, extensionType: ProjectExtensionDescriptor<T>): List<T> =
|
||||
emptyList()
|
||||
|
||||
override fun isPluginOfTypeRegistered(module: KtSourceModule, pluginType: CompilerPluginType): Boolean = false
|
||||
}
|
||||
|
||||
+10
@@ -11,10 +11,20 @@ import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
|
||||
* A service which can return extensions which are registered for some module
|
||||
*/
|
||||
public abstract class KtCompilerPluginsProvider {
|
||||
|
||||
enum class CompilerPluginType {
|
||||
ASSIGNMENT
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of extensions of a base [extensionType] which are registered for [module]
|
||||
*
|
||||
* These extensions are used in addition to those provided by the extension descriptor's [ProjectExtensionDescriptor.getInstances].
|
||||
*/
|
||||
public abstract fun <T : Any> getRegisteredExtensions(module: KtSourceModule, extensionType: ProjectExtensionDescriptor<T>): List<T>
|
||||
|
||||
/**
|
||||
* Returns `true` if at least one plugin with requested `pluginType` is registered, `false` otherwise
|
||||
*/
|
||||
public abstract fun isPluginOfTypeRegistered(module: KtSourceModule, pluginType: CompilerPluginType): Boolean
|
||||
}
|
||||
+1
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.types.expressions.ExpressionTypingComponents
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
|
||||
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
|
||||
|
||||
|
||||
@InternalNonStableExtensionPoints
|
||||
interface AssignResolutionAltererExtension : AnnotationBasedExtension {
|
||||
companion object : ProjectExtensionDescriptor<AssignResolutionAltererExtension>(
|
||||
|
||||
@@ -104,6 +104,8 @@ public class OperatorConventions {
|
||||
.put(KtTokens.MINUSEQ, KtTokens.MINUS)
|
||||
.build();
|
||||
|
||||
public static final Name ASSIGN_METHOD = Name.identifier("assign");
|
||||
|
||||
public static final ImmutableBiMap<KtSingleValueToken, Name> BOOLEAN_OPERATIONS = ImmutableBiMap.<KtSingleValueToken, Name>builder()
|
||||
.put(KtTokens.ANDAND, AND)
|
||||
.put(KtTokens.OROR, OR)
|
||||
|
||||
-3
@@ -5,10 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.assignment.plugin
|
||||
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
object AssignmentPluginNames {
|
||||
const val PLUGIN_ID = "org.jetbrains.kotlin.assignment"
|
||||
const val ANNOTATION_OPTION_NAME = "annotation"
|
||||
val ASSIGN_METHOD = Name.identifier("assign")
|
||||
}
|
||||
|
||||
+2
-2
@@ -5,10 +5,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.assignment.plugin
|
||||
|
||||
import org.jetbrains.kotlin.cfg.getElementParentDeclaration
|
||||
import org.jetbrains.kotlin.assignment.plugin.AssignmentPluginNames.ASSIGN_METHOD
|
||||
import org.jetbrains.kotlin.assignment.plugin.diagnostics.ErrorsAssignmentPlugin.CALL_ERROR_ASSIGN_METHOD_SHOULD_RETURN_UNIT
|
||||
import org.jetbrains.kotlin.assignment.plugin.diagnostics.ErrorsAssignmentPlugin.NO_APPLICABLE_ASSIGN_METHOD
|
||||
import org.jetbrains.kotlin.cfg.getElementParentDeclaration
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
@@ -29,6 +28,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingComponents
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
|
||||
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions.ASSIGN_METHOD
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import java.util.*
|
||||
|
||||
+1
-1
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.assignment.plugin.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.assignment.plugin.AssignmentPluginNames.ASSIGN_METHOD
|
||||
import org.jetbrains.kotlin.assignment.plugin.diagnostics.ErrorsAssignmentPlugin.DECLARATION_ERROR_ASSIGN_METHOD_SHOULD_RETURN_UNIT
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
@@ -19,6 +18,7 @@ import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions.ASSIGN_METHOD
|
||||
|
||||
class AssignmentPluginDeclarationChecker(private val annotations: List<String>) : DeclarationChecker {
|
||||
|
||||
|
||||
+3
-2
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.assignment.plugin.k2
|
||||
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.assignment.plugin.AssignmentPluginNames.ASSIGN_METHOD
|
||||
import org.jetbrains.kotlin.fakeElement
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
@@ -19,7 +18,9 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFieldSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.upperBoundIfFlexible
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions.ASSIGN_METHOD
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
class FirAssignmentPluginAssignAltererExtension(
|
||||
|
||||
+1
-5
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.assignment.plugin.k2.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.assignment.plugin.AssignmentPluginNames.ASSIGN_METHOD
|
||||
import org.jetbrains.kotlin.assignment.plugin.k2.annotationMatchingService
|
||||
import org.jetbrains.kotlin.assignment.plugin.k2.diagnostics.FirErrorsAssignmentPlugin.CALL_ERROR_ASSIGN_METHOD_SHOULD_RETURN_UNIT
|
||||
import org.jetbrains.kotlin.assignment.plugin.k2.diagnostics.FirErrorsAssignmentPlugin.NO_APPLICABLE_ASSIGN_METHOD
|
||||
@@ -17,18 +16,15 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.arguments
|
||||
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
|
||||
import org.jetbrains.kotlin.fir.references.isError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDiagnosticWithSingleCandidate
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
||||
import org.jetbrains.kotlin.fir.types.isUnit
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions.ASSIGN_METHOD
|
||||
|
||||
object FirAssignmentPluginFunctionCallChecker : FirFunctionCallChecker() {
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.assignment.plugin.k2.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.assignment.plugin.AssignmentPluginNames.ASSIGN_METHOD
|
||||
import org.jetbrains.kotlin.assignment.plugin.k2.annotationMatchingService
|
||||
import org.jetbrains.kotlin.assignment.plugin.k2.diagnostics.FirErrorsAssignmentPlugin.DECLARATION_ERROR_ASSIGN_METHOD_SHOULD_RETURN_UNIT
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
@@ -19,6 +18,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.isExtension
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isUnit
|
||||
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions.ASSIGN_METHOD
|
||||
|
||||
object FirAssignmentPluginFunctionChecker : FirSimpleFunctionChecker() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user