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