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