001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.lang.resolve;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.annotations.Nullable;
021 import org.jetbrains.jet.JetNodeTypes;
022 import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
023 import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
024 import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
025 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
026 import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
027 import org.jetbrains.jet.lang.psi.JetConstantExpression;
028 import org.jetbrains.jet.lang.psi.JetExpression;
029 import org.jetbrains.jet.lang.psi.JetParameter;
030 import org.jetbrains.jet.lang.psi.JetTypeReference;
031 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
032 import org.jetbrains.jet.lang.resolve.constants.BooleanValue;
033 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
034 import org.jetbrains.jet.lang.resolve.name.FqName;
035 import org.jetbrains.jet.lang.types.JetType;
036 import org.jetbrains.jet.lang.types.TypeProjection;
037 import org.jetbrains.jet.lang.types.TypeUtils;
038 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
039
040 import java.util.Collection;
041 import java.util.List;
042
043 import static org.jetbrains.jet.lang.diagnostics.Errors.INVALID_TYPE_OF_ANNOTATION_MEMBER;
044 import static org.jetbrains.jet.lang.diagnostics.Errors.NULLABLE_TYPE_OF_ANNOTATION_MEMBER;
045 import static org.jetbrains.jet.lang.resolve.BindingContext.VALUE_PARAMETER;
046 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
047
048 public class CompileTimeConstantUtils {
049
050 public static void checkConstructorParametersType(@NotNull List<JetParameter> parameters, @NotNull BindingTrace trace) {
051 for (JetParameter parameter : parameters) {
052 VariableDescriptor parameterDescriptor = trace.getBindingContext().get(VALUE_PARAMETER, parameter);
053 if (parameterDescriptor == null) continue;
054 JetType parameterType = parameterDescriptor.getType();
055 JetTypeReference typeReference = parameter.getTypeReference();
056 if (typeReference != null) {
057 if (parameterType.isNullable()) {
058 trace.report(NULLABLE_TYPE_OF_ANNOTATION_MEMBER.on(typeReference));
059 }
060 else if (!isAcceptableTypeForAnnotationParameter(parameterType)) {
061 trace.report(INVALID_TYPE_OF_ANNOTATION_MEMBER.on(typeReference));
062 }
063 }
064 }
065 }
066
067 private static boolean isAcceptableTypeForAnnotationParameter(@NotNull JetType parameterType) {
068 ClassDescriptor typeDescriptor = TypeUtils.getClassDescriptor(parameterType);
069 if (typeDescriptor == null) {
070 return false;
071 }
072
073 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
074 if (isEnumClass(typeDescriptor) ||
075 isAnnotationClass(typeDescriptor) ||
076 isJavaLangClass(typeDescriptor) ||
077 builtIns.isPrimitiveArray(parameterType) ||
078 builtIns.isPrimitiveType(parameterType) ||
079 builtIns.getStringType().equals(parameterType)) {
080 return true;
081 }
082
083 if (builtIns.isArray(parameterType)) {
084 List<TypeProjection> arguments = parameterType.getArguments();
085 if (arguments.size() == 1) {
086 JetType arrayType = arguments.get(0).getType();
087 if (arrayType.isNullable()) {
088 return false;
089 }
090 ClassDescriptor arrayTypeDescriptor = TypeUtils.getClassDescriptor(arrayType);
091 if (arrayTypeDescriptor != null) {
092 return isEnumClass(arrayTypeDescriptor) ||
093 isAnnotationClass(arrayTypeDescriptor) ||
094 isJavaLangClass(arrayTypeDescriptor) ||
095 builtIns.getStringType().equals(arrayType);
096 }
097 }
098 }
099 return false;
100 }
101
102 @Nullable
103 public static String getIntrinsicAnnotationArgument(@NotNull Annotated annotatedDescriptor) {
104 AnnotationDescriptor intrinsicAnnotation =
105 annotatedDescriptor.getAnnotations().findAnnotation(new FqName("kotlin.jvm.internal.Intrinsic"));
106 if (intrinsicAnnotation == null) return null;
107
108 Collection<CompileTimeConstant<?>> values = intrinsicAnnotation.getAllValueArguments().values();
109 if (values.isEmpty()) return null;
110
111 Object value = values.iterator().next().getValue();
112 return value instanceof String ? (String) value : null;
113 }
114
115 public static boolean isArrayMethodCall(@NotNull ResolvedCall<?> resolvedCall) {
116 return "kotlin.arrays.array".equals(getIntrinsicAnnotationArgument(resolvedCall.getResultingDescriptor().getOriginal()));
117 }
118
119 public static boolean isJavaClassMethodCall(@NotNull ResolvedCall<?> resolvedCall) {
120 return "kotlin.javaClass.function".equals(getIntrinsicAnnotationArgument(resolvedCall.getResultingDescriptor().getOriginal()));
121 }
122
123 public static boolean isJavaLangClass(ClassDescriptor descriptor) {
124 return "java.lang.Class".equals(DescriptorUtils.getFqName(descriptor).asString());
125 }
126
127 public static boolean canBeReducedToBooleanConstant(
128 @Nullable JetExpression expression,
129 @NotNull BindingTrace trace,
130 @Nullable Boolean expectedValue
131 ) {
132 if (!(expression instanceof JetConstantExpression) || expression.getNode().getElementType() != JetNodeTypes.BOOLEAN_CONSTANT) {
133 return false;
134 }
135 CompileTimeConstant<?> compileTimeConstant =
136 ConstantExpressionEvaluator.object$.evaluate(expression, trace, KotlinBuiltIns.getInstance().getBooleanType());
137 if (!(compileTimeConstant instanceof BooleanValue)) return false;
138
139 Boolean value = ((BooleanValue) compileTimeConstant).getValue();
140 return expectedValue == null || expectedValue.equals(value);
141 }
142
143 private CompileTimeConstantUtils() {
144 }
145 }