зеркало из https://github.com/github/codeql.git
Kotlin: Fix extension and dispatch parameter order in `$default` functions
This commit is contained in:
Родитель
6457e059f5
Коммит
d93dce0fa9
|
@ -957,7 +957,7 @@ open class KotlinFileExtractor(
|
|||
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 parameterTypes = 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 {
|
||||
|
@ -976,7 +976,8 @@ open class KotlinFileExtractor(
|
|||
extractMethod(methodId, locId, shortName, erase(f.returnType), paramsSignature, parentId, methodId, origin = null, extractTypeAccess = extractMethodAndParameterTypeAccesses)
|
||||
addModifiers(id, "static")
|
||||
if (extReceiver != null) {
|
||||
val extendedType = allParamTypeResults[0] // TODO: this is not correct for member extension methods, where the dispatch receiver is the first parameter
|
||||
val idx = if (dispatchReceiver != null) 1 else 0
|
||||
val extendedType = allParamTypeResults[idx]
|
||||
tw.writeKtExtensionFunctions(methodId, extendedType.javaResult.id, extendedType.kotlinResult.id)
|
||||
}
|
||||
}
|
||||
|
@ -1044,8 +1045,8 @@ open class KotlinFileExtractor(
|
|||
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) }
|
||||
dispatchReceiver?.let { Triple(it.type, 0, -1) },
|
||||
extReceiver?.let { Triple(it.type, if (dispatchReceiver != null) 1 else 0, 0) }
|
||||
)
|
||||
paramMappings.forEach { (type, fromIdx, toIdx) ->
|
||||
extractVariableAccess(tw.getLabelFor<DbParam>(getValueParameterLabel(id, fromIdx)), type, locId, thisCallId, toIdx, id, returnId)
|
||||
|
@ -1188,6 +1189,7 @@ open class KotlinFileExtractor(
|
|||
id
|
||||
|
||||
val extReceiver = f.extensionReceiverParameter
|
||||
// The following parameter order is correct, because member $default methods (where the order would be [dispatchParam], [extensionParam], normalParams) are not extracted here
|
||||
val fParameters = listOfNotNull(extReceiver) + (overriddenAttributes?.valueParameters ?: f.valueParameters)
|
||||
val paramTypes = fParameters.mapIndexed { i, vp ->
|
||||
extractValueParameter(vp, id, i, typeSubstitution, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses, overriddenAttributes?.sourceLoc)
|
||||
|
@ -1797,11 +1799,12 @@ open class KotlinFileExtractor(
|
|||
) ?: pluginContext.irBuiltIns.anyType
|
||||
|
||||
private fun getDefaultsMethodArgTypes(f: IrFunction) =
|
||||
// The $default method has type ([extensionReceiver], [dispatchReceiver], paramTypes..., int, Object)
|
||||
// The $default method has type ([dispatchReceiver], [extensionReceiver], 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) +
|
||||
listOfNotNull(f.extensionReceiverParameter?.type) +
|
||||
f.valueParameters.map { it.type } +
|
||||
listOf(pluginContext.irBuiltIns.intType, getDefaultsMethodLastArgType(f))
|
||||
).map { erase(it) }
|
||||
|
@ -1820,17 +1823,16 @@ open class KotlinFileExtractor(
|
|||
|
||||
private fun getDefaultsMethodLabel(f: IrFunction): Label<out DbCallable> {
|
||||
val defaultsMethodName = if (f is IrConstructor) "<init>" else getDefaultsMethodName(f)
|
||||
val normalArgTypes = getDefaultsMethodArgTypes(f)
|
||||
val extensionParamType = f.extensionReceiverParameter?.let { erase(it.type) }
|
||||
val argTypes = getDefaultsMethodArgTypes(f)
|
||||
|
||||
val defaultMethodLabelStr = getFunctionLabel(
|
||||
f.parent,
|
||||
maybeParentId = null,
|
||||
defaultsMethodName,
|
||||
normalArgTypes,
|
||||
argTypes,
|
||||
erase(f.returnType),
|
||||
extensionParamType,
|
||||
listOf(),
|
||||
extensionParamType = null, // if there's any, that's included already in argTypes
|
||||
functionTypeParameters = listOf(),
|
||||
classTypeArgsIncludingOuterClasses = null,
|
||||
overridesCollectionsMethod = false,
|
||||
javaSignature = null,
|
||||
|
@ -1890,13 +1892,14 @@ open class KotlinFileExtractor(
|
|||
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)
|
||||
}
|
||||
|
||||
if (extensionReceiver != null) {
|
||||
extractExpressionExpr(extensionReceiver, enclosingCallable, id, nextIdx++, enclosingStmt)
|
||||
}
|
||||
|
||||
val valueArgsWithDummies = valueArguments.zip(callTarget.valueParameters).map {
|
||||
(expr, param) -> expr ?: IrConstImpl.defaultValueForType(0, 0, param.type)
|
||||
}
|
||||
|
@ -4050,8 +4053,7 @@ open class KotlinFileExtractor(
|
|||
// 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))
|
||||
val replacementParamId = tw.getLabelFor<DbParam>(getValueParameterLabel(paramDeclarerId, replaceWithParamIdx))
|
||||
extractVariableAccess(replacementParamId, e.type, locId, exprParent.parent, exprParent.idx, callable, exprParent.enclosingStmt)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1896,7 +1896,8 @@ class VarAccess extends Expr, @varaccess {
|
|||
class ExtensionReceiverAccess extends VarAccess {
|
||||
ExtensionReceiverAccess() {
|
||||
exists(Parameter p |
|
||||
this.getVariable() = p and p.getPosition() = 0 and p.getCallable() instanceof ExtensionMethod
|
||||
this.getVariable() = p and
|
||||
p.isExtensionParameter()
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -327,18 +327,8 @@ class Callable extends StmtParent, Member, @callable {
|
|||
this instanceof Method and
|
||||
result instanceof Method and
|
||||
this.getName() + "$default" = result.getName() and
|
||||
extraLeadingParams <= 1 and
|
||||
(
|
||||
if ktExtensionFunctions(this, _, _)
|
||||
then
|
||||
// Both extension receivers are expected to occur at arg0, with any
|
||||
// dispatch receiver inserted afterwards in the $default proxy's parameter list.
|
||||
// Check the extension receiver matches here, and note regular args
|
||||
// are bumped one position to the right.
|
||||
regularParamsStartIdx = extraLeadingParams + 1 and
|
||||
this.getParameterType(0).getErasure() = eraseRaw(result.getParameterType(0))
|
||||
else regularParamsStartIdx = extraLeadingParams
|
||||
) and
|
||||
extraLeadingParams <= 1 and // 0 for static methods, 1 for instance methods
|
||||
regularParamsStartIdx = extraLeadingParams and
|
||||
lastParamType instanceof TypeObject
|
||||
)
|
||||
|
|
||||
|
@ -824,4 +814,19 @@ class ExtensionMethod extends Method {
|
|||
KotlinType getExtendedKotlinType() { result = extendedKotlinType }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ExtensionMethod" }
|
||||
|
||||
/**
|
||||
* Gets the index of the parameter that is the extension receiver. This is typically index 0. In case of `$default`
|
||||
* extension methods that are defined as members, the index is 1. Index 0 is the dispatch receiver of the `$default`
|
||||
* method.
|
||||
*/
|
||||
int getExtensionParameterIndex() {
|
||||
if
|
||||
exists(Method src |
|
||||
this = src.getKotlinParameterDefaultsProxy() and
|
||||
src.getNumberOfParameters() = this.getNumberOfParameters() - 3 // 2 extra parameters + 1 dispatch receiver
|
||||
)
|
||||
then result = 1
|
||||
else result = 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ class Parameter extends Element, @param, LocalScopeVariable {
|
|||
|
||||
/** Holds if this formal parameter is a parameter representing the dispatch receiver in an extension method. */
|
||||
predicate isExtensionParameter() {
|
||||
this.getPosition() = 0 and this.getCallable() instanceof ExtensionMethod
|
||||
this.getPosition() = this.getCallable().(ExtensionMethod).getExtensionParameterIndex()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -326,7 +326,7 @@
|
|||
| methods3.kt:6:5:6:45 | fooBarMethodExt(...) | MethodAccess |
|
||||
| methods3.kt:6:5:6:45 | int | TypeAccess |
|
||||
| methods3.kt:6:5:6:45 | int | TypeAccess |
|
||||
| methods3.kt:6:5:6:45 | p1 | VarAccess |
|
||||
| methods3.kt:6:5:6:45 | p0 | VarAccess |
|
||||
| methods3.kt:6:5:6:45 | p2 | VarAccess |
|
||||
| methods3.kt:6:5:6:45 | p2 | VarAccess |
|
||||
| methods3.kt:6:5:6:45 | p3 | VarAccess |
|
||||
|
|
|
@ -41,7 +41,7 @@ methods
|
|||
| methods3.kt:0:0:0:0 | Methods3Kt | methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt | fooBarTopLevelMethodExt(java.lang.String,int) | final, public, static | |
|
||||
| methods3.kt:0:0:0:0 | Methods3Kt | methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt$default | fooBarTopLevelMethodExt$default(java.lang.String,int,int,java.lang.Object) | public, static | Compiler generated |
|
||||
| methods3.kt:5:1:7:1 | Class3 | methods3.kt:6:5:6:45 | fooBarMethodExt | fooBarMethodExt(java.lang.String,int) | final, public | |
|
||||
| methods3.kt:5:1:7:1 | Class3 | methods3.kt:6:5:6:45 | fooBarMethodExt$default | fooBarMethodExt$default(java.lang.String,foo.bar.Class3,int,int,java.lang.Object) | public, static | Compiler generated |
|
||||
| methods3.kt:5:1:7:1 | Class3 | methods3.kt:6:5:6:45 | fooBarMethodExt$default | fooBarMethodExt$default(foo.bar.Class3,java.lang.String,int,int,java.lang.Object) | public, static | Compiler generated |
|
||||
| methods4.kt:5:3:9:3 | InsideNestedTest | methods4.kt:7:5:7:34 | m | m(foo.bar.NestedTest.InsideNestedTest) | final, public | |
|
||||
| methods5.kt:0:0:0:0 | Methods5Kt | methods5.kt:3:1:11:1 | x | x() | final, public, static | |
|
||||
| methods5.kt:5:3:5:27 | | methods5.kt:5:3:5:27 | a | a(int) | final, public | |
|
||||
|
@ -82,3 +82,9 @@ extensions
|
|||
| methods3.kt:6:5:6:45 | fooBarMethodExt$default | file:///modules/java.base/java/lang/String.class:0:0:0:0 | String |
|
||||
| methods5.kt:9:3:9:32 | f1 | file:///!unknown-binary-location/foo/bar/C1.class:0:0:0:0 | C1<T1> |
|
||||
extensionsMismatch
|
||||
extensionIndex
|
||||
| methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt | 0 | file:///modules/java.base/java/lang/String.class:0:0:0:0 | String |
|
||||
| methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt$default | 0 | file:///modules/java.base/java/lang/String.class:0:0:0:0 | String |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt | 0 | file:///modules/java.base/java/lang/String.class:0:0:0:0 | String |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt$default | 1 | file:///modules/java.base/java/lang/String.class:0:0:0:0 | String |
|
||||
| methods5.kt:9:3:9:32 | f1 | 0 | file:///!unknown-binary-location/foo/bar/C1.class:0:0:0:0 | C1<T1> |
|
||||
|
|
|
@ -26,3 +26,10 @@ query predicate extensionsMismatch(Method src, Method def) {
|
|||
def instanceof ExtensionMethod and not src instanceof ExtensionMethod
|
||||
)
|
||||
}
|
||||
|
||||
query predicate extensionIndex(ExtensionMethod m, int i, Type t) {
|
||||
m.fromSource() and
|
||||
m.getExtensionParameterIndex() = i and
|
||||
m.getExtendedType() = t and
|
||||
m.getParameter(i).getType() = t
|
||||
}
|
||||
|
|
|
@ -525,13 +525,13 @@ test.kt:
|
|||
# 21| 0: [MethodAccess] sink(...)
|
||||
# 21| -1: [TypeAccess] TestKt
|
||||
# 21| 0: [VarAccess] y
|
||||
# 19| 3: [Method] f$default
|
||||
# 19| 3: [ExtensionMethod] 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| 1: [Parameter] p1
|
||||
# 19| 0: [TypeAccess] String
|
||||
# 19| 2: [Parameter] p2
|
||||
# 19| 0: [TypeAccess] String
|
||||
# 19| 3: [Parameter] p3
|
||||
|
@ -565,8 +565,8 @@ test.kt:
|
|||
# 19| 1: [StringLiteral] "hello world"
|
||||
# 19| 2: [ReturnStmt] return ...
|
||||
# 19| 0: [MethodAccess] f(...)
|
||||
# 19| -1: [VarAccess] p1
|
||||
# 19| 0: [VarAccess] p0
|
||||
# 19| -1: [VarAccess] p0
|
||||
# 19| 0: [ExtensionReceiverAccess] this
|
||||
# 19| 1: [VarAccess] p2
|
||||
# 19| 2: [VarAccess] p3
|
||||
# 19| 3: [VarAccess] p4
|
||||
|
@ -579,8 +579,8 @@ test.kt:
|
|||
# 25| 0: [ExprStmt] <Expr>;
|
||||
# 25| 0: [MethodAccess] f$default(...)
|
||||
# 25| -1: [TypeAccess] TestExtensionMember
|
||||
# 25| 0: [VarAccess] sunk
|
||||
# 25| 1: [ThisAccess] this
|
||||
# 25| 0: [ThisAccess] this
|
||||
# 25| 1: [VarAccess] sunk
|
||||
# 25| 2: [StringLiteral] "extension sunk"
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [NullLiteral] null
|
||||
|
@ -589,8 +589,8 @@ test.kt:
|
|||
# 26| 1: [ExprStmt] <Expr>;
|
||||
# 26| 0: [MethodAccess] f$default(...)
|
||||
# 26| -1: [TypeAccess] TestExtensionMember
|
||||
# 26| 0: [VarAccess] sunk
|
||||
# 26| 1: [ThisAccess] this
|
||||
# 26| 0: [ThisAccess] this
|
||||
# 26| 1: [VarAccess] sunk
|
||||
# 26| 2: [StringLiteral] "extension sunk fp"
|
||||
# 26| 3: [StringLiteral] "extension sunk 2"
|
||||
# 1| 4: [NullLiteral] null
|
||||
|
@ -729,13 +729,13 @@ test.kt:
|
|||
# 57| 0: [MethodAccess] sink(...)
|
||||
# 57| -1: [TypeAccess] TestKt
|
||||
# 57| 0: [VarAccess] y
|
||||
# 56| 4: [Method] test$default
|
||||
# 56| 4: [ExtensionMethod] 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| 1: [Parameter] p1
|
||||
# 56| 0: [TypeAccess] ExtendMe
|
||||
# 56| 2: [Parameter] p2
|
||||
# 56| 0: [TypeAccess] String
|
||||
# 56| 3: [Parameter] p3
|
||||
|
@ -759,7 +759,7 @@ test.kt:
|
|||
# 56| 1: [MethodAccess] f(...)
|
||||
# 56| -1: [VarAccess] p0
|
||||
# 56| 0: [MethodAccess] g(...)
|
||||
# 56| -1: [VarAccess] p1
|
||||
# 56| -1: [VarAccess] p0
|
||||
# 56| 0: [VarAccess] p2
|
||||
# 56| 1: [IfStmt] if (...)
|
||||
# 56| 0: [EQExpr] ... == ...
|
||||
|
@ -773,8 +773,8 @@ test.kt:
|
|||
# 56| 1: [StringLiteral] "hello world"
|
||||
# 56| 2: [ReturnStmt] return ...
|
||||
# 56| 0: [MethodAccess] test(...)
|
||||
# 56| -1: [VarAccess] p1
|
||||
# 56| 0: [VarAccess] p0
|
||||
# 56| -1: [VarAccess] p0
|
||||
# 56| 0: [ExtensionReceiverAccess] this
|
||||
# 56| 1: [VarAccess] p2
|
||||
# 56| 2: [VarAccess] p3
|
||||
# 56| 3: [VarAccess] p4
|
||||
|
@ -787,8 +787,8 @@ test.kt:
|
|||
# 61| 0: [ExprStmt] <Expr>;
|
||||
# 61| 0: [MethodAccess] test$default(...)
|
||||
# 61| -1: [TypeAccess] TestReceiverReferences
|
||||
# 61| 0: [VarAccess] t
|
||||
# 61| 1: [ThisAccess] this
|
||||
# 61| 0: [ThisAccess] this
|
||||
# 61| 1: [VarAccess] t
|
||||
# 61| 2: [StringLiteral] "receiver refs sunk"
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [NullLiteral] null
|
||||
|
@ -797,8 +797,8 @@ test.kt:
|
|||
# 62| 1: [ExprStmt] <Expr>;
|
||||
# 62| 0: [MethodAccess] test$default(...)
|
||||
# 62| -1: [TypeAccess] TestReceiverReferences
|
||||
# 62| 0: [VarAccess] t
|
||||
# 62| 1: [ThisAccess] this
|
||||
# 62| 0: [ThisAccess] this
|
||||
# 62| 1: [VarAccess] t
|
||||
# 62| 2: [StringLiteral] "receiver refs sunk fp"
|
||||
# 62| 3: [StringLiteral] "receiver refs sunk 2"
|
||||
# 1| 4: [NullLiteral] null
|
||||
|
|
Загрузка…
Ссылка в новой задаче