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;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.kotlin.backend.common.bridges.ImplKt;
022    import org.jetbrains.kotlin.codegen.context.ClassContext;
023    import org.jetbrains.kotlin.codegen.state.GenerationState;
024    import org.jetbrains.kotlin.descriptors.*;
025    import org.jetbrains.kotlin.psi.*;
026    import org.jetbrains.kotlin.resolve.BindingContext;
027    import org.jetbrains.kotlin.resolve.DescriptorUtils;
028    
029    import java.util.Collections;
030    import java.util.List;
031    
032    import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
033    
034    public abstract class ClassBodyCodegen extends MemberCodegen<KtClassOrObject> {
035        protected final KtClassOrObject myClass;
036        protected final OwnerKind kind;
037        protected final ClassDescriptor descriptor;
038    
039        protected ClassBodyCodegen(
040                @NotNull KtClassOrObject myClass,
041                @NotNull ClassContext context,
042                @NotNull ClassBuilder v,
043                @NotNull GenerationState state,
044                @Nullable MemberCodegen<?> parentCodegen
045        ) {
046            super(state, parentCodegen, context, myClass, v);
047            this.myClass = myClass;
048            this.kind = context.getContextKind();
049            this.descriptor = bindingContext.get(BindingContext.CLASS, myClass);
050        }
051    
052        @Override
053        protected void generateBody() {
054            if (kind != OwnerKind.DEFAULT_IMPLS) {
055                //generate nested classes first and only then generate class body. It necessary to access to nested CodegenContexts
056                for (KtDeclaration declaration : myClass.getDeclarations()) {
057                    if (shouldProcessFirst(declaration)) {
058                        generateDeclaration(declaration);
059                    }
060                }
061            }
062    
063            for (KtDeclaration declaration : myClass.getDeclarations()) {
064                if (!shouldProcessFirst(declaration)) {
065                    generateDeclaration(declaration);
066                }
067            }
068    
069            if (!DescriptorUtils.isInterface(descriptor)) {
070                for (DeclarationDescriptor memberDescriptor : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) {
071                    if (memberDescriptor instanceof CallableMemberDescriptor) {
072                        CallableMemberDescriptor member = (CallableMemberDescriptor) memberDescriptor;
073                        if (!member.getKind().isReal() && ImplKt.findTraitImplementation(member) == null) {
074                            if (member instanceof FunctionDescriptor) {
075                                functionCodegen.generateBridges((FunctionDescriptor) member);
076                            }
077                            else if (member instanceof PropertyDescriptor) {
078                                PropertyGetterDescriptor getter = ((PropertyDescriptor) member).getGetter();
079                                if (getter != null) {
080                                    functionCodegen.generateBridges(getter);
081                                }
082                                PropertySetterDescriptor setter = ((PropertyDescriptor) member).getSetter();
083                                if (setter != null) {
084                                    functionCodegen.generateBridges(setter);
085                                }
086                            }
087                        }
088                    }
089                }
090            }
091    
092            generatePrimaryConstructorProperties();
093        }
094    
095        private static boolean shouldProcessFirst(KtDeclaration declaration) {
096            return !(declaration instanceof KtProperty || declaration instanceof KtNamedFunction);
097        }
098    
099        protected void generateDeclaration(KtDeclaration declaration) {
100            if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction) {
101                genFunctionOrProperty(declaration);
102            }
103            else if (declaration instanceof KtClassOrObject) {
104                if (declaration instanceof KtEnumEntry && !enumEntryNeedSubclass(bindingContext, (KtEnumEntry) declaration)) {
105                    return;
106                }
107    
108                genClassOrObject((KtClassOrObject) declaration);
109            }
110        }
111    
112        private void generatePrimaryConstructorProperties() {
113            boolean isAnnotation = descriptor.getKind() == ClassKind.ANNOTATION_CLASS;
114            for (KtParameter p : getPrimaryConstructorParameters()) {
115                if (p.hasValOrVar()) {
116                    PropertyDescriptor propertyDescriptor = bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, p);
117                    if (propertyDescriptor != null) {
118                        if (!isAnnotation) {
119                            propertyCodegen.generatePrimaryConstructorProperty(p, propertyDescriptor);
120                        }
121                        else {
122                            propertyCodegen.generateConstructorPropertyAsMethodForAnnotationClass(p, propertyDescriptor);
123                        }
124                    }
125                }
126            }
127        }
128    
129        @NotNull
130        protected List<KtParameter> getPrimaryConstructorParameters() {
131            if (myClass instanceof KtClass) {
132                return ((KtClass) myClass).getPrimaryConstructorParameters();
133            }
134            return Collections.emptyList();
135        }
136    
137        @Nullable
138        @Override
139        protected ClassDescriptor classForInnerClassRecord() {
140            return DescriptorUtils.isTopLevelDeclaration(descriptor) ? null : descriptor;
141        }
142    }