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.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.CompileTimeConstant; 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 if (descriptor instanceof PropertyDescriptor) { 158 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; 159 160 int propertyFlags = Flags.getAccessorFlags( 161 hasAnnotations(propertyDescriptor), 162 propertyDescriptor.getVisibility(), 163 propertyDescriptor.getModality(), 164 false 165 ); 166 167 PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); 168 if (getter != null) { 169 hasGetter = true; 170 int accessorFlags = getAccessorFlags(getter); 171 if (accessorFlags != propertyFlags) { 172 builder.setGetterFlags(accessorFlags); 173 } 174 } 175 176 PropertySetterDescriptor setter = propertyDescriptor.getSetter(); 177 if (setter != null) { 178 hasSetter = true; 179 int accessorFlags = getAccessorFlags(setter); 180 if (accessorFlags != propertyFlags) { 181 builder.setSetterFlags(accessorFlags); 182 } 183 184 if (!setter.isDefault()) { 185 for (ValueParameterDescriptor valueParameterDescriptor : setter.getValueParameters()) { 186 builder.addValueParameter(local.valueParameter(valueParameterDescriptor)); 187 } 188 } 189 } 190 191 CompileTimeConstant<?> compileTimeConstant = propertyDescriptor.getCompileTimeInitializer(); 192 hasConstant = !(compileTimeConstant == null || compileTimeConstant instanceof NullValue); 193 } 194 195 builder.setFlags(Flags.getCallableFlags( 196 hasAnnotations(descriptor), 197 descriptor.getVisibility(), 198 descriptor.getModality(), 199 descriptor.getKind(), 200 callableKind(descriptor), 201 hasGetter, 202 hasSetter, 203 hasConstant 204 )); 205 206 for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) { 207 builder.addTypeParameter(local.typeParameter(typeParameterDescriptor)); 208 } 209 210 ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter(); 211 if (receiverParameter != null) { 212 builder.setReceiverType(local.type(receiverParameter.getType())); 213 } 214 215 builder.setName(stringTable.getSimpleNameIndex(descriptor.getName())); 216 217 for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) { 218 builder.addValueParameter(local.valueParameter(valueParameterDescriptor)); 219 } 220 221 //noinspection ConstantConditions 222 builder.setReturnType(local.type(descriptor.getReturnType())); 223 224 extension.serializeCallable(descriptor, builder, stringTable); 225 226 return builder; 227 } 228 229 private static int getAccessorFlags(@NotNull PropertyAccessorDescriptor accessor) { 230 return Flags.getAccessorFlags( 231 hasAnnotations(accessor), 232 accessor.getVisibility(), 233 accessor.getModality(), 234 !accessor.isDefault() 235 ); 236 } 237 238 @NotNull 239 private static ProtoBuf.Callable.CallableKind callableKind(@NotNull CallableMemberDescriptor descriptor) { 240 if (descriptor instanceof PropertyDescriptor) { 241 return ((PropertyDescriptor) descriptor).isVar() ? ProtoBuf.Callable.CallableKind.VAR : ProtoBuf.Callable.CallableKind.VAL; 242 } 243 if (descriptor instanceof ConstructorDescriptor) { 244 return ProtoBuf.Callable.CallableKind.CONSTRUCTOR; 245 } 246 assert descriptor instanceof FunctionDescriptor : "Unknown descriptor class: " + descriptor.getClass(); 247 return ProtoBuf.Callable.CallableKind.FUN; 248 } 249 250 @NotNull 251 private ProtoBuf.Callable.ValueParameter.Builder valueParameter(@NotNull ValueParameterDescriptor descriptor) { 252 ProtoBuf.Callable.ValueParameter.Builder builder = ProtoBuf.Callable.ValueParameter.newBuilder(); 253 254 builder.setFlags(Flags.getValueParameterFlags(hasAnnotations(descriptor), descriptor.declaresDefaultValue())); 255 256 builder.setName(stringTable.getSimpleNameIndex(descriptor.getName())); 257 258 builder.setType(type(descriptor.getType())); 259 260 JetType varargElementType = descriptor.getVarargElementType(); 261 if (varargElementType != null) { 262 builder.setVarargElementType(type(varargElementType)); 263 } 264 265 extension.serializeValueParameter(descriptor, builder, stringTable); 266 267 return builder; 268 } 269 270 private ProtoBuf.TypeParameter.Builder typeParameter(TypeParameterDescriptor typeParameter) { 271 ProtoBuf.TypeParameter.Builder builder = ProtoBuf.TypeParameter.newBuilder(); 272 273 builder.setId(getTypeParameterId(typeParameter)); 274 275 builder.setName(stringTable.getSimpleNameIndex(typeParameter.getName())); 276 277 // to avoid storing a default 278 if (typeParameter.isReified()) { 279 builder.setReified(true); 280 } 281 282 // to avoid storing a default 283 ProtoBuf.TypeParameter.Variance variance = variance(typeParameter.getVariance()); 284 if (variance != ProtoBuf.TypeParameter.Variance.INV) { 285 builder.setVariance(variance); 286 } 287 288 for (JetType upperBound : typeParameter.getUpperBounds()) { 289 builder.addUpperBound(type(upperBound)); 290 } 291 292 return builder; 293 } 294 295 private static ProtoBuf.TypeParameter.Variance variance(Variance variance) { 296 switch (variance) { 297 case INVARIANT: 298 return ProtoBuf.TypeParameter.Variance.INV; 299 case IN_VARIANCE: 300 return ProtoBuf.TypeParameter.Variance.IN; 301 case OUT_VARIANCE: 302 return ProtoBuf.TypeParameter.Variance.OUT; 303 } 304 throw new IllegalStateException("Unknown variance: " + variance); 305 } 306 307 @NotNull 308 public ProtoBuf.Type.Builder type(@NotNull JetType type) { 309 assert !type.isError() : "Can't serialize error types: " + type; // TODO 310 311 if (TypesPackage.isFlexible(type)) return flexibleType(type); 312 313 ProtoBuf.Type.Builder builder = ProtoBuf.Type.newBuilder(); 314 315 builder.setConstructor(typeConstructor(type.getConstructor())); 316 317 for (TypeProjection projection : type.getArguments()) { 318 builder.addArgument(typeArgument(projection)); 319 } 320 321 // to avoid storing a default 322 if (type.isMarkedNullable()) { 323 builder.setNullable(true); 324 } 325 326 return builder; 327 } 328 329 private ProtoBuf.Type.Builder flexibleType(@NotNull JetType type) { 330 Flexibility flexibility = TypesPackage.flexibility(type); 331 332 ProtoBuf.Type.Builder builder = type(flexibility.getLowerBound()); 333 334 builder.setFlexibleTypeCapabilitiesId(stringTable.getStringIndex(flexibility.getExtraCapabilities().getId())); 335 336 builder.setFlexibleUpperBound(type(flexibility.getUpperBound())); 337 338 return builder; 339 } 340 341 @NotNull 342 private ProtoBuf.Type.Argument.Builder typeArgument(@NotNull TypeProjection typeProjection) { 343 ProtoBuf.Type.Argument.Builder builder = ProtoBuf.Type.Argument.newBuilder(); 344 345 if (typeProjection.isStarProjection()) { 346 builder.setProjection(ProtoBuf.Type.Argument.Projection.STAR); 347 } 348 else { 349 ProtoBuf.Type.Argument.Projection projection = projection(typeProjection.getProjectionKind()); 350 351 // to avoid storing a default 352 if (projection != ProtoBuf.Type.Argument.Projection.INV) { 353 builder.setProjection(projection); 354 } 355 builder.setType(type(typeProjection.getType())); 356 } 357 358 return builder; 359 } 360 361 @NotNull 362 private ProtoBuf.Type.Constructor.Builder typeConstructor(@NotNull TypeConstructor typeConstructor) { 363 ProtoBuf.Type.Constructor.Builder builder = ProtoBuf.Type.Constructor.newBuilder(); 364 365 ClassifierDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor(); 366 367 assert declarationDescriptor instanceof TypeParameterDescriptor || declarationDescriptor instanceof ClassDescriptor 368 : "Unknown declaration descriptor: " + typeConstructor; 369 if (declarationDescriptor instanceof TypeParameterDescriptor) { 370 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor; 371 builder.setKind(ProtoBuf.Type.Constructor.Kind.TYPE_PARAMETER); 372 builder.setId(getTypeParameterId(typeParameterDescriptor)); 373 } 374 else { 375 ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; 376 //default: builder.setKind(Type.Constructor.Kind.CLASS); 377 builder.setId(getClassId(classDescriptor)); 378 } 379 return builder; 380 } 381 382 @NotNull 383 public ProtoBuf.Package.Builder packageProto(@NotNull Collection<PackageFragmentDescriptor> fragments) { 384 return packageProto(fragments, null); 385 } 386 387 @NotNull 388 public ProtoBuf.Package.Builder packageProto(@NotNull Collection<PackageFragmentDescriptor> fragments, @Nullable Function1<DeclarationDescriptor, Boolean> skip) { 389 ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder(); 390 391 Collection<DeclarationDescriptor> members = new ArrayList<DeclarationDescriptor>(); 392 for (PackageFragmentDescriptor fragment : fragments) { 393 members.addAll(fragment.getMemberScope().getAllDescriptors()); 394 } 395 396 for (DeclarationDescriptor declaration : sort(members)) { 397 if (skip != null && skip.invoke(declaration)) continue; 398 399 if (declaration instanceof PropertyDescriptor || declaration instanceof FunctionDescriptor) { 400 builder.addMember(callableProto((CallableMemberDescriptor) declaration)); 401 } 402 } 403 404 extension.serializePackage(fragments, builder, stringTable); 405 406 return builder; 407 } 408 409 @NotNull 410 private static ProtoBuf.Type.Argument.Projection projection(@NotNull Variance projectionKind) { 411 switch (projectionKind) { 412 case INVARIANT: 413 return ProtoBuf.Type.Argument.Projection.INV; 414 case IN_VARIANCE: 415 return ProtoBuf.Type.Argument.Projection.IN; 416 case OUT_VARIANCE: 417 return ProtoBuf.Type.Argument.Projection.OUT; 418 } 419 throw new IllegalStateException("Unknown projectionKind: " + projectionKind); 420 } 421 422 private int getClassId(@NotNull ClassDescriptor descriptor) { 423 return stringTable.getFqNameIndex(descriptor); 424 } 425 426 private int getTypeParameterId(@NotNull TypeParameterDescriptor descriptor) { 427 return typeParameters.intern(descriptor); 428 } 429 430 private static boolean hasAnnotations(Annotated descriptor) { 431 return !descriptor.getAnnotations().isEmpty(); 432 } 433 434 @NotNull 435 public static <T extends DeclarationDescriptor> List<T> sort(@NotNull Collection<T> descriptors) { 436 List<T> result = new ArrayList<T>(descriptors); 437 //NOTE: the exact comparator does matter here 438 Collections.sort(result, MemberComparator.INSTANCE); 439 return result; 440 441 } 442 }