Prohibit operator mod as declaration and calls that resolved via it
#KT-24197 Fixed
This commit is contained in:
@@ -747,7 +747,9 @@ public interface Errors {
|
||||
DiagnosticFactory2<KtBinaryExpression, KotlinType, KotlinType> FORBIDDEN_IDENTITY_EQUALS = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
DiagnosticFactory2<PsiElement, FunctionDescriptor, String> DEPRECATED_BINARY_MOD = DiagnosticFactory2.create(WARNING);
|
||||
DiagnosticFactory2<PsiElement, FunctionDescriptor, String> FORBIDDEN_BINARY_MOD = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory2<PsiElement, FunctionDescriptor, String> DEPRECATED_BINARY_MOD_AS_REM = DiagnosticFactory2.create(WARNING);
|
||||
DiagnosticFactory2<PsiElement, FunctionDescriptor, String> FORBIDDEN_BINARY_MOD_AS_REM = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<KtArrayAccessExpression> NO_GET_METHOD = DiagnosticFactory0.create(ERROR, ARRAY_ACCESS);
|
||||
DiagnosticFactory0<KtArrayAccessExpression> NO_SET_METHOD = DiagnosticFactory0.create(ERROR, ARRAY_ACCESS);
|
||||
|
||||
+2
@@ -396,7 +396,9 @@ public class DefaultErrorMessages {
|
||||
MAP.put(FORBIDDEN_IDENTITY_EQUALS, "Identity equality for arguments of types {0} and {1} is forbidden", RENDER_TYPE, RENDER_TYPE);
|
||||
|
||||
MAP.put(DEPRECATED_BINARY_MOD, "Deprecated convention for ''{0}''. Use ''{1}''", NAME, STRING);
|
||||
MAP.put(FORBIDDEN_BINARY_MOD, "Convention for ''{0}'' is forbidden. Use ''{1}''", NAME, STRING);
|
||||
MAP.put(DEPRECATED_BINARY_MOD_AS_REM, "''%'' is resolved to deprecated ''{0}'' operator. Replace with ''.{0}'' or add operator ''{1}''", NAME, STRING);
|
||||
MAP.put(FORBIDDEN_BINARY_MOD_AS_REM, "''%'' is resolved to forbidden ''{0}'' operator. Replace with ''.{0}'' or add operator ''{1}''", NAME, STRING);
|
||||
|
||||
MAP.put(NO_GET_METHOD, "No get method providing array access");
|
||||
MAP.put(NO_SET_METHOD, "No set method providing array access");
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
@@ -50,10 +51,18 @@ object OperatorModifierChecker {
|
||||
checkSupportsFeature(LanguageFeature.OperatorProvideDelegate, languageVersionSettings, diagnosticHolder, modifier)
|
||||
}
|
||||
|
||||
if (functionDescriptor.name in REM_TO_MOD_OPERATION_NAMES.values
|
||||
&& languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)) {
|
||||
if (functionDescriptor.name in REM_TO_MOD_OPERATION_NAMES.values &&
|
||||
languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)
|
||||
) {
|
||||
val diagnosticFactory = if (!KotlinBuiltIns.isUnderKotlinPackage(descriptor) &&
|
||||
languageVersionSettings.supportsFeature(LanguageFeature.ProhibitOperatorMod)
|
||||
)
|
||||
Errors.FORBIDDEN_BINARY_MOD
|
||||
else
|
||||
Errors.DEPRECATED_BINARY_MOD
|
||||
|
||||
val newNameConvention = REM_TO_MOD_OPERATION_NAMES.inverse()[functionDescriptor.name]
|
||||
diagnosticHolder.report(Errors.DEPRECATED_BINARY_MOD.on(modifier, functionDescriptor, newNameConvention!!.asString()))
|
||||
diagnosticHolder.report(diagnosticFactory.on(modifier, functionDescriptor, newNameConvention!!.asString()))
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
+14
-4
@@ -117,16 +117,26 @@ private fun checkModConvention(
|
||||
|
||||
if (KotlinBuiltIns.isUnderKotlinPackage(descriptor)) {
|
||||
if (shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings)) {
|
||||
addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier)
|
||||
warnAboutDeprecatedOrForbiddenMod(descriptor, diagnosticHolder, modifier, languageVersionSettings)
|
||||
}
|
||||
} else {
|
||||
if (languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)) {
|
||||
addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier)
|
||||
warnAboutDeprecatedOrForbiddenMod(descriptor, diagnosticHolder, modifier, languageVersionSettings)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addWarningAboutDeprecatedMod(descriptor: FunctionDescriptor, diagnosticHolder: DiagnosticSink, reportOn: PsiElement) {
|
||||
private fun warnAboutDeprecatedOrForbiddenMod(
|
||||
descriptor: FunctionDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
reportOn: PsiElement,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
val diagnosticFactory = if (languageVersionSettings.supportsFeature(LanguageFeature.ProhibitOperatorMod))
|
||||
Errors.FORBIDDEN_BINARY_MOD_AS_REM
|
||||
else
|
||||
Errors.DEPRECATED_BINARY_MOD_AS_REM
|
||||
|
||||
val newNameConvention = OperatorConventions.REM_TO_MOD_OPERATION_NAMES.inverse()[descriptor.name]
|
||||
diagnosticHolder.report(Errors.DEPRECATED_BINARY_MOD_AS_REM.on(reportOn, descriptor, newNameConvention!!.asString()))
|
||||
diagnosticHolder.report(diagnosticFactory.on(reportOn, descriptor, newNameConvention!!.asString()))
|
||||
}
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// !LANGUAGE: +ProhibitOperatorMod
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
object ModAndRem {
|
||||
<!FORBIDDEN_BINARY_MOD!>operator<!> fun mod(x: Int) {}
|
||||
operator fun rem(x: Int) {}
|
||||
|
||||
<!FORBIDDEN_BINARY_MOD!>operator<!> fun modAssign(x: Int) {}
|
||||
operator fun remAssign(x: Int) {}
|
||||
}
|
||||
|
||||
object JustMod {
|
||||
<!FORBIDDEN_BINARY_MOD!>operator<!> fun mod(x: Int) {}
|
||||
<!FORBIDDEN_BINARY_MOD!>operator<!> fun modAssign(x: Int) {}
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
ModAndRem % 1
|
||||
ModAndRem.mod(1)
|
||||
ModAndRem.rem(1)
|
||||
|
||||
JustMod <!FORBIDDEN_BINARY_MOD_AS_REM!>%<!> 1
|
||||
JustMod.mod(1)
|
||||
|
||||
val r = ModAndRem
|
||||
r %= 1
|
||||
r.remAssign(1)
|
||||
|
||||
val m = JustMod
|
||||
m <!FORBIDDEN_BINARY_MOD_AS_REM!>%=<!> 1
|
||||
m.modAssign(1)
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package
|
||||
|
||||
public fun foo(): kotlin.Unit
|
||||
|
||||
public object JustMod {
|
||||
private constructor JustMod()
|
||||
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 mod(/*0*/ x: kotlin.Int): kotlin.Unit
|
||||
public final operator fun modAssign(/*0*/ x: kotlin.Int): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public object ModAndRem {
|
||||
private constructor ModAndRem()
|
||||
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 mod(/*0*/ x: kotlin.Int): kotlin.Unit
|
||||
public final operator fun modAssign(/*0*/ x: kotlin.Int): kotlin.Unit
|
||||
public final operator fun rem(/*0*/ x: kotlin.Int): kotlin.Unit
|
||||
public final operator fun remAssign(/*0*/ x: kotlin.Int): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -13813,6 +13813,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
runTest("compiler/testData/diagnostics/tests/operatorRem/doNotResolveToInapplicableRem.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("forbiddenModOperatorConvention.kt")
|
||||
public void testForbiddenModOperatorConvention() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/operatorRem/forbiddenModOperatorConvention.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("modWithRemAssign.kt")
|
||||
public void testModWithRemAssign() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/operatorRem/modWithRemAssign.kt");
|
||||
|
||||
Generated
+5
@@ -13813,6 +13813,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
runTest("compiler/testData/diagnostics/tests/operatorRem/doNotResolveToInapplicableRem.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("forbiddenModOperatorConvention.kt")
|
||||
public void testForbiddenModOperatorConvention() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/operatorRem/forbiddenModOperatorConvention.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("modWithRemAssign.kt")
|
||||
public void testModWithRemAssign() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/operatorRem/modWithRemAssign.kt");
|
||||
|
||||
@@ -77,6 +77,7 @@ enum class LanguageFeature(
|
||||
AllowContractsForCustomFunctions(KOTLIN_1_3, kind = UNSTABLE_FEATURE),
|
||||
ProhibitLocalAnnotations(KOTLIN_1_3, kind = BUG_FIX),
|
||||
ProhibitSmartcastsOnLocalDelegatedProperty(KOTLIN_1_3, kind = BUG_FIX),
|
||||
ProhibitOperatorMod(KOTLIN_1_3, kind = BUG_FIX),
|
||||
|
||||
StrictJavaNullabilityAssertions(sinceVersion = null, defaultState = State.DISABLED),
|
||||
ProperIeee754Comparisons(sinceVersion = null, defaultState = State.DISABLED),
|
||||
|
||||
@@ -148,6 +148,8 @@ class QuickFixRegistrar : QuickFixContributor {
|
||||
TYPE_CANT_BE_USED_FOR_CONST_VAL.registerFactory(removeModifierFactory)
|
||||
DEPRECATED_BINARY_MOD.registerFactory(removeModifierFactory)
|
||||
DEPRECATED_BINARY_MOD.registerFactory(RenameModToRemFix.Factory)
|
||||
FORBIDDEN_BINARY_MOD.registerFactory(removeModifierFactory)
|
||||
FORBIDDEN_BINARY_MOD.registerFactory(RenameModToRemFix.Factory)
|
||||
|
||||
|
||||
UNRESOLVED_REFERENCE.registerFactory(ImportFix)
|
||||
|
||||
@@ -41,7 +41,7 @@ class RenameModToRemFix(element: KtNamedFunction, val newName: Name) : KotlinQui
|
||||
|
||||
companion object Factory : KotlinSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
if (diagnostic.factory != Errors.DEPRECATED_BINARY_MOD) return null
|
||||
if (diagnostic.factory != Errors.DEPRECATED_BINARY_MOD && diagnostic.factory != Errors.FORBIDDEN_BINARY_MOD) return null
|
||||
|
||||
val operatorMod = diagnostic.psiElement.getNonStrictParentOfType<KtNamedFunction>() ?: return null
|
||||
val newName = REM_TO_MOD_OPERATION_NAMES.inverse()[operatorMod.nameAsName] ?: return null
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Remove 'operator' modifier" "true"
|
||||
// COMPILER_ARGUMENTS: -XXLanguage:+ProhibitOperatorMod
|
||||
|
||||
object A {
|
||||
operator<caret> fun mod(x: Int) {}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Remove 'operator' modifier" "true"
|
||||
// COMPILER_ARGUMENTS: -XXLanguage:+ProhibitOperatorMod
|
||||
|
||||
object A {
|
||||
fun mod(x: Int) {}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Rename to 'rem'" "true"
|
||||
// DISABLE-ERRORS
|
||||
// COMPILER_ARGUMENTS: -XXLanguage:+ProhibitOperatorMod
|
||||
|
||||
object Rem {
|
||||
operator<caret> fun mod(x: Int) {}
|
||||
operator fun modAssign(x: Int) {}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
Rem % 1
|
||||
Rem.mod(1)
|
||||
Rem.modAssign(1)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Rename to 'rem'" "true"
|
||||
// DISABLE-ERRORS
|
||||
// COMPILER_ARGUMENTS: -XXLanguage:+ProhibitOperatorMod
|
||||
|
||||
object Rem {
|
||||
operator fun rem(x: Int) {}
|
||||
operator fun modAssign(x: Int) {}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
Rem % 1
|
||||
Rem.rem(1)
|
||||
Rem.modAssign(1)
|
||||
}
|
||||
@@ -7699,6 +7699,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
runTest("idea/testData/quickfix/modifiers/removeInnerForClassInTrait.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("removeModifierFromForbiddenOperatorMod.kt")
|
||||
public void testRemoveModifierFromForbiddenOperatorMod() throws Exception {
|
||||
runTest("idea/testData/quickfix/modifiers/removeModifierFromForbiddenOperatorMod.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("removeModifierFromOperatorMod.kt")
|
||||
public void testRemoveModifierFromOperatorMod() throws Exception {
|
||||
runTest("idea/testData/quickfix/modifiers/removeModifierFromOperatorMod.kt");
|
||||
@@ -9287,6 +9292,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/renameToRem"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("forbiddenModAsMember.kt")
|
||||
public void testForbiddenModAsMember() throws Exception {
|
||||
runTest("idea/testData/quickfix/renameToRem/forbiddenModAsMember.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("modAsExtension.kt")
|
||||
public void testModAsExtension() throws Exception {
|
||||
runTest("idea/testData/quickfix/renameToRem/modAsExtension.kt");
|
||||
|
||||
Reference in New Issue
Block a user