001 /* 002 * Copyright 2010-2015 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.kotlin.serialization; 018 019 import com.google.protobuf.MessageLite; 020 import kotlin.CollectionsKt; 021 import kotlin.jvm.functions.Function1; 022 import org.jetbrains.annotations.NotNull; 023 import org.jetbrains.annotations.Nullable; 024 import org.jetbrains.kotlin.builtins.KotlinBuiltIns; 025 import org.jetbrains.kotlin.descriptors.*; 026 import org.jetbrains.kotlin.descriptors.annotations.Annotated; 027 import org.jetbrains.kotlin.name.Name; 028 import org.jetbrains.kotlin.resolve.MemberComparator; 029 import org.jetbrains.kotlin.resolve.constants.ConstantValue; 030 import org.jetbrains.kotlin.resolve.constants.NullValue; 031 import org.jetbrains.kotlin.types.*; 032 import org.jetbrains.kotlin.utils.ExceptionUtilsKt; 033 import org.jetbrains.kotlin.utils.Interner; 034 035 import java.io.ByteArrayOutputStream; 036 import java.io.IOException; 037 import java.util.*; 038 039 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry; 040 041 public class DescriptorSerializer { 042 private final DeclarationDescriptor containingDeclaration; 043 private final Interner<TypeParameterDescriptor> typeParameters; 044 private final SerializerExtension extension; 045 private final MutableTypeTable typeTable; 046 private final boolean serializeTypeTableToFunction; 047 048 private DescriptorSerializer( 049 @Nullable DeclarationDescriptor containingDeclaration, 050 @NotNull Interner<TypeParameterDescriptor> typeParameters, 051 @NotNull SerializerExtension extension, 052 @NotNull MutableTypeTable typeTable, 053 boolean serializeTypeTableToFunction 054 ) { 055 this.containingDeclaration = containingDeclaration; 056 this.typeParameters = typeParameters; 057 this.extension = extension; 058 this.typeTable = typeTable; 059 this.serializeTypeTableToFunction = serializeTypeTableToFunction; 060 } 061 062 @NotNull 063 public byte[] serialize(@NotNull MessageLite message) { 064 try { 065 ByteArrayOutputStream result = new ByteArrayOutputStream(); 066 getStringTable().serializeTo(result); 067 message.writeTo(result); 068 return result.toByteArray(); 069 } 070 catch (IOException e) { 071 throw ExceptionUtilsKt.rethrow(e); 072 } 073 } 074 075 @NotNull 076 public static DescriptorSerializer createTopLevel(@NotNull SerializerExtension extension) { 077 return new DescriptorSerializer(null, new Interner<TypeParameterDescriptor>(), extension, new MutableTypeTable(), false); 078 } 079 080 @NotNull 081 public static DescriptorSerializer createForLambda(@NotNull SerializerExtension extension) { 082 return new DescriptorSerializer(null, new Interner<TypeParameterDescriptor>(), extension, new MutableTypeTable(), true); 083 } 084 085 @NotNull 086 public static DescriptorSerializer create(@NotNull ClassDescriptor descriptor, @NotNull SerializerExtension extension) { 087 DeclarationDescriptor container = descriptor.getContainingDeclaration(); 088 DescriptorSerializer parentSerializer = 089 container instanceof ClassDescriptor 090 ? create((ClassDescriptor) container, extension) 091 : createTopLevel(extension); 092 093 // Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always 094 // serializing outer classes before nested classes. 095 // Otherwise our interner can get wrong ids because we may serialize classes in any order. 096 DescriptorSerializer serializer = new DescriptorSerializer( 097 descriptor, 098 new Interner<TypeParameterDescriptor>(parentSerializer.typeParameters), 099 parentSerializer.extension, 100 new MutableTypeTable(), 101 false 102 ); 103 for (TypeParameterDescriptor typeParameter : descriptor.getTypeConstructor().getParameters()) { 104 serializer.typeParameters.intern(typeParameter); 105 } 106 return serializer; 107 } 108 109 @NotNull 110 private DescriptorSerializer createChildSerializer(@NotNull CallableDescriptor callable) { 111 return new DescriptorSerializer(callable, new Interner<TypeParameterDescriptor>(typeParameters), extension, typeTable, false); 112 } 113 114 @NotNull 115 public StringTable getStringTable() { 116 return extension.getStringTable(); 117 } 118 119 private boolean useTypeTable() { 120 return extension.shouldUseTypeTable(); 121 } 122 123 @NotNull 124 public ProtoBuf.Class.Builder classProto(@NotNull ClassDescriptor classDescriptor) { 125 ProtoBuf.Class.Builder builder = ProtoBuf.Class.newBuilder(); 126 127 int flags = Flags.getClassFlags(hasAnnotations(classDescriptor), classDescriptor.getVisibility(), classDescriptor.getModality(), 128 classDescriptor.getKind(), classDescriptor.isInner(), classDescriptor.isCompanionObject(), 129 classDescriptor.isData()); 130 if (flags != builder.getFlags()) { 131 builder.setFlags(flags); 132 } 133 134 builder.setFqName(getClassId(classDescriptor)); 135 136 for (TypeParameterDescriptor typeParameterDescriptor : classDescriptor.getTypeConstructor().getParameters()) { 137 builder.addTypeParameter(typeParameter(typeParameterDescriptor)); 138 } 139 140 if (!KotlinBuiltIns.isSpecialClassWithNoSupertypes(classDescriptor)) { 141 // Special classes (Any, Nothing) have no supertypes 142 for (KotlinType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { 143 if (useTypeTable()) { 144 builder.addSupertypeId(typeId(supertype)); 145 } 146 else { 147 builder.addSupertype(type(supertype)); 148 } 149 } 150 } 151 152 for (ConstructorDescriptor descriptor : classDescriptor.getConstructors()) { 153 builder.addConstructor(constructorProto(descriptor)); 154 } 155 156 for (DeclarationDescriptor descriptor : sort(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors())) { 157 if (descriptor instanceof CallableMemberDescriptor) { 158 CallableMemberDescriptor member = (CallableMemberDescriptor) descriptor; 159 if (member.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue; 160 161 if (descriptor instanceof PropertyDescriptor) { 162 builder.addProperty(propertyProto((PropertyDescriptor) descriptor)); 163 } 164 else if (descriptor instanceof FunctionDescriptor) { 165 builder.addFunction(functionProto((FunctionDescriptor) descriptor)); 166 } 167 } 168 } 169 170 for (DeclarationDescriptor descriptor : sort(classDescriptor.getUnsubstitutedInnerClassesScope().getAllDescriptors())) { 171 int name = getSimpleNameIndex(descriptor.getName()); 172 if (isEnumEntry(descriptor)) { 173 builder.addEnumEntry(name); 174 } 175 else { 176 builder.addNestedClassName(name); 177 } 178 } 179 180 ClassDescriptor companionObjectDescriptor = classDescriptor.getCompanionObjectDescriptor(); 181 if (companionObjectDescriptor != null) { 182 builder.setCompanionObjectName(getSimpleNameIndex(companionObjectDescriptor.getName())); 183 } 184 185 ProtoBuf.TypeTable typeTableProto = typeTable.serialize(); 186 if (typeTableProto != null) { 187 builder.setTypeTable(typeTableProto); 188 } 189 190 extension.serializeClass(classDescriptor, builder); 191 192 return builder; 193 } 194 195 @NotNull 196 public ProtoBuf.Property.Builder propertyProto(@NotNull PropertyDescriptor descriptor) { 197 ProtoBuf.Property.Builder builder = ProtoBuf.Property.newBuilder(); 198 199 DescriptorSerializer local = createChildSerializer(descriptor); 200 201 boolean hasGetter = false; 202 boolean hasSetter = false; 203 boolean lateInit = descriptor.isLateInit(); 204 boolean isConst = descriptor.isConst(); 205 206 ConstantValue<?> compileTimeConstant = descriptor.getCompileTimeInitializer(); 207 boolean hasConstant = !(compileTimeConstant == null || compileTimeConstant instanceof NullValue); 208 209 boolean hasAnnotations = !descriptor.getAnnotations().getAllAnnotations().isEmpty(); 210 211 int propertyFlags = Flags.getAccessorFlags( 212 hasAnnotations, 213 descriptor.getVisibility(), 214 descriptor.getModality(), 215 false, 216 false 217 ); 218 219 PropertyGetterDescriptor getter = descriptor.getGetter(); 220 if (getter != null) { 221 hasGetter = true; 222 int accessorFlags = getAccessorFlags(getter); 223 if (accessorFlags != propertyFlags) { 224 builder.setGetterFlags(accessorFlags); 225 } 226 } 227 228 PropertySetterDescriptor setter = descriptor.getSetter(); 229 if (setter != null) { 230 hasSetter = true; 231 int accessorFlags = getAccessorFlags(setter); 232 if (accessorFlags != propertyFlags) { 233 builder.setSetterFlags(accessorFlags); 234 } 235 236 if (!setter.isDefault()) { 237 DescriptorSerializer setterLocal = local.createChildSerializer(setter); 238 for (ValueParameterDescriptor valueParameterDescriptor : setter.getValueParameters()) { 239 builder.setSetterValueParameter(setterLocal.valueParameter(valueParameterDescriptor)); 240 } 241 } 242 } 243 244 int flags = Flags.getPropertyFlags( 245 hasAnnotations, descriptor.getVisibility(), descriptor.getModality(), descriptor.getKind(), descriptor.isVar(), 246 hasGetter, hasSetter, hasConstant, isConst, lateInit 247 ); 248 if (flags != builder.getFlags()) { 249 builder.setFlags(flags); 250 } 251 252 builder.setName(getSimpleNameIndex(descriptor.getName())); 253 254 if (useTypeTable()) { 255 builder.setReturnTypeId(local.typeId(descriptor.getType())); 256 } 257 else { 258 builder.setReturnType(local.type(descriptor.getType())); 259 } 260 261 for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) { 262 builder.addTypeParameter(local.typeParameter(typeParameterDescriptor)); 263 } 264 265 ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter(); 266 if (receiverParameter != null) { 267 if (useTypeTable()) { 268 builder.setReceiverTypeId(local.typeId(receiverParameter.getType())); 269 } 270 else { 271 builder.setReceiverType(local.type(receiverParameter.getType())); 272 } 273 } 274 275 extension.serializeProperty(descriptor, builder); 276 277 return builder; 278 } 279 280 @NotNull 281 public ProtoBuf.Function.Builder functionProto(@NotNull FunctionDescriptor descriptor) { 282 ProtoBuf.Function.Builder builder = ProtoBuf.Function.newBuilder(); 283 284 DescriptorSerializer local = createChildSerializer(descriptor); 285 286 int flags = Flags.getFunctionFlags( 287 hasAnnotations(descriptor), descriptor.getVisibility(), descriptor.getModality(), descriptor.getKind(), 288 descriptor.isOperator(), descriptor.isInfix(), descriptor.isInline(), descriptor.isTailrec(), 289 descriptor.isExternal() 290 ); 291 if (flags != builder.getFlags()) { 292 builder.setFlags(flags); 293 } 294 295 builder.setName(getSimpleNameIndex(descriptor.getName())); 296 297 if (useTypeTable()) { 298 //noinspection ConstantConditions 299 builder.setReturnTypeId(local.typeId(descriptor.getReturnType())); 300 } 301 else { 302 //noinspection ConstantConditions 303 builder.setReturnType(local.type(descriptor.getReturnType())); 304 } 305 306 for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) { 307 builder.addTypeParameter(local.typeParameter(typeParameterDescriptor)); 308 } 309 310 ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter(); 311 if (receiverParameter != null) { 312 if (useTypeTable()) { 313 builder.setReceiverTypeId(local.typeId(receiverParameter.getType())); 314 } 315 else { 316 builder.setReceiverType(local.type(receiverParameter.getType())); 317 } 318 } 319 320 for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) { 321 builder.addValueParameter(local.valueParameter(valueParameterDescriptor)); 322 } 323 324 if (serializeTypeTableToFunction) { 325 ProtoBuf.TypeTable typeTableProto = typeTable.serialize(); 326 if (typeTableProto != null) { 327 builder.setTypeTable(typeTableProto); 328 } 329 } 330 331 extension.serializeFunction(descriptor, builder); 332 333 return builder; 334 } 335 336 @NotNull 337 public ProtoBuf.Constructor.Builder constructorProto(@NotNull ConstructorDescriptor descriptor) { 338 ProtoBuf.Constructor.Builder builder = ProtoBuf.Constructor.newBuilder(); 339 340 DescriptorSerializer local = createChildSerializer(descriptor); 341 342 int flags = Flags.getConstructorFlags(hasAnnotations(descriptor), descriptor.getVisibility(), !descriptor.isPrimary()); 343 if (flags != builder.getFlags()) { 344 builder.setFlags(flags); 345 } 346 347 for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) { 348 builder.addValueParameter(local.valueParameter(valueParameterDescriptor)); 349 } 350 351 extension.serializeConstructor(descriptor, builder); 352 353 return builder; 354 } 355 356 private static int getAccessorFlags(@NotNull PropertyAccessorDescriptor accessor) { 357 return Flags.getAccessorFlags( 358 hasAnnotations(accessor), 359 accessor.getVisibility(), 360 accessor.getModality(), 361 !accessor.isDefault(), 362 accessor.isExternal() 363 ); 364 } 365 366 @NotNull 367 private ProtoBuf.ValueParameter.Builder valueParameter(@NotNull ValueParameterDescriptor descriptor) { 368 ProtoBuf.ValueParameter.Builder builder = ProtoBuf.ValueParameter.newBuilder(); 369 370 int flags = Flags.getValueParameterFlags(hasAnnotations(descriptor), descriptor.declaresDefaultValue(), 371 descriptor.isCrossinline(), descriptor.isNoinline()); 372 if (flags != builder.getFlags()) { 373 builder.setFlags(flags); 374 } 375 376 builder.setName(getSimpleNameIndex(descriptor.getName())); 377 378 if (useTypeTable()) { 379 builder.setTypeId(typeId(descriptor.getType())); 380 } 381 else { 382 builder.setType(type(descriptor.getType())); 383 } 384 385 KotlinType varargElementType = descriptor.getVarargElementType(); 386 if (varargElementType != null) { 387 if (useTypeTable()) { 388 builder.setVarargElementTypeId(typeId(varargElementType)); 389 } 390 else { 391 builder.setVarargElementType(type(varargElementType)); 392 } 393 } 394 395 extension.serializeValueParameter(descriptor, builder); 396 397 return builder; 398 } 399 400 private ProtoBuf.TypeParameter.Builder typeParameter(TypeParameterDescriptor typeParameter) { 401 ProtoBuf.TypeParameter.Builder builder = ProtoBuf.TypeParameter.newBuilder(); 402 403 builder.setId(getTypeParameterId(typeParameter)); 404 405 builder.setName(getSimpleNameIndex(typeParameter.getName())); 406 407 if (typeParameter.isReified() != builder.getReified()) { 408 builder.setReified(typeParameter.isReified()); 409 } 410 411 ProtoBuf.TypeParameter.Variance variance = variance(typeParameter.getVariance()); 412 if (variance != builder.getVariance()) { 413 builder.setVariance(variance); 414 } 415 extension.serializeTypeParameter(typeParameter, builder); 416 417 Set<KotlinType> upperBounds = typeParameter.getUpperBounds(); 418 if (upperBounds.size() == 1 && KotlinBuiltIns.isDefaultBound(CollectionsKt.single(upperBounds))) return builder; 419 420 for (KotlinType upperBound : upperBounds) { 421 if (useTypeTable()) { 422 builder.addUpperBoundId(typeId(upperBound)); 423 } 424 else { 425 builder.addUpperBound(type(upperBound)); 426 } 427 } 428 429 return builder; 430 } 431 432 private static ProtoBuf.TypeParameter.Variance variance(Variance variance) { 433 switch (variance) { 434 case INVARIANT: 435 return ProtoBuf.TypeParameter.Variance.INV; 436 case IN_VARIANCE: 437 return ProtoBuf.TypeParameter.Variance.IN; 438 case OUT_VARIANCE: 439 return ProtoBuf.TypeParameter.Variance.OUT; 440 } 441 throw new IllegalStateException("Unknown variance: " + variance); 442 } 443 444 private int typeId(@NotNull KotlinType type) { 445 return typeTable.get(type(type)); 446 } 447 448 @NotNull 449 private ProtoBuf.Type.Builder type(@NotNull KotlinType type) { 450 assert !type.isError() : "Can't serialize error types: " + type; // TODO 451 452 if (FlexibleTypesKt.isFlexible(type)) { 453 Flexibility flexibility = FlexibleTypesKt.flexibility(type); 454 455 ProtoBuf.Type.Builder lowerBound = type(flexibility.getLowerBound()); 456 lowerBound.setFlexibleTypeCapabilitiesId(getStringTable().getStringIndex(flexibility.getExtraCapabilities().getId())); 457 if (useTypeTable()) { 458 lowerBound.setFlexibleUpperBoundId(typeId(flexibility.getUpperBound())); 459 } 460 else { 461 lowerBound.setFlexibleUpperBound(type(flexibility.getUpperBound())); 462 } 463 return lowerBound; 464 } 465 466 ProtoBuf.Type.Builder builder = ProtoBuf.Type.newBuilder(); 467 468 ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); 469 if (descriptor instanceof ClassDescriptor) { 470 builder.setClassName(getClassId((ClassDescriptor) descriptor)); 471 } 472 if (descriptor instanceof TypeParameterDescriptor) { 473 TypeParameterDescriptor typeParameter = (TypeParameterDescriptor) descriptor; 474 if (typeParameter.getContainingDeclaration() == containingDeclaration) { 475 builder.setTypeParameterName(getSimpleNameIndex(typeParameter.getName())); 476 } 477 else { 478 builder.setTypeParameter(getTypeParameterId(typeParameter)); 479 } 480 } 481 482 for (TypeProjection projection : type.getArguments()) { 483 builder.addArgument(typeArgument(projection)); 484 } 485 486 if (type.isMarkedNullable() != builder.getNullable()) { 487 builder.setNullable(type.isMarkedNullable()); 488 } 489 490 extension.serializeType(type, builder); 491 492 return builder; 493 } 494 495 @NotNull 496 private ProtoBuf.Type.Argument.Builder typeArgument(@NotNull TypeProjection typeProjection) { 497 ProtoBuf.Type.Argument.Builder builder = ProtoBuf.Type.Argument.newBuilder(); 498 499 if (typeProjection.isStarProjection()) { 500 builder.setProjection(ProtoBuf.Type.Argument.Projection.STAR); 501 } 502 else { 503 ProtoBuf.Type.Argument.Projection projection = projection(typeProjection.getProjectionKind()); 504 505 if (projection != builder.getProjection()) { 506 builder.setProjection(projection); 507 } 508 509 if (useTypeTable()) { 510 builder.setTypeId(typeId(typeProjection.getType())); 511 } 512 else { 513 builder.setType(type(typeProjection.getType())); 514 } 515 } 516 517 return builder; 518 } 519 520 @NotNull 521 public ProtoBuf.Package.Builder packageProto(@NotNull Collection<PackageFragmentDescriptor> fragments) { 522 return packageProto(fragments, null); 523 } 524 525 @NotNull 526 public ProtoBuf.Package.Builder packageProtoWithoutDescriptors() { 527 ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder(); 528 529 extension.serializePackage(Collections.<PackageFragmentDescriptor>emptyList(), builder); 530 531 return builder; 532 } 533 534 @NotNull 535 public ProtoBuf.Package.Builder packageProto(@NotNull Collection<PackageFragmentDescriptor> fragments, @Nullable Function1<DeclarationDescriptor, Boolean> skip) { 536 ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder(); 537 538 Collection<DeclarationDescriptor> members = new ArrayList<DeclarationDescriptor>(); 539 for (PackageFragmentDescriptor fragment : fragments) { 540 members.addAll(fragment.getMemberScope().getAllDescriptors()); 541 } 542 543 for (DeclarationDescriptor declaration : sort(members)) { 544 if (skip != null && skip.invoke(declaration)) continue; 545 546 if (declaration instanceof PropertyDescriptor) { 547 builder.addProperty(propertyProto((PropertyDescriptor) declaration)); 548 } 549 else if (declaration instanceof FunctionDescriptor) { 550 builder.addFunction(functionProto((FunctionDescriptor) declaration)); 551 } 552 } 553 554 ProtoBuf.TypeTable typeTableProto = typeTable.serialize(); 555 if (typeTableProto != null) { 556 builder.setTypeTable(typeTableProto); 557 } 558 559 extension.serializePackage(fragments, builder); 560 561 return builder; 562 } 563 564 @NotNull 565 public ProtoBuf.Package.Builder packagePartProto(@NotNull Collection<DeclarationDescriptor> members) { 566 ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder(); 567 568 for (DeclarationDescriptor declaration : sort(members)) { 569 if (declaration instanceof PropertyDescriptor) { 570 builder.addProperty(propertyProto((PropertyDescriptor) declaration)); 571 } 572 else if (declaration instanceof FunctionDescriptor) { 573 builder.addFunction(functionProto((FunctionDescriptor) declaration)); 574 } 575 } 576 577 ProtoBuf.TypeTable typeTableProto = typeTable.serialize(); 578 if (typeTableProto != null) { 579 builder.setTypeTable(typeTableProto); 580 } 581 582 return builder; 583 } 584 585 @NotNull 586 private static ProtoBuf.Type.Argument.Projection projection(@NotNull Variance projectionKind) { 587 switch (projectionKind) { 588 case INVARIANT: 589 return ProtoBuf.Type.Argument.Projection.INV; 590 case IN_VARIANCE: 591 return ProtoBuf.Type.Argument.Projection.IN; 592 case OUT_VARIANCE: 593 return ProtoBuf.Type.Argument.Projection.OUT; 594 } 595 throw new IllegalStateException("Unknown projectionKind: " + projectionKind); 596 } 597 598 private int getClassId(@NotNull ClassDescriptor descriptor) { 599 return getStringTable().getFqNameIndex(descriptor); 600 } 601 602 private int getSimpleNameIndex(@NotNull Name name) { 603 return getStringTable().getStringIndex(name.asString()); 604 } 605 606 private int getTypeParameterId(@NotNull TypeParameterDescriptor descriptor) { 607 return typeParameters.intern(descriptor); 608 } 609 610 private static boolean hasAnnotations(Annotated descriptor) { 611 return !descriptor.getAnnotations().isEmpty(); 612 } 613 614 @NotNull 615 public static <T extends DeclarationDescriptor> List<T> sort(@NotNull Collection<T> descriptors) { 616 List<T> result = new ArrayList<T>(descriptors); 617 //NOTE: the exact comparator does matter here 618 Collections.sort(result, MemberComparator.INSTANCE); 619 return result; 620 621 } 622 }