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.load.kotlin.PackageClassUtils; 029 import org.jetbrains.kotlin.name.FqName; 030 import org.jetbrains.kotlin.psi.JetFile; 031 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; 032 import org.jetbrains.org.objectweb.asm.ClassVisitor; 033 import org.jetbrains.org.objectweb.asm.FieldVisitor; 034 import org.jetbrains.org.objectweb.asm.MethodVisitor; 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 }