diff --git a/csharp/ql/test/query-tests/Linq/MissedCastOpportunity/MissedCastOpportunity.cs b/csharp/ql/test/query-tests/Linq/MissedCastOpportunity/MissedCastOpportunity.cs new file mode 100644 index 00000000000..fe5617c228a --- /dev/null +++ b/csharp/ql/test/query-tests/Linq/MissedCastOpportunity/MissedCastOpportunity.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +class MissedCastOpportunity +{ + public void M1(List animals) + { + // BAD: Can be replaced with animals.Cast(). + foreach (Animal a in animals) + { + Dog d = (Dog)a; + d.Woof(); + } + } + + public void M2(NonEnumerableClass nec) + { + // GOOD: Not possible to use Linq here. + foreach (Animal a in nec) + { + Dog d = (Dog)a; + d.Woof(); + } + } + + public void M3(Animal[] animals) + { + // BAD: Can be replaced with animals.Cast(). + foreach (Animal animal in animals) + { + Dog d = (Dog)animal; + d.Woof(); + } + } + + public void M4(Array animals) + { + // BAD: Can be replaced with animals.Cast(). + foreach (Animal animal in animals) + { + Dog d = (Dog)animal; + d.Woof(); + } + } + + public void M5(IEnumerable animals) + { + // BAD: Can be replaced with animals.Cast(). + foreach (object animal in animals) + { + Dog d = (Dog)animal; + d.Woof(); + } + } + + public class NonEnumerableClass + { + public IEnumerator GetEnumerator() => throw null; + } + + public class Animal { } + + class Dog : Animal + { + private string name; + + public Dog(string name) + { + this.name = name; + } + + public void Woof() + { + Console.WriteLine("Woof! My name is " + name + "."); + } + } +} \ No newline at end of file diff --git a/csharp/ql/test/query-tests/Linq/MissedCastOpportunity/MissedCastOpportunity.expected b/csharp/ql/test/query-tests/Linq/MissedCastOpportunity/MissedCastOpportunity.expected new file mode 100644 index 00000000000..7e08d734acc --- /dev/null +++ b/csharp/ql/test/query-tests/Linq/MissedCastOpportunity/MissedCastOpportunity.expected @@ -0,0 +1,4 @@ +| MissedCastOpportunity.cs:10:9:14:9 | foreach (... ... in ...) ... | This foreach loop immediately $@ - consider casting the sequence explicitly using '.Cast(...)'. | MissedCastOpportunity.cs:12:13:12:27 | ... ...; | casts its iteration variable to another type | +| MissedCastOpportunity.cs:30:9:34:9 | foreach (... ... in ...) ... | This foreach loop immediately $@ - consider casting the sequence explicitly using '.Cast(...)'. | MissedCastOpportunity.cs:32:13:32:32 | ... ...; | casts its iteration variable to another type | +| MissedCastOpportunity.cs:40:9:44:9 | foreach (... ... in ...) ... | This foreach loop immediately $@ - consider casting the sequence explicitly using '.Cast(...)'. | MissedCastOpportunity.cs:42:13:42:32 | ... ...; | casts its iteration variable to another type | +| MissedCastOpportunity.cs:50:9:54:9 | foreach (... ... in ...) ... | This foreach loop immediately $@ - consider casting the sequence explicitly using '.Cast(...)'. | MissedCastOpportunity.cs:52:13:52:32 | ... ...; | casts its iteration variable to another type | diff --git a/csharp/ql/test/query-tests/Linq/MissedCastOpportunity/MissedCastOpportunity.qlref b/csharp/ql/test/query-tests/Linq/MissedCastOpportunity/MissedCastOpportunity.qlref new file mode 100644 index 00000000000..8d70f999503 --- /dev/null +++ b/csharp/ql/test/query-tests/Linq/MissedCastOpportunity/MissedCastOpportunity.qlref @@ -0,0 +1 @@ +Linq/MissedCastOpportunity.ql diff --git a/csharp/ql/test/query-tests/Linq/MissedCastOpportunity/options b/csharp/ql/test/query-tests/Linq/MissedCastOpportunity/options new file mode 100644 index 00000000000..75c39b4541b --- /dev/null +++ b/csharp/ql/test/query-tests/Linq/MissedCastOpportunity/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj diff --git a/csharp/ql/test/query-tests/Linq/MissedWhereOpportunity/MissedWhereOpportunity.cs b/csharp/ql/test/query-tests/Linq/MissedWhereOpportunity/MissedWhereOpportunity.cs new file mode 100644 index 00000000000..d1326c70ee2 --- /dev/null +++ b/csharp/ql/test/query-tests/Linq/MissedWhereOpportunity/MissedWhereOpportunity.cs @@ -0,0 +1,83 @@ +using System; +using System.Linq; +using System.Collections.Generic; + +class MissedWhereOpportunity +{ + public void M1(List lst) + { + // BAD: Can be replaced with lst.Where(e => e % 2 == 0) + foreach (int i in lst) + { + if (i % 2 != 0) + continue; + Console.WriteLine(i); + Console.WriteLine((i / 2)); + } + + // BAD: Can be replaced with lst.Where(e => e % 2 == 0) + foreach (int i in lst) + { + if (i % 2 == 0) + { + Console.WriteLine(i); + Console.WriteLine((i / 2)); + } + } + } + + public void M2(NonEnumerableClass nec) + { + // GOOD: Linq can't be used here. + foreach (int i in nec) + { + if (i % 2 == 0) + { + Console.WriteLine(i); + Console.WriteLine((i / 2)); + } + } + } + + public void M3(int[] arr) + { + // BAD: Can be replaced with arr.Where(e => e % 2 == 0) + foreach (var n in arr) + { + if (n % 2 == 0) + { + Console.WriteLine(n); + Console.WriteLine((n / 2)); + } + } + } + + public void M4(Array arr) + { + // GOOD: Linq can't be used here. + foreach (var element in arr) + { + if (element.GetHashCode() % 2 == 0) + { + Console.WriteLine(element); + } + } + } + + public void M5(IEnumerable elements) + { + // BAD: Can be replaced with elements.Where(e => e.GetHashCode() % 2 == 0) + foreach (var element in elements) + { + if (element.GetHashCode() % 2 == 0) + { + Console.WriteLine(element); + } + } + } + + public class NonEnumerableClass + { + public IEnumerator GetEnumerator() => throw null; + } +} diff --git a/csharp/ql/test/query-tests/Linq/MissedWhereOpportunity/MissedWhereOpportunity.expected b/csharp/ql/test/query-tests/Linq/MissedWhereOpportunity/MissedWhereOpportunity.expected new file mode 100644 index 00000000000..5efde9aebed --- /dev/null +++ b/csharp/ql/test/query-tests/Linq/MissedWhereOpportunity/MissedWhereOpportunity.expected @@ -0,0 +1,4 @@ +| MissedWhereOpportunity.cs:10:9:16:9 | foreach (... ... in ...) ... | This foreach loop $@ - consider filtering the sequence explicitly using '.Where(...)'. | MissedWhereOpportunity.cs:12:17:12:26 | ... != ... | implicitly filters its target sequence | +| MissedWhereOpportunity.cs:19:9:26:9 | foreach (... ... in ...) ... | This foreach loop $@ - consider filtering the sequence explicitly using '.Where(...)'. | MissedWhereOpportunity.cs:21:17:21:26 | ... == ... | implicitly filters its target sequence | +| MissedWhereOpportunity.cs:45:9:52:9 | foreach (... ... in ...) ... | This foreach loop $@ - consider filtering the sequence explicitly using '.Where(...)'. | MissedWhereOpportunity.cs:47:17:47:26 | ... == ... | implicitly filters its target sequence | +| MissedWhereOpportunity.cs:70:9:76:9 | foreach (... ... in ...) ... | This foreach loop $@ - consider filtering the sequence explicitly using '.Where(...)'. | MissedWhereOpportunity.cs:72:17:72:46 | ... == ... | implicitly filters its target sequence | diff --git a/csharp/ql/test/query-tests/Linq/MissedWhereOpportunity/MissedWhereOpportunity.qlref b/csharp/ql/test/query-tests/Linq/MissedWhereOpportunity/MissedWhereOpportunity.qlref new file mode 100644 index 00000000000..4a08b459a6c --- /dev/null +++ b/csharp/ql/test/query-tests/Linq/MissedWhereOpportunity/MissedWhereOpportunity.qlref @@ -0,0 +1 @@ +Linq/MissedWhereOpportunity.ql diff --git a/csharp/ql/test/query-tests/Linq/MissedWhereOpportunity/options b/csharp/ql/test/query-tests/Linq/MissedWhereOpportunity/options new file mode 100644 index 00000000000..75c39b4541b --- /dev/null +++ b/csharp/ql/test/query-tests/Linq/MissedWhereOpportunity/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj