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.kotlin;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.jet.descriptors.serialization.ClassData;
022    import org.jetbrains.jet.descriptors.serialization.ClassId;
023    import org.jetbrains.jet.descriptors.serialization.DescriptorFinder;
024    import org.jetbrains.jet.descriptors.serialization.JavaProtoBufUtil;
025    import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedClassDescriptor;
026    import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedPackageMemberScope;
027    import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
028    import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
029    import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter;
030    import org.jetbrains.jet.lang.resolve.java.resolver.JavaClassResolver;
031    import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver;
032    import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader;
033    import org.jetbrains.jet.lang.resolve.kotlin.header.SerializedDataHeader;
034    import org.jetbrains.jet.lang.resolve.name.FqName;
035    import org.jetbrains.jet.lang.resolve.name.Name;
036    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
037    import org.jetbrains.jet.storage.LockBasedStorageManager;
038    
039    import javax.inject.Inject;
040    import java.util.Collection;
041    
042    import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.IGNORE_KOTLIN_SOURCES;
043    import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.INCLUDE_KOTLIN_SOURCES;
044    import static org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.kotlinFqNameToJavaFqName;
045    
046    public final class DeserializedDescriptorResolver {
047        private AnnotationDescriptorDeserializer annotationDeserializer;
048    
049        private final LockBasedStorageManager storageManager = new LockBasedStorageManager();
050    
051        private JavaNamespaceResolver javaNamespaceResolver;
052    
053        private JavaClassResolver javaClassResolver;
054    
055        private ErrorReporter errorReporter;
056    
057        @NotNull
058        private final DescriptorFinder javaDescriptorFinder = new DescriptorFinder() {
059            @Nullable
060            @Override
061            public ClassDescriptor findClass(@NotNull ClassId classId) {
062                return javaClassResolver.resolveClass(kotlinFqNameToJavaFqName(classId.asSingleFqName()), INCLUDE_KOTLIN_SOURCES);
063            }
064    
065            @Nullable
066            @Override
067            public NamespaceDescriptor findPackage(@NotNull FqName name) {
068                return javaNamespaceResolver.resolveNamespace(name, IGNORE_KOTLIN_SOURCES);
069            }
070    
071            @NotNull
072            @Override
073            public Collection<Name> getClassNames(@NotNull FqName packageName) {
074                return javaNamespaceResolver.getClassNamesInPackage(packageName);
075            }
076        };
077    
078        @Inject
079        public void setAnnotationDeserializer(AnnotationDescriptorDeserializer annotationDeserializer) {
080            this.annotationDeserializer = annotationDeserializer;
081        }
082    
083        @Inject
084        public void setJavaNamespaceResolver(JavaNamespaceResolver javaNamespaceResolver) {
085            this.javaNamespaceResolver = javaNamespaceResolver;
086        }
087    
088        @Inject
089        public void setJavaClassResolver(JavaClassResolver javaClassResolver) {
090            this.javaClassResolver = javaClassResolver;
091        }
092    
093        @Inject
094        public void setErrorReporter(ErrorReporter errorReporter) {
095            this.errorReporter = errorReporter;
096        }
097    
098        @Nullable
099        public ClassDescriptor resolveClass(@NotNull KotlinJvmBinaryClass kotlinClass) {
100            String[] data = readData(kotlinClass);
101            if (data != null) {
102                ClassData classData = JavaProtoBufUtil.readClassDataFrom(data);
103                return new DeserializedClassDescriptor(storageManager, annotationDeserializer, javaDescriptorFinder,
104                                                       classData.getNameResolver(), classData.getClassProto());
105            }
106            return null;
107        }
108    
109        @Nullable
110        public JetScope createKotlinPackageScope(@NotNull NamespaceDescriptor descriptor, @NotNull KotlinJvmBinaryClass kotlinClass) {
111            String[] data = readData(kotlinClass);
112            if (data != null) {
113                return new DeserializedPackageMemberScope(storageManager, descriptor, annotationDeserializer, javaDescriptorFinder,
114                                                          JavaProtoBufUtil.readPackageDataFrom(data));
115            }
116            return null;
117        }
118    
119        @Nullable
120        private String[] readData(@NotNull KotlinJvmBinaryClass kotlinClass) {
121            KotlinClassHeader header = KotlinClassHeader.read(kotlinClass);
122            if (header instanceof SerializedDataHeader) {
123                return ((SerializedDataHeader) header).getAnnotationData();
124            }
125    
126            if (header != null) {
127                errorReporter.reportIncompatibleAbiVersion(kotlinClass, header.getVersion());
128            }
129    
130            return null;
131        }
132    }