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