teach 'create from usage' to add 'operator' modifier when necessary
This commit is contained in:
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.psi.JetModifierListOwner
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction
|
||||
import org.jetbrains.kotlin.psi.JetVisitorVoid
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
|
||||
public class OperatorModifierInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
|
||||
@@ -41,25 +42,27 @@ public class OperatorModifierInspection : AbstractKotlinInspection(), CleanupLoc
|
||||
}
|
||||
|
||||
private fun JetNamedFunction.isOperator(): Boolean {
|
||||
val name = nameAsName ?: return false
|
||||
val arity = valueParameters.size()
|
||||
if (arity == 0 &&
|
||||
(nameAsName in OperatorConventions.UNARY_OPERATION_NAMES.values() ||
|
||||
nameAsName == OperatorConventions.ITERATOR)) {
|
||||
(name in OperatorConventions.UNARY_OPERATION_NAMES.values() ||
|
||||
name == OperatorConventions.ITERATOR ||
|
||||
isComponentLike(name))) {
|
||||
return true
|
||||
}
|
||||
if (arity == 1 && (nameAsName in OperatorConventions.BINARY_OPERATION_NAMES.values() ||
|
||||
nameAsName in OperatorConventions.ASSIGNMENT_OPERATIONS.values () ||
|
||||
nameAsName == OperatorConventions.CONTAINS ||
|
||||
nameAsName == OperatorConventions.COMPARE_TO)) {
|
||||
if (arity == 1 && (name in OperatorConventions.BINARY_OPERATION_NAMES.values() ||
|
||||
name in OperatorConventions.ASSIGNMENT_OPERATIONS.values () ||
|
||||
name == OperatorConventions.CONTAINS ||
|
||||
name == OperatorConventions.COMPARE_TO)) {
|
||||
return true
|
||||
}
|
||||
if (nameAsName == OperatorConventions.INVOKE) {
|
||||
if (name == OperatorConventions.INVOKE) {
|
||||
return true
|
||||
}
|
||||
if (arity >= 1 && nameAsName == OperatorConventions.GET) {
|
||||
if (arity >= 1 && name == OperatorConventions.GET) {
|
||||
return true
|
||||
}
|
||||
if (arity >= 2 && nameAsName == OperatorConventions.SET) {
|
||||
if (arity >= 2 && name == OperatorConventions.SET) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
+3
-2
@@ -467,8 +467,9 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
containingElement is JetClass && containingElement.isInterface() && !config.isExtension -> ""
|
||||
else -> "{}"
|
||||
}
|
||||
if (callableInfo.kind == CallableKind.FUNCTION) {
|
||||
psiFactory.createFunction("${modifiers}fun<> $header $body")
|
||||
if (callableInfo is FunctionInfo) {
|
||||
val operatorModifier = if (callableInfo.isOperator) "operator " else ""
|
||||
psiFactory.createFunction("${modifiers}${operatorModifier}fun<> $header $body")
|
||||
}
|
||||
else {
|
||||
psiFactory.createSecondaryConstructor("${modifiers}constructor$paramList $body")
|
||||
|
||||
+3
-2
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
import java.util.Collections
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Represents a concrete type or a set of types yet to be inferred from an expression.
|
||||
@@ -143,7 +143,8 @@ class FunctionInfo(name: String,
|
||||
returnTypeInfo: TypeInfo,
|
||||
possibleContainers: List<JetElement> = Collections.emptyList(),
|
||||
override val parameterInfos: List<ParameterInfo> = Collections.emptyList(),
|
||||
typeParameterInfos: List<TypeInfo> = Collections.emptyList()
|
||||
typeParameterInfos: List<TypeInfo> = Collections.emptyList(),
|
||||
val isOperator: Boolean = false
|
||||
) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers, typeParameterInfos) {
|
||||
override val kind: CallableKind get() = CallableKind.FUNCTION
|
||||
}
|
||||
|
||||
+3
-2
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.psi.JetBinaryExpression
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import java.util.Collections
|
||||
import java.util.*
|
||||
|
||||
public object CreateBinaryOperationActionFactory: CreateCallableMemberFromUsageFactory<JetBinaryExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetBinaryExpression? {
|
||||
@@ -54,6 +54,7 @@ public object CreateBinaryOperationActionFactory: CreateCallableMemberFromUsageF
|
||||
else -> TypeInfo(element, Variance.OUT_VARIANCE)
|
||||
}
|
||||
val parameters = Collections.singletonList(ParameterInfo(TypeInfo(argumentExpr, Variance.IN_VARIANCE)))
|
||||
return FunctionInfo(operationName, receiverType, returnType, Collections.emptyList(), parameters)
|
||||
return FunctionInfo(operationName, receiverType, returnType, parameterInfos = parameters,
|
||||
isOperator = token != JetTokens.IDENTIFIER)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,6 +49,6 @@ object CreateComponentFunctionActionFactory : CreateCallableMemberFromUsageFacto
|
||||
val entry = entries[componentNumber]
|
||||
val returnType = TypeInfo(entry, Variance.OUT_VARIANCE)
|
||||
|
||||
return FunctionInfo(name.identifier, ownerType, returnType)
|
||||
return FunctionInfo(name.identifier, ownerType, returnType, isOperator = true)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -47,6 +47,6 @@ object CreateInvokeFunctionActionFactory : CreateCallableMemberFromUsageFactory<
|
||||
}
|
||||
|
||||
val returnType = TypeInfo(element, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo(OperatorConventions.INVOKE.asString(), receiverType, returnType, emptyList(), parameters)
|
||||
return FunctionInfo(OperatorConventions.INVOKE.asString(), receiverType, returnType, parameterInfos = parameters, isOperator = true)
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -30,7 +30,8 @@ import org.jetbrains.kotlin.psi.JetForExpression
|
||||
import org.jetbrains.kotlin.types.JetTypeImpl
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import java.util.Collections
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import java.util.*
|
||||
|
||||
object CreateIteratorFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetForExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetForExpression? {
|
||||
@@ -56,6 +57,6 @@ object CreateIteratorFunctionActionFactory : CreateCallableMemberFromUsageFactor
|
||||
returnJetTypeArguments,
|
||||
returnJetType.memberScope)
|
||||
val returnType = TypeInfo(newReturnJetType, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo("iterator", iterableType, returnType)
|
||||
return FunctionInfo(OperatorConventions.ITERATOR.asString(), iterableType, returnType, isOperator = true)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -39,6 +39,6 @@ public object CreateUnaryOperationActionFactory: CreateCallableMemberFromUsageFa
|
||||
|
||||
val receiverType = TypeInfo(receiverExpr, Variance.IN_VARIANCE)
|
||||
val returnType = if (incDec) TypeInfo.ByReceiverType(Variance.OUT_VARIANCE) else TypeInfo(element, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo(operationName.asString(), receiverType, returnType)
|
||||
return FunctionInfo(operationName.asString(), receiverType, returnType, isOperator = true)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'compareTo'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun compareTo(t: T): Int {
|
||||
operator fun compareTo(t: T): Int {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'contains'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun contains(t: T): Boolean {
|
||||
operator fun contains(t: T): Boolean {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'compareTo'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun compareTo(t: T): Int {
|
||||
operator fun compareTo(t: T): Int {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'contains'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun contains(t: T): Boolean {
|
||||
operator fun contains(t: T): Boolean {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
idea/testData/quickfix/createFromUsage/createFunction/binaryOperations/plusAssignOnUserType.kt.after
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'plusAssign'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun plusAssign(t: T) {
|
||||
operator fun plusAssign(t: T) {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -3,7 +3,7 @@
|
||||
class A<T>(val n: T) {
|
||||
fun plus(): A<T> = throw Exception()
|
||||
|
||||
fun plus(t: T): A<T> {
|
||||
operator fun plus(t: T): A<T> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'plus'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun plus(t: T): A<T> {
|
||||
operator fun plus(t: T): A<T> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -3,7 +3,7 @@
|
||||
class A<T>(val n: T) {
|
||||
fun plus(i: Int, s: String): A<T> = throw Exception()
|
||||
|
||||
fun plus(t: T): A<T> {
|
||||
operator fun plus(t: T): A<T> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -6,6 +6,6 @@ fun test() {
|
||||
val a: A<Int> = 2 + A(1)
|
||||
}
|
||||
|
||||
fun Int.plus(a: A<Int>): A<Int> {
|
||||
operator fun Int.plus(a: A<Int>): A<Int> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'plus'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun plus(t: T): A<T> {
|
||||
operator fun plus(t: T): A<T> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'plus'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun plus(i: Int): A<T> {
|
||||
operator fun plus(i: Int): A<T> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'contains'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun contains(t: T): Boolean {
|
||||
operator fun contains(t: T): Boolean {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'contains'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun contains(t: T): Boolean {
|
||||
operator fun contains(t: T): Boolean {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -3,7 +3,7 @@ class Foo<T> {
|
||||
fun component1(): Int { return 0 }
|
||||
fun component2(): Int { return 0 }
|
||||
|
||||
fun component3(): Any {
|
||||
operator fun component3(): Any {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -3,7 +3,7 @@ class Foo<T> {
|
||||
fun component1(): Int { return 0 }
|
||||
fun component2(): Int { return 0 }
|
||||
|
||||
fun component3(): String {
|
||||
operator fun component3(): String {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -17,6 +17,6 @@ fun foo() {
|
||||
for ((i: Int, j: Int) in Foo<Int>()) { }
|
||||
}
|
||||
|
||||
fun Any.component2(): Int {
|
||||
operator fun Any.component2(): Int {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@ fun test(): A<String> {
|
||||
return 1(2, "2")
|
||||
}
|
||||
|
||||
fun Int.invoke(i: Int, s: String): A<String> {
|
||||
operator fun Int.invoke(i: Int, s: String): A<String> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'invoke'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun invoke(t: T, s: String): B<String> {
|
||||
operator fun invoke(t: T, s: String): B<String> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
idea/testData/quickfix/createFromUsage/createFunction/invoke/invokeOnUserTypeWithTypeParams.kt.after
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'invoke'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun <V> invoke(u: T, s: String): B<V> {
|
||||
operator fun <V> invoke(u: T, s: String): B<V> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'invoke'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun invoke(abc: T, ghi: A<T>, def: String): A<T> {
|
||||
operator fun invoke(abc: T, ghi: A<T>, def: String): A<T> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
// "Create member function 'iterator'" "true"
|
||||
class Foo<T> {
|
||||
fun iterator(): Iterator<T> {
|
||||
operator fun iterator(): Iterator<T> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
// "Create member function 'iterator'" "true"
|
||||
class Foo<T> {
|
||||
fun iterator(): Iterator<String> {
|
||||
operator fun iterator(): Iterator<String> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'inc'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun inc(): A<T> {
|
||||
operator fun inc(): A<T> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -3,7 +3,7 @@
|
||||
class A<T>(val n: T) {
|
||||
fun minus(n: Int): A<T> = throw Exception()
|
||||
|
||||
fun minus(): A<T> {
|
||||
operator fun minus(): A<T> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -4,6 +4,6 @@ fun test() {
|
||||
val a = -false
|
||||
}
|
||||
|
||||
fun Boolean.minus(): Any {
|
||||
operator fun Boolean.minus(): Any {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'minus'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun minus(): Any {
|
||||
operator fun minus(): Any {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// "Create member function 'minus'" "true"
|
||||
|
||||
class A<T>(val n: T) {
|
||||
fun minus(): A<T> {
|
||||
operator fun minus(): A<T> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user