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.k2js.translate.utils; 018 019import org.jetbrains.annotations.NotNull; 020import org.jetbrains.annotations.Nullable; 021import org.jetbrains.jet.lang.descriptors.ClassDescriptor; 022import org.jetbrains.jet.lang.descriptors.ClassKind; 023import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; 024import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 025import org.jetbrains.jet.lang.resolve.DescriptorUtils; 026import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; 027 028import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getContainingClass; 029 030public final class AnnotationsUtils { 031 032 private static final String ENUMERABLE = "js.enumerable"; 033 034 private AnnotationsUtils() { 035 } 036 037 private static boolean hasAnnotation(@NotNull DeclarationDescriptor descriptor, 038 @NotNull PredefinedAnnotation annotation) { 039 return getAnnotationByName(descriptor, annotation) != null; 040 } 041 042 @Nullable 043 private static String getAnnotationStringParameter(@NotNull DeclarationDescriptor declarationDescriptor, 044 @NotNull PredefinedAnnotation annotation) { 045 AnnotationDescriptor annotationDescriptor = getAnnotationByName(declarationDescriptor, annotation); 046 assert annotationDescriptor != null; 047 //TODO: this is a quick fix for unsupported default args problem 048 if (annotationDescriptor.getAllValueArguments().isEmpty()) { 049 return null; 050 } 051 CompileTimeConstant<?> constant = annotationDescriptor.getAllValueArguments().values().iterator().next(); 052 //TODO: this is a quick fix for unsupported default args problem 053 if (constant == null) { 054 return null; 055 } 056 Object value = constant.getValue(); 057 assert value instanceof String : "Native function annotation should have one String parameter"; 058 return (String) value; 059 } 060 061 @Nullable 062 public static String getNameForAnnotatedObject(@NotNull DeclarationDescriptor declarationDescriptor, 063 @NotNull PredefinedAnnotation annotation) { 064 if (!hasAnnotation(declarationDescriptor, annotation)) { 065 return null; 066 } 067 return getAnnotationStringParameter(declarationDescriptor, annotation); 068 } 069 070 @Nullable 071 private static AnnotationDescriptor getAnnotationByName(@NotNull DeclarationDescriptor descriptor, 072 @NotNull PredefinedAnnotation annotation) { 073 return getAnnotationByName(descriptor, annotation.getFQName()); 074 } 075 076 @Nullable 077 private static AnnotationDescriptor getAnnotationByName(@NotNull DeclarationDescriptor descriptor, @NotNull String fqn) { 078 for (AnnotationDescriptor annotationDescriptor : descriptor.getAnnotations()) { 079 if (getAnnotationClassFQName(annotationDescriptor).equals(fqn)) { 080 return annotationDescriptor; 081 } 082 } 083 return null; 084 } 085 086 @NotNull 087 private static String getAnnotationClassFQName(@NotNull AnnotationDescriptor annotationDescriptor) { 088 DeclarationDescriptor annotationDeclaration = 089 annotationDescriptor.getType().getConstructor().getDeclarationDescriptor(); 090 assert annotationDeclaration != null : "Annotation supposed to have a declaration"; 091 return DescriptorUtils.getFQName(annotationDeclaration).asString(); 092 } 093 094 public static boolean isNativeObject(@NotNull DeclarationDescriptor descriptor) { 095 return hasAnnotationOrInsideAnnotatedClass(descriptor, PredefinedAnnotation.NATIVE); 096 } 097 098 public static boolean isEnumerable(@NotNull DeclarationDescriptor descriptor) { 099 if (getAnnotationByName(descriptor, ENUMERABLE) != null) { 100 return true; 101 } 102 ClassDescriptor containingClass = getContainingClass(descriptor); 103 return containingClass != null && 104 (getAnnotationByName(containingClass, ENUMERABLE) != null || 105 (containingClass.getKind().equals(ClassKind.OBJECT) && containingClass.getName().isSpecial())); 106 } 107 108 public static boolean isLibraryObject(@NotNull DeclarationDescriptor descriptor) { 109 return hasAnnotationOrInsideAnnotatedClass(descriptor, PredefinedAnnotation.LIBRARY); 110 } 111 112 public static boolean isPredefinedObject(@NotNull DeclarationDescriptor descriptor) { 113 for (PredefinedAnnotation annotation : PredefinedAnnotation.values()) { 114 if (hasAnnotationOrInsideAnnotatedClass(descriptor, annotation)) { 115 return true; 116 } 117 } 118 return false; 119 } 120 121 public static boolean hasAnnotationOrInsideAnnotatedClass(@NotNull DeclarationDescriptor descriptor, 122 @NotNull PredefinedAnnotation annotation) { 123 return hasAnnotationOrInsideAnnotatedClass(descriptor, annotation.getFQName()); 124 } 125 126 private static boolean hasAnnotationOrInsideAnnotatedClass(@NotNull DeclarationDescriptor descriptor, @NotNull String fqn) { 127 if (getAnnotationByName(descriptor, fqn) != null) { 128 return true; 129 } 130 ClassDescriptor containingClass = getContainingClass(descriptor); 131 return containingClass != null && getAnnotationByName(containingClass, fqn) != null; 132 } 133}