Multiple classfiles generated by test supported, starting work on interfaces list for jet classes
This commit is contained in:
Generated
+1
@@ -1,6 +1,7 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="max">
|
||||
<words>
|
||||
<w>classfiles</w>
|
||||
<w>codegen</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.ClassDescriptor;
|
||||
@@ -9,7 +11,10 @@ import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
@@ -26,37 +31,78 @@ public class ClassCodegen {
|
||||
}
|
||||
|
||||
public void generate(JetClass aClass) {
|
||||
generateInterface(aClass);
|
||||
}
|
||||
|
||||
private void generateInterface(JetClass aClass) {
|
||||
ClassDescriptor descriptor = bindingContext.getClassDescriptor(aClass);
|
||||
String fqName = CodeGenUtil.getInternalImplementationName(descriptor);
|
||||
|
||||
List<JetDelegationSpecifier> delegationSpecifiers = aClass.getDelegationSpecifiers();
|
||||
for (JetDelegationSpecifier specifier : delegationSpecifiers) {
|
||||
JetType superType = bindingContext.resolveTypeReference(specifier.getTypeReference());
|
||||
String superClassFQN = CodeGenUtil.getInternalInterfaceName((ClassDescriptor) superType.getConstructor().getDeclarationDescriptor());
|
||||
}
|
||||
Set<String> superInterfaces = getSuperInterfaces(aClass);
|
||||
|
||||
ClassVisitor v = factory.forClassImplementation(descriptor);
|
||||
String fqName = CodeGenUtil.getInternalInterfaceName(descriptor);
|
||||
ClassVisitor v = factory.forClassInterface(descriptor);
|
||||
v.visit(Opcodes.V1_6,
|
||||
Opcodes.ACC_PUBLIC,
|
||||
Opcodes.ACC_PUBLIC | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT,
|
||||
fqName.replace('.', '/'),
|
||||
null,
|
||||
//"jet/lang/Namespace",
|
||||
"java/lang/Object",
|
||||
new String[0]
|
||||
);
|
||||
superInterfaces.toArray(new String[superInterfaces.size()])
|
||||
);
|
||||
|
||||
generateClassBody(aClass, v);
|
||||
|
||||
v.visitEnd();
|
||||
}
|
||||
|
||||
private Set<String> getSuperInterfaces(JetClass aClass) {
|
||||
List<JetDelegationSpecifier> delegationSpecifiers = aClass.getDelegationSpecifiers();
|
||||
String superClassName = null;
|
||||
Set<String> superInterfaces = new LinkedHashSet<String>();
|
||||
for (JetDelegationSpecifier specifier : delegationSpecifiers) {
|
||||
JetType superType = bindingContext.resolveTypeReference(specifier.getTypeReference());
|
||||
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
|
||||
PsiElement superPsi = bindingContext.getDeclarationPsiElement(superClassDescriptor);
|
||||
|
||||
if (superPsi instanceof PsiClass) {
|
||||
PsiClass psiClass = (PsiClass) superPsi;
|
||||
String fqn = psiClass.getQualifiedName();
|
||||
if (psiClass.isInterface()) {
|
||||
superInterfaces.add(fqn);
|
||||
}
|
||||
else {
|
||||
if (superClassName == null) {
|
||||
superClassName = fqn.replace('.', '/');
|
||||
|
||||
while (psiClass != null) {
|
||||
for (PsiClass ifs : psiClass.getInterfaces()) {
|
||||
superInterfaces.add(ifs.getQualifiedName().replace('.', '/'));
|
||||
}
|
||||
psiClass = psiClass.getSuperClass();
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException("Cannot determine single class to inherit from");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
superInterfaces.add(CodeGenUtil.getInternalInterfaceName(superClassDescriptor));
|
||||
}
|
||||
}
|
||||
return superInterfaces;
|
||||
}
|
||||
|
||||
private void generateClassBody(JetClass aClass, ClassVisitor v) {
|
||||
final PropertyCodegen propertyCodegen = new PropertyCodegen(v);
|
||||
final FunctionCodegen functionCodegen = new FunctionCodegen(v, JetStandardLibrary.getJetStandardLibrary(project), bindingContext);
|
||||
|
||||
for (JetDeclaration declaration : aClass.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
propertyCodegen.genInInterface((JetProperty) declaration);
|
||||
propertyCodegen.gen((JetProperty) declaration, OwnerKind.INTERFACE);
|
||||
}
|
||||
else if (declaration instanceof JetFunction) {
|
||||
functionCodegen.genInInterface((JetFunction) declaration);
|
||||
functionCodegen.gen((JetFunction) declaration, OwnerKind.INTERFACE);
|
||||
}
|
||||
}
|
||||
|
||||
v.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class Codegens {
|
||||
}
|
||||
|
||||
public ClassVisitor forClassInterface(ClassDescriptor aClass) {
|
||||
return newVisitor(CodeGenUtil.getInternalInterfaceName(aClass));
|
||||
return newVisitor(CodeGenUtil.getInternalInterfaceName(aClass) + ".class");
|
||||
}
|
||||
|
||||
public ClassCodegen forClass(BindingContext bindingContext) {
|
||||
@@ -53,11 +53,11 @@ public class Codegens {
|
||||
}
|
||||
|
||||
public ClassVisitor forClassImplementation(ClassDescriptor aClass) {
|
||||
return newVisitor(CodeGenUtil.getInternalImplementationName(aClass));
|
||||
return newVisitor(CodeGenUtil.getInternalImplementationName(aClass) + ".class");
|
||||
}
|
||||
|
||||
public ClassVisitor forClassDelegatingImplementation(ClassDescriptor aClass) {
|
||||
return newVisitor(CodeGenUtil.getInternalDelegatingImplementationName(aClass));
|
||||
return newVisitor(CodeGenUtil.getInternalDelegatingImplementationName(aClass) + ".class");
|
||||
}
|
||||
|
||||
public NamespaceCodegen forNamespace(JetNamespace namespace) {
|
||||
@@ -65,7 +65,7 @@ public class Codegens {
|
||||
String fqName = namespace.getFQName();
|
||||
NamespaceCodegen codegen = ns2codegen.get(fqName);
|
||||
if (codegen == null) {
|
||||
codegen = new NamespaceCodegen(project, newVisitor(NamespaceCodegen.getJVMClassName(fqName) + ".class"), fqName);
|
||||
codegen = new NamespaceCodegen(project, newVisitor(NamespaceCodegen.getJVMClassName(fqName) + ".class"), fqName, this);
|
||||
ns2codegen.put(fqName, codegen);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public class FunctionCodegen {
|
||||
|
||||
}
|
||||
|
||||
private void gen(JetFunction f, OwnerKind kind) {
|
||||
public void gen(JetFunction f, OwnerKind kind) {
|
||||
int flags = Opcodes.ACC_PUBLIC; // TODO.
|
||||
|
||||
boolean isStatic = kind == OwnerKind.NAMESPACE;
|
||||
|
||||
@@ -2,10 +2,7 @@ package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.jet.lang.ErrorHandler;
|
||||
import org.jetbrains.jet.lang.psi.JetDeclaration;
|
||||
import org.jetbrains.jet.lang.psi.JetFunction;
|
||||
import org.jetbrains.jet.lang.psi.JetNamespace;
|
||||
import org.jetbrains.jet.lang.psi.JetProperty;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||
@@ -18,10 +15,12 @@ import org.objectweb.asm.Opcodes;
|
||||
public class NamespaceCodegen {
|
||||
private final Project project;
|
||||
private final ClassVisitor v;
|
||||
private final Codegens codegens;
|
||||
|
||||
public NamespaceCodegen(Project project, ClassVisitor v, String fqName) {
|
||||
public NamespaceCodegen(Project project, ClassVisitor v, String fqName, Codegens codegens) {
|
||||
this.project = project;
|
||||
this.v = v;
|
||||
this.codegens = codegens;
|
||||
|
||||
v.visit(Opcodes.V1_6,
|
||||
Opcodes.ACC_PUBLIC,
|
||||
@@ -38,6 +37,7 @@ public class NamespaceCodegen {
|
||||
|
||||
final PropertyCodegen propertyCodegen = new PropertyCodegen(v);
|
||||
final FunctionCodegen functionCodegen = new FunctionCodegen(v, JetStandardLibrary.getJetStandardLibrary(project), bindingContext);
|
||||
final ClassCodegen classCodegen = codegens.forClass(bindingContext);
|
||||
|
||||
for (JetDeclaration declaration : namespace.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
@@ -46,6 +46,9 @@ public class NamespaceCodegen {
|
||||
else if (declaration instanceof JetFunction) {
|
||||
functionCodegen.genInNamespace((JetFunction) declaration);
|
||||
}
|
||||
else if (declaration instanceof JetClass) {
|
||||
classCodegen.generate((JetClass) declaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
class Foo : java.util.ArrayList
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
@@ -8,8 +9,25 @@ import java.lang.reflect.Method;
|
||||
public class ClassGenTest extends CodegenTestCase {
|
||||
public void testPSVMClass() throws Exception {
|
||||
loadFile("simpleClass.jet");
|
||||
final Class aClass = generateClass();
|
||||
System.out.println(generateToText());
|
||||
|
||||
final Class aClass = loadClass("SimpleClass", generateClassesInFile());
|
||||
final Method[] methods = aClass.getDeclaredMethods();
|
||||
assertEquals(1, methods.length);
|
||||
}
|
||||
|
||||
public void testArrayListInheritance() throws Exception {
|
||||
loadFile("inheritingFromArrayList.jet");
|
||||
System.out.println(generateToText());
|
||||
|
||||
final Class aClass = loadClass("Foo", generateClassesInFile());
|
||||
checkInterface(aClass, List.class);
|
||||
}
|
||||
|
||||
private void checkInterface(Class aClass, Class ifs) {
|
||||
for (Class anInterface : aClass.getInterfaces()) {
|
||||
if (anInterface == ifs) return;
|
||||
}
|
||||
fail(aClass.getName() + " must have " + ifs.getName() + " in its interfaces");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,52 +33,47 @@ public abstract class CodegenTestCase extends LightCodeInsightFixtureTestCase {
|
||||
NamespaceCodegen codegen = state.forNamespace(namespace);
|
||||
codegen.generate(namespace);
|
||||
|
||||
List<String> files = state.files();
|
||||
assertEquals("This test only supposed to generate single class file", 1, files.size());
|
||||
StringBuilder answer = new StringBuilder();
|
||||
|
||||
return state.asText(files.get(0));
|
||||
List<String> files = state.files();
|
||||
for (String file : files) {
|
||||
answer.append("@").append(file).append('\n');
|
||||
answer.append(state.asText(file));
|
||||
}
|
||||
|
||||
return answer.toString();
|
||||
}
|
||||
|
||||
private Class generateNamespaceClass() {
|
||||
JetFile jetFile = (JetFile) myFixture.getFile();
|
||||
final JetNamespace namespace = jetFile.getRootNamespace();
|
||||
String fqName = NamespaceCodegen.getJVMClassName(namespace.getFQName());
|
||||
Codegens state = generateClassesInFile();
|
||||
return loadClass(fqName, state);
|
||||
}
|
||||
|
||||
protected Class loadClass(String fqName, Codegens state) {
|
||||
List<String> files = state.files();
|
||||
for (String file : files) {
|
||||
if (file.equals(fqName.replace('.', '/') + ".class")) {
|
||||
final byte[] data = state.asBytes(file);
|
||||
MyClassLoader classLoader = new MyClassLoader(NamespaceGenTest.class.getClassLoader());
|
||||
return classLoader.doDefineClass(fqName, data);
|
||||
}
|
||||
}
|
||||
|
||||
fail("No classfile was generated for: " + fqName);
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Codegens generateClassesInFile() {
|
||||
Codegens state = new Codegens(getProject(), false);
|
||||
JetFile jetFile = (JetFile) myFixture.getFile();
|
||||
final JetNamespace namespace = jetFile.getRootNamespace();
|
||||
|
||||
NamespaceCodegen codegen = state.forNamespace(namespace);
|
||||
codegen.generate(namespace);
|
||||
|
||||
return getJVMClass(state, NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", "."));
|
||||
}
|
||||
|
||||
protected Class generateClass() {
|
||||
final Codegens state = new Codegens(getProject(), false);
|
||||
JetFile jetFile = (JetFile) myFixture.getFile();
|
||||
final Ref<Class> result = new Ref<Class>();
|
||||
final ClassCodegen codegen = state.forClass(AnalyzingUtils.analyzeFile(jetFile, ErrorHandler.THROW_EXCEPTION));
|
||||
jetFile.acceptChildren(new JetVisitor() {
|
||||
@Override
|
||||
public void visitJetElement(JetElement elem) {
|
||||
elem.acceptChildren(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(JetClass klass) {
|
||||
codegen.generate(klass);
|
||||
result.set(getJVMClass(state, klass.getName() + "$$Impl"));
|
||||
}
|
||||
});
|
||||
if (result.isNull()) {
|
||||
throw new IllegalArgumentException("found no classes in the file to generate");
|
||||
}
|
||||
return result.get();
|
||||
}
|
||||
|
||||
private static Class getJVMClass(Codegens state, final String fqName) {
|
||||
List<String> files = state.files();
|
||||
assertEquals("This test only supposed to generate single class file", 1, files.size());
|
||||
final byte[] data = state.asBytes(files.get(0));
|
||||
MyClassLoader classLoader = new MyClassLoader(NamespaceGenTest.class.getClassLoader());
|
||||
return classLoader.doDefineClass(fqName, data);
|
||||
return state;
|
||||
}
|
||||
|
||||
protected Method generateFunction() {
|
||||
|
||||
Reference in New Issue
Block a user