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.lang.descriptors.ClassDescriptor;
025 import org.jetbrains.jet.lang.descriptors.ClassOrPackageFragmentDescriptor;
026 import org.jetbrains.jet.lang.descriptors.PackageFragmentDescriptor;
027 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
028 import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
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.FqName;
032 import org.jetbrains.jet.lang.resolve.name.Name;
033 import org.jetbrains.jet.lang.types.DependencyClassByQualifiedNameResolver;
034
035 import static org.jetbrains.jet.descriptors.serialization.descriptors.Deserializers.AnnotatedCallableKind;
036 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject;
037 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isTrait;
038 import static org.jetbrains.jet.lang.resolve.kotlin.DescriptorDeserializersStorage.MemberSignature;
039 import static org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.kotlinFqNameToJavaFqName;
040 import static org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.naiveKotlinFqName;
041
042 public abstract class BaseDescriptorDeserializer {
043 protected DependencyClassByQualifiedNameResolver classResolver;
044 protected KotlinClassFinder kotlinClassFinder;
045 protected ErrorReporter errorReporter;
046
047 protected DescriptorDeserializersStorage storage;
048
049 public abstract void setClassResolver(@NotNull DependencyClassByQualifiedNameResolver classResolver);
050
051 public abstract void setKotlinClassFinder(@NotNull KotlinClassFinder kotlinClassFinder);
052
053 public abstract void setErrorReporter(@NotNull ErrorReporter errorReporter);
054
055 public abstract void setStorage(@NotNull DescriptorDeserializersStorage storage);
056
057 @Nullable
058 protected static MemberSignature getCallableSignature(
059 @NotNull ProtoBuf.Callable proto,
060 @NotNull NameResolver nameResolver,
061 @NotNull AnnotatedCallableKind kind
062 ) {
063 SignatureDeserializer deserializer = new SignatureDeserializer(nameResolver);
064 switch (kind) {
065 case FUNCTION:
066 if (proto.hasExtension(JavaProtoBuf.methodSignature)) {
067 return deserializer.methodSignature(proto.getExtension(JavaProtoBuf.methodSignature));
068 }
069 break;
070 case PROPERTY_GETTER:
071 if (proto.hasExtension(JavaProtoBuf.propertySignature)) {
072 return deserializer.methodSignature(proto.getExtension(JavaProtoBuf.propertySignature).getGetter());
073 }
074 break;
075 case PROPERTY_SETTER:
076 if (proto.hasExtension(JavaProtoBuf.propertySignature)) {
077 return deserializer.methodSignature(proto.getExtension(JavaProtoBuf.propertySignature).getSetter());
078 }
079 break;
080 case PROPERTY:
081 if (proto.hasExtension(JavaProtoBuf.propertySignature)) {
082 JavaProtoBuf.JavaPropertySignature propertySignature = proto.getExtension(JavaProtoBuf.propertySignature);
083
084 if (propertySignature.hasField()) {
085 JavaProtoBuf.JavaFieldSignature field = propertySignature.getField();
086 String type = deserializer.typeDescriptor(field.getType());
087 Name name = nameResolver.getName(field.getName());
088 return MemberSignature.fromFieldNameAndDesc(name, type);
089 }
090 else if (propertySignature.hasSyntheticMethod()) {
091 return deserializer.methodSignature(propertySignature.getSyntheticMethod());
092 }
093 }
094 break;
095 }
096 return null;
097 }
098
099 @Nullable
100 protected KotlinJvmBinaryClass findClassWithAnnotationsAndInitializers(
101 @NotNull ClassOrPackageFragmentDescriptor container,
102 @NotNull ProtoBuf.Callable proto,
103 @NotNull NameResolver nameResolver,
104 @NotNull AnnotatedCallableKind kind
105 ) {
106 if (container instanceof PackageFragmentDescriptor) {
107 return loadPackageFragmentClassFqName((PackageFragmentDescriptor) container, proto, nameResolver);
108 }
109 else if (isClassObject(container) && isStaticFieldInOuter(proto)) {
110 // Backing fields of properties of a class object are generated in the outer class
111 return findKotlinClassByDescriptor((ClassOrPackageFragmentDescriptor) container.getContainingDeclaration());
112 }
113 else if (isTrait(container) && kind == AnnotatedCallableKind.PROPERTY) {
114 PackageFragmentDescriptor containingPackage = DescriptorUtils.getParentOfType(container, PackageFragmentDescriptor.class);
115 assert containingPackage != null : "Trait must have a package fragment among his parents: " + container;
116
117 if (proto.hasExtension(JavaProtoBuf.implClassName)) {
118 Name tImplName = nameResolver.getName(proto.getExtension(JavaProtoBuf.implClassName));
119 return kotlinClassFinder.findKotlinClass(containingPackage.getFqName().child(tImplName));
120 }
121 return null;
122 }
123
124 return findKotlinClassByDescriptor(container);
125 }
126
127 @Nullable
128 private KotlinJvmBinaryClass loadPackageFragmentClassFqName(
129 @NotNull PackageFragmentDescriptor container,
130 @NotNull ProtoBuf.Callable proto,
131 @NotNull NameResolver nameResolver
132 ) {
133 if (proto.hasExtension(JavaProtoBuf.implClassName)) {
134 Name name = nameResolver.getName(proto.getExtension(JavaProtoBuf.implClassName));
135 FqName fqName = PackageClassUtils.getPackageClassFqName(container.getFqName()).parent().child(name);
136 return kotlinClassFinder.findKotlinClass(fqName);
137 }
138 return null;
139 }
140
141 private static boolean isStaticFieldInOuter(@NotNull ProtoBuf.Callable proto) {
142 if (!proto.hasExtension(JavaProtoBuf.propertySignature)) return false;
143 JavaProtoBuf.JavaPropertySignature propertySignature = proto.getExtension(JavaProtoBuf.propertySignature);
144 return propertySignature.hasField() && propertySignature.getField().getIsStaticInOuter();
145 }
146
147 @Nullable
148 protected KotlinJvmBinaryClass findKotlinClassByDescriptor(@NotNull ClassOrPackageFragmentDescriptor descriptor) {
149 if (descriptor instanceof ClassDescriptor) {
150 return kotlinClassFinder.findKotlinClass(kotlinFqNameToJavaFqName(naiveKotlinFqName((ClassDescriptor) descriptor)));
151 }
152 else if (descriptor instanceof PackageFragmentDescriptor) {
153 return kotlinClassFinder.findKotlinClass(
154 PackageClassUtils.getPackageClassFqName(((PackageFragmentDescriptor) descriptor).getFqName()));
155 }
156 else {
157 throw new IllegalStateException("Unrecognized descriptor: " + descriptor);
158 }
159 }
160
161 protected static class SignatureDeserializer {
162 // These types are ordered according to their sorts, this is significant for deserialization
163 private static final char[] PRIMITIVE_TYPES = new char[] { 'V', 'Z', 'C', 'B', 'S', 'I', 'F', 'J', 'D' };
164
165 private final NameResolver nameResolver;
166
167 public SignatureDeserializer(@NotNull NameResolver nameResolver) {
168 this.nameResolver = nameResolver;
169 }
170
171 @NotNull
172 public MemberSignature methodSignature(@NotNull JavaProtoBuf.JavaMethodSignature signature) {
173 Name name = nameResolver.getName(signature.getName());
174
175 StringBuilder sb = new StringBuilder();
176 sb.append('(');
177 for (int i = 0, length = signature.getParameterTypeCount(); i < length; i++) {
178 typeDescriptor(signature.getParameterType(i), sb);
179 }
180 sb.append(')');
181 typeDescriptor(signature.getReturnType(), sb);
182
183 return MemberSignature.fromMethodNameAndDesc(name, sb.toString());
184 }
185
186 @NotNull
187 public String typeDescriptor(@NotNull JavaProtoBuf.JavaType type) {
188 return typeDescriptor(type, new StringBuilder()).toString();
189 }
190
191 @NotNull
192 private StringBuilder typeDescriptor(@NotNull JavaProtoBuf.JavaType type, @NotNull StringBuilder sb) {
193 for (int i = 0; i < type.getArrayDimension(); i++) {
194 sb.append('[');
195 }
196
197 if (type.hasPrimitiveType()) {
198 sb.append(PRIMITIVE_TYPES[type.getPrimitiveType().ordinal()]);
199 }
200 else {
201 sb.append("L");
202 sb.append(fqNameToInternalName(nameResolver.getFqName(type.getClassFqName())));
203 sb.append(";");
204 }
205
206 return sb;
207 }
208
209 @NotNull
210 private static String fqNameToInternalName(@NotNull FqName fqName) {
211 return fqName.asString().replace('.', '/');
212 }
213 }
214 }