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.codegen;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.kotlin.builtins.CompanionObjectMapping;
021    import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
022    import org.jetbrains.kotlin.descriptors.ClassDescriptor;
023    import org.jetbrains.kotlin.load.java.JvmAbi;
024    import org.jetbrains.kotlin.resolve.DescriptorUtils;
025    import org.jetbrains.org.objectweb.asm.Type;
026    
027    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isNonCompanionObject;
028    
029    public class FieldInfo {
030        @NotNull
031        public static FieldInfo createForSingleton(@NotNull ClassDescriptor classDescriptor, @NotNull KotlinTypeMapper typeMapper) {
032            if (!classDescriptor.getKind().isSingleton() || DescriptorUtils.isEnumEntry(classDescriptor)) {
033                throw new UnsupportedOperationException("Can't create singleton field for class: " + classDescriptor);
034            }
035    
036            if (isNonCompanionObject(classDescriptor) || CompanionObjectMapping.INSTANCE.isMappedIntrinsicCompanionObject(classDescriptor)) {
037                return createSingletonViaInstance(classDescriptor, typeMapper);
038            }
039    
040            ClassDescriptor ownerDescriptor = DescriptorUtils.getParentOfType(classDescriptor, ClassDescriptor.class);
041            assert ownerDescriptor != null : "Owner not found for class: " + classDescriptor;
042            Type ownerType = typeMapper.mapType(ownerDescriptor);
043            return new FieldInfo(ownerType, typeMapper.mapType(classDescriptor), classDescriptor.getName().asString(), true);
044        }
045    
046        @NotNull
047        public static FieldInfo createSingletonViaInstance(
048                @NotNull ClassDescriptor classDescriptor,
049                @NotNull KotlinTypeMapper typeMapper
050        ) {
051            Type type = typeMapper.mapType(classDescriptor);
052            return new FieldInfo(type, type, JvmAbi.INSTANCE_FIELD, true);
053        }
054    
055        @NotNull
056        public static FieldInfo createForHiddenField(@NotNull Type owner, @NotNull Type fieldType, @NotNull String fieldName) {
057            return new FieldInfo(owner, fieldType, fieldName, false);
058        }
059    
060        private final Type fieldType;
061        private final Type ownerType;
062        private final String fieldName;
063        private final boolean isStatic;
064    
065        private FieldInfo(@NotNull Type ownerType, @NotNull Type fieldType, @NotNull String fieldName, boolean isStatic) {
066            this.ownerType = ownerType;
067            this.fieldType = fieldType;
068            this.fieldName = fieldName;
069            this.isStatic = isStatic;
070        }
071    
072        @NotNull
073        public Type getFieldType() {
074            return fieldType;
075        }
076    
077        @NotNull
078        public Type getOwnerType() {
079            return ownerType;
080        }
081    
082        @NotNull
083        public String getOwnerInternalName() {
084            return ownerType.getInternalName();
085        }
086    
087        @NotNull
088        public String getFieldName() {
089            return fieldName;
090        }
091    
092        public boolean isStatic() {
093            return isStatic;
094        }
095    
096        @Override
097        public String toString() {
098            return String.format("%s %s.%s : %s", isStatic ? "GETSTATIC" : "GETFIELD", ownerType.getInternalName(), fieldName, fieldType);
099        }
100    }