diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OperatorModifierChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OperatorModifierChecker.kt new file mode 100644 index 00000000000..c36c7617231 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OperatorModifierChecker.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.lexer.JetTokens +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.JetDeclaration +import org.jetbrains.kotlin.types.expressions.OperatorConventions.* + +public class OperatorModifierChecker : DeclarationChecker { + + private companion object { + private val GET = Name.identifier("get") + private val SET = Name.identifier("set") + + private val COMPONENT_REGEX = "component\\d+".toRegex() + } + + override fun check( + declaration: JetDeclaration, + descriptor: DeclarationDescriptor, + diagnosticHolder: DiagnosticSink, + bindingContext: BindingContext + ) { + val functionDescriptor = descriptor as? FunctionDescriptor ?: return + if (!functionDescriptor.isOperator) return + val modifier = declaration.modifierList?.getModifier(JetTokens.OPERATOR_KEYWORD) ?: return + + val name = functionDescriptor.name + + when { + GET == name -> {} + SET == name -> {} + INVOKE == name -> {} + CONTAINS == name -> {} + ITERATOR == name -> {} + EQUALS == name -> {} + COMPARE_TO == name -> {} + UNARY_OPERATION_NAMES.any { it.value == name } && functionDescriptor.valueParameters.isEmpty() -> {} + BINARY_OPERATION_NAMES.any { it.value == name } && functionDescriptor.valueParameters.size() == 1 -> {} + ASSIGNMENT_OPERATIONS.any { it.value == name } -> {} + name.asString().matches(COMPONENT_REGEX) -> {} + else -> diagnosticHolder.report(Errors.INAPPLICABLE_OPERATOR_MODIFIER.on(modifier)) + } + } +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index 6d0dba644ad..a6ca4b84627 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -39,7 +39,7 @@ public abstract class TargetPlatform( } } -private val DEFAULT_DECLARATION_CHECKERS = listOf(DataClassAnnotationChecker(), ConstModifierChecker, UnderscoreChecker) +private val DEFAULT_DECLARATION_CHECKERS = listOf(DataClassAnnotationChecker(), ConstModifierChecker, UnderscoreChecker, OperatorModifierChecker()) private val DEFAULT_CALL_CHECKERS = listOf(CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker()) private val DEFAULT_TYPE_CHECKERS = emptyList() private val DEFAULT_VALIDATORS = listOf(DeprecatedSymbolValidator(), AccessToPrivateTopLevelSymbolValidator(), OperatorValidator()) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/OperatorConventions.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/OperatorConventions.java index 1883652cff7..a1634eb72b4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/OperatorConventions.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/OperatorConventions.java @@ -32,6 +32,7 @@ public class OperatorConventions { public static final Name COMPARE_TO = Name.identifier("compareTo"); public static final Name CONTAINS = Name.identifier("contains"); public static final Name INVOKE = Name.identifier("invoke"); + public static final Name ITERATOR = Name.identifier("iterator"); private OperatorConventions() {} diff --git a/compiler/testData/diagnostics/tests/OperatorsWithWrongNames.kt b/compiler/testData/diagnostics/tests/OperatorsWithWrongNames.kt new file mode 100644 index 00000000000..142d53068e8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/OperatorsWithWrongNames.kt @@ -0,0 +1,11 @@ +class A { + operator fun A.minus(o: A) = o + + operator fun A.add(o: A) = o + operator fun A.get(o: A) = o + operator fun A.invokee() {} +} + +operator fun A.plus(o: A) = o +operator fun A.component1() = 1 +operator fun A.componentN() = 1 \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/OperatorsWithWrongNames.txt b/compiler/testData/diagnostics/tests/OperatorsWithWrongNames.txt new file mode 100644 index 00000000000..4916d1dcc1a --- /dev/null +++ b/compiler/testData/diagnostics/tests/OperatorsWithWrongNames.txt @@ -0,0 +1,16 @@ +package + +public operator fun A.component1(): kotlin.Int +public operator fun A.componentN(): kotlin.Int +public operator fun A.plus(/*0*/ o: A): A + +public final class A { + public constructor 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 + public final operator fun A.add(/*0*/ o: A): A + public final operator fun A.get(/*0*/ o: A): A + public final operator fun A.invokee(): kotlin.Unit + public final operator fun A.minus(/*0*/ o: A): A +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 34ba52c792c..17e3925f304 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -343,6 +343,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("OperatorsWithWrongNames.kt") + public void testOperatorsWithWrongNames() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/OperatorsWithWrongNames.kt"); + doTest(fileName); + } + @TestMetadata("OverrideFunctionWithParamDefaultValue.kt") public void testOverrideFunctionWithParamDefaultValue() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/OverrideFunctionWithParamDefaultValue.kt");