mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Kotlin: Implement JvmOverloads annotation
This generates functions that omit parameters with default values, rightmost first, such that Java can achieve a similar experience to Kotlin (which represents calls internally as if the default was supplied explicitly, and/or uses a $default method that supplies the needed arguments). A complication: combining JvmOverloads with JvmStatic means that both the companion object and the surrounding class get overloads.
This commit is contained in:
@@ -84,7 +84,7 @@ class ExternalDeclExtractor(val logger: FileLogger, val invocationTrapFile: Stri
|
||||
// file information if needed:
|
||||
val ftw = tw.makeFileTrapWriter(binaryPath, irDecl is IrClass)
|
||||
|
||||
val fileExtractor = KotlinFileExtractor(logger, ftw, binaryPath, manager, this, primitiveTypeMapping, pluginContext, globalExtensionState)
|
||||
val fileExtractor = KotlinFileExtractor(logger, ftw, binaryPath, manager, this, primitiveTypeMapping, pluginContext, KotlinFileExtractor.DeclarationStack(), globalExtensionState)
|
||||
|
||||
if (irDecl is IrClass) {
|
||||
// Populate a location and compilation-unit package for the file. This is similar to
|
||||
|
||||
@@ -322,7 +322,7 @@ private fun doFile(
|
||||
// file information
|
||||
val sftw = tw.makeSourceFileTrapWriter(srcFile, true)
|
||||
val externalDeclExtractor = ExternalDeclExtractor(logger, invocationTrapFile, srcFilePath, primitiveTypeMapping, pluginContext, globalExtensionState, fileTrapWriter)
|
||||
val fileExtractor = KotlinFileExtractor(logger, sftw, srcFilePath, null, externalDeclExtractor, primitiveTypeMapping, pluginContext, globalExtensionState)
|
||||
val fileExtractor = KotlinFileExtractor(logger, sftw, srcFilePath, null, externalDeclExtractor, primitiveTypeMapping, pluginContext, KotlinFileExtractor.DeclarationStack(), globalExtensionState)
|
||||
|
||||
fileExtractor.extractFileContents(srcFile, sftw.fileId)
|
||||
externalDeclExtractor.extractExternalClasses()
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import java.io.Closeable
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
open class KotlinFileExtractor(
|
||||
override val logger: FileLogger,
|
||||
@@ -39,7 +40,8 @@ open class KotlinFileExtractor(
|
||||
externalClassExtractor: ExternalDeclExtractor,
|
||||
primitiveTypeMapping: PrimitiveTypeMapping,
|
||||
pluginContext: IrPluginContext,
|
||||
globalExtensionState: KotlinExtractorGlobalState
|
||||
val declarationStack: DeclarationStack,
|
||||
globalExtensionState: KotlinExtractorGlobalState,
|
||||
): KotlinUsesExtractor(logger, tw, dependencyCollector, externalClassExtractor, primitiveTypeMapping, pluginContext, globalExtensionState) {
|
||||
|
||||
private inline fun <T> with(kind: String, element: IrElement, f: () -> T): T {
|
||||
@@ -475,7 +477,7 @@ open class KotlinFileExtractor(
|
||||
val proxyFunctionId = tw.getLabelFor<DbMethod>(getFunctionLabel(f, classId, listOf()))
|
||||
// We extract the function prototype with its ID overridden to belong to `c` not the companion object,
|
||||
// but suppress outputting the body, which we will replace with a delegating call below.
|
||||
forceExtractFunction(f, classId, extractBody = false, extractMethodAndParameterTypeAccesses = extractFunctionBodies, typeSubstitution = null, classTypeArgsIncludingOuterClasses = listOf(), idOverride = proxyFunctionId, locOverride = null, extractOrigin = false)
|
||||
forceExtractFunction(f, classId, extractBody = false, extractMethodAndParameterTypeAccesses = extractFunctionBodies, typeSubstitution = null, classTypeArgsIncludingOuterClasses = listOf(), extractOrigin = false, OverriddenFunctionAttributes(id = proxyFunctionId))
|
||||
addModifiers(proxyFunctionId, "static")
|
||||
tw.writeCompiler_generated(proxyFunctionId, CompilerGeneratedKinds.JVMSTATIC_PROXY_METHOD.kind)
|
||||
if (extractFunctionBodies) {
|
||||
@@ -514,8 +516,12 @@ open class KotlinFileExtractor(
|
||||
val wholeDeclAnnotated = it.hasAnnotation(jvmStaticFqName)
|
||||
when(it) {
|
||||
is IrFunction -> {
|
||||
if (wholeDeclAnnotated)
|
||||
if (wholeDeclAnnotated) {
|
||||
makeProxyFunction(it)
|
||||
if (it.hasAnnotation(jvmOverloadsFqName)) {
|
||||
extractGeneratedOverloads(it, classId, classId, extractFunctionBodies, extractMethodAndParameterTypeAccesses = extractFunctionBodies, typeSubstitution = null, classTypeArgsIncludingOuterClasses = listOf())
|
||||
}
|
||||
}
|
||||
}
|
||||
is IrProperty -> {
|
||||
it.getter?.let { getter ->
|
||||
@@ -818,38 +824,139 @@ open class KotlinFileExtractor(
|
||||
private fun extractFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?) =
|
||||
if (isFake(f))
|
||||
null
|
||||
else
|
||||
forceExtractFunction(f, parentId, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses, null, null)
|
||||
else {
|
||||
forceExtractFunction(f, parentId, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses).also {
|
||||
extractGeneratedOverloads(f, parentId, null, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses)
|
||||
}
|
||||
}
|
||||
|
||||
private fun forceExtractFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, idOverride: Label<DbMethod>?, locOverride: Label<DbLocation>?, extractOrigin: Boolean = true): Label<out DbCallable> {
|
||||
private val jvmOverloadsFqName = FqName("kotlin.jvm.JvmOverloads")
|
||||
|
||||
private fun extractGeneratedOverloads(f: IrFunction, parentId: Label<out DbReftype>, maybeSourceParentId: Label<out DbReftype>?, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?) {
|
||||
if (!f.hasAnnotation(jvmOverloadsFqName))
|
||||
return
|
||||
|
||||
fun extractGeneratedOverload(paramList: List<IrElement>) {
|
||||
val overloadParameters = paramList.filterIsInstance<IrValueParameter>()
|
||||
// Note `overloadParameters` have incorrect parents and indices, since there is no actual IrFunction describing the required synthetic overload.
|
||||
// We have to use the `overriddenAttributes` element of `DeclarationStackAdjuster` to fix up references to these parameters while we're extracting
|
||||
// these synthetic overloads.
|
||||
val overloadId = tw.getLabelFor<DbCallable>(getFunctionLabel(f, parentId, classTypeArgsIncludingOuterClasses, overloadParameters))
|
||||
val sourceParentId =
|
||||
maybeSourceParentId ?:
|
||||
if (typeSubstitution != null)
|
||||
useDeclarationParent(f.parent, false)
|
||||
else
|
||||
parentId
|
||||
val sourceDeclId = tw.getLabelFor<DbCallable>(getFunctionLabel(f, sourceParentId, listOf(), overloadParameters))
|
||||
val overriddenAttributes = OverriddenFunctionAttributes(id = overloadId, sourceDeclarationId = sourceDeclId, valueParameters = overloadParameters)
|
||||
forceExtractFunction(f, parentId, extractBody = false, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses, overriddenAttributes = overriddenAttributes)
|
||||
tw.writeCompiler_generated(overloadId, CompilerGeneratedKinds.JVMOVERLOADS_METHOD.kind)
|
||||
val realFunctionLocId = tw.getLocation(f)
|
||||
if (extractBody) {
|
||||
|
||||
DeclarationStackAdjuster(f, overriddenAttributes).use {
|
||||
|
||||
fun extractNormalArgs(argParentId: Label<out DbExprparent>, idxOffset: Int, enclosingStmtId: Label<out DbStmt>) {
|
||||
paramList.forEachIndexed { idx, param ->
|
||||
when(param) {
|
||||
is IrValueParameter -> {
|
||||
// Forward a parameter:
|
||||
val syntheticParamId = useValueParameter(param, overloadId)
|
||||
extractVariableAccess(syntheticParamId, param.type, realFunctionLocId, argParentId, idxOffset + idx, overloadId, enclosingStmtId)
|
||||
}
|
||||
is IrExpression -> {
|
||||
// Supply a default argument:
|
||||
extractExpressionExpr(param, overloadId, argParentId, idxOffset + idx, enclosingStmtId)
|
||||
}
|
||||
else -> {
|
||||
logger.errorElement("Unexpected parameter list entry", param)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a synthetic function body that calls the real function supplying default arguments where required:
|
||||
if (f is IrConstructor) {
|
||||
val blockId = tw.getFreshIdLabel<DbBlock>()
|
||||
tw.writeStmts_block(blockId, overloadId, 0, overloadId)
|
||||
tw.writeHasLocation(blockId, realFunctionLocId)
|
||||
|
||||
val constructorCallId = tw.getFreshIdLabel<DbConstructorinvocationstmt>()
|
||||
tw.writeStmts_constructorinvocationstmt(constructorCallId, blockId, 0, overloadId)
|
||||
tw.writeHasLocation(constructorCallId, realFunctionLocId)
|
||||
tw.writeCallableBinding(constructorCallId, useFunction(f))
|
||||
|
||||
extractNormalArgs(constructorCallId, 0, constructorCallId)
|
||||
} else {
|
||||
extractExpressionBody(overloadId, realFunctionLocId).also { returnId ->
|
||||
extractRawMethodAccess(
|
||||
f,
|
||||
realFunctionLocId,
|
||||
f.returnType,
|
||||
overloadId,
|
||||
returnId,
|
||||
0,
|
||||
returnId,
|
||||
f.valueParameters.size,
|
||||
{ argParentId, idxOffset ->
|
||||
extractNormalArgs(argParentId, idxOffset, returnId)
|
||||
},
|
||||
f.dispatchReceiverParameter?.type,
|
||||
f.dispatchReceiverParameter?.let { { callId ->
|
||||
extractThisAccess(it.type, overloadId, callId, -1, returnId, realFunctionLocId)
|
||||
} },
|
||||
f.extensionReceiverParameter?.let { { argParentId ->
|
||||
val syntheticParamId = useValueParameter(it, overloadId)
|
||||
extractVariableAccess(syntheticParamId, it.type, realFunctionLocId, argParentId, 0, overloadId, returnId)
|
||||
} }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val paramList: MutableList<IrElement> = f.valueParameters.toMutableList()
|
||||
for (n in (paramList.size - 1) downTo 0) {
|
||||
(paramList[n] as? IrValueParameter)?.defaultValue?.expression?.let {
|
||||
paramList[n] = it // Replace the last parameter that has a default with that default value.
|
||||
extractGeneratedOverload(paramList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun forceExtractFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, extractOrigin: Boolean = true, overriddenAttributes: OverriddenFunctionAttributes? = null): Label<out DbCallable> {
|
||||
with("function", f) {
|
||||
DeclarationStackAdjuster(f).use {
|
||||
DeclarationStackAdjuster(f, overriddenAttributes).use {
|
||||
|
||||
val javaCallable = getJavaCallable(f)
|
||||
getFunctionTypeParameters(f).mapIndexed { idx, tp -> extractTypeParameter(tp, idx, (javaCallable as? JavaTypeParameterListOwner)?.typeParameters?.getOrNull(idx)) }
|
||||
|
||||
val id =
|
||||
idOverride
|
||||
overriddenAttributes?.id
|
||||
?: // If this is a class that would ordinarily be replaced by a Java equivalent (e.g. kotlin.Map -> java.util.Map),
|
||||
// don't replace here, really extract the Kotlin version:
|
||||
useFunction<DbCallable>(f, parentId, classTypeArgsIncludingOuterClasses, noReplace = true)
|
||||
|
||||
val sourceDeclaration =
|
||||
if (typeSubstitution != null && idOverride == null)
|
||||
useFunction(f)
|
||||
else
|
||||
id
|
||||
overriddenAttributes?.sourceDeclarationId ?:
|
||||
if (typeSubstitution != null && overriddenAttributes?.id == null)
|
||||
useFunction(f)
|
||||
else
|
||||
id
|
||||
|
||||
val extReceiver = f.extensionReceiverParameter
|
||||
val idxOffset = if (extReceiver != null) 1 else 0
|
||||
val paramTypes = f.valueParameters.mapIndexed { i, vp ->
|
||||
extractValueParameter(vp, id, i + idxOffset, typeSubstitution, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses, locOverride)
|
||||
val fParameters = overriddenAttributes?.valueParameters ?: f.valueParameters
|
||||
val paramTypes = fParameters.mapIndexed { i, vp ->
|
||||
extractValueParameter(vp, id, i + idxOffset, typeSubstitution, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses, overriddenAttributes?.sourceLoc)
|
||||
}
|
||||
val allParamTypes = if (extReceiver != null) {
|
||||
val extendedType = useType(extReceiver.type)
|
||||
tw.writeKtExtensionFunctions(id.cast<DbMethod>(), extendedType.javaResult.id, extendedType.kotlinResult.id)
|
||||
|
||||
val t = extractValueParameter(extReceiver, id, 0, null, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses, locOverride)
|
||||
val t = extractValueParameter(extReceiver, id, 0, null, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses, overriddenAttributes?.sourceLoc)
|
||||
listOf(t) + paramTypes
|
||||
} else {
|
||||
paramTypes
|
||||
@@ -860,7 +967,7 @@ open class KotlinFileExtractor(
|
||||
val adjustedReturnType = addJavaLoweringWildcards(getAdjustedReturnType(f), false, (javaCallable as? JavaMethod)?.returnType)
|
||||
val substReturnType = typeSubstitution?.let { it(adjustedReturnType, TypeContext.RETURN, pluginContext) } ?: adjustedReturnType
|
||||
|
||||
val locId = locOverride ?: getLocation(f, classTypeArgsIncludingOuterClasses)
|
||||
val locId = overriddenAttributes?.sourceLoc ?: getLocation(f, classTypeArgsIncludingOuterClasses)
|
||||
|
||||
if (f.symbol is IrConstructorSymbol) {
|
||||
val unitType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN)
|
||||
@@ -2688,7 +2795,7 @@ open class KotlinFileExtractor(
|
||||
is IrDelegatingConstructorCall -> {
|
||||
val stmtParent = parent.stmt(e, callable)
|
||||
|
||||
val irCallable = declarationStack.peek()
|
||||
val irCallable = declarationStack.peek().first
|
||||
|
||||
val delegatingClass = e.symbol.owner.parent
|
||||
val currentClass = irCallable.parent
|
||||
@@ -2790,7 +2897,7 @@ open class KotlinFileExtractor(
|
||||
extractLoop(e, parent, callable)
|
||||
}
|
||||
is IrInstanceInitializerCall -> {
|
||||
val irConstructor = declarationStack.peek() as? IrConstructor
|
||||
val irConstructor = declarationStack.peek().first as? IrConstructor
|
||||
if (irConstructor == null) {
|
||||
logger.errorElement("IrInstanceInitializerCall outside constructor", e)
|
||||
return
|
||||
@@ -3274,10 +3381,19 @@ open class KotlinFileExtractor(
|
||||
extractTypeAccessRecursive(irType, locId, it, 0)
|
||||
}
|
||||
|
||||
private fun extractThisAccess(irType: IrType, callable: Label<out DbCallable>, parent: Label<out DbExprparent>, idx: Int, enclosingStmt: Label<out DbStmt>, locId: Label<out DbLocation>) =
|
||||
tw.getFreshIdLabel<DbThisaccess>().also {
|
||||
val type = useType(irType)
|
||||
tw.writeExprs_thisaccess(it, type.javaResult.id, parent, idx)
|
||||
tw.writeExprsKotlinType(it, type.kotlinResult.id)
|
||||
tw.writeHasLocation(it, locId)
|
||||
tw.writeCallableEnclosingExpr(it, callable)
|
||||
tw.writeStatementEnclosingExpr(it, enclosingStmt)
|
||||
}
|
||||
|
||||
private fun extractThisAccess(e: IrGetValue, exprParent: ExprParent, callable: Label<out DbCallable>) {
|
||||
val containingDeclaration = declarationStack.peek()
|
||||
val containingDeclaration = declarationStack.peek().first
|
||||
val locId = tw.getLocation(e)
|
||||
val type = useType(e.type)
|
||||
|
||||
if (containingDeclaration.shouldExtractAsStatic && containingDeclaration.parentClassOrNull?.isNonCompanionObject == true) {
|
||||
// Use of `this` in a non-companion object member that will be lowered to a static function -- replace with a reference
|
||||
@@ -3287,13 +3403,7 @@ open class KotlinFileExtractor(
|
||||
extractStaticTypeAccessQualifier(containingDeclaration, varAccessId, locId, callable, exprParent.enclosingStmt)
|
||||
}
|
||||
} else {
|
||||
val id = tw.getFreshIdLabel<DbThisaccess>()
|
||||
|
||||
tw.writeExprs_thisaccess(id, type.javaResult.id, exprParent.parent, exprParent.idx)
|
||||
tw.writeExprsKotlinType(id, type.kotlinResult.id)
|
||||
tw.writeHasLocation(id, locId)
|
||||
tw.writeCallableEnclosingExpr(id, callable)
|
||||
tw.writeStatementEnclosingExpr(id, exprParent.enclosingStmt)
|
||||
val id = extractThisAccess(e.type, callable, exprParent.parent, exprParent.idx, exprParent.enclosingStmt, locId)
|
||||
|
||||
fun extractTypeAccess(parent: IrClass) {
|
||||
extractTypeAccessRecursive(parent.typeWith(listOf()), locId, id, 0, callable, exprParent.enclosingStmt)
|
||||
@@ -3770,7 +3880,7 @@ open class KotlinFileExtractor(
|
||||
constructorBlock = tw.getFreshIdLabel()
|
||||
)
|
||||
|
||||
val declarationParent = declarationStack.peekAsDeclarationParent(propertyReferenceExpr) ?: return
|
||||
val declarationParent = peekDeclStackAsDeclarationParent(propertyReferenceExpr) ?: return
|
||||
val prefix = if (kPropertyClass.owner.name.asString().startsWith("KMutableProperty")) "Mutable" else ""
|
||||
val baseClass = pluginContext.referenceClass(FqName("kotlin.jvm.internal.${prefix}PropertyReference${kPropertyType.arguments.size - 1}"))?.owner?.typeWith()
|
||||
?: pluginContext.irBuiltIns.anyType
|
||||
@@ -3977,7 +4087,7 @@ open class KotlinFileExtractor(
|
||||
if (fnInterfaceType == null) {
|
||||
logger.warnElement("Cannot find functional interface type for function reference", functionReferenceExpr)
|
||||
} else {
|
||||
val declarationParent = declarationStack.peekAsDeclarationParent(functionReferenceExpr) ?: return
|
||||
val declarationParent = peekDeclStackAsDeclarationParent(functionReferenceExpr) ?: return
|
||||
// `FunctionReference` base class is required, because that's implementing `KFunction`.
|
||||
val baseClass = pluginContext.referenceClass(FqName("kotlin.jvm.internal.FunctionReference"))?.owner?.typeWith()
|
||||
?: pluginContext.irBuiltIns.anyType
|
||||
@@ -4586,7 +4696,7 @@ open class KotlinFileExtractor(
|
||||
val locId = tw.getLocation(e)
|
||||
val helper = GeneratedClassHelper(locId, ids)
|
||||
|
||||
val declarationParent = declarationStack.peekAsDeclarationParent(e) ?: return
|
||||
val declarationParent = peekDeclStackAsDeclarationParent(e) ?: return
|
||||
val classId = extractGeneratedClass(ids, listOf(pluginContext.irBuiltIns.anyType, e.typeOperand), locId, e, declarationParent)
|
||||
|
||||
// add field
|
||||
@@ -4610,7 +4720,7 @@ open class KotlinFileExtractor(
|
||||
// we would need to compose generic type substitutions -- for example, if we're implementing
|
||||
// T UnaryOperator<T>.apply(T t) here, we would need to compose substitutions so we can implement
|
||||
// the real underlying R Function<T, R>.apply(T t).
|
||||
forceExtractFunction(samMember, classId, extractBody = false, extractMethodAndParameterTypeAccesses = true, typeSub, classTypeArgs, ids.function, tw.getLocation(e))
|
||||
forceExtractFunction(samMember, classId, extractBody = false, extractMethodAndParameterTypeAccesses = true, typeSub, classTypeArgs, overriddenAttributes = OverriddenFunctionAttributes(id = ids.function, sourceLoc = tw.getLocation(e)))
|
||||
|
||||
if (st.isSuspendFunctionOrKFunction()) {
|
||||
addModifiers(ids.function, "suspend")
|
||||
@@ -4798,13 +4908,19 @@ open class KotlinFileExtractor(
|
||||
}
|
||||
}
|
||||
|
||||
// todo: calculating the enclosing ref type could be done through this, instead of walking up the declaration parent chain
|
||||
private val declarationStack = DeclarationStack()
|
||||
private inner class DeclarationStackAdjuster(val declaration: IrDeclaration, val overriddenAttributes: OverriddenFunctionAttributes? = null): Closeable {
|
||||
init {
|
||||
declarationStack.push(declaration, overriddenAttributes)
|
||||
}
|
||||
override fun close() {
|
||||
declarationStack.pop()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class DeclarationStack {
|
||||
private val stack: Stack<IrDeclaration> = Stack()
|
||||
class DeclarationStack {
|
||||
private val stack: Stack<Pair<IrDeclaration, OverriddenFunctionAttributes?>> = Stack()
|
||||
|
||||
fun push(item: IrDeclaration) = stack.push(item)
|
||||
fun push(item: IrDeclaration, overriddenAttributes: OverriddenFunctionAttributes?) = stack.push(Pair(item, overriddenAttributes))
|
||||
|
||||
fun pop() = stack.pop()
|
||||
|
||||
@@ -4812,28 +4928,23 @@ open class KotlinFileExtractor(
|
||||
|
||||
fun peek() = stack.peek()
|
||||
|
||||
fun peekAsDeclarationParent(elementToReportOn: IrElement): IrDeclarationParent? {
|
||||
val trapWriter = tw
|
||||
if (isEmpty() && trapWriter is SourceFileTrapWriter) {
|
||||
// If the current declaration is used as a parent, we might end up with an empty stack. In this case, the source file is the parent.
|
||||
return trapWriter.irFile
|
||||
}
|
||||
|
||||
val dp = peek() as? IrDeclarationParent
|
||||
if (dp == null) {
|
||||
logger.errorElement("Couldn't find current declaration parent", elementToReportOn)
|
||||
}
|
||||
return dp
|
||||
}
|
||||
fun findOverriddenAttributes(f: IrFunction) =
|
||||
stack.firstOrNull { it.first == f } ?.second
|
||||
}
|
||||
|
||||
private inner class DeclarationStackAdjuster(declaration: IrDeclaration): Closeable {
|
||||
init {
|
||||
declarationStack.push(declaration)
|
||||
}
|
||||
override fun close() {
|
||||
declarationStack.pop()
|
||||
data class OverriddenFunctionAttributes(val id: Label<out DbCallable>? = null, val sourceDeclarationId: Label<out DbCallable>? = null, val sourceLoc: Label<DbLocation>? = null, val valueParameters: List<IrValueParameter>? = null)
|
||||
|
||||
private fun peekDeclStackAsDeclarationParent(elementToReportOn: IrElement): IrDeclarationParent? {
|
||||
val trapWriter = tw
|
||||
if (declarationStack.isEmpty() && trapWriter is SourceFileTrapWriter) {
|
||||
// If the current declaration is used as a parent, we might end up with an empty stack. In this case, the source file is the parent.
|
||||
return trapWriter.irFile
|
||||
}
|
||||
|
||||
val dp = declarationStack.peek().first as? IrDeclarationParent
|
||||
if (dp == null)
|
||||
logger.errorElement("Couldn't find current declaration parent", elementToReportOn)
|
||||
return dp
|
||||
}
|
||||
|
||||
private enum class CompilerGeneratedKinds(val kind: Int) {
|
||||
@@ -4845,5 +4956,6 @@ open class KotlinFileExtractor(
|
||||
DELEGATED_PROPERTY_GETTER(6),
|
||||
DELEGATED_PROPERTY_SETTER(7),
|
||||
JVMSTATIC_PROXY_METHOD(8),
|
||||
JVMOVERLOADS_METHOD(9),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ open class KotlinUsesExtractor(
|
||||
val pluginContext: IrPluginContext,
|
||||
val globalExtensionState: KotlinExtractorGlobalState
|
||||
) {
|
||||
|
||||
val javaLangObject by lazy {
|
||||
val result = pluginContext.referenceClass(FqName("java.lang.Object"))?.owner
|
||||
result?.let { extractExternalClassLater(it) }
|
||||
@@ -128,18 +127,24 @@ open class KotlinUsesExtractor(
|
||||
return this
|
||||
}
|
||||
|
||||
val newDeclarationStack =
|
||||
if (this is KotlinFileExtractor)
|
||||
this.declarationStack
|
||||
else
|
||||
KotlinFileExtractor.DeclarationStack()
|
||||
|
||||
if (clsFile == null || isExternalDeclaration(cls)) {
|
||||
val filePath = getIrClassBinaryPath(cls)
|
||||
val newTrapWriter = tw.makeFileTrapWriter(filePath, true)
|
||||
val newLoggerTrapWriter = logger.tw.makeFileTrapWriter(filePath, false)
|
||||
val newLogger = FileLogger(logger.loggerBase, newLoggerTrapWriter)
|
||||
return KotlinFileExtractor(newLogger, newTrapWriter, filePath, dependencyCollector, externalClassExtractor, primitiveTypeMapping, pluginContext, globalExtensionState)
|
||||
return KotlinFileExtractor(newLogger, newTrapWriter, filePath, dependencyCollector, externalClassExtractor, primitiveTypeMapping, pluginContext, newDeclarationStack, globalExtensionState)
|
||||
}
|
||||
|
||||
val newTrapWriter = tw.makeSourceFileTrapWriter(clsFile, true)
|
||||
val newLoggerTrapWriter = logger.tw.makeSourceFileTrapWriter(clsFile, false)
|
||||
val newLogger = FileLogger(logger.loggerBase, newLoggerTrapWriter)
|
||||
return KotlinFileExtractor(newLogger, newTrapWriter, clsFile.path, dependencyCollector, externalClassExtractor, primitiveTypeMapping, pluginContext, globalExtensionState)
|
||||
return KotlinFileExtractor(newLogger, newTrapWriter, clsFile.path, dependencyCollector, externalClassExtractor, primitiveTypeMapping, pluginContext, newDeclarationStack, globalExtensionState)
|
||||
}
|
||||
|
||||
// The Kotlin compiler internal representation of Outer<T>.Inner<S>.InnerInner<R> is InnerInner<R, S, T>. This function returns just `R`.
|
||||
@@ -1027,14 +1032,18 @@ open class KotlinUsesExtractor(
|
||||
* looked up the parent ID ourselves, we would get as ID for
|
||||
* `java.lang.Throwable`, which isn't what we want. So we have to
|
||||
* allow it to be passed in.
|
||||
*/
|
||||
*
|
||||
* `maybeParameterList` can be supplied to override the function's
|
||||
* value parameters; this is used for generating labels of overloads
|
||||
* that omit one or more parameters that has a default value specified.
|
||||
*/
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
fun getFunctionLabel(f: IrFunction, maybeParentId: Label<out DbElement>?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?) =
|
||||
fun getFunctionLabel(f: IrFunction, maybeParentId: Label<out DbElement>?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, maybeParameterList: List<IrValueParameter>? = null) =
|
||||
getFunctionLabel(
|
||||
f.parent,
|
||||
maybeParentId,
|
||||
getFunctionShortName(f).nameInDB,
|
||||
f.valueParameters,
|
||||
maybeParameterList ?: f.valueParameters,
|
||||
getAdjustedReturnType(f),
|
||||
f.extensionReceiverParameter,
|
||||
getFunctionTypeParameters(f),
|
||||
@@ -1437,6 +1446,12 @@ open class KotlinUsesExtractor(
|
||||
|
||||
fun getTypeParameterParentLabel(param: IrTypeParameter) =
|
||||
param.parent.let {
|
||||
(it as? IrFunction)?.let { fn ->
|
||||
if (this is KotlinFileExtractor)
|
||||
this.declarationStack.findOverriddenAttributes(fn)?.id
|
||||
else
|
||||
null
|
||||
} ?:
|
||||
when (it) {
|
||||
is IrClass -> useClassSource(it)
|
||||
is IrFunction -> useFunction(it, noReplace = true)
|
||||
@@ -1574,13 +1589,21 @@ open class KotlinUsesExtractor(
|
||||
*/
|
||||
fun getValueParameterLabel(vp: IrValueParameter, parent: Label<out DbCallable>?): String {
|
||||
val declarationParent = vp.parent
|
||||
val parentId = parent ?: useDeclarationParent(declarationParent, false)
|
||||
val overriddenParentAttributes = (declarationParent as? IrFunction)?.let {
|
||||
if (this is KotlinFileExtractor)
|
||||
this.declarationStack.findOverriddenAttributes(it)
|
||||
else
|
||||
null
|
||||
}
|
||||
val parentId = parent ?: overriddenParentAttributes?.id ?: useDeclarationParent(declarationParent, false)
|
||||
|
||||
val idx = if (declarationParent is IrFunction && declarationParent.extensionReceiverParameter != null)
|
||||
val idxBase = overriddenParentAttributes?.valueParameters?.indexOf(vp) ?: vp.index
|
||||
val idxOffset = if (declarationParent is IrFunction && declarationParent.extensionReceiverParameter != null)
|
||||
// For extension functions increase the index to match what the java extractor sees:
|
||||
vp.index + 1
|
||||
1
|
||||
else
|
||||
vp.index
|
||||
0
|
||||
val idx = idxBase + idxOffset
|
||||
|
||||
if (idx < 0) {
|
||||
// We're not extracting this and this@TYPE parameters of functions:
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
public class User {
|
||||
|
||||
public static String source() { return "taint"; }
|
||||
|
||||
public static void test(Test2 t2, GenericTest<Integer> gt) {
|
||||
|
||||
Test.taintSuppliedAsDefault(1, "no taint", 2);
|
||||
Test.taintSuppliedAsDefault(1, 2);
|
||||
Test.noTaintByDefault(1, source(), 2, 3);
|
||||
Test.noTaintByDefault(1, source(), 2);
|
||||
|
||||
Test2.taintSuppliedAsDefaultStatic(1, "no taint", 2);
|
||||
Test2.taintSuppliedAsDefaultStatic(1, 2);
|
||||
Test2.noTaintByDefaultStatic(1, source(), 2, 3);
|
||||
Test2.noTaintByDefaultStatic(1, source(), 2);
|
||||
|
||||
t2.taintSuppliedAsDefault(1, "no taint", 2);
|
||||
t2.taintSuppliedAsDefault(1, 2);
|
||||
t2.noTaintByDefault(1, source(), 2, 3);
|
||||
t2.noTaintByDefault(1, source(), 2);
|
||||
|
||||
gt.taintSuppliedAsDefault(1, "no taint", 2);
|
||||
gt.taintSuppliedAsDefault(1, 2);
|
||||
gt.noTaintByDefault(1, source(), 2, 3);
|
||||
gt.noTaintByDefault(1, source(), 2);
|
||||
|
||||
new ConstructorTaintsByDefault(1, "no taint", 2);
|
||||
new ConstructorTaintsByDefault(1, 2);
|
||||
new ConstructorDoesNotTaintByDefault(1, source(), 2, 3);
|
||||
new ConstructorDoesNotTaintByDefault(1, source(), 2);
|
||||
|
||||
new GenericConstructorTaintsByDefault<Integer>(1, "no taint", 2);
|
||||
new GenericConstructorTaintsByDefault<Integer>(1, 2);
|
||||
new GenericConstructorDoesNotTaintByDefault<Integer>(1, source(), 2, 3);
|
||||
new GenericConstructorDoesNotTaintByDefault<Integer>(1, source(), 2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
| User.java:9:30:9:37 | source(...) | test.kt:13:97:13:97 | s |
|
||||
| User.java:10:30:10:37 | source(...) | test.kt:13:97:13:97 | s |
|
||||
| User.java:14:37:14:44 | source(...) | test.kt:25:105:25:105 | s |
|
||||
| User.java:15:37:15:44 | source(...) | test.kt:25:105:25:105 | s |
|
||||
| User.java:19:28:19:35 | source(...) | test.kt:33:97:33:97 | s |
|
||||
| User.java:20:28:20:35 | source(...) | test.kt:33:97:33:97 | s |
|
||||
| User.java:24:28:24:35 | source(...) | test.kt:43:93:43:93 | s |
|
||||
| User.java:25:28:25:35 | source(...) | test.kt:43:93:43:93 | s |
|
||||
| User.java:29:45:29:52 | source(...) | test.kt:58:10:58:10 | s |
|
||||
| User.java:30:45:30:52 | source(...) | test.kt:58:10:58:10 | s |
|
||||
| User.java:34:61:34:68 | source(...) | test.kt:74:10:74:10 | s |
|
||||
| User.java:35:61:35:68 | source(...) | test.kt:74:10:74:10 | s |
|
||||
| test.kt:10:55:10:62 | source(...) | test.kt:10:84:10:84 | s |
|
||||
| test.kt:22:63:22:70 | source(...) | test.kt:22:92:22:92 | s |
|
||||
| test.kt:22:63:22:70 | source(...) | test.kt:22:92:22:92 | s |
|
||||
| test.kt:30:55:30:62 | source(...) | test.kt:30:84:30:84 | s |
|
||||
| test.kt:40:53:40:60 | source(...) | test.kt:40:80:40:80 | s |
|
||||
| test.kt:47:92:47:99 | source(...) | test.kt:50:10:50:10 | s |
|
||||
| test.kt:63:100:63:107 | source(...) | test.kt:66:10:66:10 | s |
|
||||
@@ -0,0 +1,78 @@
|
||||
fun getString() = "Hello world"
|
||||
|
||||
fun source() = "tainted"
|
||||
|
||||
fun sink(s: String) { }
|
||||
|
||||
object Test {
|
||||
|
||||
@JvmOverloads @JvmStatic
|
||||
fun taintSuppliedAsDefault(before: Int, s: String = source(), after: Int) { sink(s) }
|
||||
|
||||
@JvmOverloads @JvmStatic
|
||||
fun noTaintByDefault(before: Int, s: String = "no taint", after: Int, after2: Int = 1) { sink(s) }
|
||||
|
||||
}
|
||||
|
||||
public class Test2 {
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmOverloads @JvmStatic
|
||||
fun taintSuppliedAsDefaultStatic(before: Int, s: String = source(), after: Int) { sink(s) }
|
||||
|
||||
@JvmOverloads @JvmStatic
|
||||
fun noTaintByDefaultStatic(before: Int, s: String = "no taint", after: Int, after2: Int = 1) { sink(s) }
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun taintSuppliedAsDefault(before: Int, s: String = source(), after: Int) { sink(s) }
|
||||
|
||||
@JvmOverloads
|
||||
fun noTaintByDefault(before: Int, s: String = "no taint", after: Int, after2: Int = 1) { sink(s) }
|
||||
|
||||
}
|
||||
|
||||
public class GenericTest<T> {
|
||||
|
||||
@JvmOverloads
|
||||
fun taintSuppliedAsDefault(before: T, s: String = source(), after: T) { sink(s) }
|
||||
|
||||
@JvmOverloads
|
||||
fun noTaintByDefault(before: T, s: String = "no taint", after: T, after2: Int = 1) { sink(s) }
|
||||
|
||||
}
|
||||
|
||||
public class ConstructorTaintsByDefault @JvmOverloads constructor(before: Int, s: String = source(), after: Int) {
|
||||
|
||||
init {
|
||||
sink(s)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class ConstructorDoesNotTaintByDefault @JvmOverloads constructor(before: Int, s: String = "no taint", after: Int, after2: Int = 1) {
|
||||
|
||||
init {
|
||||
sink(s)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class GenericConstructorTaintsByDefault<T> @JvmOverloads constructor(before: T, s: String = source(), after: T) {
|
||||
|
||||
init {
|
||||
sink(s)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class GenericConstructorDoesNotTaintByDefault<T> @JvmOverloads constructor(before: T, s: String = "no taint", after: T, after2: T? = null) {
|
||||
|
||||
init {
|
||||
sink(s)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
from create_database_utils import *
|
||||
|
||||
os.mkdir('kbuild')
|
||||
run_codeql_database_create(["kotlinc test.kt -d kbuild", "javac User.java -cp kbuild"], lang="java")
|
||||
@@ -0,0 +1,18 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
class Config extends DataFlow::Configuration {
|
||||
Config() { this = "config" }
|
||||
|
||||
override predicate isSource(DataFlow::Node n) {
|
||||
n.asExpr().(MethodAccess).getCallee().getName() = "source"
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node n) {
|
||||
n.asExpr().(Argument).getCall().getCallee().getName() = "sink"
|
||||
}
|
||||
}
|
||||
|
||||
from Config c, DataFlow::Node source, DataFlow::Node sink
|
||||
where c.hasFlow(source, sink)
|
||||
select source, sink
|
||||
@@ -63,6 +63,8 @@ class Element extends @element, Top {
|
||||
i = 7 and result = "Setter for a Kotlin delegated property"
|
||||
or
|
||||
i = 8 and result = "Proxy static method for a @JvmStatic-annotated function or property"
|
||||
or
|
||||
i = 9 and result = "Forwarder for a @JvmOverloads-annotated function"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,591 @@
|
||||
test.kt:
|
||||
# 0| [CompilationUnit] test
|
||||
# 0| 1: [Class] TestKt
|
||||
# 1| 1: [Method] getString
|
||||
# 1| 3: [TypeAccess] String
|
||||
# 1| 5: [BlockStmt] { ... }
|
||||
# 1| 0: [ReturnStmt] return ...
|
||||
# 1| 0: [StringLiteral] Hello world
|
||||
# 45| 2: [ExtensionMethod] testExtensionFunction
|
||||
# 45| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 45| 0: [Parameter] <this>
|
||||
# 45| 0: [TypeAccess] Test
|
||||
# 45| 1: [Parameter] a
|
||||
# 45| 0: [TypeAccess] int
|
||||
# 45| 2: [Parameter] c
|
||||
# 45| 0: [TypeAccess] double
|
||||
# 45| 3: [Parameter] e
|
||||
# 45| 0: [TypeAccess] boolean
|
||||
# 45| 5: [BlockStmt] { ... }
|
||||
# 45| 0: [ReturnStmt] return ...
|
||||
# 45| 0: [MethodAccess] testExtensionFunction(...)
|
||||
# 45| -1: [TypeAccess] TestKt
|
||||
# 45| 0: [ExtensionReceiverAccess] this
|
||||
# 45| 1: [VarAccess] a
|
||||
# 45| 2: [MethodAccess] getString(...)
|
||||
# 45| -1: [TypeAccess] TestKt
|
||||
# 45| 3: [VarAccess] c
|
||||
# 45| 4: [FloatLiteral] 1.0
|
||||
# 45| 5: [VarAccess] e
|
||||
# 45| 3: [ExtensionMethod] testExtensionFunction
|
||||
# 45| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 45| 0: [Parameter] <this>
|
||||
# 45| 0: [TypeAccess] Test
|
||||
# 45| 1: [Parameter] a
|
||||
# 45| 0: [TypeAccess] int
|
||||
# 45| 2: [Parameter] b
|
||||
# 45| 0: [TypeAccess] String
|
||||
# 45| 3: [Parameter] c
|
||||
# 45| 0: [TypeAccess] double
|
||||
# 45| 4: [Parameter] e
|
||||
# 45| 0: [TypeAccess] boolean
|
||||
# 45| 5: [BlockStmt] { ... }
|
||||
# 45| 0: [ReturnStmt] return ...
|
||||
# 45| 0: [MethodAccess] testExtensionFunction(...)
|
||||
# 45| -1: [TypeAccess] TestKt
|
||||
# 45| 0: [ExtensionReceiverAccess] this
|
||||
# 45| 1: [VarAccess] a
|
||||
# 45| 2: [VarAccess] b
|
||||
# 45| 3: [VarAccess] c
|
||||
# 45| 4: [FloatLiteral] 1.0
|
||||
# 45| 5: [VarAccess] e
|
||||
# 45| 4: [ExtensionMethod] testExtensionFunction
|
||||
# 45| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 45| 0: [Parameter] <this>
|
||||
# 45| 0: [TypeAccess] Test
|
||||
# 45| 1: [Parameter] a
|
||||
# 45| 0: [TypeAccess] int
|
||||
# 45| 2: [Parameter] b
|
||||
# 45| 0: [TypeAccess] String
|
||||
# 45| 3: [Parameter] c
|
||||
# 45| 0: [TypeAccess] double
|
||||
# 45| 4: [Parameter] d
|
||||
# 45| 0: [TypeAccess] float
|
||||
# 45| 5: [Parameter] e
|
||||
# 45| 0: [TypeAccess] boolean
|
||||
# 45| 5: [BlockStmt] { ... }
|
||||
# 45| 0: [ReturnStmt] return ...
|
||||
# 45| 0: [VarAccess] a
|
||||
# 3| 2: [Class] Test
|
||||
# 3| 1: [Constructor] Test
|
||||
# 3| 5: [BlockStmt] { ... }
|
||||
# 3| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 3| 1: [BlockStmt] { ... }
|
||||
# 6| 2: [Method] testStaticFunction
|
||||
# 6| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 6| 0: [Parameter] a
|
||||
# 6| 0: [TypeAccess] int
|
||||
# 6| 1: [Parameter] c
|
||||
# 6| 0: [TypeAccess] double
|
||||
# 6| 2: [Parameter] e
|
||||
# 6| 0: [TypeAccess] boolean
|
||||
# 6| 5: [BlockStmt] { ... }
|
||||
# 6| 0: [ReturnStmt] return ...
|
||||
# 6| 0: [MethodAccess] testStaticFunction(...)
|
||||
# 6| -1: [TypeAccess] Test
|
||||
# 6| 0: [VarAccess] a
|
||||
# 6| 1: [MethodAccess] getString(...)
|
||||
# 6| -1: [TypeAccess] TestKt
|
||||
# 6| 2: [VarAccess] c
|
||||
# 6| 3: [FloatLiteral] 1.0
|
||||
# 6| 4: [VarAccess] e
|
||||
# 6| 3: [Method] testStaticFunction
|
||||
# 6| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 6| 0: [Parameter] a
|
||||
# 6| 0: [TypeAccess] int
|
||||
# 6| 1: [Parameter] b
|
||||
# 6| 0: [TypeAccess] String
|
||||
# 6| 2: [Parameter] c
|
||||
# 6| 0: [TypeAccess] double
|
||||
# 6| 3: [Parameter] e
|
||||
# 6| 0: [TypeAccess] boolean
|
||||
# 6| 5: [BlockStmt] { ... }
|
||||
# 6| 0: [ReturnStmt] return ...
|
||||
# 6| 0: [MethodAccess] testStaticFunction(...)
|
||||
# 6| -1: [TypeAccess] Test
|
||||
# 6| 0: [VarAccess] a
|
||||
# 6| 1: [VarAccess] b
|
||||
# 6| 2: [VarAccess] c
|
||||
# 6| 3: [FloatLiteral] 1.0
|
||||
# 6| 4: [VarAccess] e
|
||||
# 6| 4: [Method] testStaticFunction
|
||||
# 6| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 6| 0: [Parameter] a
|
||||
# 6| 0: [TypeAccess] int
|
||||
# 6| 1: [Parameter] b
|
||||
# 6| 0: [TypeAccess] String
|
||||
# 6| 2: [Parameter] c
|
||||
# 6| 0: [TypeAccess] double
|
||||
# 6| 3: [Parameter] d
|
||||
# 6| 0: [TypeAccess] float
|
||||
# 6| 4: [Parameter] e
|
||||
# 6| 0: [TypeAccess] boolean
|
||||
# 6| 5: [BlockStmt] { ... }
|
||||
# 6| 0: [ReturnStmt] return ...
|
||||
# 6| 0: [VarAccess] a
|
||||
# 9| 5: [Method] testMemberFunction
|
||||
# 9| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 9| 0: [Parameter] a
|
||||
# 9| 0: [TypeAccess] int
|
||||
# 9| 1: [Parameter] c
|
||||
# 9| 0: [TypeAccess] double
|
||||
# 9| 2: [Parameter] e
|
||||
# 9| 0: [TypeAccess] boolean
|
||||
# 9| 5: [BlockStmt] { ... }
|
||||
# 9| 0: [ReturnStmt] return ...
|
||||
# 9| 0: [MethodAccess] testMemberFunction(...)
|
||||
# 9| -1: [ThisAccess] this
|
||||
# 9| 0: [VarAccess] a
|
||||
# 9| 1: [MethodAccess] getString(...)
|
||||
# 9| -1: [TypeAccess] TestKt
|
||||
# 9| 2: [VarAccess] c
|
||||
# 9| 3: [FloatLiteral] 1.0
|
||||
# 9| 4: [VarAccess] e
|
||||
# 9| 6: [Method] testMemberFunction
|
||||
# 9| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 9| 0: [Parameter] a
|
||||
# 9| 0: [TypeAccess] int
|
||||
# 9| 1: [Parameter] b
|
||||
# 9| 0: [TypeAccess] String
|
||||
# 9| 2: [Parameter] c
|
||||
# 9| 0: [TypeAccess] double
|
||||
# 9| 3: [Parameter] e
|
||||
# 9| 0: [TypeAccess] boolean
|
||||
# 9| 5: [BlockStmt] { ... }
|
||||
# 9| 0: [ReturnStmt] return ...
|
||||
# 9| 0: [MethodAccess] testMemberFunction(...)
|
||||
# 9| -1: [ThisAccess] this
|
||||
# 9| 0: [VarAccess] a
|
||||
# 9| 1: [VarAccess] b
|
||||
# 9| 2: [VarAccess] c
|
||||
# 9| 3: [FloatLiteral] 1.0
|
||||
# 9| 4: [VarAccess] e
|
||||
# 9| 7: [Method] testMemberFunction
|
||||
# 9| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 9| 0: [Parameter] a
|
||||
# 9| 0: [TypeAccess] int
|
||||
# 9| 1: [Parameter] b
|
||||
# 9| 0: [TypeAccess] String
|
||||
# 9| 2: [Parameter] c
|
||||
# 9| 0: [TypeAccess] double
|
||||
# 9| 3: [Parameter] d
|
||||
# 9| 0: [TypeAccess] float
|
||||
# 9| 4: [Parameter] e
|
||||
# 9| 0: [TypeAccess] boolean
|
||||
# 9| 5: [BlockStmt] { ... }
|
||||
# 9| 0: [ReturnStmt] return ...
|
||||
# 9| 0: [VarAccess] a
|
||||
# 12| 8: [ExtensionMethod] testMemberExtensionFunction
|
||||
# 12| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 12| 0: [Parameter] <this>
|
||||
# 12| 0: [TypeAccess] Test2
|
||||
# 12| 1: [Parameter] a
|
||||
# 12| 0: [TypeAccess] int
|
||||
# 12| 2: [Parameter] c
|
||||
# 12| 0: [TypeAccess] double
|
||||
# 12| 3: [Parameter] e
|
||||
# 12| 0: [TypeAccess] boolean
|
||||
# 12| 5: [BlockStmt] { ... }
|
||||
# 12| 0: [ReturnStmt] return ...
|
||||
# 12| 0: [MethodAccess] testMemberExtensionFunction(...)
|
||||
# 12| -1: [ThisAccess] this
|
||||
# 12| 0: [ExtensionReceiverAccess] this
|
||||
# 12| 1: [VarAccess] a
|
||||
# 12| 2: [MethodAccess] getString(...)
|
||||
# 12| -1: [TypeAccess] TestKt
|
||||
# 12| 3: [VarAccess] c
|
||||
# 12| 4: [FloatLiteral] 1.0
|
||||
# 12| 5: [VarAccess] e
|
||||
# 12| 9: [ExtensionMethod] testMemberExtensionFunction
|
||||
# 12| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 12| 0: [Parameter] <this>
|
||||
# 12| 0: [TypeAccess] Test2
|
||||
# 12| 1: [Parameter] a
|
||||
# 12| 0: [TypeAccess] int
|
||||
# 12| 2: [Parameter] b
|
||||
# 12| 0: [TypeAccess] String
|
||||
# 12| 3: [Parameter] c
|
||||
# 12| 0: [TypeAccess] double
|
||||
# 12| 4: [Parameter] e
|
||||
# 12| 0: [TypeAccess] boolean
|
||||
# 12| 5: [BlockStmt] { ... }
|
||||
# 12| 0: [ReturnStmt] return ...
|
||||
# 12| 0: [MethodAccess] testMemberExtensionFunction(...)
|
||||
# 12| -1: [ThisAccess] this
|
||||
# 12| 0: [ExtensionReceiverAccess] this
|
||||
# 12| 1: [VarAccess] a
|
||||
# 12| 2: [VarAccess] b
|
||||
# 12| 3: [VarAccess] c
|
||||
# 12| 4: [FloatLiteral] 1.0
|
||||
# 12| 5: [VarAccess] e
|
||||
# 12| 10: [ExtensionMethod] testMemberExtensionFunction
|
||||
# 12| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 12| 0: [Parameter] <this>
|
||||
# 12| 0: [TypeAccess] Test2
|
||||
# 12| 1: [Parameter] a
|
||||
# 12| 0: [TypeAccess] int
|
||||
# 12| 2: [Parameter] b
|
||||
# 12| 0: [TypeAccess] String
|
||||
# 12| 3: [Parameter] c
|
||||
# 12| 0: [TypeAccess] double
|
||||
# 12| 4: [Parameter] d
|
||||
# 12| 0: [TypeAccess] float
|
||||
# 12| 5: [Parameter] e
|
||||
# 12| 0: [TypeAccess] boolean
|
||||
# 12| 5: [BlockStmt] { ... }
|
||||
# 12| 0: [ReturnStmt] return ...
|
||||
# 12| 0: [VarAccess] a
|
||||
# 16| 3: [Class] Test2
|
||||
# 16| 1: [Constructor] Test2
|
||||
#-----| 4: (Parameters)
|
||||
# 16| 0: [Parameter] a
|
||||
# 16| 0: [TypeAccess] int
|
||||
# 16| 1: [Parameter] c
|
||||
# 16| 0: [TypeAccess] double
|
||||
# 16| 2: [Parameter] e
|
||||
# 16| 0: [TypeAccess] boolean
|
||||
# 16| 5: [BlockStmt] { ... }
|
||||
# 16| 0: [ThisConstructorInvocationStmt] this(...)
|
||||
# 16| 0: [VarAccess] a
|
||||
# 16| 1: [MethodAccess] getString(...)
|
||||
# 16| -1: [TypeAccess] TestKt
|
||||
# 16| 2: [VarAccess] c
|
||||
# 16| 3: [FloatLiteral] 1.0
|
||||
# 16| 4: [VarAccess] e
|
||||
# 16| 2: [Constructor] Test2
|
||||
#-----| 4: (Parameters)
|
||||
# 16| 0: [Parameter] a
|
||||
# 16| 0: [TypeAccess] int
|
||||
# 16| 1: [Parameter] b
|
||||
# 16| 0: [TypeAccess] String
|
||||
# 16| 2: [Parameter] c
|
||||
# 16| 0: [TypeAccess] double
|
||||
# 16| 3: [Parameter] e
|
||||
# 16| 0: [TypeAccess] boolean
|
||||
# 16| 5: [BlockStmt] { ... }
|
||||
# 16| 0: [ThisConstructorInvocationStmt] this(...)
|
||||
# 16| 0: [VarAccess] a
|
||||
# 16| 1: [VarAccess] b
|
||||
# 16| 2: [VarAccess] c
|
||||
# 16| 3: [FloatLiteral] 1.0
|
||||
# 16| 4: [VarAccess] e
|
||||
# 16| 3: [Constructor] Test2
|
||||
#-----| 4: (Parameters)
|
||||
# 16| 0: [Parameter] a
|
||||
# 16| 0: [TypeAccess] int
|
||||
# 16| 1: [Parameter] b
|
||||
# 16| 0: [TypeAccess] String
|
||||
# 16| 2: [Parameter] c
|
||||
# 16| 0: [TypeAccess] double
|
||||
# 16| 3: [Parameter] d
|
||||
# 16| 0: [TypeAccess] float
|
||||
# 16| 4: [Parameter] e
|
||||
# 16| 0: [TypeAccess] boolean
|
||||
# 16| 5: [BlockStmt] { ... }
|
||||
# 16| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 16| 1: [BlockStmt] { ... }
|
||||
# 18| 4: [Class] Companion
|
||||
# 18| 1: [Constructor] Companion
|
||||
# 18| 5: [BlockStmt] { ... }
|
||||
# 18| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 18| 1: [BlockStmt] { ... }
|
||||
# 21| 2: [Method] testCompanionFunction
|
||||
# 21| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 21| 0: [Parameter] a
|
||||
# 21| 0: [TypeAccess] int
|
||||
# 21| 1: [Parameter] c
|
||||
# 21| 0: [TypeAccess] double
|
||||
# 21| 2: [Parameter] e
|
||||
# 21| 0: [TypeAccess] boolean
|
||||
# 21| 5: [BlockStmt] { ... }
|
||||
# 21| 0: [ReturnStmt] return ...
|
||||
# 21| 0: [MethodAccess] testCompanionFunction(...)
|
||||
# 21| -1: [ThisAccess] this
|
||||
# 21| 0: [VarAccess] a
|
||||
# 21| 1: [MethodAccess] getString(...)
|
||||
# 21| -1: [TypeAccess] TestKt
|
||||
# 21| 2: [VarAccess] c
|
||||
# 21| 3: [FloatLiteral] 1.0
|
||||
# 21| 4: [VarAccess] e
|
||||
# 21| 3: [Method] testCompanionFunction
|
||||
# 21| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 21| 0: [Parameter] a
|
||||
# 21| 0: [TypeAccess] int
|
||||
# 21| 1: [Parameter] b
|
||||
# 21| 0: [TypeAccess] String
|
||||
# 21| 2: [Parameter] c
|
||||
# 21| 0: [TypeAccess] double
|
||||
# 21| 3: [Parameter] e
|
||||
# 21| 0: [TypeAccess] boolean
|
||||
# 21| 5: [BlockStmt] { ... }
|
||||
# 21| 0: [ReturnStmt] return ...
|
||||
# 21| 0: [MethodAccess] testCompanionFunction(...)
|
||||
# 21| -1: [ThisAccess] this
|
||||
# 21| 0: [VarAccess] a
|
||||
# 21| 1: [VarAccess] b
|
||||
# 21| 2: [VarAccess] c
|
||||
# 21| 3: [FloatLiteral] 1.0
|
||||
# 21| 4: [VarAccess] e
|
||||
# 21| 4: [Method] testCompanionFunction
|
||||
# 21| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 21| 0: [Parameter] a
|
||||
# 21| 0: [TypeAccess] int
|
||||
# 21| 1: [Parameter] b
|
||||
# 21| 0: [TypeAccess] String
|
||||
# 21| 2: [Parameter] c
|
||||
# 21| 0: [TypeAccess] double
|
||||
# 21| 3: [Parameter] d
|
||||
# 21| 0: [TypeAccess] float
|
||||
# 21| 4: [Parameter] e
|
||||
# 21| 0: [TypeAccess] boolean
|
||||
# 21| 5: [BlockStmt] { ... }
|
||||
# 21| 0: [ReturnStmt] return ...
|
||||
# 21| 0: [VarAccess] a
|
||||
# 24| 5: [Method] testStaticCompanionFunction
|
||||
# 24| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 24| 0: [Parameter] a
|
||||
# 24| 0: [TypeAccess] int
|
||||
# 24| 1: [Parameter] c
|
||||
# 24| 0: [TypeAccess] double
|
||||
# 24| 2: [Parameter] e
|
||||
# 24| 0: [TypeAccess] boolean
|
||||
# 24| 5: [BlockStmt] { ... }
|
||||
# 24| 0: [ReturnStmt] return ...
|
||||
# 24| 0: [MethodAccess] testStaticCompanionFunction(...)
|
||||
# 24| -1: [ThisAccess] this
|
||||
# 24| 0: [VarAccess] a
|
||||
# 24| 1: [MethodAccess] getString(...)
|
||||
# 24| -1: [TypeAccess] TestKt
|
||||
# 24| 2: [VarAccess] c
|
||||
# 24| 3: [FloatLiteral] 1.0
|
||||
# 24| 4: [VarAccess] e
|
||||
# 24| 6: [Method] testStaticCompanionFunction
|
||||
# 24| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 24| 0: [Parameter] a
|
||||
# 24| 0: [TypeAccess] int
|
||||
# 24| 1: [Parameter] b
|
||||
# 24| 0: [TypeAccess] String
|
||||
# 24| 2: [Parameter] c
|
||||
# 24| 0: [TypeAccess] double
|
||||
# 24| 3: [Parameter] e
|
||||
# 24| 0: [TypeAccess] boolean
|
||||
# 24| 5: [BlockStmt] { ... }
|
||||
# 24| 0: [ReturnStmt] return ...
|
||||
# 24| 0: [MethodAccess] testStaticCompanionFunction(...)
|
||||
# 24| -1: [ThisAccess] this
|
||||
# 24| 0: [VarAccess] a
|
||||
# 24| 1: [VarAccess] b
|
||||
# 24| 2: [VarAccess] c
|
||||
# 24| 3: [FloatLiteral] 1.0
|
||||
# 24| 4: [VarAccess] e
|
||||
# 24| 7: [Method] testStaticCompanionFunction
|
||||
# 24| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 24| 0: [Parameter] a
|
||||
# 24| 0: [TypeAccess] int
|
||||
# 24| 1: [Parameter] b
|
||||
# 24| 0: [TypeAccess] String
|
||||
# 24| 2: [Parameter] c
|
||||
# 24| 0: [TypeAccess] double
|
||||
# 24| 3: [Parameter] d
|
||||
# 24| 0: [TypeAccess] float
|
||||
# 24| 4: [Parameter] e
|
||||
# 24| 0: [TypeAccess] boolean
|
||||
# 24| 5: [BlockStmt] { ... }
|
||||
# 24| 0: [ReturnStmt] return ...
|
||||
# 24| 0: [VarAccess] a
|
||||
# 24| 5: [Method] testStaticCompanionFunction
|
||||
# 24| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 24| 0: [Parameter] a
|
||||
# 24| 0: [TypeAccess] int
|
||||
# 24| 1: [Parameter] c
|
||||
# 24| 0: [TypeAccess] double
|
||||
# 24| 2: [Parameter] e
|
||||
# 24| 0: [TypeAccess] boolean
|
||||
# 24| 5: [BlockStmt] { ... }
|
||||
# 24| 0: [ReturnStmt] return ...
|
||||
# 24| 0: [MethodAccess] testStaticCompanionFunction(...)
|
||||
# 24| -1: [ThisAccess] this
|
||||
# 24| 0: [VarAccess] a
|
||||
# 24| 1: [MethodAccess] getString(...)
|
||||
# 24| -1: [TypeAccess] TestKt
|
||||
# 24| 2: [VarAccess] c
|
||||
# 24| 3: [FloatLiteral] 1.0
|
||||
# 24| 4: [VarAccess] e
|
||||
# 24| 6: [Method] testStaticCompanionFunction
|
||||
# 24| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 24| 0: [Parameter] a
|
||||
# 24| 0: [TypeAccess] int
|
||||
# 24| 1: [Parameter] b
|
||||
# 24| 0: [TypeAccess] String
|
||||
# 24| 2: [Parameter] c
|
||||
# 24| 0: [TypeAccess] double
|
||||
# 24| 3: [Parameter] e
|
||||
# 24| 0: [TypeAccess] boolean
|
||||
# 24| 5: [BlockStmt] { ... }
|
||||
# 24| 0: [ReturnStmt] return ...
|
||||
# 24| 0: [MethodAccess] testStaticCompanionFunction(...)
|
||||
# 24| -1: [ThisAccess] this
|
||||
# 24| 0: [VarAccess] a
|
||||
# 24| 1: [VarAccess] b
|
||||
# 24| 2: [VarAccess] c
|
||||
# 24| 3: [FloatLiteral] 1.0
|
||||
# 24| 4: [VarAccess] e
|
||||
# 24| 7: [Method] testStaticCompanionFunction
|
||||
# 24| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 24| 0: [Parameter] a
|
||||
# 24| 0: [TypeAccess] int
|
||||
# 24| 1: [Parameter] b
|
||||
# 24| 0: [TypeAccess] String
|
||||
# 24| 2: [Parameter] c
|
||||
# 24| 0: [TypeAccess] double
|
||||
# 24| 3: [Parameter] d
|
||||
# 24| 0: [TypeAccess] float
|
||||
# 24| 4: [Parameter] e
|
||||
# 24| 0: [TypeAccess] boolean
|
||||
# 24| 5: [BlockStmt] { ... }
|
||||
# 24| 0: [ReturnStmt] return ...
|
||||
# 24| 0: [MethodAccess] testStaticCompanionFunction(...)
|
||||
# 24| -1: [VarAccess] Test2.Companion
|
||||
# 24| -1: [TypeAccess] Test2
|
||||
# 24| 0: [VarAccess] a
|
||||
# 24| 1: [VarAccess] b
|
||||
# 24| 2: [VarAccess] c
|
||||
# 24| 3: [VarAccess] d
|
||||
# 24| 4: [VarAccess] e
|
||||
# 30| 4: [Class,GenericType,ParameterizedType] GenericTest
|
||||
#-----| -2: (Generic Parameters)
|
||||
# 30| 0: [TypeVariable] T
|
||||
# 30| 1: [Constructor] GenericTest
|
||||
#-----| 4: (Parameters)
|
||||
# 30| 0: [Parameter] b
|
||||
# 30| 0: [TypeAccess] T
|
||||
# 30| 1: [Parameter] d
|
||||
# 30| 0: [TypeAccess] T
|
||||
# 30| 5: [BlockStmt] { ... }
|
||||
# 30| 0: [ThisConstructorInvocationStmt] this(...)
|
||||
# 30| 0: [IntegerLiteral] 1
|
||||
# 30| 1: [VarAccess] b
|
||||
# 30| 2: [StringLiteral] Hello world
|
||||
# 30| 3: [VarAccess] d
|
||||
# 30| 2: [Constructor] GenericTest
|
||||
#-----| 4: (Parameters)
|
||||
# 30| 0: [Parameter] a
|
||||
# 30| 0: [TypeAccess] int
|
||||
# 30| 1: [Parameter] b
|
||||
# 30| 0: [TypeAccess] T
|
||||
# 30| 2: [Parameter] d
|
||||
# 30| 0: [TypeAccess] T
|
||||
# 30| 5: [BlockStmt] { ... }
|
||||
# 30| 0: [ThisConstructorInvocationStmt] this(...)
|
||||
# 30| 0: [VarAccess] a
|
||||
# 30| 1: [VarAccess] b
|
||||
# 30| 2: [StringLiteral] Hello world
|
||||
# 30| 3: [VarAccess] d
|
||||
# 30| 3: [Constructor] GenericTest
|
||||
#-----| 4: (Parameters)
|
||||
# 30| 0: [Parameter] a
|
||||
# 30| 0: [TypeAccess] int
|
||||
# 30| 1: [Parameter] b
|
||||
# 30| 0: [TypeAccess] T
|
||||
# 30| 2: [Parameter] c
|
||||
# 30| 0: [TypeAccess] String
|
||||
# 30| 3: [Parameter] d
|
||||
# 30| 0: [TypeAccess] T
|
||||
# 30| 5: [BlockStmt] { ... }
|
||||
# 30| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 30| 1: [BlockStmt] { ... }
|
||||
# 33| 4: [Method] testMemberFunction
|
||||
# 33| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 33| 0: [Parameter] b
|
||||
# 33| 0: [TypeAccess] T
|
||||
# 33| 1: [Parameter] d
|
||||
# 33| 0: [TypeAccess] T
|
||||
# 33| 5: [BlockStmt] { ... }
|
||||
# 33| 0: [ReturnStmt] return ...
|
||||
# 33| 0: [MethodAccess] testMemberFunction(...)
|
||||
# 33| -1: [ThisAccess] this
|
||||
# 33| 0: [IntegerLiteral] 1
|
||||
# 33| 1: [VarAccess] b
|
||||
# 33| 2: [StringLiteral] Hello world
|
||||
# 33| 3: [VarAccess] d
|
||||
# 33| 5: [Method] testMemberFunction
|
||||
# 33| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 33| 0: [Parameter] a
|
||||
# 33| 0: [TypeAccess] int
|
||||
# 33| 1: [Parameter] b
|
||||
# 33| 0: [TypeAccess] T
|
||||
# 33| 2: [Parameter] d
|
||||
# 33| 0: [TypeAccess] T
|
||||
# 33| 5: [BlockStmt] { ... }
|
||||
# 33| 0: [ReturnStmt] return ...
|
||||
# 33| 0: [MethodAccess] testMemberFunction(...)
|
||||
# 33| -1: [ThisAccess] this
|
||||
# 33| 0: [VarAccess] a
|
||||
# 33| 1: [VarAccess] b
|
||||
# 33| 2: [StringLiteral] Hello world
|
||||
# 33| 3: [VarAccess] d
|
||||
# 33| 6: [Method] testMemberFunction
|
||||
# 33| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 33| 0: [Parameter] a
|
||||
# 33| 0: [TypeAccess] int
|
||||
# 33| 1: [Parameter] b
|
||||
# 33| 0: [TypeAccess] T
|
||||
# 33| 2: [Parameter] c
|
||||
# 33| 0: [TypeAccess] String
|
||||
# 33| 3: [Parameter] d
|
||||
# 33| 0: [TypeAccess] T
|
||||
# 33| 5: [BlockStmt] { ... }
|
||||
# 33| 0: [ReturnStmt] return ...
|
||||
# 33| 0: [VarAccess] a
|
||||
# 35| 7: [Method] useSpecialised
|
||||
# 35| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 35| 0: [Parameter] spec1
|
||||
# 35| 0: [TypeAccess] GenericTest<Float>
|
||||
# 35| 0: [TypeAccess] Float
|
||||
# 35| 1: [Parameter] spec2
|
||||
# 35| 0: [TypeAccess] GenericTest<Double>
|
||||
# 35| 0: [TypeAccess] Double
|
||||
# 35| 5: [BlockStmt] { ... }
|
||||
# 37| 0: [ExprStmt] <Expr>;
|
||||
# 37| 0: [ImplicitCoercionToUnitExpr] <implicit coercion to unit>
|
||||
# 37| 0: [TypeAccess] Unit
|
||||
# 37| 1: [MethodAccess] testMemberFunction(...)
|
||||
# 37| -1: [VarAccess] spec1
|
||||
# 37| 0: [IntegerLiteral] 1
|
||||
# 37| 1: [FloatLiteral] 1.0
|
||||
# 37| 2: [StringLiteral] Hello world
|
||||
# 37| 3: [FloatLiteral] 2.0
|
||||
# 38| 1: [ExprStmt] <Expr>;
|
||||
# 38| 0: [ImplicitCoercionToUnitExpr] <implicit coercion to unit>
|
||||
# 38| 0: [TypeAccess] Unit
|
||||
# 38| 1: [MethodAccess] testMemberFunction(...)
|
||||
# 38| -1: [VarAccess] spec2
|
||||
# 38| 0: [IntegerLiteral] 1
|
||||
# 38| 1: [DoubleLiteral] 1.0
|
||||
# 38| 2: [StringLiteral] Hello world
|
||||
# 38| 3: [DoubleLiteral] 2.0
|
||||
@@ -0,0 +1 @@
|
||||
semmle/code/java/PrintAst.ql
|
||||
@@ -0,0 +1,48 @@
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Double> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Double> | GenericTest<Double>(int,java.lang.Double,java.lang.Double) |
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Double> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Double> | GenericTest<Double>(int,java.lang.Double,java.lang.String,java.lang.Double) |
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Double> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Double> | GenericTest<Double>(java.lang.Double,java.lang.Double) |
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Double> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | testMemberFunction | testMemberFunction(int,java.lang.Double,java.lang.Double) |
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Double> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | testMemberFunction | testMemberFunction(int,java.lang.Double,java.lang.String,java.lang.Double) |
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Double> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | testMemberFunction | testMemberFunction(java.lang.Double,java.lang.Double) |
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Double> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | useSpecialised | useSpecialised(GenericTest,GenericTest) |
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Float> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Float> | GenericTest<Float>(int,java.lang.Float,java.lang.Float) |
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Float> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Float> | GenericTest<Float>(int,java.lang.Float,java.lang.String,java.lang.Float) |
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Float> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Float> | GenericTest<Float>(java.lang.Float,java.lang.Float) |
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Float> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | testMemberFunction | testMemberFunction(int,java.lang.Float,java.lang.Float) |
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Float> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | testMemberFunction | testMemberFunction(int,java.lang.Float,java.lang.String,java.lang.Float) |
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Float> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | testMemberFunction | testMemberFunction(java.lang.Float,java.lang.Float) |
|
||||
| file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | GenericTest<Float> | file:///!unknown-binary-location/GenericTest.class:0:0:0:0 | useSpecialised | useSpecialised(GenericTest,GenericTest) |
|
||||
| test.kt:0:0:0:0 | TestKt | test.kt:1:1:1:31 | getString | getString() |
|
||||
| test.kt:0:0:0:0 | TestKt | test.kt:45:1:45:112 | testExtensionFunction | testExtensionFunction(Test,int,double,boolean) |
|
||||
| test.kt:0:0:0:0 | TestKt | test.kt:45:1:45:112 | testExtensionFunction | testExtensionFunction(Test,int,java.lang.String,double,boolean) |
|
||||
| test.kt:0:0:0:0 | TestKt | test.kt:45:1:45:112 | testExtensionFunction | testExtensionFunction(Test,int,java.lang.String,double,float,boolean) |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:3:1:14:1 | Test | Test() |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:6:3:6:106 | testStaticFunction | testStaticFunction(int,double,boolean) |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:6:3:6:106 | testStaticFunction | testStaticFunction(int,java.lang.String,double,boolean) |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:6:3:6:106 | testStaticFunction | testStaticFunction(int,java.lang.String,double,float,boolean) |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:9:3:9:106 | testMemberFunction | testMemberFunction(int,double,boolean) |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:9:3:9:106 | testMemberFunction | testMemberFunction(int,java.lang.String,double,boolean) |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:9:3:9:106 | testMemberFunction | testMemberFunction(int,java.lang.String,double,float,boolean) |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:12:3:12:121 | testMemberExtensionFunction | testMemberExtensionFunction(Test2,int,double,boolean) |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:12:3:12:121 | testMemberExtensionFunction | testMemberExtensionFunction(Test2,int,java.lang.String,double,boolean) |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:12:3:12:121 | testMemberExtensionFunction | testMemberExtensionFunction(Test2,int,java.lang.String,double,float,boolean) |
|
||||
| test.kt:16:1:28:1 | Test2 | test.kt:16:34:28:1 | Test2 | Test2(int,double,boolean) |
|
||||
| test.kt:16:1:28:1 | Test2 | test.kt:16:34:28:1 | Test2 | Test2(int,java.lang.String,double,boolean) |
|
||||
| test.kt:16:1:28:1 | Test2 | test.kt:16:34:28:1 | Test2 | Test2(int,java.lang.String,double,float,boolean) |
|
||||
| test.kt:16:1:28:1 | Test2 | test.kt:24:5:24:117 | testStaticCompanionFunction | testStaticCompanionFunction(int,double,boolean) |
|
||||
| test.kt:16:1:28:1 | Test2 | test.kt:24:5:24:117 | testStaticCompanionFunction | testStaticCompanionFunction(int,java.lang.String,double,boolean) |
|
||||
| test.kt:16:1:28:1 | Test2 | test.kt:24:5:24:117 | testStaticCompanionFunction | testStaticCompanionFunction(int,java.lang.String,double,float,boolean) |
|
||||
| test.kt:18:3:26:3 | Companion | test.kt:18:3:26:3 | Companion | Companion() |
|
||||
| test.kt:18:3:26:3 | Companion | test.kt:21:5:21:111 | testCompanionFunction | testCompanionFunction(int,double,boolean) |
|
||||
| test.kt:18:3:26:3 | Companion | test.kt:21:5:21:111 | testCompanionFunction | testCompanionFunction(int,java.lang.String,double,boolean) |
|
||||
| test.kt:18:3:26:3 | Companion | test.kt:21:5:21:111 | testCompanionFunction | testCompanionFunction(int,java.lang.String,double,float,boolean) |
|
||||
| test.kt:18:3:26:3 | Companion | test.kt:24:5:24:117 | testStaticCompanionFunction | testStaticCompanionFunction(int,double,boolean) |
|
||||
| test.kt:18:3:26:3 | Companion | test.kt:24:5:24:117 | testStaticCompanionFunction | testStaticCompanionFunction(int,java.lang.String,double,boolean) |
|
||||
| test.kt:18:3:26:3 | Companion | test.kt:24:5:24:117 | testStaticCompanionFunction | testStaticCompanionFunction(int,java.lang.String,double,float,boolean) |
|
||||
| test.kt:30:1:42:1 | GenericTest | test.kt:30:43:42:1 | GenericTest | GenericTest(int,java.lang.Object,java.lang.Object) |
|
||||
| test.kt:30:1:42:1 | GenericTest | test.kt:30:43:42:1 | GenericTest | GenericTest(int,java.lang.Object,java.lang.String,java.lang.Object) |
|
||||
| test.kt:30:1:42:1 | GenericTest | test.kt:30:43:42:1 | GenericTest | GenericTest(java.lang.Object,java.lang.Object) |
|
||||
| test.kt:30:1:42:1 | GenericTest | test.kt:33:3:33:84 | testMemberFunction | testMemberFunction(int,java.lang.Object,java.lang.Object) |
|
||||
| test.kt:30:1:42:1 | GenericTest | test.kt:33:3:33:84 | testMemberFunction | testMemberFunction(int,java.lang.Object,java.lang.String,java.lang.Object) |
|
||||
| test.kt:30:1:42:1 | GenericTest | test.kt:33:3:33:84 | testMemberFunction | testMemberFunction(java.lang.Object,java.lang.Object) |
|
||||
| test.kt:30:1:42:1 | GenericTest | test.kt:35:3:40:3 | useSpecialised | useSpecialised(GenericTest,GenericTest) |
|
||||
@@ -0,0 +1,45 @@
|
||||
fun getString() = "Hello world"
|
||||
|
||||
object Test {
|
||||
|
||||
@JvmOverloads @JvmStatic
|
||||
fun testStaticFunction(a: Int, b: String = getString(), c: Double, d: Float = 1.0f, e: Boolean): Int = a
|
||||
|
||||
@JvmOverloads
|
||||
fun testMemberFunction(a: Int, b: String = getString(), c: Double, d: Float = 1.0f, e: Boolean): Int = a
|
||||
|
||||
@JvmOverloads
|
||||
fun Test2.testMemberExtensionFunction(a: Int, b: String = getString(), c: Double, d: Float = 1.0f, e: Boolean): Int = a
|
||||
|
||||
}
|
||||
|
||||
public class Test2 @JvmOverloads constructor(a: Int, b: String = getString(), c: Double, d: Float = 1.0f, e: Boolean) {
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmOverloads
|
||||
fun testCompanionFunction(a: Int, b: String = getString(), c: Double, d: Float = 1.0f, e: Boolean): Int = a
|
||||
|
||||
@JvmOverloads @JvmStatic
|
||||
fun testStaticCompanionFunction(a: Int, b: String = getString(), c: Double, d: Float = 1.0f, e: Boolean): Int = a
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class GenericTest<T> @JvmOverloads constructor(a: Int = 1, b: T, c: String = "Hello world", d: T) {
|
||||
|
||||
@JvmOverloads
|
||||
fun testMemberFunction(a: Int = 1, b: T, c: String = "Hello world", d: T): Int = a
|
||||
|
||||
fun useSpecialised(spec1: GenericTest<Float>, spec2: GenericTest<Double>) {
|
||||
|
||||
spec1.testMemberFunction(1, 1.0f, "Hello world", 2.0f)
|
||||
spec2.testMemberFunction(1, 1.0, "Hello world", 2.0)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun Test.testExtensionFunction(a: Int, b: String = getString(), c: Double, d: Float = 1.0f, e: Boolean): Int = a
|
||||
@@ -0,0 +1,5 @@
|
||||
import java
|
||||
|
||||
from Callable c
|
||||
where c.getSourceDeclaration().fromSource()
|
||||
select c.getDeclaringType(), c, c.getSignature()
|
||||
@@ -0,0 +1,43 @@
|
||||
public class User {
|
||||
|
||||
public static String source() { return "taint"; }
|
||||
|
||||
public static void test(Test2 t2, GenericTest<Integer> gt, TestDefaultParameterReference paramRefTest) {
|
||||
|
||||
Test.taintSuppliedAsDefault(1, "no taint", 2);
|
||||
Test.taintSuppliedAsDefault(1, 2);
|
||||
Test.noTaintByDefault(1, source(), 2, 3);
|
||||
Test.noTaintByDefault(1, source(), 2);
|
||||
|
||||
Test2.taintSuppliedAsDefaultStatic(1, "no taint", 2);
|
||||
Test2.taintSuppliedAsDefaultStatic(1, 2);
|
||||
Test2.noTaintByDefaultStatic(1, source(), 2, 3);
|
||||
Test2.noTaintByDefaultStatic(1, source(), 2);
|
||||
|
||||
t2.taintSuppliedAsDefault(1, "no taint", 2);
|
||||
t2.taintSuppliedAsDefault(1, 2);
|
||||
t2.noTaintByDefault(1, source(), 2, 3);
|
||||
t2.noTaintByDefault(1, source(), 2);
|
||||
|
||||
gt.taintSuppliedAsDefault(1, "no taint", 2);
|
||||
gt.taintSuppliedAsDefault(1, 2);
|
||||
gt.noTaintByDefault(1, source(), 2, 3);
|
||||
gt.noTaintByDefault(1, source(), 2);
|
||||
|
||||
new ConstructorTaintsByDefault(1, "no taint", 2);
|
||||
new ConstructorTaintsByDefault(1, 2);
|
||||
new ConstructorDoesNotTaintByDefault(1, source(), 2, 3);
|
||||
new ConstructorDoesNotTaintByDefault(1, source(), 2);
|
||||
|
||||
new GenericConstructorTaintsByDefault<Integer>(1, "no taint", 2);
|
||||
new GenericConstructorTaintsByDefault<Integer>(1, 2);
|
||||
new GenericConstructorDoesNotTaintByDefault<Integer>(1, source(), 2, 3);
|
||||
new GenericConstructorDoesNotTaintByDefault<Integer>(1, source(), 2);
|
||||
|
||||
paramRefTest.f(source(), "no flow");
|
||||
paramRefTest.f("flow", source());
|
||||
paramRefTest.f(source()); // Should also have flow due to the default for the second parameter being the value of the first
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
| User.java:9:30:9:37 | source(...) | test.kt:13:97:13:97 | s |
|
||||
| User.java:10:30:10:37 | source(...) | test.kt:13:97:13:97 | s |
|
||||
| User.java:14:37:14:44 | source(...) | test.kt:25:105:25:105 | s |
|
||||
| User.java:15:37:15:44 | source(...) | test.kt:25:105:25:105 | s |
|
||||
| User.java:19:28:19:35 | source(...) | test.kt:33:97:33:97 | s |
|
||||
| User.java:20:28:20:35 | source(...) | test.kt:33:97:33:97 | s |
|
||||
| User.java:24:28:24:35 | source(...) | test.kt:43:93:43:93 | s |
|
||||
| User.java:25:28:25:35 | source(...) | test.kt:43:93:43:93 | s |
|
||||
| User.java:29:45:29:52 | source(...) | test.kt:58:10:58:10 | s |
|
||||
| User.java:30:45:30:52 | source(...) | test.kt:58:10:58:10 | s |
|
||||
| User.java:34:61:34:68 | source(...) | test.kt:74:10:74:10 | s |
|
||||
| User.java:35:61:35:68 | source(...) | test.kt:74:10:74:10 | s |
|
||||
| User.java:38:28:38:35 | source(...) | test.kt:84:10:84:10 | y |
|
||||
| User.java:39:20:39:27 | source(...) | test.kt:84:10:84:10 | y |
|
||||
| test.kt:10:55:10:62 | source(...) | test.kt:10:84:10:84 | s |
|
||||
| test.kt:22:63:22:70 | source(...) | test.kt:22:92:22:92 | s |
|
||||
| test.kt:22:63:22:70 | source(...) | test.kt:22:92:22:92 | s |
|
||||
| test.kt:30:55:30:62 | source(...) | test.kt:30:84:30:84 | s |
|
||||
| test.kt:40:53:40:60 | source(...) | test.kt:40:80:40:80 | s |
|
||||
| test.kt:47:92:47:99 | source(...) | test.kt:50:10:50:10 | s |
|
||||
| test.kt:63:100:63:107 | source(...) | test.kt:66:10:66:10 | s |
|
||||
87
java/ql/test/kotlin/library-tests/jvmoverloads_flow/test.kt
Normal file
87
java/ql/test/kotlin/library-tests/jvmoverloads_flow/test.kt
Normal file
@@ -0,0 +1,87 @@
|
||||
fun getString() = "Hello world"
|
||||
|
||||
fun source() = "tainted"
|
||||
|
||||
fun sink(s: String) { }
|
||||
|
||||
object Test {
|
||||
|
||||
@JvmOverloads @JvmStatic
|
||||
fun taintSuppliedAsDefault(before: Int, s: String = source(), after: Int) { sink(s) }
|
||||
|
||||
@JvmOverloads @JvmStatic
|
||||
fun noTaintByDefault(before: Int, s: String = "no taint", after: Int, after2: Int = 1) { sink(s) }
|
||||
|
||||
}
|
||||
|
||||
public class Test2 {
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmOverloads @JvmStatic
|
||||
fun taintSuppliedAsDefaultStatic(before: Int, s: String = source(), after: Int) { sink(s) }
|
||||
|
||||
@JvmOverloads @JvmStatic
|
||||
fun noTaintByDefaultStatic(before: Int, s: String = "no taint", after: Int, after2: Int = 1) { sink(s) }
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun taintSuppliedAsDefault(before: Int, s: String = source(), after: Int) { sink(s) }
|
||||
|
||||
@JvmOverloads
|
||||
fun noTaintByDefault(before: Int, s: String = "no taint", after: Int, after2: Int = 1) { sink(s) }
|
||||
|
||||
}
|
||||
|
||||
public class GenericTest<T> {
|
||||
|
||||
@JvmOverloads
|
||||
fun taintSuppliedAsDefault(before: T, s: String = source(), after: T) { sink(s) }
|
||||
|
||||
@JvmOverloads
|
||||
fun noTaintByDefault(before: T, s: String = "no taint", after: T, after2: Int = 1) { sink(s) }
|
||||
|
||||
}
|
||||
|
||||
public class ConstructorTaintsByDefault @JvmOverloads constructor(before: Int, s: String = source(), after: Int) {
|
||||
|
||||
init {
|
||||
sink(s)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class ConstructorDoesNotTaintByDefault @JvmOverloads constructor(before: Int, s: String = "no taint", after: Int, after2: Int = 1) {
|
||||
|
||||
init {
|
||||
sink(s)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class GenericConstructorTaintsByDefault<T> @JvmOverloads constructor(before: T, s: String = source(), after: T) {
|
||||
|
||||
init {
|
||||
sink(s)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class GenericConstructorDoesNotTaintByDefault<T> @JvmOverloads constructor(before: T, s: String = "no taint", after: T, after2: T? = null) {
|
||||
|
||||
init {
|
||||
sink(s)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun ident(s: String) = s
|
||||
|
||||
public class TestDefaultParameterReference {
|
||||
|
||||
@JvmOverloads fun f(x: String, y: String = ident(x)) {
|
||||
sink(y)
|
||||
}
|
||||
|
||||
}
|
||||
18
java/ql/test/kotlin/library-tests/jvmoverloads_flow/test.ql
Normal file
18
java/ql/test/kotlin/library-tests/jvmoverloads_flow/test.ql
Normal file
@@ -0,0 +1,18 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
class Config extends DataFlow::Configuration {
|
||||
Config() { this = "config" }
|
||||
|
||||
override predicate isSource(DataFlow::Node n) {
|
||||
n.asExpr().(MethodAccess).getCallee().getName() = "source"
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node n) {
|
||||
n.asExpr().(Argument).getCall().getCallee().getName() = "sink"
|
||||
}
|
||||
}
|
||||
|
||||
from Config c, DataFlow::Node source, DataFlow::Node sink
|
||||
where c.hasFlow(source, sink)
|
||||
select source, sink
|
||||
@@ -0,0 +1,9 @@
|
||||
public class User {
|
||||
|
||||
public static void test(A a) {
|
||||
|
||||
a.genericFunctionWithOverloads(null, null);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
| test.kt:4:3:4:94 | genericFunctionWithOverloads | genericFunctionWithOverloads() | return | T | genericFunctionWithOverloads() |
|
||||
| test.kt:4:3:4:94 | genericFunctionWithOverloads | genericFunctionWithOverloads(java.lang.Object) | param | T | genericFunctionWithOverloads(java.lang.Object) |
|
||||
| test.kt:4:3:4:94 | genericFunctionWithOverloads | genericFunctionWithOverloads(java.lang.Object) | return | T | genericFunctionWithOverloads(java.lang.Object) |
|
||||
| test.kt:4:3:4:94 | genericFunctionWithOverloads | genericFunctionWithOverloads(java.lang.Object,java.util.List) | param | List<? extends T> | genericFunctionWithOverloads(java.lang.Object,java.util.List) |
|
||||
| test.kt:4:3:4:94 | genericFunctionWithOverloads | genericFunctionWithOverloads(java.lang.Object,java.util.List) | param | T | genericFunctionWithOverloads(java.lang.Object,java.util.List) |
|
||||
| test.kt:4:3:4:94 | genericFunctionWithOverloads | genericFunctionWithOverloads(java.lang.Object,java.util.List) | return | T | genericFunctionWithOverloads(java.lang.Object,java.util.List) |
|
||||
| test.kt:4:3:4:94 | genericFunctionWithOverloads | genericFunctionWithOverloads(java.lang.Object,java.util.List,java.lang.Object) | param | List<? extends T> | genericFunctionWithOverloads(java.lang.Object,java.util.List,java.lang.Object) |
|
||||
| test.kt:4:3:4:94 | genericFunctionWithOverloads | genericFunctionWithOverloads(java.lang.Object,java.util.List,java.lang.Object) | param | T | genericFunctionWithOverloads(java.lang.Object,java.util.List,java.lang.Object) |
|
||||
| test.kt:4:3:4:94 | genericFunctionWithOverloads | genericFunctionWithOverloads(java.lang.Object,java.util.List,java.lang.Object) | return | T | genericFunctionWithOverloads(java.lang.Object,java.util.List,java.lang.Object) |
|
||||
@@ -0,0 +1,6 @@
|
||||
public class A {
|
||||
|
||||
@JvmOverloads
|
||||
fun <T> genericFunctionWithOverloads(x: T? = null, y: List<T>? = null, z: T? = null): T? = z
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import java
|
||||
|
||||
from Method m, string kind, Type t
|
||||
where
|
||||
m.fromSource() and
|
||||
(
|
||||
kind = "param" and t = m.getAParamType()
|
||||
or
|
||||
kind = "return" and t = m.getReturnType()
|
||||
)
|
||||
// 't.(ParameterizedType).getATypeArgument().(Wildcard).getUpperBound().getType()' is pulling the 'T' out of 'List<? extends T>'
|
||||
select m, m.getSignature(), kind, t.toString(),
|
||||
[t, t.(ParameterizedType).getATypeArgument().(Wildcard).getUpperBound().getType()]
|
||||
.(TypeVariable)
|
||||
.getGenericCallable()
|
||||
.getSignature()
|
||||
Reference in New Issue
Block a user