'operator' checks

This commit is contained in:
Yan Zhulanow
2015-10-12 02:55:45 +03:00
parent dc8e796e49
commit 275f3f8954
30 changed files with 589 additions and 94 deletions
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.TypeSubstitutor;
import org.jetbrains.kotlin.util.OperatorNameConventions;
import org.jetbrains.kotlin.util.OperatorChecks;
import java.util.List;
@@ -88,7 +88,7 @@ public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implement
SimpleFunctionDescriptorImpl descriptor = super.initialize(
receiverParameterType, dispatchReceiverParameter, typeParameters, unsubstitutedValueParameters,
unsubstitutedReturnType, modality, visibility);
setOperator(OperatorNameConventions.INSTANCE$.canBeOperator(descriptor));
setOperator(OperatorChecks.INSTANCE$.canBeOperator(descriptor));
return descriptor;
}
@@ -0,0 +1,130 @@
/*
* 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.util
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlin.util.OperatorNameConventions.GET
import org.jetbrains.kotlin.util.OperatorNameConventions.SET
import org.jetbrains.kotlin.util.OperatorNameConventions.INVOKE
import org.jetbrains.kotlin.util.OperatorNameConventions.CONTAINS
import org.jetbrains.kotlin.util.OperatorNameConventions.ITERATOR
import org.jetbrains.kotlin.util.OperatorNameConventions.NEXT
import org.jetbrains.kotlin.util.OperatorNameConventions.HAS_NEXT
import org.jetbrains.kotlin.util.OperatorNameConventions.EQUALS
import org.jetbrains.kotlin.util.OperatorNameConventions.COMPARE_TO
import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_OPERATION_NAMES
import org.jetbrains.kotlin.util.OperatorNameConventions.BINARY_OPERATION_NAMES
import org.jetbrains.kotlin.util.OperatorNameConventions.ASSIGNMENT_OPERATIONS
import org.jetbrains.kotlin.util.OperatorNameConventions.COMPONENT_REGEX
import org.jetbrains.kotlin.util.OperatorNameConventions.PLUS
import org.jetbrains.kotlin.util.OperatorNameConventions.MINUS
import org.jetbrains.kotlin.util.OperatorNameConventions.RANGE_TO
import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_PLUS
import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_MINUS
import org.jetbrains.kotlin.util.OperatorNameConventions.NOT
import org.jetbrains.kotlin.util.OperatorNameConventions.INC
import org.jetbrains.kotlin.util.OperatorNameConventions.DEC
import org.jetbrains.kotlin.util.OperatorNameConventions.GET_VALUE
import org.jetbrains.kotlin.util.OperatorNameConventions.SET_VALUE
object OperatorChecks {
fun canBeOperator(functionDescriptor: FunctionDescriptor): Boolean {
val name = functionDescriptor.name
return with (functionDescriptor) {
if (!functionDescriptor.isMemberOrExtension) return false
when {
GET == name -> valueParameters.size >= 1
SET == name -> {
val lastIsOk = valueParameters.lastOrNull()?.let { !it.hasDefaultValue() && it.varargElementType == null } ?: false
valueParameters.size >= 2 && lastIsOk
}
GET_VALUE == name -> noDefaultsAndVarargs && valueParameters.size >= 2 && valueParameters[1].isPropertyMetadata
SET_VALUE == name -> noDefaultsAndVarargs && valueParameters.size >= 3 && valueParameters[1].isPropertyMetadata
INVOKE == name -> isMemberOrExtension
CONTAINS == name -> singleValueParameter && noDefaultsAndVarargs && returnsBoolean
ITERATOR == name -> noValueParameters
NEXT == name -> noValueParameters
HAS_NEXT == name -> noValueParameters && returnsBoolean
RANGE_TO == name -> singleValueParameter && noDefaultsAndVarargs
EQUALS == name -> {
fun DeclarationDescriptor.isAny() = (this as? ClassDescriptor)?.let { KotlinBuiltIns.isAny(it) } ?: false
isMember && overriddenDescriptors.any { it.containingDeclaration.isAny() }
}
COMPARE_TO == name -> returnsInt && singleValueParameter && noDefaultsAndVarargs
BINARY_OPERATION_NAMES.any { it == name } && functionDescriptor.valueParameters.size == 1 ->
singleValueParameter && noDefaultsAndVarargs
(PLUS == name) || (MINUS == name) || (UNARY_PLUS == name) || (UNARY_MINUS == name) || (NOT == name) ->
noValueParameters
(INC == name) || (DEC == name) -> {
val receiver = dispatchReceiverParameter ?: extensionReceiverParameter
isMemberOrExtension && (receiver != null) && (returnType?.let { it.isSubtypeOf(receiver.type) } ?: false)
}
ASSIGNMENT_OPERATIONS.any { it == name } ->
returnsUnit && singleValueParameter && noDefaultsAndVarargs
name.asString().matches(COMPONENT_REGEX) -> noValueParameters
else -> false
}
}
}
private val ValueParameterDescriptor.isPropertyMetadata: Boolean
get() = builtIns.propertyMetadata.defaultType.isSubtypeOf(type.makeNotNullable())
private val FunctionDescriptor.isMember: Boolean
get() = containingDeclaration is ClassDescriptor
private val FunctionDescriptor.isMemberOrExtension: Boolean
get() = isExtension || containingDeclaration is ClassDescriptor
private val FunctionDescriptor.noValueParameters: Boolean
get() = valueParameters.isEmpty
private val FunctionDescriptor.singleValueParameter: Boolean
get() = valueParameters.size == 1
private val FunctionDescriptor.returnsBoolean: Boolean
get() = returnType?.let { KotlinBuiltIns.isBoolean(it) } ?: false
private val FunctionDescriptor.returnsInt: Boolean
get() = returnType?.let { builtIns.intType == it } ?: false //TODO
private val FunctionDescriptor.returnsUnit: Boolean
get() = returnType?.let { builtIns.unitType == it } ?: false //TODO
private val FunctionDescriptor.noDefaultsAndVarargs: Boolean
get() = valueParameters.all { !it.hasDefaultValue() && it.varargElementType == null }
}
@@ -16,13 +16,15 @@
package org.jetbrains.kotlin.util
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.name.Name
import java.util.*
import kotlin.text.Regex
object OperatorNameConventions {
val GET_VALUE = Name.identifier("getValue")
val SET_VALUE = Name.identifier("setValue")
val EQUALS = Name.identifier("equals")
val IDENTITY_EQUALS = Name.identifier("identityEquals");
val COMPARE_TO = Name.identifier("compareTo")
@@ -62,31 +64,8 @@ object OperatorNameConventions {
// If you add new unary, binary or assignment operators, add it to OperatorConventions as well
val UNARY_OPERATION_NAMES_WITH_DEPRECATED = Collections.unmodifiableSet(setOf(INC, DEC, UNARY_PLUS, PLUS, UNARY_MINUS, MINUS, NOT))
private val UNARY_OPERATION_NAMES = setOf(INC, DEC, UNARY_PLUS, UNARY_MINUS, NOT)
private val BINARY_OPERATION_NAMES = setOf(TIMES, PLUS, MINUS, DIV, MOD, RANGE_TO)
private val ASSIGNMENT_OPERATIONS = setOf(TIMES_ASSIGN, DIV_ASSIGN, MOD_ASSIGN, PLUS_ASSIGN, MINUS_ASSIGN)
fun canBeOperator(functionDescriptor: FunctionDescriptor): Boolean {
val name = functionDescriptor.name
return when {
GET == name -> true
SET == name -> true
INVOKE == name -> true
CONTAINS == name -> true
ITERATOR == name -> true
NEXT == name -> true
HAS_NEXT == name -> true
EQUALS == name -> true
COMPARE_TO == name -> true
UNARY_OPERATION_NAMES.any { it == name } && functionDescriptor.valueParameters.isEmpty() -> true
BINARY_OPERATION_NAMES.any { it == name } && functionDescriptor.valueParameters.size() == 1 -> true
(PLUS == name) || (MINUS == name) -> true //temporary fix for deprecated unaryPlus()/unaryMinus()
ASSIGNMENT_OPERATIONS.any { it == name } -> true
name.asString().matches(COMPONENT_REGEX) -> true
else -> false
}
}
internal val UNARY_OPERATION_NAMES = setOf(INC, DEC, UNARY_PLUS, UNARY_MINUS, NOT)
internal val BINARY_OPERATION_NAMES = setOf(TIMES, PLUS, MINUS, DIV, MOD, RANGE_TO)
internal val ASSIGNMENT_OPERATIONS = setOf(TIMES_ASSIGN, DIV_ASSIGN, MOD_ASSIGN, PLUS_ASSIGN, MINUS_ASSIGN)
}