Rewrite evaluator to kotlin. Small refactoring
This commit is contained in:
+1
-1
@@ -114,7 +114,7 @@ public class TraceBasedJavaResolverCache implements JavaResolverCache {
|
|||||||
PsiField psiField = ((JavaFieldImpl) field).getPsi();
|
PsiField psiField = ((JavaFieldImpl) field).getPsi();
|
||||||
trace.record(VARIABLE, psiField, descriptor);
|
trace.record(VARIABLE, psiField, descriptor);
|
||||||
|
|
||||||
if (AnnotationUtils.isPropertyAcceptableAsAnnotationParameter(descriptor)) {
|
if (AnnotationUtils.isPropertyCompileTimeConstant(descriptor)) {
|
||||||
PsiExpression initializer = psiField.getInitializer();
|
PsiExpression initializer = psiField.getInitializer();
|
||||||
if (initializer instanceof PsiLiteralExpression) {
|
if (initializer instanceof PsiLiteralExpression) {
|
||||||
CompileTimeConstant<?> constant = JavaAnnotationArgumentResolver
|
CompileTimeConstant<?> constant = JavaAnnotationArgumentResolver
|
||||||
|
|||||||
-496
@@ -1,496 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2013 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.jet.lang.evaluate;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.intellij.psi.tree.IElementType;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptorImpl;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
|
||||||
import org.jetbrains.jet.lang.resolve.*;
|
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
|
||||||
import org.jetbrains.jet.lang.resolve.constants.*;
|
|
||||||
import org.jetbrains.jet.lang.resolve.constants.StringValue;
|
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
|
||||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.resolve.BindingContext.COMPILE_TIME_INITIALIZER;
|
|
||||||
|
|
||||||
@SuppressWarnings("StaticMethodReferencedViaSubclass")
|
|
||||||
public class ConstantExpressionEvaluator extends JetVisitor<CompileTimeConstant<?>, Void> {
|
|
||||||
private final BindingTrace trace;
|
|
||||||
private final JetType expectedType;
|
|
||||||
|
|
||||||
private ConstantExpressionEvaluator(@NotNull BindingTrace trace, @NotNull JetType expectedType) {
|
|
||||||
this.trace = trace;
|
|
||||||
this.expectedType = expectedType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static CompileTimeConstant<?> evaluate(@NotNull JetExpression expression, @NotNull BindingTrace trace, @NotNull JetType expectedType) {
|
|
||||||
ConstantExpressionEvaluator evaluator = new ConstantExpressionEvaluator(trace, expectedType);
|
|
||||||
return evaluator.evaluate(expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public CompileTimeConstant<?> evaluate(@NotNull JetExpression expression) {
|
|
||||||
CompileTimeConstant<?> recordedCompileTimeConstant = trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
|
|
||||||
if (recordedCompileTimeConstant != null) {
|
|
||||||
return recordedCompileTimeConstant;
|
|
||||||
}
|
|
||||||
|
|
||||||
CompileTimeConstant<?> compileTimeConstant = expression.accept(this, null);
|
|
||||||
|
|
||||||
if (compileTimeConstant != null) {
|
|
||||||
trace.record(BindingContext.COMPILE_TIME_VALUE, expression, compileTimeConstant);
|
|
||||||
return compileTimeConstant;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompileTimeConstant<?> visitConstantExpression(@NotNull JetConstantExpression expression, Void data) {
|
|
||||||
return trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompileTimeConstant<?> visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression, Void data) {
|
|
||||||
JetExpression deparenthesizedExpression = getDeparenthesizedExpression(expression);
|
|
||||||
if (deparenthesizedExpression != null) {
|
|
||||||
return evaluate(deparenthesizedExpression);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompileTimeConstant<?> visitPrefixExpression(@NotNull JetPrefixExpression expression, Void data) {
|
|
||||||
JetExpression deparenthesizedExpression = getDeparenthesizedExpression(expression);
|
|
||||||
if (deparenthesizedExpression != null) {
|
|
||||||
return evaluate(deparenthesizedExpression);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static JetExpression getDeparenthesizedExpression(JetExpression expression) {
|
|
||||||
JetExpression deparenthesizedExpr = JetPsiUtil.deparenthesize(expression);
|
|
||||||
if (deparenthesizedExpr == expression) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return deparenthesizedExpr;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompileTimeConstant<?> visitStringTemplateExpression(@NotNull JetStringTemplateExpression expression, Void data) {
|
|
||||||
JetStringTemplateEntry[] stringTemplateEntries = expression.getEntries();
|
|
||||||
if (stringTemplateEntries.length == 1) {
|
|
||||||
CompileTimeConstant singleEntry = stringTemplateEntries[0].accept(this, null);
|
|
||||||
if (!(singleEntry instanceof StringValue) && singleEntry != null) {
|
|
||||||
return new StringValue(singleEntry.getValue().toString());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return singleEntry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (stringTemplateEntries.length > 1) {
|
|
||||||
CompileTimeConstant<?> first = stringTemplateEntries[0].accept(this, null);
|
|
||||||
if (first == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
CompileTimeConstant<?> second;
|
|
||||||
String tmpResult = null;
|
|
||||||
for (int i = 1; i < stringTemplateEntries.length; i++) {
|
|
||||||
second = stringTemplateEntries[i].accept(this, null);
|
|
||||||
if (second == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Object object = EvaluatePackage.evaluateBinaryExpression(first, second, Name.identifier("plus"));
|
|
||||||
if (object instanceof String) {
|
|
||||||
tmpResult = (String) object;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tmpResult = object.toString();
|
|
||||||
}
|
|
||||||
first = new StringValue(tmpResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new StringValue(tmpResult);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompileTimeConstant<?> visitStringTemplateEntryWithExpression(@NotNull JetStringTemplateEntryWithExpression entry, Void data) {
|
|
||||||
JetExpression expression = entry.getExpression();
|
|
||||||
if (expression != null) {
|
|
||||||
return evaluate(expression);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompileTimeConstant<?> visitLiteralStringTemplateEntry(@NotNull JetLiteralStringTemplateEntry entry, Void data) {
|
|
||||||
return new StringValue(entry.getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompileTimeConstant<?> visitEscapeStringTemplateEntry(@NotNull JetEscapeStringTemplateEntry entry, Void data) {
|
|
||||||
return new StringValue(entry.getUnescapedValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompileTimeConstant<?> visitBinaryExpression(@NotNull JetBinaryExpression expression, Void data) {
|
|
||||||
JetExpression leftExpression = expression.getLeft();
|
|
||||||
if (leftExpression == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
IElementType operationToken = expression.getOperationToken();
|
|
||||||
if (OperatorConventions.BOOLEAN_OPERATIONS.containsKey(operationToken)) {
|
|
||||||
JetType booleanType = KotlinBuiltIns.getInstance().getBooleanType();
|
|
||||||
CompileTimeConstant<?> leftConstant = evaluate(leftExpression, trace, booleanType);
|
|
||||||
if (leftConstant == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
JetExpression rightExpression = expression.getRight();
|
|
||||||
if (rightExpression == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
CompileTimeConstant<?> rightConstant = evaluate(rightExpression, trace, booleanType);
|
|
||||||
if (rightConstant == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Name operationName = operationToken == JetTokens.ANDAND ? Name.identifier("andand") : Name.identifier("oror");
|
|
||||||
Object result = EvaluatePackage.evaluateBinaryExpression(leftConstant, rightConstant, operationName);
|
|
||||||
return createCompileTimeConstant(result, expectedType);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Object result = evaluateCall(expression.getOperationReference(), leftExpression);
|
|
||||||
if (OperatorConventions.COMPARISON_OPERATIONS.contains(operationToken)) {
|
|
||||||
return createCompileTimeConstantForCompareTo(result, operationToken);
|
|
||||||
}
|
|
||||||
else if (OperatorConventions.EQUALS_OPERATIONS.contains(operationToken)) {
|
|
||||||
return createCompileTimeConstantForEquals(result, operationToken);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return createCompileTimeConstant(result, expectedType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Object evaluateCall(@NotNull JetExpression resolvedCallExpression, @NotNull JetExpression receiverExpression) {
|
|
||||||
ResolvedCall<?> resolvedCall = trace.getBindingContext().get(BindingContext.RESOLVED_CALL, resolvedCallExpression);
|
|
||||||
if (resolvedCall != null) {
|
|
||||||
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
|
|
||||||
JetType receiverExpressionType = getReceiverExpressionType(resolvedCall);
|
|
||||||
if (receiverExpressionType == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ConstantExpressionEvaluator evaluator = new ConstantExpressionEvaluator(trace, receiverExpressionType);
|
|
||||||
CompileTimeConstant<?> receiverValue = receiverExpression.accept(evaluator, null);
|
|
||||||
if (receiverValue == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
List<CompileTimeConstant<?>> arguments = Lists.newArrayList();
|
|
||||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> argumentEntry : resolvedCall.getValueArguments().entrySet()) {
|
|
||||||
arguments.addAll(resolveArguments(argumentEntry.getValue().getArguments(), argumentEntry.getKey().getType(), trace));
|
|
||||||
}
|
|
||||||
Name resultingDescriptorName = resultingDescriptor.getName();
|
|
||||||
if (arguments.isEmpty()) {
|
|
||||||
return EvaluatePackage.evaluateUnaryExpression(receiverValue, resultingDescriptorName);
|
|
||||||
}
|
|
||||||
else if (arguments.size() == 1) {
|
|
||||||
return EvaluatePackage.evaluateBinaryExpression(receiverValue, arguments.iterator().next(), resultingDescriptorName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static CompileTimeConstant<?> createCompileTimeConstantForEquals(
|
|
||||||
@Nullable Object result,
|
|
||||||
@NotNull IElementType operationToken
|
|
||||||
) {
|
|
||||||
if (result instanceof Boolean) {
|
|
||||||
boolean resultCode = ((Boolean) result).booleanValue();
|
|
||||||
if (operationToken == JetTokens.EQEQ) {
|
|
||||||
return resultCode ? BooleanValue.TRUE : BooleanValue.FALSE;
|
|
||||||
}
|
|
||||||
else if (operationToken == JetTokens.EXCLEQ) {
|
|
||||||
return resultCode ? BooleanValue.FALSE : BooleanValue.TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static CompileTimeConstant<?> createCompileTimeConstantForCompareTo(
|
|
||||||
@Nullable Object result,
|
|
||||||
@NotNull IElementType operationToken
|
|
||||||
) {
|
|
||||||
if (result instanceof Integer) {
|
|
||||||
int resultCode = ((Integer) result).intValue();
|
|
||||||
if (resultCode == 0) {
|
|
||||||
if (operationToken == JetTokens.EQEQ ||
|
|
||||||
operationToken == JetTokens.LTEQ ||
|
|
||||||
operationToken == JetTokens.GTEQ) {
|
|
||||||
return BooleanValue.TRUE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return BooleanValue.FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (resultCode == 1) {
|
|
||||||
if (operationToken == JetTokens.GT ||
|
|
||||||
operationToken == JetTokens.GTEQ) {
|
|
||||||
return BooleanValue.TRUE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return BooleanValue.FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (resultCode == -1) {
|
|
||||||
if (operationToken == JetTokens.LT ||
|
|
||||||
operationToken == JetTokens.LTEQ) {
|
|
||||||
return BooleanValue.TRUE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return BooleanValue.FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompileTimeConstant<?> visitUnaryExpression(@NotNull JetUnaryExpression expression, Void data) {
|
|
||||||
JetExpression leftExpression = expression.getBaseExpression();
|
|
||||||
if (leftExpression == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Object result = evaluateCall(expression.getOperationReference(), leftExpression);
|
|
||||||
return createCompileTimeConstant(result, expectedType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static CompileTimeConstant<?> createCompileTimeConstant(@Nullable Object value, @NotNull JetType expectedType) {
|
|
||||||
if (value == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else if (value instanceof Integer) {
|
|
||||||
return getIntegerValue(((Integer) value).longValue(), expectedType);
|
|
||||||
}
|
|
||||||
else if (value instanceof Byte) {
|
|
||||||
return getIntegerValue(((Byte) value).longValue(), expectedType);
|
|
||||||
}
|
|
||||||
else if (value instanceof Short) {
|
|
||||||
return getIntegerValue(((Short) value).longValue(), expectedType);
|
|
||||||
}
|
|
||||||
else if (value instanceof Long) {
|
|
||||||
return new LongValue((Long) value);
|
|
||||||
}
|
|
||||||
else if (value instanceof Float) {
|
|
||||||
if (CompileTimeConstantResolver.noExpectedTypeOrError(expectedType) ||
|
|
||||||
expectedType.equals(KotlinBuiltIns.getInstance().getDoubleType())) {
|
|
||||||
return new DoubleValue(((Float) value).doubleValue());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return new FloatValue((Float) value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (value instanceof Double) {
|
|
||||||
return new DoubleValue((Double) value);
|
|
||||||
}
|
|
||||||
else if (value instanceof Boolean) {
|
|
||||||
return ((Boolean) value) ? BooleanValue.TRUE : BooleanValue.FALSE;
|
|
||||||
}
|
|
||||||
else if (value instanceof Character) {
|
|
||||||
return new CharValue((Character) value);
|
|
||||||
}
|
|
||||||
else if (value instanceof String) {
|
|
||||||
return new StringValue((String) value);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static CompileTimeConstant<?> getIntegerValue(@NotNull Long value, @NotNull JetType expectedType) {
|
|
||||||
if (CompileTimeConstantResolver.noExpectedTypeOrError(expectedType)) {
|
|
||||||
if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) {
|
|
||||||
return new IntValue(value.intValue());
|
|
||||||
}
|
|
||||||
return new LongValue(value);
|
|
||||||
}
|
|
||||||
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
|
|
||||||
if (expectedType.equals(builtIns.getIntType())) {
|
|
||||||
return new IntValue(value.intValue());
|
|
||||||
}
|
|
||||||
else if (expectedType.equals(builtIns.getLongType())) {
|
|
||||||
return new LongValue(value);
|
|
||||||
}
|
|
||||||
else if (expectedType.equals(builtIns.getShortType())) {
|
|
||||||
if (Short.MIN_VALUE <= value && value <= Short.MAX_VALUE) {
|
|
||||||
return new ShortValue(value.shortValue());
|
|
||||||
}
|
|
||||||
else if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) {
|
|
||||||
return new IntValue(value.intValue());
|
|
||||||
}
|
|
||||||
return new LongValue(value);
|
|
||||||
}
|
|
||||||
else if (expectedType.equals(builtIns.getByteType())) {
|
|
||||||
if (Byte.MIN_VALUE <= value && value <= Byte.MAX_VALUE) {
|
|
||||||
return new ByteValue(value.byteValue());
|
|
||||||
}
|
|
||||||
else if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) {
|
|
||||||
return new IntValue(value.intValue());
|
|
||||||
}
|
|
||||||
return new LongValue(value);
|
|
||||||
}
|
|
||||||
else if (expectedType.equals(builtIns.getCharType())) {
|
|
||||||
return new IntValue(value.intValue());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompileTimeConstant<?> visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression, Void data) {
|
|
||||||
DeclarationDescriptor descriptor = trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, expression);
|
|
||||||
if (descriptor != null && DescriptorUtils.isEnumEntry(descriptor)) {
|
|
||||||
return new EnumValue((ClassDescriptor) descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResolvedCall<? extends CallableDescriptor> resolvedCall =
|
|
||||||
trace.getBindingContext().get(BindingContext.RESOLVED_CALL, expression);
|
|
||||||
if (resolvedCall != null) {
|
|
||||||
CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor();
|
|
||||||
if (callableDescriptor instanceof PropertyDescriptor) {
|
|
||||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) callableDescriptor;
|
|
||||||
if (AnnotationUtils.isPropertyAcceptableAsAnnotationParameter(propertyDescriptor)) {
|
|
||||||
return trace.getBindingContext().get(COMPILE_TIME_INITIALIZER, propertyDescriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 1.toInt(); 1.plus(1); MyEnum.A */
|
|
||||||
@Override
|
|
||||||
public CompileTimeConstant<?> visitQualifiedExpression(@NotNull JetQualifiedExpression expression, Void data) {
|
|
||||||
JetExpression receiverExpression = expression.getReceiverExpression();
|
|
||||||
JetExpression selectorExpression = expression.getSelectorExpression();
|
|
||||||
|
|
||||||
|
|
||||||
if (selectorExpression instanceof JetCallExpression) {
|
|
||||||
JetExpression calleeExpression = ((JetCallExpression) selectorExpression).getCalleeExpression();
|
|
||||||
if (!(calleeExpression instanceof JetSimpleNameExpression)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((JetCallExpression) selectorExpression).getValueArguments().size() < 2) {
|
|
||||||
Object result = evaluateCall(calleeExpression, receiverExpression);
|
|
||||||
return createCompileTimeConstant(result, expectedType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectorExpression != null) {
|
|
||||||
return evaluate(selectorExpression);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static JetType getReceiverExpressionType(ResolvedCall<? extends CallableDescriptor> resolvedCall) {
|
|
||||||
switch(resolvedCall.getExplicitReceiverKind()) {
|
|
||||||
case THIS_OBJECT: return resolvedCall.getThisObject().getType();
|
|
||||||
case RECEIVER_ARGUMENT: return resolvedCall.getReceiverArgument().getType();
|
|
||||||
case NO_EXPLICIT_RECEIVER: return null;
|
|
||||||
case BOTH_RECEIVERS: return null;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompileTimeConstant<?> visitCallExpression(@NotNull JetCallExpression expression, Void data) {
|
|
||||||
ResolvedCall<? extends CallableDescriptor> call =
|
|
||||||
trace.getBindingContext().get(BindingContext.RESOLVED_CALL, (expression).getCalleeExpression());
|
|
||||||
if (call != null) {
|
|
||||||
CallableDescriptor resultingDescriptor = call.getResultingDescriptor();
|
|
||||||
if (AnnotationUtils.isArrayMethodCall(call)) {
|
|
||||||
JetType type = resultingDescriptor.getValueParameters().iterator().next().getVarargElementType();
|
|
||||||
List<CompileTimeConstant<?>> arguments = Lists.newArrayList();
|
|
||||||
for (ResolvedValueArgument descriptorToArgument : call.getValueArguments().values()) {
|
|
||||||
arguments.addAll(resolveArguments(descriptorToArgument.getArguments(), type, trace));
|
|
||||||
}
|
|
||||||
return new ArrayValue(arguments, resultingDescriptor.getReturnType());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resultingDescriptor instanceof ConstructorDescriptor) {
|
|
||||||
JetType constructorReturnType = resultingDescriptor.getReturnType();
|
|
||||||
assert constructorReturnType != null : "Constructor should have return type";
|
|
||||||
if (DescriptorUtils.isAnnotationClass(constructorReturnType.getConstructor().getDeclarationDescriptor())) {
|
|
||||||
AnnotationDescriptorImpl descriptor = new AnnotationDescriptorImpl();
|
|
||||||
descriptor.setAnnotationType(constructorReturnType);
|
|
||||||
AnnotationResolver.resolveAnnotationArgument(descriptor, call, trace);
|
|
||||||
return new AnnotationValue(descriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AnnotationUtils.isJavaClassMethodCall(call)) {
|
|
||||||
return new JavaClassValue(resultingDescriptor.getReturnType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static List<CompileTimeConstant<?>> resolveArguments(
|
|
||||||
@NotNull List<ValueArgument> valueArguments,
|
|
||||||
@NotNull JetType expectedType,
|
|
||||||
@NotNull BindingTrace trace
|
|
||||||
) {
|
|
||||||
List<CompileTimeConstant<?>> constants = Lists.newArrayList();
|
|
||||||
for (ValueArgument argument : valueArguments) {
|
|
||||||
JetExpression argumentExpression = argument.getArgumentExpression();
|
|
||||||
if (argumentExpression != null) {
|
|
||||||
CompileTimeConstant<?> constant = evaluate(argumentExpression, trace, expectedType);
|
|
||||||
if (constant != null) {
|
|
||||||
constants.add(constant);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return constants;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompileTimeConstant<?> visitJetElement(@NotNull JetElement element, Void data) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,407 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2013 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.jet.lang.evaluate
|
||||||
|
|
||||||
|
import com.intellij.psi.tree.IElementType
|
||||||
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptorImpl
|
||||||
|
import org.jetbrains.jet.lang.descriptors.*
|
||||||
|
import org.jetbrains.jet.lang.psi.*
|
||||||
|
import org.jetbrains.jet.lang.resolve.*
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
|
||||||
|
import org.jetbrains.jet.lang.resolve.constants.*
|
||||||
|
import org.jetbrains.jet.lang.resolve.name.Name
|
||||||
|
import org.jetbrains.jet.lang.types.JetType
|
||||||
|
import org.jetbrains.jet.lang.types.expressions.OperatorConventions
|
||||||
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
||||||
|
import org.jetbrains.jet.lexer.JetTokens
|
||||||
|
import org.jetbrains.jet.lang.resolve.BindingContext.COMPILE_TIME_INITIALIZER
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
|
import org.jetbrains.jet.lang.types.TypeUtils
|
||||||
|
import java.lang.Short as JShort
|
||||||
|
import java.lang.Byte as JByte
|
||||||
|
|
||||||
|
[suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")]
|
||||||
|
public class ConstantExpressionEvaluator private (val trace: BindingTrace) : JetVisitor<CompileTimeConstant<*>, JetType>() {
|
||||||
|
|
||||||
|
public fun evaluate(expression: JetExpression, expectedType: JetType?): CompileTimeConstant<*>? {
|
||||||
|
val recordedCompileTimeConstant = trace.get(BindingContext.COMPILE_TIME_VALUE, expression)
|
||||||
|
if (recordedCompileTimeConstant != null) {
|
||||||
|
return recordedCompileTimeConstant
|
||||||
|
}
|
||||||
|
|
||||||
|
val compileTimeConstant = expression.accept(this, expectedType ?: TypeUtils.NO_EXPECTED_TYPE)
|
||||||
|
if (compileTimeConstant != null) {
|
||||||
|
trace.record(BindingContext.COMPILE_TIME_VALUE, expression, compileTimeConstant)
|
||||||
|
return compileTimeConstant
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitConstantExpression(expression: JetConstantExpression, expectedType: JetType?): CompileTimeConstant<*>? {
|
||||||
|
return trace.get(BindingContext.COMPILE_TIME_VALUE, expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitParenthesizedExpression(expression: JetParenthesizedExpression, expectedType: JetType?): CompileTimeConstant<*>? {
|
||||||
|
val deparenthesizedExpression = getDeparenthesizedExpression(expression)
|
||||||
|
if (deparenthesizedExpression != null) {
|
||||||
|
return evaluate(deparenthesizedExpression, expectedType)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitPrefixExpression(expression: JetPrefixExpression, expectedType: JetType?): CompileTimeConstant<*>? {
|
||||||
|
val deparenthesizedExpression = getDeparenthesizedExpression(expression)
|
||||||
|
return if (deparenthesizedExpression != null) {
|
||||||
|
evaluate(deparenthesizedExpression, expectedType)
|
||||||
|
} else {
|
||||||
|
super.visitPrefixExpression(expression, expectedType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitStringTemplateExpression(expression: JetStringTemplateExpression, expectedType: JetType?): CompileTimeConstant<*>? {
|
||||||
|
val stringTemplateEntries = expression.getEntries()
|
||||||
|
if (stringTemplateEntries.size == 1) {
|
||||||
|
return stringTemplateEntries[0].accept(this, null)
|
||||||
|
}
|
||||||
|
else if (stringTemplateEntries.size > 1) {
|
||||||
|
return stringTemplateEntries.fold(StringValue(""): CompileTimeConstant<*>?) {
|
||||||
|
f, s ->
|
||||||
|
if (f != null) {
|
||||||
|
val second = s.accept(this, null)
|
||||||
|
if (second == null) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
createCompileTimeConstant(evaluateBinaryExpression(f, second, Name.identifier("plus")), expectedType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitStringTemplateEntryWithExpression(entry: JetStringTemplateEntryWithExpression, expectedType: JetType?): CompileTimeConstant<*>? {
|
||||||
|
val expression = entry.getExpression()
|
||||||
|
if (expression != null) {
|
||||||
|
return createStringConstant(evaluate(expression, expectedType))
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLiteralStringTemplateEntry(entry: JetLiteralStringTemplateEntry, expectedType: JetType?) = StringValue(entry.getText())
|
||||||
|
|
||||||
|
override fun visitEscapeStringTemplateEntry(entry: JetEscapeStringTemplateEntry, expectedType: JetType?) = StringValue(entry.getUnescapedValue())
|
||||||
|
|
||||||
|
override fun visitBinaryExpression(expression: JetBinaryExpression, expectedType: JetType?): CompileTimeConstant<*>? {
|
||||||
|
val leftExpression = expression.getLeft()
|
||||||
|
if (leftExpression == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val operationToken = expression.getOperationToken()
|
||||||
|
if (OperatorConventions.BOOLEAN_OPERATIONS.containsKey(operationToken)) {
|
||||||
|
val booleanType = KotlinBuiltIns.getInstance().getBooleanType()
|
||||||
|
val leftConstant = evaluate(leftExpression, booleanType)
|
||||||
|
if (leftConstant == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val rightExpression = expression.getRight()
|
||||||
|
if (rightExpression == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val rightConstant = evaluate(rightExpression, booleanType)
|
||||||
|
if (rightConstant == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val operationName = when(operationToken) {
|
||||||
|
JetTokens.ANDAND -> Name.identifier("&&")
|
||||||
|
JetTokens.OROR -> Name.identifier("||")
|
||||||
|
else -> throw IllegalArgumentException("Unknown boolean operation token ${operationToken}")
|
||||||
|
}
|
||||||
|
val result = evaluateBinaryExpression(leftConstant, rightConstant, operationName)
|
||||||
|
return createCompileTimeConstant(result, expectedType)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val result = evaluateCall(expression.getOperationReference(), leftExpression)
|
||||||
|
return when(operationToken) {
|
||||||
|
in OperatorConventions.COMPARISON_OPERATIONS -> createCompileTimeConstantForCompareTo(result, operationToken!!)
|
||||||
|
in OperatorConventions.EQUALS_OPERATIONS -> createCompileTimeConstantForEquals(result, operationToken!!)
|
||||||
|
else -> createCompileTimeConstant(result, expectedType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun evaluateCall(callExpression: JetExpression, receiverExpression: JetExpression): Any? {
|
||||||
|
val resolvedCall = trace.getBindingContext().get(BindingContext.RESOLVED_CALL, callExpression)
|
||||||
|
if (resolvedCall != null) {
|
||||||
|
val resultingDescriptor = resolvedCall.getResultingDescriptor()
|
||||||
|
// TODO getResultingDescriptor has NotNull annotation
|
||||||
|
if (resultingDescriptor == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val receiverExpressionType = getReceiverExpressionType(resolvedCall)
|
||||||
|
if (receiverExpressionType == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val receiverValue = evaluate(receiverExpression, receiverExpressionType)
|
||||||
|
if (receiverValue == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val arguments = resolvedCall.getValueArguments().entrySet().flatMap {
|
||||||
|
entry -> val (parameter, argument) = entry
|
||||||
|
resolveArguments(argument.getArguments(), parameter.getType())
|
||||||
|
}
|
||||||
|
|
||||||
|
val resultingDescriptorName = resultingDescriptor.getName()
|
||||||
|
if (arguments.isEmpty()) {
|
||||||
|
return evaluateUnaryExpression(receiverValue, resultingDescriptorName)
|
||||||
|
}
|
||||||
|
else if (arguments.size() == 1) {
|
||||||
|
return evaluateBinaryExpression(receiverValue, arguments.first!!, resultingDescriptorName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitUnaryExpression(expression: JetUnaryExpression, expectedType: JetType?): CompileTimeConstant<*>? {
|
||||||
|
val leftExpression = expression.getBaseExpression()
|
||||||
|
if (leftExpression == null) return null
|
||||||
|
|
||||||
|
val result = evaluateCall(expression.getOperationReference(), leftExpression)
|
||||||
|
return createCompileTimeConstant(result, expectedType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression, expectedType: JetType?): CompileTimeConstant<*>? {
|
||||||
|
val enumDescriptor = trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, expression);
|
||||||
|
if (enumDescriptor != null && DescriptorUtils.isEnumEntry(enumDescriptor)) {
|
||||||
|
return EnumValue(enumDescriptor as ClassDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
val resolvedCall = trace.getBindingContext().get(BindingContext.RESOLVED_CALL, expression)
|
||||||
|
if (resolvedCall != null) {
|
||||||
|
val callableDescriptor = resolvedCall.getResultingDescriptor()
|
||||||
|
if (callableDescriptor is PropertyDescriptor) {
|
||||||
|
if (AnnotationUtils.isPropertyCompileTimeConstant(callableDescriptor)) {
|
||||||
|
return trace.getBindingContext().get(COMPILE_TIME_INITIALIZER, callableDescriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 1.toInt(); 1.plus(1); MyEnum.A */
|
||||||
|
override fun visitQualifiedExpression(expression: JetQualifiedExpression, expectedType: JetType?): CompileTimeConstant<*>? {
|
||||||
|
val selectorExpression = expression.getSelectorExpression()
|
||||||
|
if (selectorExpression is JetCallExpression) {
|
||||||
|
val calleeExpression = selectorExpression.getCalleeExpression()
|
||||||
|
if (calleeExpression !is JetSimpleNameExpression) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val receiverExpression = expression.getReceiverExpression()
|
||||||
|
val result = evaluateCall(calleeExpression, receiverExpression)
|
||||||
|
return createCompileTimeConstant(result, expectedType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
if (selectorExpression != null) {
|
||||||
|
return evaluate(selectorExpression, expectedType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCallExpression(expression: JetCallExpression, expectedType: JetType?): CompileTimeConstant<*>? {
|
||||||
|
val call = trace.getBindingContext().get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression())
|
||||||
|
if (call != null) {
|
||||||
|
val resultingDescriptor = call.getResultingDescriptor()
|
||||||
|
if (resultingDescriptor != null) {
|
||||||
|
if (AnnotationUtils.isArrayMethodCall(call)) {
|
||||||
|
val varargType = resultingDescriptor.getValueParameters().first?.getVarargElementType()!!
|
||||||
|
|
||||||
|
//todo flatmap
|
||||||
|
val arguments = arrayListOf<CompileTimeConstant<*>>()
|
||||||
|
for (descriptorToArgument in call.getValueArguments().values()) {
|
||||||
|
arguments.addAll(resolveArguments(descriptorToArgument.getArguments(), varargType))
|
||||||
|
}
|
||||||
|
return ArrayValue(arguments, resultingDescriptor.getReturnType()!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ann()
|
||||||
|
if (resultingDescriptor is ConstructorDescriptor) {
|
||||||
|
val constructorReturnType = resultingDescriptor.getReturnType()
|
||||||
|
if (DescriptorUtils.isAnnotationClass(resultingDescriptor.getContainingDeclaration())) {
|
||||||
|
val descriptor = AnnotationDescriptorImpl()
|
||||||
|
descriptor.setAnnotationType(constructorReturnType)
|
||||||
|
AnnotationResolver.resolveAnnotationArgument(descriptor, call, trace)
|
||||||
|
return AnnotationValue(descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AnnotationUtils.isJavaClassMethodCall(call)) {
|
||||||
|
return JavaClassValue(resultingDescriptor.getReturnType())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resolveArguments(valueArguments: List<ValueArgument>, expectedType: JetType): List<CompileTimeConstant<*>> {
|
||||||
|
//todo flatMap
|
||||||
|
val constants = arrayListOf<CompileTimeConstant<*>>()
|
||||||
|
for (argument in valueArguments) {
|
||||||
|
val argumentExpression = argument.getArgumentExpression()
|
||||||
|
if (argumentExpression != null) {
|
||||||
|
val constant = evaluate(argumentExpression, expectedType)
|
||||||
|
if (constant != null) {
|
||||||
|
constants.add(constant)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return constants
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitJetElement(element: JetElement, expectedType: JetType?): CompileTimeConstant<*>? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
class object {
|
||||||
|
public fun evaluate(expression: JetExpression, trace: BindingTrace, expectedType: JetType? = TypeUtils.NO_EXPECTED_TYPE): CompileTimeConstant<*>? {
|
||||||
|
val evaluator = ConstantExpressionEvaluator(trace)
|
||||||
|
return evaluator.evaluate(expression, expectedType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDeparenthesizedExpression(expression: JetExpression): JetExpression? {
|
||||||
|
val deparenthesizedExpr = JetPsiUtil.deparenthesize(expression)
|
||||||
|
if (deparenthesizedExpr == expression) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return deparenthesizedExpr
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCompileTimeConstantForEquals(result: Any?, operationToken: IElementType): CompileTimeConstant<*>? {
|
||||||
|
if (result is Boolean) {
|
||||||
|
return when (operationToken) {
|
||||||
|
JetTokens.EQEQ -> if (result) BooleanValue.TRUE else BooleanValue.FALSE
|
||||||
|
JetTokens.EXCLEQ -> if (result) BooleanValue.FALSE else BooleanValue.TRUE
|
||||||
|
else -> throw IllegalStateException("Unknown equals operation token: $operationToken")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCompileTimeConstantForCompareTo(result: Any?, operationToken: IElementType): CompileTimeConstant<*>? {
|
||||||
|
if (result is Int) {
|
||||||
|
return when (result) {
|
||||||
|
-1 -> when (operationToken) {
|
||||||
|
JetTokens.LT -> BooleanValue.TRUE
|
||||||
|
JetTokens.LTEQ -> BooleanValue.TRUE
|
||||||
|
else -> BooleanValue.FALSE
|
||||||
|
}
|
||||||
|
0 -> when (operationToken) {
|
||||||
|
JetTokens.LTEQ -> BooleanValue.TRUE
|
||||||
|
JetTokens.GTEQ -> BooleanValue.TRUE
|
||||||
|
else -> BooleanValue.FALSE
|
||||||
|
}
|
||||||
|
1 -> when (operationToken) {
|
||||||
|
JetTokens.GT -> BooleanValue.TRUE
|
||||||
|
JetTokens.GTEQ -> BooleanValue.TRUE
|
||||||
|
else -> BooleanValue.FALSE
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createStringConstant(value: CompileTimeConstant<*>?): CompileTimeConstant<*>? {
|
||||||
|
return when (value) {
|
||||||
|
null -> null
|
||||||
|
is StringValue -> value
|
||||||
|
else -> StringValue(value.getValue().toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCompileTimeConstant(value: Any?, expectedType: JetType?): CompileTimeConstant<*>? {
|
||||||
|
return when(value) {
|
||||||
|
null -> null
|
||||||
|
is Byte, is Short, is Int, is Long -> getIntegerValue((value as Number).toLong(), expectedType ?: TypeUtils.NO_EXPECTED_TYPE)
|
||||||
|
is Char -> CharValue(value)
|
||||||
|
is Float -> if (CompileTimeConstantResolver.noExpectedTypeOrError(expectedType) ||
|
||||||
|
expectedType == KotlinBuiltIns.getInstance().getDoubleType()) DoubleValue(value.toDouble())
|
||||||
|
else FloatValue(value)
|
||||||
|
is Double -> DoubleValue(value)
|
||||||
|
is Boolean -> if (value) BooleanValue.TRUE else BooleanValue.FALSE
|
||||||
|
is String -> StringValue(value)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun getIntegerValue(value: Long, expectedType: JetType): CompileTimeConstant<*>? {
|
||||||
|
if (CompileTimeConstantResolver.noExpectedTypeOrError(expectedType)) {
|
||||||
|
if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) {
|
||||||
|
return IntValue(value.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
return LongValue(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun defaultIntegerValue(value: Long) = when (value) {
|
||||||
|
in Integer.MIN_VALUE..Integer.MAX_VALUE.toLong() -> IntValue(value.toInt())
|
||||||
|
else -> LongValue(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
val builtIns = KotlinBuiltIns.getInstance()
|
||||||
|
return when (TypeUtils.makeNotNullable(expectedType)) {
|
||||||
|
builtIns.getIntType() -> IntValue(value.toInt())
|
||||||
|
builtIns.getLongType() -> LongValue(value)
|
||||||
|
builtIns.getShortType() -> when (value) {
|
||||||
|
in JShort.MIN_VALUE..JShort.MAX_VALUE.toLong() -> ShortValue(value.toShort())
|
||||||
|
else -> defaultIntegerValue(value)
|
||||||
|
}
|
||||||
|
builtIns.getByteType() -> when (value) {
|
||||||
|
in JByte.MIN_VALUE..JByte.MAX_VALUE.toLong() -> ByteValue(value.toByte())
|
||||||
|
else -> defaultIntegerValue(value)
|
||||||
|
}
|
||||||
|
builtIns.getCharType() -> IntValue(value.toInt())
|
||||||
|
else -> defaultIntegerValue(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getReceiverExpressionType(resolvedCall: ResolvedCall<*>): JetType? {
|
||||||
|
return when (resolvedCall.getExplicitReceiverKind()) {
|
||||||
|
ExplicitReceiverKind.THIS_OBJECT -> resolvedCall.getThisObject().getType()
|
||||||
|
ExplicitReceiverKind.RECEIVER_ARGUMENT -> resolvedCall.getReceiverArgument().getType()
|
||||||
|
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER -> null
|
||||||
|
ExplicitReceiverKind.BOTH_RECEIVERS -> null
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+15
-8
@@ -62,20 +62,27 @@ private val CHAR = CompileTimeType<Char>()
|
|||||||
private val BOOLEAN = CompileTimeType<Boolean>()
|
private val BOOLEAN = CompileTimeType<Boolean>()
|
||||||
private val STRING = CompileTimeType<String>()
|
private val STRING = CompileTimeType<String>()
|
||||||
|
|
||||||
private fun <A, B> bOp(a: CompileTimeType<A>, b: CompileTimeType<B>, functionNameAsString: String, f: (A, B) -> Any) = BinaryOperation(a, b, Name.identifier(functionNameAsString)) to f as Function2<Any?, Any?, Any>
|
[suppress("UNCHECKED_CAST")]
|
||||||
|
private fun <A, B> bOp(
|
||||||
|
a: CompileTimeType<A>,
|
||||||
|
b: CompileTimeType<B>,
|
||||||
|
functionNameAsString: String,
|
||||||
|
f: (A, B) -> Any
|
||||||
|
) = BinaryOperation(a, b, Name.identifier(functionNameAsString)) to f as Function2<Any?, Any?, Any>
|
||||||
|
|
||||||
private fun <A> uOp(a: CompileTimeType<A>, functionNameAsString: String, f: (A) -> Any) = UnaryOperation(a, Name.identifier(functionNameAsString)) to f as Function1<Any?, Any>
|
private fun <A> uOp(a: CompileTimeType<A>, functionNameAsString: String, f: (A) -> Any) = UnaryOperation(a, Name.identifier(functionNameAsString)) to f as Function1<Any?, Any>
|
||||||
|
|
||||||
private data class BinaryOperation<A, B>(val f: CompileTimeType<out A>, val s: CompileTimeType<out B>, val functionName: Name)
|
private data class BinaryOperation<A, B>(val f: CompileTimeType<out A>, val s: CompileTimeType<out B>, val functionName: Name)
|
||||||
private data class UnaryOperation<A>(val f: CompileTimeType<out A>, val functionName: Name)
|
private data class UnaryOperation<A>(val f: CompileTimeType<out A>, val functionName: Name)
|
||||||
|
|
||||||
private val unaryOperations = hashMapOf<UnaryOperation<*>, (Any?) -> Any>(
|
private val unaryOperations = hashMapOf<UnaryOperation<*>, (Any?) -> Any>(
|
||||||
uOp(DOUBLE, "minus", { a -> a.minus() }),
|
uOp(DOUBLE, "minus", { -it }),
|
||||||
uOp(FLOAT, "minus", { a -> a.minus() }),
|
uOp(FLOAT, "minus", { -it }),
|
||||||
uOp(LONG, "minus", { a -> a.minus() }),
|
uOp(LONG, "minus", { -it }),
|
||||||
uOp(INT, "minus", { a -> a.minus() }),
|
uOp(INT, "minus", { -it }),
|
||||||
uOp(SHORT, "minus", { a -> a.minus() }),
|
uOp(SHORT, "minus", { -it }),
|
||||||
uOp(BYTE, "minus", { a -> a.minus() }),
|
uOp(BYTE, "minus", { -it }),
|
||||||
uOp(CHAR, "minus", { a -> a.minus() }),
|
uOp(CHAR, "minus", { -it }),
|
||||||
uOp(DOUBLE, "plus", { a -> a.plus() }),
|
uOp(DOUBLE, "plus", { a -> a.plus() }),
|
||||||
uOp(FLOAT, "plus", { a -> a.plus() }),
|
uOp(FLOAT, "plus", { a -> a.plus() }),
|
||||||
uOp(LONG, "plus", { a -> a.plus() }),
|
uOp(LONG, "plus", { a -> a.plus() }),
|
||||||
@@ -24,7 +24,7 @@ import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
|
|||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptorImpl;
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptorImpl;
|
||||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||||
import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
|
import org.jetbrains.jet.lang.evaluate.EvaluatePackage;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
|
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||||
@@ -32,7 +32,8 @@ import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
|||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
|
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
|
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.*;
|
import org.jetbrains.jet.lang.resolve.constants.ArrayValue;
|
||||||
|
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||||
@@ -47,7 +48,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.resolve.BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT;
|
import static org.jetbrains.jet.lang.resolve.BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT;
|
||||||
import static org.jetbrains.jet.lang.resolve.BindingContext.COMPILE_TIME_INITIALIZER;
|
|
||||||
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||||
|
|
||||||
public class AnnotationResolver {
|
public class AnnotationResolver {
|
||||||
@@ -257,7 +257,7 @@ public class AnnotationResolver {
|
|||||||
@NotNull JetType expectedType,
|
@NotNull JetType expectedType,
|
||||||
@NotNull BindingTrace trace
|
@NotNull BindingTrace trace
|
||||||
) {
|
) {
|
||||||
return ConstantExpressionEvaluator.evaluate(expression, trace, expectedType);
|
return EvaluatePackage.evaluate(expression, trace, expectedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ public class AnnotationUtils {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isPropertyAcceptableAsAnnotationParameter(@NotNull PropertyDescriptor descriptor) {
|
public static boolean isPropertyCompileTimeConstant(@NotNull PropertyDescriptor descriptor) {
|
||||||
if (descriptor.isVar()) {
|
if (descriptor.isVar()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -555,7 +555,7 @@ public class BodyResolver {
|
|||||||
scope, propertyDescriptor.getTypeParameters(), NO_RECEIVER_PARAMETER, trace);
|
scope, propertyDescriptor.getTypeParameters(), NO_RECEIVER_PARAMETER, trace);
|
||||||
JetType expectedTypeForInitializer = property.getTypeRef() != null ? propertyDescriptor.getType() : NO_EXPECTED_TYPE;
|
JetType expectedTypeForInitializer = property.getTypeRef() != null ? propertyDescriptor.getType() : NO_EXPECTED_TYPE;
|
||||||
expressionTypingServices.getType(propertyDeclarationInnerScope, initializer, expectedTypeForInitializer, context.getOuterDataFlowInfo(), trace);
|
expressionTypingServices.getType(propertyDeclarationInnerScope, initializer, expectedTypeForInitializer, context.getOuterDataFlowInfo(), trace);
|
||||||
if (AnnotationUtils.isPropertyAcceptableAsAnnotationParameter(propertyDescriptor)) {
|
if (AnnotationUtils.isPropertyCompileTimeConstant(propertyDescriptor)) {
|
||||||
CompileTimeConstant<?> constant = AnnotationResolver.resolveExpressionToCompileTimeValue(initializer, expectedTypeForInitializer, trace);
|
CompileTimeConstant<?> constant = AnnotationResolver.resolveExpressionToCompileTimeValue(initializer, expectedTypeForInitializer, trace);
|
||||||
if (constant != null) {
|
if (constant != null) {
|
||||||
trace.record(BindingContext.COMPILE_TIME_INITIALIZER, propertyDescriptor, constant);
|
trace.record(BindingContext.COMPILE_TIME_INITIALIZER, propertyDescriptor, constant);
|
||||||
|
|||||||
Reference in New Issue
Block a user