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