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