Skip to content

Commit 34a0a0d

Browse files
committed
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.
1 parent 6f3c9e4 commit 34a0a0d

File tree

8 files changed

+1460
-95
lines changed

8 files changed

+1460
-95
lines changed

java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt

Lines changed: 416 additions & 78 deletions
Large diffs are not rendered by default.

java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,9 +1043,9 @@ open class KotlinUsesExtractor(
10431043
f.parent,
10441044
maybeParentId,
10451045
getFunctionShortName(f).nameInDB,
1046-
maybeParameterList ?: f.valueParameters,
1046+
(maybeParameterList ?: f.valueParameters).map { it.type },
10471047
getAdjustedReturnType(f),
1048-
f.extensionReceiverParameter,
1048+
f.extensionReceiverParameter?.type,
10491049
getFunctionTypeParameters(f),
10501050
classTypeArgsIncludingOuterClasses,
10511051
overridesCollectionsMethodWithAlteredParameterTypes(f),
@@ -1067,12 +1067,12 @@ open class KotlinUsesExtractor(
10671067
maybeParentId: Label<out DbElement>?,
10681068
// The name of the function; normally f.name.asString().
10691069
name: String,
1070-
// The value parameters that the functions takes; normally f.valueParameters.
1071-
parameters: List<IrValueParameter>,
1070+
// The types of the value parameters that the functions takes; normally f.valueParameters.map { it.type }.
1071+
parameterTypes: List<IrType>,
10721072
// The return type of the function; normally f.returnType.
10731073
returnType: IrType,
1074-
// The extension receiver of the function, if any; normally f.extensionReceiverParameter.
1075-
extensionReceiverParameter: IrValueParameter?,
1074+
// The extension receiver of the function, if any; normally f.extensionReceiverParameter?.type.
1075+
extensionParamType: IrType?,
10761076
// The type parameters of the function. This does not include type parameters of enclosing classes.
10771077
functionTypeParameters: List<IrTypeParameter>,
10781078
// The type arguments of enclosing classes of the function.
@@ -1089,11 +1089,7 @@ open class KotlinUsesExtractor(
10891089
prefix: String = "callable"
10901090
): String {
10911091
val parentId = maybeParentId ?: useDeclarationParent(parent, false, classTypeArgsIncludingOuterClasses, true)
1092-
val allParams = if (extensionReceiverParameter == null) {
1093-
parameters
1094-
} else {
1095-
listOf(extensionReceiverParameter) + parameters
1096-
}
1092+
val allParamTypes = if (extensionParamType == null) parameterTypes else listOf(extensionParamType) + parameterTypes
10971093

10981094
val substitutionMap = classTypeArgsIncludingOuterClasses?.let { notNullArgs ->
10991095
if (notNullArgs.isEmpty()) {
@@ -1103,11 +1099,11 @@ open class KotlinUsesExtractor(
11031099
enclosingClass?.let { notNullClass -> makeTypeGenericSubstitutionMap(notNullClass, notNullArgs) }
11041100
}
11051101
}
1106-
val getIdForFunctionLabel = { it: IndexedValue<IrValueParameter> ->
1102+
val getIdForFunctionLabel = { it: IndexedValue<IrType> ->
11071103
// Kotlin rewrites certain Java collections types adding additional generic constraints-- for example,
11081104
// Collection.remove(Object) because Collection.remove(Collection::E) in the Kotlin universe.
11091105
// If this has happened, erase the type again to get the correct Java signature.
1110-
val maybeAmendedForCollections = if (overridesCollectionsMethod) eraseCollectionsMethodParameterType(it.value.type, name, it.index) else it.value.type
1106+
val maybeAmendedForCollections = if (overridesCollectionsMethod) eraseCollectionsMethodParameterType(it.value, name, it.index) else it.value
11111107
// Add any wildcard types that the Kotlin compiler would add in the Java lowering of this function:
11121108
val withAddedWildcards = addJavaLoweringWildcards(maybeAmendedForCollections, addParameterWildcardsByDefault, javaSignature?.let { sig -> getJavaValueParameterType(sig, it.index) })
11131109
// Now substitute any class type parameters in:
@@ -1117,7 +1113,7 @@ open class KotlinUsesExtractor(
11171113
val maybeErased = if (functionTypeParameters.isEmpty()) maybeSubbed else erase(maybeSubbed)
11181114
"{${useType(maybeErased).javaResult.id}}"
11191115
}
1120-
val paramTypeIds = allParams.withIndex().joinToString(separator = ",", transform = getIdForFunctionLabel)
1116+
val paramTypeIds = allParamTypes.withIndex().joinToString(separator = ",", transform = getIdForFunctionLabel)
11211117
val labelReturnType =
11221118
if (name == "<init>")
11231119
pluginContext.irBuiltIns.unitType
@@ -1551,7 +1547,7 @@ open class KotlinUsesExtractor(
15511547
* Note that `Array<T>` is retained (with `T` itself erased) because these are expected to be lowered to Java
15521548
* arrays, which are not generic.
15531549
*/
1554-
private fun erase (t: IrType): IrType {
1550+
fun erase (t: IrType): IrType {
15551551
if (t is IrSimpleType) {
15561552
val classifier = t.classifier
15571553
val owner = classifier.owner
@@ -1578,6 +1574,8 @@ open class KotlinUsesExtractor(
15781574
private fun eraseTypeParameter(t: IrTypeParameter) =
15791575
erase(t.superTypes[0])
15801576

1577+
fun getValueParameterLabel(parentId: Label<out DbElement>?, idx: Int) = "@\"params;{$parentId};$idx\""
1578+
15811579
/**
15821580
* Gets the label for `vp` in the context of function instance `parent`, or in that of its declaring function if
15831581
* `parent` is null.
@@ -1607,7 +1605,7 @@ open class KotlinUsesExtractor(
16071605
logger.error("Unexpected negative index for parameter")
16081606
}
16091607

1610-
return "@\"params;{$parentId};$idx\""
1608+
return getValueParameterLabel(parentId, idx)
16111609
}
16121610

16131611

@@ -1669,7 +1667,7 @@ open class KotlinUsesExtractor(
16691667
val returnType = getter?.returnType ?: setter?.valueParameters?.singleOrNull()?.type ?: pluginContext.irBuiltIns.unitType
16701668
val typeParams = getFunctionTypeParameters(func)
16711669

1672-
getFunctionLabel(p.parent, parentId, p.name.asString(), listOf(), returnType, ext, typeParams, classTypeArgsIncludingOuterClasses, overridesCollectionsMethod = false, javaSignature = null, addParameterWildcardsByDefault = false, prefix = "property")
1670+
getFunctionLabel(p.parent, parentId, p.name.asString(), listOf(), returnType, ext.type, typeParams, classTypeArgsIncludingOuterClasses, overridesCollectionsMethod = false, javaSignature = null, addParameterWildcardsByDefault = false, prefix = "property")
16731671
}
16741672
}
16751673

java/ql/lib/semmle/code/java/Element.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ class Element extends @element, Top {
6565
i = 8 and result = "Proxy static method for a @JvmStatic-annotated function or property"
6666
or
6767
i = 9 and result = "Forwarder for a @JvmOverloads-annotated function"
68+
or
69+
i = 10 and result = "Forwarder for Kotlin calls that need default arguments filling in"
6870
)
6971
}
7072
}

0 commit comments

Comments
 (0)