Skip to content

Commit d0363b2

Browse files
Another bunch of locals var fixes (#189)
Java function argument assignment ignored #187 Co-authored-by: DaniilStepanov <stepanov0995@mail.ru>
1 parent 7eb353d commit d0363b2

File tree

5 files changed

+77
-8
lines changed

5 files changed

+77
-8
lines changed

jacodb-core/src/main/kotlin/org/jacodb/impl/cfg/MethodNodeBuilder.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,17 @@ class MethodNodeBuilder(
9696
mn.tryCatchBlocks = tryCatchNodeList
9797
mn.maxLocals = localIndex
9898
mn.maxStack = maxStack + 1
99+
//At this moment, we're just copying annotations from original method without any modifications
100+
// with(method.asmNode()) {
101+
// mn.visibleAnnotations = visibleAnnotations
102+
// mn.visibleTypeAnnotations = visibleTypeAnnotations
103+
// mn.visibleLocalVariableAnnotations = visibleLocalVariableAnnotations
104+
// mn.visibleParameterAnnotations = visibleParameterAnnotations
105+
// mn.invisibleAnnotations = invisibleAnnotations
106+
// mn.invisibleTypeAnnotations = invisibleTypeAnnotations
107+
// mn.invisibleLocalVariableAnnotations = invisibleLocalVariableAnnotations
108+
// mn.invisibleParameterAnnotations = invisibleParameterAnnotations
109+
// }
99110
return mn
100111
}
101112

jacodb-core/src/main/kotlin/org/jacodb/impl/cfg/RawInstListBuilder.kt

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -413,9 +413,14 @@ class RawInstListBuilder(
413413
expr: JcRawValue,
414414
insn: AbstractInsnNode,
415415
override: Boolean = false
416-
): JcRawAssignInst? {
416+
): JcRawAssignInst {
417417
val oldVar = currentFrame.locals[variable]?.let {
418-
if (expr.typeName.isPrimitive.xor(it.typeName.isPrimitive) && it.typeName.typeName != PredefinedPrimitives.Null) {
418+
val infoFromLocalVars = methodNode.localVariables.find { it.index == variable && insn.isBetween(it.start, it.end) }
419+
val isArg = variable < argCounter && infoFromLocalVars != null && infoFromLocalVars.start == methodNode.instructions.firstOrNull { it is LabelNode }
420+
if (expr.typeName.isPrimitive.xor(it.typeName.isPrimitive)
421+
&& it.typeName.typeName != PredefinedPrimitives.Null
422+
&& !isArg
423+
) {
419424
null
420425
} else {
421426
it
@@ -438,7 +443,18 @@ class RawInstListBuilder(
438443
JcRawAssignInst(method, assignment, expr)
439444
}
440445
} else {
441-
val newLocal = nextRegisterDeclaredVariable(expr.typeName, variable, insn)
446+
//We have to get type if rhv expression is NULL
447+
val typeOfNewAssigment =
448+
if (expr.typeName.typeName == PredefinedPrimitives.Null) {
449+
methodNode.localVariables
450+
.find { it.index == variable && insn.isBetween(it.start, it.end) }
451+
?.desc?.typeName()
452+
?: currentFrame.locals[variable]?.typeName
453+
?: "java.lang.Object".typeName()
454+
} else {
455+
expr.typeName
456+
}
457+
val newLocal = nextRegisterDeclaredVariable(typeOfNewAssigment, variable, insn)
442458
val result = JcRawAssignInst(method, newLocal, expr)
443459
currentFrame = currentFrame.put(variable, newLocal)
444460
result
@@ -922,8 +938,7 @@ class RawInstListBuilder(
922938
val isArg =
923939
if (actualLocalFromDebugInfo == null) {
924940
variable < argCounter
925-
}
926-
else {
941+
} else {
927942
actualLocalFromDebugInfo.start == methodNode.instructions.firstOrNull { it is LabelNode }
928943
}
929944

@@ -1094,9 +1109,13 @@ class RawInstListBuilder(
10941109
val variable = insnNode.`var`
10951110
val local = local(variable)
10961111
val nextInst = insnNode.next
1112+
val prevInst = insnNode.previous
10971113
val incrementedVariable = when {
10981114
nextInst != null && nextInst.isBranchingInst -> local
10991115
nextInst != null && nextInst is VarInsnNode && nextInst.`var` == variable -> local
1116+
//Workaround for if (x++) if x is function argument
1117+
prevInst != null && local is JcRawArgument && prevInst is VarInsnNode && prevInst.`var` == variable -> nextRegister(local.typeName)
1118+
local is JcRawArgument -> local
11001119
else -> nextRegister(local.typeName)
11011120
}
11021121
val add = JcRawAddExpr(local.typeName, local, JcRawInt(insnNode.incr))

jacodb-core/src/test/kotlin/org/jacodb/testing/cfg/InstructionsTest.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ import org.jacodb.testing.hierarchies.Inheritance
3939
import org.jacodb.testing.primitives.Primitives
4040
import org.jacodb.testing.structure.FieldsAndMethods
4141
import org.junit.jupiter.api.Assertions.*
42-
import org.junit.jupiter.api.Disabled
4342
import org.junit.jupiter.api.Test
4443
import org.junit.jupiter.api.condition.DisabledOnJre
4544
import org.junit.jupiter.api.condition.EnabledOnJre
@@ -314,6 +313,11 @@ class InstructionsTest : BaseInstructionsTest() {
314313
assertNull(res)
315314
}
316315

316+
@Test
317+
fun `arg assignment`() {
318+
runTest(ArgAssignmentExample::class.java.name)
319+
}
320+
317321
}
318322

319323
fun JcMethod.dumpInstructions(): String {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2022 UnitTestBot contributors (utbot.org)
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.jacodb.testing.cfg;
18+
19+
public class ArgAssignmentExample {
20+
private static class X {
21+
public final int a = 0;
22+
}
23+
24+
private static X sample(X arg) {
25+
if (arg.a == 0) {
26+
arg = null;
27+
}
28+
return arg;
29+
}
30+
31+
public String box() {
32+
X result = sample(new X());
33+
return result == null ? "OK" : "BAD";
34+
}
35+
}

jacodb-core/src/testFixtures/kotlin/org/jacodb/testing/LibrariesMixin.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ val guavaLib: File
3535

3636
val asmLib: File
3737
get() {
38-
val asmUrl = classpath.first { it.contains("/asm/") }
38+
val asmUrl = classpath.first { it.contains("${File.separator}asm${File.separator}") }
3939
return File(asmUrl).also {
4040
Assertions.assertTrue(it.isFile && it.exists())
4141
}
@@ -51,7 +51,7 @@ val kotlinxCoroutines: File
5151

5252
val kotlinStdLib: File
5353
get() {
54-
val kotlinStdLib = classpath.first { it.contains("/kotlin-stdlib/") }
54+
val kotlinStdLib = classpath.first { it.contains("${File.separator}kotlin-stdlib${File.separator}") }
5555
return File(kotlinStdLib).also {
5656
Assertions.assertTrue(it.isFile && it.exists())
5757
}

0 commit comments

Comments
 (0)