SwitchCodegenUtil: convert to Kotlin and cleanup
This commit is contained in:
@@ -14,166 +14,123 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.when;
|
package org.jetbrains.kotlin.codegen.`when`
|
||||||
|
|
||||||
import kotlin.jvm.functions.Function1;
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen;
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.constants.IntegerValueConstant
|
||||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
import org.jetbrains.kotlin.resolve.constants.NullValue
|
||||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueConstant;
|
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||||
import org.jetbrains.kotlin.resolve.constants.NullValue;
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.kotlin.resolve.constants.StringValue;
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class SwitchCodegenUtil {
|
object SwitchCodegenUtil {
|
||||||
public static boolean checkAllItemsAreConstantsSatisfying(
|
@JvmStatic
|
||||||
@NotNull KtWhenExpression expression,
|
fun checkAllItemsAreConstantsSatisfying(
|
||||||
@NotNull BindingContext bindingContext,
|
expression: KtWhenExpression,
|
||||||
boolean shouldInlineConstVals,
|
bindingContext: BindingContext,
|
||||||
Function1<ConstantValue<?>, Boolean> predicate
|
shouldInlineConstVals: Boolean,
|
||||||
) {
|
predicate: Function1<ConstantValue<*>, Boolean>
|
||||||
for (KtWhenEntry entry : expression.getEntries()) {
|
): Boolean =
|
||||||
for (KtWhenCondition condition : entry.getConditions()) {
|
expression.entries.all { entry ->
|
||||||
if (!(condition instanceof KtWhenConditionWithExpression)) {
|
entry.conditions.all { condition ->
|
||||||
return false;
|
if (condition !is KtWhenConditionWithExpression) return false
|
||||||
}
|
val patternExpression = condition.expression ?: return false
|
||||||
|
val constant = ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext, shouldInlineConstVals) ?: return false
|
||||||
// ensure that expression is constant
|
predicate.invoke(constant)
|
||||||
KtExpression patternExpression = ((KtWhenConditionWithExpression) condition).getExpression();
|
|
||||||
|
|
||||||
if (patternExpression == null) return false;
|
|
||||||
|
|
||||||
ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext, shouldInlineConstVals);
|
|
||||||
if (constant == null || !predicate.invoke(constant)) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
@JvmStatic
|
||||||
}
|
fun getAllConstants(
|
||||||
|
expression: KtWhenExpression,
|
||||||
|
bindingContext: BindingContext,
|
||||||
|
shouldInlineConstVals: Boolean
|
||||||
|
): Iterable<ConstantValue<*>?> =
|
||||||
|
ArrayList<ConstantValue<*>?>().apply {
|
||||||
|
for (entry in expression.entries) {
|
||||||
|
addConstantsFromConditions(entry, bindingContext, shouldInlineConstVals)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@JvmStatic
|
||||||
public static Iterable<ConstantValue<?>> getAllConstants(
|
fun getConstantsFromEntry(
|
||||||
@NotNull KtWhenExpression expression,
|
entry: KtWhenEntry,
|
||||||
@NotNull BindingContext bindingContext,
|
bindingContext: BindingContext,
|
||||||
boolean shouldInlineConstVals
|
shouldInlineConstVals: Boolean
|
||||||
|
): Iterable<ConstantValue<*>?> =
|
||||||
|
ArrayList<ConstantValue<*>?>().apply {
|
||||||
|
addConstantsFromConditions(entry, bindingContext, shouldInlineConstVals)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ArrayList<ConstantValue<*>?>.addConstantsFromConditions(
|
||||||
|
entry: KtWhenEntry,
|
||||||
|
bindingContext: BindingContext,
|
||||||
|
shouldInlineConstVals: Boolean
|
||||||
) {
|
) {
|
||||||
List<ConstantValue<?>> result = new ArrayList<>();
|
for (condition in entry.conditions) {
|
||||||
|
if (condition !is KtWhenConditionWithExpression) continue
|
||||||
for (KtWhenEntry entry : expression.getEntries()) {
|
val patternExpression = condition.expression ?: throw AssertionError("expression in when should not be null")
|
||||||
addConstantsFromEntry(result, entry, bindingContext, shouldInlineConstVals);
|
add(ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext, shouldInlineConstVals))
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addConstantsFromEntry(
|
|
||||||
@NotNull List<ConstantValue<?>> result,
|
|
||||||
@NotNull KtWhenEntry entry,
|
|
||||||
@NotNull BindingContext bindingContext,
|
|
||||||
boolean shouldInlineConstVals
|
|
||||||
) {
|
|
||||||
for (KtWhenCondition condition : entry.getConditions()) {
|
|
||||||
if (!(condition instanceof KtWhenConditionWithExpression)) continue;
|
|
||||||
|
|
||||||
KtExpression patternExpression = ((KtWhenConditionWithExpression) condition).getExpression();
|
|
||||||
|
|
||||||
assert patternExpression != null : "expression in when should not be null";
|
|
||||||
result.add(ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext, shouldInlineConstVals));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@JvmStatic
|
||||||
public static Iterable<ConstantValue<?>> getConstantsFromEntry(
|
fun buildAppropriateSwitchCodegenIfPossible(
|
||||||
@NotNull KtWhenEntry entry,
|
expression: KtWhenExpression,
|
||||||
@NotNull BindingContext bindingContext,
|
isStatement: Boolean,
|
||||||
boolean shouldInlineConstVals
|
isExhaustive: Boolean,
|
||||||
) {
|
codegen: ExpressionCodegen
|
||||||
List<ConstantValue<?>> result = new ArrayList<>();
|
): SwitchCodegen? {
|
||||||
addConstantsFromEntry(result, entry, bindingContext, shouldInlineConstVals);
|
val bindingContext = codegen.bindingContext
|
||||||
return result;
|
val shouldInlineConstVals = codegen.state.shouldInlineConstVals
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static SwitchCodegen buildAppropriateSwitchCodegenIfPossible(
|
|
||||||
@NotNull KtWhenExpression expression,
|
|
||||||
boolean isStatement,
|
|
||||||
boolean isExhaustive,
|
|
||||||
@NotNull ExpressionCodegen codegen
|
|
||||||
) {
|
|
||||||
BindingContext bindingContext = codegen.getBindingContext();
|
|
||||||
boolean shouldInlineConstVals = codegen.getState().getShouldInlineConstVals();
|
|
||||||
if (!isThereConstantEntriesButNulls(expression, bindingContext, shouldInlineConstVals)) {
|
if (!isThereConstantEntriesButNulls(expression, bindingContext, shouldInlineConstVals)) {
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
Type subjectType = codegen.expressionType(expression.getSubjectExpression());
|
val subjectType = codegen.expressionType(expression.subjectExpression)
|
||||||
|
|
||||||
WhenByEnumsMapping mapping = codegen.getBindingContext().get(CodegenBinding.MAPPING_FOR_WHEN_BY_ENUM, expression);
|
val mapping = codegen.bindingContext.get(CodegenBinding.MAPPING_FOR_WHEN_BY_ENUM, expression)
|
||||||
|
|
||||||
if (mapping != null) {
|
return when {
|
||||||
return new EnumSwitchCodegen(expression, isStatement, isExhaustive, codegen, mapping);
|
mapping != null ->
|
||||||
|
EnumSwitchCodegen(expression, isStatement, isExhaustive, codegen, mapping)
|
||||||
|
isIntegralConstantsSwitch(expression, subjectType, bindingContext, shouldInlineConstVals) ->
|
||||||
|
IntegralConstantsSwitchCodegen(expression, isStatement, isExhaustive, codegen)
|
||||||
|
isStringConstantsSwitch(expression, subjectType, bindingContext, shouldInlineConstVals) ->
|
||||||
|
StringSwitchCodegen(expression, isStatement, isExhaustive, codegen)
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isIntegralConstantsSwitch(expression, subjectType, bindingContext, shouldInlineConstVals)) {
|
|
||||||
return new IntegralConstantsSwitchCodegen(expression, isStatement, isExhaustive, codegen);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isStringConstantsSwitch(expression, subjectType, bindingContext, shouldInlineConstVals)) {
|
|
||||||
return new StringSwitchCodegen(expression, isStatement, isExhaustive, codegen);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isThereConstantEntriesButNulls(
|
private fun isThereConstantEntriesButNulls(
|
||||||
@NotNull KtWhenExpression expression,
|
expression: KtWhenExpression,
|
||||||
@NotNull BindingContext bindingContext,
|
bindingContext: BindingContext,
|
||||||
boolean shouldInlineConstVals
|
shouldInlineConstVals: Boolean
|
||||||
) {
|
): Boolean =
|
||||||
for (ConstantValue<?> constant : getAllConstants(expression, bindingContext, shouldInlineConstVals)) {
|
getAllConstants(expression, bindingContext, shouldInlineConstVals).any { it != null && it !is NullValue }
|
||||||
if (constant != null && !(constant instanceof NullValue)) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
private fun isIntegralConstantsSwitch(
|
||||||
}
|
expression: KtWhenExpression,
|
||||||
|
subjectType: Type,
|
||||||
|
bindingContext: BindingContext,
|
||||||
|
shouldInlineConstVals: Boolean
|
||||||
|
): Boolean =
|
||||||
|
AsmUtil.isIntPrimitive(subjectType) &&
|
||||||
|
checkAllItemsAreConstantsSatisfying(expression, bindingContext, shouldInlineConstVals) { it is IntegerValueConstant<*> }
|
||||||
|
|
||||||
private static boolean isIntegralConstantsSwitch(
|
private fun isStringConstantsSwitch(
|
||||||
@NotNull KtWhenExpression expression,
|
expression: KtWhenExpression,
|
||||||
@NotNull Type subjectType,
|
subjectType: Type,
|
||||||
@NotNull BindingContext bindingContext,
|
bindingContext: BindingContext,
|
||||||
boolean shouldInlineConstVals
|
shouldInlineConstVals: Boolean
|
||||||
) {
|
): Boolean =
|
||||||
int typeSort = subjectType.getSort();
|
subjectType.className == String::class.java.name &&
|
||||||
|
checkAllItemsAreConstantsSatisfying(expression, bindingContext, shouldInlineConstVals) { it is StringValue || it is NullValue }
|
||||||
if (typeSort != Type.INT && typeSort != Type.CHAR && typeSort != Type.SHORT && typeSort != Type.BYTE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return checkAllItemsAreConstantsSatisfying(expression, bindingContext, shouldInlineConstVals,
|
|
||||||
constant -> constant instanceof IntegerValueConstant);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isStringConstantsSwitch(
|
|
||||||
@NotNull KtWhenExpression expression,
|
|
||||||
@NotNull Type subjectType,
|
|
||||||
@NotNull BindingContext bindingContext,
|
|
||||||
boolean shouldInlineConstVals
|
|
||||||
) {
|
|
||||||
|
|
||||||
if (!subjectType.getClassName().equals(String.class.getName())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return checkAllItemsAreConstantsSatisfying(expression, bindingContext, shouldInlineConstVals,
|
|
||||||
constant -> constant instanceof StringValue || constant instanceof NullValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user