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.jvm.functions.Function1; 021 import org.jetbrains.annotations.NotNull; 022 import org.jetbrains.annotations.Nullable; 023 import org.jetbrains.kotlin.builtins.KotlinBuiltIns; 024 import org.jetbrains.kotlin.descriptors.*; 025 import org.jetbrains.kotlin.descriptors.annotations.Annotated; 026 import org.jetbrains.kotlin.resolve.DescriptorFactory; 027 import org.jetbrains.kotlin.resolve.MemberComparator; 028 import org.jetbrains.kotlin.resolve.constants.ConstantValue; 029 import org.jetbrains.kotlin.resolve.constants.NullValue; 030 import org.jetbrains.kotlin.types.*; 031 import org.jetbrains.kotlin.utils.Interner; 032 import org.jetbrains.kotlin.utils.UtilsPackage; 033 034 import java.io.ByteArrayOutputStream; 035 import java.io.IOException; 036 import java.io.OutputStream; 037 import java.util.ArrayList; 038 import java.util.Collection; 039 import java.util.Collections; 040 import java.util.List; 041 042 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry; 043 import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getSecondaryConstructors; 044 045 public class DescriptorSerializer { 046 047 private final StringTable stringTable; 048 private final Interner<TypeParameterDescriptor> typeParameters; 049 private final SerializerExtension extension; 050 051 private DescriptorSerializer(StringTable stringTable, Interner<TypeParameterDescriptor> typeParameters, SerializerExtension extension) { 052 this.stringTable = stringTable; 053 this.typeParameters = typeParameters; 054 this.extension = extension; 055 } 056 057 @NotNull 058 public byte[] serialize(@NotNull MessageLite message) { 059 try { 060 ByteArrayOutputStream result = new ByteArrayOutputStream(); 061 serializeStringTable(result); 062 message.writeTo(result); 063 return result.toByteArray(); 064 } 065 catch (IOException e) { 066 throw UtilsPackage.rethrow(e); 067 } 068 } 069 070 public void serializeStringTable(@NotNull OutputStream out) throws IOException { 071 stringTable.serializeSimpleNames().writeDelimitedTo(out); 072 stringTable.serializeQualifiedNames().writeDelimitedTo(out); 073 } 074 075 @NotNull 076 public static DescriptorSerializer createTopLevel(@NotNull SerializerExtension extension) { 077 return new DescriptorSerializer(new StringTable(extension), new Interner<TypeParameterDescriptor>(), extension); 078 } 079 080 @NotNull 081 public static DescriptorSerializer create(@NotNull ClassDescriptor descriptor, @NotNull SerializerExtension extension) { 082 DeclarationDescriptor container = descriptor.getContainingDeclaration(); 083 DescriptorSerializer parentSerializer = 084 container instanceof ClassDescriptor 085 ? create((ClassDescriptor) container, extension) 086 : createTopLevel(extension); 087 088 // Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always 089 // serializing outer classes before nested classes. 090 // Otherwise our interner can get wrong ids because we may serialize classes in any order. 091 DescriptorSerializer serializer = parentSerializer.createChildSerializer(); 092 for (TypeParameterDescriptor typeParameter : descriptor.getTypeConstructor().getParameters()) { 093 serializer.typeParameters.intern(typeParameter); 094 } 095 return serializer; 096 } 097 098 private DescriptorSerializer createChildSerializer() { 099 return new DescriptorSerializer(stringTable, new Interner<TypeParameterDescriptor>(typeParameters), extension); 100 } 101 102 @NotNull 103 public StringTable getStringTable() { 104 return stringTable; 105 } 106 107 @NotNull 108 public ProtoBuf.Class.Builder classProto(@NotNull ClassDescriptor classDescriptor) { 109 ProtoBuf.Class.Builder builder = ProtoBuf.Class.newBuilder(); 110 111 int flags = Flags.getClassFlags(hasAnnotations(classDescriptor), classDescriptor.getVisibility(), classDescriptor.getModality(), 112 classDescriptor.getKind(), classDescriptor.isInner(), classDescriptor.isCompanionObject()); 113 builder.setFlags(flags); 114 115 builder.setFqName(getClassId(classDescriptor)); 116 117 for (TypeParameterDescriptor typeParameterDescriptor : classDescriptor.getTypeConstructor().getParameters()) { 118 builder.addTypeParameter(typeParameter(typeParameterDescriptor)); 119 } 120 121 if (!KotlinBuiltIns.isSpecialClassWithNoSupertypes(classDescriptor)) { 122 // Special classes (Any, Nothing) have no supertypes 123 for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { 124 builder.addSupertype(type(supertype)); 125 } 126 } 127 128 ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); 129 if (primaryConstructor != null) { 130 if (DescriptorFactory.isDefaultPrimaryConstructor(primaryConstructor)) { 131 builder.setPrimaryConstructor(ProtoBuf.Class.PrimaryConstructor.getDefaultInstance()); 132 } 133 else { 134 ProtoBuf.Class.PrimaryConstructor.Builder constructorBuilder = ProtoBuf.Class.PrimaryConstructor.newBuilder(); 135 constructorBuilder.setData(callableProto(primaryConstructor)); 136 builder.setPrimaryConstructor(constructorBuilder); 137 } 138 } 139 140 for (ConstructorDescriptor constructorDescriptor : getSecondaryConstructors(classDescriptor)) { 141 builder.addSecondaryConstructor(callableProto(constructorDescriptor)); 142 } 143 144 for (DeclarationDescriptor descriptor : sort(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors())) { 145 if (descriptor instanceof CallableMemberDescriptor) { 146 CallableMemberDescriptor member = (CallableMemberDescriptor) descriptor; 147 if (member.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue; 148 builder.addMember(callableProto(member)); 149 } 150 } 151 152 for (DeclarationDescriptor descriptor : sort(classDescriptor.getUnsubstitutedInnerClassesScope().getAllDescriptors())) { 153 int name = stringTable.getSimpleNameIndex(descriptor.getName()); 154 if (isEnumEntry(descriptor)) { 155 builder.addEnumEntry(name); 156 } 157 else { 158 builder.addNestedClassName(name); 159 } 160 } 161 162 ClassDescriptor companionObjectDescriptor = classDescriptor.getCompanionObjectDescriptor(); 163 if (companionObjectDescriptor != null) { 164 builder.setCompanionObjectName(stringTable.getSimpleNameIndex(companionObjectDescriptor.getName())); 165 } 166 167 extension.serializeClass(classDescriptor, builder, stringTable); 168 169 return builder; 170 } 171 172 @NotNull 173 public ProtoBuf.Callable.Builder callableProto(@NotNull CallableMemberDescriptor descriptor) { 174 ProtoBuf.Callable.Builder builder = ProtoBuf.Callable.newBuilder(); 175 176 DescriptorSerializer local = createChildSerializer(); 177 178 boolean hasGetter = false; 179 boolean hasSetter = false; 180 boolean hasConstant = false; 181 boolean lateInit = false; 182 boolean isConst = false; 183 boolean isOperator = false; 184 185 if (descriptor instanceof FunctionDescriptor) { 186 isOperator = ((FunctionDescriptor) descriptor).isOperator(); 187 } 188 189 if (descriptor instanceof PropertyDescriptor) { 190 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; 191 lateInit = propertyDescriptor.isLateInit(); 192 isConst = propertyDescriptor.isConst(); 193 194 int propertyFlags = Flags.getAccessorFlags( 195 hasAnnotations(propertyDescriptor), 196 propertyDescriptor.getVisibility(), 197 propertyDescriptor.getModality(), 198 false 199 ); 200 201 PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); 202 if (getter != null) { 203 hasGetter = true; 204 int accessorFlags = getAccessorFlags(getter); 205 if (accessorFlags != propertyFlags) { 206 builder.setGetterFlags(accessorFlags); 207 } 208 } 209 210 PropertySetterDescriptor setter = propertyDescriptor.getSetter(); 211 if (setter != null) { 212 hasSetter = true; 213 int accessorFlags = getAccessorFlags(setter); 214 if (accessorFlags != propertyFlags) { 215 builder.setSetterFlags(accessorFlags); 216 } 217 218 if (!setter.isDefault()) { 219 for (ValueParameterDescriptor valueParameterDescriptor : setter.getValueParameters()) { 220 builder.addValueParameter(local.valueParameter(valueParameterDescriptor)); 221 } 222 } 223 } 224 225 ConstantValue<?> compileTimeConstant = propertyDescriptor.getCompileTimeInitializer(); 226 hasConstant = !(compileTimeConstant == null || compileTimeConstant instanceof NullValue); 227 } 228 229 boolean hasAnnotations = (descriptor instanceof PropertyDescriptor) 230 ? !descriptor.getAnnotations().getAllAnnotations().isEmpty() 231 : hasAnnotations(descriptor); 232 233 builder.setFlags(Flags.getCallableFlags( 234 hasAnnotations, 235 descriptor.getVisibility(), 236 descriptor.getModality(), 237 descriptor.getKind(), 238 callableKind(descriptor), 239 hasGetter, 240 hasSetter, 241 hasConstant, 242 lateInit, 243 isConst, 244 isOperator 245 )); 246 247 for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) { 248 builder.addTypeParameter(local.typeParameter(typeParameterDescriptor)); 249 } 250 251 ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter(); 252 if (receiverParameter != null) { 253 builder.setReceiverType(local.type(receiverParameter.getType())); 254 } 255 256 builder.setName(stringTable.getSimpleNameIndex(descriptor.getName())); 257 258 for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) { 259 builder.addValueParameter(local.valueParameter(valueParameterDescriptor)); 260 } 261 262 //noinspection ConstantConditions 263 builder.setReturnType(local.type(descriptor.getReturnType())); 264 265 extension.serializeCallable(descriptor, builder, stringTable); 266 267 return builder; 268 } 269 270 private static int getAccessorFlags(@NotNull PropertyAccessorDescriptor accessor) { 271 return Flags.getAccessorFlags( 272 hasAnnotations(accessor), 273 accessor.getVisibility(), 274 accessor.getModality(), 275 !accessor.isDefault() 276 ); 277 } 278 279 @NotNull 280 private static ProtoBuf.Callable.CallableKind callableKind(@NotNull CallableMemberDescriptor descriptor) { 281 if (descriptor instanceof PropertyDescriptor) { 282 return ((PropertyDescriptor) descriptor).isVar() ? ProtoBuf.Callable.CallableKind.VAR : ProtoBuf.Callable.CallableKind.VAL; 283 } 284 if (descriptor instanceof ConstructorDescriptor) { 285 return ProtoBuf.Callable.CallableKind.CONSTRUCTOR; 286 } 287 assert descriptor instanceof FunctionDescriptor : "Unknown descriptor class: " + descriptor.getClass(); 288 return ProtoBuf.Callable.CallableKind.FUN; 289 } 290 291 @NotNull 292 private ProtoBuf.Callable.ValueParameter.Builder valueParameter(@NotNull ValueParameterDescriptor descriptor) { 293 ProtoBuf.Callable.ValueParameter.Builder builder = ProtoBuf.Callable.ValueParameter.newBuilder(); 294 295 builder.setFlags(Flags.getValueParameterFlags(hasAnnotations(descriptor), descriptor.declaresDefaultValue())); 296 297 builder.setName(stringTable.getSimpleNameIndex(descriptor.getName())); 298 299 builder.setType(type(descriptor.getType())); 300 301 JetType varargElementType = descriptor.getVarargElementType(); 302 if (varargElementType != null) { 303 builder.setVarargElementType(type(varargElementType)); 304 } 305 306 extension.serializeValueParameter(descriptor, builder, stringTable); 307 308 return builder; 309 } 310 311 private ProtoBuf.TypeParameter.Builder typeParameter(TypeParameterDescriptor typeParameter) { 312 ProtoBuf.TypeParameter.Builder builder = ProtoBuf.TypeParameter.newBuilder(); 313 314 builder.setId(getTypeParameterId(typeParameter)); 315 316 builder.setName(stringTable.getSimpleNameIndex(typeParameter.getName())); 317 318 // to avoid storing a default 319 if (typeParameter.isReified()) { 320 builder.setReified(true); 321 } 322 323 // to avoid storing a default 324 ProtoBuf.TypeParameter.Variance variance = variance(typeParameter.getVariance()); 325 if (variance != ProtoBuf.TypeParameter.Variance.INV) { 326 builder.setVariance(variance); 327 } 328 329 for (JetType upperBound : typeParameter.getUpperBounds()) { 330 builder.addUpperBound(type(upperBound)); 331 } 332 333 return builder; 334 } 335 336 private static ProtoBuf.TypeParameter.Variance variance(Variance variance) { 337 switch (variance) { 338 case INVARIANT: 339 return ProtoBuf.TypeParameter.Variance.INV; 340 case IN_VARIANCE: 341 return ProtoBuf.TypeParameter.Variance.IN; 342 case OUT_VARIANCE: 343 return ProtoBuf.TypeParameter.Variance.OUT; 344 } 345 throw new IllegalStateException("Unknown variance: " + variance); 346 } 347 348 @NotNull 349 public ProtoBuf.Type.Builder type(@NotNull JetType type) { 350 assert !type.isError() : "Can't serialize error types: " + type; // TODO 351 352 if (TypesPackage.isFlexible(type)) return flexibleType(type); 353 354 ProtoBuf.Type.Builder builder = ProtoBuf.Type.newBuilder(); 355 356 builder.setConstructor(typeConstructor(type.getConstructor())); 357 setTypeConstructorFields(builder, type.getConstructor()); 358 359 for (TypeProjection projection : type.getArguments()) { 360 builder.addArgument(typeArgument(projection)); 361 } 362 363 // to avoid storing a default 364 if (type.isMarkedNullable()) { 365 builder.setNullable(true); 366 } 367 368 extension.serializeType(type, builder, stringTable); 369 370 return builder; 371 } 372 373 private void setTypeConstructorFields(@NotNull ProtoBuf.Type.Builder builder, @NotNull TypeConstructor typeConstructor) { 374 ClassifierDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor(); 375 376 assert declarationDescriptor instanceof TypeParameterDescriptor || declarationDescriptor instanceof ClassDescriptor 377 : "Unknown declaration descriptor: " + typeConstructor; 378 if (declarationDescriptor instanceof TypeParameterDescriptor) { 379 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor; 380 builder.setConstructorTypeParameter(getTypeParameterId(typeParameterDescriptor)); 381 } 382 else { 383 ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; 384 builder.setConstructorClassName(getClassId(classDescriptor)); 385 } 386 } 387 388 private ProtoBuf.Type.Builder flexibleType(@NotNull JetType type) { 389 Flexibility flexibility = TypesPackage.flexibility(type); 390 391 ProtoBuf.Type.Builder builder = type(flexibility.getLowerBound()); 392 393 builder.setFlexibleTypeCapabilitiesId(stringTable.getStringIndex(flexibility.getExtraCapabilities().getId())); 394 395 builder.setFlexibleUpperBound(type(flexibility.getUpperBound())); 396 397 return builder; 398 } 399 400 @NotNull 401 private ProtoBuf.Type.Argument.Builder typeArgument(@NotNull TypeProjection typeProjection) { 402 ProtoBuf.Type.Argument.Builder builder = ProtoBuf.Type.Argument.newBuilder(); 403 404 if (typeProjection.isStarProjection()) { 405 builder.setProjection(ProtoBuf.Type.Argument.Projection.STAR); 406 } 407 else { 408 ProtoBuf.Type.Argument.Projection projection = projection(typeProjection.getProjectionKind()); 409 410 // to avoid storing a default 411 if (projection != ProtoBuf.Type.Argument.Projection.INV) { 412 builder.setProjection(projection); 413 } 414 builder.setType(type(typeProjection.getType())); 415 } 416 417 return builder; 418 } 419 420 @NotNull 421 private ProtoBuf.Type.Constructor.Builder typeConstructor(@NotNull TypeConstructor typeConstructor) { 422 ProtoBuf.Type.Constructor.Builder builder = ProtoBuf.Type.Constructor.newBuilder(); 423 424 ClassifierDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor(); 425 426 assert declarationDescriptor instanceof TypeParameterDescriptor || declarationDescriptor instanceof ClassDescriptor 427 : "Unknown declaration descriptor: " + typeConstructor; 428 if (declarationDescriptor instanceof TypeParameterDescriptor) { 429 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor; 430 builder.setKind(ProtoBuf.Type.Constructor.Kind.TYPE_PARAMETER); 431 builder.setId(getTypeParameterId(typeParameterDescriptor)); 432 } 433 else { 434 ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; 435 //default: builder.setKind(Type.Constructor.Kind.CLASS); 436 builder.setId(getClassId(classDescriptor)); 437 } 438 return builder; 439 } 440 441 @NotNull 442 public ProtoBuf.Package.Builder packageProto(@NotNull Collection<PackageFragmentDescriptor> fragments) { 443 return packageProto(fragments, null); 444 } 445 446 @NotNull 447 public ProtoBuf.Package.Builder packageProtoWithoutDescriptors() { 448 ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder(); 449 450 extension.serializePackage(Collections.<PackageFragmentDescriptor>emptyList(), builder, stringTable); 451 452 return builder; 453 } 454 455 @NotNull 456 public ProtoBuf.Package.Builder packageProto(@NotNull Collection<PackageFragmentDescriptor> fragments, @Nullable Function1<DeclarationDescriptor, Boolean> skip) { 457 ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder(); 458 459 Collection<DeclarationDescriptor> members = new ArrayList<DeclarationDescriptor>(); 460 for (PackageFragmentDescriptor fragment : fragments) { 461 members.addAll(fragment.getMemberScope().getAllDescriptors()); 462 } 463 464 for (DeclarationDescriptor declaration : sort(members)) { 465 if (skip != null && skip.invoke(declaration)) continue; 466 467 if (declaration instanceof PropertyDescriptor || declaration instanceof FunctionDescriptor) { 468 builder.addMember(callableProto((CallableMemberDescriptor) declaration)); 469 } 470 } 471 472 extension.serializePackage(fragments, builder, stringTable); 473 474 return builder; 475 } 476 477 @NotNull 478 public ProtoBuf.Package.Builder packagePartProto(@NotNull Collection<DeclarationDescriptor> members) { 479 ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder(); 480 481 for (DeclarationDescriptor declaration : sort(members)) { 482 if (declaration instanceof PropertyDescriptor || declaration instanceof FunctionDescriptor) { 483 builder.addMember(callableProto((CallableMemberDescriptor) declaration)); 484 } 485 } 486 487 return builder; 488 } 489 490 @NotNull 491 private static ProtoBuf.Type.Argument.Projection projection(@NotNull Variance projectionKind) { 492 switch (projectionKind) { 493 case INVARIANT: 494 return ProtoBuf.Type.Argument.Projection.INV; 495 case IN_VARIANCE: 496 return ProtoBuf.Type.Argument.Projection.IN; 497 case OUT_VARIANCE: 498 return ProtoBuf.Type.Argument.Projection.OUT; 499 } 500 throw new IllegalStateException("Unknown projectionKind: " + projectionKind); 501 } 502 503 private int getClassId(@NotNull ClassDescriptor descriptor) { 504 return stringTable.getFqNameIndex(descriptor); 505 } 506 507 private int getTypeParameterId(@NotNull TypeParameterDescriptor descriptor) { 508 return typeParameters.intern(descriptor); 509 } 510 511 private static boolean hasAnnotations(Annotated descriptor) { 512 return !descriptor.getAnnotations().isEmpty(); 513 } 514 515 @NotNull 516 public static <T extends DeclarationDescriptor> List<T> sort(@NotNull Collection<T> descriptors) { 517 List<T> result = new ArrayList<T>(descriptors); 518 //NOTE: the exact comparator does matter here 519 Collections.sort(result, MemberComparator.INSTANCE); 520 return result; 521 522 } 523 }