Refactor: move annotation arguments resolve related utils from AnnotationResolver to ConstantExpressionEvaluator
This commit is contained in:
@@ -17,51 +17,35 @@
|
|||||||
package org.jetbrains.kotlin.resolve;
|
package org.jetbrains.kotlin.resolve;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.intellij.openapi.util.Pair;
|
|
||||||
import kotlin.KotlinPackage;
|
|
||||||
import kotlin.jvm.functions.Function1;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl;
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl;
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.JetAnnotationEntry;
|
||||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver;
|
import org.jetbrains.kotlin.psi.JetModifierList;
|
||||||
|
import org.jetbrains.kotlin.psi.JetTypeParameter;
|
||||||
|
import org.jetbrains.kotlin.psi.JetTypeReference;
|
||||||
import org.jetbrains.kotlin.resolve.calls.CallResolver;
|
import org.jetbrains.kotlin.resolve.calls.CallResolver;
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.CompositeChecker;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.SimpleResolutionContext;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
|
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
|
||||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue;
|
|
||||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
|
||||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant;
|
|
||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
||||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
|
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
|
||||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor;
|
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor;
|
||||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationsContextImpl;
|
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationsContextImpl;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.JetScope;
|
import org.jetbrains.kotlin.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
|
|
||||||
import org.jetbrains.kotlin.storage.StorageManager;
|
import org.jetbrains.kotlin.storage.StorageManager;
|
||||||
import org.jetbrains.kotlin.types.ErrorUtils;
|
import org.jetbrains.kotlin.types.ErrorUtils;
|
||||||
import org.jetbrains.kotlin.types.JetType;
|
import org.jetbrains.kotlin.types.JetType;
|
||||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.diagnostics.Errors.NOT_AN_ANNOTATION_CLASS;
|
import static org.jetbrains.kotlin.diagnostics.Errors.NOT_AN_ANNOTATION_CLASS;
|
||||||
import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
|
import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||||
@@ -210,153 +194,6 @@ public class AnnotationResolver {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static Map<ValueParameterDescriptor, ConstantValue<?>> resolveAnnotationArguments(
|
|
||||||
@NotNull ResolvedCall<?> resolvedCall,
|
|
||||||
@NotNull BindingTrace trace
|
|
||||||
) {
|
|
||||||
Map<ValueParameterDescriptor, ConstantValue<?>> arguments = new HashMap<ValueParameterDescriptor, ConstantValue<?>>();
|
|
||||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> descriptorToArgument : resolvedCall.getValueArguments().entrySet()) {
|
|
||||||
ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey();
|
|
||||||
ResolvedValueArgument resolvedArgument = descriptorToArgument.getValue();
|
|
||||||
|
|
||||||
ConstantValue<?> value = getAnnotationArgumentValue(trace, parameterDescriptor, resolvedArgument);
|
|
||||||
if (value != null) {
|
|
||||||
arguments.put(parameterDescriptor, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return arguments;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static ConstantValue<?> getAnnotationArgumentValue(
|
|
||||||
BindingTrace trace,
|
|
||||||
ValueParameterDescriptor parameterDescriptor,
|
|
||||||
ResolvedValueArgument resolvedArgument
|
|
||||||
) {
|
|
||||||
JetType varargElementType = parameterDescriptor.getVarargElementType();
|
|
||||||
boolean argumentsAsVararg = varargElementType != null && !hasSpread(resolvedArgument);
|
|
||||||
final JetType constantType = argumentsAsVararg ? varargElementType : parameterDescriptor.getType();
|
|
||||||
List<CompileTimeConstant<?>> compileTimeConstants = resolveValueArguments(resolvedArgument, constantType, trace);
|
|
||||||
List<ConstantValue<?>> constants = KotlinPackage.map(compileTimeConstants, new Function1<CompileTimeConstant<?>, ConstantValue<?>>() {
|
|
||||||
@Override
|
|
||||||
public ConstantValue<?> invoke(CompileTimeConstant<?> constant) {
|
|
||||||
return constant.toConstantValue(constantType);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (argumentsAsVararg) {
|
|
||||||
if (parameterDescriptor.declaresDefaultValue() && compileTimeConstants.isEmpty()) return null;
|
|
||||||
|
|
||||||
return new 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 KotlinPackage.lastOrNull(constants);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void checkCompileTimeConstant(
|
|
||||||
@NotNull JetExpression argumentExpression,
|
|
||||||
@NotNull JetType expectedType,
|
|
||||||
@NotNull BindingTrace trace
|
|
||||||
) {
|
|
||||||
JetType 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 instanceof JetCallExpression) {
|
|
||||||
Pair<List<JetExpression>, JetType> arrayArgument = getArgumentExpressionsForArrayCall((JetCallExpression) argumentExpression, trace);
|
|
||||||
if (arrayArgument != null) {
|
|
||||||
for (JetExpression expression : arrayArgument.getFirst()) {
|
|
||||||
checkCompileTimeConstant(expression, arrayArgument.getSecond(), trace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CompileTimeConstant<?> constant = ConstantExpressionEvaluator.getConstant(argumentExpression, trace.getBindingContext());
|
|
||||||
if (constant != null && constant.getCanBeUsedInAnnotations()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassifierDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor();
|
|
||||||
if (descriptor != null && DescriptorUtils.isEnumClass(descriptor)) {
|
|
||||||
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST.on(argumentExpression));
|
|
||||||
}
|
|
||||||
else if (descriptor instanceof ClassDescriptor && KotlinBuiltIns.isKClass((ClassDescriptor) descriptor)) {
|
|
||||||
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL.on(argumentExpression));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CONST.on(argumentExpression));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static Pair<List<JetExpression>, JetType> getArgumentExpressionsForArrayCall(
|
|
||||||
@NotNull JetCallExpression expression,
|
|
||||||
@NotNull BindingTrace trace
|
|
||||||
) {
|
|
||||||
ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, trace.getBindingContext());
|
|
||||||
if (resolvedCall == null || !CompileTimeConstantUtils.isArrayMethodCall(resolvedCall)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert resolvedCall.getValueArguments().size() == 1 : "Array function should have only one vararg parameter";
|
|
||||||
Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> argumentEntry = resolvedCall.getValueArguments().entrySet().iterator().next();
|
|
||||||
|
|
||||||
List<JetExpression> result = Lists.newArrayList();
|
|
||||||
JetType elementType = argumentEntry.getKey().getVarargElementType();
|
|
||||||
for (ValueArgument valueArgument : argumentEntry.getValue().getArguments()) {
|
|
||||||
JetExpression valueArgumentExpression = valueArgument.getArgumentExpression();
|
|
||||||
if (valueArgumentExpression != null) {
|
|
||||||
if (elementType != null) {
|
|
||||||
result.add(valueArgumentExpression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new Pair<List<JetExpression>, JetType>(result, elementType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasSpread(@NotNull ResolvedValueArgument argument) {
|
|
||||||
List<ValueArgument> arguments = argument.getArguments();
|
|
||||||
return arguments.size() == 1 && arguments.get(0).getSpreadElement() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static List<CompileTimeConstant<?>> resolveValueArguments(
|
|
||||||
@NotNull ResolvedValueArgument resolvedValueArgument,
|
|
||||||
@NotNull JetType expectedType,
|
|
||||||
@NotNull BindingTrace trace
|
|
||||||
) {
|
|
||||||
List<CompileTimeConstant<?>> constants = Lists.newArrayList();
|
|
||||||
for (ValueArgument argument : resolvedValueArgument.getArguments()) {
|
|
||||||
JetExpression argumentExpression = argument.getArgumentExpression();
|
|
||||||
if (argumentExpression != null) {
|
|
||||||
CompileTimeConstant<?> constant = ConstantExpressionEvaluator.evaluate(argumentExpression, trace, expectedType);
|
|
||||||
if (constant instanceof IntegerValueTypeConstant) {
|
|
||||||
JetType defaultType = ((IntegerValueTypeConstant) constant).getType(expectedType);
|
|
||||||
SimpleResolutionContext context =
|
|
||||||
new SimpleResolutionContext(trace, JetScope.Empty.INSTANCE$, NO_EXPECTED_TYPE, DataFlowInfo.EMPTY,
|
|
||||||
ContextDependency.INDEPENDENT,
|
|
||||||
new CompositeChecker(Lists.<CallChecker>newArrayList()),
|
|
||||||
SymbolUsageValidator.Empty,
|
|
||||||
new AdditionalTypeChecker.Composite(Lists.<AdditionalTypeChecker>newArrayList()),
|
|
||||||
StatementFilter.NONE);
|
|
||||||
ArgumentTypeResolver.updateNumberType(defaultType, argumentExpression, context);
|
|
||||||
}
|
|
||||||
if (constant != null) {
|
|
||||||
constants.add(constant);
|
|
||||||
}
|
|
||||||
checkCompileTimeConstant(argumentExpression, expectedType, trace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return constants;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void reportUnsupportedAnnotationForTypeParameter(@NotNull JetTypeParameter jetTypeParameter, @NotNull BindingTrace trace) {
|
public static void reportUnsupportedAnnotationForTypeParameter(@NotNull JetTypeParameter jetTypeParameter, @NotNull BindingTrace trace) {
|
||||||
JetModifierList modifierList = jetTypeParameter.getModifierList();
|
JetModifierList modifierList = jetTypeParameter.getModifierList();
|
||||||
if (modifierList == null) return;
|
if (modifierList == null) return;
|
||||||
@@ -365,4 +202,13 @@ public class AnnotationResolver {
|
|||||||
trace.report(Errors.UNSUPPORTED.on(annotationEntry, "Annotations for type parameters are not supported yet"));
|
trace.report(Errors.UNSUPPORTED.on(annotationEntry, "Annotations for type parameters are not supported yet"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public ConstantValue<?> getAnnotationArgumentValue(
|
||||||
|
@NotNull BindingTrace trace,
|
||||||
|
@NotNull ValueParameterDescriptor valueParameter,
|
||||||
|
@NotNull ResolvedValueArgument resolvedArgument
|
||||||
|
) {
|
||||||
|
return ConstantExpressionEvaluator.getAnnotationArgumentValue(trace, valueParameter, resolvedArgument);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+154
-9
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.constants.evaluate
|
package org.jetbrains.kotlin.resolve.constants.evaluate
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.kotlin.JetNodeTypes
|
import org.jetbrains.kotlin.JetNodeTypes
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
@@ -29,19 +30,163 @@ import org.jetbrains.kotlin.lexer.JetTokens
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.resolve.*
|
import org.jetbrains.kotlin.resolve.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.checkers.CompositeChecker
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.context.SimpleResolutionContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
import org.jetbrains.kotlin.resolve.constants.*
|
import org.jetbrains.kotlin.resolve.constants.*
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||||
|
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
|
import java.util.HashMap
|
||||||
import kotlin.platform.platformStatic
|
import kotlin.platform.platformStatic
|
||||||
|
|
||||||
public class ConstantExpressionEvaluator private constructor() {
|
public class ConstantExpressionEvaluator private constructor() {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
platformStatic public fun resolveAnnotationArguments(
|
||||||
|
resolvedCall: ResolvedCall<*>,
|
||||||
|
trace: BindingTrace
|
||||||
|
): Map<ValueParameterDescriptor, ConstantValue<*>> {
|
||||||
|
val arguments = HashMap<ValueParameterDescriptor, ConstantValue<*>>()
|
||||||
|
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<List<JetExpression>, 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<JetExpression>()
|
||||||
|
for (valueArgument in argumentEntry.getValue().getArguments()) {
|
||||||
|
val valueArgumentExpression = valueArgument.getArgumentExpression()
|
||||||
|
if (valueArgumentExpression != null) {
|
||||||
|
result.add(valueArgumentExpression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pair<List<JetExpression>, 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<CompileTimeConstant<*>> {
|
||||||
|
val constants = Lists.newArrayList<CompileTimeConstant<*>>()
|
||||||
|
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<CallChecker>()),
|
||||||
|
SymbolUsageValidator.Empty,
|
||||||
|
AdditionalTypeChecker.Composite(Lists.newArrayList<AdditionalTypeChecker>()),
|
||||||
|
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<*>? {
|
platformStatic public fun evaluate(expression: JetExpression, trace: BindingTrace, expectedType: JetType? = TypeUtils.NO_EXPECTED_TYPE): CompileTimeConstant<*>? {
|
||||||
val visitor = ConstantExpressionEvaluatorVisitor(trace, KotlinBuiltIns.getInstance())
|
val visitor = ConstantExpressionEvaluatorVisitor(trace, KotlinBuiltIns.getInstance())
|
||||||
val constant = visitor.evaluate(expression, expectedType) ?: return null
|
val constant = visitor.evaluate(expression, expectedType) ?: return null
|
||||||
@@ -118,12 +263,12 @@ private class ConstantExpressionEvaluatorVisitor(private val trace: BindingTrace
|
|||||||
if (nodeElementType == JetNodeTypes.NULL) return factory.createNullValue().wrap()
|
if (nodeElementType == JetNodeTypes.NULL) return factory.createNullValue().wrap()
|
||||||
|
|
||||||
val result: Any? = when (nodeElementType) {
|
val result: Any? = when (nodeElementType) {
|
||||||
JetNodeTypes.INTEGER_CONSTANT -> parseLong(text)
|
JetNodeTypes.INTEGER_CONSTANT -> parseLong(text)
|
||||||
JetNodeTypes.FLOAT_CONSTANT -> parseFloatingLiteral(text)
|
JetNodeTypes.FLOAT_CONSTANT -> parseFloatingLiteral(text)
|
||||||
JetNodeTypes.BOOLEAN_CONSTANT -> parseBoolean(text)
|
JetNodeTypes.BOOLEAN_CONSTANT -> parseBoolean(text)
|
||||||
JetNodeTypes.CHARACTER_CONSTANT -> CompileTimeConstantChecker.parseChar(expression)
|
JetNodeTypes.CHARACTER_CONSTANT -> CompileTimeConstantChecker.parseChar(expression)
|
||||||
else -> throw IllegalArgumentException("Unsupported constant: " + expression)
|
else -> throw IllegalArgumentException("Unsupported constant: " + expression)
|
||||||
} ?: return null
|
} ?: return null
|
||||||
|
|
||||||
fun isLongWithSuffix() = nodeElementType == JetNodeTypes.INTEGER_CONSTANT && hasLongSuffix(text)
|
fun isLongWithSuffix() = nodeElementType == JetNodeTypes.INTEGER_CONSTANT && hasLongSuffix(text)
|
||||||
return createConstant(result, expectedType, CompileTimeConstant.Parameters(true, !isLongWithSuffix(), false))
|
return createConstant(result, expectedType, CompileTimeConstant.Parameters(true, !isLongWithSuffix(), false))
|
||||||
@@ -427,7 +572,7 @@ private class ConstantExpressionEvaluatorVisitor(private val trace: BindingTrace
|
|||||||
if (DescriptorUtils.isAnnotationClass(classDescriptor)) {
|
if (DescriptorUtils.isAnnotationClass(classDescriptor)) {
|
||||||
val descriptor = AnnotationDescriptorImpl(
|
val descriptor = AnnotationDescriptorImpl(
|
||||||
classDescriptor.getDefaultType(),
|
classDescriptor.getDefaultType(),
|
||||||
AnnotationResolver.resolveAnnotationArguments(call, trace)
|
ConstantExpressionEvaluator.resolveAnnotationArguments(call, trace)
|
||||||
)
|
)
|
||||||
return AnnotationValue(descriptor).wrap()
|
return AnnotationValue(descriptor).wrap()
|
||||||
}
|
}
|
||||||
@@ -536,7 +681,7 @@ private class ConstantExpressionEvaluatorVisitor(private val trace: BindingTrace
|
|||||||
= TypedCompileTimeConstant(this, parameters)
|
= TypedCompileTimeConstant(this, parameters)
|
||||||
|
|
||||||
private fun <T> ConstantValue<T>.wrap(
|
private fun <T> ConstantValue<T>.wrap(
|
||||||
canBeUsedInAnnotation: Boolean = this !is NullValue,
|
canBeUsedInAnnotation: Boolean = this !is NullValue,
|
||||||
isPure: Boolean = false,
|
isPure: Boolean = false,
|
||||||
usesVariableAsConstant: Boolean = false
|
usesVariableAsConstant: Boolean = false
|
||||||
): TypedCompileTimeConstant<T>
|
): TypedCompileTimeConstant<T>
|
||||||
|
|||||||
+2
-5
@@ -21,10 +21,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.JetAnnotationEntry
|
import org.jetbrains.kotlin.psi.JetAnnotationEntry
|
||||||
import org.jetbrains.kotlin.resolve.AnnotationResolver
|
import org.jetbrains.kotlin.resolve.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|
||||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
||||||
import org.jetbrains.kotlin.resolve.lazy.LazyEntity
|
import org.jetbrains.kotlin.resolve.lazy.LazyEntity
|
||||||
@@ -119,7 +116,7 @@ public class LazyAnnotationDescriptor(
|
|||||||
return resolutionResults.getResultingCall().getValueArguments()
|
return resolutionResults.getResultingCall().getValueArguments()
|
||||||
.mapValues { val (valueParameter, resolvedArgument) = it;
|
.mapValues { val (valueParameter, resolvedArgument) = it;
|
||||||
if (resolvedArgument == null) null
|
if (resolvedArgument == null) null
|
||||||
else AnnotationResolver.getAnnotationArgumentValue(c.trace, valueParameter, resolvedArgument)
|
else c.annotationResolver.getAnnotationArgumentValue(c.trace, valueParameter, resolvedArgument)
|
||||||
}
|
}
|
||||||
.filterValues { it != null } as Map<ValueParameterDescriptor, ConstantValue<*>>
|
.filterValues { it != null } as Map<ValueParameterDescriptor, ConstantValue<*>>
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user