kotlin-extractor: fix NotNullExpr start offset to span from operand

In K1 mode, the IrCall node for the !! operator stores startOffset at
the '!' character rather than at the start of the operand. This means
that x!! was previously reported as spanning from '!' to the end of the
expression, omitting the operand from the location.

Fix this by computing the NotNullExpr location from the value argument's
startOffset (the operand) to c.endOffset. This matches the K2 behaviour
where the IrCall.startOffset already points at the operand.

The fix guards against invalid (< 0) offsets on either side and falls
back to the default IrCall location in those cases.

Updated expected files in test-kotlin1:
- exprs/unaryOp.expected: !! locations now start at operand column
- exprs/exprs.expected: same (NotNullExpr entries corrected)
- exprs/binop.expected: !! child locations now correct (parent binop
  location for s!!.plus(5) still differs due to a separate K1 IR
  limitation where the enclosing call inherits the wrong receiver offset)
- controlflow/basic/bbStmts.expected: CFG references to !! now use the
  improved location
- controlflow/basic/getASuccessor.expected: same

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Anders Fugmann
2026-07-07 17:54:14 +02:00
parent 3fca86c8bf
commit d4efdfcbfa
6 changed files with 29 additions and 23 deletions

View File

@@ -3084,9 +3084,10 @@ open class KotlinFileExtractor(
id: Label<out DbExpr>,
c: IrCall,
callable: Label<out DbCallable>,
enclosingStmt: Label<out DbStmt>
enclosingStmt: Label<out DbStmt>,
customLocId: Label<DbLocation>? = null
) {
val locId = tw.getLocation(c)
val locId = customLocId ?: tw.getLocation(c)
extractExprContext(id, locId, callable, enclosingStmt)
val dr = c.dispatchReceiver
@@ -4584,7 +4585,12 @@ open class KotlinFileExtractor(
val type = useType(c.type)
tw.writeExprs_notnullexpr(id, type.javaResult.id, parent, idx)
tw.writeExprsKotlinType(id, type.kotlinResult.id)
unaryOp(id, c, callable, enclosingStmt)
// In K1 mode the IrCall.startOffset for !! points to the '!' character rather
// than the start of the operand. Use the operand's startOffset instead so that
// the NotNullExpr spans from the operand to the end of '!!'.
val operandStart = c.codeQlGetValueArgument(0)?.startOffset?.takeIf { it >= 0 }
val notNullLocId = if (operandStart != null && c.endOffset >= 0) tw.getLocation(operandStart, c.endOffset) else null
unaryOp(id, c, callable, enclosingStmt, notNullLocId)
}
isBuiltinCallInternal(c, "THROW_CCE") -> {
// TODO

View File

@@ -251,18 +251,18 @@
| Test.kt:91:1:98:1 | Entry | 3 | Test.kt:92:6:95:2 | { ... } |
| Test.kt:91:1:98:1 | Entry | 4 | Test.kt:93:7:93:7 | var ...; |
| Test.kt:91:1:98:1 | Entry | 5 | Test.kt:93:7:93:7 | Before x |
| Test.kt:91:1:98:1 | Entry | 6 | Test.kt:93:12:93:13 | Before ...!! |
| Test.kt:91:1:98:1 | Entry | 6 | Test.kt:93:11:93:13 | Before ...!! |
| Test.kt:91:1:98:1 | Entry | 7 | Test.kt:93:11:93:11 | o |
| Test.kt:91:1:98:1 | Entry | 8 | Test.kt:93:12:93:13 | ...!! |
| Test.kt:91:1:98:1 | Entry | 8 | Test.kt:93:11:93:13 | ...!! |
| Test.kt:91:1:98:1 | Exit | 0 | Test.kt:91:1:98:1 | Exit |
| Test.kt:91:1:98:1 | Normal Exit | 0 | Test.kt:91:1:98:1 | Normal Exit |
| Test.kt:93:12:93:13 | After ...!! | 0 | Test.kt:93:12:93:13 | After ...!! |
| Test.kt:93:12:93:13 | After ...!! | 1 | Test.kt:93:7:93:7 | x |
| Test.kt:93:12:93:13 | After ...!! | 2 | Test.kt:93:7:93:7 | After x |
| Test.kt:93:12:93:13 | After ...!! | 3 | Test.kt:93:7:93:7 | After var ...; |
| Test.kt:93:12:93:13 | After ...!! | 4 | Test.kt:94:3:94:10 | Before return ... |
| Test.kt:93:12:93:13 | After ...!! | 5 | Test.kt:94:10:94:10 | 1 |
| Test.kt:93:12:93:13 | After ...!! | 6 | Test.kt:94:3:94:10 | return ... |
| Test.kt:93:11:93:13 | After ...!! | 0 | Test.kt:93:11:93:13 | After ...!! |
| Test.kt:93:11:93:13 | After ...!! | 1 | Test.kt:93:7:93:7 | x |
| Test.kt:93:11:93:13 | After ...!! | 2 | Test.kt:93:7:93:7 | After x |
| Test.kt:93:11:93:13 | After ...!! | 3 | Test.kt:93:7:93:7 | After var ...; |
| Test.kt:93:11:93:13 | After ...!! | 4 | Test.kt:94:3:94:10 | Before return ... |
| Test.kt:93:11:93:13 | After ...!! | 5 | Test.kt:94:10:94:10 | 1 |
| Test.kt:93:11:93:13 | After ...!! | 6 | Test.kt:94:3:94:10 | return ... |
| Test.kt:95:4:97:2 | catch (...) | 0 | Test.kt:95:4:97:2 | catch (...) |
| Test.kt:95:4:97:2 | catch (...) | 1 | Test.kt:95:11:95:33 | e |
| Test.kt:95:11:95:33 | After e [match] | 0 | Test.kt:95:11:95:33 | After e [match] |

View File

@@ -150,9 +150,9 @@
| Test.kt:92:6:95:2 | { ... } | BlockStmt | Test.kt:93:7:93:7 | var ...; | LocalVariableDeclStmt |
| Test.kt:93:7:93:7 | var ...; | LocalVariableDeclStmt | Test.kt:93:11:93:11 | o | VarAccess |
| Test.kt:93:7:93:7 | x | LocalVariableDeclExpr | Test.kt:94:10:94:10 | 1 | IntegerLiteral |
| Test.kt:93:11:93:11 | o | VarAccess | Test.kt:93:12:93:13 | ...!! | NotNullExpr |
| Test.kt:93:12:93:13 | ...!! | NotNullExpr | Test.kt:93:7:93:7 | x | LocalVariableDeclExpr |
| Test.kt:93:12:93:13 | ...!! | NotNullExpr | Test.kt:95:4:97:2 | catch (...) | CatchClause |
| Test.kt:93:11:93:11 | o | VarAccess | Test.kt:93:11:93:13 | ...!! | NotNullExpr |
| Test.kt:93:11:93:13 | ...!! | NotNullExpr | Test.kt:93:7:93:7 | x | LocalVariableDeclExpr |
| Test.kt:93:11:93:13 | ...!! | NotNullExpr | Test.kt:95:4:97:2 | catch (...) | CatchClause |
| Test.kt:94:3:94:10 | return ... | ReturnStmt | Test.kt:91:1:98:1 | Normal Exit | Method |
| Test.kt:94:10:94:10 | 1 | IntegerLiteral | Test.kt:94:3:94:10 | return ... | ReturnStmt |
| Test.kt:95:4:97:2 | catch (...) | CatchClause | Test.kt:95:11:95:33 | e | LocalVariableDeclExpr |

View File

@@ -96,8 +96,8 @@
| exprs.kt:141:12:141:20 | ... + ... | exprs.kt:141:12:141:14 | 123 | exprs.kt:141:18:141:20 | 456 |
| exprs.kt:167:8:167:16 | ... (value not-equals) ... | exprs.kt:167:8:167:8 | r | exprs.kt:167:13:167:16 | null |
| exprs.kt:196:31:196:37 | ... + ... | exprs.kt:196:31:196:32 | getA1(...) | exprs.kt:196:36:196:37 | a2 |
| exprs.kt:211:20:211:29 | ... + ... | exprs.kt:211:20:211:21 | ...!! | exprs.kt:211:28:211:28 | 5 |
| exprs.kt:212:19:212:25 | ... + ... | exprs.kt:212:20:212:21 | ...!! | exprs.kt:212:25:212:25 | 5 |
| exprs.kt:211:20:211:29 | ... + ... | exprs.kt:211:19:211:21 | ...!! | exprs.kt:211:28:211:28 | 5 |
| exprs.kt:212:19:212:25 | ... + ... | exprs.kt:212:19:212:21 | ...!! | exprs.kt:212:25:212:25 | 5 |
| exprs.kt:230:12:230:47 | ... (value equals) ... | exprs.kt:230:12:230:27 | notNullPrimitive | exprs.kt:230:32:230:47 | notNullPrimitive |
| exprs.kt:231:12:231:48 | ... (value equals) ... | exprs.kt:231:12:231:27 | notNullPrimitive | exprs.kt:231:32:231:48 | nullablePrimitive |
| exprs.kt:232:12:232:49 | ... (value equals) ... | exprs.kt:232:12:232:28 | nullablePrimitive | exprs.kt:232:33:232:49 | nullablePrimitive |

View File

@@ -1572,7 +1572,7 @@
| exprs.kt:201:22:201:28 | Object | file://:0:0:0:0 | <none> | TypeAccess |
| exprs.kt:202:9:202:9 | y | exprs.kt:201:1:203:1 | notNullAssertion | LocalVariableDeclExpr |
| exprs.kt:202:18:202:18 | x | exprs.kt:201:1:203:1 | notNullAssertion | VarAccess |
| exprs.kt:202:19:202:20 | ...!! | exprs.kt:201:1:203:1 | notNullAssertion | NotNullExpr |
| exprs.kt:202:18:202:20 | ...!! | exprs.kt:201:1:203:1 | notNullAssertion | NotNullExpr |
| exprs.kt:206:5:217:5 | Unit | file://:0:0:0:0 | <none> | TypeAccess |
| exprs.kt:206:11:206:18 | Object | file://:0:0:0:0 | <none> | TypeAccess |
| exprs.kt:206:21:206:30 | String | file://:0:0:0:0 | <none> | TypeAccess |
@@ -1592,13 +1592,13 @@
| exprs.kt:210:23:210:23 | 5 | exprs.kt:206:5:217:5 | x | IntegerLiteral |
| exprs.kt:211:13:211:14 | b2 | exprs.kt:206:5:217:5 | x | LocalVariableDeclExpr |
| exprs.kt:211:19:211:19 | s | exprs.kt:206:5:217:5 | x | VarAccess |
| exprs.kt:211:20:211:21 | ...!! | exprs.kt:206:5:217:5 | x | NotNullExpr |
| exprs.kt:211:19:211:21 | ...!! | exprs.kt:206:5:217:5 | x | NotNullExpr |
| exprs.kt:211:20:211:29 | ... + ... | exprs.kt:206:5:217:5 | x | AddExpr |
| exprs.kt:211:28:211:28 | 5 | exprs.kt:206:5:217:5 | x | IntegerLiteral |
| exprs.kt:212:13:212:14 | b3 | exprs.kt:206:5:217:5 | x | LocalVariableDeclExpr |
| exprs.kt:212:19:212:19 | s | exprs.kt:206:5:217:5 | x | VarAccess |
| exprs.kt:212:19:212:21 | ...!! | exprs.kt:206:5:217:5 | x | NotNullExpr |
| exprs.kt:212:19:212:25 | ... + ... | exprs.kt:206:5:217:5 | x | AddExpr |
| exprs.kt:212:20:212:21 | ...!! | exprs.kt:206:5:217:5 | x | NotNullExpr |
| exprs.kt:212:25:212:25 | 5 | exprs.kt:206:5:217:5 | x | IntegerLiteral |
| exprs.kt:213:13:213:14 | c0 | exprs.kt:206:5:217:5 | x | LocalVariableDeclExpr |
| exprs.kt:213:18:213:36 | Color | exprs.kt:206:5:217:5 | x | TypeAccess |

View File

@@ -2,9 +2,9 @@
| exprs.kt:32:15:32:26 | !... | exprs.kt:32:15:32:26 | contains(...) |
| exprs.kt:79:15:79:22 | ~... | exprs.kt:79:15:79:16 | lx |
| exprs.kt:121:14:121:16 | !... | exprs.kt:121:15:121:16 | b1 |
| exprs.kt:202:19:202:20 | ...!! | exprs.kt:202:18:202:18 | x |
| exprs.kt:211:20:211:21 | ...!! | exprs.kt:211:19:211:19 | s |
| exprs.kt:212:20:212:21 | ...!! | exprs.kt:212:19:212:19 | s |
| exprs.kt:202:18:202:20 | ...!! | exprs.kt:202:18:202:18 | x |
| exprs.kt:211:19:211:21 | ...!! | exprs.kt:211:19:211:19 | s |
| exprs.kt:212:19:212:21 | ...!! | exprs.kt:212:19:212:19 | s |
| exprs.kt:286:5:286:6 | -... | exprs.kt:286:6:286:6 | i |
| exprs.kt:287:5:287:6 | +... | exprs.kt:287:6:287:6 | i |
| exprs.kt:288:5:288:6 | -... | exprs.kt:288:6:288:6 | d |