Add KotlinInfo annotation, serialize classes to bytecode
This commit is contained in:
@@ -12,6 +12,8 @@
|
||||
<orderEntry type="module" module-name="runtime" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="intellij-core" level="project" />
|
||||
<orderEntry type="library" name="javax.inject" level="project" />
|
||||
<orderEntry type="module" module-name="serialization" />
|
||||
<orderEntry type="library" name="protobuf-java" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
|
||||
import org.jetbrains.jet.descriptors.serialization.*;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
@@ -60,17 +61,20 @@ import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.jet.utils.ExceptionUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.asm4.Opcodes.*;
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.jet.codegen.CodegenUtil.*;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
|
||||
import static org.jetbrains.jet.descriptors.serialization.ClassSerializationUtil.constantSerializer;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isKindOf;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
|
||||
|
||||
@@ -209,9 +213,31 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor);
|
||||
|
||||
writeKotlinInfoIfNeeded();
|
||||
|
||||
writeClassSignatureIfNeeded(signature);
|
||||
}
|
||||
|
||||
private void writeKotlinInfoIfNeeded() {
|
||||
if (!(descriptor.getContainingDeclaration() instanceof ClassOrNamespaceDescriptor)) return;
|
||||
|
||||
final AnnotationVisitor av = v.getVisitor().visitAnnotation("Ljet/KotlinInfo;", true);
|
||||
DescriptorSerializer serializer = new DescriptorSerializer(DescriptorNamer.DEFAULT);
|
||||
|
||||
ClassSerializationUtil.serializeClass(descriptor, constantSerializer(serializer), new ClassSerializationUtil.Sink() {
|
||||
@Override
|
||||
public void writeClass(@NotNull ClassDescriptor classDescriptor, @NotNull ProtoBuf.Class classProto) {
|
||||
av.visit("data", classProto.toByteArray());
|
||||
}
|
||||
});
|
||||
|
||||
ByteArrayOutputStream nameTable = new ByteArrayOutputStream();
|
||||
NameSerializationUtil.serializeNameTable(nameTable, serializer.getNameTable());
|
||||
av.visit("nameTable", nameTable.toByteArray());
|
||||
|
||||
av.visitEnd();
|
||||
}
|
||||
|
||||
private void writeEnclosingMethod() {
|
||||
//JVMS7: A class must have an EnclosingMethod attribute if and only if it is a local class or an anonymous class.
|
||||
DeclarationDescriptor parentDescriptor = descriptor.getContainingDeclaration();
|
||||
|
||||
+24
-10
@@ -17,25 +17,39 @@
|
||||
package org.jetbrains.jet.descriptors.serialization;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.utils.ExceptionUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class NameSerializationUtil {
|
||||
@NotNull
|
||||
public static NameResolver deserializeNameResolver(@NotNull InputStream in) throws IOException {
|
||||
ProtoBuf.SimpleNameTable simpleNames = ProtoBuf.SimpleNameTable.parseDelimitedFrom(in);
|
||||
ProtoBuf.QualifiedNameTable qualifiedNames = ProtoBuf.QualifiedNameTable.parseDelimitedFrom(in);
|
||||
return new NameResolver(simpleNames, qualifiedNames);
|
||||
private NameSerializationUtil() {
|
||||
}
|
||||
|
||||
public static void serializeNameTable(@NotNull OutputStream out, @NotNull NameTable nameTable) throws IOException {
|
||||
ProtoBuf.SimpleNameTable simpleNamesProto = toSimpleNameTable(nameTable);
|
||||
simpleNamesProto.writeDelimitedTo(out);
|
||||
@NotNull
|
||||
public static NameResolver deserializeNameResolver(@NotNull InputStream in) {
|
||||
try {
|
||||
ProtoBuf.SimpleNameTable simpleNames = ProtoBuf.SimpleNameTable.parseDelimitedFrom(in);
|
||||
ProtoBuf.QualifiedNameTable qualifiedNames = ProtoBuf.QualifiedNameTable.parseDelimitedFrom(in);
|
||||
return new NameResolver(simpleNames, qualifiedNames);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw ExceptionUtils.rethrow(e);
|
||||
}
|
||||
}
|
||||
|
||||
ProtoBuf.QualifiedNameTable qualifiedNameTable = toQualifiedNameTable(nameTable);
|
||||
qualifiedNameTable.writeDelimitedTo(out);
|
||||
public static void serializeNameTable(@NotNull OutputStream out, @NotNull NameTable nameTable) {
|
||||
try {
|
||||
ProtoBuf.SimpleNameTable simpleNamesProto = toSimpleNameTable(nameTable);
|
||||
simpleNamesProto.writeDelimitedTo(out);
|
||||
|
||||
ProtoBuf.QualifiedNameTable qualifiedNameTable = toQualifiedNameTable(nameTable);
|
||||
qualifiedNameTable.writeDelimitedTo(out);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw ExceptionUtils.rethrow(e);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+4
-1
@@ -84,10 +84,13 @@ public class NameTable {
|
||||
NamespaceDescriptor namespaceDescriptor = (NamespaceDescriptor) containingDeclaration;
|
||||
builder.setParentQualifiedName(getFqNameIndex(namespaceDescriptor));
|
||||
}
|
||||
else {
|
||||
else if (containingDeclaration instanceof ClassDescriptor) {
|
||||
ClassDescriptor outerClass = (ClassDescriptor) containingDeclaration;
|
||||
builder.setParentQualifiedName(getFqNameIndex(outerClass));
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("FQ names are only stored for top-level or inner classes: " + classDescriptor);
|
||||
}
|
||||
|
||||
return qualifiedNames.intern(builder);
|
||||
}
|
||||
|
||||
@@ -43,19 +43,27 @@ import org.jetbrains.jet.config.CompilerConfiguration;
|
||||
import org.jetbrains.jet.lang.ModuleConfiguration;
|
||||
import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
|
||||
import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.diagnostics.Severity;
|
||||
import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetPsiFactory;
|
||||
import org.jetbrains.jet.lang.psi.JetPsiUtil;
|
||||
import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.ImportPath;
|
||||
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaBridgeConfiguration;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaToKotlinClassMap;
|
||||
import org.jetbrains.jet.lang.resolve.lazy.LazyResolveTestUtil;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
|
||||
import org.jetbrains.jet.plugin.JetLanguage;
|
||||
import org.jetbrains.jet.test.InnerTestClasses;
|
||||
import org.jetbrains.jet.test.TestMetadata;
|
||||
@@ -614,4 +622,17 @@ public class JetTestUtils {
|
||||
descriptor.setModuleConfiguration(ModuleConfiguration.EMPTY);
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static NamespaceDescriptorImpl createTestNamespace(@NotNull String testPackageName) {
|
||||
ModuleDescriptorImpl module = new ModuleDescriptorImpl(Name.special("<test module>"), JavaBridgeConfiguration.ALL_JAVA_IMPORTS,
|
||||
JavaToKotlinClassMap.getInstance());
|
||||
NamespaceDescriptorImpl rootNamespace =
|
||||
new NamespaceDescriptorImpl(module, Collections.<AnnotationDescriptor>emptyList(), JetPsiUtil.ROOT_NAMESPACE_NAME);
|
||||
module.setRootNamespace(rootNamespace);
|
||||
NamespaceDescriptorImpl test =
|
||||
new NamespaceDescriptorImpl(rootNamespace, Collections.<AnnotationDescriptor>emptyList(), Name.identifier(testPackageName));
|
||||
test.initialize(new WritableScopeImpl(JetScope.EMPTY, test, RedeclarationHandler.DO_NOTHING, "members of test namespace"));
|
||||
return test;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-21
@@ -21,31 +21,28 @@ import com.google.common.collect.Maps;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.ConfigurationKind;
|
||||
import org.jetbrains.jet.JetTestUtils;
|
||||
import org.jetbrains.jet.TestJdkKind;
|
||||
import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
|
||||
import org.jetbrains.jet.descriptors.serialization.descriptors.AnnotationDeserializer;
|
||||
import org.jetbrains.jet.jvm.compiler.ExpectedLoadErrorsUtil;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.psi.JetPsiUtil;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaBridgeConfiguration;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaToKotlinClassMap;
|
||||
import org.jetbrains.jet.lang.resolve.lazy.KotlinTestWithEnvironment;
|
||||
import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||
import org.jetbrains.jet.renderer.DescriptorRendererBuilder;
|
||||
import org.jetbrains.jet.test.util.NamespaceComparator;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.jet.descriptors.serialization.ClassSerializationUtil.constantSerializer;
|
||||
|
||||
@@ -95,7 +92,8 @@ public class BuiltinsDeserializationTest extends KotlinTestWithEnvironment {
|
||||
|
||||
List<ProtoBuf.Callable> callableProtos = serializeCallables(serializer, allDescriptors);
|
||||
|
||||
final NamespaceDescriptorImpl actualNamespace = createTestNamespace(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME.shortName().asString());
|
||||
final NamespaceDescriptorImpl actualNamespace = JetTestUtils
|
||||
.createTestNamespace(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME.shortName().asString());
|
||||
|
||||
final NameResolver nameResolver = NameSerializationUtil.createNameResolver(serializer.getNameTable());
|
||||
|
||||
@@ -215,16 +213,4 @@ public class BuiltinsDeserializationTest extends KotlinTestWithEnvironment {
|
||||
private static ClassId getClassId(ClassDescriptor classDescriptor) {
|
||||
return ClassSerializationUtil.getClassId(classDescriptor, NAMER);
|
||||
}
|
||||
|
||||
private static NamespaceDescriptorImpl createTestNamespace(String testPackageName) {
|
||||
ModuleDescriptorImpl module = new ModuleDescriptorImpl(Name.special("<test module>"), JavaBridgeConfiguration.ALL_JAVA_IMPORTS,
|
||||
JavaToKotlinClassMap.getInstance());
|
||||
NamespaceDescriptorImpl rootNamespace =
|
||||
new NamespaceDescriptorImpl(module, Collections.<AnnotationDescriptor>emptyList(), JetPsiUtil.ROOT_NAMESPACE_NAME);
|
||||
module.setRootNamespace(rootNamespace);
|
||||
NamespaceDescriptorImpl test =
|
||||
new NamespaceDescriptorImpl(rootNamespace, Collections.<AnnotationDescriptor>emptyList(), Name.identifier(testPackageName));
|
||||
test.initialize(new WritableScopeImpl(JetScope.EMPTY, test, RedeclarationHandler.DO_NOTHING, "members of test namespace"));
|
||||
return test;
|
||||
}
|
||||
}
|
||||
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.descriptors.serialization;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import jet.KotlinInfo;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.ConfigurationKind;
|
||||
import org.jetbrains.jet.JetTestUtils;
|
||||
import org.jetbrains.jet.codegen.CodegenTestCase;
|
||||
import org.jetbrains.jet.descriptors.serialization.descriptors.AnnotationDeserializer;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
public class WriteSerializedInfoTest extends CodegenTestCase {
|
||||
public static final FqName NAMESPACE_NAME = new FqName("test");
|
||||
public static final FqNameUnsafe CLASS_NAME = new FqNameUnsafe("A");
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL);
|
||||
}
|
||||
|
||||
public void testKotlinInfo() throws Exception {
|
||||
loadText("package " + NAMESPACE_NAME + "\n" +
|
||||
"\n" +
|
||||
"class " + CLASS_NAME + " {\n" +
|
||||
" fun foo() {}\n" +
|
||||
" fun bar() = 42\n" +
|
||||
"}\n");
|
||||
Class aClass = generateClass(NAMESPACE_NAME + "." + CLASS_NAME);
|
||||
|
||||
assertTrue(aClass.isAnnotationPresent(KotlinInfo.class));
|
||||
KotlinInfo kotlinInfo = (KotlinInfo) aClass.getAnnotation(KotlinInfo.class);
|
||||
|
||||
AbstractClassResolver classResolver = new KotlinInfoBasedClassResolver(kotlinInfo);
|
||||
|
||||
ClassDescriptor descriptor = classResolver.findClass(new ClassId(NAMESPACE_NAME, CLASS_NAME));
|
||||
assertNotNull(descriptor);
|
||||
assertEquals(CLASS_NAME.asString(), descriptor.getName().asString());
|
||||
}
|
||||
|
||||
private static class KotlinInfoBasedClassResolver extends AbstractClassResolver {
|
||||
private final NameResolver nameResolver;
|
||||
private final ProtoBuf.Class classProto;
|
||||
private final NamespaceDescriptorImpl namespace;
|
||||
|
||||
public KotlinInfoBasedClassResolver(@NotNull KotlinInfo kotlinInfo) throws InvalidProtocolBufferException {
|
||||
super(new LockBasedStorageManager(), AnnotationDeserializer.UNSUPPORTED);
|
||||
|
||||
this.nameResolver = NameSerializationUtil.deserializeNameResolver(new ByteArrayInputStream(kotlinInfo.nameTable()));
|
||||
this.classProto = ProtoBuf.Class.parseFrom(kotlinInfo.data());
|
||||
this.namespace = JetTestUtils.createTestNamespace(NAMESPACE_NAME.asString());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected ClassData getClassData(@NotNull ClassId classId) {
|
||||
assert classId.getPackageFqName().equals(NAMESPACE_NAME) &&
|
||||
classId.getRelativeClassName().equals(CLASS_NAME) : "Unsupported classId: " + classId;
|
||||
return new ClassData(nameResolver, classProto);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected DeclarationDescriptor getPackage(@NotNull FqName fqName) {
|
||||
assert fqName.equals(NAMESPACE_NAME) : "Unsupported namespace: " + fqName;
|
||||
return namespace;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected ClassId getClassId(@NotNull ClassDescriptor classDescriptor) {
|
||||
return ClassSerializationUtil.getClassId(classDescriptor, DescriptorNamer.DEFAULT);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Name getClassObjectName(@NotNull ClassDescriptor outerClass) {
|
||||
return Name.special("<class object>");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void classDescriptorCreated(@NotNull ClassDescriptor classDescriptor) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jet;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface KotlinInfo {
|
||||
byte[] data();
|
||||
|
||||
byte[] nameTable();
|
||||
}
|
||||
Reference in New Issue
Block a user