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