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); 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 @Override 100 public MethodVisitor newMethod( 101 @Nullable PsiElement 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 != null) { 111 // If stub for method generated 112 markLastChild(origin); 113 } 114 115 return internalVisitor; 116 } 117 118 @Override 119 public FieldVisitor newField( 120 @Nullable PsiElement origin, 121 int access, 122 @NotNull String name, 123 @NotNull String desc, 124 @Nullable String signature, 125 @Nullable Object value 126 ) { 127 FieldVisitor internalVisitor = super.newField(origin, access, name, desc, signature, value); 128 129 if (internalVisitor != null) { 130 // If stub for field generated 131 markLastChild(origin); 132 } 133 134 return internalVisitor; 135 } 136 137 private void markLastChild(@Nullable PsiElement origin) { 138 List children = v.getResult().getChildrenStubs(); 139 StubBase last = (StubBase) children.get(children.size() - 1); 140 141 PsiElement oldOrigin = last.getUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT); 142 if (oldOrigin != null) { 143 throw new IllegalStateException("Rewriting origin element: " + oldOrigin.getText() + " for stub " + last.toString()); 144 } 145 146 last.putUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT, origin); 147 } 148 149 @Override 150 public void done() { 151 if (!isNamespace) { 152 StubElement pop = parentStack.pop(); 153 assert pop == v.getResult(); 154 } 155 super.done(); 156 } 157 }