001 /*
002 * Copyright 2010-2015 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.kotlin.resolve;
018
019 import kotlin.collections.SetsKt;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
023 import org.jetbrains.kotlin.descriptors.ClassDescriptor;
024 import org.jetbrains.kotlin.descriptors.VariableDescriptor;
025 import org.jetbrains.kotlin.psi.KtExpression;
026 import org.jetbrains.kotlin.psi.KtParameter;
027 import org.jetbrains.kotlin.psi.KtPsiUtil;
028 import org.jetbrains.kotlin.psi.KtTypeReference;
029 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
030 import org.jetbrains.kotlin.resolve.constants.BooleanValue;
031 import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
032 import org.jetbrains.kotlin.resolve.constants.ConstantValue;
033 import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant;
034 import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
035 import org.jetbrains.kotlin.types.KotlinType;
036 import org.jetbrains.kotlin.types.TypeProjection;
037 import org.jetbrains.kotlin.types.TypeUtils;
038
039 import java.util.List;
040 import java.util.Set;
041
042 import static org.jetbrains.kotlin.diagnostics.Errors.INVALID_TYPE_OF_ANNOTATION_MEMBER;
043 import static org.jetbrains.kotlin.diagnostics.Errors.NULLABLE_TYPE_OF_ANNOTATION_MEMBER;
044 import static org.jetbrains.kotlin.resolve.BindingContext.VALUE_PARAMETER;
045 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isAnnotationClass;
046 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumClass;
047
048 public class CompileTimeConstantUtils {
049
050 private final static Set<String> ARRAY_CALL_NAMES = SetsKt.hashSetOf(
051 "kotlin.arrayOf",
052 "kotlin.doubleArrayOf",
053 "kotlin.floatArrayOf",
054 "kotlin.longArrayOf",
055 "kotlin.intArrayOf",
056 "kotlin.charArrayOf",
057 "kotlin.shortArrayOf",
058 "kotlin.byteArrayOf",
059 "kotlin.booleanArrayOf"
060 );
061
062 public static void checkConstructorParametersType(@NotNull List<KtParameter> parameters, @NotNull BindingTrace trace) {
063 for (KtParameter parameter : parameters) {
064 VariableDescriptor parameterDescriptor = trace.getBindingContext().get(VALUE_PARAMETER, parameter);
065 if (parameterDescriptor == null) continue;
066 KotlinType parameterType = parameterDescriptor.getType();
067 KtTypeReference typeReference = parameter.getTypeReference();
068 if (typeReference != null) {
069 if (parameterType.isMarkedNullable()) {
070 trace.report(NULLABLE_TYPE_OF_ANNOTATION_MEMBER.on(typeReference));
071 }
072 else if (!isAcceptableTypeForAnnotationParameter(parameterType)) {
073 trace.report(INVALID_TYPE_OF_ANNOTATION_MEMBER.on(typeReference));
074 }
075 }
076 }
077 }
078
079 private static boolean isAcceptableTypeForAnnotationParameter(@NotNull KotlinType parameterType) {
080 ClassDescriptor typeDescriptor = TypeUtils.getClassDescriptor(parameterType);
081 if (typeDescriptor == null) {
082 return false;
083 }
084
085 if (isEnumClass(typeDescriptor) ||
086 isAnnotationClass(typeDescriptor) ||
087 KotlinBuiltIns.isKClass(typeDescriptor) ||
088 KotlinBuiltIns.isPrimitiveArray(parameterType) ||
089 KotlinBuiltIns.isPrimitiveType(parameterType) ||
090 KotlinBuiltIns.isString(parameterType)) {
091 return true;
092 }
093
094 if (KotlinBuiltIns.isArray(parameterType)) {
095 List<TypeProjection> arguments = parameterType.getArguments();
096 if (arguments.size() == 1) {
097 KotlinType arrayType = arguments.get(0).getType();
098 if (arrayType.isMarkedNullable()) {
099 return false;
100 }
101 ClassDescriptor arrayTypeDescriptor = TypeUtils.getClassDescriptor(arrayType);
102 if (arrayTypeDescriptor != null) {
103 return isEnumClass(arrayTypeDescriptor) ||
104 isAnnotationClass(arrayTypeDescriptor) ||
105 KotlinBuiltIns.isKClass(arrayTypeDescriptor) ||
106 KotlinBuiltIns.isString(arrayType);
107 }
108 }
109 }
110 return false;
111 }
112
113 public static boolean isArrayMethodCall(@NotNull ResolvedCall<?> resolvedCall) {
114 return ARRAY_CALL_NAMES.contains(DescriptorUtils.getFqName(resolvedCall.getCandidateDescriptor()).asString());
115 }
116
117 public static boolean canBeReducedToBooleanConstant(
118 @Nullable KtExpression expression,
119 @NotNull BindingContext context,
120 @Nullable Boolean expectedValue
121 ) {
122 KtExpression effectiveExpression = KtPsiUtil.deparenthesize(expression);
123
124 if (effectiveExpression == null) return false;
125
126 CompileTimeConstant<?> compileTimeConstant = ConstantExpressionEvaluator.getConstant(effectiveExpression, context);
127 if (!(compileTimeConstant instanceof TypedCompileTimeConstant) || compileTimeConstant.getUsesVariableAsConstant()) return false;
128
129 ConstantValue constantValue = ((TypedCompileTimeConstant) compileTimeConstant).getConstantValue();
130
131 if (!(constantValue instanceof BooleanValue)) return false;
132
133 Boolean value = ((BooleanValue) constantValue).getValue();
134 return expectedValue == null || expectedValue.equals(value);
135 }
136
137 private CompileTimeConstantUtils() {
138 }
139 }