mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Extract generic method prototypes
These feature substituted types according to their declaring generic specialisation, with wildcards that reach top-level being converted to their upper or lower bound depending on usage context. This commit also includes an incidental fix such that constructors declare their return-type as unit, consistent with the Java extractor.
This commit is contained in:
committed by
Ian Lynagh
parent
b38f47f9ea
commit
bb3049a686
@@ -1,6 +1,9 @@
|
||||
package com.github.codeql
|
||||
|
||||
import com.github.codeql.utils.versions.functionN
|
||||
import com.github.codeql.utils.lowerBound
|
||||
import com.github.codeql.utils.substituteTypeAndArguments
|
||||
import com.github.codeql.utils.upperBound
|
||||
import com.semmle.extractor.java.OdasaOutput
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
|
||||
@@ -12,10 +15,12 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.toIrConst
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
open class KotlinFileExtractor(
|
||||
override val logger: FileLogger,
|
||||
@@ -49,7 +54,7 @@ open class KotlinFileExtractor(
|
||||
is IrClass -> return getClassLabel(element, listOf()).classLabel
|
||||
is IrTypeParameter -> return getTypeParameterLabel(element)
|
||||
is IrFunction -> return getFunctionLabel(element)
|
||||
is IrValueParameter -> return getValueParameterLabel(element)
|
||||
is IrValueParameter -> return getValueParameterLabel(element, null)
|
||||
is IrProperty -> return getPropertyLabel(element)
|
||||
is IrField -> return getFieldLabel(element)
|
||||
is IrEnumEntry -> return getEnumEntryLabel(element)
|
||||
@@ -87,7 +92,7 @@ open class KotlinFileExtractor(
|
||||
return id
|
||||
}
|
||||
|
||||
fun extractClassInstance(c: IrClass, typeArgs: List<IrTypeArgument>): Label<out DbClassorinterface> {
|
||||
fun extractClassInstance(c: IrClass, typeArgs: List<IrTypeArgument>, extractFunctionPrototypes: Boolean): Label<out DbClassorinterface> {
|
||||
if (typeArgs.isEmpty()) {
|
||||
logger.warn(Severity.ErrorSevere, "Instance without type arguments: " + c.name.asString())
|
||||
}
|
||||
@@ -128,6 +133,18 @@ open class KotlinFileExtractor(
|
||||
val locId = tw.getLocation(c)
|
||||
tw.writeHasLocation(id, locId)
|
||||
|
||||
if (extractFunctionPrototypes) {
|
||||
val typeParamSubstitution = c.typeParameters.map({ it.symbol }).zip(typeArgs).toMap()
|
||||
|
||||
c.declarations.map {
|
||||
when(it) {
|
||||
is IrFunction -> extractFunction(it, id, false, typeParamSubstitution)
|
||||
is IrProperty -> extractProperty(it, id, false, typeParamSubstitution)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
@@ -259,12 +276,15 @@ open class KotlinFileExtractor(
|
||||
return FieldResult(instanceId, instanceName)
|
||||
}
|
||||
|
||||
private fun extractValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>, idx: Int): TypeResults {
|
||||
return extractValueParameter(useValueParameter(vp), vp.type, vp.name.asString(), tw.getLocation(vp), parent, idx)
|
||||
private fun extractValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>, idx: Int, typeSubstitutionMap: Map<IrTypeParameterSymbol, IrTypeArgument>?): TypeResults {
|
||||
return extractValueParameter(useValueParameter(vp, parent), vp.type, vp.name.asString(), tw.getLocation(vp), parent, idx, typeSubstitutionMap)
|
||||
}
|
||||
|
||||
private fun extractValueParameter(id: Label<out DbParam>, t: IrType, name: String, locId: Label<DbLocation>, parent: Label<out DbCallable>, idx: Int): TypeResults {
|
||||
val type = useType(t)
|
||||
private fun extractValueParameter(id: Label<out DbParam>, t: IrType, name: String, locId: Label<DbLocation>, parent: Label<out DbCallable>, idx: Int, typeSubstitutionMap: Map<IrTypeParameterSymbol, IrTypeArgument>?): TypeResults {
|
||||
val substitutedType = t.substituteTypeAndArguments(typeSubstitutionMap) {
|
||||
it.lowerBound(pluginContext)
|
||||
}
|
||||
val type = useType(substitutedType)
|
||||
tw.writeParams(id, type.javaResult.id, type.kotlinResult.id, idx, parent, id)
|
||||
tw.writeHasLocation(id, locId)
|
||||
tw.writeParamName(id, name)
|
||||
@@ -338,7 +358,7 @@ open class KotlinFileExtractor(
|
||||
}
|
||||
}
|
||||
|
||||
fun extractFunction(f: IrFunction, parentId: Label<out DbReftype>): Label<out DbCallable> {
|
||||
fun extractFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean = true, typeSubstitutionMap: Map<IrTypeParameterSymbol, IrTypeArgument>? = null): Label<out DbCallable> {
|
||||
currentFunction = f
|
||||
|
||||
f.typeParameters.map { extractTypeParameter(it) }
|
||||
@@ -349,19 +369,21 @@ open class KotlinFileExtractor(
|
||||
if (f.isLocalFunction())
|
||||
getLocalFunctionLabels(f).function
|
||||
else
|
||||
useFunction<DbCallable>(f)
|
||||
// TODO: figure out whether to standardise on naming top-level functions for the file-class
|
||||
// or (as temporarily done here) for their containing package.
|
||||
useFunction<DbCallable>(f, if (f.parent is IrFile) useDeclarationParent(f.parent) else parentId)
|
||||
|
||||
val extReceiver = f.extensionReceiverParameter
|
||||
val idxOffset = if (extReceiver != null) 1 else 0
|
||||
val paramTypes = f.valueParameters.mapIndexed { i, vp ->
|
||||
extractValueParameter(vp, id, i + idxOffset)
|
||||
extractValueParameter(vp, id, i + idxOffset, typeSubstitutionMap)
|
||||
}
|
||||
val allParamTypes = if (extReceiver != null) {
|
||||
val extendedType = useType(extReceiver.type)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
tw.writeKtExtensionFunctions(id as Label<DbMethod>, extendedType.javaResult.id, extendedType.kotlinResult.id)
|
||||
|
||||
val t = extractValueParameter(extReceiver, id, 0)
|
||||
val t = extractValueParameter(extReceiver, id, 0, null)
|
||||
val l = mutableListOf(t)
|
||||
l.addAll(paramTypes)
|
||||
l
|
||||
@@ -371,13 +393,21 @@ open class KotlinFileExtractor(
|
||||
|
||||
val paramsSignature = allParamTypes.joinToString(separator = ",", prefix = "(", postfix = ")") { it.javaResult.signature!! }
|
||||
|
||||
val substReturnType = f.returnType.substituteTypeAndArguments(typeSubstitutionMap) {
|
||||
it.upperBound(pluginContext)
|
||||
}
|
||||
|
||||
if (f.symbol is IrConstructorSymbol) {
|
||||
val returnType = useType(erase(f.returnType), TypeContext.RETURN)
|
||||
val shortName = if (f.returnType.isAnonymous) "" else f.returnType.classFqName?.shortName()?.asString() ?: f.name.asString()
|
||||
val unitType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN)
|
||||
val shortName = when {
|
||||
f.returnType.isAnonymous -> ""
|
||||
typeSubstitutionMap != null -> useType(substReturnType).javaResult.shortName
|
||||
else -> f.returnType.classFqName?.shortName()?.asString() ?: f.name.asString()
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
tw.writeConstrs(id as Label<DbConstructor>, shortName, "$shortName$paramsSignature", returnType.javaResult.id, returnType.kotlinResult.id, parentId, id)
|
||||
tw.writeConstrs(id as Label<DbConstructor>, shortName, "$shortName$paramsSignature", unitType.javaResult.id, unitType.kotlinResult.id, parentId, id)
|
||||
} else {
|
||||
val returnType = useType(f.returnType, TypeContext.RETURN)
|
||||
val returnType = useType(substReturnType, TypeContext.RETURN)
|
||||
val shortName = getFunctionShortName(f)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
tw.writeMethods(id as Label<DbMethod>, shortName, "$shortName$paramsSignature", returnType.javaResult.id, returnType.kotlinResult.id, parentId, id)
|
||||
@@ -386,7 +416,9 @@ open class KotlinFileExtractor(
|
||||
|
||||
tw.writeHasLocation(id, locId)
|
||||
val body = f.body
|
||||
if(body != null) {
|
||||
if(body != null && extractBody) {
|
||||
// Type substitution should only be used to extract a prototype, not the body as well:
|
||||
assert(typeSubstitutionMap == null)
|
||||
extractBody(body, id)
|
||||
}
|
||||
|
||||
@@ -403,8 +435,8 @@ open class KotlinFileExtractor(
|
||||
return id
|
||||
}
|
||||
|
||||
fun extractProperty(p: IrProperty, parentId: Label<out DbReftype>) {
|
||||
val id = useProperty(p)
|
||||
fun extractProperty(p: IrProperty, parentId: Label<out DbReftype>, extractBackingField: Boolean = true, typeSubstitutionMap: Map<IrTypeParameterSymbol, IrTypeArgument>? = null) {
|
||||
val id = useProperty(p, parentId)
|
||||
val locId = tw.getLocation(p)
|
||||
tw.writeKtProperties(id, p.name.asString())
|
||||
tw.writeHasLocation(id, locId)
|
||||
@@ -415,7 +447,7 @@ open class KotlinFileExtractor(
|
||||
|
||||
if(getter != null) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val getterId = extractFunction(getter, parentId) as Label<out DbMethod>
|
||||
val getterId = extractFunction(getter, parentId, extractBackingField, typeSubstitutionMap) as Label<out DbMethod>
|
||||
tw.writeKtPropertyGetters(id, getterId)
|
||||
} else {
|
||||
if (p.modality != Modality.FINAL || !isExternalDeclaration(p)) {
|
||||
@@ -428,7 +460,7 @@ open class KotlinFileExtractor(
|
||||
logger.warnElement(Severity.ErrorSevere, "!isVar property with a setter", p)
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val setterId = extractFunction(setter, parentId) as Label<out DbMethod>
|
||||
val setterId = extractFunction(setter, parentId, extractBackingField, typeSubstitutionMap) as Label<out DbMethod>
|
||||
tw.writeKtPropertySetters(id, setterId)
|
||||
} else {
|
||||
if (p.isVar && !isExternalDeclaration(p)) {
|
||||
@@ -436,7 +468,7 @@ open class KotlinFileExtractor(
|
||||
}
|
||||
}
|
||||
|
||||
if(bf != null) {
|
||||
if(bf != null && extractBackingField) {
|
||||
val fieldId = extractField(bf, parentId)
|
||||
tw.writeKtPropertyBackingFields(id, fieldId)
|
||||
}
|
||||
@@ -692,17 +724,16 @@ open class KotlinFileExtractor(
|
||||
isFunction("kotlin", "Double", fName)
|
||||
}
|
||||
|
||||
fun extractMethodAccess(callTarget: IrFunction, extractTypeArguments: Boolean = true){
|
||||
fun extractMethodAccess(callTarget: IrFunction, extractMethodTypeArguments: Boolean = true, extractClassTypeArguments: Boolean = false) {
|
||||
val id = tw.getFreshIdLabel<DbMethodaccess>()
|
||||
val type = useType(c.type)
|
||||
val locId = tw.getLocation(c)
|
||||
|
||||
tw.writeExprs_methodaccess(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
||||
tw.writeHasLocation(id, locId)
|
||||
tw.writeCallableEnclosingExpr(id, callable)
|
||||
tw.writeStatementEnclosingExpr(id, enclosingStmt)
|
||||
|
||||
if (extractTypeArguments) {
|
||||
if (extractMethodTypeArguments) {
|
||||
// type arguments at index -2, -3, ...
|
||||
extractTypeArguments(c, id, callable, enclosingStmt, -2, true)
|
||||
}
|
||||
@@ -730,10 +761,28 @@ open class KotlinFileExtractor(
|
||||
tw.writeStatementEnclosingExpr(typeAccessId, enclosingStmt)
|
||||
|
||||
} else {
|
||||
val methodId = useFunction<DbMethod>(callTarget)
|
||||
val dr = c.dispatchReceiver
|
||||
|
||||
// Returns true if type is C<T1, T2, ...> where C is declared `class <T1, T2, ...> C { ... }`
|
||||
fun isUnspecialised(type: IrSimpleType) =
|
||||
type.classifier.owner is IrClass &&
|
||||
(type.classifier.owner as IrClass).typeParameters.zip(type.arguments).all { paramAndArg ->
|
||||
(paramAndArg.second as? IrTypeProjection)?.let {
|
||||
// Type arg refers to the class' own type parameter?
|
||||
it.variance == Variance.INVARIANT &&
|
||||
it.type.classifierOrNull?.owner === paramAndArg.first
|
||||
} ?: false
|
||||
}
|
||||
|
||||
val drType = dr?.type
|
||||
val methodId =
|
||||
if (drType != null && extractClassTypeArguments && drType is IrSimpleType && !isUnspecialised(drType))
|
||||
useFunction<DbCallable>(callTarget, drType.arguments)
|
||||
else
|
||||
useFunction<DbCallable>(callTarget)
|
||||
|
||||
tw.writeCallableBinding(id, methodId)
|
||||
|
||||
val dr = c.dispatchReceiver
|
||||
if (dr != null) {
|
||||
extractExpressionExpr(dr, callable, id, -1, enclosingStmt)
|
||||
}
|
||||
@@ -1055,7 +1104,7 @@ open class KotlinFileExtractor(
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
extractMethodAccess(c.symbol.owner)
|
||||
extractMethodAccess(c.symbol.owner, true, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1725,7 +1774,7 @@ open class KotlinFileExtractor(
|
||||
|
||||
val argsParamId = tw.getFreshIdLabel<DbParam>()
|
||||
val argsParamType = pluginContext.irBuiltIns.arrayClass.typeWith(pluginContext.irBuiltIns.anyNType)
|
||||
val paramType = extractValueParameter(argsParamId, argsParamType, "args", locId, methodId, 0)
|
||||
val paramType = extractValueParameter(argsParamId, argsParamType, "args", locId, methodId, 0, null)
|
||||
|
||||
val paramsSignature = "(${paramType.javaResult.signature!!})"
|
||||
|
||||
|
||||
@@ -89,7 +89,14 @@ open class KotlinUsesExtractor(
|
||||
return KotlinSourceFileExtractor(newLogger, newTrapWriter, clsFile, externalClassExtractor, primitiveTypeMapping, pluginContext)
|
||||
}
|
||||
|
||||
fun useClassInstance(c: IrClass, typeArgs: List<IrTypeArgument>): UseClassInstanceResult {
|
||||
private fun anyDeclarationExtracted(c: IrClass, id: Label<out DbClassorinterface>) =
|
||||
c.declarations.any {
|
||||
it is IrFunction &&
|
||||
tw.getExistingLabelFor<DbCallable>(getFunctionLabel(
|
||||
id, it.name.asString(), it.valueParameters, it.returnType, it.extensionReceiverParameter)) != null
|
||||
}
|
||||
|
||||
fun useClassInstance(c: IrClass, typeArgs: List<IrTypeArgument>, inReceiverContext: Boolean = false): UseClassInstanceResult {
|
||||
if (c.isAnonymousObject) {
|
||||
logger.warn(Severity.ErrorSevere, "Unexpected access to anonymous class instance")
|
||||
}
|
||||
@@ -102,7 +109,8 @@ open class KotlinUsesExtractor(
|
||||
|
||||
val extractClass = substituteClass ?: c
|
||||
|
||||
val classTypeResult = addClassLabel(extractClass, typeArgs)
|
||||
val classTypeResult = addClassLabel(extractClass, typeArgs, inReceiverContext)
|
||||
|
||||
// Extract both the Kotlin and equivalent Java classes, so that we have database entries
|
||||
// for both even if all internal references to the Kotlin type are substituted.
|
||||
if(c != extractClass) {
|
||||
@@ -139,17 +147,27 @@ open class KotlinUsesExtractor(
|
||||
externalClassExtractor.extractLater(c)
|
||||
}
|
||||
|
||||
fun addClassLabel(c: IrClass, typeArgs: List<IrTypeArgument>): TypeResult<DbClassorinterface> {
|
||||
fun addClassLabel(c: IrClass, typeArgs: List<IrTypeArgument>, inReceiverContext: Boolean = false): TypeResult<DbClassorinterface> {
|
||||
val classLabelResult = getClassLabel(c, typeArgs)
|
||||
|
||||
var shouldExtractClass = false
|
||||
|
||||
val classLabel : Label<out DbClassorinterface> = tw.getLabelFor(classLabelResult.classLabel, {
|
||||
// If this is a generic type instantiation then it has no
|
||||
// source entity, so we need to extract it here
|
||||
if (typeArgs.isNotEmpty()) {
|
||||
this.withSourceFileOfClass(c).extractClassInstance(c, typeArgs)
|
||||
}
|
||||
shouldExtractClass = true
|
||||
|
||||
extractClassLaterIfExternal(c)
|
||||
})
|
||||
|
||||
if (typeArgs.isNotEmpty()) {
|
||||
// Extract again if we've already extracted the class itself but not its declared functions:
|
||||
// This might happen e.g. if we see it for the first time in the context of a parameter type (which doesn't
|
||||
// require method prototype extraction), then later as a function receiver (which does).
|
||||
if (shouldExtractClass || (inReceiverContext && !anyDeclarationExtracted(c, classLabel)))
|
||||
this.withSourceFileOfClass(c).extractClassInstance(c, typeArgs, inReceiverContext)
|
||||
}
|
||||
|
||||
return TypeResult(
|
||||
classLabel,
|
||||
c.fqNameWhenAvailable?.asString(),
|
||||
@@ -443,10 +461,10 @@ class X {
|
||||
}
|
||||
}
|
||||
|
||||
fun useDeclarationParent(dp: IrDeclarationParent): Label<out DbElement> =
|
||||
fun useDeclarationParent(dp: IrDeclarationParent, classTypeArguments: List<IrTypeArgument>? = null, inReceiverContext: Boolean = false): Label<out DbElement> =
|
||||
when(dp) {
|
||||
is IrFile -> usePackage(dp.fqName.asString())
|
||||
is IrClass -> useClassSource(dp)
|
||||
is IrClass -> if (classTypeArguments != null) useClassInstance(dp, classTypeArguments, inReceiverContext).typeResult.id else useClassSource(dp)
|
||||
is IrFunction -> useFunction(dp)
|
||||
else -> {
|
||||
logger.warn(Severity.ErrorSevere, "Unrecognised IrDeclarationParent: " + dp.javaClass)
|
||||
@@ -463,8 +481,8 @@ class X {
|
||||
return f.name.asString()
|
||||
}
|
||||
|
||||
fun getFunctionLabel(f: IrFunction) : String {
|
||||
return getFunctionLabel(f.parent, getFunctionShortName(f), f.valueParameters, f.returnType, f.extensionReceiverParameter)
|
||||
fun getFunctionLabel(f: IrFunction, classTypeArguments: List<IrTypeArgument>? = null) : String {
|
||||
return getFunctionLabel(f.parent, getFunctionShortName(f), f.valueParameters, f.returnType, f.extensionReceiverParameter, classTypeArguments)
|
||||
}
|
||||
|
||||
fun getFunctionLabel(
|
||||
@@ -472,6 +490,21 @@ class X {
|
||||
name: String,
|
||||
parameters: List<IrValueParameter>,
|
||||
returnType: IrType,
|
||||
extensionReceiverParameter: IrValueParameter?,
|
||||
classTypeArguments: List<IrTypeArgument>? = null
|
||||
): String {
|
||||
val parentId = useDeclarationParent(parent, classTypeArguments, true)
|
||||
return getFunctionLabel(parentId, name, parameters, returnType, extensionReceiverParameter)
|
||||
}
|
||||
|
||||
fun getFunctionLabel(f: IrFunction, parentId: Label<out DbElement>) =
|
||||
getFunctionLabel(parentId, f.name.asString(), f.valueParameters, f.returnType, f.extensionReceiverParameter)
|
||||
|
||||
fun getFunctionLabel(
|
||||
parentId: Label<out DbElement>,
|
||||
name: String,
|
||||
parameters: List<IrValueParameter>,
|
||||
returnType: IrType,
|
||||
extensionReceiverParameter: IrValueParameter?
|
||||
): String {
|
||||
val allParams = if (extensionReceiverParameter == null) {
|
||||
@@ -483,7 +516,6 @@ class X {
|
||||
}
|
||||
val paramTypeIds = allParams.joinToString { "{${useType(erase(it.type)).javaResult.id}}" }
|
||||
val returnTypeId = useType(erase(returnType)).javaResult.id
|
||||
val parentId = useDeclarationParent(parent)
|
||||
return "@\"callable;{$parentId}.$name($paramTypeIds){$returnTypeId}\""
|
||||
}
|
||||
|
||||
@@ -515,21 +547,27 @@ class X {
|
||||
return res
|
||||
}
|
||||
|
||||
fun <T: DbCallable> useFunction(f: IrFunction): Label<out T> {
|
||||
if (f.isLocalFunction()) {
|
||||
val ids = getLocalFunctionLabels(f)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return ids.function as Label<out T>
|
||||
}
|
||||
|
||||
val label = getFunctionLabel(f)
|
||||
fun <T: DbCallable> useFunctionCommon(f: IrFunction, label: String): Label<out T> {
|
||||
val id: Label<T> = tw.getLabelFor(label)
|
||||
if(isExternalDeclaration(f)) {
|
||||
if (isExternalDeclaration(f)) {
|
||||
extractExternalEnclosingClassLater(f)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
fun <T: DbCallable> useFunction(f: IrFunction, classTypeArguments: List<IrTypeArgument>? = null): Label<out T> {
|
||||
if (f.isLocalFunction()) {
|
||||
val ids = getLocalFunctionLabels(f)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return ids.function as Label<out T>
|
||||
} else {
|
||||
return useFunctionCommon<T>(f, getFunctionLabel(f, classTypeArguments))
|
||||
}
|
||||
}
|
||||
|
||||
fun <T: DbCallable> useFunction(f: IrFunction, parentId: Label<out DbElement>) =
|
||||
useFunctionCommon<T>(f, getFunctionLabel(f, parentId))
|
||||
|
||||
fun getTypeArgumentLabel(
|
||||
arg: IrTypeArgument
|
||||
): TypeResult<DbReftype> {
|
||||
@@ -706,7 +744,7 @@ class X {
|
||||
|
||||
fun useValueDeclaration(d: IrValueDeclaration): Label<out DbVariable> =
|
||||
when(d) {
|
||||
is IrValueParameter -> useValueParameter(d)
|
||||
is IrValueParameter -> useValueParameter(d, null)
|
||||
is IrVariable -> useVariable(d)
|
||||
else -> {
|
||||
logger.warn(Severity.ErrorSevere, "Unrecognised IrValueDeclaration: " + d.javaClass)
|
||||
@@ -739,9 +777,12 @@ class X {
|
||||
fun eraseTypeParameter(t: IrTypeParameter) =
|
||||
erase(t.superTypes[0])
|
||||
|
||||
fun getValueParameterLabel(vp: IrValueParameter): String {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val parentId: Label<out DbMethod> = useDeclarationParent(vp.parent) as Label<out DbMethod>
|
||||
/**
|
||||
* Gets the label for `vp` in the context of function instance `parent`, or in that of its declaring function if
|
||||
* `parent` is null.
|
||||
*/
|
||||
fun getValueParameterLabel(vp: IrValueParameter, parent: Label<out DbCallable>?): String {
|
||||
val parentId = parent ?: useDeclarationParent(vp.parent)
|
||||
val idx = vp.index
|
||||
if (idx < 0) {
|
||||
// We're not extracting this and this@TYPE parameters of functions:
|
||||
@@ -750,8 +791,9 @@ class X {
|
||||
return "@\"params;{$parentId};$idx\""
|
||||
}
|
||||
|
||||
fun useValueParameter(vp: IrValueParameter): Label<out DbParam> =
|
||||
tw.getLabelFor(getValueParameterLabel(vp))
|
||||
|
||||
fun useValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>?): Label<out DbParam> =
|
||||
tw.getLabelFor(getValueParameterLabel(vp, parent))
|
||||
|
||||
fun getFieldLabel(f: IrField): String {
|
||||
val parentId = useDeclarationParent(f.parent)
|
||||
@@ -761,14 +803,18 @@ class X {
|
||||
fun useField(f: IrField): Label<out DbField> =
|
||||
tw.getLabelFor(getFieldLabel(f))
|
||||
|
||||
fun getPropertyLabel(p: IrProperty): String {
|
||||
val parentId = useDeclarationParent(p.parent)
|
||||
return "@\"property;{$parentId};${p.name.asString()}\""
|
||||
}
|
||||
fun getPropertyLabel(p: IrProperty) =
|
||||
getPropertyLabel(p, useDeclarationParent(p.parent))
|
||||
|
||||
fun getPropertyLabel(p: IrProperty, parentId: Label<out DbElement>) =
|
||||
"@\"property;{$parentId};${p.name.asString()}\""
|
||||
|
||||
fun useProperty(p: IrProperty): Label<out DbKt_property> =
|
||||
tw.getLabelFor(getPropertyLabel(p))
|
||||
|
||||
fun useProperty(p: IrProperty, parentId: Label<out DbElement>): Label<out DbKt_property> =
|
||||
tw.getLabelFor(getPropertyLabel(p, parentId))
|
||||
|
||||
fun getEnumEntryLabel(ee: IrEnumEntry): String {
|
||||
val parentId = useDeclarationParent(ee.parent)
|
||||
return "@\"field;{$parentId};${ee.name.asString()}\""
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.github.codeql.utils
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
@@ -76,3 +77,34 @@ fun IrSimpleType.substituteTypeArguments(substitutionMap: Map<IrTypeParameterSym
|
||||
annotations
|
||||
)
|
||||
}
|
||||
|
||||
fun IrTypeArgument.upperBound(context: IrPluginContext) =
|
||||
when(this) {
|
||||
is IrStarProjection -> context.irBuiltIns.anyNType
|
||||
is IrTypeProjection -> when(this.variance) {
|
||||
Variance.INVARIANT -> this.type
|
||||
Variance.IN_VARIANCE -> if (this.type.isNullable()) context.irBuiltIns.anyNType else context.irBuiltIns.anyType
|
||||
Variance.OUT_VARIANCE -> this.type
|
||||
}
|
||||
else -> context.irBuiltIns.anyNType
|
||||
}
|
||||
|
||||
fun IrTypeArgument.lowerBound(context: IrPluginContext) =
|
||||
when(this) {
|
||||
is IrStarProjection -> context.irBuiltIns.nothingType
|
||||
is IrTypeProjection -> when(this.variance) {
|
||||
Variance.INVARIANT -> this.type
|
||||
Variance.IN_VARIANCE -> this.type
|
||||
Variance.OUT_VARIANCE -> if (this.type.isNullable()) context.irBuiltIns.nothingNType else context.irBuiltIns.nothingType
|
||||
}
|
||||
else -> context.irBuiltIns.nothingType
|
||||
}
|
||||
|
||||
fun IrType.substituteTypeAndArguments(substitutionMap: Map<IrTypeParameterSymbol, IrTypeArgument>?, topLevelMatchHandler: (IrTypeArgument) -> IrType): IrType =
|
||||
substitutionMap?.let { substMap ->
|
||||
this.classifierOrNull?.let { typeClassifier ->
|
||||
substMap[typeClassifier]?.let {
|
||||
topLevelMatchHandler(it)
|
||||
} ?: (this as IrSimpleType).substituteTypeArguments(substMap)
|
||||
} ?: this
|
||||
} ?: this
|
||||
@@ -0,0 +1,33 @@
|
||||
class Generic2<T> {
|
||||
|
||||
public Generic2(T init) { stored = init; }
|
||||
|
||||
private T stored;
|
||||
|
||||
T identity2(T param) { return identity(param); }
|
||||
T identity(T param) { return param; }
|
||||
T getter() { return stored; }
|
||||
void setter(T param) { stored = param; }
|
||||
|
||||
}
|
||||
|
||||
public class Test {
|
||||
|
||||
public static void user() {
|
||||
|
||||
Generic2<String> invariant = new Generic2<String>("hello world");
|
||||
invariant.identity("hello world");
|
||||
invariant.identity2("hello world");
|
||||
|
||||
Generic2<? extends String> projectedOut = invariant;
|
||||
projectedOut.getter();
|
||||
|
||||
Generic2<? super String> projectedIn = invariant;
|
||||
projectedIn.setter("hi planet");
|
||||
projectedIn.getter();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
calls
|
||||
| Test.java:7:33:7:47 | identity(...) | Test.java:7:5:7:13 | identity2 | Test.java:1:7:1:14 | Generic2 | Test.java:8:5:8:12 | identity | Test.java:1:7:1:14 | Generic2 |
|
||||
| Test.java:19:5:19:37 | identity(...) | Test.java:16:22:16:25 | user | Test.java:14:14:14:17 | Test | Generic2.class:0:0:0:0 | identity | Generic2.class:0:0:0:0 | Generic2<String> |
|
||||
| Test.java:20:5:20:38 | identity2(...) | Test.java:16:22:16:25 | user | Test.java:14:14:14:17 | Test | Generic2.class:0:0:0:0 | identity2 | Generic2.class:0:0:0:0 | Generic2<String> |
|
||||
| Test.java:23:5:23:25 | getter(...) | Test.java:16:22:16:25 | user | Test.java:14:14:14:17 | Test | Generic2.class:0:0:0:0 | getter | Generic2.class:0:0:0:0 | Generic2<? extends String> |
|
||||
| Test.java:26:5:26:35 | setter(...) | Test.java:16:22:16:25 | user | Test.java:14:14:14:17 | Test | Generic2.class:0:0:0:0 | setter | Generic2.class:0:0:0:0 | Generic2<? super String> |
|
||||
| Test.java:27:5:27:24 | getter(...) | Test.java:16:22:16:25 | user | Test.java:14:14:14:17 | Test | Generic2.class:0:0:0:0 | getter | Generic2.class:0:0:0:0 | Generic2<? super String> |
|
||||
| test.kt:1:1:10:1 | <obinit>(...) | test.kt:1:1:10:1 | Generic | test.kt:1:1:10:1 | Generic | test.kt:1:1:10:1 | <obinit> | test.kt:1:1:10:1 | Generic |
|
||||
| test.kt:5:32:5:46 | identity(...) | test.kt:5:3:5:46 | identity2 | test.kt:1:1:10:1 | Generic | test.kt:6:3:6:35 | identity | test.kt:1:1:10:1 | Generic |
|
||||
| test.kt:7:21:7:26 | <get-stored>(...) | test.kt:7:3:7:26 | getter | test.kt:1:1:10:1 | Generic | test.kt:3:3:3:19 | <get-stored> | test.kt:1:1:10:1 | Generic |
|
||||
| test.kt:8:26:8:31 | <set-stored>(...) | test.kt:8:3:8:41 | setter | test.kt:1:1:10:1 | Generic | test.kt:3:3:3:19 | <set-stored> | test.kt:1:1:10:1 | Generic |
|
||||
| test.kt:15:13:15:35 | identity(...) | test.kt:12:1:25:1 | user | test.kt:0:0:0:0 | TestKt | test.kt:6:3:6:35 | identity | test.kt:1:1:10:1 | Generic<String> |
|
||||
| test.kt:16:13:16:36 | identity2(...) | test.kt:12:1:25:1 | user | test.kt:0:0:0:0 | TestKt | test.kt:5:3:5:46 | identity2 | test.kt:1:1:10:1 | Generic<String> |
|
||||
| test.kt:19:16:19:23 | getter(...) | test.kt:12:1:25:1 | user | test.kt:0:0:0:0 | TestKt | test.kt:7:3:7:26 | getter | test.kt:1:1:10:1 | Generic<? extends String> |
|
||||
| test.kt:22:15:22:33 | setter(...) | test.kt:12:1:25:1 | user | test.kt:0:0:0:0 | TestKt | test.kt:8:3:8:41 | setter | test.kt:1:1:10:1 | Generic<? super String> |
|
||||
| test.kt:23:15:23:22 | getter(...) | test.kt:12:1:25:1 | user | test.kt:0:0:0:0 | TestKt | test.kt:7:3:7:26 | getter | test.kt:1:1:10:1 | Generic<? super String> |
|
||||
constructors
|
||||
| Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2<? extends String>(java.lang.String) | ? extends String | void |
|
||||
| Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2<? super String>(java.lang.Object) | ? super String | void |
|
||||
| Generic2.class:0:0:0:0 | Generic2<String> | Generic2.class:0:0:0:0 | Generic2<String> | Generic2<String>(java.lang.String) | String | void |
|
||||
| Test.java:1:7:1:14 | Generic2 | Test.java:3:10:3:17 | Generic2 | Generic2(java.lang.Object) | T | void |
|
||||
| Test.java:14:14:14:17 | Test | Test.java:14:14:14:17 | Test | Test() | No parameters | void |
|
||||
| test.kt:1:1:10:1 | Generic | test.kt:1:1:10:1 | Generic | Generic(java.lang.Object) | T | void |
|
||||
| test.kt:1:1:10:1 | Generic<? extends String> | test.kt:1:1:10:1 | Generic<? extends String> | Generic<? extends String>(java.lang.Void) | Void | void |
|
||||
| test.kt:1:1:10:1 | Generic<? super String> | test.kt:1:1:10:1 | Generic<? super String> | Generic<? super String>(java.lang.String) | String | void |
|
||||
| test.kt:1:1:10:1 | Generic<String> | test.kt:1:1:10:1 | Generic<String> | Generic<String>(java.lang.String) | String | void |
|
||||
constructorCalls
|
||||
| Test.java:18:34:18:68 | new Generic2<String>(...) | Generic2.class:0:0:0:0 | Generic2<String> |
|
||||
| test.kt:14:19:14:48 | new Generic(...) | test.kt:1:1:10:1 | Generic |
|
||||
refTypes
|
||||
| Test.java:1:7:1:14 | Generic2 |
|
||||
| Test.java:1:16:1:16 | T |
|
||||
| Test.java:14:14:14:17 | Test |
|
||||
| test.kt:0:0:0:0 | TestKt |
|
||||
| test.kt:1:1:10:1 | Generic |
|
||||
| test.kt:1:15:1:15 | T |
|
||||
#select
|
||||
| Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | getter | getter() | No parameters | ? extends String |
|
||||
| Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | identity | identity(java.lang.String) | ? extends String | ? extends String |
|
||||
| Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | identity2 | identity2(java.lang.String) | ? extends String | ? extends String |
|
||||
| Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | setter | setter(java.lang.String) | ? extends String | void |
|
||||
| Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | getter | getter() | No parameters | ? super String |
|
||||
| Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | identity | identity(java.lang.Object) | ? super String | ? super String |
|
||||
| Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | identity2 | identity2(java.lang.Object) | ? super String | ? super String |
|
||||
| Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | setter | setter(java.lang.Object) | ? super String | void |
|
||||
| Generic2.class:0:0:0:0 | Generic2<String> | Generic2.class:0:0:0:0 | getter | getter() | No parameters | String |
|
||||
| Generic2.class:0:0:0:0 | Generic2<String> | Generic2.class:0:0:0:0 | identity | identity(java.lang.String) | String | String |
|
||||
| Generic2.class:0:0:0:0 | Generic2<String> | Generic2.class:0:0:0:0 | identity2 | identity2(java.lang.String) | String | String |
|
||||
| Generic2.class:0:0:0:0 | Generic2<String> | Generic2.class:0:0:0:0 | setter | setter(java.lang.String) | String | void |
|
||||
| Test.java:1:7:1:14 | Generic2 | Test.java:7:5:7:13 | identity2 | identity2(java.lang.Object) | T | T |
|
||||
| Test.java:1:7:1:14 | Generic2 | Test.java:8:5:8:12 | identity | identity(java.lang.Object) | T | T |
|
||||
| Test.java:1:7:1:14 | Generic2 | Test.java:9:5:9:10 | getter | getter() | No parameters | T |
|
||||
| Test.java:1:7:1:14 | Generic2 | Test.java:10:8:10:13 | setter | setter(java.lang.Object) | T | void |
|
||||
| Test.java:14:14:14:17 | Test | Test.java:16:22:16:25 | user | user() | No parameters | void |
|
||||
| test.kt:0:0:0:0 | TestKt | test.kt:12:1:25:1 | user | user() | No parameters | void |
|
||||
| test.kt:1:1:10:1 | Generic | test.kt:1:1:10:1 | <obinit> | <obinit>() | No parameters | Unit |
|
||||
| test.kt:1:1:10:1 | Generic | test.kt:1:1:10:1 | equals | equals(java.lang.Object) | Object | boolean |
|
||||
| test.kt:1:1:10:1 | Generic | test.kt:1:1:10:1 | hashCode | hashCode() | No parameters | int |
|
||||
| test.kt:1:1:10:1 | Generic | test.kt:1:1:10:1 | toString | toString() | No parameters | String |
|
||||
| test.kt:1:1:10:1 | Generic | test.kt:3:3:3:19 | <get-stored> | <get-stored>() | No parameters | T |
|
||||
| test.kt:1:1:10:1 | Generic | test.kt:3:3:3:19 | <set-stored> | <set-stored>(java.lang.Object) | T | void |
|
||||
| test.kt:1:1:10:1 | Generic | test.kt:5:3:5:46 | identity2 | identity2(java.lang.Object) | T | T |
|
||||
| test.kt:1:1:10:1 | Generic | test.kt:6:3:6:35 | identity | identity(java.lang.Object) | T | T |
|
||||
| test.kt:1:1:10:1 | Generic | test.kt:7:3:7:26 | getter | getter() | No parameters | T |
|
||||
| test.kt:1:1:10:1 | Generic | test.kt:8:3:8:41 | setter | setter(java.lang.Object) | T | void |
|
||||
| test.kt:1:1:10:1 | Generic<? extends String> | test.kt:1:1:10:1 | equals | equals(java.lang.Object) | Object | boolean |
|
||||
| test.kt:1:1:10:1 | Generic<? extends String> | test.kt:1:1:10:1 | hashCode | hashCode() | No parameters | int |
|
||||
| test.kt:1:1:10:1 | Generic<? extends String> | test.kt:1:1:10:1 | toString | toString() | No parameters | String |
|
||||
| test.kt:1:1:10:1 | Generic<? extends String> | test.kt:3:3:3:19 | <get-stored> | <get-stored>() | No parameters | String |
|
||||
| test.kt:1:1:10:1 | Generic<? extends String> | test.kt:3:3:3:19 | <set-stored> | <set-stored>(java.lang.Void) | Void | void |
|
||||
| test.kt:1:1:10:1 | Generic<? extends String> | test.kt:5:3:5:46 | identity2 | identity2(java.lang.Void) | Void | String |
|
||||
| test.kt:1:1:10:1 | Generic<? extends String> | test.kt:6:3:6:35 | identity | identity(java.lang.Void) | Void | String |
|
||||
| test.kt:1:1:10:1 | Generic<? extends String> | test.kt:7:3:7:26 | getter | getter() | No parameters | String |
|
||||
| test.kt:1:1:10:1 | Generic<? extends String> | test.kt:8:3:8:41 | setter | setter(java.lang.Void) | Void | void |
|
||||
| test.kt:1:1:10:1 | Generic<? super String> | test.kt:1:1:10:1 | equals | equals(java.lang.Object) | Object | boolean |
|
||||
| test.kt:1:1:10:1 | Generic<? super String> | test.kt:1:1:10:1 | hashCode | hashCode() | No parameters | int |
|
||||
| test.kt:1:1:10:1 | Generic<? super String> | test.kt:1:1:10:1 | toString | toString() | No parameters | String |
|
||||
| test.kt:1:1:10:1 | Generic<? super String> | test.kt:3:3:3:19 | <get-stored> | <get-stored>() | No parameters | Object |
|
||||
| test.kt:1:1:10:1 | Generic<? super String> | test.kt:3:3:3:19 | <set-stored> | <set-stored>(java.lang.String) | String | void |
|
||||
| test.kt:1:1:10:1 | Generic<? super String> | test.kt:5:3:5:46 | identity2 | identity2(java.lang.String) | String | Object |
|
||||
| test.kt:1:1:10:1 | Generic<? super String> | test.kt:6:3:6:35 | identity | identity(java.lang.String) | String | Object |
|
||||
| test.kt:1:1:10:1 | Generic<? super String> | test.kt:7:3:7:26 | getter | getter() | No parameters | Object |
|
||||
| test.kt:1:1:10:1 | Generic<? super String> | test.kt:8:3:8:41 | setter | setter(java.lang.String) | String | void |
|
||||
| test.kt:1:1:10:1 | Generic<String> | test.kt:1:1:10:1 | equals | equals(java.lang.Object) | Object | boolean |
|
||||
| test.kt:1:1:10:1 | Generic<String> | test.kt:1:1:10:1 | hashCode | hashCode() | No parameters | int |
|
||||
| test.kt:1:1:10:1 | Generic<String> | test.kt:1:1:10:1 | toString | toString() | No parameters | String |
|
||||
| test.kt:1:1:10:1 | Generic<String> | test.kt:3:3:3:19 | <get-stored> | <get-stored>() | No parameters | String |
|
||||
| test.kt:1:1:10:1 | Generic<String> | test.kt:3:3:3:19 | <set-stored> | <set-stored>(java.lang.String) | String | void |
|
||||
| test.kt:1:1:10:1 | Generic<String> | test.kt:5:3:5:46 | identity2 | identity2(java.lang.String) | String | String |
|
||||
| test.kt:1:1:10:1 | Generic<String> | test.kt:6:3:6:35 | identity | identity(java.lang.String) | String | String |
|
||||
| test.kt:1:1:10:1 | Generic<String> | test.kt:7:3:7:26 | getter | getter() | No parameters | String |
|
||||
| test.kt:1:1:10:1 | Generic<String> | test.kt:8:3:8:41 | setter | setter(java.lang.String) | String | void |
|
||||
@@ -0,0 +1,27 @@
|
||||
class Generic<T>(init: T) {
|
||||
|
||||
var stored = init
|
||||
|
||||
fun identity2(param: T): T = identity(param)
|
||||
fun identity(param: T): T = param
|
||||
fun getter(): T = stored
|
||||
fun setter(param: T) { stored = param }
|
||||
|
||||
}
|
||||
|
||||
fun user() {
|
||||
|
||||
val invariant = Generic<String>("hello world")
|
||||
invariant.identity("hello world")
|
||||
invariant.identity2("hello world")
|
||||
|
||||
val projectedOut: Generic<out String> = invariant
|
||||
projectedOut.getter()
|
||||
|
||||
val projectedIn: Generic<in String> = invariant
|
||||
projectedIn.setter("hi planet")
|
||||
projectedIn.getter()
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import java
|
||||
|
||||
string paramTypeIfPresent(Callable m) {
|
||||
if exists(m.getAParamType())
|
||||
then result = m.getAParamType().toString()
|
||||
else result = "No parameters"
|
||||
}
|
||||
|
||||
query predicate calls(MethodAccess ma, Callable caller, RefType callerType, Callable called, RefType calledType) {
|
||||
|
||||
ma.getEnclosingCallable() = caller and
|
||||
ma.getCallee() = called and
|
||||
caller.fromSource() and
|
||||
callerType = caller.getDeclaringType() and
|
||||
calledType = called.getDeclaringType()
|
||||
|
||||
}
|
||||
|
||||
query predicate constructors(RefType t, Constructor c, string signature, string paramType, string returnType) {
|
||||
t.getSourceDeclaration().fromSource() and
|
||||
c.getDeclaringType() = t and
|
||||
signature = c.getSignature() and
|
||||
paramType = paramTypeIfPresent(c) and
|
||||
returnType = c.getReturnType().toString()
|
||||
}
|
||||
|
||||
query predicate constructorCalls(ConstructorCall cc, Constructor callee) {
|
||||
callee = cc.getConstructor() and
|
||||
callee.getSourceDeclaration().fromSource()
|
||||
}
|
||||
|
||||
query predicate refTypes(RefType rt) {
|
||||
rt.fromSource()
|
||||
}
|
||||
|
||||
from RefType t, Method m
|
||||
where t.getSourceDeclaration().fromSource() and m.getDeclaringType() = t
|
||||
select t, m, m.getSignature(), paramTypeIfPresent(m), m.getReturnType().toString()
|
||||
@@ -34,11 +34,25 @@ function
|
||||
| generics.kt:11:6:11:19 | toString | toString() |
|
||||
| generics.kt:13:1:18:1 | <obinit> | <obinit>() |
|
||||
| generics.kt:13:1:18:1 | C1 | C1(java.lang.Object) |
|
||||
| generics.kt:13:1:18:1 | C1<Integer,Integer> | C1<Integer,Integer>(int) |
|
||||
| generics.kt:13:1:18:1 | C1<String,Integer> | C1<String,Integer>(java.lang.String) |
|
||||
| generics.kt:13:1:18:1 | equals | equals(java.lang.Object) |
|
||||
| generics.kt:13:1:18:1 | equals | equals(java.lang.Object) |
|
||||
| generics.kt:13:1:18:1 | equals | equals(java.lang.Object) |
|
||||
| generics.kt:13:1:18:1 | hashCode | hashCode() |
|
||||
| generics.kt:13:1:18:1 | hashCode | hashCode() |
|
||||
| generics.kt:13:1:18:1 | hashCode | hashCode() |
|
||||
| generics.kt:13:1:18:1 | toString | toString() |
|
||||
| generics.kt:13:1:18:1 | toString | toString() |
|
||||
| generics.kt:13:1:18:1 | toString | toString() |
|
||||
| generics.kt:13:16:13:23 | <get-t> | <get-t>() |
|
||||
| generics.kt:13:16:13:23 | <get-t> | <get-t>() |
|
||||
| generics.kt:13:16:13:23 | <get-t> | <get-t>() |
|
||||
| generics.kt:14:5:14:19 | f1 | f1(int) |
|
||||
| generics.kt:14:5:14:19 | f1 | f1(java.lang.Object) |
|
||||
| generics.kt:14:5:14:19 | f1 | f1(java.lang.String) |
|
||||
| generics.kt:15:5:17:5 | f2 | f2(java.lang.Object) |
|
||||
| generics.kt:15:5:17:5 | f2 | f2(java.lang.Object) |
|
||||
| generics.kt:15:5:17:5 | f2 | f2(java.lang.Object) |
|
||||
| generics.kt:20:1:22:1 | <obinit> | <obinit>() |
|
||||
| generics.kt:20:1:22:1 | C2 | C2() |
|
||||
@@ -59,8 +73,6 @@ genericFunction
|
||||
| generics.kt:15:5:17:5 | f2 | generics.kt:15:10:15:10 | U | 0 |
|
||||
| generics.kt:21:5:21:23 | f4 | generics.kt:21:10:21:10 | P | 0 |
|
||||
genericCall
|
||||
| generics.kt:27:17:27:22 | f2(...) | generics.kt:15:10:15:10 | U | String |
|
||||
| generics.kt:30:17:30:21 | f2(...) | generics.kt:15:10:15:10 | U | Integer |
|
||||
| generics.kt:32:8:32:12 | f4(...) | generics.kt:21:10:21:10 | P | Integer |
|
||||
genericCtor
|
||||
| generics.kt:16:16:16:26 | new C1(...) | 0 | U |
|
||||
|
||||
Reference in New Issue
Block a user