Extract module 'deserialization' out of 'serialization'

'deserialization' stays in core because it's needed both in compiler and
reflection, but 'serialization' is used only in the compiler
This commit is contained in:
Alexander Udalov
2015-03-27 04:24:32 +03:00
parent d09e0e73fa
commit 32c3bb8c7f
60 changed files with 203 additions and 188 deletions
+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="protobuf-java" level="project" />
<orderEntry type="library" name="javax.inject" level="project" />
<orderEntry type="module" module-name="descriptors" />
<orderEntry type="module" module-name="deserialization" exported="" />
<orderEntry type="module" module-name="util" />
</component>
</module>
@@ -0,0 +1,145 @@
/*
* Copyright 2010-2015 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.kotlin.serialization
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.serialization.ProtoBuf.Annotation.Argument.Value
import org.jetbrains.kotlin.serialization.ProtoBuf.Annotation.Argument.Value.Type
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
public object AnnotationSerializer {
public fun serializeAnnotation(annotation: AnnotationDescriptor, stringTable: StringTable): ProtoBuf.Annotation {
return with(ProtoBuf.Annotation.newBuilder()) {
val annotationClass = annotation.getType().getConstructor().getDeclarationDescriptor() as? ClassDescriptor
?: error("Annotation type is not a class: ${annotation.getType()}")
setId(stringTable.getFqNameIndex(annotationClass))
for ((parameter, value) in annotation.getAllValueArguments()) {
val argument = ProtoBuf.Annotation.Argument.newBuilder()
argument.setNameId(stringTable.getSimpleNameIndex(parameter.getName()))
argument.setValue(valueProto(value, parameter.getType(), stringTable))
addArgument(argument)
}
build()
}
}
fun valueProto(constant: CompileTimeConstant<*>, type: JetType, nameTable: StringTable): Value.Builder = with(Value.newBuilder()) {
constant.accept(object : AnnotationArgumentVisitor<Unit, Unit> {
override fun visitAnnotationValue(value: AnnotationValue, data: Unit) {
setType(Type.ANNOTATION)
setAnnotation(serializeAnnotation(value.getValue(), nameTable))
}
override fun visitArrayValue(value: ArrayValue, data: Unit) {
setType(Type.ARRAY)
for (element in value.getValue()) {
addArrayElement(valueProto(element, KotlinBuiltIns.getInstance().getArrayElementType(type), nameTable).build())
}
}
override fun visitBooleanValue(value: BooleanValue, data: Unit) {
setType(Type.BOOLEAN)
setIntValue(if (value.getValue()) 1 else 0)
}
override fun visitByteValue(value: ByteValue, data: Unit) {
setType(Type.BYTE)
setIntValue(value.getValue().toLong())
}
override fun visitCharValue(value: CharValue, data: Unit) {
setType(Type.CHAR)
setIntValue(value.getValue().toLong())
}
override fun visitDoubleValue(value: DoubleValue, data: Unit) {
setType(Type.DOUBLE)
setDoubleValue(value.getValue())
}
override fun visitEnumValue(value: EnumValue, data: Unit) {
setType(Type.ENUM)
val enumEntry = value.getValue()
setClassId(nameTable.getFqNameIndex(enumEntry.getContainingDeclaration() as ClassDescriptor))
setEnumValueId(nameTable.getSimpleNameIndex(enumEntry.getName()))
}
override fun visitErrorValue(value: ErrorValue, data: Unit) {
throw UnsupportedOperationException("Error value: $value")
}
override fun visitFloatValue(value: FloatValue, data: Unit) {
setType(Type.FLOAT)
setFloatValue(value.getValue())
}
override fun visitIntValue(value: IntValue, data: Unit) {
setType(Type.INT)
setIntValue(value.getValue().toLong())
}
override fun visitJavaClassValue(value: JavaClassValue, data: Unit) {
// TODO: support class literals
throw UnsupportedOperationException("Class literal annotation arguments are not yet supported: $value")
}
override fun visitLongValue(value: LongValue, data: Unit) {
setType(Type.LONG)
setIntValue(value.getValue())
}
override fun visitNullValue(value: NullValue, data: Unit) {
throw UnsupportedOperationException("Null should not appear in annotation arguments")
}
override fun visitNumberTypeValue(constant: IntegerValueTypeConstant, data: Unit) {
// TODO: IntegerValueTypeConstant should not occur in annotation arguments
val number = constant.getValue(type)
val specificConstant = with(KotlinBuiltIns.getInstance()) {
when (type) {
getLongType() -> LongValue(number.toLong(), true, true, true)
getIntType() -> IntValue(number.toInt(), true, true, true)
getShortType() -> ShortValue(number.toShort(), true, true, true)
getByteType() -> ByteValue(number.toByte(), true, true, true)
else -> throw IllegalStateException("Integer constant $constant has non-integer type $type")
}
}
specificConstant.accept(this, data)
}
override fun visitShortValue(value: ShortValue, data: Unit) {
setType(Type.SHORT)
setIntValue(value.getValue().toLong())
}
override fun visitStringValue(value: StringValue, data: Unit) {
setType(Type.STRING)
setStringValue(nameTable.getStringIndex(value.getValue()))
}
}, Unit)
this
}
}
@@ -0,0 +1,442 @@
/*
* Copyright 2010-2015 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.kotlin.serialization;
import kotlin.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotated;
import org.jetbrains.kotlin.resolve.DescriptorFactory;
import org.jetbrains.kotlin.resolve.MemberComparator;
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
import org.jetbrains.kotlin.resolve.constants.NullValue;
import org.jetbrains.kotlin.types.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getSecondaryConstructors;
public class DescriptorSerializer {
private final StringTable stringTable;
private final Interner<TypeParameterDescriptor> typeParameters;
private final SerializerExtension extension;
private DescriptorSerializer(StringTable stringTable, Interner<TypeParameterDescriptor> typeParameters, SerializerExtension extension) {
this.stringTable = stringTable;
this.typeParameters = typeParameters;
this.extension = extension;
}
@NotNull
public static DescriptorSerializer createTopLevel(@NotNull SerializerExtension extension) {
return new DescriptorSerializer(new StringTable(extension), new Interner<TypeParameterDescriptor>(), extension);
}
@NotNull
public static DescriptorSerializer create(@NotNull ClassDescriptor descriptor, @NotNull SerializerExtension extension) {
DeclarationDescriptor container = descriptor.getContainingDeclaration();
DescriptorSerializer parentSerializer =
container instanceof ClassDescriptor
? create((ClassDescriptor) container, extension)
: createTopLevel(extension);
// Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always
// serializing outer classes before nested classes.
// Otherwise our interner can get wrong ids because we may serialize classes in any order.
DescriptorSerializer serializer = parentSerializer.createChildSerializer();
for (TypeParameterDescriptor typeParameter : descriptor.getTypeConstructor().getParameters()) {
serializer.typeParameters.intern(typeParameter);
}
return serializer;
}
private DescriptorSerializer createChildSerializer() {
return new DescriptorSerializer(stringTable, new Interner<TypeParameterDescriptor>(typeParameters), extension);
}
@NotNull
public StringTable getStringTable() {
return stringTable;
}
@NotNull
public ProtoBuf.Class.Builder classProto(@NotNull ClassDescriptor classDescriptor) {
ProtoBuf.Class.Builder builder = ProtoBuf.Class.newBuilder();
int flags = Flags.getClassFlags(hasAnnotations(classDescriptor), classDescriptor.getVisibility(), classDescriptor.getModality(),
classDescriptor.getKind(), classDescriptor.isInner(), classDescriptor.isCompanionObject());
builder.setFlags(flags);
builder.setFqName(getClassId(classDescriptor));
for (TypeParameterDescriptor typeParameterDescriptor : classDescriptor.getTypeConstructor().getParameters()) {
builder.addTypeParameter(typeParameter(typeParameterDescriptor));
}
if (!KotlinBuiltIns.isSpecialClassWithNoSupertypes(classDescriptor)) {
// Special classes (Any, Nothing) have no supertypes
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
builder.addSupertype(type(supertype));
}
}
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
if (primaryConstructor != null) {
if (DescriptorFactory.isDefaultPrimaryConstructor(primaryConstructor)) {
builder.setPrimaryConstructor(ProtoBuf.Class.PrimaryConstructor.getDefaultInstance());
}
else {
ProtoBuf.Class.PrimaryConstructor.Builder constructorBuilder = ProtoBuf.Class.PrimaryConstructor.newBuilder();
constructorBuilder.setData(callableProto(primaryConstructor));
builder.setPrimaryConstructor(constructorBuilder);
}
}
for (ConstructorDescriptor constructorDescriptor : getSecondaryConstructors(classDescriptor)) {
builder.addSecondaryConstructor(callableProto(constructorDescriptor));
}
for (DeclarationDescriptor descriptor : sort(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors())) {
if (descriptor instanceof CallableMemberDescriptor) {
CallableMemberDescriptor member = (CallableMemberDescriptor) descriptor;
if (member.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue;
builder.addMember(callableProto(member));
}
}
for (DeclarationDescriptor descriptor : sort(classDescriptor.getUnsubstitutedInnerClassesScope().getAllDescriptors())) {
int name = stringTable.getSimpleNameIndex(descriptor.getName());
if (isEnumEntry(descriptor)) {
builder.addEnumEntry(name);
}
else {
builder.addNestedClassName(name);
}
}
ClassDescriptor companionObjectDescriptor = classDescriptor.getCompanionObjectDescriptor();
if (companionObjectDescriptor != null) {
builder.setCompanionObjectName(stringTable.getSimpleNameIndex(companionObjectDescriptor.getName()));
}
extension.serializeClass(classDescriptor, builder, stringTable);
return builder;
}
@NotNull
public ProtoBuf.Callable.Builder callableProto(@NotNull CallableMemberDescriptor descriptor) {
ProtoBuf.Callable.Builder builder = ProtoBuf.Callable.newBuilder();
DescriptorSerializer local = createChildSerializer();
boolean hasGetter = false;
boolean hasSetter = false;
boolean hasConstant = false;
if (descriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
int propertyFlags = Flags.getAccessorFlags(
hasAnnotations(propertyDescriptor),
propertyDescriptor.getVisibility(),
propertyDescriptor.getModality(),
false
);
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
if (getter != null) {
hasGetter = true;
int accessorFlags = getAccessorFlags(getter);
if (accessorFlags != propertyFlags) {
builder.setGetterFlags(accessorFlags);
}
}
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
if (setter != null) {
hasSetter = true;
int accessorFlags = getAccessorFlags(setter);
if (accessorFlags != propertyFlags) {
builder.setSetterFlags(accessorFlags);
}
if (!setter.isDefault()) {
for (ValueParameterDescriptor valueParameterDescriptor : setter.getValueParameters()) {
builder.addValueParameter(local.valueParameter(valueParameterDescriptor));
}
}
}
CompileTimeConstant<?> compileTimeConstant = propertyDescriptor.getCompileTimeInitializer();
hasConstant = !(compileTimeConstant == null || compileTimeConstant instanceof NullValue);
}
builder.setFlags(Flags.getCallableFlags(
hasAnnotations(descriptor),
descriptor.getVisibility(),
descriptor.getModality(),
descriptor.getKind(),
callableKind(descriptor),
hasGetter,
hasSetter,
hasConstant
));
for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) {
builder.addTypeParameter(local.typeParameter(typeParameterDescriptor));
}
ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
if (receiverParameter != null) {
builder.setReceiverType(local.type(receiverParameter.getType()));
}
builder.setName(stringTable.getSimpleNameIndex(descriptor.getName()));
for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) {
builder.addValueParameter(local.valueParameter(valueParameterDescriptor));
}
//noinspection ConstantConditions
builder.setReturnType(local.type(descriptor.getReturnType()));
extension.serializeCallable(descriptor, builder, stringTable);
return builder;
}
private static int getAccessorFlags(@NotNull PropertyAccessorDescriptor accessor) {
return Flags.getAccessorFlags(
hasAnnotations(accessor),
accessor.getVisibility(),
accessor.getModality(),
!accessor.isDefault()
);
}
@NotNull
private static ProtoBuf.Callable.CallableKind callableKind(@NotNull CallableMemberDescriptor descriptor) {
if (descriptor instanceof PropertyDescriptor) {
return ((PropertyDescriptor) descriptor).isVar() ? ProtoBuf.Callable.CallableKind.VAR : ProtoBuf.Callable.CallableKind.VAL;
}
if (descriptor instanceof ConstructorDescriptor) {
return ProtoBuf.Callable.CallableKind.CONSTRUCTOR;
}
assert descriptor instanceof FunctionDescriptor : "Unknown descriptor class: " + descriptor.getClass();
return ProtoBuf.Callable.CallableKind.FUN;
}
@NotNull
private ProtoBuf.Callable.ValueParameter.Builder valueParameter(@NotNull ValueParameterDescriptor descriptor) {
ProtoBuf.Callable.ValueParameter.Builder builder = ProtoBuf.Callable.ValueParameter.newBuilder();
builder.setFlags(Flags.getValueParameterFlags(hasAnnotations(descriptor), descriptor.declaresDefaultValue()));
builder.setName(stringTable.getSimpleNameIndex(descriptor.getName()));
builder.setType(type(descriptor.getType()));
JetType varargElementType = descriptor.getVarargElementType();
if (varargElementType != null) {
builder.setVarargElementType(type(varargElementType));
}
extension.serializeValueParameter(descriptor, builder, stringTable);
return builder;
}
private ProtoBuf.TypeParameter.Builder typeParameter(TypeParameterDescriptor typeParameter) {
ProtoBuf.TypeParameter.Builder builder = ProtoBuf.TypeParameter.newBuilder();
builder.setId(getTypeParameterId(typeParameter));
builder.setName(stringTable.getSimpleNameIndex(typeParameter.getName()));
// to avoid storing a default
if (typeParameter.isReified()) {
builder.setReified(true);
}
// to avoid storing a default
ProtoBuf.TypeParameter.Variance variance = variance(typeParameter.getVariance());
if (variance != ProtoBuf.TypeParameter.Variance.INV) {
builder.setVariance(variance);
}
for (JetType upperBound : typeParameter.getUpperBounds()) {
builder.addUpperBound(type(upperBound));
}
return builder;
}
private static ProtoBuf.TypeParameter.Variance variance(Variance variance) {
switch (variance) {
case INVARIANT:
return ProtoBuf.TypeParameter.Variance.INV;
case IN_VARIANCE:
return ProtoBuf.TypeParameter.Variance.IN;
case OUT_VARIANCE:
return ProtoBuf.TypeParameter.Variance.OUT;
}
throw new IllegalStateException("Unknown variance: " + variance);
}
@NotNull
public ProtoBuf.Type.Builder type(@NotNull JetType type) {
assert !type.isError() : "Can't serialize error types: " + type; // TODO
if (TypesPackage.isFlexible(type)) return flexibleType(type);
ProtoBuf.Type.Builder builder = ProtoBuf.Type.newBuilder();
builder.setConstructor(typeConstructor(type.getConstructor()));
for (TypeProjection projection : type.getArguments()) {
builder.addArgument(typeArgument(projection));
}
// to avoid storing a default
if (type.isMarkedNullable()) {
builder.setNullable(true);
}
return builder;
}
private ProtoBuf.Type.Builder flexibleType(@NotNull JetType type) {
Flexibility flexibility = TypesPackage.flexibility(type);
ProtoBuf.Type.Builder builder = type(flexibility.getLowerBound());
builder.setFlexibleTypeCapabilitiesId(stringTable.getStringIndex(flexibility.getExtraCapabilities().getId()));
builder.setFlexibleUpperBound(type(flexibility.getUpperBound()));
return builder;
}
@NotNull
private ProtoBuf.Type.Argument.Builder typeArgument(@NotNull TypeProjection typeProjection) {
ProtoBuf.Type.Argument.Builder builder = ProtoBuf.Type.Argument.newBuilder();
if (typeProjection.isStarProjection()) {
builder.setProjection(ProtoBuf.Type.Argument.Projection.STAR);
}
else {
ProtoBuf.Type.Argument.Projection projection = projection(typeProjection.getProjectionKind());
// to avoid storing a default
if (projection != ProtoBuf.Type.Argument.Projection.INV) {
builder.setProjection(projection);
}
builder.setType(type(typeProjection.getType()));
}
return builder;
}
@NotNull
private ProtoBuf.Type.Constructor.Builder typeConstructor(@NotNull TypeConstructor typeConstructor) {
ProtoBuf.Type.Constructor.Builder builder = ProtoBuf.Type.Constructor.newBuilder();
ClassifierDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
assert declarationDescriptor instanceof TypeParameterDescriptor || declarationDescriptor instanceof ClassDescriptor
: "Unknown declaration descriptor: " + typeConstructor;
if (declarationDescriptor instanceof TypeParameterDescriptor) {
TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
builder.setKind(ProtoBuf.Type.Constructor.Kind.TYPE_PARAMETER);
builder.setId(getTypeParameterId(typeParameterDescriptor));
}
else {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
//default: builder.setKind(Type.Constructor.Kind.CLASS);
builder.setId(getClassId(classDescriptor));
}
return builder;
}
@NotNull
public ProtoBuf.Package.Builder packageProto(@NotNull Collection<PackageFragmentDescriptor> fragments) {
return packageProto(fragments, null);
}
@NotNull
public ProtoBuf.Package.Builder packageProto(@NotNull Collection<PackageFragmentDescriptor> fragments, @Nullable Function1<DeclarationDescriptor, Boolean> skip) {
ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder();
Collection<DeclarationDescriptor> members = new ArrayList<DeclarationDescriptor>();
for (PackageFragmentDescriptor fragment : fragments) {
members.addAll(fragment.getMemberScope().getAllDescriptors());
}
for (DeclarationDescriptor declaration : sort(members)) {
if (skip != null && skip.invoke(declaration)) continue;
if (declaration instanceof PropertyDescriptor || declaration instanceof FunctionDescriptor) {
builder.addMember(callableProto((CallableMemberDescriptor) declaration));
}
}
extension.serializePackage(fragments, builder, stringTable);
return builder;
}
@NotNull
private static ProtoBuf.Type.Argument.Projection projection(@NotNull Variance projectionKind) {
switch (projectionKind) {
case INVARIANT:
return ProtoBuf.Type.Argument.Projection.INV;
case IN_VARIANCE:
return ProtoBuf.Type.Argument.Projection.IN;
case OUT_VARIANCE:
return ProtoBuf.Type.Argument.Projection.OUT;
}
throw new IllegalStateException("Unknown projectionKind: " + projectionKind);
}
private int getClassId(@NotNull ClassDescriptor descriptor) {
return stringTable.getFqNameIndex(descriptor);
}
private int getTypeParameterId(@NotNull TypeParameterDescriptor descriptor) {
return typeParameters.intern(descriptor);
}
private static boolean hasAnnotations(Annotated descriptor) {
return !descriptor.getAnnotations().isEmpty();
}
@NotNull
public static <T extends DeclarationDescriptor> List<T> sort(@NotNull Collection<T> descriptors) {
List<T> result = new ArrayList<T>(descriptors);
//NOTE: the exact comparator does matter here
Collections.sort(result, MemberComparator.INSTANCE);
return result;
}
}
@@ -0,0 +1,71 @@
/*
* Copyright 2010-2015 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.kotlin.serialization;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class Interner<T> {
private final Interner<T> parent;
private final int firstIndex;
private final Map<T, Integer> interned = new HashMap<T, Integer>();
public Interner(Interner<T> parent) {
this.parent = parent;
this.firstIndex = parent != null ? parent.interned.size() + parent.firstIndex : 0;
}
public Interner() {
this(null);
}
@Nullable
private Integer find(@NotNull T obj) {
assert parent == null || parent.interned.size() + parent.firstIndex == firstIndex :
"Parent changed in parallel with child: indexes will be wrong";
if (parent != null) {
Integer index = parent.find(obj);
if (index != null) return index;
}
return interned.get(obj);
}
public int intern(@NotNull T obj) {
Integer index = find(obj);
if (index != null) return index;
index = firstIndex + interned.size();
interned.put(obj, index);
return index;
}
@NotNull
public List<T> getAllInternedObjects() {
return KotlinPackage.toSortedListBy(interned.keySet(), new Function1<T, Integer>() {
@Override
public Integer invoke(T key) {
return interned.get(key);
}
});
}
}
@@ -0,0 +1,74 @@
/*
* Copyright 2010-2015 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.kotlin.serialization;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.serialization.deserialization.NameResolver;
import org.jetbrains.kotlin.utils.UtilsPackage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class SerializationUtil {
private SerializationUtil() {
}
@NotNull
public static byte[] serializeClassData(@NotNull ClassData classData) {
try {
ByteArrayOutputStream result = new ByteArrayOutputStream();
serializeNameResolver(result, classData.getNameResolver());
classData.getClassProto().writeTo(result);
return result.toByteArray();
}
catch (IOException e) {
throw UtilsPackage.rethrow(e);
}
}
@NotNull
public static byte[] serializePackageData(@NotNull PackageData packageData) {
try {
ByteArrayOutputStream result = new ByteArrayOutputStream();
serializeNameResolver(result, packageData.getNameResolver());
packageData.getPackageProto().writeTo(result);
return result.toByteArray();
}
catch (IOException e) {
throw UtilsPackage.rethrow(e);
}
}
private static void serializeNameResolver(@NotNull OutputStream out, @NotNull NameResolver nameResolver) {
serializeStringTable(out, nameResolver.getStringTable(), nameResolver.getQualifiedNameTable());
}
public static void serializeStringTable(
@NotNull OutputStream out,
@NotNull ProtoBuf.StringTable stringTable,
@NotNull ProtoBuf.QualifiedNameTable qualifiedNameTable
) {
try {
stringTable.writeDelimitedTo(out);
qualifiedNameTable.writeDelimitedTo(out);
}
catch (IOException e) {
throw UtilsPackage.rethrow(e);
}
}
}
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2015 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.kotlin.serialization;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import java.util.Collection;
public abstract class SerializerExtension {
public void serializeClass(
@NotNull ClassDescriptor descriptor,
@NotNull ProtoBuf.Class.Builder proto,
@NotNull StringTable stringTable
) {
}
public void serializePackage(
@NotNull Collection<PackageFragmentDescriptor> packageFragments,
@NotNull ProtoBuf.Package.Builder proto,
@NotNull StringTable stringTable
) {
}
public void serializeCallable(
@NotNull CallableMemberDescriptor callable,
@NotNull ProtoBuf.Callable.Builder proto,
@NotNull StringTable stringTable
) {
}
public void serializeValueParameter(
@NotNull ValueParameterDescriptor descriptor,
@NotNull ProtoBuf.Callable.ValueParameter.Builder proto,
@NotNull StringTable stringTable
) {
}
@NotNull
public String getLocalClassName(@NotNull ClassDescriptor descriptor) {
throw new UnsupportedOperationException("Local classes are unsupported: " + descriptor);
}
}
@@ -0,0 +1,138 @@
/*
* Copyright 2010-2015 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.kotlin.serialization;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.ClassOrPackageFragmentDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import static org.jetbrains.kotlin.serialization.ProtoBuf.QualifiedNameTable.QualifiedName;
public class StringTable {
private static final class FqNameProto {
public final QualifiedName.Builder fqName;
public FqNameProto(@NotNull QualifiedName.Builder fqName) {
this.fqName = fqName;
}
@Override
public int hashCode() {
int result = 13;
result = 31 * result + fqName.getParentQualifiedName();
result = 31 * result + fqName.getShortName();
result = 31 * result + fqName.getKind().hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) return false;
QualifiedName.Builder other = ((FqNameProto) obj).fqName;
return fqName.getParentQualifiedName() == other.getParentQualifiedName()
&& fqName.getShortName() == other.getShortName()
&& fqName.getKind() == other.getKind();
}
}
private final Interner<String> strings = new Interner<String>();
private final Interner<FqNameProto> qualifiedNames = new Interner<FqNameProto>();
private final SerializerExtension extension;
public StringTable(@NotNull SerializerExtension extension) {
this.extension = extension;
}
public int getSimpleNameIndex(@NotNull Name name) {
return getStringIndex(name.asString());
}
public int getStringIndex(@NotNull String string) {
return strings.intern(string);
}
public int getFqNameIndex(@NotNull ClassOrPackageFragmentDescriptor descriptor) {
QualifiedName.Builder builder = QualifiedName.newBuilder();
if (descriptor instanceof ClassDescriptor) {
builder.setKind(QualifiedName.Kind.CLASS);
}
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
int shortName;
if (containingDeclaration instanceof PackageFragmentDescriptor) {
shortName = getSimpleNameIndex(descriptor.getName());
PackageFragmentDescriptor fragment = (PackageFragmentDescriptor) containingDeclaration;
if (!fragment.getFqName().isRoot()) {
builder.setParentQualifiedName(getFqNameIndex(fragment.getFqName()));
}
}
else if (containingDeclaration instanceof ClassDescriptor) {
shortName = getSimpleNameIndex(descriptor.getName());
ClassDescriptor outerClass = (ClassDescriptor) containingDeclaration;
builder.setParentQualifiedName(getFqNameIndex(outerClass));
}
else {
if (descriptor instanceof ClassDescriptor) {
builder.setKind(QualifiedName.Kind.LOCAL);
shortName = getStringIndex(extension.getLocalClassName((ClassDescriptor) descriptor));
}
else {
throw new IllegalStateException("Package container should be a package: " + descriptor);
}
}
builder.setShortName(shortName);
return qualifiedNames.intern(new FqNameProto(builder));
}
public int getFqNameIndex(@NotNull FqName fqName) {
int result = -1;
for (Name segment : fqName.pathSegments()) {
QualifiedName.Builder builder = QualifiedName.newBuilder();
builder.setShortName(getSimpleNameIndex(segment));
if (result != -1) {
builder.setParentQualifiedName(result);
}
result = qualifiedNames.intern(new FqNameProto(builder));
}
return result;
}
@NotNull
public ProtoBuf.StringTable serializeSimpleNames() {
ProtoBuf.StringTable.Builder builder = ProtoBuf.StringTable.newBuilder();
for (String simpleName : strings.getAllInternedObjects()) {
builder.addString(simpleName);
}
return builder.build();
}
@NotNull
public ProtoBuf.QualifiedNameTable serializeQualifiedNames() {
ProtoBuf.QualifiedNameTable.Builder builder = ProtoBuf.QualifiedNameTable.newBuilder();
for (FqNameProto fqName : qualifiedNames.getAllInternedObjects()) {
builder.addQualifiedName(fqName.fqName);
}
return builder.build();
}
}
@@ -0,0 +1,78 @@
/*
* Copyright 2010-2015 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.kotlin.serialization.builtins
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.constants.NullValue
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.serialization.AnnotationSerializer
import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.SerializerExtension
import org.jetbrains.kotlin.serialization.StringTable
public object BuiltInsSerializerExtension : SerializerExtension() {
override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder, stringTable: StringTable) {
for (annotation in descriptor.getAnnotations()) {
proto.addExtension(BuiltInsProtoBuf.classAnnotation, AnnotationSerializer.serializeAnnotation(annotation, stringTable))
}
}
override fun serializePackage(
packageFragments: Collection<PackageFragmentDescriptor>,
proto: ProtoBuf.Package.Builder,
stringTable: StringTable
) {
val classes = packageFragments.flatMap {
it.getMemberScope().getDescriptors(DescriptorKindFilter.CLASSIFIERS).filterIsInstance<ClassDescriptor>()
}
for (descriptor in DescriptorSerializer.sort(classes)) {
proto.addExtension(BuiltInsProtoBuf.className, stringTable.getSimpleNameIndex(descriptor.getName()))
}
}
override fun serializeCallable(
callable: CallableMemberDescriptor,
proto: ProtoBuf.Callable.Builder,
stringTable: StringTable
) {
for (annotation in callable.getAnnotations()) {
proto.addExtension(BuiltInsProtoBuf.callableAnnotation, AnnotationSerializer.serializeAnnotation(annotation, stringTable))
}
val compileTimeConstant = (callable as? PropertyDescriptor)?.getCompileTimeInitializer()
if (compileTimeConstant != null && compileTimeConstant !is NullValue) {
val type = compileTimeConstant.getType(KotlinBuiltIns.getInstance())
proto.setExtension(BuiltInsProtoBuf.compileTimeValue, AnnotationSerializer.valueProto(compileTimeConstant, type, stringTable).build())
}
}
override fun serializeValueParameter(
descriptor: ValueParameterDescriptor,
proto: ProtoBuf.Callable.ValueParameter.Builder,
stringTable: StringTable
) {
for (annotation in descriptor.getAnnotations()) {
proto.addExtension(BuiltInsProtoBuf.parameterAnnotation, AnnotationSerializer.serializeAnnotation(annotation, stringTable))
}
}
}