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 }