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>
K1 and K2 IR backends compute source locations differently. K1 uses the IR
node's synthetic startOffset/endOffset, while K2 reconstructs source positions
from PSI. For expression-level nodes this causes location differences across
the two language modes.
Introduce PSI-backed location lookup as the preferred source for spans wherever
PSI is available:
getPsiBasedLocation(element) ?: tw.getLocation(element)
getPsiBasedLocation() resolves the PSI element for the IR node via
psi2Ir.findPsiElement() and builds a location from its startOffset..endOffset.
currentIrFile is tracked in extractFileContents so the PSI lookup has the
file context it needs.
Applied to expression-level nodes (both K1 and K2 modes):
- local variable declarations (extractVariable, extractVariableExpr)
- IrLocalDelegatedProperty blocks
- IrWhen expressions and when-branches
- IrGetValue (varaccess) expressions
- IrFunctionExpression (lambda) nodes
- Block statements (extractBlock)
- this/super access expressions (extractThisAccess)
- String literals
Declaration-level nodes (class, function, property) are guarded with
if (usesK2) to avoid a regression in K1 mode where the PSI lookup causes
parameterised type instantiations to appear as fromSource(), inflating
generic-type query results. The K1 IR frontend does not map all declaration
nodes cleanly to source PSI elements; for these nodes we keep the original
IR-based location in K1 mode.
Expected output changes (both suites):
- controlflow/basic/bbStmts, bbStrictDominance, bbSuccessor, getASuccessor,
strictDominance: when-branch and varaccess location improvements
- java-kotlin-collection-type-generic-methods/test: new stdlib entries from
JDK update (AbstractCollection<Runnable> methods)
- annotation_classes/PrintAst: variable access location improvement in K1
- classes/genericExprTypes: location improvement in K1
- compilation-units/cus: removed two internal JDK inner-class entries (stdlib
version change)
- reflection/reflection: removed a few external-class entries (stdlib version)
Verified: all 285 tests pass for both test-kotlin1 (kotlinc 2.3.20 / K1) and
test-kotlin2 (kotlinc 2.4.0 / K2).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy K1's richer C2.kt (which includes test2, test3 and l.get(0) in test)
into test-kotlin2. K2 in -language 2.0 mode already tracks dataflow through
array.set() and indirect wrapper calls, so the additional tests produce results
identical to K1.
The expected files for test-kotlin1 and test-kotlin2 are now byte-identical for
this test.
Verified:
- test-kotlin1 (kotlinc 2.3.20 / -language 1.9): all tests pass
- test-kotlin2 (kotlinc 2.4.0 / -language 2.0): all tests pass
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the K1-only comment '// This doesn't generate a throw statement in
Kotlin 1 mode' from test-kotlin1/library-tests/generated-throws/generated-throws.kt
so the source files are byte-identical between the two suites.
The expected outputs still legitimately differ: in K2 mode the compiler generates
an implicit throw NoWhenBranchMatchedException for the exhaustive sealed-class when
expression, but the K1 frontend does not emit this node. This is a mode-specific
behaviour difference that cannot be bridged by an extractor change.
Both tests continue to pass:
- test-kotlin1 (kotlinc 2.3.20 / -language 1.9): 0 throw results (unchanged)
- test-kotlin2 (kotlinc 2.4.0 / -language 2.0): 1 throw result (unchanged)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
In K2 mode the frontend emits `-123L` as IrCall(unaryMinus, IrConst(123L))
rather than IrConst(-123L) as in K1. Queries that search for negative numeric
literals therefore need to match both a UnaryMinusExpr wrapping a literal and a
plain literal, depending on language mode.
Fix: when extractCallExpression encounters an isNumericFunction(unaryMinus) call
whose dispatchReceiver is already an IrConst, fold the negation into the constant
before extracting. The resulting literal node is identical to what K1 emits.
Location: extend the span one character to the left to cover the `-` sign.
In K2 the IrCall's startOffset equals the receiver's startOffset, so we recover
the minus by subtracting one from the receiver offset.
K1 is unaffected: the K1 frontend folds the sign into the constant before IR
generation, so this new branch never triggers when compiling with -language 1.9.
Expected output changes:
- test-kotlin2/library-tests/literals/literals.expected: negative long, float and
double literals now appear as plain typed literals instead of as UnaryMinus nodes.
The file is now byte-identical to test-kotlin1/library-tests/literals/literals.expected.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Port ministdlib from test-kotlin1 to test-kotlin2. The ministdlib test
exercises a minimal Kotlin standard library written from scratch. Its
options file is updated to include -language-version 2.0 so the test
runs in K2 mode when the K2 compiler is active.
- Port nested_types from test-kotlin2 to test-kotlin1. The nested_types
test exercises type-alias and inner-type queries. Expected output is
identical in K1 and K2 modes so no expected-file changes are needed.
- Add test-kotlin2/options with codeql-extractor-kotlin-options:
-language-version 2.0. The CodeQL CLI adds -language-version 1.9 by
default in legacy test extraction mode. Without this override the K2
test suite would run in K1 mode, defeating the purpose of the split.
Both ministdlib and nested_types produce byte-identical expected output
across K1 (2.3.20, -language-version 1.9) and K2 (2.4.0, default K2).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Update documentation to only claim support for 2.4.0x
* Python test code; remove newlines between imports.
* Sync comments between kotlin 1.8 and 1.9
* Update code comments to attach where actually relevant,
and improve comments on IrMemberAccessExpression<*>.extensionReceiverParameterIndex()