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.binding;
018    
019    import com.intellij.openapi.util.Pair;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor;
023    import org.jetbrains.kotlin.descriptors.*;
024    import org.jetbrains.kotlin.types.JetType;
025    import org.jetbrains.org.objectweb.asm.Type;
026    
027    import java.util.*;
028    
029    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.getDirectMember;
030    
031    public final class MutableClosure implements CalculatedClosure {
032        private final ClassDescriptor enclosingClass;
033        private final CallableDescriptor enclosingFunWithReceiverDescriptor;
034    
035        private boolean captureThis;
036        private boolean captureReceiver;
037    
038        private Map<DeclarationDescriptor, EnclosedValueDescriptor> captureVariables;
039        private Map<DeclarationDescriptor, Integer> parameterOffsetInConstructor;
040        private List<Pair<String, Type>> recordedFields;
041    
042        MutableClosure(@NotNull ClassDescriptor classDescriptor, @Nullable ClassDescriptor enclosingClass) {
043            this.enclosingClass = enclosingClass;
044            this.enclosingFunWithReceiverDescriptor = enclosingExtensionMemberForClass(classDescriptor);
045        }
046    
047        @Nullable
048        private static CallableDescriptor enclosingExtensionMemberForClass(@NotNull ClassDescriptor classDescriptor) {
049            DeclarationDescriptor classContainer = classDescriptor.getContainingDeclaration();
050            if (classContainer instanceof CallableMemberDescriptor) {
051                CallableMemberDescriptor member = getDirectMember((CallableMemberDescriptor) classContainer);
052                if (member.getExtensionReceiverParameter() != null) {
053                    return member;
054                }
055            }
056            return null;
057        }
058    
059        @Nullable
060        public ClassDescriptor getEnclosingClass() {
061            return enclosingClass;
062        }
063    
064        @Override
065        public ClassDescriptor getCaptureThis() {
066            return captureThis ? enclosingClass : null;
067        }
068    
069        public void setCaptureThis() {
070            this.captureThis = true;
071        }
072    
073        @Override
074        public JetType getCaptureReceiverType() {
075            if (captureReceiver) {
076                ReceiverParameterDescriptor parameter = getEnclosingReceiverDescriptor();
077                assert parameter != null : "Receiver parameter should exist in " + enclosingFunWithReceiverDescriptor;
078                return parameter.getType();
079            }
080    
081            return null;
082        }
083    
084        public void setCaptureReceiver() {
085            if (enclosingFunWithReceiverDescriptor == null) {
086                throw new IllegalStateException("Extension receiver parameter should exist");
087            }
088            this.captureReceiver = true;
089        }
090    
091        @NotNull
092        @Override
093        public Map<DeclarationDescriptor, EnclosedValueDescriptor> getCaptureVariables() {
094            return captureVariables != null ? captureVariables : Collections.<DeclarationDescriptor, EnclosedValueDescriptor>emptyMap();
095        }
096    
097        @NotNull
098        @Override
099        public List<Pair<String, Type>> getRecordedFields() {
100            return recordedFields != null ? recordedFields : Collections.<Pair<String, Type>>emptyList();
101        }
102    
103        public void recordField(String name, Type type) {
104            if (recordedFields == null) {
105                recordedFields = new LinkedList<Pair<String, Type>>();
106            }
107            recordedFields.add(new Pair<String, Type>(name, type));
108        }
109    
110        public void captureVariable(EnclosedValueDescriptor value) {
111            if (captureVariables == null) {
112                captureVariables = new LinkedHashMap<DeclarationDescriptor, EnclosedValueDescriptor>();
113            }
114            captureVariables.put(value.getDescriptor(), value);
115        }
116    
117        public void setCapturedParameterOffsetInConstructor(DeclarationDescriptor descriptor, int offset) {
118            if (parameterOffsetInConstructor == null) {
119                parameterOffsetInConstructor = new LinkedHashMap<DeclarationDescriptor, Integer>();
120            }
121            parameterOffsetInConstructor.put(descriptor, offset);
122        }
123    
124        public int getCapturedParameterOffsetInConstructor(DeclarationDescriptor descriptor) {
125            Integer result = parameterOffsetInConstructor != null ? parameterOffsetInConstructor.get(descriptor) : null;
126            return result != null ? result.intValue() : -1;
127        }
128    
129        @Nullable
130        public ReceiverParameterDescriptor getEnclosingReceiverDescriptor() {
131            return enclosingFunWithReceiverDescriptor != null ? enclosingFunWithReceiverDescriptor.getExtensionReceiverParameter() : null;
132        }
133    }