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.JetTypeMapper;
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 JetTypeMapper typeMapper) {
032            if (!classDescriptor.getKind().isSingleton()) {
033                throw new UnsupportedOperationException("Can't create singleton field for class: " + classDescriptor);
034            }
035    
036            if (isNonCompanionObject(classDescriptor) || CompanionObjectMapping.hasMappingToObject(classDescriptor)) {
037                Type type = typeMapper.mapType(classDescriptor);
038                return new FieldInfo(type, type, JvmAbi.INSTANCE_FIELD, true);
039            }
040            else {
041                ClassDescriptor ownerDescriptor = DescriptorUtils.getParentOfType(classDescriptor, ClassDescriptor.class);
042                assert ownerDescriptor != null : "Owner not found for class: " + classDescriptor;
043                Type ownerType = typeMapper.mapType(ownerDescriptor);
044                return new FieldInfo(ownerType, typeMapper.mapType(classDescriptor), classDescriptor.getName().asString(), true);
045            }
046        }
047    
048        @NotNull
049        public static FieldInfo createForHiddenField(@NotNull Type owner, @NotNull Type fieldType, @NotNull String fieldName) {
050            return new FieldInfo(owner, fieldType, fieldName, false);
051        }
052    
053        private final Type fieldType;
054        private final Type ownerType;
055        private final String fieldName;
056        private final boolean isStatic;
057    
058        private FieldInfo(@NotNull Type ownerType, @NotNull Type fieldType, @NotNull String fieldName, boolean isStatic) {
059            this.ownerType = ownerType;
060            this.fieldType = fieldType;
061            this.fieldName = fieldName;
062            this.isStatic = isStatic;
063        }
064    
065        @NotNull
066        public Type getFieldType() {
067            return fieldType;
068        }
069    
070        @NotNull
071        public Type getOwnerType() {
072            return ownerType;
073        }
074    
075        @NotNull
076        public String getOwnerInternalName() {
077            return ownerType.getInternalName();
078        }
079    
080        @NotNull
081        public String getFieldName() {
082            return fieldName;
083        }
084    
085        public boolean isStatic() {
086            return isStatic;
087        }
088    
089        @Override
090        public String toString() {
091            return String.format("%s %s.%s : %s", isStatic ? "GETSTATIC" : "GETFIELD", ownerType.getInternalName(), fieldName, fieldType);
092        }
093    }