001    /*
002     * Copyright 2010-2013 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.jet.codegen;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.asm4.MethodVisitor;
022    import org.jetbrains.asm4.Type;
023    import org.jetbrains.jet.codegen.context.ClassContext;
024    import org.jetbrains.jet.codegen.state.GenerationState;
025    import org.jetbrains.jet.lang.descriptors.*;
026    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
027    import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
028    import org.jetbrains.jet.lang.psi.*;
029    import org.jetbrains.jet.lang.resolve.BindingContext;
030    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
031    import org.jetbrains.jet.lang.resolve.name.Name;
032    
033    import java.util.Collections;
034    import java.util.List;
035    
036    import static org.jetbrains.asm4.Opcodes.*;
037    import static org.jetbrains.jet.codegen.AsmUtil.genMethodThrow;
038    import static org.jetbrains.jet.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
039    
040    public abstract class ClassBodyCodegen extends MemberCodegen {
041        protected final JetClassOrObject myClass;
042        protected final OwnerKind kind;
043        protected final ClassDescriptor descriptor;
044        protected final ClassBuilder v;
045        protected final ClassContext context;
046    
047        private MethodVisitor clInitMethod;
048    
049        private ExpressionCodegen clInitCodegen;
050    
051        protected ClassBodyCodegen(
052                @NotNull JetClassOrObject aClass,
053                @NotNull ClassContext context,
054                @NotNull ClassBuilder v,
055                @NotNull GenerationState state,
056                @Nullable MemberCodegen parentCodegen
057        ) {
058            super(state, parentCodegen);
059            descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
060            myClass = aClass;
061            this.context = context;
062            this.kind = context.getContextKind();
063            this.v = v;
064        }
065    
066        public void generate() {
067            generateDeclaration();
068    
069            generateClassBody();
070    
071            generateSyntheticParts();
072    
073            generateStaticInitializer();
074    
075            generateRemoveInIterator();
076    
077            generateKotlinAnnotation();
078        }
079    
080        protected abstract void generateDeclaration();
081    
082        protected void generateKotlinAnnotation() {
083        }
084    
085        protected void generateSyntheticParts() {
086        }
087    
088        private void generateClassBody() {
089            FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state);
090            PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, this);
091    
092            if (kind != OwnerKind.TRAIT_IMPL) {
093                //generate nested classes first and only then generate class body. It necessary to access to nested CodegenContexts
094                for (JetDeclaration declaration : myClass.getDeclarations()) {
095                    if (shouldProcessFirst(declaration)) {
096                        generateDeclaration(propertyCodegen, declaration);
097                    }
098                }
099            }
100    
101            for (JetDeclaration declaration : myClass.getDeclarations()) {
102                if (!shouldProcessFirst(declaration)) {
103                    generateDeclaration(propertyCodegen, declaration);
104                }
105            }
106    
107            generatePrimaryConstructorProperties(propertyCodegen, myClass);
108        }
109    
110        private boolean shouldProcessFirst(JetDeclaration declaration) {
111            return false == (declaration instanceof JetProperty || declaration instanceof JetNamedFunction);
112        }
113    
114    
115        protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration) {
116            if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) {
117                genFunctionOrProperty(context, (JetTypeParameterListOwner) declaration, v);
118            }
119            else if (declaration instanceof JetClassOrObject) {
120                if (declaration instanceof JetEnumEntry && !enumEntryNeedSubclass(
121                        state.getBindingContext(), (JetEnumEntry) declaration)) {
122                    return;
123                }
124    
125                genClassOrObject(context, (JetClassOrObject) declaration);
126            }
127            else if (declaration instanceof JetClassObject) {
128                genClassOrObject(context, ((JetClassObject) declaration).getObjectDeclaration());
129            }
130        }
131    
132        private void generatePrimaryConstructorProperties(PropertyCodegen propertyCodegen, JetClassOrObject origin) {
133            boolean isAnnotation = origin instanceof JetClass && ((JetClass) origin).isAnnotation();
134            for (JetParameter p : getPrimaryConstructorParameters()) {
135                if (p.getValOrVarNode() != null) {
136                    PropertyDescriptor propertyDescriptor = state.getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, p);
137                    if (propertyDescriptor != null) {
138                        if (!isAnnotation) {
139                            propertyCodegen.generatePrimaryConstructorProperty(p, propertyDescriptor);
140                        }
141                        else {
142                            propertyCodegen.generateConstructorPropertyAsMethodForAnnotationClass(p, propertyDescriptor);
143                        }
144                    }
145                }
146            }
147        }
148    
149        protected @NotNull List<JetParameter> getPrimaryConstructorParameters() {
150            if (myClass instanceof JetClass) {
151                return ((JetClass) myClass).getPrimaryConstructorParameters();
152            }
153            return Collections.emptyList();
154        }
155    
156        private void generateStaticInitializer() {
157            if (clInitMethod != null) {
158                createOrGetClInitMethod();
159    
160                if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
161                    ExpressionCodegen codegen = createOrGetClInitCodegen();
162    
163                    createOrGetClInitMethod().visitInsn(RETURN);
164                    FunctionCodegen.endVisit(codegen.v, "static initializer", myClass);
165                }
166            }
167        }
168    
169        @Nullable
170        protected MethodVisitor createOrGetClInitMethod() {
171            if (clInitMethod == null) {
172                clInitMethod = v.newMethod(null, ACC_STATIC, "<clinit>", "()V", null, null);
173            }
174            return clInitMethod;
175        }
176    
177        @Nullable
178        protected ExpressionCodegen createOrGetClInitCodegen() {
179            assert state.getClassBuilderMode() == ClassBuilderMode.FULL;
180            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
181                if (clInitCodegen == null) {
182                    MethodVisitor method = createOrGetClInitMethod();
183                    method.visitCode();
184                    SimpleFunctionDescriptorImpl clInit =
185                            new SimpleFunctionDescriptorImpl(descriptor, Collections.<AnnotationDescriptor>emptyList(),
186                                                             Name.special("<clinit>"),
187                                                             CallableMemberDescriptor.Kind.SYNTHESIZED);
188                    clInit.initialize(null, null, Collections.<TypeParameterDescriptor>emptyList(),
189                                      Collections.<ValueParameterDescriptor>emptyList(), null, null, Visibilities.PRIVATE, false);
190    
191                    clInitCodegen = new ExpressionCodegen(method, new FrameMap(), Type.VOID_TYPE, context.intoFunction(clInit), state);
192                }
193            }
194            return clInitCodegen;
195        }
196    
197        private void generateRemoveInIterator() {
198            // generates stub 'remove' function for subclasses of Iterator to be compatible with java.util.Iterator
199            if (DescriptorUtils.isIteratorWithoutRemoveImpl(descriptor)) {
200                MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "remove", "()V", null, null);
201                genMethodThrow(mv, "java/lang/UnsupportedOperationException", "Mutating method called on a Kotlin Iterator");
202            }
203        }
204    }