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 }