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