diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/OperatorValidator.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/OperatorValidator.kt index 0fdc2cbed1c..fa5691256fe 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/OperatorValidator.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/OperatorValidator.kt @@ -29,6 +29,11 @@ import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.util.OperatorNameConventions +import org.jetbrains.kotlin.util.OperatorNameConventions.PLUS +import org.jetbrains.kotlin.util.OperatorNameConventions.MINUS +import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_PLUS +import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_MINUS public class OperatorValidator : SymbolUsageValidator { @@ -61,10 +66,24 @@ public class OperatorValidator : SymbolUsageValidator { return } - if (isConventionOperator() || isArrayAccessExpression()) { + val isConventionOperator = isConventionOperator() + if (isConventionOperator || isArrayAccessExpression()) { if (!functionDescriptor.isOperator) { report(jetElement, functionDescriptor, trace) } + if (isConventionOperator && call != null) { + checkDeprecatedUnaryConventions(call, functionDescriptor, trace) + } + } + } + + private fun checkDeprecatedUnaryConventions(call: Call, functionDescriptor: FunctionDescriptor, sink: DiagnosticSink) { + (call.callElement as? JetPrefixExpression)?.let { expr -> + val functionName = functionDescriptor.name + if (functionName == PLUS || functionName == MINUS) { + val newName = if (functionName == PLUS) UNARY_PLUS else UNARY_MINUS + sink.report(Errors.DEPRECATED_UNARY_PLUS_MINUS.on(expr, functionDescriptor, newName.asString())) + } } } diff --git a/compiler/testData/diagnostics/tests/Builders.kt b/compiler/testData/diagnostics/tests/Builders.kt index 414ae97fe3a..d60d1ebe417 100644 --- a/compiler/testData/diagnostics/tests/Builders.kt +++ b/compiler/testData/diagnostics/tests/Builders.kt @@ -93,7 +93,7 @@ abstract class Tag(val name : String) : Element() { } abstract class TagWithText(name : String) : Tag(name) { - operator fun String.plus() { + operator fun String.unaryPlus() { children.add(TextElement(this)) } } diff --git a/compiler/testData/diagnostics/tests/Builders.txt b/compiler/testData/diagnostics/tests/Builders.txt index a25fe43ffce..1717a2ad6ea 100644 --- a/compiler/testData/diagnostics/tests/Builders.txt +++ b/compiler/testData/diagnostics/tests/Builders.txt @@ -24,7 +24,7 @@ package html { invisible_fake final override /*1*/ /*fake_override*/ fun renderAttributes(): kotlin.String? public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public final override /*1*/ /*fake_override*/ fun ul(/*0*/ init: html.UL.() -> kotlin.Unit): html.UL - public final override /*1*/ /*fake_override*/ fun kotlin.String.plus(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun kotlin.String.unaryPlus(): kotlin.Unit } public final class B : html.BodyTag { @@ -43,7 +43,7 @@ package html { invisible_fake final override /*1*/ /*fake_override*/ fun renderAttributes(): kotlin.String? public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public final override /*1*/ /*fake_override*/ fun ul(/*0*/ init: html.UL.() -> kotlin.Unit): html.UL - public final override /*1*/ /*fake_override*/ fun kotlin.String.plus(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun kotlin.String.unaryPlus(): kotlin.Unit } public final class Body : html.BodyTag { @@ -62,7 +62,7 @@ package html { invisible_fake final override /*1*/ /*fake_override*/ fun renderAttributes(): kotlin.String? public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public final override /*1*/ /*fake_override*/ fun ul(/*0*/ init: html.UL.() -> kotlin.Unit): html.UL - public final override /*1*/ /*fake_override*/ fun kotlin.String.plus(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun kotlin.String.unaryPlus(): kotlin.Unit } public abstract class BodyTag : html.TagWithText { @@ -81,7 +81,7 @@ package html { invisible_fake final override /*1*/ /*fake_override*/ fun renderAttributes(): kotlin.String? public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public final fun ul(/*0*/ init: html.UL.() -> kotlin.Unit): html.UL - public final override /*1*/ /*fake_override*/ fun kotlin.String.plus(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun kotlin.String.unaryPlus(): kotlin.Unit } public abstract class Element { @@ -108,7 +108,7 @@ package html { invisible_fake final override /*1*/ /*fake_override*/ fun renderAttributes(): kotlin.String? public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public final override /*1*/ /*fake_override*/ fun ul(/*0*/ init: html.UL.() -> kotlin.Unit): html.UL - public final override /*1*/ /*fake_override*/ fun kotlin.String.plus(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun kotlin.String.unaryPlus(): kotlin.Unit } public final class HTML : html.TagWithText { @@ -124,7 +124,7 @@ package html { public open override /*1*/ /*fake_override*/ fun render(/*0*/ builder: java.lang.StringBuilder, /*1*/ indent: kotlin.String): kotlin.Unit invisible_fake final override /*1*/ /*fake_override*/ fun renderAttributes(): kotlin.String? public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String - public final override /*1*/ /*fake_override*/ fun kotlin.String.plus(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun kotlin.String.unaryPlus(): kotlin.Unit } public final class Head : html.TagWithText { @@ -139,7 +139,7 @@ package html { invisible_fake final override /*1*/ /*fake_override*/ fun renderAttributes(): kotlin.String? public final fun title(/*0*/ init: html.Title.() -> kotlin.Unit): html.Title public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String - public final override /*1*/ /*fake_override*/ fun kotlin.String.plus(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun kotlin.String.unaryPlus(): kotlin.Unit } public final class LI : html.BodyTag { @@ -158,7 +158,7 @@ package html { invisible_fake final override /*1*/ /*fake_override*/ fun renderAttributes(): kotlin.String? public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public final override /*1*/ /*fake_override*/ fun ul(/*0*/ init: html.UL.() -> kotlin.Unit): html.UL - public final override /*1*/ /*fake_override*/ fun kotlin.String.plus(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun kotlin.String.unaryPlus(): kotlin.Unit } public final class P : html.BodyTag { @@ -177,7 +177,7 @@ package html { invisible_fake final override /*1*/ /*fake_override*/ fun renderAttributes(): kotlin.String? public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public final override /*1*/ /*fake_override*/ fun ul(/*0*/ init: html.UL.() -> kotlin.Unit): html.UL - public final override /*1*/ /*fake_override*/ fun kotlin.String.plus(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun kotlin.String.unaryPlus(): kotlin.Unit } public abstract class Tag : html.Element { @@ -204,7 +204,7 @@ package html { public open override /*1*/ /*fake_override*/ fun render(/*0*/ builder: java.lang.StringBuilder, /*1*/ indent: kotlin.String): kotlin.Unit invisible_fake final override /*1*/ /*fake_override*/ fun renderAttributes(): kotlin.String? public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String - public final operator fun kotlin.String.plus(): kotlin.Unit + public final operator fun kotlin.String.unaryPlus(): kotlin.Unit } public final class TextElement : html.Element { @@ -227,7 +227,7 @@ package html { public open override /*1*/ /*fake_override*/ fun render(/*0*/ builder: java.lang.StringBuilder, /*1*/ indent: kotlin.String): kotlin.Unit invisible_fake final override /*1*/ /*fake_override*/ fun renderAttributes(): kotlin.String? public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String - public final override /*1*/ /*fake_override*/ fun kotlin.String.plus(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun kotlin.String.unaryPlus(): kotlin.Unit } public final class UL : html.BodyTag { @@ -247,6 +247,6 @@ package html { invisible_fake final override /*1*/ /*fake_override*/ fun renderAttributes(): kotlin.String? public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public final override /*1*/ /*fake_override*/ fun ul(/*0*/ init: html.UL.() -> kotlin.Unit): html.UL - public final override /*1*/ /*fake_override*/ fun kotlin.String.plus(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun kotlin.String.unaryPlus(): kotlin.Unit } } diff --git a/compiler/testData/diagnostics/tests/DeprecatedUnaryOperatorConventions.kt b/compiler/testData/diagnostics/tests/DeprecatedUnaryOperatorConventions.kt index b4bcafdd384..a3dba473a4a 100644 --- a/compiler/testData/diagnostics/tests/DeprecatedUnaryOperatorConventions.kt +++ b/compiler/testData/diagnostics/tests/DeprecatedUnaryOperatorConventions.kt @@ -15,8 +15,18 @@ operator fun String.unaryPlus(): Int = 0 fun test() { requireInt(+ "") requireInt(+ Example()) - requireString(+ ExampleDeprecated()) + requireString(+ ExampleDeprecated()) } fun requireInt(n: Int) {} -fun requireString(s: String) {} \ No newline at end of file +fun requireString(s: String) {} + +class Example2 { + operator fun plus() = this + operator fun minus() = this + + fun test() { + +this + -this + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/DeprecatedUnaryOperatorConventions.txt b/compiler/testData/diagnostics/tests/DeprecatedUnaryOperatorConventions.txt index bd8caa42d0f..8cc5ee1815f 100644 --- a/compiler/testData/diagnostics/tests/DeprecatedUnaryOperatorConventions.txt +++ b/compiler/testData/diagnostics/tests/DeprecatedUnaryOperatorConventions.txt @@ -15,6 +15,16 @@ public final class Example { public final operator fun unaryPlus(): kotlin.Int } +public final class Example2 { + public constructor Example2() + 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 final operator fun minus(): Example2 + public final operator fun plus(): Example2 + public final fun test(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + public final class ExampleDeprecated { public constructor ExampleDeprecated() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.kt index 3b857bb9334..2111c5589be 100644 --- a/compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.kt +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.kt @@ -33,7 +33,7 @@ class MyProperty { } } -operator fun MyProperty.plus() = MyProperty() +operator fun MyProperty.unaryPlus() = MyProperty() operator fun MyProperty.minus(i: Int) = MyProperty() object O { diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.txt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.txt index 0b027fead42..ab01623fd46 100644 --- a/compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.txt +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.txt @@ -6,7 +6,7 @@ package baz { public fun getMyProperty(): baz.MyProperty public fun println(/*0*/ a: kotlin.Any?): kotlin.Any? public operator fun baz.MyProperty.minus(/*0*/ i: kotlin.Int): baz.MyProperty - public operator fun baz.MyProperty.plus(): baz.MyProperty + public operator fun baz.MyProperty.unaryPlus(): baz.MyProperty public final class A { public constructor A(/*0*/ outer: baz.Outer) diff --git a/compiler/testData/diagnostics/tests/inline/unaryExpressions/mathOperation.kt b/compiler/testData/diagnostics/tests/inline/unaryExpressions/mathOperation.kt index 9a16aa08d7e..c53f05d9a4d 100644 --- a/compiler/testData/diagnostics/tests/inline/unaryExpressions/mathOperation.kt +++ b/compiler/testData/diagnostics/tests/inline/unaryExpressions/mathOperation.kt @@ -1,12 +1,12 @@ // !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE -VAL_REASSIGNMENT -UNUSED_CHANGED_VALUE -VARIABLE_EXPECTED -inline operator fun Function1.plus() = this -operator fun Function1.minus() = this +inline operator fun Function1.unaryPlus() = this +operator fun Function1.unaryMinus() = this inline operator fun Function1.inc() = this operator fun Function1.dec() = this -inline operator fun @Extension Function2.plus(){} -operator fun @Extension Function2.minus(){} +inline operator fun @Extension Function2.unaryPlus(){} +operator fun @Extension Function2.unaryMinus(){} inline operator fun @Extension Function2.inc() = this operator fun @Extension Function2.dec() = this diff --git a/compiler/testData/diagnostics/tests/inline/unaryExpressions/mathOperation.txt b/compiler/testData/diagnostics/tests/inline/unaryExpressions/mathOperation.txt index 8da0ac01ea8..0b4f05ec6a3 100644 --- a/compiler/testData/diagnostics/tests/inline/unaryExpressions/mathOperation.txt +++ b/compiler/testData/diagnostics/tests/inline/unaryExpressions/mathOperation.txt @@ -6,7 +6,7 @@ public operator fun (T.(T) -> V).dec(): T.(T) -> V @kotlin.inline() public operator fun ((T) -> V).inc(): (T) -> V @kotlin.inline() public operator fun (T.(T) -> V).inc(): T.(T) -> V @kotlin.inline() public fun ((T) -> V).inlineFunWithInvoke(): kotlin.Unit -public operator fun ((T) -> V).minus(): (T) -> V -public operator fun (T.(T) -> V).minus(): kotlin.Unit -@kotlin.inline() public operator fun ((T) -> V).plus(): (T) -> V -@kotlin.inline() public operator fun (T.(T) -> V).plus(): kotlin.Unit +public operator fun ((T) -> V).unaryMinus(): (T) -> V +public operator fun (T.(T) -> V).unaryMinus(): kotlin.Unit +@kotlin.inline() public operator fun ((T) -> V).unaryPlus(): (T) -> V +@kotlin.inline() public operator fun (T.(T) -> V).unaryPlus(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/InfixCallNullability.kt b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/InfixCallNullability.kt index 5f537ad1c2c..0f4790f933a 100644 --- a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/InfixCallNullability.kt +++ b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/InfixCallNullability.kt @@ -1,6 +1,6 @@ class A() { operator infix fun plus(i : Int) {} - operator fun minus() {} + operator fun unaryMinus() {} operator infix fun contains(a : Any?) : Boolean = true } @@ -20,8 +20,8 @@ fun test(x : Int?, a : A?) { a plus 1 a + 1 -a - a.minus() - a?.minus() + a.unaryMinus() + a?.unaryMinus() a.div(1) a / 1 diff --git a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/InfixCallNullability.txt b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/InfixCallNullability.txt index 59fba32b8d3..7af18d04f45 100644 --- a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/InfixCallNullability.txt +++ b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/InfixCallNullability.txt @@ -9,7 +9,7 @@ public final class A { public final operator infix fun contains(/*0*/ a: kotlin.Any?): kotlin.Boolean 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 final operator fun minus(): kotlin.Unit public final operator infix fun plus(/*0*/ i: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + public final operator fun unaryMinus(): kotlin.Unit } diff --git a/compiler/testData/diagnostics/tests/operatorsOverloading/kt3450.kt b/compiler/testData/diagnostics/tests/operatorsOverloading/kt3450.kt index 1c7670478e3..3f5d1e27f07 100644 --- a/compiler/testData/diagnostics/tests/operatorsOverloading/kt3450.kt +++ b/compiler/testData/diagnostics/tests/operatorsOverloading/kt3450.kt @@ -3,7 +3,7 @@ public class A { public operator fun get(vararg attrs : Pair) : A = this } -operator fun String.plus() : A = A() +operator fun String.unaryPlus() : A = A() operator fun A.div(s : String) : A = A() fun test() { diff --git a/compiler/testData/diagnostics/tests/operatorsOverloading/kt3450.txt b/compiler/testData/diagnostics/tests/operatorsOverloading/kt3450.txt index dce1dc05ab7..a93713addd7 100644 --- a/compiler/testData/diagnostics/tests/operatorsOverloading/kt3450.txt +++ b/compiler/testData/diagnostics/tests/operatorsOverloading/kt3450.txt @@ -3,8 +3,8 @@ package public val x: B public fun test(): kotlin.Unit public operator fun A.div(/*0*/ s: kotlin.String): A -public operator fun kotlin.String.plus(): A public infix fun A.to(/*0*/ that: B): Pair +public operator fun kotlin.String.unaryPlus(): A public final class A { public constructor A() diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/staticCallsInDynamicContext.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/staticCallsInDynamicContext.kt index d2849500d72..53ff9b7b1b4 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/staticCallsInDynamicContext.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/staticCallsInDynamicContext.kt @@ -27,7 +27,7 @@ fun dynamic.test() { this() C() + C() - +C() + +C() this + C() diff --git a/idea/testData/checker/Builders.kt b/idea/testData/checker/Builders.kt index 92e46536007..85c29075c93 100644 --- a/idea/testData/checker/Builders.kt +++ b/idea/testData/checker/Builders.kt @@ -24,7 +24,7 @@ import java.util.* } abstract class TagWithText(name : String) : Tag(name) { - operator fun String.plus() { + operator fun String.unaryPlus() { children.add(TextElement(this)) } } diff --git a/idea/testData/highlighter/deprecated/Operation.kt b/idea/testData/highlighter/deprecated/Operation.kt index cf2dd29971c..9e853e32301 100644 --- a/idea/testData/highlighter/deprecated/Operation.kt +++ b/idea/testData/highlighter/deprecated/Operation.kt @@ -7,7 +7,7 @@ class MyClass { @Deprecated("Use A instead") operator fun MyClass.times(i: MyClass) { i.i } @Deprecated("Use A instead") operator fun MyClass.not() { } -@Deprecated("Use A instead") operator fun MyClass.plus() { } +@Deprecated("Use A instead") operator fun MyClass.unaryPlus() { } @Deprecated("Use A instead") operator fun MyClass.contains(i: MyClass): Boolean { i.i; return false } @@ -24,7 +24,7 @@ fun test() { x1 * x2 !x1 - +x1 + +x1 x1 in x2 x1 !in x2