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
017package org.jetbrains.jet.lang.resolve;
018
019import org.jetbrains.annotations.NotNull;
020import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
021import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
022import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
023import org.jetbrains.jet.lang.psi.JetParameter;
024import org.jetbrains.jet.lang.psi.JetTypeReference;
025import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
026import org.jetbrains.jet.lang.types.JetType;
027import org.jetbrains.jet.lang.types.TypeProjection;
028import org.jetbrains.jet.lang.types.TypeUtils;
029import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
030
031import java.util.List;
032
033import static org.jetbrains.jet.lang.diagnostics.Errors.INVALID_TYPE_OF_ANNOTATION_MEMBER;
034import static org.jetbrains.jet.lang.resolve.BindingContext.VALUE_PARAMETER;
035import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isAnnotationClass;
036import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClass;
037
038public class AnnotationUtils {
039
040    public static void checkConstructorParametersType(@NotNull List<JetParameter> parameters, @NotNull BindingTrace trace) {
041        for (JetParameter parameter : parameters) {
042            VariableDescriptor parameterDescriptor = trace.getBindingContext().get(VALUE_PARAMETER, parameter);
043            if (parameterDescriptor == null) continue;
044            JetType parameterType = parameterDescriptor.getType();
045            if (!isAcceptableTypeForAnnotationParameter(parameterType)) {
046                JetTypeReference typeReference = parameter.getTypeReference();
047                if (typeReference != null) {
048                    trace.report(INVALID_TYPE_OF_ANNOTATION_MEMBER.on(typeReference));
049                }
050            }
051        }
052    }
053
054    private static boolean isAcceptableTypeForAnnotationParameter(@NotNull JetType parameterType) {
055        if (parameterType.isNullable()) {
056            return false;
057        }
058        ClassDescriptor typeDescriptor = TypeUtils.getClassDescriptor(parameterType);
059        if (typeDescriptor == null) {
060            return false;
061        }
062
063        KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
064        if (isEnumClass(typeDescriptor) ||
065            isAnnotationClass(typeDescriptor) ||
066            isJavaLangClass(typeDescriptor) ||
067            builtIns.isPrimitiveArray(parameterType) ||
068            builtIns.isPrimitiveType(parameterType) ||
069            builtIns.getStringType().equals(parameterType)) {
070                return true;
071        }
072
073        if (builtIns.isArray(parameterType)) {
074            List<TypeProjection> arguments = parameterType.getArguments();
075            if (arguments.size() == 1) {
076                JetType arrayType = arguments.get(0).getType();
077                if (arrayType.isNullable()) {
078                    return false;
079                }
080                ClassDescriptor arrayTypeDescriptor = TypeUtils.getClassDescriptor(arrayType);
081                if (arrayTypeDescriptor != null) {
082                    return isEnumClass(arrayTypeDescriptor) ||
083                           isAnnotationClass(arrayTypeDescriptor) ||
084                           isJavaLangClass(arrayTypeDescriptor) ||
085                           builtIns.getStringType().equals(arrayType);
086                }
087            }
088        }
089        return false;
090    }
091
092    public static boolean isArrayMethodCall(@NotNull ResolvedCall resolvedCall) {
093        List<AnnotationDescriptor> annotations = resolvedCall.getResultingDescriptor().getOriginal().getAnnotations();
094        if (annotations != null) {
095            for (AnnotationDescriptor annotation : annotations) {
096                //noinspection ConstantConditions
097                if ("Intrinsic".equals(annotation.getType().getConstructor().getDeclarationDescriptor().getName().asString())) {
098                    return "kotlin.arrays.array".equals(annotation.getAllValueArguments().values().iterator().next().getValue());
099                }
100            }
101        }
102        return false;
103    }
104
105    public static boolean isJavaClassMethodCall(@NotNull ResolvedCall resolvedCall) {
106        List<AnnotationDescriptor> annotations = resolvedCall.getResultingDescriptor().getOriginal().getAnnotations();
107        if (annotations != null) {
108            for (AnnotationDescriptor annotation : annotations) {
109                //noinspection ConstantConditions
110                if ("Intrinsic".equals(annotation.getType().getConstructor().getDeclarationDescriptor().getName().asString())) {
111                    return "kotlin.javaClass.function".equals(annotation.getAllValueArguments().values().iterator().next().getValue());
112                }
113            }
114        }
115        return false;
116    }
117
118    private static boolean isJavaLangClass(ClassDescriptor descriptor) {
119        return "java.lang.Class".equals(DescriptorUtils.getFQName(descriptor).asString());
120    }
121
122    private AnnotationUtils() {
123    }
124}