diff --git a/platform/build-scripts/src/org/jetbrains/intellij/build/kotlin/KotlinPluginBuilder.kt b/platform/build-scripts/src/org/jetbrains/intellij/build/kotlin/KotlinPluginBuilder.kt index 3c7d5f3717f8..69771e8f1887 100644 --- a/platform/build-scripts/src/org/jetbrains/intellij/build/kotlin/KotlinPluginBuilder.kt +++ b/platform/build-scripts/src/org/jetbrains/intellij/build/kotlin/KotlinPluginBuilder.kt @@ -86,7 +86,8 @@ object KotlinPluginBuilder { "kotlin.compiler-plugins.sam-with-receiver.common", "kotlin.compiler-plugins.sam-with-receiver.gradle", "kotlin.compiler-plugins.sam-with-receiver.maven", - "kotlin.compiler-plugins.assignment.common", + "kotlin.compiler-plugins.assignment.common-k1", + "kotlin.compiler-plugins.assignment.common-k2", "kotlin.compiler-plugins.assignment.gradle", "kotlin.compiler-plugins.assignment.maven", "kotlin.compiler-plugins.lombok.gradle", diff --git a/plugins/kotlin/bundled-compiler-plugins-support/kotlin.bundled-compiler-plugins-support.iml b/plugins/kotlin/bundled-compiler-plugins-support/kotlin.bundled-compiler-plugins-support.iml index 6870861fbb8c..bc67734f603f 100644 --- a/plugins/kotlin/bundled-compiler-plugins-support/kotlin.bundled-compiler-plugins-support.iml +++ b/plugins/kotlin/bundled-compiler-plugins-support/kotlin.bundled-compiler-plugins-support.iml @@ -18,5 +18,6 @@ + \ No newline at end of file diff --git a/plugins/kotlin/bundled-compiler-plugins-support/src/org/jetbrains/kotlin/idea/fir/extensions/KotlinK2BundledCompilerPlugins.kt b/plugins/kotlin/bundled-compiler-plugins-support/src/org/jetbrains/kotlin/idea/fir/extensions/KotlinK2BundledCompilerPlugins.kt index 5655710eda98..659aaee799a7 100644 --- a/plugins/kotlin/bundled-compiler-plugins-support/src/org/jetbrains/kotlin/idea/fir/extensions/KotlinK2BundledCompilerPlugins.kt +++ b/plugins/kotlin/bundled-compiler-plugins-support/src/org/jetbrains/kotlin/idea/fir/extensions/KotlinK2BundledCompilerPlugins.kt @@ -3,6 +3,7 @@ package org.jetbrains.kotlin.idea.fir.extensions import com.intellij.openapi.application.PathManager import org.jetbrains.kotlin.allopen.AllOpenComponentRegistrar +import org.jetbrains.kotlin.assignment.plugin.AssignmentComponentRegistrar import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi import org.jetbrains.kotlin.idea.fir.extensions.KotlinK2BundledCompilerPlugins.Companion.COMPILER_PLUGIN_REGISTRAR_FILE @@ -50,6 +51,10 @@ enum class KotlinK2BundledCompilerPlugins( SamWithReceiverComponentRegistrar::class, ), + ASSIGNMENT_COMPILER_PLUGIN( + AssignmentComponentRegistrar::class, + ), + KOTLINX_SERIALIZATION_COMPILER_PLUGIN( SerializationComponentRegistrar::class, ), diff --git a/plugins/kotlin/compiler-plugins/assignment/common/kotlin.compiler-plugins.assignment.common.iml b/plugins/kotlin/compiler-plugins/assignment/common-k1/kotlin.compiler-plugins.assignment.common-k1.iml similarity index 79% rename from plugins/kotlin/compiler-plugins/assignment/common/kotlin.compiler-plugins.assignment.common.iml rename to plugins/kotlin/compiler-plugins/assignment/common-k1/kotlin.compiler-plugins.assignment.common-k1.iml index 1190a563e43b..402da3d59042 100644 --- a/plugins/kotlin/compiler-plugins/assignment/common/kotlin.compiler-plugins.assignment.common.iml +++ b/plugins/kotlin/compiler-plugins/assignment/common-k1/kotlin.compiler-plugins.assignment.common-k1.iml @@ -3,6 +3,7 @@ + @@ -19,5 +20,9 @@ + + + + \ No newline at end of file diff --git a/plugins/kotlin/compiler-plugins/assignment/common-k1/resources/kotlin.compiler-plugins.assignment.common-k1.xml b/plugins/kotlin/compiler-plugins/assignment/common-k1/resources/kotlin.compiler-plugins.assignment.common-k1.xml new file mode 100644 index 000000000000..859881a3fd89 --- /dev/null +++ b/plugins/kotlin/compiler-plugins/assignment/common-k1/resources/kotlin.compiler-plugins.assignment.common-k1.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/plugins/kotlin/compiler-plugins/assignment/common/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/AssignmentAnnotationNamesCache.kt b/plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/AssignmentAnnotationNamesCache.kt similarity index 97% rename from plugins/kotlin/compiler-plugins/assignment/common/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/AssignmentAnnotationNamesCache.kt rename to plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/AssignmentAnnotationNamesCache.kt index 540ac7321146..3f1f198b75c3 100644 --- a/plugins/kotlin/compiler-plugins/assignment/common/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/AssignmentAnnotationNamesCache.kt +++ b/plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/AssignmentAnnotationNamesCache.kt @@ -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 diff --git a/plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/AssignmentPluginImportFix.kt b/plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/AssignmentPluginImportFix.kt new file mode 100644 index 000000000000..f2d37eb7dd6f --- /dev/null +++ b/plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/AssignmentPluginImportFix.kt @@ -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 + get() = listOf(OperatorConventions.ASSIGN_METHOD) +} \ No newline at end of file diff --git a/plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/AssignmentPluginQuickFixContributor.kt b/plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/AssignmentPluginQuickFixContributor.kt new file mode 100644 index 000000000000..412d2ad8da85 --- /dev/null +++ b/plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/AssignmentPluginQuickFixContributor.kt @@ -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) + } +} \ No newline at end of file diff --git a/plugins/kotlin/compiler-plugins/assignment/common/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/IdeAssignPluginResolutionAltererExtension.kt b/plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/IdeAssignPluginResolutionAltererExtension.kt similarity index 82% rename from plugins/kotlin/compiler-plugins/assignment/common/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/IdeAssignPluginResolutionAltererExtension.kt rename to plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/IdeAssignPluginResolutionAltererExtension.kt index a12a22561058..326061e9a5af 100644 --- a/plugins/kotlin/compiler-plugins/assignment/common/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/IdeAssignPluginResolutionAltererExtension.kt +++ b/plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/IdeAssignPluginResolutionAltererExtension.kt @@ -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 diff --git a/plugins/kotlin/compiler-plugins/assignment/common/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/IdeAssignmentContainerContributor.kt b/plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/IdeAssignmentContainerContributor.kt similarity index 93% rename from plugins/kotlin/compiler-plugins/assignment/common/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/IdeAssignmentContainerContributor.kt rename to plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/IdeAssignmentContainerContributor.kt index a3c6b84d604c..b5c4a7876ff9 100644 --- a/plugins/kotlin/compiler-plugins/assignment/common/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/IdeAssignmentContainerContributor.kt +++ b/plugins/kotlin/compiler-plugins/assignment/common-k1/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/k1/IdeAssignmentContainerContributor.kt @@ -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 diff --git a/plugins/kotlin/compiler-plugins/assignment/common/kotlin.compiler-plugins.assignment.common-k2.iml b/plugins/kotlin/compiler-plugins/assignment/common/kotlin.compiler-plugins.assignment.common-k2.iml new file mode 100644 index 000000000000..11894572de5e --- /dev/null +++ b/plugins/kotlin/compiler-plugins/assignment/common/kotlin.compiler-plugins.assignment.common-k2.iml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/kotlin/compiler-plugins/assignment/common/resources/kotlin.compiler-plugins.assignment.common-k2.xml b/plugins/kotlin/compiler-plugins/assignment/common/resources/kotlin.compiler-plugins.assignment.common-k2.xml new file mode 100644 index 000000000000..017516b7a346 --- /dev/null +++ b/plugins/kotlin/compiler-plugins/assignment/common/resources/kotlin.compiler-plugins.assignment.common-k2.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/plugins/kotlin/compiler-plugins/assignment/common/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/FirAssignmentPluginQuickFixRegistrar.kt b/plugins/kotlin/compiler-plugins/assignment/common/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/FirAssignmentPluginQuickFixRegistrar.kt new file mode 100644 index 000000000000..ce2675ecf6ed --- /dev/null +++ b/plugins/kotlin/compiler-plugins/assignment/common/src/org/jetbrains/kotlin/idea/compilerPlugin/assignment/FirAssignmentPluginQuickFixRegistrar.kt @@ -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) \ No newline at end of file diff --git a/plugins/kotlin/compiler-plugins/assignment/gradle/resources/kotlin.compiler-plugins.assignment.gradle.xml b/plugins/kotlin/compiler-plugins/assignment/gradle/resources/kotlin.compiler-plugins.assignment.gradle.xml index 12180cd4c7ee..c33af57bb93b 100644 --- a/plugins/kotlin/compiler-plugins/assignment/gradle/resources/kotlin.compiler-plugins.assignment.gradle.xml +++ b/plugins/kotlin/compiler-plugins/assignment/gradle/resources/kotlin.compiler-plugins.assignment.gradle.xml @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/fir/extensions/KtCompilerPluginsProviderIdeImpl.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/fir/extensions/KtCompilerPluginsProviderIdeImpl.kt index 0d8b7293639e..800c14daab29 100644 --- a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/fir/extensions/KtCompilerPluginsProviderIdeImpl.kt +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/fir/extensions/KtCompilerPluginsProviderIdeImpl.kt @@ -34,6 +34,9 @@ import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor +import org.jetbrains.kotlin.fir.extensions.FirAssignExpressionAltererExtension +import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar +import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter import org.jetbrains.kotlin.idea.base.projectStructure.ideaModule import org.jetbrains.kotlin.idea.base.projectStructure.moduleInfo import org.jetbrains.kotlin.idea.base.projectStructure.moduleInfo.ModuleTestSourceInfo @@ -129,6 +132,17 @@ internal class KtCompilerPluginsProviderIdeImpl(private val project: Project) : return registrars as List } + override fun isPluginOfTypeRegistered(module: KtSourceModule, pluginType: CompilerPluginType): Boolean { + val extension = when (pluginType) { + CompilerPluginType.ASSIGNMENT -> FirAssignExpressionAltererExtension::class + else -> return false + } + + return getRegisteredExtensions(module, FirExtensionRegistrarAdapter) + .map { (it as FirExtensionRegistrar).configure() } + .any { it.extensions[extension]?.isNotEmpty() == true } + } + @OptIn(Frontend10ApiUsage::class) private fun computeExtensionStorage(module: KtSourceModule): CompilerPluginRegistrar.ExtensionStorage? { val classLoader = pluginsCache?.pluginsClassLoader ?: return null diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt index 8df57ef28f9f..d7735871f144 100644 --- a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/ImportQuickFix.kt @@ -37,7 +37,7 @@ import org.jetbrains.kotlin.psi.KtPsiUtil.isSelectorInQualified import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.unwrapNullability -internal class ImportQuickFix( +class ImportQuickFix( element: KtElement, private val importCandidates: List ) : QuickFixActionBase(element), HintAction { @@ -162,7 +162,7 @@ internal class ImportQuickFix( } } - internal companion object { + companion object { val FACTORY = diagnosticFixFactory(KtFirDiagnostic.UnresolvedReference::class) { diagnostic -> val element = diagnostic.psi @@ -171,21 +171,22 @@ internal class ImportQuickFix( val quickFix = when (element) { is KtTypeReference -> createImportTypeFix(indexProvider, element) - is KtNameReferenceExpression -> createImportNameFix(indexProvider, element) + is KtNameReferenceExpression -> { + if (isSelectorInQualified(element)) null + else createImportNameFix(indexProvider, element, element.getReferencedNameAsName()) + } else -> null } listOfNotNull(quickFix) } - private fun KtAnalysisSession.createImportNameFix( + fun KtAnalysisSession.createImportNameFix( indexProvider: KtSymbolFromIndexProvider, - element: KtNameReferenceExpression + element: KtReferenceExpression, + unresolvedName: Name ): ImportQuickFix? { - if (isSelectorInQualified(element)) return null - val firFile = element.containingKtFile.getFileSymbol() - val unresolvedName = element.getReferencedNameAsName() val isVisible: (KtSymbol) -> Boolean = { it !is KtSymbolWithVisibility || isVisible(it, firFile, null, element) } diff --git a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixMultiFileTestGenerated.java b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixMultiFileTestGenerated.java index 6897b633de6d..e074dee6c703 100644 --- a/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixMultiFileTestGenerated.java +++ b/plugins/kotlin/fir/test/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixMultiFileTestGenerated.java @@ -31,6 +31,11 @@ public abstract class HighLevelQuickFixMultiFileTestGenerated extends AbstractHi runTest("../idea/tests/testData/quickfix/autoImports/invisible/annotation.before.Main.kt"); } + @TestMetadata("assignmentOperator.before.Main.kt") + public void testAssignmentOperator() throws Exception { + runTest("../idea/tests/testData/quickfix/autoImports/invisible/assignmentOperator.before.Main.kt"); + } + @TestMetadata("class.before.Main.kt") public void testClass() throws Exception { runTest("../idea/tests/testData/quickfix/autoImports/invisible/class.before.Main.kt"); diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt index 960607745bc5..3914b3fa5aee 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt @@ -16,6 +16,7 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer +import com.intellij.openapi.util.IntellijInternalApi import com.intellij.packageDependencies.DependencyValidationManager import com.intellij.psi.PsiElement import com.intellij.psi.PsiErrorElement @@ -85,7 +86,8 @@ import java.util.* /** * Check possibility and perform fix for unresolved references. */ -internal abstract class ImportFixBase protected constructor( +@IntellijInternalApi +abstract class ImportFixBase protected constructor( expression: T, private val expressionToAnalyzePointer: SmartPsiElementPointer?, factory: Factory @@ -376,7 +378,8 @@ internal abstract class ImportFixBase protected constructor( abstract class FactoryWithUnresolvedReferenceQuickFix: Factory(), UnresolvedReferenceQuickFixFactory } -internal abstract class OrdinaryImportFixBase(expression: T, factory: Factory) : ImportFixBase(expression, factory) { +@IntellijInternalApi +abstract class OrdinaryImportFixBase(expression: T, factory: Factory) : ImportFixBase(expression, factory) { override fun fillCandidates( name: String, callTypeAndReceiver: CallTypeAndReceiver<*, *>, @@ -462,7 +465,8 @@ internal abstract class OrdinaryImportFixBase(expression: T, f } // This is required to be abstract to reduce bunch file size -internal abstract class AbstractImportFix(expression: KtSimpleNameExpression, factory: Factory) : +@IntellijInternalApi +abstract class AbstractImportFix(expression: KtSimpleNameExpression, factory: Factory) : OrdinaryImportFixBase(expression, factory) { override fun getCallTypeAndReceiver() = element?.let { CallTypeAndReceiver.detect(it) } diff --git a/plugins/kotlin/idea/tests/kotlin.idea.tests.iml b/plugins/kotlin/idea/tests/kotlin.idea.tests.iml index f1c2d8539389..12a2fc483e24 100644 --- a/plugins/kotlin/idea/tests/kotlin.idea.tests.iml +++ b/plugins/kotlin/idea/tests/kotlin.idea.tests.iml @@ -56,7 +56,7 @@ - + diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index 688eff41334f..18433ae6254c 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -121,6 +121,11 @@ public abstract class QuickFixMultiFileTestGenerated extends AbstractQuickFixMul runTest("testData/quickfix/autoImports/invisible/annotation.before.Main.kt"); } + @TestMetadata("assignmentOperator.before.Main.kt") + public void testAssignmentOperator() throws Exception { + runTest("testData/quickfix/autoImports/invisible/assignmentOperator.before.Main.kt"); + } + @TestMetadata("class.before.Main.kt") public void testClass() throws Exception { runTest("testData/quickfix/autoImports/invisible/class.before.Main.kt"); diff --git a/plugins/kotlin/idea/tests/testData/inspections/unusedImport/assignmentOperator.Dependency.kt b/plugins/kotlin/idea/tests/testData/inspections/unusedImport/assignmentOperator.Dependency.kt new file mode 100644 index 000000000000..2bf392740948 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspections/unusedImport/assignmentOperator.Dependency.kt @@ -0,0 +1,12 @@ +package test.assignment + +@SupportsKotlinAssignmentOverloading +interface Property { + set(value: T) +} + +fun Property.assign(value: T?) + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.CLASS) +annotation class SupportsKotlinAssignmentOverloading \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/inspections/unusedImport/assignmentOperator.kt b/plugins/kotlin/idea/tests/testData/inspections/unusedImport/assignmentOperator.kt new file mode 100644 index 000000000000..9795d0a2d709 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/inspections/unusedImport/assignmentOperator.kt @@ -0,0 +1,12 @@ +import test.assignment.Property +import test.assignment.assign + +class MyPlugin(val myExtension: MyExtension) { + fun test() { + myExtension.property = "hello" + } +} + +interface MyExtension { + val property: Property +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/inspections/unusedImport/inspectionData/inspections.test b/plugins/kotlin/idea/tests/testData/inspections/unusedImport/inspectionData/inspections.test index 06b8a58c057d..e713c1f414ea 100644 --- a/plugins/kotlin/idea/tests/testData/inspections/unusedImport/inspectionData/inspections.test +++ b/plugins/kotlin/idea/tests/testData/inspections/unusedImport/inspectionData/inspections.test @@ -1,2 +1,3 @@ // INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.KotlinUnusedImportInspection -// RUNTIME_WITH_FULL_JDK \ No newline at end of file +// RUNTIME_WITH_FULL_JDK +// COMPILER_PLUGIN_OPTIONS: plugin:org.jetbrains.kotlin.assignment:annotation=test.assignment.SupportsKotlinAssignmentOverloading \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/invisible/assignmentOperator.after.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/invisible/assignmentOperator.after.kt new file mode 100644 index 000000000000..4f3f8fb1689c --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/invisible/assignmentOperator.after.kt @@ -0,0 +1,19 @@ +// "Import extension function 'Property.assign'" "true" +// ERROR: No applicable 'assign' function found for '=' overload +// ERROR: Type mismatch: inferred type is String but Property was expected +// ERROR: Val cannot be reassigned +// COMPILER_PLUGIN_OPTIONS: plugin:org.jetbrains.kotlin.assignment:annotation=test.assignment.SupportsKotlinAssignmentOverloading +/* IGNORE_FIR */ + +import test.assignment.Property +import test.assignment.assign + +class MyPlugin(val myExtension: MyExtension) { + fun test() { + myExtension.property = "hello" + } +} + +interface MyExtension { + val property: Property +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/invisible/assignmentOperator.before.Dependency.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/invisible/assignmentOperator.before.Dependency.kt new file mode 100644 index 000000000000..2bf392740948 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/invisible/assignmentOperator.before.Dependency.kt @@ -0,0 +1,12 @@ +package test.assignment + +@SupportsKotlinAssignmentOverloading +interface Property { + set(value: T) +} + +fun Property.assign(value: T?) + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.CLASS) +annotation class SupportsKotlinAssignmentOverloading \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/autoImports/invisible/assignmentOperator.before.Main.kt b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/invisible/assignmentOperator.before.Main.kt new file mode 100644 index 000000000000..b120877d9655 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/quickfix/autoImports/invisible/assignmentOperator.before.Main.kt @@ -0,0 +1,18 @@ +// "Import extension function 'Property.assign'" "true" +// ERROR: No applicable 'assign' function found for '=' overload +// ERROR: Type mismatch: inferred type is String but Property was expected +// ERROR: Val cannot be reassigned +// COMPILER_PLUGIN_OPTIONS: plugin:org.jetbrains.kotlin.assignment:annotation=test.assignment.SupportsKotlinAssignmentOverloading +/* IGNORE_FIR */ + +import test.assignment.Property + +class MyPlugin(val myExtension: MyExtension) { + fun test() { + myExtension.property = "hello" + } +} + +interface MyExtension { + val property: Property +} \ No newline at end of file diff --git a/plugins/kotlin/intellij.kotlin.plugin.community.main.iml b/plugins/kotlin/intellij.kotlin.plugin.community.main.iml index 6bcbbdd0a800..2a1deef07da0 100644 --- a/plugins/kotlin/intellij.kotlin.plugin.community.main.iml +++ b/plugins/kotlin/intellij.kotlin.plugin.community.main.iml @@ -73,7 +73,7 @@ - + diff --git a/plugins/kotlin/jvm/resources/META-INF/jvm-common.xml b/plugins/kotlin/jvm/resources/META-INF/jvm-common.xml index 5e13bc032411..7d392286eb9a 100644 --- a/plugins/kotlin/jvm/resources/META-INF/jvm-common.xml +++ b/plugins/kotlin/jvm/resources/META-INF/jvm-common.xml @@ -113,9 +113,6 @@ - - - diff --git a/plugins/kotlin/maven/tests/kotlin.maven.tests.iml b/plugins/kotlin/maven/tests/kotlin.maven.tests.iml index 81f127c39433..a6dcd4cce7ed 100644 --- a/plugins/kotlin/maven/tests/kotlin.maven.tests.iml +++ b/plugins/kotlin/maven/tests/kotlin.maven.tests.iml @@ -40,7 +40,7 @@ - + diff --git a/plugins/kotlin/plugin/k1/kotlin.plugin.k1.iml b/plugins/kotlin/plugin/k1/kotlin.plugin.k1.iml index a2d0a0e84cd6..bc520b0264d9 100644 --- a/plugins/kotlin/plugin/k1/kotlin.plugin.k1.iml +++ b/plugins/kotlin/plugin/k1/kotlin.plugin.k1.iml @@ -63,7 +63,7 @@ - + diff --git a/plugins/kotlin/plugin/k1/resources/META-INF/k1.xml b/plugins/kotlin/plugin/k1/resources/META-INF/k1.xml index ce8735ca93ac..1ae659551ebb 100644 --- a/plugins/kotlin/plugin/k1/resources/META-INF/k1.xml +++ b/plugins/kotlin/plugin/k1/resources/META-INF/k1.xml @@ -83,6 +83,7 @@ + diff --git a/plugins/kotlin/plugin/k1/resources/META-INF/scripting-support.xml b/plugins/kotlin/plugin/k1/resources/META-INF/scripting-support.xml index 424e4b541421..6945c1bd6667 100644 --- a/plugins/kotlin/plugin/k1/resources/META-INF/scripting-support.xml +++ b/plugins/kotlin/plugin/k1/resources/META-INF/scripting-support.xml @@ -29,6 +29,10 @@ parentId="preferences.language.Kotlin"/> + + + diff --git a/plugins/kotlin/plugin/k2/kotlin.plugin.k2.iml b/plugins/kotlin/plugin/k2/kotlin.plugin.k2.iml index dd3915dc85a3..d2dc06ca352c 100644 --- a/plugins/kotlin/plugin/k2/kotlin.plugin.k2.iml +++ b/plugins/kotlin/plugin/k2/kotlin.plugin.k2.iml @@ -99,5 +99,8 @@ + + + \ No newline at end of file diff --git a/plugins/kotlin/plugin/k2/resources/META-INF/k2.xml b/plugins/kotlin/plugin/k2/resources/META-INF/k2.xml index 3a1bf2d0db2a..df0a51d69209 100644 --- a/plugins/kotlin/plugin/k2/resources/META-INF/k2.xml +++ b/plugins/kotlin/plugin/k2/resources/META-INF/k2.xml @@ -248,5 +248,6 @@ + diff --git a/plugins/kotlin/project-tests/project-tests-base/kotlin.project-tests.project-tests-base.iml b/plugins/kotlin/project-tests/project-tests-base/kotlin.project-tests.project-tests-base.iml index b3f5f0ba3e72..b63bfee9b54c 100644 --- a/plugins/kotlin/project-tests/project-tests-base/kotlin.project-tests.project-tests-base.iml +++ b/plugins/kotlin/project-tests/project-tests-base/kotlin.project-tests.project-tests-base.iml @@ -34,7 +34,6 @@ - diff --git a/plugins/kotlin/project-tests/project-tests-fe10/kotlin.project-tests.project-tests-fe10.iml b/plugins/kotlin/project-tests/project-tests-fe10/kotlin.project-tests.project-tests-fe10.iml index e99cccc67176..d7c44d163896 100644 --- a/plugins/kotlin/project-tests/project-tests-fe10/kotlin.project-tests.project-tests-fe10.iml +++ b/plugins/kotlin/project-tests/project-tests-fe10/kotlin.project-tests.project-tests-fe10.iml @@ -39,7 +39,7 @@ - + \ No newline at end of file diff --git a/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/KotlinLightCodeInsightFixtureTestCase.kt b/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/KotlinLightCodeInsightFixtureTestCase.kt index 4d5a167fa22d..cd1c716cf71c 100644 --- a/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/KotlinLightCodeInsightFixtureTestCase.kt +++ b/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/KotlinLightCodeInsightFixtureTestCase.kt @@ -62,6 +62,7 @@ import org.jetbrains.kotlin.idea.formatter.KotlinStyleGuideCodeStyle import org.jetbrains.kotlin.idea.inspections.UnusedSymbolInspection import org.jetbrains.kotlin.idea.test.CompilerTestDirectives.API_VERSION_DIRECTIVE import org.jetbrains.kotlin.idea.test.CompilerTestDirectives.COMPILER_ARGUMENTS_DIRECTIVE +import org.jetbrains.kotlin.idea.test.CompilerTestDirectives.COMPILER_PLUGIN_OPTIONS import org.jetbrains.kotlin.idea.test.CompilerTestDirectives.JVM_TARGET_DIRECTIVE import org.jetbrains.kotlin.idea.test.CompilerTestDirectives.KOTLIN_COMPILER_VERSION_DIRECTIVE import org.jetbrains.kotlin.idea.test.CompilerTestDirectives.LANGUAGE_VERSION_DIRECTIVE @@ -350,6 +351,8 @@ object CompilerTestDirectives { const val API_VERSION_DIRECTIVE = "API_VERSION:" const val JVM_TARGET_DIRECTIVE = "JVM_TARGET:" const val COMPILER_ARGUMENTS_DIRECTIVE = "COMPILER_ARGUMENTS:" + const val COMPILER_PLUGIN_OPTIONS = "COMPILER_PLUGIN_OPTIONS:" + val ALL_COMPILER_TEST_DIRECTIVES = listOf( LANGUAGE_VERSION_DIRECTIVE, @@ -386,6 +389,11 @@ private fun configureCompilerOptions(fileText: String, project: Project, module: val apiVersion = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// $API_VERSION_DIRECTIVE ") ?.let { ApiVersion.parse(it) } + InTextDirectivesUtils.findStringWithPrefixes(fileText, "// $COMPILER_PLUGIN_OPTIONS ") + ?.split("\\s+,\\s+")?.toTypedArray()?.let { + KotlinCommonCompilerArgumentsHolder.getInstance(project).update { this.pluginOptions = it } + } + if (compilerVersion != null || languageVersion != null || apiVersion != null || jvmTarget != null || options != null || projectLanguageVersion != null ) {