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