diff --git a/csharp/ql/test/library-tests/conversion/span/Span.cs b/csharp/ql/test/library-tests/conversion/span/Span.cs new file mode 100644 index 00000000000..965396b0e25 --- /dev/null +++ b/csharp/ql/test/library-tests/conversion/span/Span.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; + +public interface CovariantInterface { } + +public interface InvariantInterface { } + +public interface Interface { } + +public class Base { } + +public class Derived : Base { } + +public class C +{ + public void M() + { + string[] stringArray = []; + string[][] stringArrayArray; + string[,] stringArray2D; + + Span stringSpan = stringArray; // string[] -> Span; + + // Covariant conversions to ReadOnlySpan + // Assignments are included to illustrate that this compiles. + // Only the use of the types matter in terms of test output. + ReadOnlySpan> covariantInterfaceBaseReadOnlySpan; + ReadOnlySpan> covariantInterfaceDerivedReadOnlySpan = default; + Span> covariantInterfaceDerivedSpan = default; + CovariantInterface[] covariantInterfaceDerivedArray = []; + covariantInterfaceBaseReadOnlySpan = covariantInterfaceDerivedReadOnlySpan; // ReadOnlySpan> -> ReadOnlySpan> + covariantInterfaceBaseReadOnlySpan = covariantInterfaceDerivedSpan; // Span> -> ReadOnlySpan> + covariantInterfaceBaseReadOnlySpan = covariantInterfaceDerivedArray; // CovariantInterface[] -> ReadOnlySpan> + + // Identify conversions to ReadOnlySpan + ReadOnlySpan stringReadOnlySpan; + stringReadOnlySpan = stringSpan; // Span -> ReadOnlySpan; + stringReadOnlySpan = stringArray; // string[] -> ReadOnlySpan; + + // Convert string to ReadOnlySpan + string s = ""; + ReadOnlySpan charReadOnlySpan = s; // string -> ReadOnlySpan + + // Use the non-covariant interfaces to show that no conversion is possible. + ReadOnlySpan> invariantInterfaceBaseReadOnlySpan; + ReadOnlySpan> invariantInterfaceDerivedReadOnlySpan; + Span> invariantInterfaceDerivedSpan; + InvariantInterface[] invariantInterfaceDerivedArray; + ReadOnlySpan> interfaceBaseReadOnlySpan; + ReadOnlySpan> interfaceDerivedReadOnlySpan; + Span> interfaceDerivedSpan; + Interface[] interfaceDerivedArray; + } +} diff --git a/csharp/ql/test/library-tests/conversion/span/span.expected b/csharp/ql/test/library-tests/conversion/span/span.expected new file mode 100644 index 00000000000..207fa0d7558 --- /dev/null +++ b/csharp/ql/test/library-tests/conversion/span/span.expected @@ -0,0 +1,16 @@ +| CovariantInterface[] | ReadOnlySpan> | +| CovariantInterface[] | ReadOnlySpan> | +| CovariantInterface[] | Span> | +| Interface[] | ReadOnlySpan> | +| Interface[] | Span> | +| InvariantInterface[] | ReadOnlySpan> | +| InvariantInterface[] | Span> | +| ReadOnlySpan> | ReadOnlySpan> | +| Span> | ReadOnlySpan> | +| Span> | ReadOnlySpan> | +| Span> | ReadOnlySpan> | +| Span> | ReadOnlySpan> | +| Span | ReadOnlySpan | +| String[] | ReadOnlySpan | +| String[] | Span | +| string | ReadOnlySpan | diff --git a/csharp/ql/test/library-tests/conversion/span/span.ql b/csharp/ql/test/library-tests/conversion/span/span.ql new file mode 100644 index 00000000000..63464937784 --- /dev/null +++ b/csharp/ql/test/library-tests/conversion/span/span.ql @@ -0,0 +1,9 @@ +import semmle.code.csharp.Conversion + +private class InterestingType extends Type { + InterestingType() { exists(LocalVariable lv | lv.getType() = this) } +} + +from InterestingType sub, InterestingType sup +where convSpan(sub, sup) and sub != sup +select sub.toStringWithTypes() as s1, sup.toStringWithTypes() as s2 order by s1, s2