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 com.intellij.psi.PsiElement;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.kotlin.codegen.inline.FileMapping;
023    import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
024    import org.jetbrains.kotlin.codegen.inline.SMAPBuilder;
025    import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
026    import org.jetbrains.org.objectweb.asm.*;
027    
028    import java.util.ArrayList;
029    import java.util.List;
030    
031    public abstract class AbstractClassBuilder implements ClassBuilder {
032        protected static final MethodVisitor EMPTY_METHOD_VISITOR = new MethodVisitor(Opcodes.ASM5) {};
033        protected static final FieldVisitor EMPTY_FIELD_VISITOR = new FieldVisitor(Opcodes.ASM5) {};
034    
035        private String thisName;
036    
037        private final JvmSerializationBindings serializationBindings = new JvmSerializationBindings();
038    
039        private final List<FileMapping> fileMappings = new ArrayList<FileMapping>();
040    
041        private String sourceName;
042    
043        private String debugInfo;
044    
045        public static class Concrete extends AbstractClassBuilder {
046            private final ClassVisitor v;
047    
048            public Concrete(@NotNull ClassVisitor v) {
049                this.v = v;
050            }
051    
052            @Override
053            @NotNull
054            public ClassVisitor getVisitor() {
055                return v;
056            }
057        }
058    
059        @Override
060        @NotNull
061        public FieldVisitor newField(
062                @NotNull JvmDeclarationOrigin origin,
063                int access,
064                @NotNull String name,
065                @NotNull String desc,
066                @Nullable String signature,
067                @Nullable Object value
068        ) {
069            FieldVisitor visitor = getVisitor().visitField(access, name, desc, signature, value);
070            if (visitor == null) {
071                return EMPTY_FIELD_VISITOR;
072            }
073            return visitor;
074        }
075    
076        @Override
077        @NotNull
078        public MethodVisitor newMethod(
079                @NotNull JvmDeclarationOrigin origin,
080                int access,
081                @NotNull String name,
082                @NotNull String desc,
083                @Nullable String signature,
084                @Nullable String[] exceptions
085        ) {
086            MethodVisitor visitor = getVisitor().visitMethod(access, name, desc, signature, exceptions);
087            if (visitor == null) {
088                return EMPTY_METHOD_VISITOR;
089            }
090            return visitor;
091        }
092    
093        @Override
094        @NotNull
095        public JvmSerializationBindings getSerializationBindings() {
096            return serializationBindings;
097        }
098    
099        @Override
100        @NotNull
101        public AnnotationVisitor newAnnotation(@NotNull String desc, boolean visible) {
102            return getVisitor().visitAnnotation(desc, visible);
103        }
104    
105        @Override
106        public void done() {
107            if (!fileMappings.isEmpty() && InlineCodegenUtil.GENERATE_SMAP) {
108                FileMapping origin = fileMappings.get(0);
109                assert sourceName == null || origin.getName().equals(sourceName) : "Error " + origin.getName() +  " != "  + sourceName;
110                getVisitor().visitSource(origin.getName(), new SMAPBuilder(origin.getName(), origin.getPath(), fileMappings).build());
111            }
112            else {
113                getVisitor().visitSource(sourceName, debugInfo);
114            }
115    
116            getVisitor().visitEnd();
117        }
118    
119        @Override
120        public void defineClass(
121                @Nullable PsiElement origin,
122                int version,
123                int access,
124                @NotNull String name,
125                @Nullable String signature,
126                @NotNull String superName,
127                @NotNull String[] interfaces
128        ) {
129            thisName = name;
130            getVisitor().visit(version, access, name, signature, superName, interfaces);
131        }
132    
133        @Override
134        public void visitSource(@NotNull String name, @Nullable String debug) {
135            sourceName = name;
136            debugInfo = debug;
137        }
138    
139        @Override
140        public void visitOuterClass(@NotNull String owner, @Nullable String name, @Nullable String desc) {
141            getVisitor().visitOuterClass(owner, name, desc);
142        }
143    
144        @Override
145        public void visitInnerClass(@NotNull String name, @Nullable String outerName, @Nullable String innerName, int access) {
146            getVisitor().visitInnerClass(name, outerName, innerName, access);
147        }
148    
149        @Override
150        @NotNull
151        public String getThisName() {
152            assert thisName != null : "This name isn't set";
153            return thisName;
154        }
155    
156        @Override
157        public void addSMAP(FileMapping mapping) {
158            fileMappings.add(mapping);
159        }
160    }