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