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 org.jetbrains.annotations.NotNull;
020 import org.jetbrains.annotations.Nullable;
021 import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
022 import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
023 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
024 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptorImpl;
025 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
026 import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames;
027 import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap;
028 import org.jetbrains.jet.lang.resolve.java.structure.JavaAnnotation;
029 import org.jetbrains.jet.lang.resolve.java.structure.JavaAnnotationArgument;
030 import org.jetbrains.jet.lang.resolve.java.structure.JavaAnnotationOwner;
031 import org.jetbrains.jet.lang.resolve.name.FqName;
032 import org.jetbrains.jet.lang.resolve.name.Name;
033
034 import javax.inject.Inject;
035 import java.util.ArrayList;
036 import java.util.Collection;
037 import java.util.List;
038
039 import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.INCLUDE_KOTLIN_SOURCES;
040 import static org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils.fqNameByClass;
041
042 public final class JavaAnnotationResolver {
043 public static final Name DEFAULT_ANNOTATION_MEMBER_NAME = Name.identifier("value");
044 public static final FqName JETBRAINS_NOT_NULL_ANNOTATION = fqNameByClass(NotNull.class);
045 public static final FqName JETBRAINS_MUTABLE_ANNOTATION = new FqName("org.jetbrains.annotations.Mutable");
046 public static final FqName JETBRAINS_READONLY_ANNOTATION = new FqName("org.jetbrains.annotations.ReadOnly");
047
048 private JavaClassResolver classResolver;
049 private JavaAnnotationArgumentResolver argumentResolver;
050 private ExternalAnnotationResolver externalAnnotationResolver;
051
052 public JavaAnnotationResolver() {
053 }
054
055 @Inject
056 public void setClassResolver(JavaClassResolver classResolver) {
057 this.classResolver = classResolver;
058 }
059
060 @Inject
061 public void setArgumentResolver(JavaAnnotationArgumentResolver argumentResolver) {
062 this.argumentResolver = argumentResolver;
063 }
064
065 @Inject
066 public void setExternalAnnotationResolver(ExternalAnnotationResolver externalAnnotationResolver) {
067 this.externalAnnotationResolver = externalAnnotationResolver;
068 }
069
070 private void resolveAnnotations(
071 @NotNull Collection<JavaAnnotation> annotations,
072 @NotNull PostponedTasks tasks,
073 @NotNull List<AnnotationDescriptor> result
074 ) {
075 for (JavaAnnotation javaAnnotation : annotations) {
076 AnnotationDescriptor annotation = resolveAnnotation(javaAnnotation, tasks);
077 if (annotation != null) {
078 result.add(annotation);
079 }
080 }
081 }
082
083 @NotNull
084 public List<AnnotationDescriptor> resolveAnnotations(@NotNull JavaAnnotationOwner owner, @NotNull PostponedTasks tasks) {
085 List<AnnotationDescriptor> result = new ArrayList<AnnotationDescriptor>();
086 resolveAnnotations(owner.getAnnotations(), tasks, result);
087 resolveAnnotations(externalAnnotationResolver.findExternalAnnotations(owner), tasks, result);
088 return result;
089 }
090
091 @NotNull
092 public List<AnnotationDescriptor> resolveAnnotations(@NotNull JavaAnnotationOwner owner) {
093 PostponedTasks postponedTasks = new PostponedTasks();
094 List<AnnotationDescriptor> annotations = resolveAnnotations(owner, postponedTasks);
095 postponedTasks.performTasks();
096 return annotations;
097 }
098
099 @Nullable
100 public AnnotationDescriptor resolveAnnotation(@NotNull JavaAnnotation javaAnnotation, @NotNull PostponedTasks postponedTasks) {
101 final AnnotationDescriptorImpl annotation = new AnnotationDescriptorImpl();
102 FqName fqName = javaAnnotation.getFqName();
103 if (fqName == null) {
104 return null;
105 }
106
107 // Don't process internal jet annotations and jetbrains NotNull annotations
108 if (fqName.asString().startsWith("jet.runtime.typeinfo.")
109 || fqName.equals(JETBRAINS_NOT_NULL_ANNOTATION)
110 || fqName.equals(JvmAnnotationNames.KOTLIN_CLASS)
111 || fqName.equals(JvmAnnotationNames.KOTLIN_PACKAGE)
112 ) {
113 return null;
114 }
115
116 AnnotationDescriptor mappedClassDescriptor = JavaToKotlinClassMap.getInstance().mapToAnnotationClass(fqName);
117 if (mappedClassDescriptor != null) {
118 return mappedClassDescriptor;
119 }
120
121 final ClassDescriptor annotationClass = classResolver.resolveClass(fqName, INCLUDE_KOTLIN_SOURCES, postponedTasks);
122 if (annotationClass == null) {
123 return null;
124 }
125
126 postponedTasks.addTask(new Runnable() {
127 @Override
128 public void run() {
129 annotation.setAnnotationType(annotationClass.getDefaultType());
130 }
131 });
132
133
134 for (JavaAnnotationArgument argument : javaAnnotation.getArguments()) {
135 CompileTimeConstant value = argumentResolver.resolveAnnotationArgument(fqName, argument, postponedTasks);
136 if (value == null) continue;
137
138 Name name = argument.getName();
139 ValueParameterDescriptor descriptor = DescriptorResolverUtils.getAnnotationParameterByName(
140 name == null ? DEFAULT_ANNOTATION_MEMBER_NAME : name, annotationClass);
141 if (descriptor != null) {
142 annotation.setValueArgument(descriptor, value);
143 }
144 }
145
146 return annotation;
147 }
148
149 @Nullable
150 public JavaAnnotation findAnnotationWithExternal(@NotNull JavaAnnotationOwner owner, @NotNull FqName name) {
151 JavaAnnotation annotation = owner.findAnnotation(name);
152 if (annotation != null) {
153 return annotation;
154 }
155
156 return externalAnnotationResolver.findExternalAnnotation(owner, name);
157 }
158
159 public boolean hasNotNullAnnotation(@NotNull JavaAnnotationOwner owner) {
160 return findAnnotationWithExternal(owner, JETBRAINS_NOT_NULL_ANNOTATION) != null;
161 }
162
163 public boolean hasMutableAnnotation(@NotNull JavaAnnotationOwner owner) {
164 return findAnnotationWithExternal(owner, JETBRAINS_MUTABLE_ANNOTATION) != null;
165 }
166
167 public boolean hasReadonlyAnnotation(@NotNull JavaAnnotationOwner owner) {
168 return findAnnotationWithExternal(owner, JETBRAINS_READONLY_ANNOTATION) != null;
169 }
170 }