do not generate namespace class for empty namespace
This commit is contained in:
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2012 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.codegen;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Stepan Koltsov
|
||||||
|
*/
|
||||||
|
public abstract class ClassBuilderOnDemand {
|
||||||
|
|
||||||
|
private ClassBuilder classBuilder;
|
||||||
|
|
||||||
|
private List<ClassBuilderCallback> optionalDeclarations = Lists.newArrayList();
|
||||||
|
|
||||||
|
interface ClassBuilderCallback {
|
||||||
|
void doSomething(@NotNull ClassBuilder classBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
protected abstract ClassBuilder createClassBuilder();
|
||||||
|
|
||||||
|
public void addOptionalDeclaration(@NotNull ClassBuilderCallback callback) {
|
||||||
|
optionalDeclarations.add(callback);
|
||||||
|
if (classBuilder != null) {
|
||||||
|
callback.doSomething(classBuilder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public ClassBuilder getClassBuilder() {
|
||||||
|
if (classBuilder == null) {
|
||||||
|
classBuilder = createClassBuilder();
|
||||||
|
for (ClassBuilderCallback callback : optionalDeclarations) {
|
||||||
|
callback.doSomething(classBuilder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return classBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void done() {
|
||||||
|
if (classBuilder != null) {
|
||||||
|
classBuilder.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,12 +61,18 @@ public class ClassFileFactory {
|
|||||||
return newVisitor(className.getInternalName() + ".class");
|
return newVisitor(className.getInternalName() + ".class");
|
||||||
}
|
}
|
||||||
|
|
||||||
NamespaceCodegen forNamespace(FqName fqName, Collection<JetFile> files) {
|
NamespaceCodegen forNamespace(final FqName fqName, Collection<JetFile> files) {
|
||||||
assert !isDone : "Already done!";
|
assert !isDone : "Already done!";
|
||||||
NamespaceCodegen codegen = ns2codegen.get(fqName);
|
NamespaceCodegen codegen = ns2codegen.get(fqName);
|
||||||
if (codegen == null) {
|
if (codegen == null) {
|
||||||
final ClassBuilder builder = newVisitor(NamespaceCodegen.getJVMClassNameForKotlinNs(fqName).getInternalName() + ".class");
|
ClassBuilderOnDemand onDemand = new ClassBuilderOnDemand() {
|
||||||
codegen = new NamespaceCodegen(builder, fqName, state, files);
|
@NotNull
|
||||||
|
@Override
|
||||||
|
protected ClassBuilder createClassBuilder() {
|
||||||
|
return newVisitor(NamespaceCodegen.getJVMClassNameForKotlinNs(fqName).getInternalName() + ".class");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
codegen = new NamespaceCodegen(onDemand, fqName, state, files);
|
||||||
ns2codegen.put(fqName, codegen);
|
ns2codegen.put(fqName, codegen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,29 +44,37 @@ import static org.objectweb.asm.Opcodes.*;
|
|||||||
* @author max
|
* @author max
|
||||||
*/
|
*/
|
||||||
public class NamespaceCodegen {
|
public class NamespaceCodegen {
|
||||||
private final ClassBuilder v;
|
@NotNull
|
||||||
|
private final ClassBuilderOnDemand v;
|
||||||
@NotNull private final FqName name;
|
@NotNull private final FqName name;
|
||||||
private final GenerationState state;
|
private final GenerationState state;
|
||||||
private final Collection<JetFile> files;
|
private final Collection<JetFile> files;
|
||||||
private int nextMultiFile = 0;
|
private int nextMultiFile = 0;
|
||||||
|
|
||||||
public NamespaceCodegen(ClassBuilder v, @NotNull FqName fqName, GenerationState state, Collection<JetFile> files) {
|
public NamespaceCodegen(@NotNull ClassBuilderOnDemand v, @NotNull final FqName fqName, GenerationState state, Collection<JetFile> files) {
|
||||||
this.v = v;
|
this.v = v;
|
||||||
name = fqName;
|
name = fqName;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.files = files;
|
this.files = files;
|
||||||
|
|
||||||
PsiFile sourceFile = files.iterator().next().getContainingFile();
|
final PsiFile sourceFile = files.iterator().next().getContainingFile();
|
||||||
v.defineClass(sourceFile, V1_6,
|
|
||||||
ACC_PUBLIC/*|ACC_SUPER*/,
|
v.addOptionalDeclaration(new ClassBuilderOnDemand.ClassBuilderCallback() {
|
||||||
getJVMClassNameForKotlinNs(fqName).getInternalName(),
|
@Override
|
||||||
null,
|
public void doSomething(@NotNull ClassBuilder v) {
|
||||||
//"jet/lang/Namespace",
|
v.defineClass(sourceFile, V1_6,
|
||||||
"java/lang/Object",
|
ACC_PUBLIC/*|ACC_SUPER*/,
|
||||||
new String[0]
|
getJVMClassNameForKotlinNs(fqName).getInternalName(),
|
||||||
);
|
null,
|
||||||
// TODO figure something out for a namespace that spans multiple files
|
//"jet/lang/Namespace",
|
||||||
v.visitSource(sourceFile.getName(), null);
|
"java/lang/Object",
|
||||||
|
new String[0]
|
||||||
|
);
|
||||||
|
// TODO figure something out for a namespace that spans multiple files
|
||||||
|
v.visitSource(sourceFile.getName(), null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generate(CompilationErrorHandler errorHandler, Progress progress) {
|
public void generate(CompilationErrorHandler errorHandler, Progress progress) {
|
||||||
@@ -115,14 +123,14 @@ public class NamespaceCodegen {
|
|||||||
NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file);
|
NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file);
|
||||||
final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor);
|
final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor);
|
||||||
state.getInjector().getMemberCodegen().generateFunctionOrProperty(
|
state.getInjector().getMemberCodegen().generateFunctionOrProperty(
|
||||||
(JetTypeParameterListOwner) declaration, context, v);
|
(JetTypeParameterListOwner) declaration, context, v.getClassBuilder());
|
||||||
}
|
}
|
||||||
else if (declaration instanceof JetNamedFunction) {
|
else if (declaration instanceof JetNamedFunction) {
|
||||||
if(!multiFile) {
|
if(!multiFile) {
|
||||||
NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file);
|
NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file);
|
||||||
final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor);
|
final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor);
|
||||||
state.getInjector().getMemberCodegen().generateFunctionOrProperty(
|
state.getInjector().getMemberCodegen().generateFunctionOrProperty(
|
||||||
(JetTypeParameterListOwner) declaration, context, v);
|
(JetTypeParameterListOwner) declaration, context, v.getClassBuilder());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (declaration instanceof JetClassOrObject) {
|
else if (declaration instanceof JetClassOrObject) {
|
||||||
@@ -167,7 +175,7 @@ public class NamespaceCodegen {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
final CodegenContext context = CodegenContexts.STATIC.intoNamespacePart(className, descriptor);
|
final CodegenContext context = CodegenContexts.STATIC.intoNamespacePart(className, descriptor);
|
||||||
state.getInjector().getMemberCodegen().generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, v);
|
state.getInjector().getMemberCodegen().generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, v.getClassBuilder());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,39 +186,44 @@ public class NamespaceCodegen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void generateStaticInitializers() {
|
private void generateStaticInitializers() {
|
||||||
JetFile namespace = files.iterator().next(); // @todo: hack
|
final JetFile namespace = files.iterator().next(); // @todo: hack
|
||||||
|
|
||||||
MethodVisitor mv = v.newMethod(namespace, ACC_PUBLIC | ACC_STATIC, "<clinit>", "()V", null, null);
|
v.addOptionalDeclaration(new ClassBuilderOnDemand.ClassBuilderCallback() {
|
||||||
for (JetFile file : files) {
|
@Override
|
||||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
public void doSomething(@NotNull ClassBuilder v) {
|
||||||
mv.visitCode();
|
MethodVisitor mv = v.newMethod(namespace, ACC_PUBLIC | ACC_STATIC, "<clinit>", "()V", null, null);
|
||||||
|
for (JetFile file : files) {
|
||||||
|
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||||
|
mv.visitCode();
|
||||||
|
|
||||||
FrameMap frameMap = new FrameMap();
|
FrameMap frameMap = new FrameMap();
|
||||||
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContexts.STATIC, state);
|
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContexts.STATIC, state);
|
||||||
|
|
||||||
for (JetDeclaration declaration : file.getDeclarations()) {
|
for (JetDeclaration declaration : file.getDeclarations()) {
|
||||||
if (declaration instanceof JetProperty) {
|
if (declaration instanceof JetProperty) {
|
||||||
final JetExpression initializer = ((JetProperty) declaration).getInitializer();
|
final JetExpression initializer = ((JetProperty) declaration).getInitializer();
|
||||||
if (initializer != null && !(initializer instanceof JetConstantExpression)) {
|
if (initializer != null && !(initializer instanceof JetConstantExpression)) {
|
||||||
final PropertyDescriptor descriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration);
|
final PropertyDescriptor descriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration);
|
||||||
assert descriptor != null;
|
assert descriptor != null;
|
||||||
if(descriptor.getReceiverParameter().exists()) {
|
if(descriptor.getReceiverParameter().exists()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
codegen.genToJVMStack(initializer);
|
||||||
|
StackValue.Property propValue = codegen.intermediateValueForProperty(descriptor, true, null);
|
||||||
|
propValue.store(propValue.type, new InstructionAdapter(mv));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
codegen.genToJVMStack(initializer);
|
|
||||||
StackValue.Property propValue = codegen.intermediateValueForProperty(descriptor, true, null);
|
|
||||||
propValue.store(propValue.type, new InstructionAdapter(mv));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||||
mv.visitInsn(RETURN);
|
mv.visitInsn(RETURN);
|
||||||
FunctionCodegen.endVisit(mv, "static initializer for namespace", namespace);
|
FunctionCodegen.endVisit(mv, "static initializer for namespace", namespace);
|
||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasNonConstantPropertyInitializers() {
|
private boolean hasNonConstantPropertyInitializers() {
|
||||||
|
|||||||
Reference in New Issue
Block a user