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 com.google.protobuf.Internal; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.kotlin.descriptors.*; 022 023 public class Flags { 024 private Flags() {} 025 026 // Common 027 028 public static final FlagField<Boolean> HAS_ANNOTATIONS = FlagField.booleanFirst(); 029 030 public static final FlagField<ProtoBuf.Visibility> VISIBILITY = FlagField.after(HAS_ANNOTATIONS, ProtoBuf.Visibility.values()); 031 032 public static final FlagField<ProtoBuf.Modality> MODALITY = FlagField.after(VISIBILITY, ProtoBuf.Modality.values()); 033 034 // Class 035 036 public static final FlagField<ProtoBuf.Class.Kind> CLASS_KIND = FlagField.after(MODALITY, ProtoBuf.Class.Kind.values()); 037 038 public static final FlagField<Boolean> INNER = FlagField.booleanAfter(CLASS_KIND); 039 040 // Callables 041 042 public static final FlagField<ProtoBuf.Callable.CallableKind> CALLABLE_KIND = FlagField.after(MODALITY, 043 ProtoBuf.Callable.CallableKind.values()); 044 045 public static final FlagField<ProtoBuf.Callable.MemberKind> MEMBER_KIND = FlagField.after(CALLABLE_KIND, 046 ProtoBuf.Callable.MemberKind.values()); 047 public static final FlagField<Boolean> HAS_GETTER = FlagField.booleanAfter(MEMBER_KIND); 048 public static final FlagField<Boolean> HAS_SETTER = FlagField.booleanAfter(HAS_GETTER); 049 public static final FlagField<Boolean> HAS_CONSTANT = FlagField.booleanAfter(HAS_SETTER); 050 051 public static final FlagField<Boolean> LATE_INIT = FlagField.booleanAfter(HAS_CONSTANT); 052 053 // Parameters 054 055 public static final FlagField<Boolean> DECLARES_DEFAULT_VALUE = FlagField.booleanAfter(HAS_ANNOTATIONS); 056 057 // Accessors 058 059 // It's important that this flag is negated: "is NOT default" instead of "is default" 060 public static final FlagField<Boolean> IS_NOT_DEFAULT = FlagField.booleanAfter(MODALITY); 061 062 // --- 063 064 private static <E> int bitWidth(@NotNull E[] enumEntries) { 065 int length = enumEntries.length - 1; 066 if (length == 0) return 1; 067 for (int i = 31; i >= 0; i--) { 068 if ((length & (1 << i)) != 0) return i + 1; 069 } 070 throw new IllegalStateException("Empty enum: " + enumEntries.getClass()); 071 } 072 073 public static int getClassFlags( 074 boolean hasAnnotations, 075 Visibility visibility, 076 Modality modality, 077 ClassKind kind, 078 boolean inner, 079 boolean isCompanionObject 080 ) { 081 return HAS_ANNOTATIONS.toFlags(hasAnnotations) 082 | MODALITY.toFlags(modality(modality)) 083 | VISIBILITY.toFlags(visibility(visibility)) 084 | CLASS_KIND.toFlags(classKind(kind, isCompanionObject)) 085 | INNER.toFlags(inner) 086 ; 087 } 088 089 private static ProtoBuf.Class.Kind classKind(ClassKind kind, boolean isCompanionObject) { 090 if (isCompanionObject) return ProtoBuf.Class.Kind.CLASS_OBJECT; 091 092 switch (kind) { 093 case CLASS: 094 return ProtoBuf.Class.Kind.CLASS; 095 case INTERFACE: 096 return ProtoBuf.Class.Kind.TRAIT; 097 case ENUM_CLASS: 098 return ProtoBuf.Class.Kind.ENUM_CLASS; 099 case ENUM_ENTRY: 100 return ProtoBuf.Class.Kind.ENUM_ENTRY; 101 case ANNOTATION_CLASS: 102 return ProtoBuf.Class.Kind.ANNOTATION_CLASS; 103 case OBJECT: 104 return ProtoBuf.Class.Kind.OBJECT; 105 } 106 throw new IllegalArgumentException("Unknown class kind: " + kind); 107 } 108 109 public static int getCallableFlags( 110 boolean hasAnnotations, 111 @NotNull Visibility visibility, 112 @NotNull Modality modality, 113 @NotNull CallableMemberDescriptor.Kind memberKind, 114 @NotNull ProtoBuf.Callable.CallableKind callableKind, 115 boolean hasGetter, 116 boolean hasSetter, 117 boolean hasConstant, 118 boolean lateInit 119 ) { 120 return HAS_ANNOTATIONS.toFlags(hasAnnotations) 121 | MODALITY.toFlags(modality(modality)) 122 | VISIBILITY.toFlags(visibility(visibility)) 123 | MEMBER_KIND.toFlags(memberKind(memberKind)) 124 | CALLABLE_KIND.toFlags(callableKind) 125 | HAS_GETTER.toFlags(hasGetter) 126 | HAS_SETTER.toFlags(hasSetter) 127 | HAS_CONSTANT.toFlags(hasConstant) 128 | LATE_INIT.toFlags(lateInit) 129 ; 130 } 131 132 public static int getAccessorFlags( 133 boolean hasAnnotations, 134 @NotNull Visibility visibility, 135 @NotNull Modality modality, 136 boolean isNotDefault 137 ) { 138 return HAS_ANNOTATIONS.toFlags(hasAnnotations) 139 | MODALITY.toFlags(modality(modality)) 140 | VISIBILITY.toFlags(visibility(visibility)) 141 | IS_NOT_DEFAULT.toFlags(isNotDefault) 142 ; 143 } 144 145 @NotNull 146 private static ProtoBuf.Visibility visibility(@NotNull Visibility visibility) { 147 if (visibility == Visibilities.INTERNAL) { 148 return ProtoBuf.Visibility.INTERNAL; 149 } 150 else if (visibility == Visibilities.PUBLIC) { 151 return ProtoBuf.Visibility.PUBLIC; 152 } 153 else if (visibility == Visibilities.PRIVATE) { 154 return ProtoBuf.Visibility.PRIVATE; 155 } 156 else if (visibility == Visibilities.PRIVATE_TO_THIS) { 157 return ProtoBuf.Visibility.PRIVATE_TO_THIS; 158 } 159 else if (visibility == Visibilities.PROTECTED) { 160 return ProtoBuf.Visibility.PROTECTED; 161 } 162 else if (visibility == Visibilities.LOCAL) { 163 return ProtoBuf.Visibility.LOCAL; 164 } 165 throw new IllegalArgumentException("Unknown visibility: " + visibility); 166 } 167 168 @NotNull 169 private static ProtoBuf.Modality modality(@NotNull Modality modality) { 170 switch (modality) { 171 case FINAL: 172 return ProtoBuf.Modality.FINAL; 173 case OPEN: 174 return ProtoBuf.Modality.OPEN; 175 case ABSTRACT: 176 return ProtoBuf.Modality.ABSTRACT; 177 case SEALED: 178 return ProtoBuf.Modality.SEALED; 179 } 180 throw new IllegalArgumentException("Unknown modality: " + modality); 181 } 182 183 @NotNull 184 private static ProtoBuf.Callable.MemberKind memberKind(@NotNull CallableMemberDescriptor.Kind kind) { 185 switch (kind) { 186 case DECLARATION: 187 return ProtoBuf.Callable.MemberKind.DECLARATION; 188 case FAKE_OVERRIDE: 189 return ProtoBuf.Callable.MemberKind.FAKE_OVERRIDE; 190 case DELEGATION: 191 return ProtoBuf.Callable.MemberKind.DELEGATION; 192 case SYNTHESIZED: 193 return ProtoBuf.Callable.MemberKind.SYNTHESIZED; 194 } 195 throw new IllegalArgumentException("Unknown member kind: " + kind); 196 } 197 198 public static int getValueParameterFlags(boolean hasAnnotations, boolean declaresDefaultValue) { 199 return HAS_ANNOTATIONS.toFlags(hasAnnotations) 200 | DECLARES_DEFAULT_VALUE.toFlags(declaresDefaultValue) 201 ; 202 } 203 204 // Infrastructure 205 206 public static abstract class FlagField<E> { 207 public static <E extends Internal.EnumLite> FlagField<E> after(FlagField<?> previousField, E[] values) { 208 int offset = previousField.offset + previousField.bitWidth; 209 return new EnumLiteFlagField<E>(offset, values); 210 } 211 212 public static <E extends Internal.EnumLite> FlagField<E> first(E[] values) { 213 return new EnumLiteFlagField<E>(0, values); 214 } 215 216 public static FlagField<Boolean> booleanFirst() { 217 return new BooleanFlagField(0); 218 } 219 220 public static FlagField<Boolean> booleanAfter(FlagField<?> previousField) { 221 int offset = previousField.offset + previousField.bitWidth; 222 return new BooleanFlagField(offset); 223 } 224 225 private final int offset; 226 private final int bitWidth; 227 private final E[] values; 228 229 private FlagField(int offset, E[] values) { 230 this.offset = offset; 231 this.bitWidth = bitWidth(values); 232 this.values = values; 233 } 234 235 public E get(int flags) { 236 int maskUnshifted = (1 << bitWidth) - 1; 237 int mask = maskUnshifted << offset; 238 int value = (flags & mask) >> offset; 239 for (E e : values) { 240 if (getIntValue(e) == value) { 241 return e; 242 } 243 } 244 throw new IllegalStateException("Flag not found: " + value); 245 } 246 247 public int toFlags(E value) { 248 return getIntValue(value) << offset; 249 } 250 251 protected abstract int getIntValue(E value); 252 253 } 254 255 private static class BooleanFlagField extends FlagField<Boolean> { 256 private static final Boolean[] BOOLEAN = { false, true }; 257 258 public BooleanFlagField(int offset) { 259 super(offset, BOOLEAN); 260 } 261 262 @Override 263 protected int getIntValue(Boolean value) { 264 return value ? 1 : 0; 265 } 266 } 267 268 private static class EnumLiteFlagField<E extends Internal.EnumLite> extends FlagField<E> { 269 public EnumLiteFlagField(int offset, E[] values) { 270 super(offset, values); 271 } 272 273 @Override 274 protected int getIntValue(E value) { 275 return value.getNumber(); 276 } 277 } 278 279 }