mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
Implement $default method synthesis
This adds methods that fill in default parameters whenever a constructor or method uses default parameter values. I use as similar an approach to the real Kotlin compiler as possible both because this produces the desirable dataflow, and because it should merge cleanly with the same class file seen by the Java extractor, which will see and extract the signatures of the default methods.
This commit is contained in:
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
@@ -688,7 +689,7 @@ open class KotlinFileExtractor(
|
||||
"<clinit>",
|
||||
listOf(),
|
||||
pluginContext.irBuiltIns.unitType,
|
||||
extensionReceiverParameter = null,
|
||||
extensionParamType = null,
|
||||
functionTypeParameters = listOf(),
|
||||
classTypeArgsIncludingOuterClasses = listOf(),
|
||||
overridesCollectionsMethod = false,
|
||||
@@ -832,10 +833,117 @@ open class KotlinFileExtractor(
|
||||
null
|
||||
else {
|
||||
forceExtractFunction(f, parentId, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses).also {
|
||||
// The defaults-forwarder function is a static utility, not a member, so we only need to extract this for the unspecialised instance of this class.
|
||||
if (classTypeArgsIncludingOuterClasses.isNullOrEmpty())
|
||||
extractDefaultsFunction(f, parentId, extractBody)
|
||||
extractGeneratedOverloads(f, parentId, null, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses)
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractDefaultsFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean) {
|
||||
if (f.valueParameters.none { it.defaultValue != null })
|
||||
return
|
||||
|
||||
val id = getDefaultsMethodLabel(f)
|
||||
val locId = getLocation(f, null)
|
||||
val extReceiver = f.extensionReceiverParameter
|
||||
val dispatchReceiver = if (f.shouldExtractAsStatic) null else f.dispatchReceiverParameter
|
||||
val parameterTypes = listOfNotNull(extReceiver?.let { erase(it.type) }) + getDefaultsMethodArgTypes(f)
|
||||
val allParamTypeResults = parameterTypes.mapIndexed { i, paramType ->
|
||||
val paramId = tw.getLabelFor<DbParam>(getValueParameterLabel(id, i))
|
||||
extractValueParameter(paramId, paramType, "p$i", locId, id, i, paramId, isVararg = false, syntheticParameterNames = true, isCrossinline = false, isNoinline = false).also {
|
||||
extractTypeAccess(useType(paramType), locId, paramId, -1)
|
||||
}
|
||||
}
|
||||
val paramsSignature = allParamTypeResults.joinToString(separator = ",", prefix = "(", postfix = ")") { it.javaResult.signature }
|
||||
val shortName = getDefaultsMethodName(f)
|
||||
|
||||
if (f.symbol is IrConstructorSymbol) {
|
||||
val constrId = id.cast<DbConstructor>()
|
||||
extractConstructor(constrId, shortName, paramsSignature, parentId, constrId)
|
||||
} else {
|
||||
val methodId = id.cast<DbMethod>()
|
||||
extractMethod(methodId, locId, shortName, erase(f.returnType), paramsSignature, parentId, methodId, origin = null, extractTypeAccess = true)
|
||||
addModifiers(id, "static")
|
||||
}
|
||||
tw.writeHasLocation(id, locId)
|
||||
addModifiers(id, "public")
|
||||
tw.writeCompiler_generated(id, CompilerGeneratedKinds.DEFAULT_ARGUMENTS_METHOD.kind)
|
||||
|
||||
if (extractBody) {
|
||||
val nonSyntheticParams = listOfNotNull(dispatchReceiver) + f.valueParameters
|
||||
// This stack entry represents as if we're extracting the 'real' function `f`, giving the indices of its non-synthetic parameters
|
||||
// such that when we extract the default expressions below, any reference to f's nth parameter will resolve to f$default's
|
||||
// n + o'th parameter, where `o` is the parameter offset caused by adding any dispatch receiver to the parameter list.
|
||||
// Note we don't need to add the extension receiver here because `useValueParameter` always assumes an extension receiver
|
||||
// will be prepended if one exists.
|
||||
DeclarationStackAdjuster(f, OverriddenFunctionAttributes(id, id, locId, nonSyntheticParams)).use {
|
||||
val realParamsVarId = getValueParameterLabel(id, parameterTypes.size - 2)
|
||||
val intType = pluginContext.irBuiltIns.intType
|
||||
val paramIdxOffset = listOf(dispatchReceiver, f.extensionReceiverParameter).count { it != null }
|
||||
extractBlockBody(id, locId).also { blockId ->
|
||||
var nextStmt = 0
|
||||
// For each parameter with a default, sub in the default value if the caller hasn't supplied a value:
|
||||
f.valueParameters.forEachIndexed { paramIdx, param ->
|
||||
val defaultVal = param.defaultValue
|
||||
if (defaultVal != null) {
|
||||
extractIfStmt(locId, blockId, nextStmt++, id).also { ifId ->
|
||||
// if (realParams & thisParamBit == 0) ...
|
||||
extractEqualsExpression(locId, ifId, 0, id, ifId).also { eqId ->
|
||||
extractAndbitExpression(intType, locId, eqId, 0, id, ifId).also { opId ->
|
||||
extractConstantInteger(1 shl paramIdx, locId, opId, 0, id, ifId)
|
||||
extractVariableAccess(tw.getLabelFor<DbParam>(realParamsVarId), intType, locId, opId, 1, id, ifId)
|
||||
}
|
||||
extractConstantInteger(0, locId, eqId, 1, id, ifId)
|
||||
}
|
||||
// thisParamVar = defaultExpr...
|
||||
extractExpressionStmt(locId, ifId, 1, id).also { exprStmtId ->
|
||||
extractAssignExpr(param.type, locId, exprStmtId, 0, id, exprStmtId).also { assignId ->
|
||||
extractVariableAccess(tw.getLabelFor<DbParam>(getValueParameterLabel(id, paramIdx + paramIdxOffset)), param.type, locId, assignId, 0, id, exprStmtId)
|
||||
extractExpressionExpr(defaultVal.expression, id, assignId, 1, exprStmtId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now call the real function:
|
||||
val realFunctionId = useFunction<DbCallable>(f)
|
||||
if (f is IrConstructor) {
|
||||
tw.getFreshIdLabel<DbConstructorinvocationstmt>().also { thisCallId ->
|
||||
tw.writeStmts_constructorinvocationstmt(thisCallId, blockId, nextStmt++, id)
|
||||
tw.writeHasLocation(thisCallId, locId)
|
||||
f.valueParameters.forEachIndexed { idx, param ->
|
||||
extractVariableAccess(tw.getLabelFor<DbParam>(getValueParameterLabel(id, idx)), param.type, locId, thisCallId, idx, id, thisCallId)
|
||||
}
|
||||
tw.writeCallableBinding(thisCallId, realFunctionId)
|
||||
}
|
||||
} else {
|
||||
tw.getFreshIdLabel<DbReturnstmt>().also { returnId ->
|
||||
tw.writeStmts_returnstmt(returnId, blockId, nextStmt++, id)
|
||||
tw.writeHasLocation(returnId, locId)
|
||||
extractMethodAccessWithoutArgs(f.returnType, locId, id, returnId, 0, returnId, realFunctionId).also { thisCallId ->
|
||||
val realFnIdxOffset = if (f.extensionReceiverParameter != null) 1 else 0
|
||||
val paramMappings = f.valueParameters.mapIndexed { idx, param -> Triple(param.type, idx + paramIdxOffset, idx + realFnIdxOffset) } +
|
||||
listOfNotNull(
|
||||
dispatchReceiver?.let { Triple(it.type, realFnIdxOffset, -1) },
|
||||
extReceiver?.let { Triple(it.type, 0, 0) }
|
||||
)
|
||||
paramMappings.forEach { (type, fromIdx, toIdx) ->
|
||||
extractVariableAccess(tw.getLabelFor<DbParam>(getValueParameterLabel(id, fromIdx)), type, locId, thisCallId, toIdx, id, returnId)
|
||||
}
|
||||
if (f.shouldExtractAsStatic)
|
||||
extractStaticTypeAccessQualifier(f, thisCallId, locId, id, returnId)
|
||||
else if (f.isLocalFunction()) {
|
||||
extractNewExprForLocalFunction(getLocallyVisibleFunctionLabels(f), thisCallId, locId, id, returnId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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>?) {
|
||||
@@ -932,6 +1040,29 @@ open class KotlinFileExtractor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractConstructor(id: Label<out DbConstructor>, shortName: String, paramsSignature: String, parentId: Label<out DbReftype>, sourceDeclaration: Label<out DbConstructor>) {
|
||||
val unitType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN)
|
||||
tw.writeConstrs(id, shortName, "$shortName$paramsSignature", unitType.javaResult.id, parentId, sourceDeclaration)
|
||||
tw.writeConstrsKotlinType(id, unitType.kotlinResult.id)
|
||||
}
|
||||
|
||||
private fun extractMethod(id: Label<out DbMethod>, locId: Label<out DbLocation>, shortName: String, returnType: IrType, paramsSignature: String, parentId: Label<out DbReftype>, sourceDeclaration: Label<out DbMethod>, origin: IrDeclarationOrigin?, extractTypeAccess: Boolean) {
|
||||
val returnTypeResults = useType(returnType, TypeContext.RETURN)
|
||||
tw.writeMethods(id, shortName, "$shortName$paramsSignature", returnTypeResults.javaResult.id, parentId, sourceDeclaration)
|
||||
tw.writeMethodsKotlinType(id, returnTypeResults.kotlinResult.id)
|
||||
when (origin) {
|
||||
IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER ->
|
||||
tw.writeCompiler_generated(id, CompilerGeneratedKinds.GENERATED_DATA_CLASS_MEMBER.kind)
|
||||
IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR ->
|
||||
tw.writeCompiler_generated(id, CompilerGeneratedKinds.DEFAULT_PROPERTY_ACCESSOR.kind)
|
||||
IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER ->
|
||||
tw.writeCompiler_generated(id, CompilerGeneratedKinds.ENUM_CLASS_SPECIAL_MEMBER.kind)
|
||||
}
|
||||
if (extractTypeAccess) {
|
||||
extractTypeAccessRecursive(returnType, locId, id, -1)
|
||||
}
|
||||
}
|
||||
|
||||
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, overriddenAttributes).use {
|
||||
@@ -976,42 +1107,23 @@ open class KotlinFileExtractor(
|
||||
val locId = overriddenAttributes?.sourceLoc ?: getLocation(f, classTypeArgsIncludingOuterClasses)
|
||||
|
||||
if (f.symbol is IrConstructorSymbol) {
|
||||
val unitType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN)
|
||||
val shortName = when {
|
||||
adjustedReturnType.isAnonymous -> ""
|
||||
typeSubstitution != null -> useType(substReturnType).javaResult.shortName
|
||||
else -> adjustedReturnType.classFqName?.shortName()?.asString() ?: f.name.asString()
|
||||
}
|
||||
val constrId = id.cast<DbConstructor>()
|
||||
tw.writeConstrs(constrId, shortName, "$shortName$paramsSignature", unitType.javaResult.id, parentId, sourceDeclaration.cast<DbConstructor>())
|
||||
tw.writeConstrsKotlinType(constrId, unitType.kotlinResult.id)
|
||||
extractConstructor(id.cast(), shortName, paramsSignature, parentId, sourceDeclaration.cast())
|
||||
} else {
|
||||
val returnType = useType(substReturnType, TypeContext.RETURN)
|
||||
val shortName = getFunctionShortName(f)
|
||||
val shortNames = getFunctionShortName(f)
|
||||
val methodId = id.cast<DbMethod>()
|
||||
tw.writeMethods(methodId, shortName.nameInDB, "${shortName.nameInDB}$paramsSignature", returnType.javaResult.id, parentId, sourceDeclaration.cast<DbMethod>())
|
||||
tw.writeMethodsKotlinType(methodId, returnType.kotlinResult.id)
|
||||
if (extractOrigin) {
|
||||
when (f.origin) {
|
||||
IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER ->
|
||||
tw.writeCompiler_generated(methodId, CompilerGeneratedKinds.GENERATED_DATA_CLASS_MEMBER.kind)
|
||||
IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR ->
|
||||
tw.writeCompiler_generated(methodId, CompilerGeneratedKinds.DEFAULT_PROPERTY_ACCESSOR.kind)
|
||||
IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER ->
|
||||
tw.writeCompiler_generated(methodId, CompilerGeneratedKinds.ENUM_CLASS_SPECIAL_MEMBER.kind)
|
||||
}
|
||||
}
|
||||
extractMethod(methodId, locId, shortNames.nameInDB, substReturnType, paramsSignature, parentId, sourceDeclaration.cast(), if (extractOrigin) f.origin else null, extractMethodAndParameterTypeAccesses)
|
||||
|
||||
if (extractMethodAndParameterTypeAccesses) {
|
||||
extractTypeAccessRecursive(substReturnType, locId, id, -1)
|
||||
}
|
||||
|
||||
if (shortName.nameInDB != shortName.kotlinName) {
|
||||
tw.writeKtFunctionOriginalNames(methodId, shortName.kotlinName)
|
||||
if (shortNames.nameInDB != shortNames.kotlinName) {
|
||||
tw.writeKtFunctionOriginalNames(methodId, shortNames.kotlinName)
|
||||
}
|
||||
|
||||
if (f.hasInterfaceParent() && f.body != null) {
|
||||
addModifiers(id, "default") // The actual output class file may or may not have this modifier, depending on the -Xjvm-default setting.
|
||||
addModifiers(methodId, "default") // The actual output class file may or may not have this modifier, depending on the -Xjvm-default setting.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1209,14 +1321,18 @@ open class KotlinFileExtractor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractBlockBody(callable: Label<out DbCallable>, locId: Label<DbLocation>) =
|
||||
tw.getFreshIdLabel<DbBlock>().also {
|
||||
tw.writeStmts_block(it, callable, 0, callable)
|
||||
tw.writeHasLocation(it, locId)
|
||||
}
|
||||
|
||||
private fun extractBlockBody(b: IrBlockBody, callable: Label<out DbCallable>) {
|
||||
with("block body", b) {
|
||||
val id = tw.getFreshIdLabel<DbBlock>()
|
||||
val locId = tw.getLocation(b)
|
||||
tw.writeStmts_block(id, callable, 0, callable)
|
||||
tw.writeHasLocation(id, locId)
|
||||
for ((sIdx, stmt) in b.statements.withIndex()) {
|
||||
extractStatement(stmt, callable, id, sIdx)
|
||||
extractBlockBody(callable, tw.getLocation(b)).also {
|
||||
for ((sIdx, stmt) in b.statements.withIndex()) {
|
||||
extractStatement(stmt, callable, it, sIdx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1294,6 +1410,12 @@ open class KotlinFileExtractor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractIfStmt(locId: Label<DbLocation>, parent: Label<out DbStmtparent>, idx: Int, callable: Label<out DbCallable>) =
|
||||
tw.getFreshIdLabel<DbIfstmt>().also {
|
||||
tw.writeStmts_ifstmt(it, parent, idx, callable)
|
||||
tw.writeHasLocation(it, locId)
|
||||
}
|
||||
|
||||
private fun extractStatement(s: IrStatement, callable: Label<out DbCallable>, parent: Label<out DbStmtparent>, idx: Int) {
|
||||
with("statement", s) {
|
||||
when(s) {
|
||||
@@ -1521,6 +1643,147 @@ open class KotlinFileExtractor(
|
||||
extractTypeAccessRecursive(pluginContext.irBuiltIns.anyType, locId, idNewexpr, -3, enclosingCallable, enclosingStmt)
|
||||
}
|
||||
|
||||
fun extractMethodAccessWithoutArgs(
|
||||
returnType: IrType,
|
||||
locId: Label<DbLocation>,
|
||||
enclosingCallable: Label<out DbCallable>,
|
||||
callsiteParent: Label<out DbExprparent>,
|
||||
childIdx: Int,
|
||||
enclosingStmt: Label<out DbStmt>,
|
||||
methodLabel: Label<out DbCallable>?
|
||||
) = tw.getFreshIdLabel<DbMethodaccess>().also { id ->
|
||||
val type = useType(returnType)
|
||||
|
||||
tw.writeExprs_methodaccess(id, type.javaResult.id, callsiteParent, childIdx)
|
||||
tw.writeExprsKotlinType(id, type.kotlinResult.id)
|
||||
tw.writeHasLocation(id, locId)
|
||||
tw.writeCallableEnclosingExpr(id, enclosingCallable)
|
||||
tw.writeStatementEnclosingExpr(id, enclosingStmt)
|
||||
|
||||
// The caller should have warned about this before, so we don't repeat the warning here.
|
||||
if (methodLabel != null)
|
||||
tw.writeCallableBinding(id, methodLabel)
|
||||
}
|
||||
|
||||
private val defaultConstructorMarkerClass by lazy {
|
||||
val result = pluginContext.referenceClass(FqName("kotlin.jvm.internal.DefaultConstructorMarker"))?.owner
|
||||
result?.let { extractExternalClassLater(it) }
|
||||
result
|
||||
}
|
||||
|
||||
private val defaultConstructorMarkerType by lazy {
|
||||
defaultConstructorMarkerClass?.typeWith()
|
||||
}
|
||||
|
||||
private fun getDefaultsMethodLastArgType(f: IrFunction) =
|
||||
(
|
||||
if (f is IrConstructor)
|
||||
defaultConstructorMarkerType
|
||||
else
|
||||
null
|
||||
) ?: pluginContext.irBuiltIns.anyType
|
||||
|
||||
private fun getDefaultsMethodArgTypes(f: IrFunction) =
|
||||
// The $default method has type ([extensionReceiver], [dispatchReciever], paramTypes..., int, Object)
|
||||
// All parameter types are erased. The trailing int is a mask indicating which parameter values are real
|
||||
// and which should be replaced by defaults. The final Object parameter is apparently always null.
|
||||
(
|
||||
listOfNotNull(if (f.shouldExtractAsStatic) null else f.dispatchReceiverParameter?.type) +
|
||||
f.valueParameters.map { it.type } +
|
||||
listOf(pluginContext.irBuiltIns.intType, getDefaultsMethodLastArgType(f))
|
||||
).map { erase(it) }
|
||||
|
||||
private fun getDefaultsMethodName(f: IrFunction) =
|
||||
if (f is IrConstructor) {
|
||||
f.returnType.let {
|
||||
when {
|
||||
it.isAnonymous -> ""
|
||||
else -> it.classFqName?.shortName()?.asString() ?: f.name.asString()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
f.name.asString() + "\$default"
|
||||
}
|
||||
|
||||
private fun getDefaultsMethodLabel(f: IrFunction): Label<out DbCallable> {
|
||||
val defaultsMethodName = getDefaultsMethodName(f)
|
||||
val normalArgTypes = getDefaultsMethodArgTypes(f)
|
||||
val extensionParamType = f.extensionReceiverParameter?.let { erase(it.type) }
|
||||
|
||||
val defaultMethodLabelStr = getFunctionLabel(
|
||||
f.parent,
|
||||
maybeParentId = null,
|
||||
defaultsMethodName,
|
||||
normalArgTypes,
|
||||
erase(f.returnType),
|
||||
extensionParamType,
|
||||
listOf(),
|
||||
classTypeArgsIncludingOuterClasses = null,
|
||||
overridesCollectionsMethod = false,
|
||||
javaSignature = null,
|
||||
addParameterWildcardsByDefault = false
|
||||
)
|
||||
|
||||
return tw.getLabelFor(defaultMethodLabelStr)
|
||||
}
|
||||
|
||||
private fun extractsDefaultsCall(
|
||||
syntacticCallTarget: IrFunction,
|
||||
locId: Label<DbLocation>,
|
||||
callsite: IrCall,
|
||||
enclosingCallable: Label<out DbCallable>,
|
||||
callsiteParent: Label<out DbExprparent>,
|
||||
childIdx: Int,
|
||||
enclosingStmt: Label<out DbStmt>,
|
||||
valueArguments: List<IrExpression?>,
|
||||
dispatchReceiver: IrExpression?,
|
||||
extensionReceiver: IrExpression?
|
||||
) {
|
||||
val callTarget = syntacticCallTarget.target.realOverrideTarget
|
||||
val defaultMethodLabel = getDefaultsMethodLabel(callTarget)
|
||||
val id = extractMethodAccessWithoutArgs(callsite.type, locId, enclosingCallable, callsiteParent, childIdx, enclosingStmt, defaultMethodLabel)
|
||||
|
||||
if (callTarget.isLocalFunction()) {
|
||||
extractNewExprForLocalFunction(getLocallyVisibleFunctionLabels(callTarget), id, locId, enclosingCallable, enclosingStmt)
|
||||
} else {
|
||||
extractStaticTypeAccessQualifierUnchecked(callTarget.parent, id, locId, enclosingCallable, enclosingStmt)
|
||||
}
|
||||
|
||||
extractDefaultsCallArguments(id, callTarget, enclosingCallable, enclosingStmt, valueArguments, dispatchReceiver, extensionReceiver)
|
||||
}
|
||||
|
||||
private fun extractDefaultsCallArguments(
|
||||
id: Label<out DbExprparent>,
|
||||
callTarget: IrFunction,
|
||||
enclosingCallable: Label<out DbCallable>,
|
||||
enclosingStmt: Label<out DbStmt>,
|
||||
valueArguments: List<IrExpression?>,
|
||||
dispatchReceiver: IrExpression?,
|
||||
extensionReceiver: IrExpression?
|
||||
) {
|
||||
var nextIdx = 0
|
||||
if (extensionReceiver != null) {
|
||||
extractExpressionExpr(extensionReceiver, enclosingCallable, id, nextIdx++, enclosingStmt)
|
||||
}
|
||||
if (dispatchReceiver != null && !callTarget.shouldExtractAsStatic) {
|
||||
extractExpressionExpr(dispatchReceiver, enclosingCallable, id, nextIdx++, enclosingStmt)
|
||||
}
|
||||
|
||||
val valueArgsWithDummies = valueArguments.zip(callTarget.valueParameters).map {
|
||||
(expr, param) -> expr ?: IrConstImpl.defaultValueForType(0, 0, param.type)
|
||||
}
|
||||
|
||||
var realParamsMask = 0
|
||||
valueArguments.forEachIndexed { index, arg -> if (arg != null) realParamsMask = realParamsMask or (1 shl index) }
|
||||
|
||||
val extraArgs = listOf(
|
||||
IrConstImpl.int(0, 0, pluginContext.irBuiltIns.intType, realParamsMask),
|
||||
IrConstImpl.defaultValueForType(0, 0, getDefaultsMethodLastArgType(callTarget))
|
||||
)
|
||||
|
||||
extractCallValueArguments(id, valueArgsWithDummies + extraArgs, enclosingStmt, enclosingCallable, nextIdx)
|
||||
}
|
||||
|
||||
fun extractRawMethodAccess(
|
||||
syntacticCallTarget: IrFunction,
|
||||
callsite: IrCall,
|
||||
@@ -1537,24 +1800,38 @@ open class KotlinFileExtractor(
|
||||
|
||||
val locId = tw.getLocation(callsite)
|
||||
|
||||
extractRawMethodAccess(
|
||||
syntacticCallTarget,
|
||||
locId,
|
||||
callsite.type,
|
||||
enclosingCallable,
|
||||
callsiteParent,
|
||||
childIdx,
|
||||
enclosingStmt,
|
||||
valueArguments.size,
|
||||
{ argParent, idxOffset -> extractCallValueArguments(argParent, valueArguments, enclosingStmt, enclosingCallable, idxOffset) },
|
||||
dispatchReceiver?.type,
|
||||
dispatchReceiver?.let { { callId -> extractExpressionExpr(dispatchReceiver, enclosingCallable, callId, -1, enclosingStmt) } },
|
||||
extensionReceiver?.let { { argParent -> extractExpressionExpr(extensionReceiver, enclosingCallable, argParent, 0, enclosingStmt) } },
|
||||
typeArguments,
|
||||
extractClassTypeArguments,
|
||||
superQualifierSymbol
|
||||
)
|
||||
|
||||
if (valueArguments.any { it == null }) {
|
||||
extractsDefaultsCall(
|
||||
syntacticCallTarget,
|
||||
locId,
|
||||
callsite,
|
||||
enclosingCallable,
|
||||
callsiteParent,
|
||||
childIdx,
|
||||
enclosingStmt,
|
||||
valueArguments,
|
||||
dispatchReceiver,
|
||||
extensionReceiver
|
||||
)
|
||||
} else {
|
||||
extractRawMethodAccess(
|
||||
syntacticCallTarget,
|
||||
locId,
|
||||
callsite.type,
|
||||
enclosingCallable,
|
||||
callsiteParent,
|
||||
childIdx,
|
||||
enclosingStmt,
|
||||
valueArguments.size,
|
||||
{ argParent, idxOffset -> extractCallValueArguments(argParent, valueArguments, enclosingStmt, enclosingCallable, idxOffset) },
|
||||
dispatchReceiver?.type,
|
||||
dispatchReceiver?.let { { callId -> extractExpressionExpr(dispatchReceiver, enclosingCallable, callId, -1, enclosingStmt) } },
|
||||
extensionReceiver?.let { { argParent -> extractExpressionExpr(extensionReceiver, enclosingCallable, argParent, 0, enclosingStmt) } },
|
||||
typeArguments,
|
||||
extractClassTypeArguments,
|
||||
superQualifierSymbol
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFunctionInvokeMethod(typeArgs: List<IrTypeArgument>): IrFunction? {
|
||||
@@ -1634,26 +1911,16 @@ open class KotlinFileExtractor(
|
||||
superQualifierSymbol: IrClassSymbol? = null) {
|
||||
|
||||
val callTarget = syntacticCallTarget.target.realOverrideTarget
|
||||
val id = tw.getFreshIdLabel<DbMethodaccess>()
|
||||
val type = useType(returnType)
|
||||
val methodId = getCalleeMethodId(callTarget, drType, extractClassTypeArguments)
|
||||
if (methodId == null) {
|
||||
logger.warn("No method to bind call to for raw method access")
|
||||
}
|
||||
|
||||
tw.writeExprs_methodaccess(id, type.javaResult.id, callsiteParent, childIdx)
|
||||
tw.writeExprsKotlinType(id, type.kotlinResult.id)
|
||||
tw.writeHasLocation(id, locId)
|
||||
tw.writeCallableEnclosingExpr(id, enclosingCallable)
|
||||
tw.writeStatementEnclosingExpr(id, enclosingStmt)
|
||||
val id = extractMethodAccessWithoutArgs(returnType, locId, enclosingCallable, callsiteParent, childIdx, enclosingStmt, methodId)
|
||||
|
||||
// type arguments at index -2, -3, ...
|
||||
extractTypeArguments(typeArguments, locId, id, enclosingCallable, enclosingStmt, -2, true)
|
||||
|
||||
val methodId = getCalleeMethodId(callTarget, drType, extractClassTypeArguments)
|
||||
|
||||
if (methodId == null) {
|
||||
logger.warn("No method to bind call to for raw method access")
|
||||
} else {
|
||||
tw.writeCallableBinding(id, methodId)
|
||||
}
|
||||
|
||||
if (callTarget.isLocalFunction()) {
|
||||
extractNewExprForLocalFunction(getLocallyVisibleFunctionLabels(callTarget), id, locId, enclosingCallable, enclosingStmt)
|
||||
} else if (callTarget.shouldExtractAsStatic) {
|
||||
@@ -1683,16 +1950,19 @@ open class KotlinFileExtractor(
|
||||
extractValueArguments(argParent, idxOffset)
|
||||
}
|
||||
|
||||
private fun extractStaticTypeAccessQualifierUnchecked(parent: IrDeclarationParent, parentExpr: Label<out DbExprparent>, locId: Label<DbLocation>, enclosingCallable: Label<out DbCallable>, enclosingStmt: Label<out DbStmt>) {
|
||||
if (parent is IrClass) {
|
||||
extractTypeAccessRecursive(parent.toRawType(), locId, parentExpr, -1, enclosingCallable, enclosingStmt)
|
||||
} else if (parent is IrFile) {
|
||||
extractTypeAccess(useFileClassType(parent), locId, parentExpr, -1, enclosingCallable, enclosingStmt)
|
||||
} else {
|
||||
logger.warnElement("Unexpected static type access qualifier ${parent.javaClass}", parent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractStaticTypeAccessQualifier(target: IrDeclaration, parentExpr: Label<out DbExprparent>, locId: Label<DbLocation>, enclosingCallable: Label<out DbCallable>, enclosingStmt: Label<out DbStmt>) {
|
||||
if (target.shouldExtractAsStatic) {
|
||||
val parent = target.parent
|
||||
if (parent is IrClass) {
|
||||
extractTypeAccessRecursive(parent.toRawType(), locId, parentExpr, -1, enclosingCallable, enclosingStmt)
|
||||
} else if (parent is IrFile) {
|
||||
extractTypeAccess(useFileClassType(parent), locId, parentExpr, -1, enclosingCallable, enclosingStmt)
|
||||
} else {
|
||||
logger.warnElement("Unexpected static type access qualifer ${parent.javaClass}", target)
|
||||
}
|
||||
extractStaticTypeAccessQualifierUnchecked(target.parent, parentExpr, locId, enclosingCallable, enclosingStmt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2666,14 +2936,22 @@ open class KotlinFileExtractor(
|
||||
useType(eType)
|
||||
}
|
||||
val locId = tw.getLocation(e)
|
||||
val id = extractNewExpr(e.symbol.owner, eType.arguments, type, locId, parent, idx, callable, enclosingStmt)
|
||||
val valueArgs = (0 until e.valueArgumentsCount).map { e.getValueArgument(it) }
|
||||
val anyDefaultArgs = valueArgs.any { it == null }
|
||||
val id = if (anyDefaultArgs) {
|
||||
extractNewExpr(getDefaultsMethodLabel(e.symbol.owner).cast(), type, locId, parent, idx, callable, enclosingStmt).also {
|
||||
extractDefaultsCallArguments(it, e.symbol.owner, callable, enclosingStmt, valueArgs, null, null)
|
||||
}
|
||||
} else {
|
||||
extractNewExpr(e.symbol.owner, eType.arguments, type, locId, parent, idx, callable, enclosingStmt).also {
|
||||
extractCallValueArguments(it, e, enclosingStmt, callable, 0)
|
||||
}
|
||||
}
|
||||
|
||||
if (isAnonymous) {
|
||||
tw.writeIsAnonymClass(type.javaResult.id.cast<DbClass>(), id)
|
||||
}
|
||||
|
||||
extractCallValueArguments(id, e, enclosingStmt, callable, 0)
|
||||
|
||||
val dr = e.dispatchReceiver
|
||||
if (dr != null) {
|
||||
extractExpressionExpr(dr, callable, id, -2, enclosingStmt)
|
||||
@@ -2872,6 +3150,12 @@ open class KotlinFileExtractor(
|
||||
return false
|
||||
}
|
||||
|
||||
private fun extractExpressionStmt(locId: Label<DbLocation>, parent: Label<out DbStmtparent>, idx: Int, callable: Label<out DbCallable>) =
|
||||
tw.getFreshIdLabel<DbExprstmt>().also {
|
||||
tw.writeStmts_exprstmt(it, parent, idx, callable)
|
||||
tw.writeHasLocation(it, locId)
|
||||
}
|
||||
|
||||
private fun extractExpressionStmt(e: IrExpression, callable: Label<out DbCallable>, parent: Label<out DbStmtparent>, idx: Int) {
|
||||
extractExpression(e, callable, StmtParent(parent, idx))
|
||||
}
|
||||
@@ -2880,6 +3164,45 @@ open class KotlinFileExtractor(
|
||||
extractExpression(e, callable, ExprParent(parent, idx, enclosingStmt))
|
||||
}
|
||||
|
||||
private fun extractExprContext(id: Label<out DbExpr>, locId: Label<DbLocation>, callable: Label<out DbCallable>, enclosingStmt: Label<out DbStmt>) {
|
||||
tw.writeHasLocation(id, locId)
|
||||
tw.writeCallableEnclosingExpr(id, callable)
|
||||
tw.writeStatementEnclosingExpr(id, enclosingStmt)
|
||||
}
|
||||
|
||||
private fun extractEqualsExpression(locId: Label<DbLocation>, parent: Label<out DbExprparent>, idx: Int, callable: Label<out DbCallable>, enclosingStmt: Label<out DbStmt>) =
|
||||
tw.getFreshIdLabel<DbEqexpr>().also {
|
||||
val type = useType(pluginContext.irBuiltIns.booleanType)
|
||||
tw.writeExprs_eqexpr(it, type.javaResult.id, parent, idx)
|
||||
tw.writeExprsKotlinType(it, type.kotlinResult.id)
|
||||
extractExprContext(it, locId, callable, enclosingStmt)
|
||||
}
|
||||
|
||||
private fun extractAndbitExpression(type: IrType, locId: Label<DbLocation>, parent: Label<out DbExprparent>, idx: Int, callable: Label<out DbCallable>, enclosingStmt: Label<out DbStmt>) =
|
||||
tw.getFreshIdLabel<DbAndbitexpr>().also {
|
||||
val typeResults = useType(type)
|
||||
tw.writeExprs_andbitexpr(it, typeResults.javaResult.id, parent, idx)
|
||||
tw.writeExprsKotlinType(it, typeResults.kotlinResult.id)
|
||||
extractExprContext(it, locId, callable, enclosingStmt)
|
||||
}
|
||||
|
||||
private fun extractConstantInteger(v: Int, locId: Label<DbLocation>, parent: Label<out DbExprparent>, idx: Int, callable: Label<out DbCallable>, enclosingStmt: Label<out DbStmt>) =
|
||||
tw.getFreshIdLabel<DbIntegerliteral>().also {
|
||||
val type = useType(pluginContext.irBuiltIns.intType)
|
||||
tw.writeExprs_integerliteral(it, type.javaResult.id, parent, idx)
|
||||
tw.writeExprsKotlinType(it, type.kotlinResult.id)
|
||||
tw.writeNamestrings(v.toString(), v.toString(), it)
|
||||
extractExprContext(it, locId, callable, enclosingStmt)
|
||||
}
|
||||
|
||||
private fun extractAssignExpr(type: IrType, locId: Label<DbLocation>, parent: Label<out DbExprparent>, idx: Int, callable: Label<out DbCallable>, enclosingStmt: Label<out DbStmt>) =
|
||||
tw.getFreshIdLabel<DbAssignexpr>().also {
|
||||
val typeResults = useType(type)
|
||||
tw.writeExprs_assignexpr(it, typeResults.javaResult.id, parent, idx)
|
||||
tw.writeExprsKotlinType(it, typeResults.kotlinResult.id)
|
||||
extractExprContext(it, locId, callable, enclosingStmt)
|
||||
}
|
||||
|
||||
private fun extractExpression(e: IrExpression, callable: Label<out DbCallable>, parent: StmtExprParent) {
|
||||
with("expression", e) {
|
||||
when(e) {
|
||||
@@ -3130,7 +3453,7 @@ open class KotlinFileExtractor(
|
||||
val exprParent = parent.expr(e, callable)
|
||||
val owner = e.symbol.owner
|
||||
if (owner is IrValueParameter && owner.index == -1 && !owner.isExtensionReceiver()) {
|
||||
extractThisAccess(e, exprParent, callable)
|
||||
extractThisAccess(e, owner.parent, exprParent, callable)
|
||||
} else {
|
||||
val isAnnotationClassParameter = ((owner as? IrValueParameter)?.parent as? IrConstructor)?.parentClassOrNull?.kind == ClassKind.ANNOTATION_CLASS
|
||||
val extractType = if (isAnnotationClassParameter) kClassToJavaClass(e.type) else e.type
|
||||
@@ -3482,7 +3805,7 @@ open class KotlinFileExtractor(
|
||||
tw.writeStatementEnclosingExpr(it, enclosingStmt)
|
||||
}
|
||||
|
||||
private fun extractThisAccess(e: IrGetValue, exprParent: ExprParent, callable: Label<out DbCallable>) {
|
||||
private fun extractThisAccess(e: IrGetValue, thisParamParent: IrDeclarationParent, exprParent: ExprParent, callable: Label<out DbCallable>) {
|
||||
val containingDeclaration = declarationStack.peek().first
|
||||
val locId = tw.getLocation(e)
|
||||
|
||||
@@ -3494,6 +3817,20 @@ open class KotlinFileExtractor(
|
||||
extractStaticTypeAccessQualifier(containingDeclaration, varAccessId, locId, callable, exprParent.enclosingStmt)
|
||||
}
|
||||
} else {
|
||||
if (thisParamParent is IrFunction) {
|
||||
val overriddenAttributes = declarationStack.findOverriddenAttributes(thisParamParent)
|
||||
val replaceWithParamIdx = overriddenAttributes?.valueParameters?.indexOf(e.symbol.owner)
|
||||
if (replaceWithParamIdx != null && replaceWithParamIdx != -1) {
|
||||
// Use of 'this' in a function where the dispatch receiver is passed like an ordinary parameter,
|
||||
// such as a `$default` static function that substitutes in default arguments as needed.
|
||||
val paramDeclarerId = overriddenAttributes.id ?: useDeclarationParent(thisParamParent, false)
|
||||
val extensionParamOffset = if (thisParamParent.extensionReceiverParameter != null) 1 else 0
|
||||
val replacementParamId = tw.getLabelFor<DbParam>(getValueParameterLabel(paramDeclarerId, replaceWithParamIdx + extensionParamOffset))
|
||||
extractVariableAccess(replacementParamId, e.type, locId, exprParent.parent, exprParent.idx, callable, exprParent.enclosingStmt)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val id = extractThisAccess(e.type, callable, exprParent.parent, exprParent.idx, exprParent.enclosingStmt, locId)
|
||||
|
||||
fun extractTypeAccess(parent: IrClass) {
|
||||
@@ -5048,5 +5385,6 @@ open class KotlinFileExtractor(
|
||||
DELEGATED_PROPERTY_SETTER(7),
|
||||
JVMSTATIC_PROXY_METHOD(8),
|
||||
JVMOVERLOADS_METHOD(9),
|
||||
DEFAULT_ARGUMENTS_METHOD(10)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1043,9 +1043,9 @@ open class KotlinUsesExtractor(
|
||||
f.parent,
|
||||
maybeParentId,
|
||||
getFunctionShortName(f).nameInDB,
|
||||
maybeParameterList ?: f.valueParameters,
|
||||
(maybeParameterList ?: f.valueParameters).map { it.type },
|
||||
getAdjustedReturnType(f),
|
||||
f.extensionReceiverParameter,
|
||||
f.extensionReceiverParameter?.type,
|
||||
getFunctionTypeParameters(f),
|
||||
classTypeArgsIncludingOuterClasses,
|
||||
overridesCollectionsMethodWithAlteredParameterTypes(f),
|
||||
@@ -1067,12 +1067,12 @@ open class KotlinUsesExtractor(
|
||||
maybeParentId: Label<out DbElement>?,
|
||||
// The name of the function; normally f.name.asString().
|
||||
name: String,
|
||||
// The value parameters that the functions takes; normally f.valueParameters.
|
||||
parameters: List<IrValueParameter>,
|
||||
// The types of the value parameters that the functions takes; normally f.valueParameters.map { it.type }.
|
||||
parameterTypes: List<IrType>,
|
||||
// The return type of the function; normally f.returnType.
|
||||
returnType: IrType,
|
||||
// The extension receiver of the function, if any; normally f.extensionReceiverParameter.
|
||||
extensionReceiverParameter: IrValueParameter?,
|
||||
// The extension receiver of the function, if any; normally f.extensionReceiverParameter?.type.
|
||||
extensionParamType: IrType?,
|
||||
// The type parameters of the function. This does not include type parameters of enclosing classes.
|
||||
functionTypeParameters: List<IrTypeParameter>,
|
||||
// The type arguments of enclosing classes of the function.
|
||||
@@ -1089,11 +1089,7 @@ open class KotlinUsesExtractor(
|
||||
prefix: String = "callable"
|
||||
): String {
|
||||
val parentId = maybeParentId ?: useDeclarationParent(parent, false, classTypeArgsIncludingOuterClasses, true)
|
||||
val allParams = if (extensionReceiverParameter == null) {
|
||||
parameters
|
||||
} else {
|
||||
listOf(extensionReceiverParameter) + parameters
|
||||
}
|
||||
val allParamTypes = if (extensionParamType == null) parameterTypes else listOf(extensionParamType) + parameterTypes
|
||||
|
||||
val substitutionMap = classTypeArgsIncludingOuterClasses?.let { notNullArgs ->
|
||||
if (notNullArgs.isEmpty()) {
|
||||
@@ -1103,11 +1099,11 @@ open class KotlinUsesExtractor(
|
||||
enclosingClass?.let { notNullClass -> makeTypeGenericSubstitutionMap(notNullClass, notNullArgs) }
|
||||
}
|
||||
}
|
||||
val getIdForFunctionLabel = { it: IndexedValue<IrValueParameter> ->
|
||||
val getIdForFunctionLabel = { it: IndexedValue<IrType> ->
|
||||
// Kotlin rewrites certain Java collections types adding additional generic constraints-- for example,
|
||||
// Collection.remove(Object) because Collection.remove(Collection::E) in the Kotlin universe.
|
||||
// If this has happened, erase the type again to get the correct Java signature.
|
||||
val maybeAmendedForCollections = if (overridesCollectionsMethod) eraseCollectionsMethodParameterType(it.value.type, name, it.index) else it.value.type
|
||||
val maybeAmendedForCollections = if (overridesCollectionsMethod) eraseCollectionsMethodParameterType(it.value, name, it.index) else it.value
|
||||
// Add any wildcard types that the Kotlin compiler would add in the Java lowering of this function:
|
||||
val withAddedWildcards = addJavaLoweringWildcards(maybeAmendedForCollections, addParameterWildcardsByDefault, javaSignature?.let { sig -> getJavaValueParameterType(sig, it.index) })
|
||||
// Now substitute any class type parameters in:
|
||||
@@ -1117,7 +1113,7 @@ open class KotlinUsesExtractor(
|
||||
val maybeErased = if (functionTypeParameters.isEmpty()) maybeSubbed else erase(maybeSubbed)
|
||||
"{${useType(maybeErased).javaResult.id}}"
|
||||
}
|
||||
val paramTypeIds = allParams.withIndex().joinToString(separator = ",", transform = getIdForFunctionLabel)
|
||||
val paramTypeIds = allParamTypes.withIndex().joinToString(separator = ",", transform = getIdForFunctionLabel)
|
||||
val labelReturnType =
|
||||
if (name == "<init>")
|
||||
pluginContext.irBuiltIns.unitType
|
||||
@@ -1551,7 +1547,7 @@ open class KotlinUsesExtractor(
|
||||
* Note that `Array<T>` is retained (with `T` itself erased) because these are expected to be lowered to Java
|
||||
* arrays, which are not generic.
|
||||
*/
|
||||
private fun erase (t: IrType): IrType {
|
||||
fun erase (t: IrType): IrType {
|
||||
if (t is IrSimpleType) {
|
||||
val classifier = t.classifier
|
||||
val owner = classifier.owner
|
||||
@@ -1578,6 +1574,8 @@ open class KotlinUsesExtractor(
|
||||
private fun eraseTypeParameter(t: IrTypeParameter) =
|
||||
erase(t.superTypes[0])
|
||||
|
||||
fun getValueParameterLabel(parentId: Label<out DbElement>?, idx: Int) = "@\"params;{$parentId};$idx\""
|
||||
|
||||
/**
|
||||
* Gets the label for `vp` in the context of function instance `parent`, or in that of its declaring function if
|
||||
* `parent` is null.
|
||||
@@ -1607,7 +1605,7 @@ open class KotlinUsesExtractor(
|
||||
logger.error("Unexpected negative index for parameter")
|
||||
}
|
||||
|
||||
return "@\"params;{$parentId};$idx\""
|
||||
return getValueParameterLabel(parentId, idx)
|
||||
}
|
||||
|
||||
|
||||
@@ -1669,7 +1667,7 @@ open class KotlinUsesExtractor(
|
||||
val returnType = getter?.returnType ?: setter?.valueParameters?.singleOrNull()?.type ?: pluginContext.irBuiltIns.unitType
|
||||
val typeParams = getFunctionTypeParameters(func)
|
||||
|
||||
getFunctionLabel(p.parent, parentId, p.name.asString(), listOf(), returnType, ext, typeParams, classTypeArgsIncludingOuterClasses, overridesCollectionsMethod = false, javaSignature = null, addParameterWildcardsByDefault = false, prefix = "property")
|
||||
getFunctionLabel(p.parent, parentId, p.name.asString(), listOf(), returnType, ext.type, typeParams, classTypeArgsIncludingOuterClasses, overridesCollectionsMethod = false, javaSignature = null, addParameterWildcardsByDefault = false, prefix = "property")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ class Element extends @element, Top {
|
||||
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"
|
||||
or
|
||||
i = 10 and result = "Forwarder for Kotlin calls that need default arguments filling in"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,849 @@
|
||||
test.kt:
|
||||
# 0| [CompilationUnit] test
|
||||
# 0| 1: [Class] TestKt
|
||||
# 1| 1: [Method] sink
|
||||
# 1| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 1| 0: [Parameter] a
|
||||
# 1| 0: [TypeAccess] Object
|
||||
# 1| 5: [BlockStmt] { ... }
|
||||
# 3| 2: [Class] TestMember
|
||||
# 3| 1: [Constructor] TestMember
|
||||
# 3| 5: [BlockStmt] { ... }
|
||||
# 3| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 3| 1: [BlockStmt] { ... }
|
||||
# 5| 2: [Method] f
|
||||
# 5| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 5| 0: [Parameter] x
|
||||
# 5| 0: [TypeAccess] String
|
||||
# 5| 1: [Parameter] y
|
||||
# 5| 0: [TypeAccess] String
|
||||
# 5| 2: [Parameter] z
|
||||
# 5| 0: [TypeAccess] String
|
||||
# 5| 5: [BlockStmt] { ... }
|
||||
# 6| 0: [ExprStmt] <Expr>;
|
||||
# 6| 0: [MethodAccess] sink(...)
|
||||
# 6| -1: [TypeAccess] TestKt
|
||||
# 6| 0: [VarAccess] y
|
||||
# 5| 3: [Method] f$default
|
||||
# 5| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 5| 0: [Parameter] p0
|
||||
# 5| 0: [TypeAccess] TestMember
|
||||
# 5| 1: [Parameter] p1
|
||||
# 5| 0: [TypeAccess] String
|
||||
# 5| 2: [Parameter] p2
|
||||
# 5| 0: [TypeAccess] String
|
||||
# 5| 3: [Parameter] p3
|
||||
# 5| 0: [TypeAccess] String
|
||||
# 5| 4: [Parameter] p4
|
||||
# 5| 0: [TypeAccess] int
|
||||
# 5| 5: [Parameter] p5
|
||||
# 5| 0: [TypeAccess] Object
|
||||
# 5| 5: [BlockStmt] { ... }
|
||||
# 5| 0: [IfStmt] if (...)
|
||||
# 5| 0: [EQExpr] ... == ...
|
||||
# 5| 0: [AndBitwiseExpr] ... & ...
|
||||
# 5| 0: [IntegerLiteral] 2
|
||||
# 5| 1: [VarAccess] p4
|
||||
# 5| 1: [IntegerLiteral] 0
|
||||
# 5| 1: [ExprStmt] <Expr>;
|
||||
# 5| 0: [AssignExpr] ...=...
|
||||
# 5| 0: [VarAccess] p2
|
||||
# 5| 1: [VarAccess] p1
|
||||
# 5| 1: [IfStmt] if (...)
|
||||
# 5| 0: [EQExpr] ... == ...
|
||||
# 5| 0: [AndBitwiseExpr] ... & ...
|
||||
# 5| 0: [IntegerLiteral] 4
|
||||
# 5| 1: [VarAccess] p4
|
||||
# 5| 1: [IntegerLiteral] 0
|
||||
# 5| 1: [ExprStmt] <Expr>;
|
||||
# 5| 0: [AssignExpr] ...=...
|
||||
# 5| 0: [VarAccess] p3
|
||||
# 5| 1: [StringLiteral] hello world
|
||||
# 5| 2: [ReturnStmt] return ...
|
||||
# 5| 0: [MethodAccess] f(...)
|
||||
# 5| -1: [VarAccess] p0
|
||||
# 5| 0: [VarAccess] p1
|
||||
# 5| 1: [VarAccess] p2
|
||||
# 5| 2: [VarAccess] p3
|
||||
# 9| 4: [Method] user
|
||||
# 9| 3: [TypeAccess] Unit
|
||||
# 9| 5: [BlockStmt] { ... }
|
||||
# 10| 0: [ExprStmt] <Expr>;
|
||||
# 10| 0: [MethodAccess] f$default(...)
|
||||
# 10| -1: [TypeAccess] TestMember
|
||||
# 10| 0: [ThisAccess] this
|
||||
# 10| 1: [StringLiteral] member sunk
|
||||
# 1| 2: [NullLiteral] null
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [IntegerLiteral] 1
|
||||
# 1| 5: [NullLiteral] null
|
||||
# 11| 1: [ExprStmt] <Expr>;
|
||||
# 11| 0: [MethodAccess] f$default(...)
|
||||
# 11| -1: [TypeAccess] TestMember
|
||||
# 11| 0: [ThisAccess] this
|
||||
# 11| 1: [StringLiteral] member sunk fp
|
||||
# 11| 2: [StringLiteral] member sunk 2
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [IntegerLiteral] 3
|
||||
# 1| 5: [NullLiteral] null
|
||||
# 12| 2: [ExprStmt] <Expr>;
|
||||
# 12| 0: [MethodAccess] f(...)
|
||||
# 12| -1: [ThisAccess] this
|
||||
# 12| 0: [StringLiteral] not sunk
|
||||
# 12| 1: [StringLiteral] member sunk 3
|
||||
# 12| 2: [StringLiteral] not sunk
|
||||
# 17| 3: [Class] TestExtensionMember
|
||||
# 17| 1: [Constructor] TestExtensionMember
|
||||
# 17| 5: [BlockStmt] { ... }
|
||||
# 17| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 17| 1: [BlockStmt] { ... }
|
||||
# 19| 2: [ExtensionMethod] f
|
||||
# 19| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 19| 0: [Parameter] <this>
|
||||
# 19| 0: [TypeAccess] String
|
||||
# 19| 1: [Parameter] x
|
||||
# 19| 0: [TypeAccess] String
|
||||
# 19| 2: [Parameter] y
|
||||
# 19| 0: [TypeAccess] String
|
||||
# 19| 3: [Parameter] z
|
||||
# 19| 0: [TypeAccess] String
|
||||
# 19| 5: [BlockStmt] { ... }
|
||||
# 20| 0: [ExprStmt] <Expr>;
|
||||
# 20| 0: [MethodAccess] sink(...)
|
||||
# 20| -1: [TypeAccess] TestKt
|
||||
# 20| 0: [ExtensionReceiverAccess] this
|
||||
# 21| 1: [ExprStmt] <Expr>;
|
||||
# 21| 0: [MethodAccess] sink(...)
|
||||
# 21| -1: [TypeAccess] TestKt
|
||||
# 21| 0: [VarAccess] y
|
||||
# 19| 3: [Method] f$default
|
||||
# 19| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 19| 0: [Parameter] p0
|
||||
# 19| 0: [TypeAccess] String
|
||||
# 19| 1: [Parameter] p1
|
||||
# 19| 0: [TypeAccess] TestExtensionMember
|
||||
# 19| 2: [Parameter] p2
|
||||
# 19| 0: [TypeAccess] String
|
||||
# 19| 3: [Parameter] p3
|
||||
# 19| 0: [TypeAccess] String
|
||||
# 19| 4: [Parameter] p4
|
||||
# 19| 0: [TypeAccess] String
|
||||
# 19| 5: [Parameter] p5
|
||||
# 19| 0: [TypeAccess] int
|
||||
# 19| 6: [Parameter] p6
|
||||
# 19| 0: [TypeAccess] Object
|
||||
# 19| 5: [BlockStmt] { ... }
|
||||
# 19| 0: [IfStmt] if (...)
|
||||
# 19| 0: [EQExpr] ... == ...
|
||||
# 19| 0: [AndBitwiseExpr] ... & ...
|
||||
# 19| 0: [IntegerLiteral] 2
|
||||
# 19| 1: [VarAccess] p5
|
||||
# 19| 1: [IntegerLiteral] 0
|
||||
# 19| 1: [ExprStmt] <Expr>;
|
||||
# 19| 0: [AssignExpr] ...=...
|
||||
# 19| 0: [VarAccess] p3
|
||||
# 19| 1: [VarAccess] p2
|
||||
# 19| 1: [IfStmt] if (...)
|
||||
# 19| 0: [EQExpr] ... == ...
|
||||
# 19| 0: [AndBitwiseExpr] ... & ...
|
||||
# 19| 0: [IntegerLiteral] 4
|
||||
# 19| 1: [VarAccess] p5
|
||||
# 19| 1: [IntegerLiteral] 0
|
||||
# 19| 1: [ExprStmt] <Expr>;
|
||||
# 19| 0: [AssignExpr] ...=...
|
||||
# 19| 0: [VarAccess] p4
|
||||
# 19| 1: [StringLiteral] hello world
|
||||
# 19| 2: [ReturnStmt] return ...
|
||||
# 19| 0: [MethodAccess] f(...)
|
||||
# 19| -1: [VarAccess] p1
|
||||
# 19| 0: [VarAccess] p0
|
||||
# 19| 1: [VarAccess] p2
|
||||
# 19| 2: [VarAccess] p3
|
||||
# 19| 3: [VarAccess] p4
|
||||
# 24| 4: [Method] user
|
||||
# 24| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 24| 0: [Parameter] sunk
|
||||
# 24| 0: [TypeAccess] String
|
||||
# 24| 5: [BlockStmt] { ... }
|
||||
# 25| 0: [ExprStmt] <Expr>;
|
||||
# 25| 0: [MethodAccess] f$default(...)
|
||||
# 25| -1: [TypeAccess] TestExtensionMember
|
||||
# 25| 0: [VarAccess] sunk
|
||||
# 25| 1: [ThisAccess] this
|
||||
# 25| 2: [StringLiteral] extension sunk
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [NullLiteral] null
|
||||
# 1| 5: [IntegerLiteral] 1
|
||||
# 1| 6: [NullLiteral] null
|
||||
# 26| 1: [ExprStmt] <Expr>;
|
||||
# 26| 0: [MethodAccess] f$default(...)
|
||||
# 26| -1: [TypeAccess] TestExtensionMember
|
||||
# 26| 0: [VarAccess] sunk
|
||||
# 26| 1: [ThisAccess] this
|
||||
# 26| 2: [StringLiteral] extension sunk fp
|
||||
# 26| 3: [StringLiteral] extension sunk 2
|
||||
# 1| 4: [NullLiteral] null
|
||||
# 1| 5: [IntegerLiteral] 3
|
||||
# 1| 6: [NullLiteral] null
|
||||
# 27| 2: [ExprStmt] <Expr>;
|
||||
# 27| 0: [MethodAccess] f(...)
|
||||
# 27| -1: [ThisAccess] this
|
||||
# 27| 0: [VarAccess] sunk
|
||||
# 27| 1: [StringLiteral] not sunk
|
||||
# 27| 2: [StringLiteral] extension sunk 3
|
||||
# 27| 3: [StringLiteral] not sunk
|
||||
# 32| 4: [Class] TestStaticMember
|
||||
# 32| 1: [Constructor] TestStaticMember
|
||||
# 32| 5: [BlockStmt] { ... }
|
||||
# 32| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 32| 1: [BlockStmt] { ... }
|
||||
# 34| 2: [Method] f
|
||||
# 34| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 34| 0: [Parameter] x
|
||||
# 34| 0: [TypeAccess] String
|
||||
# 34| 1: [Parameter] y
|
||||
# 34| 0: [TypeAccess] String
|
||||
# 34| 2: [Parameter] z
|
||||
# 34| 0: [TypeAccess] String
|
||||
# 34| 5: [BlockStmt] { ... }
|
||||
# 35| 0: [ExprStmt] <Expr>;
|
||||
# 35| 0: [MethodAccess] sink(...)
|
||||
# 35| -1: [TypeAccess] TestKt
|
||||
# 35| 0: [VarAccess] y
|
||||
# 34| 3: [Method] f$default
|
||||
# 34| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 34| 0: [Parameter] p0
|
||||
# 34| 0: [TypeAccess] String
|
||||
# 34| 1: [Parameter] p1
|
||||
# 34| 0: [TypeAccess] String
|
||||
# 34| 2: [Parameter] p2
|
||||
# 34| 0: [TypeAccess] String
|
||||
# 34| 3: [Parameter] p3
|
||||
# 34| 0: [TypeAccess] int
|
||||
# 34| 4: [Parameter] p4
|
||||
# 34| 0: [TypeAccess] Object
|
||||
# 34| 5: [BlockStmt] { ... }
|
||||
# 34| 0: [IfStmt] if (...)
|
||||
# 34| 0: [EQExpr] ... == ...
|
||||
# 34| 0: [AndBitwiseExpr] ... & ...
|
||||
# 34| 0: [IntegerLiteral] 2
|
||||
# 34| 1: [VarAccess] p3
|
||||
# 34| 1: [IntegerLiteral] 0
|
||||
# 34| 1: [ExprStmt] <Expr>;
|
||||
# 34| 0: [AssignExpr] ...=...
|
||||
# 34| 0: [VarAccess] p1
|
||||
# 34| 1: [VarAccess] p0
|
||||
# 34| 1: [IfStmt] if (...)
|
||||
# 34| 0: [EQExpr] ... == ...
|
||||
# 34| 0: [AndBitwiseExpr] ... & ...
|
||||
# 34| 0: [IntegerLiteral] 4
|
||||
# 34| 1: [VarAccess] p3
|
||||
# 34| 1: [IntegerLiteral] 0
|
||||
# 34| 1: [ExprStmt] <Expr>;
|
||||
# 34| 0: [AssignExpr] ...=...
|
||||
# 34| 0: [VarAccess] p2
|
||||
# 34| 1: [StringLiteral] hello world
|
||||
# 34| 2: [ReturnStmt] return ...
|
||||
# 34| 0: [MethodAccess] f(...)
|
||||
# 34| -1: [TypeAccess] TestStaticMember
|
||||
# 34| 0: [VarAccess] p0
|
||||
# 34| 1: [VarAccess] p1
|
||||
# 34| 2: [VarAccess] p2
|
||||
# 38| 4: [Method] user
|
||||
# 38| 3: [TypeAccess] Unit
|
||||
# 38| 5: [BlockStmt] { ... }
|
||||
# 39| 0: [ExprStmt] <Expr>;
|
||||
# 39| 0: [MethodAccess] f$default(...)
|
||||
# 39| -1: [TypeAccess] TestStaticMember
|
||||
# 39| 0: [StringLiteral] static sunk
|
||||
# 1| 1: [NullLiteral] null
|
||||
# 1| 2: [NullLiteral] null
|
||||
# 1| 3: [IntegerLiteral] 1
|
||||
# 1| 4: [NullLiteral] null
|
||||
# 40| 1: [ExprStmt] <Expr>;
|
||||
# 40| 0: [MethodAccess] f$default(...)
|
||||
# 40| -1: [TypeAccess] TestStaticMember
|
||||
# 40| 0: [StringLiteral] static sunk fp
|
||||
# 40| 1: [StringLiteral] static sunk 2
|
||||
# 1| 2: [NullLiteral] null
|
||||
# 1| 3: [IntegerLiteral] 3
|
||||
# 1| 4: [NullLiteral] null
|
||||
# 41| 2: [ExprStmt] <Expr>;
|
||||
# 41| 0: [MethodAccess] f(...)
|
||||
# 41| -1: [TypeAccess] TestStaticMember
|
||||
# 41| 0: [StringLiteral] not sunk
|
||||
# 41| 1: [StringLiteral] static sunk 3
|
||||
# 41| 2: [StringLiteral] not sunk
|
||||
# 46| 5: [Class] ExtendMe
|
||||
# 46| 1: [Constructor] ExtendMe
|
||||
# 46| 5: [BlockStmt] { ... }
|
||||
# 46| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 46| 1: [BlockStmt] { ... }
|
||||
# 48| 2: [Method] f
|
||||
# 48| 3: [TypeAccess] String
|
||||
#-----| 4: (Parameters)
|
||||
# 48| 0: [Parameter] x
|
||||
# 48| 0: [TypeAccess] String
|
||||
# 48| 5: [BlockStmt] { ... }
|
||||
# 48| 0: [ReturnStmt] return ...
|
||||
# 48| 0: [VarAccess] x
|
||||
# 52| 6: [Class] TestReceiverReferences
|
||||
# 52| 1: [Constructor] TestReceiverReferences
|
||||
# 52| 5: [BlockStmt] { ... }
|
||||
# 52| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 52| 1: [BlockStmt] { ... }
|
||||
# 54| 2: [Method] g
|
||||
# 54| 3: [TypeAccess] String
|
||||
#-----| 4: (Parameters)
|
||||
# 54| 0: [Parameter] x
|
||||
# 54| 0: [TypeAccess] String
|
||||
# 54| 5: [BlockStmt] { ... }
|
||||
# 54| 0: [ReturnStmt] return ...
|
||||
# 54| 0: [VarAccess] x
|
||||
# 56| 3: [ExtensionMethod] test
|
||||
# 56| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 56| 0: [Parameter] <this>
|
||||
# 56| 0: [TypeAccess] ExtendMe
|
||||
# 56| 1: [Parameter] x
|
||||
# 56| 0: [TypeAccess] String
|
||||
# 56| 2: [Parameter] y
|
||||
# 56| 0: [TypeAccess] String
|
||||
# 56| 3: [Parameter] z
|
||||
# 56| 0: [TypeAccess] String
|
||||
# 56| 5: [BlockStmt] { ... }
|
||||
# 57| 0: [ExprStmt] <Expr>;
|
||||
# 57| 0: [MethodAccess] sink(...)
|
||||
# 57| -1: [TypeAccess] TestKt
|
||||
# 57| 0: [VarAccess] y
|
||||
# 56| 4: [Method] test$default
|
||||
# 56| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 56| 0: [Parameter] p0
|
||||
# 56| 0: [TypeAccess] ExtendMe
|
||||
# 56| 1: [Parameter] p1
|
||||
# 56| 0: [TypeAccess] TestReceiverReferences
|
||||
# 56| 2: [Parameter] p2
|
||||
# 56| 0: [TypeAccess] String
|
||||
# 56| 3: [Parameter] p3
|
||||
# 56| 0: [TypeAccess] String
|
||||
# 56| 4: [Parameter] p4
|
||||
# 56| 0: [TypeAccess] String
|
||||
# 56| 5: [Parameter] p5
|
||||
# 56| 0: [TypeAccess] int
|
||||
# 56| 6: [Parameter] p6
|
||||
# 56| 0: [TypeAccess] Object
|
||||
# 56| 5: [BlockStmt] { ... }
|
||||
# 56| 0: [IfStmt] if (...)
|
||||
# 56| 0: [EQExpr] ... == ...
|
||||
# 56| 0: [AndBitwiseExpr] ... & ...
|
||||
# 56| 0: [IntegerLiteral] 2
|
||||
# 56| 1: [VarAccess] p5
|
||||
# 56| 1: [IntegerLiteral] 0
|
||||
# 56| 1: [ExprStmt] <Expr>;
|
||||
# 56| 0: [AssignExpr] ...=...
|
||||
# 56| 0: [VarAccess] p3
|
||||
# 56| 1: [MethodAccess] f(...)
|
||||
# 56| -1: [VarAccess] p0
|
||||
# 56| 0: [MethodAccess] g(...)
|
||||
# 56| -1: [VarAccess] p1
|
||||
# 56| 0: [VarAccess] p2
|
||||
# 56| 1: [IfStmt] if (...)
|
||||
# 56| 0: [EQExpr] ... == ...
|
||||
# 56| 0: [AndBitwiseExpr] ... & ...
|
||||
# 56| 0: [IntegerLiteral] 4
|
||||
# 56| 1: [VarAccess] p5
|
||||
# 56| 1: [IntegerLiteral] 0
|
||||
# 56| 1: [ExprStmt] <Expr>;
|
||||
# 56| 0: [AssignExpr] ...=...
|
||||
# 56| 0: [VarAccess] p4
|
||||
# 56| 1: [StringLiteral] hello world
|
||||
# 56| 2: [ReturnStmt] return ...
|
||||
# 56| 0: [MethodAccess] test(...)
|
||||
# 56| -1: [VarAccess] p1
|
||||
# 56| 0: [VarAccess] p0
|
||||
# 56| 1: [VarAccess] p2
|
||||
# 56| 2: [VarAccess] p3
|
||||
# 56| 3: [VarAccess] p4
|
||||
# 60| 5: [Method] user
|
||||
# 60| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 60| 0: [Parameter] t
|
||||
# 60| 0: [TypeAccess] ExtendMe
|
||||
# 60| 5: [BlockStmt] { ... }
|
||||
# 61| 0: [ExprStmt] <Expr>;
|
||||
# 61| 0: [MethodAccess] test$default(...)
|
||||
# 61| -1: [TypeAccess] TestReceiverReferences
|
||||
# 61| 0: [VarAccess] t
|
||||
# 61| 1: [ThisAccess] this
|
||||
# 61| 2: [StringLiteral] receiver refs sunk
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [NullLiteral] null
|
||||
# 1| 5: [IntegerLiteral] 1
|
||||
# 1| 6: [NullLiteral] null
|
||||
# 62| 1: [ExprStmt] <Expr>;
|
||||
# 62| 0: [MethodAccess] test$default(...)
|
||||
# 62| -1: [TypeAccess] TestReceiverReferences
|
||||
# 62| 0: [VarAccess] t
|
||||
# 62| 1: [ThisAccess] this
|
||||
# 62| 2: [StringLiteral] receiver refs sunk fp
|
||||
# 62| 3: [StringLiteral] receiver refs sunk 2
|
||||
# 1| 4: [NullLiteral] null
|
||||
# 1| 5: [IntegerLiteral] 3
|
||||
# 1| 6: [NullLiteral] null
|
||||
# 63| 2: [ExprStmt] <Expr>;
|
||||
# 63| 0: [MethodAccess] test(...)
|
||||
# 63| -1: [ThisAccess] this
|
||||
# 63| 0: [VarAccess] t
|
||||
# 63| 1: [StringLiteral] not sunk
|
||||
# 63| 2: [StringLiteral] receiver refs sunk 3
|
||||
# 63| 3: [StringLiteral] not sunk
|
||||
# 68| 7: [Class] TestConstructor
|
||||
# 68| 1: [Constructor] TestConstructor
|
||||
#-----| 4: (Parameters)
|
||||
# 68| 0: [Parameter] x
|
||||
# 68| 0: [TypeAccess] String
|
||||
# 68| 1: [Parameter] y
|
||||
# 68| 0: [TypeAccess] String
|
||||
# 68| 2: [Parameter] z
|
||||
# 68| 0: [TypeAccess] String
|
||||
# 68| 5: [BlockStmt] { ... }
|
||||
# 68| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 68| 1: [BlockStmt] { ... }
|
||||
# 71| 0: [ExprStmt] <Expr>;
|
||||
# 71| 0: [MethodAccess] sink(...)
|
||||
# 71| -1: [TypeAccess] TestKt
|
||||
# 71| 0: [VarAccess] y
|
||||
# 68| 2: [Constructor] TestConstructor
|
||||
#-----| 4: (Parameters)
|
||||
# 68| 0: [Parameter] p0
|
||||
# 68| 0: [TypeAccess] String
|
||||
# 68| 1: [Parameter] p1
|
||||
# 68| 0: [TypeAccess] String
|
||||
# 68| 2: [Parameter] p2
|
||||
# 68| 0: [TypeAccess] String
|
||||
# 68| 3: [Parameter] p3
|
||||
# 68| 0: [TypeAccess] int
|
||||
# 68| 4: [Parameter] p4
|
||||
# 68| 0: [TypeAccess] DefaultConstructorMarker
|
||||
# 68| 5: [BlockStmt] { ... }
|
||||
# 68| 0: [IfStmt] if (...)
|
||||
# 68| 0: [EQExpr] ... == ...
|
||||
# 68| 0: [AndBitwiseExpr] ... & ...
|
||||
# 68| 0: [IntegerLiteral] 2
|
||||
# 68| 1: [VarAccess] p3
|
||||
# 68| 1: [IntegerLiteral] 0
|
||||
# 68| 1: [ExprStmt] <Expr>;
|
||||
# 68| 0: [AssignExpr] ...=...
|
||||
# 68| 0: [VarAccess] p1
|
||||
# 68| 1: [VarAccess] p0
|
||||
# 68| 1: [IfStmt] if (...)
|
||||
# 68| 0: [EQExpr] ... == ...
|
||||
# 68| 0: [AndBitwiseExpr] ... & ...
|
||||
# 68| 0: [IntegerLiteral] 4
|
||||
# 68| 1: [VarAccess] p3
|
||||
# 68| 1: [IntegerLiteral] 0
|
||||
# 68| 1: [ExprStmt] <Expr>;
|
||||
# 68| 0: [AssignExpr] ...=...
|
||||
# 68| 0: [VarAccess] p2
|
||||
# 68| 1: [StringLiteral] hello world
|
||||
# 68| 2: [ThisConstructorInvocationStmt] this(...)
|
||||
# 68| 0: [VarAccess] p0
|
||||
# 68| 1: [VarAccess] p1
|
||||
# 68| 2: [VarAccess] p2
|
||||
# 74| 3: [Method] user
|
||||
# 74| 3: [TypeAccess] Unit
|
||||
# 74| 5: [BlockStmt] { ... }
|
||||
# 75| 0: [ExprStmt] <Expr>;
|
||||
# 75| 0: [ImplicitCoercionToUnitExpr] <implicit coercion to unit>
|
||||
# 75| 0: [TypeAccess] Unit
|
||||
# 75| 1: [ClassInstanceExpr] new TestConstructor(...)
|
||||
# 75| -3: [TypeAccess] TestConstructor
|
||||
# 75| 0: [StringLiteral] constructor sunk
|
||||
# 1| 1: [NullLiteral] null
|
||||
# 1| 2: [NullLiteral] null
|
||||
# 1| 3: [IntegerLiteral] 1
|
||||
# 1| 4: [NullLiteral] null
|
||||
# 76| 1: [ExprStmt] <Expr>;
|
||||
# 76| 0: [ImplicitCoercionToUnitExpr] <implicit coercion to unit>
|
||||
# 76| 0: [TypeAccess] Unit
|
||||
# 76| 1: [ClassInstanceExpr] new TestConstructor(...)
|
||||
# 76| -3: [TypeAccess] TestConstructor
|
||||
# 76| 0: [StringLiteral] constructor sunk fp
|
||||
# 76| 1: [StringLiteral] constructor sunk 2
|
||||
# 1| 2: [NullLiteral] null
|
||||
# 1| 3: [IntegerLiteral] 3
|
||||
# 1| 4: [NullLiteral] null
|
||||
# 77| 2: [ExprStmt] <Expr>;
|
||||
# 77| 0: [ImplicitCoercionToUnitExpr] <implicit coercion to unit>
|
||||
# 77| 0: [TypeAccess] Unit
|
||||
# 77| 1: [ClassInstanceExpr] new TestConstructor(...)
|
||||
# 77| -3: [TypeAccess] TestConstructor
|
||||
# 77| 0: [StringLiteral] not sunk
|
||||
# 77| 1: [StringLiteral] constructor sunk 3
|
||||
# 77| 2: [StringLiteral] not sunk
|
||||
# 82| 8: [Class] TestLocal
|
||||
# 82| 1: [Constructor] TestLocal
|
||||
# 82| 5: [BlockStmt] { ... }
|
||||
# 82| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 82| 1: [BlockStmt] { ... }
|
||||
# 84| 2: [Method] enclosing
|
||||
# 84| 3: [TypeAccess] Unit
|
||||
# 84| 5: [BlockStmt] { ... }
|
||||
# 86| 0: [LocalTypeDeclStmt] class ...
|
||||
# 86| 0: [LocalClass]
|
||||
# 86| 1: [Constructor]
|
||||
# 86| 5: [BlockStmt] { ... }
|
||||
# 86| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 86| 2: [Method] f
|
||||
# 86| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 86| 0: [Parameter] x
|
||||
# 86| 0: [TypeAccess] String
|
||||
# 86| 1: [Parameter] y
|
||||
# 86| 0: [TypeAccess] String
|
||||
# 86| 2: [Parameter] z
|
||||
# 86| 0: [TypeAccess] String
|
||||
# 86| 5: [BlockStmt] { ... }
|
||||
# 87| 0: [ExprStmt] <Expr>;
|
||||
# 87| 0: [MethodAccess] sink(...)
|
||||
# 87| -1: [TypeAccess] TestKt
|
||||
# 87| 0: [VarAccess] y
|
||||
# 86| 3: [Method] f$default
|
||||
# 86| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 86| 0: [Parameter] p0
|
||||
# 86| 0: [TypeAccess] String
|
||||
# 86| 1: [Parameter] p1
|
||||
# 86| 0: [TypeAccess] String
|
||||
# 86| 2: [Parameter] p2
|
||||
# 86| 0: [TypeAccess] String
|
||||
# 86| 3: [Parameter] p3
|
||||
# 86| 0: [TypeAccess] int
|
||||
# 86| 4: [Parameter] p4
|
||||
# 86| 0: [TypeAccess] Object
|
||||
# 86| 5: [BlockStmt] { ... }
|
||||
# 86| 0: [IfStmt] if (...)
|
||||
# 86| 0: [EQExpr] ... == ...
|
||||
# 86| 0: [AndBitwiseExpr] ... & ...
|
||||
# 86| 0: [IntegerLiteral] 2
|
||||
# 86| 1: [VarAccess] p3
|
||||
# 86| 1: [IntegerLiteral] 0
|
||||
# 86| 1: [ExprStmt] <Expr>;
|
||||
# 86| 0: [AssignExpr] ...=...
|
||||
# 86| 0: [VarAccess] p1
|
||||
# 86| 1: [VarAccess] p0
|
||||
# 86| 1: [IfStmt] if (...)
|
||||
# 86| 0: [EQExpr] ... == ...
|
||||
# 86| 0: [AndBitwiseExpr] ... & ...
|
||||
# 86| 0: [IntegerLiteral] 4
|
||||
# 86| 1: [VarAccess] p3
|
||||
# 86| 1: [IntegerLiteral] 0
|
||||
# 86| 1: [ExprStmt] <Expr>;
|
||||
# 86| 0: [AssignExpr] ...=...
|
||||
# 86| 0: [VarAccess] p2
|
||||
# 86| 1: [StringLiteral] hello world
|
||||
# 86| 2: [ReturnStmt] return ...
|
||||
# 86| 0: [MethodAccess] f(...)
|
||||
# 86| -1: [ClassInstanceExpr] new (...)
|
||||
# 86| -3: [TypeAccess] Object
|
||||
# 86| 0: [VarAccess] p0
|
||||
# 86| 1: [VarAccess] p1
|
||||
# 86| 2: [VarAccess] p2
|
||||
# 90| 1: [LocalTypeDeclStmt] class ...
|
||||
# 90| 0: [LocalClass]
|
||||
# 90| 1: [Constructor]
|
||||
# 90| 5: [BlockStmt] { ... }
|
||||
# 90| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 90| 2: [Method] user
|
||||
# 90| 3: [TypeAccess] Unit
|
||||
# 90| 5: [BlockStmt] { ... }
|
||||
# 91| 0: [ExprStmt] <Expr>;
|
||||
# 91| 0: [MethodAccess] f$default(...)
|
||||
# 91| -1: [ClassInstanceExpr] new (...)
|
||||
# 91| -3: [TypeAccess] Object
|
||||
# 91| 0: [StringLiteral] local sunk
|
||||
# 1| 1: [NullLiteral] null
|
||||
# 1| 2: [NullLiteral] null
|
||||
# 1| 3: [IntegerLiteral] 1
|
||||
# 1| 4: [NullLiteral] null
|
||||
# 92| 1: [ExprStmt] <Expr>;
|
||||
# 92| 0: [MethodAccess] f$default(...)
|
||||
# 92| -1: [ClassInstanceExpr] new (...)
|
||||
# 92| -3: [TypeAccess] Object
|
||||
# 92| 0: [StringLiteral] local sunk fp
|
||||
# 92| 1: [StringLiteral] local sunk 2
|
||||
# 1| 2: [NullLiteral] null
|
||||
# 1| 3: [IntegerLiteral] 3
|
||||
# 1| 4: [NullLiteral] null
|
||||
# 93| 2: [ExprStmt] <Expr>;
|
||||
# 93| 0: [MethodAccess] f(...)
|
||||
# 93| -1: [ClassInstanceExpr] new (...)
|
||||
# 93| -3: [TypeAccess] Object
|
||||
# 93| 0: [StringLiteral] not sunk
|
||||
# 93| 1: [StringLiteral] local sunk 3
|
||||
# 93| 2: [StringLiteral] not sunk
|
||||
# 100| 9: [Class] TestLocalClass
|
||||
# 100| 1: [Constructor] TestLocalClass
|
||||
# 100| 5: [BlockStmt] { ... }
|
||||
# 100| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 100| 1: [BlockStmt] { ... }
|
||||
# 102| 2: [Method] enclosingFunction
|
||||
# 102| 3: [TypeAccess] Unit
|
||||
# 102| 5: [BlockStmt] { ... }
|
||||
# 104| 0: [LocalTypeDeclStmt] class ...
|
||||
# 104| 0: [LocalClass] EnclosingLocalClass
|
||||
# 104| 1: [Constructor] EnclosingLocalClass
|
||||
# 104| 5: [BlockStmt] { ... }
|
||||
# 104| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 104| 1: [BlockStmt] { ... }
|
||||
# 106| 2: [Method] f
|
||||
# 106| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 106| 0: [Parameter] x
|
||||
# 106| 0: [TypeAccess] String
|
||||
# 106| 1: [Parameter] y
|
||||
# 106| 0: [TypeAccess] String
|
||||
# 106| 2: [Parameter] z
|
||||
# 106| 0: [TypeAccess] String
|
||||
# 106| 5: [BlockStmt] { ... }
|
||||
# 107| 0: [ExprStmt] <Expr>;
|
||||
# 107| 0: [MethodAccess] sink(...)
|
||||
# 107| -1: [TypeAccess] TestKt
|
||||
# 107| 0: [VarAccess] y
|
||||
# 106| 3: [Method] f$default
|
||||
# 106| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 106| 0: [Parameter] p0
|
||||
# 106| 0: [TypeAccess] EnclosingLocalClass
|
||||
# 106| 1: [Parameter] p1
|
||||
# 106| 0: [TypeAccess] String
|
||||
# 106| 2: [Parameter] p2
|
||||
# 106| 0: [TypeAccess] String
|
||||
# 106| 3: [Parameter] p3
|
||||
# 106| 0: [TypeAccess] String
|
||||
# 106| 4: [Parameter] p4
|
||||
# 106| 0: [TypeAccess] int
|
||||
# 106| 5: [Parameter] p5
|
||||
# 106| 0: [TypeAccess] Object
|
||||
# 106| 5: [BlockStmt] { ... }
|
||||
# 106| 0: [IfStmt] if (...)
|
||||
# 106| 0: [EQExpr] ... == ...
|
||||
# 106| 0: [AndBitwiseExpr] ... & ...
|
||||
# 106| 0: [IntegerLiteral] 2
|
||||
# 106| 1: [VarAccess] p4
|
||||
# 106| 1: [IntegerLiteral] 0
|
||||
# 106| 1: [ExprStmt] <Expr>;
|
||||
# 106| 0: [AssignExpr] ...=...
|
||||
# 106| 0: [VarAccess] p2
|
||||
# 106| 1: [VarAccess] p1
|
||||
# 106| 1: [IfStmt] if (...)
|
||||
# 106| 0: [EQExpr] ... == ...
|
||||
# 106| 0: [AndBitwiseExpr] ... & ...
|
||||
# 106| 0: [IntegerLiteral] 4
|
||||
# 106| 1: [VarAccess] p4
|
||||
# 106| 1: [IntegerLiteral] 0
|
||||
# 106| 1: [ExprStmt] <Expr>;
|
||||
# 106| 0: [AssignExpr] ...=...
|
||||
# 106| 0: [VarAccess] p3
|
||||
# 106| 1: [StringLiteral] hello world
|
||||
# 106| 2: [ReturnStmt] return ...
|
||||
# 106| 0: [MethodAccess] f(...)
|
||||
# 106| -1: [VarAccess] p0
|
||||
# 106| 0: [VarAccess] p1
|
||||
# 106| 1: [VarAccess] p2
|
||||
# 106| 2: [VarAccess] p3
|
||||
# 110| 4: [Method] user
|
||||
# 110| 3: [TypeAccess] Unit
|
||||
# 110| 5: [BlockStmt] { ... }
|
||||
# 111| 0: [ExprStmt] <Expr>;
|
||||
# 111| 0: [MethodAccess] f$default(...)
|
||||
# 111| -1: [TypeAccess] EnclosingLocalClass
|
||||
# 111| 0: [ThisAccess] this
|
||||
# 111| 1: [StringLiteral] local sunk
|
||||
# 1| 2: [NullLiteral] null
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [IntegerLiteral] 1
|
||||
# 1| 5: [NullLiteral] null
|
||||
# 112| 1: [ExprStmt] <Expr>;
|
||||
# 112| 0: [MethodAccess] f$default(...)
|
||||
# 112| -1: [TypeAccess] EnclosingLocalClass
|
||||
# 112| 0: [ThisAccess] this
|
||||
# 112| 1: [StringLiteral] local sunk fp
|
||||
# 112| 2: [StringLiteral] local sunk 2
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [IntegerLiteral] 3
|
||||
# 1| 5: [NullLiteral] null
|
||||
# 113| 2: [ExprStmt] <Expr>;
|
||||
# 113| 0: [MethodAccess] f(...)
|
||||
# 113| -1: [ThisAccess] this
|
||||
# 113| 0: [StringLiteral] not sunk
|
||||
# 113| 1: [StringLiteral] local sunk 3
|
||||
# 113| 2: [StringLiteral] not sunk
|
||||
# 122| 10: [Class,GenericType,ParameterizedType] TestGeneric
|
||||
#-----| -2: (Generic Parameters)
|
||||
# 122| 0: [TypeVariable] T
|
||||
# 122| 1: [Constructor] TestGeneric
|
||||
# 122| 5: [BlockStmt] { ... }
|
||||
# 122| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 122| 1: [BlockStmt] { ... }
|
||||
# 124| 2: [Method] f
|
||||
# 124| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 124| 0: [Parameter] x
|
||||
# 124| 0: [TypeAccess] T
|
||||
# 124| 1: [Parameter] y
|
||||
# 124| 0: [TypeAccess] T
|
||||
# 124| 2: [Parameter] z
|
||||
# 124| 0: [TypeAccess] T
|
||||
# 124| 5: [BlockStmt] { ... }
|
||||
# 125| 0: [ExprStmt] <Expr>;
|
||||
# 125| 0: [MethodAccess] sink(...)
|
||||
# 125| -1: [TypeAccess] TestKt
|
||||
# 125| 0: [VarAccess] y
|
||||
# 124| 3: [Method] f$default
|
||||
# 124| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 124| 0: [Parameter] p0
|
||||
# 124| 0: [TypeAccess] TestGeneric<>
|
||||
# 124| 1: [Parameter] p1
|
||||
# 124| 0: [TypeAccess] Object
|
||||
# 124| 2: [Parameter] p2
|
||||
# 124| 0: [TypeAccess] Object
|
||||
# 124| 3: [Parameter] p3
|
||||
# 124| 0: [TypeAccess] Object
|
||||
# 124| 4: [Parameter] p4
|
||||
# 124| 0: [TypeAccess] int
|
||||
# 124| 5: [Parameter] p5
|
||||
# 124| 0: [TypeAccess] Object
|
||||
# 124| 5: [BlockStmt] { ... }
|
||||
# 124| 0: [IfStmt] if (...)
|
||||
# 124| 0: [EQExpr] ... == ...
|
||||
# 124| 0: [AndBitwiseExpr] ... & ...
|
||||
# 124| 0: [IntegerLiteral] 2
|
||||
# 124| 1: [VarAccess] p4
|
||||
# 124| 1: [IntegerLiteral] 0
|
||||
# 124| 1: [ExprStmt] <Expr>;
|
||||
# 124| 0: [AssignExpr] ...=...
|
||||
# 124| 0: [VarAccess] p2
|
||||
# 124| 1: [VarAccess] p1
|
||||
# 124| 1: [IfStmt] if (...)
|
||||
# 124| 0: [EQExpr] ... == ...
|
||||
# 124| 0: [AndBitwiseExpr] ... & ...
|
||||
# 124| 0: [IntegerLiteral] 4
|
||||
# 124| 1: [VarAccess] p4
|
||||
# 124| 1: [IntegerLiteral] 0
|
||||
# 124| 1: [ExprStmt] <Expr>;
|
||||
# 124| 0: [AssignExpr] ...=...
|
||||
# 124| 0: [VarAccess] p3
|
||||
# 124| 1: [NullLiteral] null
|
||||
# 124| 2: [ReturnStmt] return ...
|
||||
# 124| 0: [MethodAccess] f(...)
|
||||
# 124| -1: [VarAccess] p0
|
||||
# 124| 0: [VarAccess] p1
|
||||
# 124| 1: [VarAccess] p2
|
||||
# 124| 2: [VarAccess] p3
|
||||
# 128| 4: [Method] user
|
||||
# 128| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 128| 0: [Parameter] tgs
|
||||
# 128| 0: [TypeAccess] TestGeneric<String>
|
||||
# 128| 0: [TypeAccess] String
|
||||
# 128| 1: [Parameter] tcs
|
||||
# 128| 0: [TypeAccess] TestGeneric<CharSequence>
|
||||
# 128| 0: [TypeAccess] CharSequence
|
||||
# 128| 5: [BlockStmt] { ... }
|
||||
# 129| 0: [ExprStmt] <Expr>;
|
||||
# 129| 0: [MethodAccess] f$default(...)
|
||||
# 129| -1: [TypeAccess] TestGeneric<>
|
||||
# 129| 0: [VarAccess] tgs
|
||||
# 129| 1: [StringLiteral] generic sunk
|
||||
# 1| 2: [NullLiteral] null
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [IntegerLiteral] 1
|
||||
# 1| 5: [NullLiteral] null
|
||||
# 130| 1: [ExprStmt] <Expr>;
|
||||
# 130| 0: [MethodAccess] f$default(...)
|
||||
# 130| -1: [TypeAccess] TestGeneric<>
|
||||
# 130| 0: [VarAccess] tcs
|
||||
# 130| 1: [StringLiteral] generic sunk fp
|
||||
# 130| 2: [StringLiteral] generic sunk 2
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [IntegerLiteral] 3
|
||||
# 1| 5: [NullLiteral] null
|
||||
# 131| 2: [ExprStmt] <Expr>;
|
||||
# 131| 0: [MethodAccess] f(...)
|
||||
# 131| -1: [VarAccess] tgs
|
||||
# 131| 0: [StringLiteral] not sunk
|
||||
# 131| 1: [StringLiteral] generic sunk 3
|
||||
# 131| 2: [StringLiteral] not sunk
|
||||
# 132| 3: [ExprStmt] <Expr>;
|
||||
# 132| 0: [MethodAccess] f(...)
|
||||
# 132| -1: [VarAccess] tcs
|
||||
# 132| 0: [StringLiteral] not sunk
|
||||
# 132| 1: [StringLiteral] generic sunk 3
|
||||
# 132| 2: [StringLiteral] not sunk
|
||||
# 135| 5: [Method] testReturn
|
||||
# 135| 3: [TypeAccess] T
|
||||
#-----| 4: (Parameters)
|
||||
# 135| 0: [Parameter] t1
|
||||
# 135| 0: [TypeAccess] T
|
||||
# 135| 1: [Parameter] t2
|
||||
# 135| 0: [TypeAccess] T
|
||||
# 135| 5: [BlockStmt] { ... }
|
||||
# 135| 0: [ReturnStmt] return ...
|
||||
# 135| 0: [VarAccess] t1
|
||||
# 135| 6: [Method] testReturn$default
|
||||
# 135| 3: [TypeAccess] Object
|
||||
#-----| 4: (Parameters)
|
||||
# 135| 0: [Parameter] p0
|
||||
# 135| 0: [TypeAccess] TestGeneric<>
|
||||
# 135| 1: [Parameter] p1
|
||||
# 135| 0: [TypeAccess] Object
|
||||
# 135| 2: [Parameter] p2
|
||||
# 135| 0: [TypeAccess] Object
|
||||
# 135| 3: [Parameter] p3
|
||||
# 135| 0: [TypeAccess] int
|
||||
# 135| 4: [Parameter] p4
|
||||
# 135| 0: [TypeAccess] Object
|
||||
# 135| 5: [BlockStmt] { ... }
|
||||
# 135| 0: [IfStmt] if (...)
|
||||
# 135| 0: [EQExpr] ... == ...
|
||||
# 135| 0: [AndBitwiseExpr] ... & ...
|
||||
# 135| 0: [IntegerLiteral] 2
|
||||
# 135| 1: [VarAccess] p3
|
||||
# 135| 1: [IntegerLiteral] 0
|
||||
# 135| 1: [ExprStmt] <Expr>;
|
||||
# 135| 0: [AssignExpr] ...=...
|
||||
# 135| 0: [VarAccess] p2
|
||||
# 135| 1: [NullLiteral] null
|
||||
# 135| 1: [ReturnStmt] return ...
|
||||
# 135| 0: [MethodAccess] testReturn(...)
|
||||
# 135| -1: [VarAccess] p0
|
||||
# 135| 0: [VarAccess] p1
|
||||
# 135| 1: [VarAccess] p2
|
||||
# 137| 7: [Method] testReturnUser
|
||||
# 137| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 137| 0: [Parameter] tgs
|
||||
# 137| 0: [TypeAccess] TestGeneric<String>
|
||||
# 137| 0: [TypeAccess] String
|
||||
# 137| 5: [BlockStmt] { ... }
|
||||
# 138| 0: [ExprStmt] <Expr>;
|
||||
# 138| 0: [MethodAccess] sink(...)
|
||||
# 138| -1: [TypeAccess] TestKt
|
||||
# 138| 0: [MethodAccess] testReturn$default(...)
|
||||
# 138| -1: [TypeAccess] TestGeneric<>
|
||||
# 138| 0: [VarAccess] tgs
|
||||
# 138| 1: [StringLiteral] sunk return value
|
||||
# 1| 2: [NullLiteral] null
|
||||
# 1| 3: [IntegerLiteral] 1
|
||||
# 1| 4: [NullLiteral] null
|
||||
@@ -0,0 +1 @@
|
||||
semmle/code/java/PrintAst.ql
|
||||
@@ -0,0 +1,2 @@
|
||||
shouldBeSunkButIsnt
|
||||
shouldntBeSunkButIs
|
||||
@@ -0,0 +1,34 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
class ShouldNotBeSunk extends StringLiteral {
|
||||
ShouldNotBeSunk() { this.getValue().matches("%not sunk%") }
|
||||
}
|
||||
|
||||
class ShouldBeSunk extends StringLiteral {
|
||||
ShouldBeSunk() {
|
||||
this.getValue().matches("%sunk%") and
|
||||
not this instanceof ShouldNotBeSunk
|
||||
}
|
||||
}
|
||||
|
||||
class Config extends DataFlow::Configuration {
|
||||
Config() { this = "Config" }
|
||||
|
||||
override predicate isSource(DataFlow::Node n) {
|
||||
n.asExpr() instanceof ShouldBeSunk or
|
||||
n.asExpr() instanceof ShouldNotBeSunk
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node n) {
|
||||
n.asExpr().(Argument).getCall().getCallee().getName() = "sink"
|
||||
}
|
||||
}
|
||||
|
||||
predicate isSunk(StringLiteral sl) {
|
||||
exists(Config c, DataFlow::Node source | c.hasFlow(source, _) and sl = source.asExpr())
|
||||
}
|
||||
|
||||
query predicate shouldBeSunkButIsnt(ShouldBeSunk src) { not isSunk(src) }
|
||||
|
||||
query predicate shouldntBeSunkButIs(ShouldNotBeSunk src) { isSunk(src) }
|
||||
141
java/ql/test/kotlin/library-tests/parameter-defaults/test.kt
Normal file
141
java/ql/test/kotlin/library-tests/parameter-defaults/test.kt
Normal file
@@ -0,0 +1,141 @@
|
||||
fun sink(a: Any?) { }
|
||||
|
||||
class TestMember {
|
||||
|
||||
fun f(x: String, y: String = x, z: String = "hello world") {
|
||||
sink(y)
|
||||
}
|
||||
|
||||
fun user() {
|
||||
f("member sunk")
|
||||
f("member sunk fp", "member sunk 2")
|
||||
f("not sunk", "member sunk 3", "not sunk")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestExtensionMember {
|
||||
|
||||
fun String.f(x: String, y: String = x, z: String = "hello world") {
|
||||
sink(this)
|
||||
sink(y)
|
||||
}
|
||||
|
||||
fun user(sunk: String) {
|
||||
sunk.f("extension sunk")
|
||||
sunk.f("extension sunk fp", "extension sunk 2")
|
||||
sunk.f("not sunk", "extension sunk 3", "not sunk")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object TestStaticMember {
|
||||
|
||||
@JvmStatic fun f(x: String, y: String = x, z: String = "hello world") {
|
||||
sink(y)
|
||||
}
|
||||
|
||||
fun user() {
|
||||
f("static sunk")
|
||||
f("static sunk fp", "static sunk 2")
|
||||
f("not sunk", "static sunk 3", "not sunk")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ExtendMe {
|
||||
|
||||
fun f(x: String) = x
|
||||
|
||||
}
|
||||
|
||||
class TestReceiverReferences {
|
||||
|
||||
fun g(x: String) = x
|
||||
|
||||
fun ExtendMe.test(x: String, y: String = this.f(this@TestReceiverReferences.g(x)), z: String = "hello world") {
|
||||
sink(y)
|
||||
}
|
||||
|
||||
fun user(t: ExtendMe) {
|
||||
t.test("receiver refs sunk")
|
||||
t.test("receiver refs sunk fp", "receiver refs sunk 2")
|
||||
t.test("not sunk", "receiver refs sunk 3", "not sunk")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestConstructor(x: String, y: String = x, z: String = "hello world") {
|
||||
|
||||
init {
|
||||
sink(y)
|
||||
}
|
||||
|
||||
fun user() {
|
||||
TestConstructor("constructor sunk")
|
||||
TestConstructor("constructor sunk fp", "constructor sunk 2")
|
||||
TestConstructor("not sunk", "constructor sunk 3", "not sunk")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestLocal {
|
||||
|
||||
fun enclosing() {
|
||||
|
||||
fun f(x: String, y: String = x, z: String = "hello world") {
|
||||
sink(y)
|
||||
}
|
||||
|
||||
fun user() {
|
||||
f("local sunk")
|
||||
f("local sunk fp", "local sunk 2")
|
||||
f("not sunk", "local sunk 3", "not sunk")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestLocalClass {
|
||||
|
||||
fun enclosingFunction() {
|
||||
|
||||
class EnclosingLocalClass {
|
||||
|
||||
fun f(x: String, y: String = x, z: String = "hello world") {
|
||||
sink(y)
|
||||
}
|
||||
|
||||
fun user() {
|
||||
f("local sunk")
|
||||
f("local sunk fp", "local sunk 2")
|
||||
f("not sunk", "local sunk 3", "not sunk")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestGeneric<T> {
|
||||
|
||||
fun f(x: T, y: T = x, z: T? = null) {
|
||||
sink(y)
|
||||
}
|
||||
|
||||
fun user(tgs: TestGeneric<String>, tcs: TestGeneric<CharSequence>) {
|
||||
tgs.f("generic sunk")
|
||||
tcs.f("generic sunk fp", "generic sunk 2")
|
||||
tgs.f("not sunk", "generic sunk 3", "not sunk")
|
||||
tcs.f("not sunk", "generic sunk 3", "not sunk")
|
||||
}
|
||||
|
||||
fun testReturn(t1: T, t2: T? = null) = t1
|
||||
|
||||
fun testReturnUser(tgs: TestGeneric<String>) {
|
||||
sink(tgs.testReturn("sunk return value"))
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user