From 92161370f13fe1825542c0c3a1a4de13f6e1dc31 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Thu, 16 Jul 2015 21:47:51 +0300 Subject: [PATCH] Refactor: Make some of utils in ConstantExpressionEvaluator non static --- .../kotlin/resolve/AnnotationResolver.java | 8 +- .../evaluate/ConstantExpressionEvaluator.kt | 290 +++++++++--------- 2 files changed, 158 insertions(+), 140 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationResolver.java index 94ab977b442..e03f12eced9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationResolver.java @@ -55,6 +55,7 @@ public class AnnotationResolver { private CallResolver callResolver; private StorageManager storageManager; private TypeResolver typeResolver; + private ConstantExpressionEvaluator constantExpressionEvaluator; @Inject public void setCallResolver(CallResolver callResolver) { @@ -71,6 +72,11 @@ public class AnnotationResolver { this.typeResolver = typeResolver; } + @Inject + public void setConstantExpressionEvaluator(ConstantExpressionEvaluator constantExpressionEvaluator) { + this.constantExpressionEvaluator = constantExpressionEvaluator; + } + @NotNull public Annotations resolveAnnotationsWithoutArguments( @NotNull JetScope scope, @@ -209,6 +215,6 @@ public class AnnotationResolver { @NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument resolvedArgument ) { - return ConstantExpressionEvaluator.getAnnotationArgumentValue(trace, valueParameter, resolvedArgument); + return constantExpressionEvaluator.getAnnotationArgumentValue(trace, valueParameter, resolvedArgument); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt index 5a48adfa2ea..c09f3bae657 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt @@ -52,145 +52,153 @@ import java.math.BigInteger import java.util.HashMap import kotlin.platform.platformStatic -public class ConstantExpressionEvaluator private constructor() { +public class ConstantExpressionEvaluator(private val builtIns: KotlinBuiltIns) { + + internal fun resolveAnnotationArguments( + resolvedCall: ResolvedCall<*>, + trace: BindingTrace + ): Map> { + val arguments = HashMap>() + for ((parameterDescriptor, resolvedArgument) in resolvedCall.getValueArguments().entrySet()) { + val value = getAnnotationArgumentValue(trace, parameterDescriptor, resolvedArgument) + if (value != null) { + arguments.put(parameterDescriptor, value) + } + } + return arguments + } + + public fun getAnnotationArgumentValue( + trace: BindingTrace, + parameterDescriptor: ValueParameterDescriptor, + resolvedArgument: ResolvedValueArgument + ): ConstantValue<*>? { + val varargElementType = parameterDescriptor.getVarargElementType() + val argumentsAsVararg = varargElementType != null && !hasSpread(resolvedArgument) + val constantType = if (argumentsAsVararg) varargElementType else parameterDescriptor.getType() + val compileTimeConstants = resolveValueArguments(resolvedArgument, constantType!!, trace) + val constants = compileTimeConstants.map { it.toConstantValue(constantType) } + + if (argumentsAsVararg) { + if (parameterDescriptor.declaresDefaultValue() && compileTimeConstants.isEmpty()) return null + + return ArrayValue(constants, parameterDescriptor.getType()) + } + else { + // we should actually get only one element, but just in case of getting many, we take the last one + return constants.lastOrNull() + } + } + + private fun checkCompileTimeConstant( + argumentExpression: JetExpression, + expectedType: JetType, + trace: BindingTrace + ) { + val expressionType = trace.getType(argumentExpression) + + if (expressionType == null || !JetTypeChecker.DEFAULT.isSubtypeOf(expressionType, expectedType)) { + // TYPE_MISMATCH should be reported otherwise + return + } + + // array(1, null, 3) - error should be reported on inner expression + if (argumentExpression is JetCallExpression) { + val arrayArgument = getArgumentExpressionsForArrayCall(argumentExpression, trace) + if (arrayArgument != null) { + for (expression in arrayArgument.first) { + checkCompileTimeConstant(expression, arrayArgument.second!!, trace) + } + } + } + + val constant = ConstantExpressionEvaluator.getConstant(argumentExpression, trace.getBindingContext()) + if (constant != null && constant.canBeUsedInAnnotations) { + return + } + + val descriptor = expressionType.getConstructor().getDeclarationDescriptor() + if (descriptor != null && DescriptorUtils.isEnumClass(descriptor)) { + trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST.on(argumentExpression)) + } + else if (descriptor is ClassDescriptor && KotlinBuiltIns.isKClass(descriptor)) { + trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL.on(argumentExpression)) + } + else { + trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CONST.on(argumentExpression)) + } + } + + private fun getArgumentExpressionsForArrayCall( + expression: JetCallExpression, + trace: BindingTrace + ): Pair, JetType?>? { + val resolvedCall = expression.getResolvedCall(trace.getBindingContext()) + if (resolvedCall == null || !CompileTimeConstantUtils.isArrayMethodCall(resolvedCall)) { + return null + } + + assert(resolvedCall.getValueArguments().size() == 1, "Array function should have only one vararg parameter") + + val argumentEntry = resolvedCall.getValueArguments().entrySet().iterator().next() + + val elementType = argumentEntry.getKey().getVarargElementType() ?: return null + + val result = arrayListOf() + for (valueArgument in argumentEntry.getValue().getArguments()) { + val valueArgumentExpression = valueArgument.getArgumentExpression() + if (valueArgumentExpression != null) { + result.add(valueArgumentExpression) + } + } + + return Pair, JetType>(result, elementType) + } + + private fun hasSpread(argument: ResolvedValueArgument): Boolean { + val arguments = argument.getArguments() + return arguments.size() == 1 && arguments.get(0).getSpreadElement() != null + } + + private fun resolveValueArguments( + resolvedValueArgument: ResolvedValueArgument, + expectedType: JetType, + trace: BindingTrace): List> { + val constants = Lists.newArrayList>() + for (argument in resolvedValueArgument.getArguments()) { + val argumentExpression = argument.getArgumentExpression() ?: continue + val constant = ConstantExpressionEvaluator.evaluate(argumentExpression, trace, expectedType) + if (constant is IntegerValueTypeConstant) { + val defaultType = constant.getType(expectedType) + val context = SimpleResolutionContext(trace, JetScope.Empty, TypeUtils.NO_EXPECTED_TYPE, DataFlowInfo.EMPTY, + ContextDependency.INDEPENDENT, + CompositeChecker(Lists.newArrayList()), + SymbolUsageValidator.Empty, + AdditionalTypeChecker.Composite(Lists.newArrayList()), + StatementFilter.NONE) + ArgumentTypeResolver.updateNumberType(defaultType, argumentExpression, context) + } + if (constant != null) { + constants.add(constant) + } + checkCompileTimeConstant(argumentExpression, expectedType, trace) + } + return constants + } + + public fun evaluateExpression( + expression: JetExpression, + trace: BindingTrace, + expectedType: JetType? = TypeUtils.NO_EXPECTED_TYPE + ): CompileTimeConstant<*>? { + val visitor = ConstantExpressionEvaluatorVisitor(this, trace, builtIns) + val constant = visitor.evaluate(expression, expectedType) ?: return null + return if (!constant.isError) constant else null + } + companion object { - - platformStatic public fun resolveAnnotationArguments( - resolvedCall: ResolvedCall<*>, - trace: BindingTrace - ): Map> { - val arguments = HashMap>() - for ((parameterDescriptor, resolvedArgument) in resolvedCall.getValueArguments().entrySet()) { - val value = getAnnotationArgumentValue(trace, parameterDescriptor, resolvedArgument) - if (value != null) { - arguments.put(parameterDescriptor, value) - } - } - return arguments - } - - platformStatic public fun getAnnotationArgumentValue( - trace: BindingTrace, - parameterDescriptor: ValueParameterDescriptor, - resolvedArgument: ResolvedValueArgument - ): ConstantValue<*>? { - val varargElementType = parameterDescriptor.getVarargElementType() - val argumentsAsVararg = varargElementType != null && !hasSpread(resolvedArgument) - val constantType = if (argumentsAsVararg) varargElementType else parameterDescriptor.getType() - val compileTimeConstants = resolveValueArguments(resolvedArgument, constantType!!, trace) - val constants = compileTimeConstants.map { it.toConstantValue(constantType) } - - if (argumentsAsVararg) { - if (parameterDescriptor.declaresDefaultValue() && compileTimeConstants.isEmpty()) return null - - return ArrayValue(constants, parameterDescriptor.getType()) - } - else { - // we should actually get only one element, but just in case of getting many, we take the last one - return constants.lastOrNull() - } - } - - private fun checkCompileTimeConstant( - argumentExpression: JetExpression, - expectedType: JetType, - trace: BindingTrace - ) { - val expressionType = trace.getType(argumentExpression) - - if (expressionType == null || !JetTypeChecker.DEFAULT.isSubtypeOf(expressionType, expectedType)) { - // TYPE_MISMATCH should be reported otherwise - return - } - - // array(1, null, 3) - error should be reported on inner expression - if (argumentExpression is JetCallExpression) { - val arrayArgument = getArgumentExpressionsForArrayCall(argumentExpression, trace) - if (arrayArgument != null) { - for (expression in arrayArgument.first) { - checkCompileTimeConstant(expression, arrayArgument.second!!, trace) - } - } - } - - val constant = ConstantExpressionEvaluator.getConstant(argumentExpression, trace.getBindingContext()) - if (constant != null && constant.canBeUsedInAnnotations) { - return - } - - val descriptor = expressionType.getConstructor().getDeclarationDescriptor() - if (descriptor != null && DescriptorUtils.isEnumClass(descriptor)) { - trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST.on(argumentExpression)) - } - else if (descriptor is ClassDescriptor && KotlinBuiltIns.isKClass(descriptor)) { - trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL.on(argumentExpression)) - } - else { - trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CONST.on(argumentExpression)) - } - } - - private fun getArgumentExpressionsForArrayCall( - expression: JetCallExpression, - trace: BindingTrace - ): Pair, JetType?>? { - val resolvedCall = expression.getResolvedCall(trace.getBindingContext()) - if (resolvedCall == null || !CompileTimeConstantUtils.isArrayMethodCall(resolvedCall)) { - return null - } - - assert(resolvedCall.getValueArguments().size() == 1, "Array function should have only one vararg parameter") - - val argumentEntry = resolvedCall.getValueArguments().entrySet().iterator().next() - - val elementType = argumentEntry.getKey().getVarargElementType() ?: return null - - val result = arrayListOf() - for (valueArgument in argumentEntry.getValue().getArguments()) { - val valueArgumentExpression = valueArgument.getArgumentExpression() - if (valueArgumentExpression != null) { - result.add(valueArgumentExpression) - } - } - - return Pair, JetType>(result, elementType) - } - - private fun hasSpread(argument: ResolvedValueArgument): Boolean { - val arguments = argument.getArguments() - return arguments.size() == 1 && arguments.get(0).getSpreadElement() != null - } - - private fun resolveValueArguments( - resolvedValueArgument: ResolvedValueArgument, - expectedType: JetType, - trace: BindingTrace): List> { - val constants = Lists.newArrayList>() - for (argument in resolvedValueArgument.getArguments()) { - val argumentExpression = argument.getArgumentExpression() ?: continue - val constant = ConstantExpressionEvaluator.evaluate(argumentExpression, trace, expectedType) - if (constant is IntegerValueTypeConstant) { - val defaultType = constant.getType(expectedType) - val context = SimpleResolutionContext(trace, JetScope.Empty, TypeUtils.NO_EXPECTED_TYPE, DataFlowInfo.EMPTY, - ContextDependency.INDEPENDENT, - CompositeChecker(Lists.newArrayList()), - SymbolUsageValidator.Empty, - AdditionalTypeChecker.Composite(Lists.newArrayList()), - StatementFilter.NONE) - ArgumentTypeResolver.updateNumberType(defaultType, argumentExpression, context) - } - if (constant != null) { - constants.add(constant) - } - checkCompileTimeConstant(argumentExpression, expectedType, trace) - } - return constants - } - platformStatic public fun evaluate(expression: JetExpression, trace: BindingTrace, expectedType: JetType? = TypeUtils.NO_EXPECTED_TYPE): CompileTimeConstant<*>? { - val visitor = ConstantExpressionEvaluatorVisitor(trace, KotlinBuiltIns.getInstance()) - val constant = visitor.evaluate(expression, expectedType) ?: return null - return if (!constant.isError) constant else null + return ConstantExpressionEvaluator(KotlinBuiltIns.getInstance()).evaluateExpression(expression, trace, expectedType) } platformStatic public fun evaluateToConstantValue( @@ -212,7 +220,11 @@ public class ConstantExpressionEvaluator private constructor() { } } -private class ConstantExpressionEvaluatorVisitor(private val trace: BindingTrace, private val builtIns: KotlinBuiltIns) : JetVisitor?, JetType>() { +private class ConstantExpressionEvaluatorVisitor( + private val constantExpressionEvaluator: ConstantExpressionEvaluator, + private val trace: BindingTrace, + private val builtIns: KotlinBuiltIns +) : JetVisitor?, JetType>() { private val factory = ConstantValueFactory(builtIns) fun evaluate(expression: JetExpression, expectedType: JetType?): CompileTimeConstant<*>? { @@ -572,7 +584,7 @@ private class ConstantExpressionEvaluatorVisitor(private val trace: BindingTrace if (DescriptorUtils.isAnnotationClass(classDescriptor)) { val descriptor = AnnotationDescriptorImpl( classDescriptor.getDefaultType(), - ConstantExpressionEvaluator.resolveAnnotationArguments(call, trace) + constantExpressionEvaluator.resolveAnnotationArguments(call, trace) ) return AnnotationValue(descriptor).wrap() }