From 03a697a7072e4904a8ccbfa5cf1ffe80b9bf485e Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 19 Jan 2017 13:51:15 +0300 Subject: [PATCH] Prohibit renaming operator to another operator on import. --- .../jetbrains/kotlin/diagnostics/Errors.java | 2 ++ .../rendering/DefaultErrorMessages.java | 1 + .../kotlin/resolve/lazy/LazyImportScope.kt | 21 +++++++++++++++---- .../tests/imports/OperatorRenameOnImport.kt | 16 ++++++++++++++ .../tests/imports/OperatorRenameOnImport.txt | 15 +++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 6 ++++++ 6 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/imports/OperatorRenameOnImport.kt create mode 100644 compiler/testData/diagnostics/tests/imports/OperatorRenameOnImport.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index d2b53cac075..08b9f477d45 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -179,6 +179,8 @@ public interface Errors { DiagnosticFactory1 CONFLICTING_IMPORT = DiagnosticFactory1.create(ERROR, PositioningStrategies.IMPORT_ALIAS); + DiagnosticFactory0 OPERATOR_RENAMED_ON_IMPORT = DiagnosticFactory0.create(ERROR); + // Modifiers DiagnosticFactory2 INCOMPATIBLE_MODIFIERS = DiagnosticFactory2.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 17c3a810311..13fcad38d5f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -190,6 +190,7 @@ public class DefaultErrorMessages { MAP.put(CANNOT_BE_IMPORTED, "Cannot import ''{0}'', functions and properties can be imported only from packages or objects", TO_STRING); MAP.put(PACKAGE_CANNOT_BE_IMPORTED, "Packages cannot be imported"); MAP.put(CONFLICTING_IMPORT, "Conflicting import, imported name ''{0}'' is ambiguous", STRING); + MAP.put(OPERATOR_RENAMED_ON_IMPORT, "Operator renamed to a different operator on import"); MAP.put(PLATFORM_CLASS_MAPPED_TO_KOTLIN, "This class shouldn''t be used in Kotlin. Use {0} instead.", CLASSES_OR_SEPARATED); MAP.put(CANNOT_INFER_PARAMETER_TYPE, "Cannot infer a type for this parameter. Please specify it explicitly."); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt index 312254555f9..5a393e587c3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt @@ -29,13 +29,12 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap import org.jetbrains.kotlin.psi.KtImportDirective import org.jetbrains.kotlin.psi.KtPsiUtil -import org.jetbrains.kotlin.resolve.BindingTrace -import org.jetbrains.kotlin.resolve.PlatformClassesMappedToKotlinChecker -import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver -import org.jetbrains.kotlin.resolve.isHiddenInResolution +import org.jetbrains.kotlin.psi.KtReferenceExpression +import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.ImportingScope import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.util.collectionUtils.concat import org.jetbrains.kotlin.utils.Printer import java.util.* @@ -110,6 +109,8 @@ class LazyImportResolver( explicitClassImports.put(alias, importDirective) } } + + checkResolvedImportDirective(importDirective) } for ((alias, import) in explicitClassImports.entries()) { if (alias.all { it == '_' }) { @@ -126,6 +127,18 @@ class LazyImportResolver( } } + private fun checkResolvedImportDirective(importDirective: KtImportDirective) { + val importedReference = KtPsiUtil.getLastReference(importDirective.importedReference ?: return) ?: return + val importedDescriptor = traceForImportResolve.bindingContext.get(BindingContext.REFERENCE_TARGET, importedReference) ?: return + + val aliasName = importDirective.aliasName + + if (importedDescriptor is FunctionDescriptor && importedDescriptor.isOperator && + aliasName != null && OperatorConventions.isConventionName(Name.identifier(aliasName))) { + traceForImportResolve.report(Errors.OPERATOR_RENAMED_ON_IMPORT.on(importedReference)) + } + } + override fun forceResolveImport(importDirective: KtImportDirective) { getImportScope(importDirective) } diff --git a/compiler/testData/diagnostics/tests/imports/OperatorRenameOnImport.kt b/compiler/testData/diagnostics/tests/imports/OperatorRenameOnImport.kt new file mode 100644 index 00000000000..2eb9e432679 --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/OperatorRenameOnImport.kt @@ -0,0 +1,16 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// FILE: a.kt +package a + +interface A + +operator fun A.plus(other: A): A = this + +// FILE: b.kt +package b + +import a.A +import a.plus as minus + +fun test(a1: A, a2: A) = + a1 - a2 \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/imports/OperatorRenameOnImport.txt b/compiler/testData/diagnostics/tests/imports/OperatorRenameOnImport.txt new file mode 100644 index 00000000000..fe195fc73a6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/OperatorRenameOnImport.txt @@ -0,0 +1,15 @@ +package + +package a { + public operator fun a.A.plus(/*0*/ other: a.A): a.A + + public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +package b { + public fun test(/*0*/ a1: a.A, /*1*/ a2: a.A): a.A +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index dca35bac279..75929d674e7 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -9589,6 +9589,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("OperatorRenameOnImport.kt") + public void testOperatorRenameOnImport() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/imports/OperatorRenameOnImport.kt"); + doTest(fileName); + } + @TestMetadata("PackageLocalClassNotImported.kt") public void testPackageLocalClassNotImported() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/imports/PackageLocalClassNotImported.kt");