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    }