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