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