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.java.resolver; 018 019import com.google.common.collect.Lists; 020import com.intellij.codeInsight.ExternalAnnotationsManager; 021import com.intellij.psi.*; 022import org.jetbrains.annotations.NotNull; 023import org.jetbrains.annotations.Nullable; 024import org.jetbrains.jet.lang.descriptors.ClassDescriptor; 025import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; 026import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 027import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; 028import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils; 029import org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule; 030import org.jetbrains.jet.lang.resolve.java.JavaToKotlinClassMap; 031import org.jetbrains.jet.lang.resolve.java.JvmAbi; 032import org.jetbrains.jet.lang.resolve.name.FqName; 033import org.jetbrains.jet.lang.resolve.name.Name; 034 035import javax.inject.Inject; 036import java.util.ArrayList; 037import java.util.Arrays; 038import java.util.List; 039 040public final class JavaAnnotationResolver { 041 private JavaClassResolver classResolver; 042 private JavaCompileTimeConstResolver compileTimeConstResolver; 043 044 public JavaAnnotationResolver() { 045 } 046 047 @Inject 048 public void setClassResolver(JavaClassResolver classResolver) { 049 this.classResolver = classResolver; 050 } 051 052 @Inject 053 public void setCompileTimeConstResolver(JavaCompileTimeConstResolver compileTimeConstResolver) { 054 this.compileTimeConstResolver = compileTimeConstResolver; 055 } 056 057 @NotNull 058 public List<AnnotationDescriptor> resolveAnnotations(@NotNull PsiModifierListOwner owner, @NotNull PostponedTasks tasks) { 059 PsiAnnotation[] psiAnnotations = getAllAnnotations(owner); 060 List<AnnotationDescriptor> r = Lists.newArrayListWithCapacity(psiAnnotations.length); 061 for (PsiAnnotation psiAnnotation : psiAnnotations) { 062 AnnotationDescriptor annotation = resolveAnnotation(psiAnnotation, tasks); 063 if (annotation != null) { 064 r.add(annotation); 065 } 066 } 067 return r; 068 } 069 070 @NotNull 071 public List<AnnotationDescriptor> resolveAnnotations(@NotNull PsiModifierListOwner owner) { 072 PostponedTasks postponedTasks = new PostponedTasks(); 073 List<AnnotationDescriptor> annotations = resolveAnnotations(owner, postponedTasks); 074 postponedTasks.performTasks(); 075 return annotations; 076 } 077 078 @Nullable 079 public AnnotationDescriptor resolveAnnotation(PsiAnnotation psiAnnotation, @NotNull PostponedTasks postponedTasks) { 080 final AnnotationDescriptor annotation = new AnnotationDescriptor(); 081 String qname = psiAnnotation.getQualifiedName(); 082 if (qname == null) { 083 return null; 084 } 085 086 // Don't process internal jet annotations and jetbrains NotNull annotations 087 if (qname.startsWith("jet.runtime.typeinfo.") || qname.equals(JvmAbi.JETBRAINS_NOT_NULL_ANNOTATION.getFqName().asString())) { 088 return null; 089 } 090 091 FqName annotationFqName = new FqName(qname); 092 093 AnnotationDescriptor mappedClassDescriptor = JavaToKotlinClassMap.getInstance().mapToAnnotationClass(annotationFqName); 094 if (mappedClassDescriptor != null) { 095 return mappedClassDescriptor; 096 } 097 098 final ClassDescriptor annotationClass = 099 classResolver.resolveClass(annotationFqName, DescriptorSearchRule.INCLUDE_KOTLIN, postponedTasks); 100 if (annotationClass == null) { 101 return null; 102 } 103 104 postponedTasks.addTask(new Runnable() { 105 @Override 106 public void run() { 107 annotation.setAnnotationType(annotationClass.getDefaultType()); 108 } 109 }); 110 111 112 PsiAnnotationParameterList parameterList = psiAnnotation.getParameterList(); 113 for (PsiNameValuePair psiNameValuePair : parameterList.getAttributes()) { 114 PsiAnnotationMemberValue value = psiNameValuePair.getValue(); 115 String name = psiNameValuePair.getName(); 116 if (name == null) name = "value"; 117 Name identifier = Name.identifier(name); 118 119 if (value == null) return null; 120 CompileTimeConstant compileTimeConst = 121 compileTimeConstResolver.getCompileTimeConstFromExpression(annotationFqName, identifier, value, postponedTasks); 122 if (compileTimeConst != null) { 123 ValueParameterDescriptor valueParameterDescriptor = 124 DescriptorResolverUtils.getValueParameterDescriptorForAnnotationParameter(identifier, annotationClass); 125 if (valueParameterDescriptor != null) { 126 annotation.setValueArgument(valueParameterDescriptor, compileTimeConst); 127 } 128 } 129 } 130 131 return annotation; 132 } 133 134 @NotNull 135 private static PsiAnnotation[] getAllAnnotations(@NotNull PsiModifierListOwner owner) { 136 List<PsiAnnotation> result = new ArrayList<PsiAnnotation>(); 137 138 PsiModifierList list = owner.getModifierList(); 139 if (list != null) { 140 result.addAll(Arrays.asList(list.getAnnotations())); 141 } 142 143 PsiAnnotation[] externalAnnotations = ExternalAnnotationsManager.getInstance(owner.getProject()).findExternalAnnotations(owner); 144 if (externalAnnotations != null) { 145 result.addAll(Arrays.asList(externalAnnotations)); 146 } 147 148 return result.toArray(new PsiAnnotation[result.size()]); 149 } 150 151 @Nullable 152 public static PsiAnnotation findOwnAnnotation(@NotNull PsiModifierListOwner owner, @NotNull String fqName) { 153 PsiModifierList list = owner.getModifierList(); 154 if (list != null) { 155 PsiAnnotation found = list.findAnnotation(fqName); 156 if (found != null) { 157 return found; 158 } 159 } 160 161 return null; 162 } 163 164 @Nullable 165 public static PsiAnnotation findAnnotationWithExternal(@NotNull PsiModifierListOwner owner, @NotNull String fqName) { 166 PsiAnnotation annotation = findOwnAnnotation(owner, fqName); 167 if (annotation != null) { 168 return annotation; 169 } 170 171 return ExternalAnnotationsManager.getInstance(owner.getProject()).findExternalAnnotation(owner, fqName); 172 } 173}