Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
967f45d
Kotlin: Update kotlin_rules to 2.2.0 and remove support for Kotlin 1.…
andersfugmann Dec 4, 2025
7597ef2
Kotlin: Remove resource_strip_prefix for kotlin extraction
andersfugmann Dec 4, 2025
462f6a8
Kotlin: Silence compilation warnings
andersfugmann Dec 4, 2025
50a949e
Kotlin: Add support for Kotlin 2.3.0-Beta2
andersfugmann Dec 4, 2025
4b84dec
Kotlin: Update compiler plugin for Kotlin 2.3.0-Beta2
andersfugmann Dec 4, 2025
3ec8b99
Kotlin: Fix bazel format and address copilot review comments
andersfugmann Dec 5, 2025
198cb8e
Kotlin: Strip prefix when building plugin
andersfugmann Dec 20, 2025
26613f3
Kotlin: Create IrSimpleType factory function to support constructor c…
andersfugmann Jan 5, 2026
be98773
Kotlin: Fix spelling
andersfugmann Jan 5, 2026
ef304b2
Kotlin: Remove obsolete file
andersfugmann Jan 5, 2026
d70f0c6
Kotlin: Remove support for Kotlin versions 1.6 and 1.7
andersfugmann Jan 5, 2026
ae05362
Kotlin: Add additional warning suppresion to v1_9_0 and remove copy i…
andersfugmann Jan 5, 2026
bf6e3c5
Kotlin: Do not skip writing of getter and setters if the local deliga…
andersfugmann Jan 6, 2026
0d3a3a8
Kotlin: Add changenotes for Kotlin 2.3 support and removal of support…
andersfugmann Jan 8, 2026
6aabadd
Kotlin: Bump versions in documentation
andersfugmann Jan 7, 2026
02c121c
Kotlin: Bump default version
andersfugmann Jan 7, 2026
e70f6e4
Kotlin: Bump upper bound for supported kotlin version in integration …
andersfugmann Jan 7, 2026
faccf3b
Kotlin: Update kotlin compiler version in integration tests
andersfugmann Jan 8, 2026
25031cd
Kotlin: Update kotlin serialization integration test to use Kotlin co…
andersfugmann Jan 8, 2026
240e961
Kotlin: Update kotlin assets to Kotlin 2.3.0
andersfugmann Jan 13, 2026
12ce544
Kotlin: Accept column location changes in tests
andersfugmann Jan 14, 2026
45bc8d5
Kotlin: Add bitwise 'and' operation expected by Kotlin 2.3 compiler t…
andersfugmann Jan 15, 2026
d0878a2
Kotlin: Accept test changes
andersfugmann Jan 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 4 additions & 13 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ bazel_dep(name = "bazel_skylib", version = "1.8.1")
bazel_dep(name = "abseil-cpp", version = "20240116.1", repo_name = "absl")
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
bazel_dep(name = "fmt", version = "12.1.0-codeql.1")
bazel_dep(name = "rules_kotlin", version = "2.1.3-codeql.1")
bazel_dep(name = "rules_kotlin", version = "2.2.0-codeql.1")
bazel_dep(name = "gazelle", version = "0.40.0")
bazel_dep(name = "rules_dotnet", version = "0.21.5-codeql.1")
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
Expand Down Expand Up @@ -221,10 +221,6 @@ use_repo(
kotlin_extractor_deps,
"codeql_kotlin_defaults",
"codeql_kotlin_embeddable",
"kotlin-compiler-1.6.0",
"kotlin-compiler-1.6.20",
"kotlin-compiler-1.7.0",
"kotlin-compiler-1.7.20",
"kotlin-compiler-1.8.0",
"kotlin-compiler-1.9.0-Beta",
"kotlin-compiler-1.9.20-Beta",
Expand All @@ -234,10 +230,7 @@ use_repo(
"kotlin-compiler-2.1.20-Beta1",
"kotlin-compiler-2.2.0-Beta1",
"kotlin-compiler-2.2.20-Beta2",
"kotlin-compiler-embeddable-1.6.0",
"kotlin-compiler-embeddable-1.6.20",
"kotlin-compiler-embeddable-1.7.0",
"kotlin-compiler-embeddable-1.7.20",
"kotlin-compiler-2.3.0",
"kotlin-compiler-embeddable-1.8.0",
"kotlin-compiler-embeddable-1.9.0-Beta",
"kotlin-compiler-embeddable-1.9.20-Beta",
Expand All @@ -247,10 +240,7 @@ use_repo(
"kotlin-compiler-embeddable-2.1.20-Beta1",
"kotlin-compiler-embeddable-2.2.0-Beta1",
"kotlin-compiler-embeddable-2.2.20-Beta2",
"kotlin-stdlib-1.6.0",
"kotlin-stdlib-1.6.20",
"kotlin-stdlib-1.7.0",
"kotlin-stdlib-1.7.20",
"kotlin-compiler-embeddable-2.3.0",
"kotlin-stdlib-1.8.0",
"kotlin-stdlib-1.9.0-Beta",
"kotlin-stdlib-1.9.20-Beta",
Expand All @@ -260,6 +250,7 @@ use_repo(
"kotlin-stdlib-2.1.20-Beta1",
"kotlin-stdlib-2.2.0-Beta1",
"kotlin-stdlib-2.2.20-Beta2",
"kotlin-stdlib-2.3.0",
)

go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
Expand Down
3 changes: 1 addition & 2 deletions docs/codeql/reusables/supported-versions-compilers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
Java,"Java 7 to 25 [6]_","javac (OpenJDK and Oracle JDK),

Eclipse compiler for Java (ECJ) [7]_",``.java``
Kotlin,"Kotlin 1.6.0 [15]_ to 2.2.2\ *x*","kotlinc",``.kt``
Kotlin,"Kotlin 1.8.0 to 2.3.0\ *x*","kotlinc",``.kt``
JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [8]_"
Python [9]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13",Not applicable,``.py``
Ruby [10]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``"
Expand All @@ -45,4 +45,3 @@
.. [12] Support for the analysis of Swift requires macOS.
.. [13] Embedded Swift is not supported.
.. [14] TypeScript analysis is performed by running the JavaScript extractor with TypeScript enabled. This is the default.
.. [15] Support for Kotlin versions 1.6 and 1.7 is deprecated and will be removed in release 2.24.1.
8 changes: 1 addition & 7 deletions java/kotlin-extractor/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,7 @@ kt_javac_options(
javac_opts = ":javac-options",
kotlinc_opts = ":kotlinc-options-%s" % v,
module_name = "codeql-kotlin-extractor",
# resource_strip_prefix is very nit-picky: the following makes it work from
# `codeql`, `@codeql_kotlin_embeddable` and `semmle-code`
resource_strip_prefix = (
("../%s/" % repo_name() if repo_name() else "") +
("%s/" % package_name() if package_name() else "") +
v
),
resource_strip_prefix = v,
resources = [
":resources-%s" % v,
],
Expand Down
3 changes: 0 additions & 3 deletions java/kotlin-extractor/deps/kotlin-compiler-1.6.0.jar

This file was deleted.

3 changes: 0 additions & 3 deletions java/kotlin-extractor/deps/kotlin-compiler-1.6.20.jar

This file was deleted.

3 changes: 0 additions & 3 deletions java/kotlin-extractor/deps/kotlin-compiler-1.7.0.jar

This file was deleted.

3 changes: 0 additions & 3 deletions java/kotlin-extractor/deps/kotlin-compiler-1.7.20.jar

This file was deleted.

3 changes: 3 additions & 0 deletions java/kotlin-extractor/deps/kotlin-compiler-2.3.0.jar
Git LFS file not shown

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Git LFS file not shown
3 changes: 0 additions & 3 deletions java/kotlin-extractor/deps/kotlin-stdlib-1.6.0.jar

This file was deleted.

3 changes: 0 additions & 3 deletions java/kotlin-extractor/deps/kotlin-stdlib-1.6.20.jar

This file was deleted.

3 changes: 0 additions & 3 deletions java/kotlin-extractor/deps/kotlin-stdlib-1.7.0.jar

This file was deleted.

3 changes: 0 additions & 3 deletions java/kotlin-extractor/deps/kotlin-stdlib-1.7.20.jar

This file was deleted.

3 changes: 3 additions & 0 deletions java/kotlin-extractor/deps/kotlin-stdlib-2.3.0.jar
Git LFS file not shown
2 changes: 1 addition & 1 deletion java/kotlin-extractor/dev/wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import io
import os

DEFAULT_VERSION = "2.2.0"
DEFAULT_VERSION = "2.3.0"


def options():
Expand Down
30 changes: 21 additions & 9 deletions java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ open class KotlinFileExtractor(

private fun extractClassModifiers(c: IrClass, id: Label<out DbClassorinterface>) {
with("class modifiers", c) {
@Suppress("REDUNDANT_ELSE_IN_WHEN")
when (c.modality) {
Modality.FINAL -> addModifiers(id, "final")
Modality.SEALED -> addModifiers(id, "sealed")
Expand Down Expand Up @@ -1342,7 +1343,7 @@ open class KotlinFileExtractor(
extractTypeAccessRecursive(substitutedType, location, id, -1)
}
val syntheticParameterNames =
isUnderscoreParameter(vp) ||
vp.origin == IrDeclarationOrigin.UNDERSCORE_PARAMETER ||
((vp.parent as? IrFunction)?.let { hasSynthesizedParameterNames(it) } ?: true)
val javaParameter =
when (val callable = (vp.parent as? IrFunction)?.let { getJavaCallable(it) }) {
Expand Down Expand Up @@ -1644,7 +1645,7 @@ open class KotlinFileExtractor(
extractMethodAndParameterTypeAccesses: Boolean,
typeSubstitution: TypeSubstitution?,
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?
) =
) : Label<out DbCallable> =
forceExtractFunction(
f,
parentId,
Expand Down Expand Up @@ -2801,6 +2802,7 @@ open class KotlinFileExtractor(

private fun extractBody(b: IrBody, callable: Label<out DbCallable>) {
with("body", b) {
@Suppress("REDUNDANT_ELSE_IN_WHEN")
when (b) {
is IrBlockBody -> extractBlockBody(b, callable)
is IrSyntheticBody -> extractSyntheticBody(b, callable)
Expand Down Expand Up @@ -2834,7 +2836,7 @@ open class KotlinFileExtractor(
when {
kind == IrSyntheticBodyKind.ENUM_VALUES -> tw.writeKtSyntheticBody(callable, 1)
kind == IrSyntheticBodyKind.ENUM_VALUEOF -> tw.writeKtSyntheticBody(callable, 2)
kind == kind_ENUM_ENTRIES -> tw.writeKtSyntheticBody(callable, 3)
kind == IrSyntheticBodyKind.ENUM_ENTRIES -> tw.writeKtSyntheticBody(callable, 3)
else -> {
logger.errorElement("Unhandled synthetic body kind " + kind, b)
}
Expand Down Expand Up @@ -2973,13 +2975,23 @@ open class KotlinFileExtractor(
val locId = tw.getLocation(s)
tw.writeStmts_block(blockId, parent, idx, callable)
tw.writeHasLocation(blockId, locId)
extractVariable(s.delegate, callable, blockId, 0)

// For Kotlin < 2.3, s.delegate is not-nullable. Cast to be nullable,
// as a workaround to silence warnings for kotlin < 2.3 about the elvis
// operator being redundant.
// For Kotlin >= 2.3, the cast is redundant, so we need to silence that warning
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know why it is now nullable? Is that actually an error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tbh, I have not dug into why it can be nullable. Let me take a look at the API to understand if its an error if its null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was very convincing in explaining that the delegate may become null after lowering. But as the extractor hooks into the pipeline before lowering, the delegate should always be set.

@Suppress("USELESS_CAST")
val delegate = s.delegate as IrVariable?
val propId = tw.getFreshIdLabel<DbKt_property>()
tw.writeKtProperties(propId, s.name.asString())
tw.writeHasLocation(propId, locId)
tw.writeKtPropertyDelegates(propId, useVariable(s.delegate))

if (delegate == null) {
// This is not expected to happen, as the plugin hooks into the pipeline before IR lowering.
logger.errorElement("Local delegated property is missing delegate", s)
} else {
extractVariable(delegate, callable, blockId, 0)
tw.writeKtProperties(propId, s.name.asString())
tw.writeHasLocation(propId, locId)
tw.writeKtPropertyDelegates(propId, useVariable(delegate))
}
// Getter:
extractStatement(s.getter, callable, blockId, 1)
val getterLabel = getLocallyVisibleFunctionLabels(s.getter).function
Expand Down Expand Up @@ -3332,7 +3344,7 @@ open class KotlinFileExtractor(
// that specified the default values, which will in turn dynamically dispatch back to the
// relevant override.
val overriddenCallTarget =
(callTarget as? IrSimpleFunction)?.allOverriddenIncludingSelf()?.firstOrNull {
(callTarget as? IrSimpleFunction)?.allOverridden(includeSelf = true)?.firstOrNull {
it.overriddenSymbols.isEmpty() &&
it.valueParameters.any { p -> p.defaultValue != null }
} ?: callTarget
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ open class KotlinUsesExtractor(
componentType.isNullableCodeQL()
if (unchanged) arrayType
else
IrSimpleTypeImpl(
codeqlIrSimpleTypeImpl(
arrayType.classifier,
true,
listOf(makeTypeProjection(componentTypeBroadened, Variance.INVARIANT)),
Expand Down Expand Up @@ -849,9 +849,6 @@ open class KotlinUsesExtractor(
}

private fun useSimpleType(s: IrSimpleType, context: TypeContext): TypeResults {
if (s.abbreviation != null) {
// TODO: Extract this information
}
// We use this when we don't actually have an IrClass for a class
// we want to refer to
// TODO: Eliminate the need for this if possible
Expand Down Expand Up @@ -939,7 +936,7 @@ open class KotlinUsesExtractor(
return arrayInfo.componentTypeResults
}
owner is IrClass -> {
val args = if (s.codeQlIsRawType()) null else s.arguments
val args = if (s.isRawType()) null else s.arguments

return useSimpleTypeClass(owner, args, s.isNullableCodeQL())
}
Expand Down Expand Up @@ -1836,6 +1833,7 @@ open class KotlinUsesExtractor(

// Note this function doesn't return a signature because type arguments are never
// incorporated into function signatures.
@Suppress("REDUNDANT_ELSE_IN_WHEN")
return when (arg) {
is IrStarProjection -> {
val anyTypeLabel =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.github.codeql

import com.github.codeql.utils.versions.copyParameterToFunction
import com.github.codeql.utils.versions.createImplicitParameterDeclarationWithWrappedDescriptor
import java.lang.annotation.ElementType
import java.util.HashSet
Expand All @@ -21,7 +20,9 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.IrClassReference
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue
Expand All @@ -31,6 +32,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.constructedClass
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.copyTo
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
Expand Down Expand Up @@ -330,7 +332,7 @@ class MetaAnnotationSupport(
)
return
}
val newParam = copyParameterToFunction(thisReceiever, this)
val newParam = thisReceiever.copyTo(this)
dispatchReceiverParameter = newParam
body =
factory
Expand Down
36 changes: 36 additions & 0 deletions java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.parentClassOrNull
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
import org.jetbrains.kotlin.load.kotlin.FacadeClassSource
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass
import org.jetbrains.kotlin.name.FqName

// Adapted from Kotlin's interpreter/Utils.kt function 'internalName'
// Translates class names into their JLS section 13.1 binary name,
Expand All @@ -31,6 +33,40 @@ fun getFileClassName(f: IrFile) =
.replaceFirst(Regex("""\.kt$"""), "")
.replaceFirstChar { it.uppercase() }) + "Kt")

fun getFileClassFqName(d: IrDeclaration): FqName? {
// d is in a file class.
// Get the name in a similar way to the compiler's ExternalPackageParentPatcherLowering
// visitMemberAccess/generateOrGetFacadeClass.

// But first, fields aren't IrMemberWithContainerSource, so we need
// to get back to the property (if there is one)
if (d is IrField) {
val propSym = d.correspondingPropertySymbol
if (propSym != null) {
return getFileClassFqName(propSym.owner)
}
}

// Now the main code
if (d is IrMemberWithContainerSource) {
val containerSource = d.containerSource
if (containerSource is FacadeClassSource) {
val facadeClassName = containerSource.facadeClassName
if (facadeClassName != null) {
// TODO: This is really a multifile-class rather than a file-class,
// but for now we treat them the same.
return facadeClassName.fqNameForTopLevelClassMaybeWithDollars
} else {
return containerSource.className.fqNameForTopLevelClassMaybeWithDollars
}
} else {
return null
}
} else {
return null
}
}

fun getIrElementBinaryName(that: IrElement): String {
if (that is IrFile) {
val shortName = getFileClassName(that)
Expand Down
29 changes: 29 additions & 0 deletions java/kotlin-extractor/src/main/kotlin/utils/GetByFqName.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,38 @@ package com.github.codeql.utils

import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name

fun getClassByFqName(pluginContext: IrPluginContext, fqName: FqName): IrClassSymbol? {
val id = ClassId.topLevel(fqName)
return getClassByClassId(pluginContext, id)
}

fun getClassByClassId(pluginContext: IrPluginContext, id: ClassId): IrClassSymbol? {
return pluginContext.referenceClass(id)
}

fun getFunctionsByFqName(
pluginContext: IrPluginContext,
pkgName: FqName,
name: Name
): Collection<IrSimpleFunctionSymbol> {
val id = CallableId(pkgName, name)
return pluginContext.referenceFunctions(id)
}

fun getPropertiesByFqName(
pluginContext: IrPluginContext,
pkgName: FqName,
name: Name
): Collection<IrPropertySymbol> {
val id = CallableId(pkgName, name)
return pluginContext.referenceProperties(id)
}

fun getClassByFqName(pluginContext: IrPluginContext, fqName: String): IrClassSymbol? {
return getClassByFqName(pluginContext, FqName(fqName))
}
Expand Down
Loading
Loading