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 com.intellij.psi.PsiElement;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.asm4.*;
023    
024    public abstract class ClassBuilder {
025        protected static final MethodVisitor EMPTY_METHOD_VISITOR = new MethodVisitor(Opcodes.ASM4) {};
026        protected static final FieldVisitor EMPTY_FIELD_VISITOR = new FieldVisitor(Opcodes.ASM4) {};
027    
028        private String thisName;
029    
030        private final JvmSerializationBindings serializationBindings = new JvmSerializationBindings();
031    
032        public static class Concrete extends ClassBuilder {
033            private final ClassVisitor v;
034    
035            public Concrete(@NotNull ClassVisitor v) {
036                this.v = v;
037            }
038    
039            @Override
040            @NotNull
041            public ClassVisitor getVisitor() {
042                return v;
043            }
044        }
045    
046        @NotNull
047        public FieldVisitor newField(
048                @Nullable PsiElement origin,
049                int access,
050                @NotNull String name,
051                @NotNull String desc,
052                @Nullable String signature,
053                @Nullable Object value
054        ) {
055            FieldVisitor visitor = getVisitor().visitField(access, name, desc, signature, value);
056            if (visitor == null) {
057                return EMPTY_FIELD_VISITOR;
058            }
059            return visitor;
060        }
061    
062        @NotNull
063        public MethodVisitor newMethod(
064                @Nullable PsiElement origin,
065                int access,
066                @NotNull String name,
067                @NotNull String desc,
068                @Nullable String signature,
069                @Nullable String[] exceptions
070        ) {
071            MethodVisitor visitor = getVisitor().visitMethod(access, name, desc, signature, exceptions);
072            if (visitor == null) {
073                return EMPTY_METHOD_VISITOR;
074            }
075            return visitor;
076        }
077    
078        @NotNull
079        public JvmSerializationBindings getSerializationBindings() {
080            return serializationBindings;
081        }
082    
083        @NotNull
084        public AnnotationVisitor newAnnotation(@NotNull String desc, boolean visible) {
085            return getVisitor().visitAnnotation(desc, visible);
086        }
087    
088        public void done() {
089            getVisitor().visitEnd();
090        }
091    
092        @NotNull
093        public abstract ClassVisitor getVisitor();
094    
095        public void defineClass(
096                @Nullable PsiElement origin,
097                int version,
098                int access,
099                @NotNull String name,
100                @Nullable String signature,
101                @NotNull String superName,
102                @NotNull String[] interfaces
103        ) {
104            thisName = name;
105            getVisitor().visit(version, access, name, signature, superName, interfaces);
106        }
107    
108        public void visitSource(@NotNull String name, @Nullable String debug) {
109            getVisitor().visitSource(name, debug);
110        }
111    
112        public void visitOuterClass(@NotNull String owner, @Nullable String name, @Nullable String desc) {
113            getVisitor().visitOuterClass(owner, name, desc);
114        }
115    
116        public void visitInnerClass(@NotNull String name, @Nullable String outerName, @Nullable String innerName, int access) {
117            getVisitor().visitInnerClass(name, outerName, innerName, access);
118        }
119    
120        @NotNull
121        public String getThisName() {
122            assert thisName != null : "This name isn't set";
123            return thisName;
124        }
125    }