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