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    }