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.js.translate.utils; 018 019 import com.intellij.util.Function; 020 import com.intellij.util.containers.ContainerUtil; 021 import org.jetbrains.annotations.NotNull; 022 import org.jetbrains.annotations.Nullable; 023 import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor; 024 import org.jetbrains.kotlin.descriptors.ClassDescriptor; 025 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; 026 import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; 027 import org.jetbrains.kotlin.js.PredefinedAnnotation; 028 import org.jetbrains.kotlin.name.FqName; 029 import org.jetbrains.kotlin.resolve.DescriptorUtils; 030 import org.jetbrains.kotlin.resolve.constants.ConstantValue; 031 032 import java.util.List; 033 import java.util.Set; 034 035 public final class AnnotationsUtils { 036 037 private AnnotationsUtils() { 038 } 039 040 public static boolean hasAnnotation( 041 @NotNull DeclarationDescriptor descriptor, 042 @NotNull PredefinedAnnotation annotation 043 ) { 044 return getAnnotationByName(descriptor, annotation) != null; 045 } 046 047 @Nullable 048 private static String getAnnotationStringParameter(@NotNull DeclarationDescriptor declarationDescriptor, 049 @NotNull PredefinedAnnotation annotation) { 050 AnnotationDescriptor annotationDescriptor = getAnnotationByName(declarationDescriptor, annotation); 051 assert annotationDescriptor != null; 052 //TODO: this is a quick fix for unsupported default args problem 053 if (annotationDescriptor.getAllValueArguments().isEmpty()) { 054 return null; 055 } 056 ConstantValue<?> constant = annotationDescriptor.getAllValueArguments().values().iterator().next(); 057 //TODO: this is a quick fix for unsupported default args problem 058 if (constant == null) { 059 return null; 060 } 061 Object value = constant.getValue(); 062 assert value instanceof String : "Native function annotation should have one String parameter"; 063 return (String) value; 064 } 065 066 @Nullable 067 public static String getNameForAnnotatedObject(@NotNull DeclarationDescriptor declarationDescriptor, 068 @NotNull PredefinedAnnotation annotation) { 069 if (!hasAnnotation(declarationDescriptor, annotation)) { 070 return null; 071 } 072 return getAnnotationStringParameter(declarationDescriptor, annotation); 073 } 074 075 @Nullable 076 public static String getNameForAnnotatedObjectWithOverrides(@NotNull DeclarationDescriptor declarationDescriptor) { 077 List<DeclarationDescriptor> descriptors; 078 079 if (declarationDescriptor instanceof CallableMemberDescriptor && 080 DescriptorUtils.isOverride((CallableMemberDescriptor) declarationDescriptor)) { 081 082 Set<CallableMemberDescriptor> overriddenDeclarations = 083 DescriptorUtils.getAllOverriddenDeclarations((CallableMemberDescriptor) declarationDescriptor); 084 085 descriptors = ContainerUtil.mapNotNull(overriddenDeclarations, new Function<CallableMemberDescriptor, DeclarationDescriptor>() { 086 @Override 087 public DeclarationDescriptor fun(CallableMemberDescriptor descriptor) { 088 return DescriptorUtils.isOverride(descriptor) ? null : descriptor; 089 } 090 }); 091 } 092 else { 093 descriptors = ContainerUtil.newArrayList(declarationDescriptor); 094 } 095 096 for (DeclarationDescriptor descriptor : descriptors) { 097 for (PredefinedAnnotation annotation : PredefinedAnnotation.Companion.getWITH_CUSTOM_NAME()) { 098 if (!hasAnnotationOrInsideAnnotatedClass(descriptor, annotation)) { 099 continue; 100 } 101 String name = getNameForAnnotatedObject(descriptor, annotation); 102 return name != null ? name : descriptor.getName().asString(); 103 } 104 } 105 return null; 106 } 107 108 @Nullable 109 private static AnnotationDescriptor getAnnotationByName( 110 @NotNull DeclarationDescriptor descriptor, 111 @NotNull PredefinedAnnotation annotation 112 ) { 113 return getAnnotationByName(descriptor, annotation.getFqName()); 114 } 115 116 @Nullable 117 private static AnnotationDescriptor getAnnotationByName(@NotNull DeclarationDescriptor descriptor, @NotNull FqName fqName) { 118 return descriptor.getAnnotations().findAnnotation(fqName); 119 } 120 121 public static boolean isNativeObject(@NotNull DeclarationDescriptor descriptor) { 122 return hasAnnotationOrInsideAnnotatedClass(descriptor, PredefinedAnnotation.NATIVE); 123 } 124 125 public static boolean isLibraryObject(@NotNull DeclarationDescriptor descriptor) { 126 return hasAnnotationOrInsideAnnotatedClass(descriptor, PredefinedAnnotation.LIBRARY); 127 } 128 129 public static boolean isPredefinedObject(@NotNull DeclarationDescriptor descriptor) { 130 for (PredefinedAnnotation annotation : PredefinedAnnotation.values()) { 131 if (hasAnnotationOrInsideAnnotatedClass(descriptor, annotation)) { 132 return true; 133 } 134 } 135 return false; 136 } 137 138 public static boolean hasAnnotationOrInsideAnnotatedClass( 139 @NotNull DeclarationDescriptor descriptor, 140 @NotNull PredefinedAnnotation annotation 141 ) { 142 return hasAnnotationOrInsideAnnotatedClass(descriptor, annotation.getFqName()); 143 } 144 145 private static boolean hasAnnotationOrInsideAnnotatedClass(@NotNull DeclarationDescriptor descriptor, @NotNull FqName fqName) { 146 if (getAnnotationByName(descriptor, fqName) != null) { 147 return true; 148 } 149 ClassDescriptor containingClass = DescriptorUtils.getContainingClass(descriptor); 150 return containingClass != null && hasAnnotationOrInsideAnnotatedClass(containingClass, fqName); 151 } 152 }