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.java.resolver;
018
019 import com.google.common.collect.Lists;
020 import com.intellij.codeInsight.ExternalAnnotationsManager;
021 import com.intellij.psi.*;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
025 import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
026 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
027 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
028 import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils;
029 import org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule;
030 import org.jetbrains.jet.lang.resolve.java.JavaToKotlinClassMap;
031 import org.jetbrains.jet.lang.resolve.java.JvmAbi;
032 import org.jetbrains.jet.lang.resolve.name.FqName;
033 import org.jetbrains.jet.lang.resolve.name.Name;
034
035 import javax.inject.Inject;
036 import java.util.ArrayList;
037 import java.util.Arrays;
038 import java.util.List;
039
040 public 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 }