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