diff --git a/csharp/ql/lib/semmle/code/csharp/Callable.qll b/csharp/ql/lib/semmle/code/csharp/Callable.qll index 03de29d6d431..6384f4582769 100644 --- a/csharp/ql/lib/semmle/code/csharp/Callable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Callable.qll @@ -8,6 +8,7 @@ import Stmt import Type import exprs.Call private import commons.QualifiedName +private import commons.Collections private import semmle.code.csharp.ExprOrStmtParent private import semmle.code.csharp.metrics.Complexity private import TypeRef @@ -273,7 +274,7 @@ class Method extends Callable, Virtualizable, Attributable, @method { Type getParamsType() { exists(Parameter last | last = this.getParameter(this.getNumberOfParameters() - 1) | last.isParams() and - result = last.getType().(ArrayType).getElementType() + result = last.getType().(ParamsCollectionType).getElementType() ) } diff --git a/csharp/ql/lib/semmle/code/csharp/commons/Collections.qll b/csharp/ql/lib/semmle/code/csharp/commons/Collections.qll index db38e7cb6ebb..a291c5dee4c4 100644 --- a/csharp/ql/lib/semmle/code/csharp/commons/Collections.qll +++ b/csharp/ql/lib/semmle/code/csharp/commons/Collections.qll @@ -2,6 +2,8 @@ import csharp import semmle.code.csharp.frameworks.system.Collections +private import semmle.code.csharp.frameworks.System +private import semmle.code.csharp.frameworks.system.collections.Generic private string modifyMethodName() { result = @@ -67,6 +69,39 @@ class CollectionType extends RefType { } } +/** + * A collection type that can be used as a `params` parameter type. + */ +abstract private class ParamsCollectionTypeImpl extends ValueOrRefType { + abstract Type getElementType(); +} + +private class AddArrayType extends ParamsCollectionTypeImpl instanceof ArrayType { + override Type getElementType() { result = ArrayType.super.getElementType() } +} + +private class AddCollectionTypes extends ParamsCollectionTypeImpl { + private ConstructedType base; + + AddCollectionTypes() { + exists(UnboundGenericType unboundbase | + base = this.getABaseType*() and unboundbase = base.getUnboundGeneric() + | + unboundbase instanceof SystemCollectionsGenericIEnumerableTInterface or + unboundbase instanceof SystemCollectionsGenericICollectionInterface or + unboundbase instanceof SystemCollectionsGenericIListTInterface or + unboundbase instanceof SystemCollectionsGenericIReadOnlyCollectionTInterface or + unboundbase instanceof SystemCollectionsGenericIReadOnlyListTInterface or + unboundbase instanceof SystemSpanStruct or + unboundbase instanceof SystemReadOnlySpanStruct + ) + } + + override Type getElementType() { result = base.getTypeArgument(0) } +} + +final class ParamsCollectionType = ParamsCollectionTypeImpl; + /** Holds if `t` is a collection type. */ predicate isCollectionType(ValueOrRefType t) { t.getABaseType*() instanceof SystemCollectionsIEnumerableInterface and diff --git a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll index 1b27871d1ef6..080b7d5c7325 100644 --- a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll @@ -6,6 +6,7 @@ */ import csharp +private import semmle.code.csharp.commons.Collections private import RuntimeCallable /** A call. */ @@ -1137,7 +1138,7 @@ private module Internal { if p.isParams() then ( j >= i and - paramType = p.getType().(ArrayType).getElementType() + paramType = p.getType().(ParamsCollectionType).getElementType() ) else ( i = j and paramType = p.getType() diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll index ac16df764162..56e063b1b5e0 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll @@ -755,3 +755,19 @@ class SystemNotImplementedExceptionClass extends SystemClass { class SystemDateTimeStruct extends SystemStruct { SystemDateTimeStruct() { this.hasName("DateTime") } } + +/** The `System.Span` struct. */ +class SystemSpanStruct extends SystemUnboundGenericStruct { + SystemSpanStruct() { + this.hasName("Span`1") and + this.getNumberOfTypeParameters() = 1 + } +} + +/** The `System.ReadOnlySpan` struct. */ +class SystemReadOnlySpanStruct extends SystemUnboundGenericStruct { + SystemReadOnlySpanStruct() { + this.hasName("ReadOnlySpan`1") and + this.getNumberOfTypeParameters() = 1 + } +} diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Generic.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Generic.qll index da41e09c3643..24c1277af026 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Generic.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/collections/Generic.qll @@ -158,3 +158,21 @@ class SystemCollectionsGenericIDictionaryInterface extends SystemCollectionsGene this.getNumberOfTypeParameters() = 2 } } + +/** The ``System.Collections.Generic.IReadOnlyCollection`1`` interface. */ +class SystemCollectionsGenericIReadOnlyCollectionTInterface extends SystemCollectionsGenericUnboundGenericInterface +{ + SystemCollectionsGenericIReadOnlyCollectionTInterface() { + this.hasName("IReadOnlyCollection`1") and + this.getNumberOfTypeParameters() = 1 + } +} + +/** The ``System.Collections.Generic.IReadOnlyList`1`` interface. */ +class SystemCollectionsGenericIReadOnlyListTInterface extends SystemCollectionsGenericUnboundGenericInterface +{ + SystemCollectionsGenericIReadOnlyListTInterface() { + this.hasName("IReadOnlyList`1") and + this.getNumberOfTypeParameters() = 1 + } +}