mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Kotlin: extract methods defined on collections types with their Java signatures
Collection, List and Map all define various methods which are either made more generic in Kotlin (e.g. `remove(Object) -> remove(E)`, `containsAll(Collection<?>) -> containsAll(Collection<E>)`), or are made invariant (e.g. `addAll(Collection<? extends E>) -> addAll(Collection<E>)`). This substitutes the types back to their Java signatures, thereby avoiding differing trap labels and duplicated methods for these types and their descendents.
This commit is contained in:
@@ -491,11 +491,17 @@ open class KotlinFileExtractor(
|
||||
private fun extractValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, parentSourceDeclaration: Label<out DbCallable>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, extractTypeAccess: Boolean, locOverride: Label<DbLocation>? = null): TypeResults {
|
||||
with("value parameter", vp) {
|
||||
val location = locOverride ?: getLocation(vp, classTypeArgsIncludingOuterClasses)
|
||||
val maybeErasedType = (vp.parent as? IrFunction)?.let {
|
||||
if (overridesCollectionsMethodWithAlteredParameterTypes(it))
|
||||
eraseCollectionsMethodParameterType(vp.type, it.name.asString(), idx)
|
||||
else
|
||||
null
|
||||
} ?: vp.type
|
||||
val id = useValueParameter(vp, parent)
|
||||
if (extractTypeAccess) {
|
||||
extractTypeAccessRecursive(typeSubstitution?.let { it(vp.type, TypeContext.OTHER, pluginContext) } ?: vp.type, location, id, -1)
|
||||
extractTypeAccessRecursive(typeSubstitution?.let { it(maybeErasedType, TypeContext.OTHER, pluginContext) } ?: maybeErasedType, location, id, -1)
|
||||
}
|
||||
return extractValueParameter(id, vp.type, vp.name.asString(), location, parent, idx, typeSubstitution, useValueParameter(vp, parentSourceDeclaration), vp.isVararg)
|
||||
return extractValueParameter(id, maybeErasedType, vp.name.asString(), location, parent, idx, typeSubstitution, useValueParameter(vp, parentSourceDeclaration), vp.isVararg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,7 +530,8 @@ open class KotlinFileExtractor(
|
||||
pluginContext.irBuiltIns.unitType,
|
||||
extensionReceiverParameter = null,
|
||||
functionTypeParameters = listOf(),
|
||||
classTypeArgsIncludingOuterClasses = listOf()
|
||||
classTypeArgsIncludingOuterClasses = listOf(),
|
||||
overridesCollectionsMethod = false
|
||||
)
|
||||
val clinitId = tw.getLabelFor<DbMethod>(clinitLabel)
|
||||
val returnType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN)
|
||||
@@ -1391,12 +1398,6 @@ open class KotlinFileExtractor(
|
||||
result
|
||||
}
|
||||
|
||||
val javaLangObject by lazy {
|
||||
val result = pluginContext.referenceClass(FqName("java.lang.Object"))?.owner
|
||||
result?.let { extractExternalClassLater(it) }
|
||||
result
|
||||
}
|
||||
|
||||
val objectCloneMethod by lazy {
|
||||
val result = javaLangObject?.declarations?.find {
|
||||
it is IrFunction && it.name.asString() == "clone"
|
||||
|
||||
@@ -5,16 +5,20 @@ import com.github.codeql.utils.versions.isRawType
|
||||
import com.semmle.extractor.java.OdasaOutput
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.allOverridden
|
||||
import org.jetbrains.kotlin.backend.common.ir.isOverridableOrOverrides
|
||||
import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.getLastOverridden
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -31,6 +35,17 @@ open class KotlinUsesExtractor(
|
||||
val pluginContext: IrPluginContext,
|
||||
val globalExtensionState: KotlinExtractorGlobalState
|
||||
) {
|
||||
|
||||
val javaLangObject by lazy {
|
||||
val result = pluginContext.referenceClass(FqName("java.lang.Object"))?.owner
|
||||
result?.let { extractExternalClassLater(it) }
|
||||
result
|
||||
}
|
||||
|
||||
val javaLangObjectType by lazy {
|
||||
javaLangObject?.typeWith()
|
||||
}
|
||||
|
||||
fun usePackage(pkg: String): Label<out DbPackage> {
|
||||
return extractPackage(pkg)
|
||||
}
|
||||
@@ -789,6 +804,52 @@ open class KotlinUsesExtractor(
|
||||
else -> null
|
||||
}
|
||||
|
||||
val javaUtilCollection by lazy {
|
||||
val result = pluginContext.referenceClass(FqName("java.util.Collection"))?.owner
|
||||
result?.let { extractExternalClassLater(it) }
|
||||
result
|
||||
}
|
||||
|
||||
val wildcardCollectionType by lazy {
|
||||
javaUtilCollection?.let {
|
||||
it.symbol.typeWithArguments(listOf(IrStarProjectionImpl))
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeCovariant(t: IrTypeArgument) =
|
||||
t.typeOrNull?.let { makeTypeProjection(it, Variance.OUT_VARIANCE) } ?: t
|
||||
|
||||
private fun makeArgumentsCovariant(t: IrType) = (t as? IrSimpleType)?.let {
|
||||
t.toBuilder().also { b -> b.arguments = b.arguments.map(this::makeCovariant) }.buildSimpleType()
|
||||
} ?: t
|
||||
|
||||
fun eraseCollectionsMethodParameterType(t: IrType, collectionsMethodName: String, paramIdx: Int) =
|
||||
when(collectionsMethodName) {
|
||||
"contains", "remove", "containsKey", "containsValue", "get", "indexOf", "lastIndexOf" -> javaLangObjectType
|
||||
"getOrDefault" -> if (paramIdx == 0) javaLangObjectType else null
|
||||
"containsAll", "removeAll", "retainAll" -> wildcardCollectionType
|
||||
// Kotlin defines these like addAll(Collection<E>); Java uses addAll(Collection<? extends E>)
|
||||
"putAll", "addAll" -> makeArgumentsCovariant(t)
|
||||
else -> null
|
||||
} ?: t
|
||||
|
||||
private fun overridesFunctionDefinedOn(f: IrFunction, packageName: String, className: String) =
|
||||
(f as? IrSimpleFunction)?.let {
|
||||
it.overriddenSymbols.any { overridden ->
|
||||
overridden.owner.parentClassOrNull?.let { defnClass ->
|
||||
defnClass.name.asString() == className &&
|
||||
defnClass.packageFqName?.asString() == packageName
|
||||
} ?: false
|
||||
}
|
||||
} ?: false
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
fun overridesCollectionsMethodWithAlteredParameterTypes(f: IrFunction) =
|
||||
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(f.descriptor) != null ||
|
||||
(f.name.asString() == "putAll" && overridesFunctionDefinedOn(f, "kotlin.collections", "MutableMap")) ||
|
||||
(f.name.asString() == "addAll" && overridesFunctionDefinedOn(f, "kotlin.collections", "MutableCollection")) ||
|
||||
(f.name.asString() == "addAll" && overridesFunctionDefinedOn(f, "kotlin.collections", "MutableList"))
|
||||
|
||||
/*
|
||||
* This is the normal getFunctionLabel function to use. If you want
|
||||
* to refer to the function in its source class then
|
||||
@@ -810,8 +871,19 @@ open class KotlinUsesExtractor(
|
||||
* `java.lang.Throwable`, which isn't what we want. So we have to
|
||||
* allow it to be passed in.
|
||||
*/
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
fun getFunctionLabel(f: IrFunction, maybeParentId: Label<out DbElement>?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?) =
|
||||
getFunctionLabel(f.parent, maybeParentId, getFunctionShortName(f).nameInDB, f.valueParameters, f.returnType, f.extensionReceiverParameter, getFunctionTypeParameters(f), classTypeArgsIncludingOuterClasses)
|
||||
getFunctionLabel(
|
||||
f.parent,
|
||||
maybeParentId,
|
||||
getFunctionShortName(f).nameInDB,
|
||||
f.valueParameters,
|
||||
f.returnType,
|
||||
f.extensionReceiverParameter,
|
||||
getFunctionTypeParameters(f),
|
||||
classTypeArgsIncludingOuterClasses,
|
||||
overridesCollectionsMethodWithAlteredParameterTypes(f)
|
||||
)
|
||||
|
||||
/*
|
||||
* This function actually generates the label for a function.
|
||||
@@ -837,6 +909,9 @@ open class KotlinUsesExtractor(
|
||||
functionTypeParameters: List<IrTypeParameter>,
|
||||
// The type arguments of enclosing classes of the function.
|
||||
classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?,
|
||||
// If true, this method implements a Java Collections interface (Collection, Map or List) and may need
|
||||
// parameter erasure to match the way this class will appear to an external consumer of the .class file.
|
||||
overridesCollectionsMethod: Boolean,
|
||||
// The prefix used in the label. "callable", unless a property label is created, then it's "property".
|
||||
prefix: String = "callable"
|
||||
): String {
|
||||
@@ -855,14 +930,19 @@ open class KotlinUsesExtractor(
|
||||
enclosingClass?.let { notNullClass -> makeTypeGenericSubstitutionMap(notNullClass, notNullArgs) }
|
||||
}
|
||||
}
|
||||
val getIdForFunctionLabel = { it: IrValueParameter ->
|
||||
// Mimic the Java extractor's behaviour: functions with type parameters are named for their erased types;
|
||||
val getIdForFunctionLabel = { it: IndexedValue<IrValueParameter> ->
|
||||
// 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
|
||||
// Now substitute any class type parameters in:
|
||||
val maybeSubbed = maybeAmendedForCollections.substituteTypeAndArguments(substitutionMap, TypeContext.OTHER, pluginContext)
|
||||
// Finally, mimic the Java extractor's behaviour by naming functions with type parameters for their erased types;
|
||||
// those without type parameters are named for the generic type.
|
||||
val maybeSubbed = it.type.substituteTypeAndArguments(substitutionMap, TypeContext.OTHER, pluginContext)
|
||||
val maybeErased = if (functionTypeParameters.isEmpty()) maybeSubbed else erase(maybeSubbed)
|
||||
"{${useType(maybeErased).javaResult.id}}"
|
||||
}
|
||||
val paramTypeIds = allParams.joinToString(separator = ",", transform = getIdForFunctionLabel)
|
||||
val paramTypeIds = allParams.withIndex().joinToString(separator = ",", transform = getIdForFunctionLabel)
|
||||
val labelReturnType =
|
||||
if (name == "<init>")
|
||||
pluginContext.irBuiltIns.unitType
|
||||
@@ -1299,7 +1379,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, "property")
|
||||
getFunctionLabel(p.parent, parentId, p.name.asString(), listOf(), returnType, ext, typeParams, classTypeArgsIncludingOuterClasses, overridesCollectionsMethod = false, prefix = "property")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import java.util.Map;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Collection;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.List;
|
||||
import java.util.AbstractList;
|
||||
|
||||
public class Test {
|
||||
|
||||
public static void test(
|
||||
Map<String, String> p1,
|
||||
AbstractMap<String, String> p2,
|
||||
Collection<String> p3,
|
||||
AbstractCollection<String> p4,
|
||||
List<String> p5,
|
||||
AbstractList<String> p6) {
|
||||
|
||||
// Use a method of each to ensure method prototypes are extracted:
|
||||
p1.remove("Hello");
|
||||
p2.remove("Hello");
|
||||
p3.remove("Hello");
|
||||
p4.remove("Hello");
|
||||
p5.remove("Hello");
|
||||
p6.remove("Hello");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,412 @@
|
||||
methodWithDuplicate
|
||||
#select
|
||||
| AbstractCollection | add | E |
|
||||
| AbstractCollection | addAll | Collection<? extends E> |
|
||||
| AbstractCollection | contains | Object |
|
||||
| AbstractCollection | containsAll | Collection<?> |
|
||||
| AbstractCollection | remove | Object |
|
||||
| AbstractCollection | removeAll | Collection<?> |
|
||||
| AbstractCollection | retainAll | Collection<?> |
|
||||
| AbstractCollection | toArray | T[] |
|
||||
| AbstractCollection<E> | add | E |
|
||||
| AbstractCollection<E> | addAll | Collection<? extends E> |
|
||||
| AbstractCollection<E> | contains | Object |
|
||||
| AbstractCollection<E> | containsAll | Collection<?> |
|
||||
| AbstractCollection<E> | remove | Object |
|
||||
| AbstractCollection<E> | removeAll | Collection<?> |
|
||||
| AbstractCollection<E> | retainAll | Collection<?> |
|
||||
| AbstractCollection<E> | toArray | T[] |
|
||||
| AbstractCollection<String> | add | String |
|
||||
| AbstractCollection<String> | addAll | Collection<? extends String> |
|
||||
| AbstractCollection<String> | contains | Object |
|
||||
| AbstractCollection<String> | containsAll | Collection<?> |
|
||||
| AbstractCollection<String> | remove | Object |
|
||||
| AbstractCollection<String> | removeAll | Collection<?> |
|
||||
| AbstractCollection<String> | retainAll | Collection<?> |
|
||||
| AbstractCollection<String> | toArray | T[] |
|
||||
| AbstractList | add | E |
|
||||
| AbstractList | add | int |
|
||||
| AbstractList | addAll | Collection<? extends E> |
|
||||
| AbstractList | addAll | int |
|
||||
| AbstractList | equals | Object |
|
||||
| AbstractList | get | int |
|
||||
| AbstractList | indexOf | Object |
|
||||
| AbstractList | lastIndexOf | Object |
|
||||
| AbstractList | listIterator | int |
|
||||
| AbstractList | removeAt | int |
|
||||
| AbstractList | removeRange | int |
|
||||
| AbstractList | set | E |
|
||||
| AbstractList | set | int |
|
||||
| AbstractList | subList | int |
|
||||
| AbstractList | subListRangeCheck | int |
|
||||
| AbstractList<E> | add | E |
|
||||
| AbstractList<E> | add | int |
|
||||
| AbstractList<E> | addAll | Collection<? extends E> |
|
||||
| AbstractList<E> | addAll | int |
|
||||
| AbstractList<E> | equals | Object |
|
||||
| AbstractList<E> | get | int |
|
||||
| AbstractList<E> | indexOf | Object |
|
||||
| AbstractList<E> | lastIndexOf | Object |
|
||||
| AbstractList<E> | listIterator | int |
|
||||
| AbstractList<E> | removeAt | int |
|
||||
| AbstractList<E> | removeRange | int |
|
||||
| AbstractList<E> | set | E |
|
||||
| AbstractList<E> | set | int |
|
||||
| AbstractList<E> | subList | int |
|
||||
| AbstractList<E> | subListRangeCheck | int |
|
||||
| AbstractMap | containsEntry | Entry<?,?> |
|
||||
| AbstractMap | containsKey | Object |
|
||||
| AbstractMap | containsValue | Object |
|
||||
| AbstractMap | equals | Object |
|
||||
| AbstractMap | get | Object |
|
||||
| AbstractMap | put | K |
|
||||
| AbstractMap | put | V |
|
||||
| AbstractMap | putAll | Map<? extends K,? extends V> |
|
||||
| AbstractMap | remove | Object |
|
||||
| AbstractMap<Identity,Entry<?>> | containsKey | Object |
|
||||
| AbstractMap<Identity,Entry<?>> | containsValue | Object |
|
||||
| AbstractMap<Identity,Entry<?>> | equals | Object |
|
||||
| AbstractMap<Identity,Entry<?>> | get | Object |
|
||||
| AbstractMap<Identity,Entry<?>> | put | Entry<?> |
|
||||
| AbstractMap<Identity,Entry<?>> | put | Identity |
|
||||
| AbstractMap<Identity,Entry<?>> | putAll | Map<? extends Identity,? extends Entry<?>> |
|
||||
| AbstractMap<Identity,Entry<?>> | remove | Object |
|
||||
| AbstractMap<K,V> | containsKey | Object |
|
||||
| AbstractMap<K,V> | containsValue | Object |
|
||||
| AbstractMap<K,V> | equals | Object |
|
||||
| AbstractMap<K,V> | get | Object |
|
||||
| AbstractMap<K,V> | put | K |
|
||||
| AbstractMap<K,V> | put | V |
|
||||
| AbstractMap<K,V> | putAll | Map<? extends K,? extends V> |
|
||||
| AbstractMap<K,V> | remove | Object |
|
||||
| AbstractMap<String,String> | containsEntry | Entry<?,?> |
|
||||
| AbstractMap<String,String> | containsKey | Object |
|
||||
| AbstractMap<String,String> | containsValue | Object |
|
||||
| AbstractMap<String,String> | equals | Object |
|
||||
| AbstractMap<String,String> | get | Object |
|
||||
| AbstractMap<String,String> | put | String |
|
||||
| AbstractMap<String,String> | putAll | Map<? extends String,? extends String> |
|
||||
| AbstractMap<String,String> | remove | Object |
|
||||
| AbstractMutableCollection | add | E |
|
||||
| AbstractMutableList | add | E |
|
||||
| AbstractMutableList | add | int |
|
||||
| AbstractMutableList | removeAt | int |
|
||||
| AbstractMutableList | set | E |
|
||||
| AbstractMutableList | set | int |
|
||||
| AbstractMutableMap | put | K |
|
||||
| AbstractMutableMap | put | V |
|
||||
| Collection | add | E |
|
||||
| Collection | addAll | Collection<? extends E> |
|
||||
| Collection | contains | Object |
|
||||
| Collection | containsAll | Collection<?> |
|
||||
| Collection | equals | Object |
|
||||
| Collection | remove | Object |
|
||||
| Collection | removeAll | Collection<?> |
|
||||
| Collection | removeIf | Predicate<? super E> |
|
||||
| Collection | retainAll | Collection<?> |
|
||||
| Collection | toArray | IntFunction<T[]> |
|
||||
| Collection | toArray | T[] |
|
||||
| Collection<E> | add | E |
|
||||
| Collection<E> | addAll | Collection<? extends E> |
|
||||
| Collection<E> | contains | Object |
|
||||
| Collection<E> | containsAll | Collection<?> |
|
||||
| Collection<E> | remove | Object |
|
||||
| Collection<E> | removeAll | Collection<?> |
|
||||
| Collection<E> | removeIf | Predicate<? super E> |
|
||||
| Collection<E> | retainAll | Collection<?> |
|
||||
| Collection<E> | toArray | IntFunction<T[]> |
|
||||
| Collection<E> | toArray | T[] |
|
||||
| Collection<Entry<K,V>> | add | Entry<K,V> |
|
||||
| Collection<Entry<K,V>> | addAll | Collection<? extends Entry<K,V>> |
|
||||
| Collection<Entry<K,V>> | contains | Object |
|
||||
| Collection<Entry<K,V>> | containsAll | Collection<?> |
|
||||
| Collection<Entry<K,V>> | remove | Object |
|
||||
| Collection<Entry<K,V>> | removeAll | Collection<?> |
|
||||
| Collection<Entry<K,V>> | removeIf | Predicate<? super Entry<K,V>> |
|
||||
| Collection<Entry<K,V>> | retainAll | Collection<?> |
|
||||
| Collection<Entry<K,V>> | toArray | IntFunction<T[]> |
|
||||
| Collection<Entry<K,V>> | toArray | T[] |
|
||||
| Collection<K> | add | K |
|
||||
| Collection<K> | addAll | Collection<? extends K> |
|
||||
| Collection<K> | contains | Object |
|
||||
| Collection<K> | containsAll | Collection<?> |
|
||||
| Collection<K> | remove | Object |
|
||||
| Collection<K> | removeAll | Collection<?> |
|
||||
| Collection<K> | removeIf | Predicate<? super K> |
|
||||
| Collection<K> | retainAll | Collection<?> |
|
||||
| Collection<K> | toArray | IntFunction<T[]> |
|
||||
| Collection<K> | toArray | T[] |
|
||||
| Collection<String> | add | String |
|
||||
| Collection<String> | addAll | Collection<? extends String> |
|
||||
| Collection<String> | contains | Object |
|
||||
| Collection<String> | containsAll | Collection<?> |
|
||||
| Collection<String> | equals | Object |
|
||||
| Collection<String> | remove | Object |
|
||||
| Collection<String> | removeAll | Collection<?> |
|
||||
| Collection<String> | removeIf | Predicate<? super String> |
|
||||
| Collection<String> | retainAll | Collection<?> |
|
||||
| Collection<String> | toArray | IntFunction<T[]> |
|
||||
| Collection<String> | toArray | T[] |
|
||||
| Collection<V> | add | V |
|
||||
| Collection<V> | addAll | Collection<? extends V> |
|
||||
| Collection<V> | contains | Object |
|
||||
| Collection<V> | containsAll | Collection<?> |
|
||||
| Collection<V> | remove | Object |
|
||||
| Collection<V> | removeAll | Collection<?> |
|
||||
| Collection<V> | removeIf | Predicate<? super V> |
|
||||
| Collection<V> | retainAll | Collection<?> |
|
||||
| Collection<V> | toArray | IntFunction<T[]> |
|
||||
| Collection<V> | toArray | T[] |
|
||||
| List | add | E |
|
||||
| List | add | int |
|
||||
| List | addAll | Collection<? extends E> |
|
||||
| List | addAll | int |
|
||||
| List | contains | Object |
|
||||
| List | containsAll | Collection<?> |
|
||||
| List | copyOf | Collection<? extends E> |
|
||||
| List | equals | Object |
|
||||
| List | get | int |
|
||||
| List | indexOf | Object |
|
||||
| List | lastIndexOf | Object |
|
||||
| List | listIterator | int |
|
||||
| List | of | E |
|
||||
| List | of | E[] |
|
||||
| List | remove | Object |
|
||||
| List | remove | int |
|
||||
| List | removeAll | Collection<?> |
|
||||
| List | replaceAll | UnaryOperator<E> |
|
||||
| List | retainAll | Collection<?> |
|
||||
| List | set | E |
|
||||
| List | set | int |
|
||||
| List | sort | Comparator<? super E> |
|
||||
| List | subList | int |
|
||||
| List | toArray | T[] |
|
||||
| List<E> | add | E |
|
||||
| List<E> | add | int |
|
||||
| List<E> | addAll | Collection<? extends E> |
|
||||
| List<E> | addAll | int |
|
||||
| List<E> | contains | Object |
|
||||
| List<E> | containsAll | Collection<?> |
|
||||
| List<E> | copyOf | Collection<? extends E> |
|
||||
| List<E> | get | int |
|
||||
| List<E> | indexOf | Object |
|
||||
| List<E> | lastIndexOf | Object |
|
||||
| List<E> | listIterator | int |
|
||||
| List<E> | of | E |
|
||||
| List<E> | of | E[] |
|
||||
| List<E> | remove | Object |
|
||||
| List<E> | remove | int |
|
||||
| List<E> | removeAll | Collection<?> |
|
||||
| List<E> | replaceAll | UnaryOperator<E> |
|
||||
| List<E> | retainAll | Collection<?> |
|
||||
| List<E> | set | E |
|
||||
| List<E> | set | int |
|
||||
| List<E> | sort | Comparator<? super E> |
|
||||
| List<E> | subList | int |
|
||||
| List<E> | toArray | T[] |
|
||||
| List<String> | add | String |
|
||||
| List<String> | add | int |
|
||||
| List<String> | addAll | Collection<? extends String> |
|
||||
| List<String> | addAll | int |
|
||||
| List<String> | contains | Object |
|
||||
| List<String> | containsAll | Collection<?> |
|
||||
| List<String> | copyOf | Collection<? extends E> |
|
||||
| List<String> | equals | Object |
|
||||
| List<String> | get | int |
|
||||
| List<String> | indexOf | Object |
|
||||
| List<String> | lastIndexOf | Object |
|
||||
| List<String> | listIterator | int |
|
||||
| List<String> | of | E |
|
||||
| List<String> | of | E[] |
|
||||
| List<String> | remove | Object |
|
||||
| List<String> | remove | int |
|
||||
| List<String> | removeAll | Collection<?> |
|
||||
| List<String> | replaceAll | UnaryOperator<String> |
|
||||
| List<String> | retainAll | Collection<?> |
|
||||
| List<String> | set | String |
|
||||
| List<String> | set | int |
|
||||
| List<String> | sort | Comparator<? super String> |
|
||||
| List<String> | subList | int |
|
||||
| List<String> | toArray | T[] |
|
||||
| Map | compute | BiFunction<? super K,? super V,? extends V> |
|
||||
| Map | compute | K |
|
||||
| Map | computeIfAbsent | Function<? super K,? extends V> |
|
||||
| Map | computeIfAbsent | K |
|
||||
| Map | computeIfPresent | BiFunction<? super K,? super V,? extends V> |
|
||||
| Map | computeIfPresent | K |
|
||||
| Map | containsKey | Object |
|
||||
| Map | containsValue | Object |
|
||||
| Map | copyOf | Map<? extends K,? extends V> |
|
||||
| Map | entry | K |
|
||||
| Map | entry | V |
|
||||
| Map | equals | Object |
|
||||
| Map | forEach | BiConsumer<? super K,? super V> |
|
||||
| Map | get | Object |
|
||||
| Map | getOrDefault | Object |
|
||||
| Map | getOrDefault | V |
|
||||
| Map | merge | BiFunction<? super V,? super V,? extends V> |
|
||||
| Map | merge | K |
|
||||
| Map | merge | V |
|
||||
| Map | of | K |
|
||||
| Map | of | V |
|
||||
| Map | ofEntries | Entry<? extends K,? extends V>[] |
|
||||
| Map | put | K |
|
||||
| Map | put | V |
|
||||
| Map | putAll | Map<? extends K,? extends V> |
|
||||
| Map | putIfAbsent | K |
|
||||
| Map | putIfAbsent | V |
|
||||
| Map | remove | Object |
|
||||
| Map | replace | K |
|
||||
| Map | replace | V |
|
||||
| Map | replaceAll | BiFunction<? super K,? super V,? extends V> |
|
||||
| Map<Identity,Entry<?>> | compute | BiFunction<? super Identity,? super Entry<?>,? extends Entry<?>> |
|
||||
| Map<Identity,Entry<?>> | compute | Identity |
|
||||
| Map<Identity,Entry<?>> | computeIfAbsent | Function<? super Identity,? extends Entry<?>> |
|
||||
| Map<Identity,Entry<?>> | computeIfAbsent | Identity |
|
||||
| Map<Identity,Entry<?>> | computeIfPresent | BiFunction<? super Identity,? super Entry<?>,? extends Entry<?>> |
|
||||
| Map<Identity,Entry<?>> | computeIfPresent | Identity |
|
||||
| Map<Identity,Entry<?>> | containsKey | Object |
|
||||
| Map<Identity,Entry<?>> | containsValue | Object |
|
||||
| Map<Identity,Entry<?>> | copyOf | Map<? extends K,? extends V> |
|
||||
| Map<Identity,Entry<?>> | entry | K |
|
||||
| Map<Identity,Entry<?>> | entry | V |
|
||||
| Map<Identity,Entry<?>> | forEach | BiConsumer<? super Identity,? super Entry<?>> |
|
||||
| Map<Identity,Entry<?>> | get | Object |
|
||||
| Map<Identity,Entry<?>> | getOrDefault | Entry<?> |
|
||||
| Map<Identity,Entry<?>> | getOrDefault | Object |
|
||||
| Map<Identity,Entry<?>> | merge | BiFunction<? super Entry<?>,? super Entry<?>,? extends Entry<?>> |
|
||||
| Map<Identity,Entry<?>> | merge | Entry<?> |
|
||||
| Map<Identity,Entry<?>> | merge | Identity |
|
||||
| Map<Identity,Entry<?>> | of | K |
|
||||
| Map<Identity,Entry<?>> | of | V |
|
||||
| Map<Identity,Entry<?>> | ofEntries | Entry<? extends K,? extends V>[] |
|
||||
| Map<Identity,Entry<?>> | put | Entry<?> |
|
||||
| Map<Identity,Entry<?>> | put | Identity |
|
||||
| Map<Identity,Entry<?>> | putAll | Map<? extends Identity,? extends Entry<?>> |
|
||||
| Map<Identity,Entry<?>> | putIfAbsent | Entry<?> |
|
||||
| Map<Identity,Entry<?>> | putIfAbsent | Identity |
|
||||
| Map<Identity,Entry<?>> | remove | Object |
|
||||
| Map<Identity,Entry<?>> | replace | Entry<?> |
|
||||
| Map<Identity,Entry<?>> | replace | Identity |
|
||||
| Map<Identity,Entry<?>> | replaceAll | BiFunction<? super Identity,? super Entry<?>,? extends Entry<?>> |
|
||||
| Map<K,V> | compute | BiFunction<? super K,? super V,? extends V> |
|
||||
| Map<K,V> | compute | K |
|
||||
| Map<K,V> | computeIfAbsent | Function<? super K,? extends V> |
|
||||
| Map<K,V> | computeIfAbsent | K |
|
||||
| Map<K,V> | computeIfPresent | BiFunction<? super K,? super V,? extends V> |
|
||||
| Map<K,V> | computeIfPresent | K |
|
||||
| Map<K,V> | containsKey | Object |
|
||||
| Map<K,V> | containsValue | Object |
|
||||
| Map<K,V> | copyOf | Map<? extends K,? extends V> |
|
||||
| Map<K,V> | entry | K |
|
||||
| Map<K,V> | entry | V |
|
||||
| Map<K,V> | forEach | BiConsumer<? super K,? super V> |
|
||||
| Map<K,V> | get | Object |
|
||||
| Map<K,V> | getOrDefault | Object |
|
||||
| Map<K,V> | getOrDefault | V |
|
||||
| Map<K,V> | merge | BiFunction<? super V,? super V,? extends V> |
|
||||
| Map<K,V> | merge | K |
|
||||
| Map<K,V> | merge | V |
|
||||
| Map<K,V> | of | K |
|
||||
| Map<K,V> | of | V |
|
||||
| Map<K,V> | ofEntries | Entry<? extends K,? extends V>[] |
|
||||
| Map<K,V> | put | K |
|
||||
| Map<K,V> | put | V |
|
||||
| Map<K,V> | putAll | Map<? extends K,? extends V> |
|
||||
| Map<K,V> | putIfAbsent | K |
|
||||
| Map<K,V> | putIfAbsent | V |
|
||||
| Map<K,V> | remove | Object |
|
||||
| Map<K,V> | replace | K |
|
||||
| Map<K,V> | replace | V |
|
||||
| Map<K,V> | replaceAll | BiFunction<? super K,? super V,? extends V> |
|
||||
| Map<Object,Object> | compute | BiFunction<? super Object,? super Object,? extends Object> |
|
||||
| Map<Object,Object> | compute | Object |
|
||||
| Map<Object,Object> | computeIfAbsent | Function<? super Object,? extends Object> |
|
||||
| Map<Object,Object> | computeIfAbsent | Object |
|
||||
| Map<Object,Object> | computeIfPresent | BiFunction<? super Object,? super Object,? extends Object> |
|
||||
| Map<Object,Object> | computeIfPresent | Object |
|
||||
| Map<Object,Object> | containsKey | Object |
|
||||
| Map<Object,Object> | containsValue | Object |
|
||||
| Map<Object,Object> | copyOf | Map<? extends K,? extends V> |
|
||||
| Map<Object,Object> | entry | K |
|
||||
| Map<Object,Object> | entry | V |
|
||||
| Map<Object,Object> | forEach | BiConsumer<? super Object,? super Object> |
|
||||
| Map<Object,Object> | get | Object |
|
||||
| Map<Object,Object> | getOrDefault | Object |
|
||||
| Map<Object,Object> | merge | BiFunction<? super Object,? super Object,? extends Object> |
|
||||
| Map<Object,Object> | merge | Object |
|
||||
| Map<Object,Object> | of | K |
|
||||
| Map<Object,Object> | of | V |
|
||||
| Map<Object,Object> | ofEntries | Entry<? extends K,? extends V>[] |
|
||||
| Map<Object,Object> | put | Object |
|
||||
| Map<Object,Object> | putAll | Map<? extends Object,? extends Object> |
|
||||
| Map<Object,Object> | putIfAbsent | Object |
|
||||
| Map<Object,Object> | remove | Object |
|
||||
| Map<Object,Object> | replace | Object |
|
||||
| Map<Object,Object> | replaceAll | BiFunction<? super Object,? super Object,? extends Object> |
|
||||
| Map<String,String> | compute | BiFunction<? super String,? super String,? extends String> |
|
||||
| Map<String,String> | compute | String |
|
||||
| Map<String,String> | computeIfAbsent | Function<? super String,? extends String> |
|
||||
| Map<String,String> | computeIfAbsent | String |
|
||||
| Map<String,String> | computeIfPresent | BiFunction<? super String,? super String,? extends String> |
|
||||
| Map<String,String> | computeIfPresent | String |
|
||||
| Map<String,String> | containsKey | Object |
|
||||
| Map<String,String> | containsValue | Object |
|
||||
| Map<String,String> | copyOf | Map<? extends K,? extends V> |
|
||||
| Map<String,String> | entry | K |
|
||||
| Map<String,String> | entry | V |
|
||||
| Map<String,String> | equals | Object |
|
||||
| Map<String,String> | forEach | BiConsumer<? super String,? super String> |
|
||||
| Map<String,String> | get | Object |
|
||||
| Map<String,String> | getOrDefault | Object |
|
||||
| Map<String,String> | getOrDefault | String |
|
||||
| Map<String,String> | merge | BiFunction<? super String,? super String,? extends String> |
|
||||
| Map<String,String> | merge | String |
|
||||
| Map<String,String> | of | K |
|
||||
| Map<String,String> | of | V |
|
||||
| Map<String,String> | ofEntries | Entry<? extends K,? extends V>[] |
|
||||
| Map<String,String> | put | String |
|
||||
| Map<String,String> | putAll | Map<? extends String,? extends String> |
|
||||
| Map<String,String> | putIfAbsent | String |
|
||||
| Map<String,String> | remove | Object |
|
||||
| Map<String,String> | replace | String |
|
||||
| Map<String,String> | replaceAll | BiFunction<? super String,? super String,? extends String> |
|
||||
| MutableCollection | add | E |
|
||||
| MutableCollection | addAll | Collection |
|
||||
| MutableCollection | remove | Object |
|
||||
| MutableCollection | removeAll | Collection<?> |
|
||||
| MutableCollection | removeIf | Predicate<? super E> |
|
||||
| MutableCollection | retainAll | Collection<?> |
|
||||
| MutableList | add | E |
|
||||
| MutableList | add | int |
|
||||
| MutableList | addAll | Collection<? extends E> |
|
||||
| MutableList | addAll | Collection<E> |
|
||||
| MutableList | addAll | int |
|
||||
| MutableList | listIterator | int |
|
||||
| MutableList | remove | Object |
|
||||
| MutableList | removeAll | Collection<?> |
|
||||
| MutableList | removeAt | int |
|
||||
| MutableList | replaceAll | UnaryOperator<E> |
|
||||
| MutableList | retainAll | Collection<?> |
|
||||
| MutableList | set | E |
|
||||
| MutableList | set | int |
|
||||
| MutableList | sort | Comparator<? super E> |
|
||||
| MutableList | subList | int |
|
||||
| MutableMap | compute | BiFunction<? super K,? super V,? extends V> |
|
||||
| MutableMap | compute | K |
|
||||
| MutableMap | computeIfAbsent | Function<? super K,? extends V> |
|
||||
| MutableMap | computeIfAbsent | K |
|
||||
| MutableMap | computeIfPresent | BiFunction<? super K,? super V,? extends V> |
|
||||
| MutableMap | computeIfPresent | K |
|
||||
| MutableMap | merge | BiFunction<? super V,? super V,? extends V> |
|
||||
| MutableMap | merge | K |
|
||||
| MutableMap | merge | V |
|
||||
| MutableMap | put | K |
|
||||
| MutableMap | put | V |
|
||||
| MutableMap | putAll | Map<? extends K,V> |
|
||||
| MutableMap | putIfAbsent | K |
|
||||
| MutableMap | putIfAbsent | V |
|
||||
| MutableMap | remove | Object |
|
||||
| MutableMap | replace | K |
|
||||
| MutableMap | replace | V |
|
||||
| MutableMap | replaceAll | BiFunction<? super K,? super V,? extends V> |
|
||||
@@ -0,0 +1,29 @@
|
||||
fun test(
|
||||
p1: Map<String, String>,
|
||||
p2: AbstractMap<String, String>,
|
||||
p3: Collection<String>,
|
||||
p4: AbstractCollection<String>,
|
||||
p5: List<String>,
|
||||
p6: AbstractList<String>,
|
||||
p7: MutableMap<String, String>,
|
||||
p8: AbstractMutableMap<String, String>,
|
||||
p9: MutableCollection<String>,
|
||||
p10: AbstractMutableCollection<String>,
|
||||
p11: MutableList<String>,
|
||||
p12: AbstractMutableList<String>) {
|
||||
|
||||
// Use a method of each to ensure method prototypes are extracted:
|
||||
p1.get("Hello");
|
||||
p2.get("Hello");
|
||||
p3.contains("Hello");
|
||||
p4.contains("Hello");
|
||||
p5.contains("Hello");
|
||||
p6.contains("Hello");
|
||||
p7.remove("Hello");
|
||||
p8.remove("Hello");
|
||||
p9.remove("Hello");
|
||||
p10.remove("Hello");
|
||||
p11.remove("Hello");
|
||||
p12.remove("Hello");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import java
|
||||
|
||||
RefType getARelevantCollectionType() {
|
||||
result.hasQualifiedName(["java.util", "kotlin.collections"], ["Abstract", ""] + ["Mutable", ""] + ["Collection", "List", "Map"])
|
||||
}
|
||||
|
||||
class RelevantMethod extends Method {
|
||||
|
||||
RelevantMethod() { this.getDeclaringType().getSourceDeclaration() = getARelevantCollectionType() }
|
||||
|
||||
}
|
||||
|
||||
// Check for methods with suspicious twins -- probably another extraction of the same method outline which was given a different trap key.
|
||||
// It so happens the collections methods of interest to this test don't use overloads with the same parameter count.
|
||||
query predicate methodWithDuplicate(string methodName, string typeName) {
|
||||
exists(RelevantMethod m, RelevantMethod dup |
|
||||
dup.getName() = m.getName() and
|
||||
not dup.getName() = ["of", "remove", "toArray"] and // These really do have overloads with the same parameter count, so it isn't trivial to tell if they are intentional overloads or inappropriate duplicates.
|
||||
dup.getNumberOfParameters() = m.getNumberOfParameters() and
|
||||
dup.getDeclaringType() = m.getDeclaringType() and
|
||||
dup != m and
|
||||
methodName = m.getName() and
|
||||
typeName = m.getDeclaringType().getName()
|
||||
)
|
||||
}
|
||||
|
||||
from RelevantMethod m
|
||||
select m.getDeclaringType().getName(), m.getName(), m.getAParamType().getName()
|
||||
Reference in New Issue
Block a user