001    /*
002     * Copyright 2010-2014 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.JavaProtoBuf;
022    import org.jetbrains.jet.descriptors.serialization.NameResolver;
023    import org.jetbrains.jet.descriptors.serialization.ProtoBuf;
024    import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedCallableMemberDescriptor;
025    import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
026    import org.jetbrains.jet.lang.descriptors.ClassOrPackageFragmentDescriptor;
027    import org.jetbrains.jet.lang.descriptors.PackageFragmentDescriptor;
028    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
029    import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
030    import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter;
031    import org.jetbrains.jet.lang.resolve.name.Name;
032    import org.jetbrains.jet.lang.types.DependencyClassByQualifiedNameResolver;
033    
034    import static org.jetbrains.jet.descriptors.serialization.descriptors.Deserializers.AnnotatedCallableKind;
035    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject;
036    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isTrait;
037    import static org.jetbrains.jet.lang.resolve.kotlin.DescriptorDeserializersStorage.MemberSignature;
038    import static org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.kotlinFqNameToJavaFqName;
039    import static org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.naiveKotlinFqName;
040    
041    public abstract class BaseDescriptorDeserializer {
042        protected DependencyClassByQualifiedNameResolver classResolver;
043        protected KotlinClassFinder kotlinClassFinder;
044        protected ErrorReporter errorReporter;
045    
046        protected DescriptorDeserializersStorage storage;
047    
048        public abstract void setClassResolver(@NotNull DependencyClassByQualifiedNameResolver classResolver);
049    
050        public abstract void setKotlinClassFinder(@NotNull KotlinClassFinder kotlinClassFinder);
051    
052        public abstract void setErrorReporter(@NotNull ErrorReporter errorReporter);
053    
054        public abstract void setStorage(@NotNull DescriptorDeserializersStorage storage);
055    
056        @Nullable
057        protected static MemberSignature getCallableSignature(
058                @NotNull ProtoBuf.Callable proto,
059                @NotNull NameResolver nameResolver,
060                @NotNull AnnotatedCallableKind kind
061        ) {
062            SignatureDeserializer deserializer = new SignatureDeserializer(nameResolver);
063            switch (kind) {
064                case FUNCTION:
065                    if (proto.hasExtension(JavaProtoBuf.methodSignature)) {
066                        return deserializer.methodSignature(proto.getExtension(JavaProtoBuf.methodSignature));
067                    }
068                    break;
069                case PROPERTY_GETTER:
070                    if (proto.hasExtension(JavaProtoBuf.propertySignature)) {
071                        return deserializer.methodSignature(proto.getExtension(JavaProtoBuf.propertySignature).getGetter());
072                    }
073                    break;
074                case PROPERTY_SETTER:
075                    if (proto.hasExtension(JavaProtoBuf.propertySignature)) {
076                        return deserializer.methodSignature(proto.getExtension(JavaProtoBuf.propertySignature).getSetter());
077                    }
078                    break;
079                case PROPERTY:
080                    if (proto.hasExtension(JavaProtoBuf.propertySignature)) {
081                        JavaProtoBuf.JavaPropertySignature propertySignature = proto.getExtension(JavaProtoBuf.propertySignature);
082    
083                        if (propertySignature.hasField()) {
084                            JavaProtoBuf.JavaFieldSignature field = propertySignature.getField();
085                            String type = deserializer.typeDescriptor(field.getType());
086                            Name name = nameResolver.getName(field.getName());
087                            return MemberSignature.fromFieldNameAndDesc(name, type);
088                        }
089                        else if (propertySignature.hasSyntheticMethod()) {
090                            return deserializer.methodSignature(propertySignature.getSyntheticMethod());
091                        }
092                    }
093                    break;
094            }
095            return null;
096        }
097    
098        @Nullable
099        protected KotlinJvmBinaryClass findClassWithAnnotationsAndInitializers(
100                @NotNull ClassOrPackageFragmentDescriptor container,
101                @NotNull ProtoBuf.Callable proto,
102                @NotNull NameResolver nameResolver,
103                @NotNull AnnotatedCallableKind kind
104        ) {
105            if (container instanceof PackageFragmentDescriptor) {
106                return getPackagePartClassFqNameSafe((PackageFragmentDescriptor) container, proto, nameResolver);
107            }
108            else if (isClassObject(container) && isStaticFieldInOuter(proto)) {
109                // Backing fields of properties of a class object are generated in the outer class
110                return findKotlinClassByDescriptor((ClassOrPackageFragmentDescriptor) container.getContainingDeclaration());
111            }
112            else if (isTrait(container) && kind == AnnotatedCallableKind.PROPERTY) {
113                PackageFragmentDescriptor containingPackage = DescriptorUtils.getParentOfType(container, PackageFragmentDescriptor.class);
114                assert containingPackage != null : "Trait must have a package fragment among his parents: " + container;
115    
116                if (proto.hasExtension(JavaProtoBuf.implClassName)) {
117                    Name tImplName = nameResolver.getName(proto.getExtension(JavaProtoBuf.implClassName));
118                    return kotlinClassFinder.findKotlinClass(containingPackage.getFqName().child(tImplName));
119                }
120                return null;
121            }
122    
123            return findKotlinClassByDescriptor(container);
124        }
125    
126        @Nullable
127        private KotlinJvmBinaryClass getPackagePartClassFqNameSafe(
128                @NotNull PackageFragmentDescriptor container,
129                @NotNull ProtoBuf.Callable proto,
130                @NotNull NameResolver nameResolver
131        ) {
132            if (proto.hasExtension(JavaProtoBuf.implClassName)) {
133                return kotlinClassFinder.findKotlinClass(container.getFqName().child(getPackagePartClassName(proto, nameResolver)));
134            }
135            return null;
136        }
137    
138        @NotNull
139        public static Name getPackagePartClassName(@NotNull DeserializedCallableMemberDescriptor deserializedCallableMember) {
140            return getPackagePartClassName(deserializedCallableMember.getProto(), deserializedCallableMember.getNameResolver());
141        }
142    
143        @NotNull
144        private static Name getPackagePartClassName(@NotNull ProtoBuf.Callable proto, @NotNull NameResolver nameResolver) {
145            return nameResolver.getName(proto.getExtension(JavaProtoBuf.implClassName));
146        }
147    
148        private static boolean isStaticFieldInOuter(@NotNull ProtoBuf.Callable proto) {
149            if (!proto.hasExtension(JavaProtoBuf.propertySignature)) return false;
150            JavaProtoBuf.JavaPropertySignature propertySignature = proto.getExtension(JavaProtoBuf.propertySignature);
151            return propertySignature.hasField() && propertySignature.getField().getIsStaticInOuter();
152        }
153    
154        @Nullable
155        protected KotlinJvmBinaryClass findKotlinClassByDescriptor(@NotNull ClassOrPackageFragmentDescriptor descriptor) {
156            if (descriptor instanceof ClassDescriptor) {
157                return kotlinClassFinder.findKotlinClass(kotlinFqNameToJavaFqName(naiveKotlinFqName((ClassDescriptor) descriptor)));
158            }
159            else if (descriptor instanceof PackageFragmentDescriptor) {
160                return kotlinClassFinder.findKotlinClass(
161                        PackageClassUtils.getPackageClassFqName(((PackageFragmentDescriptor) descriptor).getFqName()));
162            }
163            else {
164                throw new IllegalStateException("Unrecognized descriptor: " + descriptor);
165            }
166        }
167    }