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.asJava;
018
019 import com.intellij.psi.PsiElement;
020 import com.intellij.psi.impl.compiled.InnerClassSourceStrategy;
021 import com.intellij.psi.impl.compiled.StubBuildingVisitor;
022 import com.intellij.psi.stubs.StubBase;
023 import com.intellij.psi.stubs.StubElement;
024 import com.intellij.util.containers.Stack;
025 import org.jetbrains.annotations.NotNull;
026 import org.jetbrains.annotations.Nullable;
027 import org.jetbrains.kotlin.codegen.AbstractClassBuilder;
028 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
029 import org.jetbrains.org.objectweb.asm.ClassVisitor;
030 import org.jetbrains.org.objectweb.asm.FieldVisitor;
031 import org.jetbrains.org.objectweb.asm.MethodVisitor;
032
033 import java.util.List;
034
035 public class StubClassBuilder extends AbstractClassBuilder {
036 private static final InnerClassSourceStrategy<Object> EMPTY_STRATEGY = new InnerClassSourceStrategy<Object>() {
037 @Override
038 public Object findInnerClass(String s, Object o) {
039 return null;
040 }
041
042 @Override
043 public void accept(Object innerClass, StubBuildingVisitor<Object> visitor) {
044 throw new UnsupportedOperationException("Shall not be called!");
045 }
046 };
047 private final StubElement parent;
048 private StubBuildingVisitor v;
049 private final Stack<StubElement> parentStack;
050
051 public StubClassBuilder(@NotNull Stack<StubElement> parentStack) {
052 this.parentStack = parentStack;
053 this.parent = parentStack.peek();
054 }
055
056 @NotNull
057 @Override
058 public ClassVisitor getVisitor() {
059 assert v != null : "Called before class is defined";
060 return v;
061 }
062
063 @Override
064 public void defineClass(
065 PsiElement origin,
066 int version,
067 int access,
068 @NotNull String name,
069 @Nullable String signature,
070 @NotNull String superName,
071 @NotNull String[] interfaces
072 ) {
073 assert v == null : "defineClass() called twice?";
074 v = new StubBuildingVisitor<Object>(null, EMPTY_STRATEGY, parent, access, null);
075
076 super.defineClass(origin, version, access, name, signature, superName, interfaces);
077
078 parentStack.push(v.getResult());
079
080 ((StubBase) v.getResult()).putUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT, origin);
081 }
082
083 @NotNull
084 @Override
085 public MethodVisitor newMethod(
086 @NotNull JvmDeclarationOrigin origin,
087 int access,
088 @NotNull String name,
089 @NotNull String desc,
090 @Nullable String signature,
091 @Nullable String[] exceptions
092 ) {
093 MethodVisitor internalVisitor = super.newMethod(origin, access, name, desc, signature, exceptions);
094
095 if (internalVisitor != EMPTY_METHOD_VISITOR) {
096 // If stub for method generated
097 markLastChild(origin.getElement());
098 }
099
100 return internalVisitor;
101 }
102
103 @NotNull
104 @Override
105 public FieldVisitor newField(
106 @NotNull JvmDeclarationOrigin origin,
107 int access,
108 @NotNull String name,
109 @NotNull String desc,
110 @Nullable String signature,
111 @Nullable Object value
112 ) {
113 FieldVisitor internalVisitor = super.newField(origin, access, name, desc, signature, value);
114
115 if (internalVisitor != EMPTY_FIELD_VISITOR) {
116 // If stub for field generated
117 markLastChild(origin.getElement());
118 }
119
120 return internalVisitor;
121 }
122
123 private void markLastChild(@Nullable PsiElement origin) {
124 List children = v.getResult().getChildrenStubs();
125 StubBase last = (StubBase) children.get(children.size() - 1);
126
127 PsiElement oldOrigin = last.getUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT);
128 if (oldOrigin != null) {
129 throw new IllegalStateException("Rewriting origin element: " + oldOrigin.getText() + " for stub " + last.toString());
130 }
131
132 last.putUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT, origin);
133 }
134
135 @Override
136 public void done() {
137 StubElement pop = parentStack.pop();
138 assert pop == v.getResult();
139 super.done();
140 }
141 }