diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AbstractClassBuilder.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AbstractClassBuilder.java index 6c9edc05b76..a4535dbb94c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AbstractClassBuilder.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AbstractClassBuilder.java @@ -19,9 +19,14 @@ package org.jetbrains.kotlin.codegen; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.codegen.inline.FileMapping; +import org.jetbrains.kotlin.codegen.inline.SMAPBuilder; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; import org.jetbrains.org.objectweb.asm.*; +import java.util.ArrayList; +import java.util.List; + public abstract class AbstractClassBuilder implements ClassBuilder { protected static final MethodVisitor EMPTY_METHOD_VISITOR = new MethodVisitor(Opcodes.ASM5) {}; protected static final FieldVisitor EMPTY_FIELD_VISITOR = new FieldVisitor(Opcodes.ASM5) {}; @@ -30,6 +35,12 @@ public abstract class AbstractClassBuilder implements ClassBuilder { private final JvmSerializationBindings serializationBindings = new JvmSerializationBindings(); + private final List fileMappings = new ArrayList(); + + private String sourceName; + + private String debugInfo; + public static class Concrete extends AbstractClassBuilder { private final ClassVisitor v; @@ -92,6 +103,15 @@ public abstract class AbstractClassBuilder implements ClassBuilder { @Override public void done() { + if (!fileMappings.isEmpty()) { + FileMapping origin = fileMappings.get(0); + assert sourceName == null || origin.getName().equals(sourceName) : "Error " + origin.getName() + " != " + sourceName; + getVisitor().visitSource(origin.getName(), new SMAPBuilder(origin.getName(), origin.getPath(), fileMappings).build()); + } + else { + getVisitor().visitSource(sourceName, debugInfo); + } + getVisitor().visitEnd(); } @@ -111,7 +131,8 @@ public abstract class AbstractClassBuilder implements ClassBuilder { @Override public void visitSource(@NotNull String name, @Nullable String debug) { - getVisitor().visitSource(name, debug); + sourceName = name; + debugInfo = debug; } @Override @@ -130,4 +151,9 @@ public abstract class AbstractClassBuilder implements ClassBuilder { assert thisName != null : "This name isn't set"; return thisName; } + + @Override + public void addSMAP(FileMapping mapping) { + fileMappings.add(mapping); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilder.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilder.java index 23fe2c4b93a..f87f7205af3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilder.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilder.java @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.codegen.inline.FileMapping; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; import org.jetbrains.org.objectweb.asm.AnnotationVisitor; import org.jetbrains.org.objectweb.asm.ClassVisitor; @@ -75,4 +76,6 @@ public interface ClassBuilder { @NotNull String getThisName(); + + void addSMAP(FileMapping mapping); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index 83bcb97c50f..d29524d98c5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -25,6 +25,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.codegen.binding.CalculatedClosure; import org.jetbrains.kotlin.codegen.context.ClosureContext; +import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil; import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; @@ -141,6 +142,9 @@ public class ClosureCodegen extends MemberCodegen { superClassAsmType.getInternalName(), superInterfaceAsmTypes ); + + InlineCodegenUtil.initDefaultSourceMappingIfNeeded(context, this, state); + v.visitSource(element.getContainingFile().getName(), null); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/DelegatingClassBuilder.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/DelegatingClassBuilder.java index 5af4e4b6030..b76185d77fb 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/DelegatingClassBuilder.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/DelegatingClassBuilder.java @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.codegen.inline.FileMapping; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; import org.jetbrains.org.objectweb.asm.AnnotationVisitor; import org.jetbrains.org.objectweb.asm.ClassVisitor; @@ -111,4 +112,9 @@ public abstract class DelegatingClassBuilder implements ClassBuilder { public String getThisName() { return getDelegate().getThisName(); } + + @Override + public void addSMAP(FileMapping mapping) { + getDelegate().addSMAP(mapping); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 659d296cc4e..ec37278e989 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.codegen.binding.MutableClosure; import org.jetbrains.kotlin.codegen.context.*; import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; +import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil; import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; @@ -209,6 +210,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ); v.visitSource(myClass.getContainingFile().getName(), null); + InlineCodegenUtil.initDefaultSourceMappingIfNeeded(context, this, state); + writeEnclosingMethod(); AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor, null); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java index 6f1c5213baf..03001de7389 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java @@ -20,7 +20,6 @@ import com.intellij.openapi.progress.ProcessCanceledException; import kotlin.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.backend.common.CodegenUtil; import org.jetbrains.kotlin.codegen.context.*; import org.jetbrains.kotlin.codegen.inline.*; import org.jetbrains.kotlin.codegen.state.GenerationState; @@ -100,8 +99,8 @@ public abstract class MemberCodegen wrapped) { - this(wrapped.state, wrapped.getParentCodegen(), wrapped.getContext(), wrapped.element, wrapped.v); + protected MemberCodegen(@NotNull MemberCodegen wrapped, T declaration, FieldOwnerContext codegenContext) { + this(wrapped.state, wrapped.getParentCodegen(), codegenContext, declaration, wrapped.v); } public void generate() { @@ -136,14 +135,10 @@ public abstract class MemberCodegen mapping = sourceMapper.getFileMapping(); - for (RawFileMapping fileMapping : mapping) { - v.addSMAP(fileMapping.toFileMapping()); - } + SourceMapper.Default.flushToClassBuilder(sourceMapper, v); } v.done(); @@ -207,8 +202,7 @@ public abstract class MemberCodegen additionalFakeParams = @@ -159,6 +188,8 @@ public class AnonymousObjectTransformer { result.addAllClassesToRemove(constructorResult); + SourceMapper.Default.flushToClassBuilder(sourceMapper, classBuilder); + classBuilder.done(); anonymousObjectGen.setNewLambdaType(newLambdaType); @@ -183,7 +214,7 @@ public class AnonymousObjectTransformer { MethodInliner inliner = new MethodInliner(sourceNode, parameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")), remapper, isSameModule, "Transformer for " + anonymousObjectGen.getOwnerInternalName(), - null); + sourceMapper); InlineResult result = inliner.doInline(resultVisitor, new LocalVarRemapper(parameters, 0), false, LabelOwner.NOT_APPLICABLE); result.getReifiedTypeParametersUsages().mergeAll(typeParametersToReify); @@ -272,7 +303,7 @@ public class AnonymousObjectTransformer { MethodInliner inliner = new MethodInliner(constructor, constructorParameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")), remapper, isSameModule, "Transformer for constructor of " + anonymousObjectGen.getOwnerInternalName(), - null); + sourceMapper); InlineResult result = inliner.doInline(capturedFieldInitializer, new LocalVarRemapper(constructorParameters, 0), false, LabelOwner.NOT_APPLICABLE); constructorVisitor.visitMaxs(-1, -1); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineAdapter.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineAdapter.java index 47104665e8a..8025030deaf 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineAdapter.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineAdapter.java @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.codegen.inline; +import org.jetbrains.annotations.NotNull; import org.jetbrains.org.objectweb.asm.Label; import org.jetbrains.org.objectweb.asm.MethodVisitor; import org.jetbrains.org.objectweb.asm.Opcodes; @@ -35,7 +36,7 @@ public class InlineAdapter extends InstructionAdapter { private int nextLocalIndexBeforeInline = -1; - public InlineAdapter(MethodVisitor mv, int localsSize, SourceMapper sourceMapper) { + public InlineAdapter(MethodVisitor mv, int localsSize, @NotNull SourceMapper sourceMapper) { super(InlineCodegenUtil.API, mv); nextLocalIndex = localsSize; this.sourceMapper = sourceMapper; @@ -86,13 +87,7 @@ public class InlineAdapter extends InstructionAdapter { @Override public void visitLineNumber(int line, Label start) { - if (!isLambdaInlining) { - if (sourceMapper != null) { - sourceMapper.visitLineNumber(mv, line, start); - } - } else { - super.visitLineNumber(line, start); - } + sourceMapper.visitLineNumber(mv, line, start); } @Override diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index 9cb857d6c4b..2db76113be3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -26,11 +26,13 @@ import org.jetbrains.kotlin.builtins.InlineStrategy; import org.jetbrains.kotlin.builtins.InlineUtil; import org.jetbrains.kotlin.codegen.*; import org.jetbrains.kotlin.codegen.context.CodegenContext; +import org.jetbrains.kotlin.codegen.context.FieldOwnerContext; import org.jetbrains.kotlin.codegen.context.MethodContext; import org.jetbrains.kotlin.codegen.context.PackageContext; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.load.kotlin.PackageClassUtils; import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.renderer.DescriptorRenderer; @@ -38,7 +40,6 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.jvm.AsmTypes; -import org.jetbrains.kotlin.resolve.jvm.JvmClassName; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; @@ -83,7 +84,7 @@ public class InlineCodegen extends CallGenerator { private LambdaInfo activeLambda; - private SourceMapper sourceMapper; + private final SourceMapper sourceMapper; public InlineCodegen( @NotNull ExpressionCodegen codegen, @@ -113,10 +114,10 @@ public class InlineCodegen extends CallGenerator { isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), state.getOutDirectory()); - Integer lineNumbers = CodegenUtil.getLineNumberForElement(callElement.getContainingFile(), true); - assert lineNumbers != null : "Couldn't extract line count in " + callElement.getContainingFile(); + Integer lastLineNumber = CodegenUtil.getLineNumberForElement(callElement.getContainingFile(), true); + assert lastLineNumber != null : "Couldn't extract line count in " + callElement.getContainingFile(); - sourceMapper = codegen.getParentCodegen().getSourceMapper(); + sourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper(); } @Override @@ -176,8 +177,14 @@ public class InlineCodegen extends CallGenerator { (DeserializedSimpleFunctionDescriptor) functionDescriptor); VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containerClassId, state); - nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(), asmMethod.getName(), asmMethod.getDescriptor(), - JvmClassName.byClassId(containerClassId).getInternalName()); + if (functionDescriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor) { + /*use facade class*/ + containerClassId = PackageClassUtils.getPackageClassId(containerClassId.getPackageFqName()); + } + nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(), + asmMethod.getName(), + asmMethod.getDescriptor(), + containerClassId); if (nodeAndSMAP == null) { throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor)); @@ -185,11 +192,11 @@ public class InlineCodegen extends CallGenerator { } else { PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor); - Type ownerType = typeMapper.mapOwner(functionDescriptor, false); - if (element == null) { + if (element == null || !(element instanceof JetNamedFunction)) { throw new RuntimeException("Couldn't find declaration for function " + descriptorName(functionDescriptor)); } + JetNamedFunction inliningFunction = (JetNamedFunction) element; MethodNode node = new MethodNode(InlineCodegenUtil.API, getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0), @@ -201,22 +208,24 @@ public class InlineCodegen extends CallGenerator { //for maxLocals calculation MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node); MethodContext methodContext = context.getParentContext().intoFunction(functionDescriptor); + SMAP smap; if (callDefault) { - FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen()); + Type ownerType = typeMapper.mapOwner(functionDescriptor, false/*use facade class*/); + FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction, + (FieldOwnerContext) methodContext.getParentContext(), + ownerType.getInternalName()); FunctionCodegen.generateDefaultImplBody( methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, - (JetNamedFunction) element, parentCodegen + inliningFunction, parentCodegen ); - - smap = new SMAP(parentCodegen.mappings); + smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings()); } else { - smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, (JetDeclarationWithBody) element, - jvmSignature); + smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false); } - PsiFile file = element.getContainingFile(); - nodeAndSMAP = new SMAPAndMethodNode(node, file.getName(), ownerType.getInternalName(), smap); + + nodeAndSMAP = new SMAPAndMethodNode(node, smap); maxCalcAdapter.visitMaxs(-1, -1); maxCalcAdapter.visitEnd(); } @@ -224,8 +233,6 @@ public class InlineCodegen extends CallGenerator { } private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) { - sourceMapper.visitSource(nodeAndSmap.getSource(), nodeAndSmap.getSourcePath()); - MethodNode node = nodeAndSmap.getNode(); ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node.instructions); generateClosuresBodies(); @@ -246,7 +253,8 @@ public class InlineCodegen extends CallGenerator { codegen.getParentCodegen().getClassName(), reifiedTypeInliner); MethodInliner inliner = new MethodInliner(node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule, - "Method inlining " + callElement.getText(), sourceMapper); //with captured + "Method inlining " + callElement.getText(), + createNestedSourceMapper(nodeAndSmap)); //with captured LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize); @@ -287,7 +295,7 @@ public class InlineCodegen extends CallGenerator { } } - private MethodNode generateLambdaBody(LambdaInfo info) { + private SMAPAndMethodNode generateLambdaBody(LambdaInfo info) { JetFunctionLiteral declaration = info.getFunctionLiteral(); FunctionDescriptor descriptor = info.getFunctionDescriptor(); @@ -301,10 +309,9 @@ public class InlineCodegen extends CallGenerator { MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode); - generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature); + SMAP smap = generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, true); adapter.visitMaxs(-1, -1); - - return methodNode; + return new SMAPAndMethodNode(methodNode, smap); } private SMAP generateMethodBody( @@ -312,28 +319,44 @@ public class InlineCodegen extends CallGenerator { @NotNull FunctionDescriptor descriptor, @NotNull MethodContext context, @NotNull JetDeclarationWithBody declaration, - @NotNull JvmMethodSignature jvmMethodSignature + @NotNull JvmMethodSignature jvmMethodSignature, + boolean isLambda ) { - FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen()); + FakeMemberCodegen parentCodegen = + new FakeMemberCodegen(codegen.getParentCodegen(), declaration, + (FieldOwnerContext) context.getParentContext(), + isLambda ? codegen.getParentCodegen().getClassName() : typeMapper.mapOwner(descriptor, false).getInternalName()); + FunctionCodegen.generateMethodBody( - adapter, descriptor, context, jvmMethodSignature, - new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration), - // Wrapping for preventing marking actual parent codegen as containing reifier markers - parentCodegen + adapter, descriptor, context, jvmMethodSignature, + new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration), + // Wrapping for preventing marking actual parent codegen as containing reifier markers + parentCodegen ); - return new SMAP(parentCodegen.mappings); + return createSMAPWithDefaultMapping(declaration, parentCodegen.getOrCreateSourceMapper().getResultMappings()); + } + + private static SMAP createSMAPWithDefaultMapping( + @NotNull JetDeclarationWithBody declaration, + @NotNull List mappings + ) { + PsiFile containingFile = declaration.getContainingFile(); + Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true); + assert lineNumbers != null : "Couldn't extract line count in " + containingFile; + + return new SMAP(mappings); } private static class FakeMemberCodegen extends MemberCodegen { private final MemberCodegen delegate; + @NotNull private final String className; - List mappings = new ArrayList(); - - public FakeMemberCodegen(@NotNull MemberCodegen wrapped) { - super(wrapped); + public FakeMemberCodegen(@NotNull MemberCodegen wrapped, @NotNull JetElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) { + super(wrapped, declaration, codegenContext); delegate = wrapped; + this.className = className; } @Override @@ -357,6 +380,11 @@ public class InlineCodegen extends CallGenerator { return delegate.getInlineNameGenerator(); } + @NotNull + @Override + public String getClassName() { + return className; + } } @Override @@ -627,4 +655,8 @@ public class InlineCodegen extends CallGenerator { } } + private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) { + return new NestedSourceMapper(sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo()); + } + } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java index 25ef6ac8cd6..88286cccff4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java @@ -24,8 +24,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import org.jetbrains.kotlin.backend.common.output.OutputFile; +import org.jetbrains.kotlin.codegen.MemberCodegen; import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.context.CodegenContext; +import org.jetbrains.kotlin.codegen.context.MethodContext; import org.jetbrains.kotlin.codegen.context.PackageContext; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; @@ -43,6 +45,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage; import org.jetbrains.kotlin.resolve.jvm.AsmTypes; +import org.jetbrains.kotlin.resolve.jvm.JvmClassName; import org.jetbrains.kotlin.serialization.ProtoBuf; import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor; import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf; @@ -83,11 +86,14 @@ public class InlineCodegenUtil { byte[] classData, final String methodName, final String methodDescriptor, - String containerInternalName + ClassId classId ) throws ClassNotFoundException, IOException { ClassReader cr = new ClassReader(classData); final MethodNode[] node = new MethodNode[1]; - final String [] debugInfo = new String[2]; + final String[] debugInfo = new String[2]; + final int[] lines = new int[2]; + lines[0] = Integer.MAX_VALUE; + lines[1] = Integer.MIN_VALUE; cr.accept(new ClassVisitor(API) { @Override @@ -98,22 +104,53 @@ public class InlineCodegenUtil { } @Override - public MethodVisitor visitMethod(int access, @NotNull String name, @NotNull String desc, String signature, String[] exceptions) { + public MethodVisitor visitMethod( + int access, + @NotNull String name, + @NotNull String desc, + String signature, + String[] exceptions + ) { if (methodName.equals(name) && methodDescriptor.equals(desc)) { - node[0] = new MethodNode(access, name, desc, signature, exceptions); + node[0] = new MethodNode(API, access, name, desc, signature, exceptions) { + + @Override + public void visitLineNumber(int line, Label start) { + super.visitLineNumber(line, start); + lines[0] = Math.min(lines[0], line); + lines[1] = Math.max(lines[1], line); + } + }; return node[0]; } return null; } }, ClassReader.SKIP_FRAMES); - return new SMAPAndMethodNode(node[0], debugInfo[0], containerInternalName, new SMAPParser(debugInfo[1], "TODO").parse()); + SMAP smap = new SMAPParser(debugInfo[1], debugInfo[0], classId.toString(), lines[0], lines[1]).parse(); + return new SMAPAndMethodNode(node[0], smap); } + public static void initDefaultSourceMappingIfNeeded(@NotNull CodegenContext context, @NotNull MemberCodegen codegen, @NotNull GenerationState state) { + if (state.isInlineEnabled()) { + CodegenContext parentContext = context.getParentContext(); + while (parentContext != null) { + if (parentContext instanceof MethodContext) { + if (((MethodContext) parentContext).isInlineFunction()) { + //just init default one to one mapping + codegen.getOrCreateSourceMapper(); + break; + } + } + parentContext = parentContext.getParentContext(); + } + } + } @NotNull public static VirtualFile getVirtualFileForCallable(@NotNull ClassId containerClassId, @NotNull GenerationState state) { - VirtualFile file = findVirtualFileWithHeader(state.getProject(), containerClassId); + VirtualFileFinder fileFinder = VirtualFileFinder.SERVICE.getInstance(state.getProject()); + VirtualFile file = fileFinder.findVirtualFileWithHeader(containerClassId.asSingleFqName().toSafe()); if (file == null) { throw new IllegalStateException("Couldn't find declaration file for " + containerClassId); } @@ -129,8 +166,7 @@ public class InlineCodegenUtil { throw new IllegalStateException("Function in namespace should have implClassName property in proto: " + deserializedDescriptor); } Name name = deserializedDescriptor.getNameResolver().getName(proto.getExtension(JvmProtoBuf.implClassName)); - ClassId packageClassId = PackageClassUtils.getPackageClassId(((PackageFragmentDescriptor) parentDeclaration).getFqName()); - containerClassId = new ClassId(packageClassId.getPackageFqName(), name); + containerClassId = new ClassId(((PackageFragmentDescriptor) parentDeclaration).getFqName(), name); } else { containerClassId = getContainerClassId(deserializedDescriptor); } @@ -140,12 +176,6 @@ public class InlineCodegenUtil { return containerClassId; } - @Nullable - public static VirtualFile findVirtualFileWithHeader(@NotNull Project project, @NotNull ClassId containerClassId) { - VirtualFileFinder fileFinder = VirtualFileFinder.SERVICE.getInstance(project); - return fileFinder.findVirtualFileWithHeader(containerClassId.asSingleFqName().toSafe()); - } - @Nullable public static VirtualFile findVirtualFile(@NotNull Project project, @NotNull String internalName) { VirtualFileFinder fileFinder = VirtualFileFinder.SERVICE.getInstance(project); @@ -163,8 +193,9 @@ public class InlineCodegenUtil { if (containerDescriptor instanceof ClassDescriptor) { ClassId classId = DescriptorUtilPackage.getClassId((ClassDescriptor) containerDescriptor); if (isTrait(containerDescriptor)) { - FqNameUnsafe shortName = classId.getRelativeClassName(); - classId = new ClassId(classId.getPackageFqName(), Name.identifier(shortName.shortName().toString() + JvmAbi.TRAIT_IMPL_SUFFIX)); + FqNameUnsafe relativeClassName = classId.getRelativeClassName(); + //TODO test nested trait fun inlining + classId = new ClassId(classId.getPackageFqName(), Name.identifier(relativeClassName.shortName().asString() + JvmAbi.TRAIT_IMPL_SUFFIX)); } return classId; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.java index 30eb936ed65..553c5901daf 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.java @@ -32,7 +32,6 @@ import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.jvm.AsmTypes; import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode; -import org.jetbrains.org.objectweb.asm.tree.MethodNode; import java.util.ArrayList; import java.util.Arrays; @@ -51,7 +50,7 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner { private final CalculatedClosure closure; - private MethodNode node; + private SMAPAndMethodNode node; private List capturedVars; @@ -76,11 +75,11 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner { assert closure != null : "Closure for lambda should be not null " + expression.getText(); } - public MethodNode getNode() { + public SMAPAndMethodNode getNode() { return node; } - public void setNode(MethodNode node) { + public void setNode(SMAPAndMethodNode node) { this.node = node; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java index d3d8470f34f..57e07fc69c9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java @@ -54,7 +54,7 @@ public class MethodInliner { private final String errorPrefix; - private SourceMapper sourceMapper; + private final SourceMapper sourceMapper; private final JetTypeMapper typeMapper; @@ -83,7 +83,7 @@ public class MethodInliner { @NotNull FieldRemapper nodeRemapper, boolean isSameModule, @NotNull String errorPrefix, - SourceMapper sourceMapper + @NotNull SourceMapper sourceMapper ) { this.node = node; this.parameters = parameters; @@ -132,6 +132,7 @@ public class MethodInliner { //flush transformed node to output resultNode.accept(new InliningInstructionAdapter(adapter)); + sourceMapper.endMapping(); return result; } @@ -216,11 +217,16 @@ public class MethodInliner { new InlinedLambdaRemapper(info.getLambdaClassType().getInternalName(), nodeRemapper, lambdaParameters); setLambdaInlining(true); - MethodInliner inliner = new MethodInliner(info.getNode(), lambdaParameters, + SMAP lambdaSMAP = info.getNode().getClassSMAP(); + SourceMapper mapper = + inliningContext.classRegeneration && !inliningContext.isInliningLambda ? + new NestedSourceMapper(sourceMapper, lambdaSMAP.getIntervals(), lambdaSMAP.getSourceInfo()) + : new InlineLambdaSourceMapper(sourceMapper.getParent(), info.getNode()); + MethodInliner inliner = new MethodInliner(info.getNode().getNode(), lambdaParameters, inliningContext.subInlineLambda(info), newCapturedRemapper, true /*cause all calls in same module as lambda*/, "Lambda inlining " + info.getLambdaClassType().getInternalName(), - IdenticalSourceMapper.INSTANCE$); + mapper); LocalVarRemapper remapper = new LocalVarRemapper(lambdaParameters, valueParamShift); InlineResult lambdaResult = inliner.doInline(this.mv, remapper, true, info);//TODO add skipped this and receiver @@ -233,6 +239,7 @@ public class MethodInliner { StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this); setLambdaInlining(false); addInlineMarker(this, false); + mapper.endMapping(); } else if (isAnonymousConstructorCall(owner, name)) { //TODO add method assert anonymousObjectGen != null : " call not corresponds to new call" + owner + " " + name; @@ -272,7 +279,6 @@ public class MethodInliner { }; - node.accept(lambdaInliner); return resultNode; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RemappingClassBuilder.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RemappingClassBuilder.java index 00a3bf71c4b..fc97cb4159e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RemappingClassBuilder.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RemappingClassBuilder.java @@ -81,4 +81,5 @@ public class RemappingClassBuilder extends DelegatingClassBuilder { public ClassVisitor getVisitor() { return new RemappingClassAdapter(builder.getVisitor(), remapper); } + } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAP.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAP.kt index 45839f60fd5..7a4a112c052 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAP.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAP.kt @@ -16,16 +16,20 @@ package org.jetbrains.kotlin.codegen.inline +import com.intellij.openapi.application.ApplicationManager import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.Label import java.util -import java.util.HashSet -import java.util.Arrays +import java.util.LinkedHashMap +import java.util.Collections +import java.util.ArrayList +import org.jetbrains.kotlin.codegen.SourceInfo +import org.jetbrains.kotlin.codegen.ClassBuilder +//TODO join parameter public class SMAPBuilder(val source: String, val path: String, - val fileMappings: List, - val lineCountInOriginalFile: Int) { + val fileMappings: List) { val header = "SMAP\n$source\nKotlin\n*S Kotlin" @@ -34,29 +38,13 @@ public class SMAPBuilder(val source: String, return null; } + val fileIds = "*F" + fileMappings.mapIndexed {(id, file) -> "\n${file.toSMAPFile(id + 1)}" }.join("") + val lineMappings = "*L" + fileMappings.map { it.toSMAPMapping() }.join("") - val defaultSourceMapping = RawFileMapping(source, path) - for(i in 1..lineCountInOriginalFile) { - defaultSourceMapping.mapLine(i, i - 1, true) - } - val allMappings = arrayListOf(defaultSourceMapping.toFileMapping()) - allMappings.addAll(fileMappings) - - var id = 1; - - val fileIds = "*F" + - allMappings.fold("") {(a, e) -> - a + "\n${e.toSMAPFile(id++)}" - } - - val fileMappings = "*L" + - allMappings.fold("") {(a, e) -> - a + "${e.toSMAPMapping()}" - } - - return header + "\n" + fileIds +"\n" + fileMappings + "\n*E\n" + return "$header\n$fileIds\n$lineMappings\n*E\n" } + fun RangeMapping.toSMAP(fileId: Int): String { return if (range == 1) "$source#$fileId:$dest" else "$source#$fileId,$range:$dest" } @@ -66,55 +54,193 @@ public class SMAPBuilder(val source: String, return "+ $id $name\n$path" } + //TODO inline fun FileMapping.toSMAPMapping(): String { - return lineMappings.fold("") { - (a, e) -> - "$a\n${e.toSMAP(id)}" + return lineMappings.map { + "\n${it.toSMAP(id)}" + }.join("") + } +} + +public open class NestedSourceMapper(parent: SourceMapper, val ranges: List, sourceInfo: SourceInfo) : DefaultSourceMapper(sourceInfo, parent) { + + override fun visitLineNumber(iv: MethodVisitor, lineNumber: Int, start: Label) { + val index = Collections.binarySearch(ranges, RangeMapping(lineNumber, lineNumber, 1)) { + (value, key) -> + if (value.contains(key.dest)) 0 else RangeMapping.Comparator.compare(value, key) + } + if (index < 0) { + parent!!.visitSource(sourceInfo.source, sourceInfo.pathOrCleanFQN) + parent!!.visitLineNumber(iv, lineNumber, start) + } + else { + val rangeMapping = ranges[index] + parent!!.visitSource(rangeMapping.parent!!.name, rangeMapping.parent!!.path) + parent!!.visitLineNumber(iv, rangeMapping.map(lineNumber), start) } } } -public object IdenticalSourceMapper: SourceMapper(-1) { +public open class InlineLambdaSourceMapper(parent: SourceMapper, smap: SMAPAndMethodNode) : NestedSourceMapper(parent, smap.ranges, smap.classSMAP.sourceInfo) { override fun visitSource(name: String, path: String) { - + super.visitSource(name, path) + if (isOriginalVisited()) { + parent!!.visitOrigin() + } } + override fun visitOrigin() { + super.visitOrigin() + parent!!.visitOrigin() + } + + private fun isOriginalVisited(): Boolean { + return lastVisited == origin + } + + override fun visitLineNumber(iv: MethodVisitor, lineNumber: Int, start: Label) { + val index = Collections.binarySearch(ranges, RangeMapping(lineNumber, lineNumber, 1)) { + (value, key) -> + if (value.contains(key.dest)) 0 else RangeMapping.Comparator.compare(value, key) + } + if (index >= 0) { + val fmapping = ranges[index].parent!! + if (fmapping.path == origin.path && fmapping.name == origin.name) { + parent!!.visitOrigin() + parent!!.visitLineNumber(iv, lineNumber, start) + return + } + } + super.visitLineNumber(iv, lineNumber, start) + } +} + +trait SourceMapper { + + val resultMappings: List + val parent: SourceMapper? + + open fun visitSource(name: String, path: String) { + throw UnsupportedOperationException("fail") + } + + open fun visitOrigin() { + throw UnsupportedOperationException("fail") + } + + open fun visitLineNumber(iv: MethodVisitor, lineNumber: Int, start: Label) { + throw UnsupportedOperationException("fail") + } + + open fun endMapping() { + parent?.visitOrigin() + } + + default object { + + fun flushToClassBuilder(mapper: SourceMapper, v: ClassBuilder) { + for (fileMapping in mapper.resultMappings) { + v.addSMAP(fileMapping) + } + } + + fun createFromSmap(smap: SMAP): DefaultSourceMapper { + val sourceMapper = DefaultSourceMapper(smap.sourceInfo, null) + smap.fileMappings.stream() + //default one mapped through sourceInfo + .filterNot { it == smap.default } + .forEach { fileMapping -> + sourceMapper.visitSource(fileMapping.name, fileMapping.path) + fileMapping.lineMappings.forEach { + sourceMapper.lastVisited!!.mapNewInterval(it.source, it.dest, it.range) + } + } + + return sourceMapper + } + } +} + +public object IdenticalSourceMapper : SourceMapper { + override val resultMappings: List + get() = emptyList() + + override val parent: SourceMapper? + get() = null + + override fun visitSource(name: String, path: String) {} + + override fun visitOrigin() {} + override fun visitLineNumber(iv: MethodVisitor, lineNumber: Int, start: Label) { iv.visitLineNumber(lineNumber, start) } } -public open class SourceMapper(val lineNumbers: Int) { +public open class DefaultSourceMapper(val sourceInfo: SourceInfo, override val parent: SourceMapper?): SourceMapper { - private var maxUsedValue = lineNumbers; + protected var maxUsedValue: Int = sourceInfo.linesInFile - private var lastMappedWithChanges: RawFileMapping? = null; + var lastVisited: RawFileMapping? = null - var fileMapping: MutableList = arrayListOf(); + private var lastMappedWithChanges: RawFileMapping? = null - open fun visitSource(name: String, path: String) { - fileMapping.add(RawFileMapping(name, path)) + var fileMappings: LinkedHashMap = linkedMapOf(); + + protected val origin: RawFileMapping + { + visitSource(sourceInfo.source, sourceInfo.pathOrCleanFQN) + origin = lastVisited!! + //map interval + (1..maxUsedValue).forEach {origin.mapLine(it, it - 1, true) } } - open fun visitLineNumber(iv: MethodVisitor, lineNumber: Int, start: Label) { - val fileMapping = fileMapping.last() - val mappedLineIndex = fileMapping.mapLine(lineNumber, maxUsedValue, true) + override val resultMappings: List + get() = fileMappings.values().map { it.toFileMapping() } + + override fun visitSource(name: String, path: String) { + lastVisited = fileMappings.getOrPut("$name#$path", { RawFileMapping(name, path) }) + } + + override fun visitOrigin() { + lastVisited = origin + } + + override fun visitLineNumber(iv: MethodVisitor, lineNumber: Int, start: Label) { + val mappedLineIndex = createMapping(lineNumber) iv.visitLineNumber(mappedLineIndex, start) + } + + protected fun createMapping(lineNumber: Int): Int { + val fileMapping = lastVisited!! + val mappedLineIndex = fileMapping.mapLine(lineNumber, maxUsedValue, lastMappedWithChanges == lastVisited) if (mappedLineIndex > maxUsedValue) { lastMappedWithChanges = fileMapping maxUsedValue = mappedLineIndex } + return mappedLineIndex + } +} + +/*Source Mapping*/ +class SMAP(val fileMappings: List) { + init { + assert(fileMappings.isNotEmpty(), "File Mappings shouldn't be empty") } -} -/*Source Mapping*/ -class SMAP(fileMappings: List) { - var fileMappings: List = fileMappings + val default: FileMapping + get() = fileMappings.first() - val intervals = fileMappings.flatMap { it -> it.lineMappings }.sortBy(RangeMapping.Comparator) + val intervals = fileMappings.flatMap { it.lineMappings }.sortBy(RangeMapping.Comparator) - class object { + val sourceInfo: SourceInfo + init { + val defaultMapping = default.lineMappings.single() + sourceInfo = SourceInfo(default.name, default.path, defaultMapping.source + defaultMapping.range - 1) + } + + default object { val FILE_SECTION = "*F" val LINE_SECTION = "*L" @@ -138,27 +264,38 @@ class RawFileMapping(val name: String, val path: String) { } fun mapLine(source: Int, currentIndex: Int, isLastMapped: Boolean): Int { - var dest = lineMappings.get(source); + var dest = lineMappings[source] if (dest == null) { val rangeMapping: RangeMapping if (rangeMappings.isNotEmpty() && isLastMapped && couldFoldInRange(lastMappedWithNewIndex, source)) { rangeMapping = rangeMappings.last() - rangeMapping.range += source - lastMappedWithNewIndex; - dest = lineMappings.get(lastMappedWithNewIndex) + source - lastMappedWithNewIndex; - } else { - dest = currentIndex + 1; + rangeMapping.range += source - lastMappedWithNewIndex + dest = lineMappings[lastMappedWithNewIndex] + source - lastMappedWithNewIndex + } + else { + dest = currentIndex + 1 rangeMapping = RangeMapping(source, dest) rangeMappings.add(rangeMapping) } lineMappings.put(source, dest) - lastMappedWithNewIndex = source; + lastMappedWithNewIndex = source } return dest } + fun mapNewInterval(source: Int, dest: Int, range: Int) { + val rangeMapping = RangeMapping(source, dest, range) + rangeMappings.add(rangeMapping) + + (source..(source + range - 1)).forEach { + lineMappings.put(source, dest) + } + } + private fun couldFoldInRange(first: Int, second: Int): Boolean { + //TODO val delta = second - first return delta > 0 && delta <= 10; } @@ -175,7 +312,8 @@ public class FileMapping(val name: String, val path: String) { } } -public class RangeMapping(val source: Int, val dest: Int, var range: Int = 1) { +//TODO comparable +data public class RangeMapping(val source: Int, val dest: Int, var range: Int = 1) { var parent: FileMapping? = null; @@ -184,7 +322,7 @@ public class RangeMapping(val source: Int, val dest: Int, var range: Int = 1) { } fun map(destLine: Int): Int { - return source + destLine - dest + return source + (destLine - dest) } object Comparator : util.Comparator { @@ -194,7 +332,8 @@ public class RangeMapping(val source: Int, val dest: Int, var range: Int = 1) { val res = o1.dest - o2.dest if (res == 0) { return o1.range - o2.range - } else { + } + else { return res } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAPAndMethodNode.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAPAndMethodNode.kt index b6d37845c53..a1da1bbb9c9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAPAndMethodNode.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAPAndMethodNode.kt @@ -22,23 +22,24 @@ import org.jetbrains.org.objectweb.asm.tree.LineNumberNode import org.jetbrains.org.objectweb.asm.Label import kotlin.properties.Delegates import java.util.Collections +import kotlin.properties.ReadOnlyProperty +import org.jetbrains.kotlin.codegen.SourceInfo -class SMAPAndMethodNode(val node: MethodNode, val source: String, val sourcePath: String, classSMAP: SMAP) { +//TODO comment +class SMAPAndMethodNode(val node: MethodNode, val classSMAP: SMAP) { - val lineNumbers = Delegates.lazy { - InsnStream(node.instructions.getFirst(), null).filterIsInstance(javaClass()).map { - val index = Collections.binarySearch(classSMAP.intervals, RangeMapping(it.line, it.line, 1), { - (value, key) -> if (value.contains(key.dest)) 0 else RangeMapping.Comparator.compare(value, key) - }) - if (index < 0) throw IllegalStateException("Unmapped lable in inlined function " + it) + val lineNumbers = + InsnStream(node.instructions.getFirst(), null).stream().filterIsInstance().map { + val index = Collections.binarySearch(classSMAP.intervals, RangeMapping(it.line, it.line, 1)) { + (value, key) -> + if (value.contains(key.dest)) 0 else RangeMapping.Comparator.compare(value, key) + } + if (index < 0) + throw IllegalStateException("Unmapped label in inlined function $it ${it.line}") LabelAndMapping(it, classSMAP.intervals[index]) - } - }; + }.toList() + val ranges = lineNumbers.stream().map { it.mapper }.toList().distinct().toList(); } -class LabelAndMapping(val lineNumberNode: LineNumberNode, val mapper: RangeMapping) { - val getOriginalLine = mapper.map(lineNumberNode.line) - val getOriginalFileName = mapper.parent!!.name - val getOriginalPath = mapper.parent!!.path -} \ No newline at end of file +class LabelAndMapping(val lineNumberNode: LineNumberNode, val mapper: RangeMapping) \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAPParser.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAPParser.kt index 133933aa033..ed3fd54b423 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAPParser.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAPParser.kt @@ -16,18 +16,23 @@ package org.jetbrains.kotlin.codegen.inline -class SMAPParser(val input: String?, val path: String) { +class SMAPParser(val mappingInfo: String?, val source: String, val path: String, val methodStartLine: Int, val methodEndLine: Int) { val fileMappings = linkedMapOf() fun parse() : SMAP { - if (input == null || input.isEmpty()) { - return SMAP(listOf()) + if (mappingInfo == null || mappingInfo.isEmpty()) { + val fm = FileMapping(source, path) + if (methodStartLine <= methodEndLine) { + //one to one + fm.addRangeMapping(RangeMapping(methodStartLine, methodStartLine, methodEndLine - methodStartLine + 1)) + } + return SMAP(listOf(fm)) } - val fileSectionStart = input.indexOf(SMAP.FILE_SECTION) + SMAP.FILE_SECTION.length() - val lineSectionAnchor = input.indexOf(SMAP.LINE_SECTION) - val files = input.substring(fileSectionStart, lineSectionAnchor) + val fileSectionStart = mappingInfo.indexOf(SMAP.FILE_SECTION) + SMAP.FILE_SECTION.length() + val lineSectionAnchor = mappingInfo.indexOf(SMAP.LINE_SECTION) + val files = mappingInfo.substring(fileSectionStart, lineSectionAnchor) val fileEntries = files.trim().split('+') @@ -44,7 +49,7 @@ class SMAPParser(val input: String?, val path: String) { } - val lines = input.substring(lineSectionAnchor + SMAP.LINE_SECTION.length(), input.indexOf(SMAP.END)).trim().split('\n') + val lines = mappingInfo.substring(lineSectionAnchor + SMAP.LINE_SECTION.length(), mappingInfo.indexOf(SMAP.END)).trim().split('\n') for (lineMapping in lines) { /*only simple mapping now*/ val targetSplit = lineMapping.indexOf(':') diff --git a/compiler/testData/lineNumber/simpleSmap.kt b/compiler/testData/lineNumber/simpleSmap.kt new file mode 100644 index 00000000000..a25bfa746f5 --- /dev/null +++ b/compiler/testData/lineNumber/simpleSmap.kt @@ -0,0 +1,9 @@ +inline fun inlineFun(s: () -> Unit) { + s() +} + +fun main(args: Array) { + inlineFun { + test.lineNumber() + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LineNumberTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LineNumberTestGenerated.java index c173421de77..a8971b0233c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LineNumberTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LineNumberTestGenerated.java @@ -114,6 +114,12 @@ public class LineNumberTestGenerated extends AbstractLineNumberTest { doTest(fileName); } + @TestMetadata("simpleSmap.kt") + public void testSimpleSmap() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/lineNumber/simpleSmap.kt"); + doTest(fileName); + } + @TestMetadata("topLevel.kt") public void testTopLevel() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/lineNumber/topLevel.kt");