Extract BaseDeserializer from AnnotationDeserializer. Move storage to separate class
This commit is contained in:
+29
-311
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.kotlin;
|
||||
|
||||
import kotlin.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.descriptors.serialization.JavaProtoBuf;
|
||||
@@ -28,69 +27,48 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationsImpl;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.constants.EnumValue;
|
||||
import org.jetbrains.jet.lang.resolve.constants.ErrorValue;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
||||
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter;
|
||||
import org.jetbrains.jet.lang.resolve.java.resolver.ResolverPackage;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.types.DependencyClassByQualifiedNameResolver;
|
||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||
import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
|
||||
import org.jetbrains.jet.storage.StorageManager;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isTrait;
|
||||
import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.*;
|
||||
import static org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.kotlinFqNameToJavaFqName;
|
||||
import static org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.naiveKotlinFqName;
|
||||
import static org.jetbrains.jet.descriptors.serialization.descriptors.Deserializers.AnnotatedCallableKind;
|
||||
import static org.jetbrains.jet.lang.resolve.kotlin.DescriptorDeserializersStorage.MemberSignature;
|
||||
|
||||
public class AnnotationDescriptorDeserializer implements AnnotationDeserializer {
|
||||
private DependencyClassByQualifiedNameResolver classResolver;
|
||||
private KotlinClassFinder kotlinClassFinder;
|
||||
private ErrorReporter errorReporter;
|
||||
|
||||
private final MemoizedFunctionToNotNull<KotlinJvmBinaryClass, Map<MemberSignature, List<AnnotationDescriptor>>> memberAnnotations;
|
||||
|
||||
public AnnotationDescriptorDeserializer(@NotNull StorageManager storageManager) {
|
||||
this.memberAnnotations = storageManager.createMemoizedFunction(
|
||||
new Function1<KotlinJvmBinaryClass, Map<MemberSignature, List<AnnotationDescriptor>>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<MemberSignature, List<AnnotationDescriptor>> invoke(@NotNull KotlinJvmBinaryClass kotlinClass) {
|
||||
try {
|
||||
return loadMemberAnnotationsFromClass(kotlinClass);
|
||||
}
|
||||
catch (IOException e) {
|
||||
errorReporter.reportAnnotationLoadingError(
|
||||
"Error loading member annotations from Kotlin class: " + kotlinClass, e);
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
});
|
||||
public class AnnotationDescriptorDeserializer extends BaseDescriptorDeserializer implements AnnotationDeserializer {
|
||||
@Inject
|
||||
@Override
|
||||
public void setStorage(@NotNull DescriptorDeserializersStorage storage) {
|
||||
this.storage = storage;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setClassResolver(DependencyClassByQualifiedNameResolver classResolver) {
|
||||
@Override
|
||||
public void setClassResolver(@NotNull DependencyClassByQualifiedNameResolver classResolver) {
|
||||
this.classResolver = classResolver;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setKotlinClassFinder(KotlinClassFinder kotlinClassFinder) {
|
||||
@Override
|
||||
public void setKotlinClassFinder(@NotNull KotlinClassFinder kotlinClassFinder) {
|
||||
this.kotlinClassFinder = kotlinClassFinder;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setErrorReporter(ErrorReporter errorReporter) {
|
||||
@Override
|
||||
public void setErrorReporter(@NotNull ErrorReporter errorReporter) {
|
||||
this.errorReporter = errorReporter;
|
||||
}
|
||||
|
||||
@@ -113,20 +91,6 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private KotlinJvmBinaryClass findKotlinClassByDescriptor(@NotNull ClassOrPackageFragmentDescriptor descriptor) {
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
return kotlinClassFinder.findKotlinClass(kotlinFqNameToJavaFqName(naiveKotlinFqName((ClassDescriptor) descriptor)));
|
||||
}
|
||||
else if (descriptor instanceof PackageFragmentDescriptor) {
|
||||
return kotlinClassFinder.findKotlinClass(
|
||||
PackageClassUtils.getPackageClassFqName(((PackageFragmentDescriptor) descriptor).getFqName()));
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Unrecognized descriptor: " + descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Annotations loadClassAnnotationsFromClass(@NotNull KotlinJvmBinaryClass kotlinClass) throws IOException {
|
||||
final List<AnnotationDescriptor> result = new ArrayList<AnnotationDescriptor>();
|
||||
@@ -135,7 +99,7 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
|
||||
@Nullable
|
||||
@Override
|
||||
public KotlinJvmBinaryClass.AnnotationArgumentVisitor visitAnnotation(@NotNull JvmClassName className) {
|
||||
return resolveAnnotation(className, result);
|
||||
return resolveAnnotation(className, result, classResolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,21 +111,22 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
|
||||
}
|
||||
|
||||
private static boolean ignoreAnnotation(@NotNull JvmClassName className) {
|
||||
return className.equals(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_CLASS))
|
||||
|| className.equals(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_PACKAGE))
|
||||
|| className.equals(JvmClassName.byFqNameWithoutInnerClasses(JETBRAINS_NOT_NULL_ANNOTATION))
|
||||
|| className.equals(JvmClassName.byFqNameWithoutInnerClasses(JETBRAINS_NULLABLE_ANNOTATION))
|
||||
return className.equals(JvmClassName.byFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CLASS))
|
||||
|| className.equals(JvmClassName.byFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_PACKAGE))
|
||||
|| className.equals(JvmClassName.byFqNameWithoutInnerClasses(JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION))
|
||||
|| className.equals(JvmClassName.byFqNameWithoutInnerClasses(JvmAnnotationNames.JETBRAINS_NULLABLE_ANNOTATION))
|
||||
|| className.getInternalName().startsWith("jet/runtime/typeinfo/");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private KotlinJvmBinaryClass.AnnotationArgumentVisitor resolveAnnotation(
|
||||
public static KotlinJvmBinaryClass.AnnotationArgumentVisitor resolveAnnotation(
|
||||
@NotNull JvmClassName className,
|
||||
@NotNull final List<AnnotationDescriptor> result
|
||||
@NotNull final List<AnnotationDescriptor> result,
|
||||
@NotNull final DependencyClassByQualifiedNameResolver classResolver
|
||||
) {
|
||||
if (ignoreAnnotation(className)) return null;
|
||||
|
||||
final ClassDescriptor annotationClass = resolveClass(className);
|
||||
final ClassDescriptor annotationClass = resolveClass(className, classResolver);
|
||||
final AnnotationDescriptorImpl annotation = new AnnotationDescriptorImpl();
|
||||
annotation.setAnnotationType(annotationClass.getDefaultType());
|
||||
|
||||
@@ -188,7 +153,7 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
|
||||
|
||||
@NotNull
|
||||
private CompileTimeConstant<?> enumEntryValue(@NotNull JvmClassName enumClassName, @NotNull Name name) {
|
||||
ClassDescriptor enumClass = resolveClass(enumClassName);
|
||||
ClassDescriptor enumClass = resolveClass(enumClassName, classResolver);
|
||||
if (enumClass.getKind() == ClassKind.ENUM_CLASS) {
|
||||
ClassifierDescriptor classifier = enumClass.getUnsubstitutedInnerClassesScope().getClassifier(name);
|
||||
if (classifier instanceof ClassDescriptor) {
|
||||
@@ -213,7 +178,7 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ClassDescriptor resolveClass(@NotNull JvmClassName className) {
|
||||
private static ClassDescriptor resolveClass(@NotNull JvmClassName className, DependencyClassByQualifiedNameResolver classResolver) {
|
||||
ClassDescriptor annotationClass = classResolver.resolveClass(className.getFqNameForClassNameWithoutDollars());
|
||||
return annotationClass != null ? annotationClass : ErrorUtils.getErrorClass();
|
||||
}
|
||||
@@ -246,257 +211,10 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
|
||||
return Annotations.EMPTY;
|
||||
}
|
||||
|
||||
List<AnnotationDescriptor> annotations = memberAnnotations.invoke(kotlinClass).get(signature);
|
||||
List<AnnotationDescriptor> annotations = storage.getMemberAnnotations().invoke(kotlinClass).get(signature);
|
||||
return annotations == null ? Annotations.EMPTY : new AnnotationsImpl(annotations);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private KotlinJvmBinaryClass findClassWithMemberAnnotations(
|
||||
@NotNull ClassOrPackageFragmentDescriptor container,
|
||||
@NotNull ProtoBuf.Callable proto,
|
||||
@NotNull NameResolver nameResolver,
|
||||
@NotNull AnnotatedCallableKind kind
|
||||
) {
|
||||
if (container instanceof PackageFragmentDescriptor) {
|
||||
return loadPackageFragmentClassFqName((PackageFragmentDescriptor) container, proto, nameResolver);
|
||||
}
|
||||
else if (isClassObject(container) && isStaticFieldInOuter(proto)) {
|
||||
// Backing fields of properties of a class object are generated in the outer class
|
||||
return findKotlinClassByDescriptor((ClassOrPackageFragmentDescriptor) container.getContainingDeclaration());
|
||||
}
|
||||
else if (isTrait(container) && kind == AnnotatedCallableKind.PROPERTY) {
|
||||
PackageFragmentDescriptor containingPackage = DescriptorUtils.getParentOfType(container, PackageFragmentDescriptor.class);
|
||||
assert containingPackage != null : "Trait must have a package fragment among his parents: " + container;
|
||||
|
||||
if (proto.hasExtension(JavaProtoBuf.implClassName)) {
|
||||
Name tImplName = nameResolver.getName(proto.getExtension(JavaProtoBuf.implClassName));
|
||||
return kotlinClassFinder.findKotlinClass(containingPackage.getFqName().child(tImplName));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return findKotlinClassByDescriptor(container);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private KotlinJvmBinaryClass loadPackageFragmentClassFqName(
|
||||
@NotNull PackageFragmentDescriptor container,
|
||||
@NotNull ProtoBuf.Callable proto,
|
||||
@NotNull NameResolver nameResolver
|
||||
) {
|
||||
if (proto.hasExtension(JavaProtoBuf.implClassName)) {
|
||||
Name name = nameResolver.getName(proto.getExtension(JavaProtoBuf.implClassName));
|
||||
FqName fqName = PackageClassUtils.getPackageClassFqName(container.getFqName()).parent().child(name);
|
||||
return kotlinClassFinder.findKotlinClass(fqName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isStaticFieldInOuter(@NotNull ProtoBuf.Callable proto) {
|
||||
if (!proto.hasExtension(JavaProtoBuf.propertySignature)) return false;
|
||||
JavaProtoBuf.JavaPropertySignature propertySignature = proto.getExtension(JavaProtoBuf.propertySignature);
|
||||
return propertySignature.hasField() && propertySignature.getField().getIsStaticInOuter();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static MemberSignature getCallableSignature(
|
||||
@NotNull ProtoBuf.Callable proto,
|
||||
@NotNull NameResolver nameResolver,
|
||||
@NotNull AnnotatedCallableKind kind
|
||||
) {
|
||||
SignatureDeserializer deserializer = new SignatureDeserializer(nameResolver);
|
||||
switch (kind) {
|
||||
case FUNCTION:
|
||||
if (proto.hasExtension(JavaProtoBuf.methodSignature)) {
|
||||
return deserializer.methodSignature(proto.getExtension(JavaProtoBuf.methodSignature));
|
||||
}
|
||||
break;
|
||||
case PROPERTY_GETTER:
|
||||
if (proto.hasExtension(JavaProtoBuf.propertySignature)) {
|
||||
return deserializer.methodSignature(proto.getExtension(JavaProtoBuf.propertySignature).getGetter());
|
||||
}
|
||||
break;
|
||||
case PROPERTY_SETTER:
|
||||
if (proto.hasExtension(JavaProtoBuf.propertySignature)) {
|
||||
return deserializer.methodSignature(proto.getExtension(JavaProtoBuf.propertySignature).getSetter());
|
||||
}
|
||||
break;
|
||||
case PROPERTY:
|
||||
if (proto.hasExtension(JavaProtoBuf.propertySignature)) {
|
||||
JavaProtoBuf.JavaPropertySignature propertySignature = proto.getExtension(JavaProtoBuf.propertySignature);
|
||||
|
||||
if (propertySignature.hasField()) {
|
||||
JavaProtoBuf.JavaFieldSignature field = propertySignature.getField();
|
||||
String type = deserializer.typeDescriptor(field.getType());
|
||||
Name name = nameResolver.getName(field.getName());
|
||||
return MemberSignature.fromFieldNameAndDesc(name, type);
|
||||
}
|
||||
else if (propertySignature.hasSyntheticMethod()) {
|
||||
return deserializer.methodSignature(propertySignature.getSyntheticMethod());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<MemberSignature, List<AnnotationDescriptor>> loadMemberAnnotationsFromClass(@NotNull KotlinJvmBinaryClass kotlinClass)
|
||||
throws IOException {
|
||||
final Map<MemberSignature, List<AnnotationDescriptor>> memberAnnotations =
|
||||
new HashMap<MemberSignature, List<AnnotationDescriptor>>();
|
||||
|
||||
kotlinClass.loadMemberAnnotations(new KotlinJvmBinaryClass.MemberVisitor() {
|
||||
@Nullable
|
||||
@Override
|
||||
public KotlinJvmBinaryClass.MethodAnnotationVisitor visitMethod(@NotNull Name name, @NotNull String desc) {
|
||||
return new AnnotationVisitorForMethod(MemberSignature.fromMethodNameAndDesc(name, desc));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public KotlinJvmBinaryClass.AnnotationVisitor visitField(@NotNull Name name, @NotNull String desc) {
|
||||
return new MemberAnnotationVisitor(MemberSignature.fromFieldNameAndDesc(name, desc));
|
||||
}
|
||||
|
||||
class AnnotationVisitorForMethod extends MemberAnnotationVisitor implements KotlinJvmBinaryClass.MethodAnnotationVisitor {
|
||||
public AnnotationVisitorForMethod(@NotNull MemberSignature signature) {
|
||||
super(signature);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public KotlinJvmBinaryClass.AnnotationArgumentVisitor visitParameterAnnotation(int index, @NotNull JvmClassName className) {
|
||||
MemberSignature paramSignature = MemberSignature.fromMethodSignatureAndParameterIndex(signature, index);
|
||||
List<AnnotationDescriptor> result = memberAnnotations.get(paramSignature);
|
||||
if (result == null) {
|
||||
result = new ArrayList<AnnotationDescriptor>();
|
||||
memberAnnotations.put(paramSignature, result);
|
||||
}
|
||||
return resolveAnnotation(className, result);
|
||||
}
|
||||
}
|
||||
|
||||
class MemberAnnotationVisitor implements KotlinJvmBinaryClass.AnnotationVisitor {
|
||||
private final List<AnnotationDescriptor> result = new ArrayList<AnnotationDescriptor>();
|
||||
protected final MemberSignature signature;
|
||||
|
||||
public MemberAnnotationVisitor(@NotNull MemberSignature signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public KotlinJvmBinaryClass.AnnotationArgumentVisitor visitAnnotation(@NotNull JvmClassName className) {
|
||||
return resolveAnnotation(className, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (!result.isEmpty()) {
|
||||
memberAnnotations.put(signature, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return memberAnnotations;
|
||||
}
|
||||
|
||||
// The purpose of this class is to hold a unique signature of either a method or a field, so that annotations on a member can be put
|
||||
// into a map indexed by these signatures
|
||||
private static final class MemberSignature {
|
||||
private final String signature;
|
||||
|
||||
private MemberSignature(@NotNull String signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static MemberSignature fromMethodNameAndDesc(@NotNull Name name, @NotNull String desc) {
|
||||
return new MemberSignature(name.asString() + desc);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static MemberSignature fromFieldNameAndDesc(@NotNull Name name, @NotNull String desc) {
|
||||
return new MemberSignature(name.asString() + "#" + desc);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static MemberSignature fromMethodSignatureAndParameterIndex(@NotNull MemberSignature signature, int index) {
|
||||
return new MemberSignature(signature.signature + "@" + index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return signature.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof MemberSignature && signature.equals(((MemberSignature) o).signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return signature;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SignatureDeserializer {
|
||||
// These types are ordered according to their sorts, this is significant for deserialization
|
||||
private static final char[] PRIMITIVE_TYPES = new char[] { 'V', 'Z', 'C', 'B', 'S', 'I', 'F', 'J', 'D' };
|
||||
|
||||
private final NameResolver nameResolver;
|
||||
|
||||
public SignatureDeserializer(@NotNull NameResolver nameResolver) {
|
||||
this.nameResolver = nameResolver;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MemberSignature methodSignature(@NotNull JavaProtoBuf.JavaMethodSignature signature) {
|
||||
Name name = nameResolver.getName(signature.getName());
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('(');
|
||||
for (int i = 0, length = signature.getParameterTypeCount(); i < length; i++) {
|
||||
typeDescriptor(signature.getParameterType(i), sb);
|
||||
}
|
||||
sb.append(')');
|
||||
typeDescriptor(signature.getReturnType(), sb);
|
||||
|
||||
return MemberSignature.fromMethodNameAndDesc(name, sb.toString());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String typeDescriptor(@NotNull JavaProtoBuf.JavaType type) {
|
||||
return typeDescriptor(type, new StringBuilder()).toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StringBuilder typeDescriptor(@NotNull JavaProtoBuf.JavaType type, @NotNull StringBuilder sb) {
|
||||
for (int i = 0; i < type.getArrayDimension(); i++) {
|
||||
sb.append('[');
|
||||
}
|
||||
|
||||
if (type.hasPrimitiveType()) {
|
||||
sb.append(PRIMITIVE_TYPES[type.getPrimitiveType().ordinal()]);
|
||||
}
|
||||
else {
|
||||
sb.append("L");
|
||||
sb.append(fqNameToInternalName(nameResolver.getFqName(type.getClassFqName())));
|
||||
sb.append(";");
|
||||
}
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String fqNameToInternalName(@NotNull FqName fqName) {
|
||||
return fqName.asString().replace('.', '/');
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Annotations loadValueParameterAnnotations(
|
||||
@@ -517,4 +235,4 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
|
||||
|
||||
return Annotations.EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.kotlin;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.descriptors.serialization.JavaProtoBuf;
|
||||
import org.jetbrains.jet.descriptors.serialization.NameResolver;
|
||||
import org.jetbrains.jet.descriptors.serialization.ProtoBuf;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassOrPackageFragmentDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PackageFragmentDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
|
||||
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.types.DependencyClassByQualifiedNameResolver;
|
||||
|
||||
import static org.jetbrains.jet.descriptors.serialization.descriptors.Deserializers.AnnotatedCallableKind;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isTrait;
|
||||
import static org.jetbrains.jet.lang.resolve.kotlin.DescriptorDeserializersStorage.MemberSignature;
|
||||
import static org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.kotlinFqNameToJavaFqName;
|
||||
import static org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.naiveKotlinFqName;
|
||||
|
||||
public abstract class BaseDescriptorDeserializer {
|
||||
protected DependencyClassByQualifiedNameResolver classResolver;
|
||||
protected KotlinClassFinder kotlinClassFinder;
|
||||
protected ErrorReporter errorReporter;
|
||||
|
||||
protected DescriptorDeserializersStorage storage;
|
||||
|
||||
public abstract void setClassResolver(@NotNull DependencyClassByQualifiedNameResolver classResolver);
|
||||
|
||||
public abstract void setKotlinClassFinder(@NotNull KotlinClassFinder kotlinClassFinder);
|
||||
|
||||
public abstract void setErrorReporter(@NotNull ErrorReporter errorReporter);
|
||||
|
||||
public abstract void setStorage(@NotNull DescriptorDeserializersStorage storage);
|
||||
|
||||
@Nullable
|
||||
protected static MemberSignature getCallableSignature(
|
||||
@NotNull ProtoBuf.Callable proto,
|
||||
@NotNull NameResolver nameResolver,
|
||||
@NotNull AnnotatedCallableKind kind
|
||||
) {
|
||||
SignatureDeserializer deserializer = new SignatureDeserializer(nameResolver);
|
||||
switch (kind) {
|
||||
case FUNCTION:
|
||||
if (proto.hasExtension(JavaProtoBuf.methodSignature)) {
|
||||
return deserializer.methodSignature(proto.getExtension(JavaProtoBuf.methodSignature));
|
||||
}
|
||||
break;
|
||||
case PROPERTY_GETTER:
|
||||
if (proto.hasExtension(JavaProtoBuf.propertySignature)) {
|
||||
return deserializer.methodSignature(proto.getExtension(JavaProtoBuf.propertySignature).getGetter());
|
||||
}
|
||||
break;
|
||||
case PROPERTY_SETTER:
|
||||
if (proto.hasExtension(JavaProtoBuf.propertySignature)) {
|
||||
return deserializer.methodSignature(proto.getExtension(JavaProtoBuf.propertySignature).getSetter());
|
||||
}
|
||||
break;
|
||||
case PROPERTY:
|
||||
if (proto.hasExtension(JavaProtoBuf.propertySignature)) {
|
||||
JavaProtoBuf.JavaPropertySignature propertySignature = proto.getExtension(JavaProtoBuf.propertySignature);
|
||||
|
||||
if (propertySignature.hasField()) {
|
||||
JavaProtoBuf.JavaFieldSignature field = propertySignature.getField();
|
||||
String type = deserializer.typeDescriptor(field.getType());
|
||||
Name name = nameResolver.getName(field.getName());
|
||||
return MemberSignature.fromFieldNameAndDesc(name, type);
|
||||
}
|
||||
else if (propertySignature.hasSyntheticMethod()) {
|
||||
return deserializer.methodSignature(propertySignature.getSyntheticMethod());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected KotlinJvmBinaryClass findClassWithMemberAnnotations(
|
||||
@NotNull ClassOrPackageFragmentDescriptor container,
|
||||
@NotNull ProtoBuf.Callable proto,
|
||||
@NotNull NameResolver nameResolver,
|
||||
@NotNull AnnotatedCallableKind kind
|
||||
) {
|
||||
if (container instanceof PackageFragmentDescriptor) {
|
||||
return loadPackageFragmentClassFqName((PackageFragmentDescriptor) container, proto, nameResolver);
|
||||
}
|
||||
else if (isClassObject(container) && isStaticFieldInOuter(proto)) {
|
||||
// Backing fields of properties of a class object are generated in the outer class
|
||||
return findKotlinClassByDescriptor((ClassOrPackageFragmentDescriptor) container.getContainingDeclaration());
|
||||
}
|
||||
else if (isTrait(container) && kind == AnnotatedCallableKind.PROPERTY) {
|
||||
PackageFragmentDescriptor containingPackage = DescriptorUtils.getParentOfType(container, PackageFragmentDescriptor.class);
|
||||
assert containingPackage != null : "Trait must have a package fragment among his parents: " + container;
|
||||
|
||||
if (proto.hasExtension(JavaProtoBuf.implClassName)) {
|
||||
Name tImplName = nameResolver.getName(proto.getExtension(JavaProtoBuf.implClassName));
|
||||
return kotlinClassFinder.findKotlinClass(containingPackage.getFqName().child(tImplName));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return findKotlinClassByDescriptor(container);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private KotlinJvmBinaryClass loadPackageFragmentClassFqName(
|
||||
@NotNull PackageFragmentDescriptor container,
|
||||
@NotNull ProtoBuf.Callable proto,
|
||||
@NotNull NameResolver nameResolver
|
||||
) {
|
||||
if (proto.hasExtension(JavaProtoBuf.implClassName)) {
|
||||
Name name = nameResolver.getName(proto.getExtension(JavaProtoBuf.implClassName));
|
||||
FqName fqName = PackageClassUtils.getPackageClassFqName(container.getFqName()).parent().child(name);
|
||||
return kotlinClassFinder.findKotlinClass(fqName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isStaticFieldInOuter(@NotNull ProtoBuf.Callable proto) {
|
||||
if (!proto.hasExtension(JavaProtoBuf.propertySignature)) return false;
|
||||
JavaProtoBuf.JavaPropertySignature propertySignature = proto.getExtension(JavaProtoBuf.propertySignature);
|
||||
return propertySignature.hasField() && propertySignature.getField().getIsStaticInOuter();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected KotlinJvmBinaryClass findKotlinClassByDescriptor(@NotNull ClassOrPackageFragmentDescriptor descriptor) {
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
return kotlinClassFinder.findKotlinClass(kotlinFqNameToJavaFqName(naiveKotlinFqName((ClassDescriptor) descriptor)));
|
||||
}
|
||||
else if (descriptor instanceof PackageFragmentDescriptor) {
|
||||
return kotlinClassFinder.findKotlinClass(
|
||||
PackageClassUtils.getPackageClassFqName(((PackageFragmentDescriptor) descriptor).getFqName()));
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Unrecognized descriptor: " + descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class SignatureDeserializer {
|
||||
// These types are ordered according to their sorts, this is significant for deserialization
|
||||
private static final char[] PRIMITIVE_TYPES = new char[] { 'V', 'Z', 'C', 'B', 'S', 'I', 'F', 'J', 'D' };
|
||||
|
||||
private final NameResolver nameResolver;
|
||||
|
||||
public SignatureDeserializer(@NotNull NameResolver nameResolver) {
|
||||
this.nameResolver = nameResolver;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MemberSignature methodSignature(@NotNull JavaProtoBuf.JavaMethodSignature signature) {
|
||||
Name name = nameResolver.getName(signature.getName());
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('(');
|
||||
for (int i = 0, length = signature.getParameterTypeCount(); i < length; i++) {
|
||||
typeDescriptor(signature.getParameterType(i), sb);
|
||||
}
|
||||
sb.append(')');
|
||||
typeDescriptor(signature.getReturnType(), sb);
|
||||
|
||||
return MemberSignature.fromMethodNameAndDesc(name, sb.toString());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String typeDescriptor(@NotNull JavaProtoBuf.JavaType type) {
|
||||
return typeDescriptor(type, new StringBuilder()).toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StringBuilder typeDescriptor(@NotNull JavaProtoBuf.JavaType type, @NotNull StringBuilder sb) {
|
||||
for (int i = 0; i < type.getArrayDimension(); i++) {
|
||||
sb.append('[');
|
||||
}
|
||||
|
||||
if (type.hasPrimitiveType()) {
|
||||
sb.append(PRIMITIVE_TYPES[type.getPrimitiveType().ordinal()]);
|
||||
}
|
||||
else {
|
||||
sb.append("L");
|
||||
sb.append(fqNameToInternalName(nameResolver.getFqName(type.getClassFqName())));
|
||||
sb.append(";");
|
||||
}
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String fqNameToInternalName(@NotNull FqName fqName) {
|
||||
return fqName.asString().replace('.', '/');
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.kotlin;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.descriptors.serialization.descriptors.AnnotationDeserializer;
|
||||
import org.jetbrains.jet.descriptors.serialization.descriptors.Deserializers;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class DescriptorDeserializers implements Deserializers {
|
||||
|
||||
private AnnotationDescriptorDeserializer annotationDescriptorDeserializer;
|
||||
|
||||
@Inject
|
||||
public void setAnnotationDescriptorDeserializer(AnnotationDescriptorDeserializer annotationDescriptorDeserializer) {
|
||||
this.annotationDescriptorDeserializer = annotationDescriptorDeserializer;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AnnotationDeserializer getAnnotationDeserializer() {
|
||||
return annotationDescriptorDeserializer;
|
||||
}
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.kotlin;
|
||||
|
||||
import kotlin.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
||||
import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.types.DependencyClassByQualifiedNameResolver;
|
||||
import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
|
||||
import org.jetbrains.jet.storage.StorageManager;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class DescriptorDeserializersStorage {
|
||||
private DependencyClassByQualifiedNameResolver classResolver;
|
||||
private ErrorReporter errorReporter;
|
||||
|
||||
private final MemoizedFunctionToNotNull<KotlinJvmBinaryClass, Map<MemberSignature, List<AnnotationDescriptor>>> memberAnnotations;
|
||||
|
||||
public DescriptorDeserializersStorage(@NotNull StorageManager storageManager) {
|
||||
this.memberAnnotations = storageManager.createMemoizedFunction(
|
||||
new Function1<KotlinJvmBinaryClass, Map<MemberSignature, List<AnnotationDescriptor>>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<MemberSignature, List<AnnotationDescriptor>> invoke(@NotNull KotlinJvmBinaryClass kotlinClass) {
|
||||
try {
|
||||
return loadMemberAnnotationsFromClass(kotlinClass);
|
||||
}
|
||||
catch (IOException e) {
|
||||
errorReporter.reportAnnotationLoadingError(
|
||||
"Error loading member annotations from Kotlin class: " + kotlinClass, e);
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setClassResolver(DependencyClassByQualifiedNameResolver classResolver) {
|
||||
this.classResolver = classResolver;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setErrorReporter(ErrorReporter errorReporter) {
|
||||
this.errorReporter = errorReporter;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MemoizedFunctionToNotNull<KotlinJvmBinaryClass, Map<MemberSignature, List<AnnotationDescriptor>>> getMemberAnnotations() {
|
||||
return memberAnnotations;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Map<MemberSignature, List<AnnotationDescriptor>> loadMemberAnnotationsFromClass(@NotNull KotlinJvmBinaryClass kotlinClass)
|
||||
throws IOException {
|
||||
final Map<MemberSignature, List<AnnotationDescriptor>> memberAnnotations =
|
||||
new HashMap<MemberSignature, List<AnnotationDescriptor>>();
|
||||
|
||||
kotlinClass.loadMemberAnnotations(new KotlinJvmBinaryClass.MemberVisitor() {
|
||||
@Nullable
|
||||
@Override
|
||||
public KotlinJvmBinaryClass.MethodAnnotationVisitor visitMethod(@NotNull Name name, @NotNull String desc) {
|
||||
return new AnnotationVisitorForMethod(MemberSignature.fromMethodNameAndDesc(name, desc));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public KotlinJvmBinaryClass.AnnotationVisitor visitField(@NotNull Name name, @NotNull String desc) {
|
||||
return new MemberAnnotationVisitor(MemberSignature.fromFieldNameAndDesc(name, desc));
|
||||
}
|
||||
|
||||
class AnnotationVisitorForMethod extends MemberAnnotationVisitor implements KotlinJvmBinaryClass.MethodAnnotationVisitor {
|
||||
public AnnotationVisitorForMethod(@NotNull MemberSignature signature) {
|
||||
super(signature);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public KotlinJvmBinaryClass.AnnotationArgumentVisitor visitParameterAnnotation(int index, @NotNull JvmClassName className) {
|
||||
MemberSignature paramSignature = MemberSignature.fromMethodSignatureAndParameterIndex(signature, index);
|
||||
List<AnnotationDescriptor> result = memberAnnotations.get(paramSignature);
|
||||
if (result == null) {
|
||||
result = new ArrayList<AnnotationDescriptor>();
|
||||
memberAnnotations.put(paramSignature, result);
|
||||
}
|
||||
return AnnotationDescriptorDeserializer.resolveAnnotation(className, result, classResolver);
|
||||
}
|
||||
}
|
||||
|
||||
class MemberAnnotationVisitor implements KotlinJvmBinaryClass.AnnotationVisitor {
|
||||
private final List<AnnotationDescriptor> result = new ArrayList<AnnotationDescriptor>();
|
||||
protected final MemberSignature signature;
|
||||
|
||||
public MemberAnnotationVisitor(@NotNull MemberSignature signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public KotlinJvmBinaryClass.AnnotationArgumentVisitor visitAnnotation(@NotNull JvmClassName className) {
|
||||
return AnnotationDescriptorDeserializer.resolveAnnotation(className, result, classResolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (!result.isEmpty()) {
|
||||
memberAnnotations.put(signature, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return memberAnnotations;
|
||||
}
|
||||
|
||||
// The purpose of this class is to hold a unique signature of either a method or a field, so that annotations on a member can be put
|
||||
// into a map indexed by these signatures
|
||||
protected static final class MemberSignature {
|
||||
private final String signature;
|
||||
|
||||
private MemberSignature(@NotNull String signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static MemberSignature fromMethodNameAndDesc(@NotNull Name name, @NotNull String desc) {
|
||||
return new MemberSignature(name.asString() + desc);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static MemberSignature fromFieldNameAndDesc(@NotNull Name name, @NotNull String desc) {
|
||||
return new MemberSignature(name.asString() + "#" + desc);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static MemberSignature fromMethodSignatureAndParameterIndex(@NotNull MemberSignature signature, int index) {
|
||||
return new MemberSignature(signature.signature + "@" + index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return signature.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof MemberSignature && signature.equals(((MemberSignature) o).signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return signature;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -43,7 +43,7 @@ import static org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader.Kin
|
||||
import static org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader.Kind.PACKAGE_FACADE;
|
||||
|
||||
public final class DeserializedDescriptorResolver {
|
||||
private AnnotationDescriptorDeserializer annotationDeserializer;
|
||||
private DescriptorDeserializers annotationDeserializer;
|
||||
|
||||
private StorageManager storageManager;
|
||||
|
||||
@@ -69,7 +69,7 @@ public final class DeserializedDescriptorResolver {
|
||||
};
|
||||
|
||||
@Inject
|
||||
public void setAnnotationDeserializer(AnnotationDescriptorDeserializer annotationDeserializer) {
|
||||
public void setAnnotationDeserializer(DescriptorDeserializers annotationDeserializer) {
|
||||
this.annotationDeserializer = annotationDeserializer;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user