teach 'create from usage' to add 'operator' modifier when necessary

This commit is contained in:
Dmitry Jemerov
2015-09-24 16:28:03 +02:00
parent bda0bd1de1
commit 3dbb74bf0c
35 changed files with 54 additions and 47 deletions
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.psi.JetModifierListOwner
import org.jetbrains.kotlin.psi.JetNamedFunction import org.jetbrains.kotlin.psi.JetNamedFunction
import org.jetbrains.kotlin.psi.JetVisitorVoid import org.jetbrains.kotlin.psi.JetVisitorVoid
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.expressions.OperatorConventions
public class OperatorModifierInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { public class OperatorModifierInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
@@ -41,25 +42,27 @@ public class OperatorModifierInspection : AbstractKotlinInspection(), CleanupLoc
} }
private fun JetNamedFunction.isOperator(): Boolean { private fun JetNamedFunction.isOperator(): Boolean {
val name = nameAsName ?: return false
val arity = valueParameters.size() val arity = valueParameters.size()
if (arity == 0 && if (arity == 0 &&
(nameAsName in OperatorConventions.UNARY_OPERATION_NAMES.values() || (name in OperatorConventions.UNARY_OPERATION_NAMES.values() ||
nameAsName == OperatorConventions.ITERATOR)) { name == OperatorConventions.ITERATOR ||
isComponentLike(name))) {
return true return true
} }
if (arity == 1 && (nameAsName in OperatorConventions.BINARY_OPERATION_NAMES.values() || if (arity == 1 && (name in OperatorConventions.BINARY_OPERATION_NAMES.values() ||
nameAsName in OperatorConventions.ASSIGNMENT_OPERATIONS.values () || name in OperatorConventions.ASSIGNMENT_OPERATIONS.values () ||
nameAsName == OperatorConventions.CONTAINS || name == OperatorConventions.CONTAINS ||
nameAsName == OperatorConventions.COMPARE_TO)) { name == OperatorConventions.COMPARE_TO)) {
return true return true
} }
if (nameAsName == OperatorConventions.INVOKE) { if (name == OperatorConventions.INVOKE) {
return true return true
} }
if (arity >= 1 && nameAsName == OperatorConventions.GET) { if (arity >= 1 && name == OperatorConventions.GET) {
return true return true
} }
if (arity >= 2 && nameAsName == OperatorConventions.SET) { if (arity >= 2 && name == OperatorConventions.SET) {
return true return true
} }
return false return false
@@ -467,8 +467,9 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
containingElement is JetClass && containingElement.isInterface() && !config.isExtension -> "" containingElement is JetClass && containingElement.isInterface() && !config.isExtension -> ""
else -> "{}" else -> "{}"
} }
if (callableInfo.kind == CallableKind.FUNCTION) { if (callableInfo is FunctionInfo) {
psiFactory.createFunction("${modifiers}fun<> $header $body") val operatorModifier = if (callableInfo.isOperator) "operator " else ""
psiFactory.createFunction("${modifiers}${operatorModifier}fun<> $header $body")
} }
else { else {
psiFactory.createSecondaryConstructor("${modifiers}constructor$paramList $body") psiFactory.createSecondaryConstructor("${modifiers}constructor$paramList $body")
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.supertypes 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. * 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, returnTypeInfo: TypeInfo,
possibleContainers: List<JetElement> = Collections.emptyList(), possibleContainers: List<JetElement> = Collections.emptyList(),
override val parameterInfos: List<ParameterInfo> = 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) { ) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers, typeParameterInfos) {
override val kind: CallableKind get() = CallableKind.FUNCTION override val kind: CallableKind get() = CallableKind.FUNCTION
} }
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.JetBinaryExpression import org.jetbrains.kotlin.psi.JetBinaryExpression
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.expressions.OperatorConventions
import java.util.Collections import java.util.*
public object CreateBinaryOperationActionFactory: CreateCallableMemberFromUsageFactory<JetBinaryExpression>() { public object CreateBinaryOperationActionFactory: CreateCallableMemberFromUsageFactory<JetBinaryExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetBinaryExpression? { override fun getElementOfInterest(diagnostic: Diagnostic): JetBinaryExpression? {
@@ -54,6 +54,7 @@ public object CreateBinaryOperationActionFactory: CreateCallableMemberFromUsageF
else -> TypeInfo(element, Variance.OUT_VARIANCE) else -> TypeInfo(element, Variance.OUT_VARIANCE)
} }
val parameters = Collections.singletonList(ParameterInfo(TypeInfo(argumentExpr, Variance.IN_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)
} }
} }
@@ -49,6 +49,6 @@ object CreateComponentFunctionActionFactory : CreateCallableMemberFromUsageFacto
val entry = entries[componentNumber] val entry = entries[componentNumber]
val returnType = TypeInfo(entry, Variance.OUT_VARIANCE) val returnType = TypeInfo(entry, Variance.OUT_VARIANCE)
return FunctionInfo(name.identifier, ownerType, returnType) return FunctionInfo(name.identifier, ownerType, returnType, isOperator = true)
} }
} }
@@ -47,6 +47,6 @@ object CreateInvokeFunctionActionFactory : CreateCallableMemberFromUsageFactory<
} }
val returnType = TypeInfo(element, Variance.OUT_VARIANCE) 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)
} }
} }
@@ -30,7 +30,8 @@ import org.jetbrains.kotlin.psi.JetForExpression
import org.jetbrains.kotlin.types.JetTypeImpl import org.jetbrains.kotlin.types.JetTypeImpl
import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import java.util.Collections import org.jetbrains.kotlin.types.expressions.OperatorConventions
import java.util.*
object CreateIteratorFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetForExpression>() { object CreateIteratorFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetForExpression>() {
override fun getElementOfInterest(diagnostic: Diagnostic): JetForExpression? { override fun getElementOfInterest(diagnostic: Diagnostic): JetForExpression? {
@@ -56,6 +57,6 @@ object CreateIteratorFunctionActionFactory : CreateCallableMemberFromUsageFactor
returnJetTypeArguments, returnJetTypeArguments,
returnJetType.memberScope) returnJetType.memberScope)
val returnType = TypeInfo(newReturnJetType, Variance.OUT_VARIANCE) val returnType = TypeInfo(newReturnJetType, Variance.OUT_VARIANCE)
return FunctionInfo("iterator", iterableType, returnType) return FunctionInfo(OperatorConventions.ITERATOR.asString(), iterableType, returnType, isOperator = true)
} }
} }
@@ -39,6 +39,6 @@ public object CreateUnaryOperationActionFactory: CreateCallableMemberFromUsageFa
val receiverType = TypeInfo(receiverExpr, Variance.IN_VARIANCE) val receiverType = TypeInfo(receiverExpr, Variance.IN_VARIANCE)
val returnType = if (incDec) TypeInfo.ByReceiverType(Variance.OUT_VARIANCE) else TypeInfo(element, Variance.OUT_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,7 +1,7 @@
// "Create member function 'compareTo'" "true" // "Create member function 'compareTo'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,7 +1,7 @@
// "Create member function 'contains'" "true" // "Create member function 'contains'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,7 +1,7 @@
// "Create member function 'compareTo'" "true" // "Create member function 'compareTo'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,7 +1,7 @@
// "Create member function 'contains'" "true" // "Create member function 'contains'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,7 +1,7 @@
// "Create member function 'plusAssign'" "true" // "Create member function 'plusAssign'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -3,7 +3,7 @@
class A<T>(val n: T) { class A<T>(val n: T) {
fun plus(): A<T> = throw Exception() 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,7 +1,7 @@
// "Create member function 'plus'" "true" // "Create member function 'plus'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -3,7 +3,7 @@
class A<T>(val n: T) { class A<T>(val n: T) {
fun plus(i: Int, s: String): A<T> = throw Exception() 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -6,6 +6,6 @@ fun test() {
val a: A<Int> = 2 + A(1) 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
@@ -1,7 +1,7 @@
// "Create member function 'plus'" "true" // "Create member function 'plus'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,7 +1,7 @@
// "Create member function 'plus'" "true" // "Create member function 'plus'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,7 +1,7 @@
// "Create member function 'contains'" "true" // "Create member function 'contains'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,7 +1,7 @@
// "Create member function 'contains'" "true" // "Create member function 'contains'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -3,7 +3,7 @@ class Foo<T> {
fun component1(): Int { return 0 } fun component1(): Int { return 0 }
fun component2(): 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -3,7 +3,7 @@ class Foo<T> {
fun component1(): Int { return 0 } fun component1(): Int { return 0 }
fun component2(): 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -17,6 +17,6 @@ fun foo() {
for ((i: Int, j: Int) in Foo<Int>()) { } 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
@@ -6,6 +6,6 @@ fun test(): A<String> {
return 1(2, "2") 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
@@ -1,7 +1,7 @@
// "Create member function 'invoke'" "true" // "Create member function 'invoke'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,7 +1,7 @@
// "Create member function 'invoke'" "true" // "Create member function 'invoke'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,7 +1,7 @@
// "Create member function 'invoke'" "true" // "Create member function 'invoke'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,6 +1,6 @@
// "Create member function 'iterator'" "true" // "Create member function 'iterator'" "true"
class Foo<T> { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,6 +1,6 @@
// "Create member function 'iterator'" "true" // "Create member function 'iterator'" "true"
class Foo<T> { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,7 +1,7 @@
// "Create member function 'inc'" "true" // "Create member function 'inc'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -3,7 +3,7 @@
class A<T>(val n: T) { class A<T>(val n: T) {
fun minus(n: Int): A<T> = throw Exception() 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -4,6 +4,6 @@ fun test() {
val a = -false 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
@@ -1,7 +1,7 @@
// "Create member function 'minus'" "true" // "Create member function 'minus'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }
@@ -1,7 +1,7 @@
// "Create member function 'minus'" "true" // "Create member function 'minus'" "true"
class A<T>(val n: T) { 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. throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
} }
} }