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.descriptors.ClassDescriptor; 021 import org.jetbrains.kotlin.descriptors.ClassOrPackageFragmentDescriptor; 022 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; 023 import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor; 024 import org.jetbrains.kotlin.name.FqName; 025 import org.jetbrains.kotlin.name.Name; 026 import org.jetbrains.kotlin.types.ErrorUtils; 027 028 import static org.jetbrains.kotlin.serialization.ProtoBuf.QualifiedNameTable.QualifiedName; 029 030 public class StringTable { 031 private static final class FqNameProto { 032 public final QualifiedName.Builder fqName; 033 034 public FqNameProto(@NotNull QualifiedName.Builder fqName) { 035 this.fqName = fqName; 036 } 037 038 @Override 039 public int hashCode() { 040 int result = 13; 041 result = 31 * result + fqName.getParentQualifiedName(); 042 result = 31 * result + fqName.getShortName(); 043 result = 31 * result + fqName.getKind().hashCode(); 044 return result; 045 } 046 047 @Override 048 public boolean equals(Object obj) { 049 if (obj == null || getClass() != obj.getClass()) return false; 050 051 QualifiedName.Builder other = ((FqNameProto) obj).fqName; 052 return fqName.getParentQualifiedName() == other.getParentQualifiedName() 053 && fqName.getShortName() == other.getShortName() 054 && fqName.getKind() == other.getKind(); 055 } 056 } 057 058 private final Interner<String> strings = new Interner<String>(); 059 private final Interner<FqNameProto> qualifiedNames = new Interner<FqNameProto>(); 060 private final SerializerExtension extension; 061 062 public StringTable(@NotNull SerializerExtension extension) { 063 this.extension = extension; 064 } 065 066 public int getSimpleNameIndex(@NotNull Name name) { 067 return getStringIndex(name.asString()); 068 } 069 070 public int getStringIndex(@NotNull String string) { 071 return strings.intern(string); 072 } 073 074 public int getFqNameIndex(@NotNull ClassOrPackageFragmentDescriptor descriptor) { 075 if (ErrorUtils.isError(descriptor)) { 076 throw new IllegalStateException("Cannot get FQ name of error class: " + descriptor); 077 } 078 079 QualifiedName.Builder builder = QualifiedName.newBuilder(); 080 if (descriptor instanceof ClassDescriptor) { 081 builder.setKind(QualifiedName.Kind.CLASS); 082 } 083 084 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 085 int shortName; 086 if (containingDeclaration instanceof PackageFragmentDescriptor) { 087 shortName = getSimpleNameIndex(descriptor.getName()); 088 PackageFragmentDescriptor fragment = (PackageFragmentDescriptor) containingDeclaration; 089 if (!fragment.getFqName().isRoot()) { 090 builder.setParentQualifiedName(getFqNameIndex(fragment.getFqName())); 091 } 092 } 093 else if (containingDeclaration instanceof ClassDescriptor) { 094 shortName = getSimpleNameIndex(descriptor.getName()); 095 ClassDescriptor outerClass = (ClassDescriptor) containingDeclaration; 096 builder.setParentQualifiedName(getFqNameIndex(outerClass)); 097 } 098 else { 099 if (descriptor instanceof ClassDescriptor) { 100 builder.setKind(QualifiedName.Kind.LOCAL); 101 shortName = getStringIndex(extension.getLocalClassName((ClassDescriptor) descriptor)); 102 } 103 else { 104 throw new IllegalStateException("Package container should be a package: " + descriptor); 105 } 106 } 107 108 builder.setShortName(shortName); 109 110 return qualifiedNames.intern(new FqNameProto(builder)); 111 } 112 113 public int getFqNameIndex(@NotNull FqName fqName) { 114 int result = -1; 115 for (Name segment : fqName.pathSegments()) { 116 QualifiedName.Builder builder = QualifiedName.newBuilder(); 117 builder.setShortName(getSimpleNameIndex(segment)); 118 if (result != -1) { 119 builder.setParentQualifiedName(result); 120 } 121 result = qualifiedNames.intern(new FqNameProto(builder)); 122 } 123 return result; 124 } 125 126 @NotNull 127 public ProtoBuf.StringTable serializeSimpleNames() { 128 ProtoBuf.StringTable.Builder builder = ProtoBuf.StringTable.newBuilder(); 129 for (String simpleName : strings.getAllInternedObjects()) { 130 builder.addString(simpleName); 131 } 132 return builder.build(); 133 } 134 135 @NotNull 136 public ProtoBuf.QualifiedNameTable serializeQualifiedNames() { 137 ProtoBuf.QualifiedNameTable.Builder builder = ProtoBuf.QualifiedNameTable.newBuilder(); 138 for (FqNameProto fqName : qualifiedNames.getAllInternedObjects()) { 139 builder.addQualifiedName(fqName.fqName); 140 } 141 return builder.build(); 142 } 143 }