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.context;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.kotlin.codegen.AsmUtil;
022    import org.jetbrains.kotlin.codegen.JvmCodegenUtil;
023    import org.jetbrains.kotlin.codegen.OwnerKind;
024    import org.jetbrains.kotlin.codegen.StackValue;
025    import org.jetbrains.kotlin.codegen.binding.MutableClosure;
026    import org.jetbrains.kotlin.codegen.state.GenerationState;
027    import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
028    import org.jetbrains.kotlin.descriptors.*;
029    import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
030    import org.jetbrains.kotlin.resolve.inline.InlineUtil;
031    import org.jetbrains.org.objectweb.asm.Label;
032    import org.jetbrains.org.objectweb.asm.Type;
033    
034    public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
035        private final boolean isInliningLambda;
036        private Label methodStartLabel;
037        private Label methodEndLabel;
038    
039        // Note: in case of code inside property accessors, functionDescriptor will be that accessor,
040        // but CodegenContext#contextDescriptor will be the corresponding property
041        private final FunctionDescriptor functionDescriptor;
042    
043        protected MethodContext(
044                @NotNull FunctionDescriptor functionDescriptor,
045                @NotNull OwnerKind contextKind,
046                @NotNull CodegenContext parentContext,
047                @Nullable MutableClosure closure,
048                boolean isInliningLambda
049        ) {
050            super(JvmCodegenUtil.getDirectMember(functionDescriptor), contextKind, parentContext, closure,
051                  parentContext.hasThisDescriptor() ? parentContext.getThisDescriptor() : null, null);
052            this.isInliningLambda = isInliningLambda;
053            this.functionDescriptor = functionDescriptor;
054        }
055    
056        @NotNull
057        @Override
058        public CodegenContext getParentContext() {
059            //noinspection ConstantConditions
060            return super.getParentContext();
061        }
062    
063        public StackValue getReceiverExpression(JetTypeMapper typeMapper) {
064            assert getCallableDescriptorWithReceiver() != null;
065            @SuppressWarnings("ConstantConditions")
066            Type asmType = typeMapper.mapType(getCallableDescriptorWithReceiver().getExtensionReceiverParameter().getType());
067            return StackValue.local(AsmUtil.getReceiverIndex(this, getContextDescriptor()), asmType);
068        }
069    
070        @Override
071        public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) {
072            if (d instanceof SyntheticFieldDescriptor) {
073                SyntheticFieldDescriptor fieldDescriptor = (SyntheticFieldDescriptor) d;
074                d = fieldDescriptor.getPropertyDescriptor();
075            }
076            if (getContextDescriptor() == d) {
077                return result != null ? result : StackValue.LOCAL_0;
078            }
079    
080            return getParentContext().lookupInContext(d, result, state, ignoreNoOuter);
081        }
082    
083        @Nullable
084        public StackValue generateReceiver(@NotNull CallableDescriptor descriptor, @NotNull GenerationState state, boolean ignoreNoOuter) {
085            if (getCallableDescriptorWithReceiver() == descriptor) {
086                return getReceiverExpression(state.getTypeMapper());
087            }
088            ReceiverParameterDescriptor parameter = descriptor.getExtensionReceiverParameter();
089            return lookupInContext(parameter, StackValue.LOCAL_0, state, ignoreNoOuter);
090        }
091    
092        @Override
093        public StackValue getOuterExpression(StackValue prefix, boolean ignoreNoOuter) {
094            return getParentContext().getOuterExpression(prefix, false);
095        }
096    
097        @Nullable
098        public Label getMethodStartLabel() {
099            return methodStartLabel;
100        }
101    
102        public void setMethodStartLabel(@NotNull Label methodStartLabel) {
103            this.methodStartLabel = methodStartLabel;
104        }
105    
106        @Nullable
107        public Label getMethodEndLabel() {
108            return methodEndLabel;
109        }
110    
111        public void setMethodEndLabel(@NotNull Label methodEndLabel) {
112            this.methodEndLabel = methodEndLabel;
113        }
114    
115        @Override
116        public String toString() {
117            return "Method: " + getContextDescriptor();
118        }
119    
120        public boolean isInlineFunction() {
121            return InlineUtil.isInline(getContextDescriptor());
122        }
123    
124        public boolean isInliningLambda() {
125            return isInliningLambda;
126        }
127    
128        @NotNull
129        public FunctionDescriptor getFunctionDescriptor() {
130            return functionDescriptor;
131        }
132    }