Refactor and prettify checkCompileTimeConstant method

This commit is contained in:
Mikhail Zarechenskiy
2018-03-07 14:31:18 +03:00
parent 96caf7f4ce
commit baf16895f2
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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.resolve.constants.evaluate package org.jetbrains.kotlin.resolve.constants.evaluate
@@ -120,72 +109,63 @@ class ConstantExpressionEvaluator(
private fun checkCompileTimeConstant( private fun checkCompileTimeConstant(
argumentExpression: KtExpression, argumentExpression: KtExpression,
expectedType: KotlinType, expressionType: KotlinType,
trace: BindingTrace trace: BindingTrace
) { ) {
val expressionType = trace.getType(argumentExpression)
if (expressionType == null || !KotlinTypeChecker.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 KtCallExpression) {
getArgumentExpressionsForArrayCall(argumentExpression, trace)?.let { checkArgumentsAreCompileTimeConstants(it, trace) }
}
if (argumentExpression is KtCollectionLiteralExpression) {
getArgumentExpressionsForCollectionLiteralCall(argumentExpression, trace)?.let {
checkArgumentsAreCompileTimeConstants(
it,
trace
)
}
}
val constant = ConstantExpressionEvaluator.getConstant(argumentExpression, trace.bindingContext) val constant = ConstantExpressionEvaluator.getConstant(argumentExpression, trace.bindingContext)
if (constant != null && constant.canBeUsedInAnnotations) { if (constant != null && constant.canBeUsedInAnnotations) {
if (constant.usesNonConstValAsConstant) { checkInnerPartsOfCompileTimeConstant(constant, trace, argumentExpression)
trace.report(Errors.NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION.on(argumentExpression))
}
if (argumentExpression is KtClassLiteralExpression) {
val lhsExpression = argumentExpression.receiverExpression
if (lhsExpression != null) {
val doubleColonLhs = trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, lhsExpression)
if (doubleColonLhs is DoubleColonLHS.Expression && !doubleColonLhs.isObjectQualifier) {
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL.on(argumentExpression))
}
}
}
return return
} }
val descriptor = expressionType.constructor.declarationDescriptor val descriptor = expressionType.constructor.declarationDescriptor
if (descriptor != null && DescriptorUtils.isEnumClass(descriptor)) { val diagnosticFactory = when {
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST.on(argumentExpression)) DescriptorUtils.isEnumClass(descriptor) -> Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST
} else if (descriptor is ClassDescriptor && KotlinBuiltIns.isKClass(descriptor)) { descriptor is ClassDescriptor && KotlinBuiltIns.isKClass(descriptor) -> Errors.ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL.on(argumentExpression)) else -> Errors.ANNOTATION_PARAMETER_MUST_BE_CONST
} else {
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CONST.on(argumentExpression))
} }
trace.report(diagnosticFactory.on(argumentExpression))
} }
private fun checkArgumentsAreCompileTimeConstants( private fun checkInnerPartsOfCompileTimeConstant(
argumentsWithComponentType: Pair<List<KtExpression>, KotlinType?>, constant: CompileTimeConstant<*>,
trace: BindingTrace trace: BindingTrace,
argumentExpression: KtExpression
) { ) {
val (arguments, componentType) = argumentsWithComponentType // array(1, <!>null<!>, 3) - error should be reported on inner expression
for (expression in arguments) { val callArguments = when (argumentExpression) {
checkCompileTimeConstant(expression, componentType!!, trace) is KtCallExpression -> getArgumentExpressionsForArrayCall(argumentExpression, trace)
is KtCollectionLiteralExpression -> getArgumentExpressionsForCollectionLiteralCall(argumentExpression, trace)
else -> null
}
if (callArguments != null) {
for (argument in callArguments) {
val type = trace.getType(argument) ?: continue
checkCompileTimeConstant(argument, type, trace)
}
}
if (constant.usesNonConstValAsConstant) {
trace.report(Errors.NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION.on(argumentExpression))
}
if (argumentExpression is KtClassLiteralExpression) {
val lhsExpression = argumentExpression.receiverExpression
if (lhsExpression != null) {
val doubleColonLhs = trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, lhsExpression)
if (doubleColonLhs is DoubleColonLHS.Expression && !doubleColonLhs.isObjectQualifier) {
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL.on(argumentExpression))
}
}
} }
} }
private fun getArgumentExpressionsForArrayCall( private fun getArgumentExpressionsForArrayCall(
expression: KtCallExpression, expression: KtCallExpression,
trace: BindingTrace trace: BindingTrace
): Pair<List<KtExpression>, KotlinType?>? { ): List<KtExpression>? {
val resolvedCall = expression.getResolvedCall(trace.bindingContext) ?: return null val resolvedCall = expression.getResolvedCall(trace.bindingContext) ?: return null
return getArgumentExpressionsForArrayLikeCall(resolvedCall) return getArgumentExpressionsForArrayLikeCall(resolvedCall)
} }
@@ -193,19 +173,16 @@ class ConstantExpressionEvaluator(
private fun getArgumentExpressionsForCollectionLiteralCall( private fun getArgumentExpressionsForCollectionLiteralCall(
expression: KtCollectionLiteralExpression, expression: KtCollectionLiteralExpression,
trace: BindingTrace trace: BindingTrace
): Pair<List<KtExpression>, KotlinType?>? { ): List<KtExpression>? {
val resolvedCall = trace[COLLECTION_LITERAL_CALL, expression] ?: return null val resolvedCall = trace[COLLECTION_LITERAL_CALL, expression] ?: return null
return getArgumentExpressionsForArrayLikeCall(resolvedCall) return getArgumentExpressionsForArrayLikeCall(resolvedCall)
} }
private fun getArgumentExpressionsForArrayLikeCall(resolvedCall: ResolvedCall<*>): Pair<List<KtExpression>, KotlinType>? { private fun getArgumentExpressionsForArrayLikeCall(resolvedCall: ResolvedCall<*>): List<KtExpression>? {
if (!CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall)) { if (!CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall)) {
return null return null
} }
val returnType = resolvedCall.resultingDescriptor.returnType ?: return null
val componentType = module.builtIns.getArrayElementType(returnType)
val result = arrayListOf<KtExpression>() val result = arrayListOf<KtExpression>()
for ((_, resolvedValueArgument) in resolvedCall.valueArguments) { for ((_, resolvedValueArgument) in resolvedCall.valueArguments) {
for (valueArgument in resolvedValueArgument.arguments) { for (valueArgument in resolvedValueArgument.arguments) {
@@ -216,7 +193,7 @@ class ConstantExpressionEvaluator(
} }
} }
return Pair<List<KtExpression>, KotlinType>(result, componentType) return result
} }
private fun hasSpread(argument: ResolvedValueArgument): Boolean { private fun hasSpread(argument: ResolvedValueArgument): Boolean {
@@ -240,7 +217,15 @@ class ConstantExpressionEvaluator(
if (constant != null) { if (constant != null) {
constants.add(constant) constants.add(constant)
} }
checkCompileTimeConstant(argumentExpression, expectedType, trace)
val expressionType = trace.getType(argumentExpression) ?: continue
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(expressionType, expectedType)) {
// TYPE_MISMATCH should be reported otherwise
continue
}
checkCompileTimeConstant(argumentExpression, expressionType, trace)
} }
return constants return constants
} }