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