Write lineNumbers for constructors

This commit is contained in:
Natalia Ukhorskaya
2015-11-27 12:43:45 +03:00
parent 3ec383dfca
commit d0355a793b
24 changed files with 266 additions and 30 deletions
@@ -188,6 +188,12 @@ public class CodegenUtil {
return null;
}
}
if (statement instanceof KtConstructorDelegationReferenceExpression && statement.getTextLength() == 0) {
// PsiElement for constructor delegation reference is always generated, so we shouldn't mark it's line number if it's empty
return null;
}
Document document = file.getViewProvider().getDocument();
return document != null ? document.getLineNumber(markEndOffset ? statement.getTextRange().getEndOffset() : statement.getTextOffset()) + 1 : null;
}
@@ -283,7 +283,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
MemberCodegen.markLineNumberForSyntheticFunction(DescriptorUtils.getParentOfType(funDescriptor, ClassDescriptor.class), iv);
MemberCodegen.markLineNumberForDescriptor(DescriptorUtils.getParentOfType(funDescriptor, ClassDescriptor.class), iv);
iv.load(0, asmType);
@@ -27,7 +27,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.backend.common.bridges.Bridge;
import org.jetbrains.kotlin.backend.common.bridges.ImplKt;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithOnlyTargetedAnnotations;
import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics;
@@ -856,7 +855,7 @@ public class FunctionCodegen {
Type[] originalArgTypes = delegateTo.getArgumentTypes();
InstructionAdapter iv = new InstructionAdapter(mv);
MemberCodegen.markLineNumberForSyntheticFunction(owner.getThisDescriptor(), iv);
MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv);
if (delegateTo.getArgumentTypes().length == 1 && isSpecialBridge) {
generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes()[0]);
@@ -851,7 +851,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
// Invoke the object constructor but ignore the result because INSTANCE$ will be initialized in the first line of <init>
InstructionAdapter v = createOrGetClInitCodegen().v;
markLineNumberForSyntheticFunction(element, v);
markLineNumberForElement(element, v);
v.anew(classAsmType);
v.invokespecial(classAsmType.getInternalName(), "<init>", "()V", false);
@@ -942,14 +942,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor);
KtPrimaryConstructor primaryConstructor = myClass.getPrimaryConstructor();
final KtPrimaryConstructor primaryConstructor = myClass.getPrimaryConstructor();
JvmDeclarationOrigin origin = JvmDeclarationOriginKt
.OtherOrigin(primaryConstructor != null ? primaryConstructor : myClass, constructorDescriptor);
functionCodegen.generateMethod(origin, constructorDescriptor, constructorContext,
new FunctionGenerationStrategy.CodegenBased<ConstructorDescriptor>(state, constructorDescriptor) {
@Override
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
generatePrimaryConstructorImpl(callableDescriptor, codegen, delegationFieldsInfo);
generatePrimaryConstructorImpl(callableDescriptor, codegen, delegationFieldsInfo, primaryConstructor);
}
}
);
@@ -993,10 +993,13 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private void generatePrimaryConstructorImpl(
@NotNull ConstructorDescriptor constructorDescriptor,
@NotNull ExpressionCodegen codegen,
@NotNull DelegationFieldsInfo fieldsInfo
@NotNull DelegationFieldsInfo fieldsInfo,
@Nullable KtPrimaryConstructor primaryConstructor
) {
InstructionAdapter iv = codegen.v;
markLineNumberForConstructor(constructorDescriptor, primaryConstructor, codegen);
generateClosureInitialization(iv);
generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor,
@@ -1053,6 +1056,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
) {
InstructionAdapter iv = codegen.v;
KtSecondaryConstructor constructor =
(KtSecondaryConstructor) DescriptorToSourceUtils.descriptorToDeclaration(constructorDescriptor);
markLineNumberForConstructor(constructorDescriptor, constructor, codegen);
ResolvedCall<ConstructorDescriptor> constructorDelegationCall =
getDelegationConstructorCall(bindingContext, constructorDescriptor);
ConstructorDescriptor delegateConstructor = constructorDelegationCall == null ? null :
@@ -1065,8 +1073,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
generateInitializers(codegen);
}
KtSecondaryConstructor constructor =
(KtSecondaryConstructor) DescriptorToSourceUtils.descriptorToDeclaration(constructorDescriptor);
assert constructor != null;
if (constructor.hasBody()) {
codegen.gen(constructor.getBodyExpression(), Type.VOID_TYPE);
@@ -1075,6 +1081,29 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
iv.visitInsn(RETURN);
}
private static void markLineNumberForConstructor(
@NotNull ConstructorDescriptor descriptor,
@Nullable KtConstructor constructor,
@NotNull ExpressionCodegen codegen
) {
if (constructor == null) {
markLineNumberForDescriptor(descriptor.getContainingDeclaration(), codegen.v);
}
else if (constructor.hasBody() && !(constructor instanceof KtSecondaryConstructor && !((KtSecondaryConstructor) constructor).hasImplicitDelegationCall())) {
KtBlockExpression bodyExpression = constructor.getBodyExpression();
List<KtExpression> statements = bodyExpression != null ? bodyExpression.getStatements() : Collections.<KtExpression>emptyList();
if (!statements.isEmpty()) {
codegen.markStartLineNumber(statements.iterator().next());
}
else {
codegen.markStartLineNumber(bodyExpression != null ? bodyExpression : constructor);
}
}
else {
codegen.markStartLineNumber(constructor);
}
}
private void generateInitializers(@NotNull final ExpressionCodegen codegen) {
generateInitializers(new Function0<ExpressionCodegen>() {
@Override
@@ -144,18 +144,18 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
return null;
}
public static void markLineNumberForSyntheticFunction(@Nullable ClassDescriptor declarationDescriptor, @NotNull InstructionAdapter v) {
public static void markLineNumberForDescriptor(@Nullable ClassDescriptor declarationDescriptor, @NotNull InstructionAdapter v) {
if (declarationDescriptor == null) {
return;
}
PsiElement classElement = DescriptorToSourceUtils.getSourceFromDescriptor(declarationDescriptor);
if (classElement != null) {
markLineNumberForSyntheticFunction(classElement, v);
markLineNumberForElement(classElement, v);
}
}
public static void markLineNumberForSyntheticFunction(@NotNull PsiElement element, @NotNull InstructionAdapter v) {
public static void markLineNumberForElement(@NotNull PsiElement element, @NotNull InstructionAdapter v) {
Integer lineNumber = CodegenUtil.getLineNumberForElement(element, false);
if (lineNumber != null) {
Label label = new Label();
@@ -601,7 +601,7 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, accessor) {
@Override
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
markLineNumberForSyntheticFunction(element, codegen.v);
markLineNumberForElement(element, codegen.v);
generateMethodCallTo(original, accessor, codegen.v);
codegen.v.areturn(signature.getReturnType());
@@ -631,7 +631,7 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
InstructionAdapter iv = codegen.v;
markLineNumberForSyntheticFunction(element, iv);
markLineNumberForElement(element, iv);
Type[] argTypes = signature.getAsmMethod().getArgumentTypes();
for (int i = 0, reg = 0; i < argTypes.length; i++) {
@@ -14,4 +14,4 @@ fun foo() {
}
// 2 5 8 9 15
// 2 1 5 8 9 15
+1 -1
View File
@@ -12,4 +12,4 @@ fun foo() {
.bar()
}
// 2 3 7 8 9 8 9 11 12 11 12 17 13
// 2 3 1 7 8 9 8 9 11 12 11 12 17 13
+1 -1
View File
@@ -12,4 +12,4 @@ fun foo() {
.bar()
}
// 2 3 7 8 9 8 9 11 12 11 17 12 17 13
// 2 3 1 7 8 9 8 9 11 12 11 17 12 17 13
@@ -176,7 +176,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
codeFragment.checkForErrors(false)
val extractionResult = getFunctionForExtractedFragment(codeFragment, sourcePosition.file, sourcePosition.line)
?: throw IllegalStateException("Code fragment cannot be extracted to function")
?: throw IllegalStateException("Code fragment cannot be extracted to function: ${codeFragment.text}")
val parametersDescriptor = extractionResult.getParametersForDebugger(codeFragment)
val extractedFunction = extractionResult.declaration as KtNamedFunction
@@ -216,7 +216,7 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: KtCodeFragment,
insertNewInitializer(classOrObject.getOrCreateBody())
}
contextElement is KtClassOrObject -> {
insertNewInitializer(contextElement.getBody()!!)
insertNewInitializer(contextElement.getOrCreateBody())
}
contextElement is KtFunctionLiteral -> {
val block = contextElement.bodyExpression!!
+15
View File
@@ -2,6 +2,11 @@ LineBreakpoint created at constructors.kt:9
LineBreakpoint created at constructors.kt:13
LineBreakpoint created at constructors.kt:20
LineBreakpoint created at constructors.kt:28
LineBreakpoint created at constructors.kt:48
LineBreakpoint created at constructors.kt:53
LineBreakpoint created at constructors.kt:58
LineBreakpoint created at constructors.kt:64
LineBreakpoint created at constructors.kt:70
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! constructors.ConstructorsKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
constructors.kt:9
@@ -12,6 +17,16 @@ constructors.kt:20
Compile bytecode for p1 + p2
constructors.kt:28
Compile bytecode for i1
constructors.kt:48
Compile bytecode for 1 + 1
constructors.kt:53
Compile bytecode for 1 + 2
constructors.kt:58
Compile bytecode for a
constructors.kt:64
Compile bytecode for 1 + 3
constructors.kt:70
Compile bytecode for i
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -2,6 +2,7 @@ LineBreakpoint created at doNotSkipConstructors.kt:5
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! doNotSkipConstructors.DoNotSkipConstructorsKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
doNotSkipConstructors.kt:5
doNotSkipConstructors.kt:9
doNotSkipConstructors.kt:11
doNotSkipConstructors.kt:5
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
+2 -2
View File
@@ -22,8 +22,8 @@ fwBackingField.kt:24
fwBackingField.kt:25
fwBackingField.kt:26
fwBackingField.kt:61
fwBackingField.kt:0
fwBackingField.kt:0
fwBackingField.kt:29
fwBackingField.kt:29
fwBackingField.kt:61
fwBackingField.kt:36
fwBackingField.kt:37
@@ -0,0 +1,38 @@
LineBreakpoint created at smartStepIntoConstructor.kt:7
LineBreakpoint created at smartStepIntoConstructor.kt:11
LineBreakpoint created at smartStepIntoConstructor.kt:15
LineBreakpoint created at smartStepIntoConstructor.kt:19
LineBreakpoint created at smartStepIntoConstructor.kt:23
LineBreakpoint created at smartStepIntoConstructor.kt:27
LineBreakpoint created at smartStepIntoConstructor.kt:31
LineBreakpoint created at smartStepIntoConstructor.kt:35
LineBreakpoint created at smartStepIntoConstructor.kt:39
LineBreakpoint created at smartStepIntoConstructor.kt:43
LineBreakpoint created at smartStepIntoConstructor.kt:47
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! smartStepIntoConstructor.SmartStepIntoConstructorKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
smartStepIntoConstructor.kt:7
smartStepIntoConstructor.kt:51
smartStepIntoConstructor.kt:11
smartStepIntoConstructor.kt:52
smartStepIntoConstructor.kt:15
smartStepIntoConstructor.kt:54
smartStepIntoConstructor.kt:19
smartStepIntoConstructor.kt:57
smartStepIntoConstructor.kt:23
smartStepIntoConstructor.kt:61
smartStepIntoConstructor.kt:27
smartStepIntoConstructor.kt:66
smartStepIntoConstructor.kt:31
smartStepIntoConstructor.kt:69
smartStepIntoConstructor.kt:35
smartStepIntoConstructor.kt:74
smartStepIntoConstructor.kt:39
smartStepIntoConstructor.kt:81
smartStepIntoConstructor.kt:43
smartStepIntoConstructor.kt:89
smartStepIntoConstructor.kt:47
smartStepIntoConstructor.kt:97
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -34,4 +34,38 @@ fun main(args: Array<String>) {
Derived2(1, 1)
Derived1(1)
}
A()
B()
C(1)
D()
E(1)
}
// EXPRESSION: 1 + 1
// RESULT: 2: I
//Breakpoint!
class A
// EXPRESSION: 1 + 2
// RESULT: 3: I
//Breakpoint!
class B()
// EXPRESSION: a
// RESULT: 0: I
//Breakpoint!
class C(val a: Int)
class D {
// EXPRESSION: 1 + 3
// RESULT: 4: I
//Breakpoint!
constructor()
}
class E {
// EXPRESSION: i
// RESULT: 1: I
//Breakpoint!
constructor(i: Int)
}
@@ -0,0 +1,103 @@
package smartStepIntoConstructor
fun main(args: Array<String>) {
// SMART_STEP_INTO_BY_INDEX: 1
// RESUME: 1
//Breakpoint!
B()
// SMART_STEP_INTO_BY_INDEX: 1
// RESUME: 1
//Breakpoint!
C(1)
// SMART_STEP_INTO_BY_INDEX: 1
// RESUME: 1
//Breakpoint!
D()
// SMART_STEP_INTO_BY_INDEX: 1
// RESUME: 1
//Breakpoint!
E(1)
// SMART_STEP_INTO_BY_INDEX: 1
// RESUME: 1
//Breakpoint!
F()
// SMART_STEP_INTO_BY_INDEX: 1
// RESUME: 1
//Breakpoint!
G(1)
// SMART_STEP_INTO_BY_INDEX: 1
// RESUME: 1
//Breakpoint!
J()
// SMART_STEP_INTO_BY_INDEX: 1
// RESUME: 1
//Breakpoint!
K(1)
// SMART_STEP_INTO_BY_INDEX: 1
// RESUME: 1
//Breakpoint!
L()
// SMART_STEP_INTO_BY_INDEX: 1
// RESUME: 1
//Breakpoint!
M()
// SMART_STEP_INTO_BY_INDEX: 1
// RESUME: 1
//Breakpoint!
N(1)
}
class B()
class C(val a: Int)
class D {
constructor()
}
class E {
constructor(i: Int)
}
class F {
constructor() {
val a = 1
}
}
class G {
constructor(i: Int) {
val a = 1
}
}
class J {
init {
val a = 1
}
}
class K(val i: Int) {
init {
val a = 1
}
}
class L {
constructor() {
val a = 1
}
init {
val a = 1
}
}
class M {
constructor(): this(1) {
val a = 1
}
constructor(i: Int) {
}
}
class N {
constructor(i: Int): this() {
val a = 1
}
constructor() {
}
}
@@ -13,4 +13,4 @@ class A {
}
// SKIP_CONSTRUCTORS: false
// STEP_INTO: 2
// STEP_INTO: 3
@@ -7,3 +7,5 @@ fun main(args: Array<String>) {
}
class A
// SKIP_CONSTRUCTORS: true
@@ -45,4 +45,5 @@ class A {
}
// STEP_INTO: 26
// SKIP_SYNTHETIC_METHODS: false
// SKIP_SYNTHETIC_METHODS: false
// SKIP_CONSTRUCTORS: true
@@ -45,4 +45,5 @@ class A {
}
// STEP_INTO: 26
// SKIP_SYNTHETIC_METHODS: true
// SKIP_SYNTHETIC_METHODS: true
// SKIP_CONSTRUCTORS: true
@@ -47,4 +47,5 @@ class MyInterfaceImpl: MyInterface {
get() = 1
}
// STEP_INTO: 38
// STEP_INTO: 38
// SKIP_CONSTRUCTORS: true
@@ -7,8 +7,8 @@ class A {
}
fun main(args: Array<String>) {
A()
val a = A()
//Breakpoint!
A().bar()
a.bar()
}
@@ -9,8 +9,8 @@ class A {
}
fun main(args: Array<String>) {
A()
val a = A()
//Breakpoint!
A().bar
a.bar
}
@@ -559,6 +559,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
doCustomTest(fileName);
}
@TestMetadata("smartStepIntoConstructor.kt")
public void testSmartStepIntoConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/custom/smartStepIntoConstructor.kt");
doCustomTest(fileName);
}
@TestMetadata("smartStepIntoInlinedFunLiteral.kt")
public void testSmartStepIntoInlinedFunLiteral() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/custom/smartStepIntoInlinedFunLiteral.kt");