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.resolve.constants.CompileTimeConstant; 026 import org.jetbrains.kotlin.resolve.constants.NullValue; 027 import org.jetbrains.kotlin.types.*; 028 029 import java.util.ArrayList; 030 import java.util.Collection; 031 import java.util.Collections; 032 import java.util.List; 033 034 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry; 035 036 public class DescriptorSerializer { 037 038 private final StringTable stringTable; 039 private final Interner<TypeParameterDescriptor> typeParameters; 040 private final SerializerExtension extension; 041 042 private DescriptorSerializer(StringTable stringTable, Interner<TypeParameterDescriptor> typeParameters, SerializerExtension extension) { 043 this.stringTable = stringTable; 044 this.typeParameters = typeParameters; 045 this.extension = extension; 046 } 047 048 @NotNull 049 public static DescriptorSerializer createTopLevel(@NotNull SerializerExtension extension) { 050 return new DescriptorSerializer(new StringTable(extension), new Interner<TypeParameterDescriptor>(), extension); 051 } 052 053 @NotNull 054 public static DescriptorSerializer create(@NotNull ClassDescriptor descriptor, @NotNull SerializerExtension extension) { 055 DeclarationDescriptor container = descriptor.getContainingDeclaration(); 056 DescriptorSerializer parentSerializer = 057 container instanceof ClassDescriptor 058 ? create((ClassDescriptor) container, extension) 059 : createTopLevel(extension); 060 061 // Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always 062 // serializing outer classes before nested classes. 063 // Otherwise our interner can get wrong ids because we may serialize classes in any order. 064 DescriptorSerializer serializer = parentSerializer.createChildSerializer(); 065 for (TypeParameterDescriptor typeParameter : descriptor.getTypeConstructor().getParameters()) { 066 serializer.typeParameters.intern(typeParameter); 067 } 068 return serializer; 069 } 070 071 private DescriptorSerializer createChildSerializer() { 072 return new DescriptorSerializer(stringTable, new Interner<TypeParameterDescriptor>(typeParameters), extension); 073 } 074 075 @NotNull 076 public StringTable getStringTable() { 077 return stringTable; 078 } 079 080 @NotNull 081 public ProtoBuf.Class.Builder classProto(@NotNull ClassDescriptor classDescriptor) { 082 ProtoBuf.Class.Builder builder = ProtoBuf.Class.newBuilder(); 083 084 int flags = Flags.getClassFlags(hasAnnotations(classDescriptor), classDescriptor.getVisibility(), classDescriptor.getModality(), 085 classDescriptor.getKind(), classDescriptor.isInner(), classDescriptor.isDefaultObject()); 086 builder.setFlags(flags); 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 defaultObjectDescriptor = classDescriptor.getDefaultObjectDescriptor(); 134 if (defaultObjectDescriptor != null) { 135 builder.setDefaultObjectName(stringTable.getSimpleNameIndex(defaultObjectDescriptor.getName())); 136 } 137 138 extension.serializeClass(classDescriptor, builder, stringTable); 139 140 return builder; 141 } 142 143 @NotNull 144 public ProtoBuf.Callable.Builder callableProto(@NotNull CallableMemberDescriptor descriptor) { 145 ProtoBuf.Callable.Builder builder = ProtoBuf.Callable.newBuilder(); 146 147 DescriptorSerializer local = createChildSerializer(); 148 149 boolean hasGetter = false; 150 boolean hasSetter = false; 151 boolean hasConstant = false; 152 if (descriptor instanceof PropertyDescriptor) { 153 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; 154 155 int propertyFlags = Flags.getAccessorFlags( 156 hasAnnotations(propertyDescriptor), 157 propertyDescriptor.getVisibility(), 158 propertyDescriptor.getModality(), 159 false 160 ); 161 162 PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); 163 if (getter != null) { 164 hasGetter = true; 165 int accessorFlags = getAccessorFlags(getter); 166 if (accessorFlags != propertyFlags) { 167 builder.setGetterFlags(accessorFlags); 168 } 169 } 170 171 PropertySetterDescriptor setter = propertyDescriptor.getSetter(); 172 if (setter != null) { 173 hasSetter = true; 174 int accessorFlags = getAccessorFlags(setter); 175 if (accessorFlags != propertyFlags) { 176 builder.setSetterFlags(accessorFlags); 177 } 178 179 if (!setter.isDefault()) { 180 for (ValueParameterDescriptor valueParameterDescriptor : setter.getValueParameters()) { 181 builder.addValueParameter(local.valueParameter(valueParameterDescriptor)); 182 } 183 } 184 } 185 186 CompileTimeConstant<?> compileTimeConstant = propertyDescriptor.getCompileTimeInitializer(); 187 hasConstant = !(compileTimeConstant == null || compileTimeConstant instanceof NullValue); 188 } 189 190 builder.setFlags(Flags.getCallableFlags( 191 hasAnnotations(descriptor), 192 descriptor.getVisibility(), 193 descriptor.getModality(), 194 descriptor.getKind(), 195 callableKind(descriptor), 196 hasGetter, 197 hasSetter, 198 hasConstant 199 )); 200 201 for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) { 202 builder.addTypeParameter(local.typeParameter(typeParameterDescriptor)); 203 } 204 205 ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter(); 206 if (receiverParameter != null) { 207 builder.setReceiverType(local.type(receiverParameter.getType())); 208 } 209 210 builder.setName(stringTable.getSimpleNameIndex(descriptor.getName())); 211 212 for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) { 213 builder.addValueParameter(local.valueParameter(valueParameterDescriptor)); 214 } 215 216 //noinspection ConstantConditions 217 builder.setReturnType(local.type(descriptor.getReturnType())); 218 219 extension.serializeCallable(descriptor, builder, stringTable); 220 221 return builder; 222 } 223 224 private static int getAccessorFlags(@NotNull PropertyAccessorDescriptor accessor) { 225 return Flags.getAccessorFlags( 226 hasAnnotations(accessor), 227 accessor.getVisibility(), 228 accessor.getModality(), 229 !accessor.isDefault() 230 ); 231 } 232 233 @NotNull 234 private static ProtoBuf.Callable.CallableKind callableKind(@NotNull CallableMemberDescriptor descriptor) { 235 if (descriptor instanceof PropertyDescriptor) { 236 return ((PropertyDescriptor) descriptor).isVar() ? ProtoBuf.Callable.CallableKind.VAR : ProtoBuf.Callable.CallableKind.VAL; 237 } 238 if (descriptor instanceof ConstructorDescriptor) { 239 return ProtoBuf.Callable.CallableKind.CONSTRUCTOR; 240 } 241 assert descriptor instanceof FunctionDescriptor : "Unknown descriptor class: " + descriptor.getClass(); 242 return ProtoBuf.Callable.CallableKind.FUN; 243 } 244 245 @NotNull 246 private ProtoBuf.Callable.ValueParameter.Builder valueParameter(@NotNull ValueParameterDescriptor descriptor) { 247 ProtoBuf.Callable.ValueParameter.Builder builder = ProtoBuf.Callable.ValueParameter.newBuilder(); 248 249 builder.setFlags(Flags.getValueParameterFlags(hasAnnotations(descriptor), descriptor.declaresDefaultValue())); 250 251 builder.setName(stringTable.getSimpleNameIndex(descriptor.getName())); 252 253 builder.setType(type(descriptor.getType())); 254 255 JetType varargElementType = descriptor.getVarargElementType(); 256 if (varargElementType != null) { 257 builder.setVarargElementType(type(varargElementType)); 258 } 259 260 extension.serializeValueParameter(descriptor, builder, stringTable); 261 262 return builder; 263 } 264 265 private ProtoBuf.TypeParameter.Builder typeParameter(TypeParameterDescriptor typeParameter) { 266 ProtoBuf.TypeParameter.Builder builder = ProtoBuf.TypeParameter.newBuilder(); 267 268 builder.setId(getTypeParameterId(typeParameter)); 269 270 builder.setName(stringTable.getSimpleNameIndex(typeParameter.getName())); 271 272 // to avoid storing a default 273 if (typeParameter.isReified()) { 274 builder.setReified(true); 275 } 276 277 // to avoid storing a default 278 ProtoBuf.TypeParameter.Variance variance = variance(typeParameter.getVariance()); 279 if (variance != ProtoBuf.TypeParameter.Variance.INV) { 280 builder.setVariance(variance); 281 } 282 283 for (JetType upperBound : typeParameter.getUpperBounds()) { 284 builder.addUpperBound(type(upperBound)); 285 } 286 287 return builder; 288 } 289 290 private static ProtoBuf.TypeParameter.Variance variance(Variance variance) { 291 switch (variance) { 292 case INVARIANT: 293 return ProtoBuf.TypeParameter.Variance.INV; 294 case IN_VARIANCE: 295 return ProtoBuf.TypeParameter.Variance.IN; 296 case OUT_VARIANCE: 297 return ProtoBuf.TypeParameter.Variance.OUT; 298 } 299 throw new IllegalStateException("Unknown variance: " + variance); 300 } 301 302 @NotNull 303 public ProtoBuf.Type.Builder type(@NotNull JetType type) { 304 assert !type.isError() : "Can't serialize error types: " + type; // TODO 305 306 if (TypesPackage.isFlexible(type)) return flexibleType(type); 307 308 ProtoBuf.Type.Builder builder = ProtoBuf.Type.newBuilder(); 309 310 builder.setConstructor(typeConstructor(type.getConstructor())); 311 312 for (TypeProjection projection : type.getArguments()) { 313 builder.addArgument(typeArgument(projection)); 314 } 315 316 // to avoid storing a default 317 if (type.isMarkedNullable()) { 318 builder.setNullable(true); 319 } 320 321 return builder; 322 } 323 324 private ProtoBuf.Type.Builder flexibleType(@NotNull JetType type) { 325 Flexibility flexibility = TypesPackage.flexibility(type); 326 327 ProtoBuf.Type.Builder builder = type(flexibility.getLowerBound()); 328 329 builder.setFlexibleTypeCapabilitiesId(stringTable.getStringIndex(flexibility.getExtraCapabilities().getId())); 330 331 builder.setFlexibleUpperBound(type(flexibility.getUpperBound())); 332 333 return builder; 334 } 335 336 @NotNull 337 private ProtoBuf.Type.Argument.Builder typeArgument(@NotNull TypeProjection typeProjection) { 338 ProtoBuf.Type.Argument.Builder builder = ProtoBuf.Type.Argument.newBuilder(); 339 340 if (typeProjection.isStarProjection()) { 341 builder.setProjection(ProtoBuf.Type.Argument.Projection.STAR); 342 } 343 else { 344 ProtoBuf.Type.Argument.Projection projection = projection(typeProjection.getProjectionKind()); 345 346 // to avoid storing a default 347 if (projection != ProtoBuf.Type.Argument.Projection.INV) { 348 builder.setProjection(projection); 349 } 350 } 351 352 builder.setType(type(typeProjection.getType())); 353 return builder; 354 } 355 356 @NotNull 357 private ProtoBuf.Type.Constructor.Builder typeConstructor(@NotNull TypeConstructor typeConstructor) { 358 ProtoBuf.Type.Constructor.Builder builder = ProtoBuf.Type.Constructor.newBuilder(); 359 360 ClassifierDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor(); 361 362 assert declarationDescriptor instanceof TypeParameterDescriptor || declarationDescriptor instanceof ClassDescriptor 363 : "Unknown declaration descriptor: " + typeConstructor; 364 if (declarationDescriptor instanceof TypeParameterDescriptor) { 365 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor; 366 builder.setKind(ProtoBuf.Type.Constructor.Kind.TYPE_PARAMETER); 367 builder.setId(getTypeParameterId(typeParameterDescriptor)); 368 } 369 else { 370 ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; 371 //default: builder.setKind(Type.Constructor.Kind.CLASS); 372 builder.setId(getClassId(classDescriptor)); 373 } 374 return builder; 375 } 376 377 @NotNull 378 public ProtoBuf.Package.Builder packageProto(@NotNull Collection<PackageFragmentDescriptor> fragments) { 379 ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder(); 380 381 Collection<DeclarationDescriptor> members = new ArrayList<DeclarationDescriptor>(); 382 for (PackageFragmentDescriptor fragment : fragments) { 383 members.addAll(fragment.getMemberScope().getAllDescriptors()); 384 } 385 386 for (DeclarationDescriptor declaration : sort(members)) { 387 if (declaration instanceof PropertyDescriptor || declaration instanceof FunctionDescriptor) { 388 builder.addMember(callableProto((CallableMemberDescriptor) declaration)); 389 } 390 } 391 392 extension.serializePackage(fragments, builder, stringTable); 393 394 return builder; 395 } 396 397 @NotNull 398 private static ProtoBuf.Type.Argument.Projection projection(@NotNull Variance projectionKind) { 399 switch (projectionKind) { 400 case INVARIANT: 401 return ProtoBuf.Type.Argument.Projection.INV; 402 case IN_VARIANCE: 403 return ProtoBuf.Type.Argument.Projection.IN; 404 case OUT_VARIANCE: 405 return ProtoBuf.Type.Argument.Projection.OUT; 406 } 407 throw new IllegalStateException("Unknown projectionKind: " + projectionKind); 408 } 409 410 private int getClassId(@NotNull ClassDescriptor descriptor) { 411 return stringTable.getFqNameIndex(descriptor); 412 } 413 414 private int getTypeParameterId(@NotNull TypeParameterDescriptor descriptor) { 415 return typeParameters.intern(descriptor); 416 } 417 418 private static boolean hasAnnotations(Annotated descriptor) { 419 return !descriptor.getAnnotations().isEmpty(); 420 } 421 422 @NotNull 423 public static <T extends DeclarationDescriptor> List<T> sort(@NotNull Collection<T> descriptors) { 424 List<T> result = new ArrayList<T>(descriptors); 425 //NOTE: the exact comparator does matter here 426 Collections.sort(result, MemberComparator.INSTANCE); 427 return result; 428 429 } 430 }