Skip to content

Commit f43577b

Browse files
authored
Merge pull request #1450 from mavasani/ImmutableCollection
Do not flag RS0012 for ToImmutable invocations if the contents of the…
2 parents 7597eb5 + b71a93e commit f43577b

File tree

2 files changed

+43
-8
lines changed

2 files changed

+43
-8
lines changed

src/Microsoft.NetCore.Analyzers/Core/ImmutableCollections/DoNotCallToImmutableCollectionOnAnImmutableCollectionValue.cs

+11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.Collections.Immutable;
55
using System.Diagnostics;
6+
using System.Linq;
67
using Analyzer.Utilities;
78
using Analyzer.Utilities.Extensions;
89
using Microsoft.CodeAnalysis;
@@ -67,6 +68,16 @@ public override void Initialize(AnalysisContext context)
6768
}
6869

6970
Debug.Assert(!string.IsNullOrEmpty(metadataName));
71+
72+
// Do not flag invocations that take any explicit argument (comparer, converter, etc.)
73+
// as they can potentially modify the contents of the resulting collection.
74+
// See https://github.com/dotnet/roslyn/issues/23625 for language specific implementation below.
75+
var argumentsToSkip = targetMethod.IsExtensionMethod && invocation.Language != LanguageNames.VisualBasic ? 1 : 0;
76+
if (invocation.Arguments.Skip(argumentsToSkip).Any(arg => arg.ArgumentKind == ArgumentKind.Explicit))
77+
{
78+
return;
79+
}
80+
7081
var immutableCollectionType = compilation.GetTypeByMetadataName(metadataName);
7182
if (immutableCollectionType == null)
7283
{

src/Microsoft.NetCore.Analyzers/UnitTests/ImmutableCollections/DoNotCallToImmutableCollectionOnAnImmutableCollectionValueTests.cs

+32-8
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
3535

3636
#region No Diagnostic Tests
3737

38-
[Theory]
38+
[Theory, WorkItem(1432, "https://github.com/dotnet/roslyn-analyzers/issues/1432")]
3939
[MemberData(nameof(CollectionNames_Arity1))]
4040
public void NoDiagnosticCases_Arity1(string collectionName)
4141
{
@@ -50,15 +50,21 @@ static class Extensions
5050
{{
5151
return default({collectionName}<TSource>);
5252
}}
53+
54+
public static {collectionName}<TSource> To{collectionName}<TSource>(this IEnumerable<TSource> items, IEqualityComparer<TSource> comparer)
55+
{{
56+
return default({collectionName}<TSource>);
57+
}}
5358
}}
5459
5560
class C
5661
{{
57-
public void M(IEnumerable<int> p1, List<int> p2, {collectionName}<int> p3)
62+
public void M(IEnumerable<int> p1, List<int> p2, {collectionName}<int> p3, IEqualityComparer<int> comparer)
5863
{{
5964
// Allowed
6065
p1.To{collectionName}();
6166
p2.To{collectionName}();
67+
p3.To{collectionName}(comparer); // Potentially modifies the collection
6268
6369
// No dataflow
6470
IEnumerable<int> l1 = p3;
@@ -76,13 +82,19 @@ Module Extensions
7682
Public Function To{collectionName}(Of TSource)(items As IEnumerable(Of TSource)) As {collectionName}(Of TSource)
7783
Return Nothing
7884
End Function
85+
86+
<System.Runtime.CompilerServices.Extension> _
87+
Public Function To{collectionName}(Of TSource)(items As IEnumerable(Of TSource), comparer as IEqualityComparer(Of TSource)) As {collectionName}(Of TSource)
88+
Return Nothing
89+
End Function
7990
End Module
8091
8192
Class C
82-
Public Sub M(p1 As IEnumerable(Of Integer), p2 As List(Of Integer), p3 As {collectionName}(Of Integer))
93+
Public Sub M(p1 As IEnumerable(Of Integer), p2 As List(Of Integer), p3 As {collectionName}(Of Integer), comparer As IEqualityComparer(Of Integer))
8394
' Allowed
8495
p1.To{collectionName}()
8596
p2.To{collectionName}()
97+
p3.To{collectionName}(comparer) ' Potentially modifies the collection
8698
8799
' No dataflow
88100
Dim l1 As IEnumerable(Of Integer) = p3
@@ -92,7 +104,7 @@ End Class
92104
");
93105
}
94106

95-
[Theory]
107+
[Theory, WorkItem(1432, "https://github.com/dotnet/roslyn-analyzers/issues/1432")]
96108
[MemberData(nameof(CollectionNames_Arity2))]
97109
public void NoDiagnosticCases_Arity2(string collectionName)
98110
{
@@ -107,15 +119,21 @@ static class Extensions
107119
{{
108120
return default({collectionName}<TKey, TValue>);
109121
}}
122+
123+
public static {collectionName}<TKey, TValue> To{collectionName}<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> items, IEqualityComparer<TKey> keyComparer)
124+
{{
125+
return default({collectionName}<TKey, TValue>);
126+
}}
110127
}}
111128
112129
class C
113130
{{
114-
public void M(IEnumerable<KeyValuePair<int, int>> p1, List<KeyValuePair<int, int>> p2, {collectionName}<int, int> p3)
131+
public void M(IEnumerable<KeyValuePair<int, int>> p1, List<KeyValuePair<int, int>> p2, {collectionName}<int, int> p3, IEqualityComparer<int> keyComparer)
115132
{{
116133
// Allowed
117134
p1.To{collectionName}();
118135
p2.To{collectionName}();
136+
p3.To{collectionName}(keyComparer); // Potentially modifies the collection
119137
120138
// No dataflow
121139
IEnumerable<KeyValuePair<int, int>> l1 = p3;
@@ -133,13 +151,19 @@ Module Extensions
133151
Public Function To{collectionName}(Of TKey, TValue)(items As IEnumerable(Of KeyValuePair(Of TKey, TValue))) As {collectionName}(Of TKey, TValue)
134152
Return Nothing
135153
End Function
154+
155+
<System.Runtime.CompilerServices.Extension> _
156+
Public Function To{collectionName}(Of TKey, TValue)(items As IEnumerable(Of KeyValuePair(Of TKey, TValue)), keyComparer As IEqualityComparer(Of TKey)) As {collectionName}(Of TKey, TValue)
157+
Return Nothing
158+
End Function
136159
End Module
137160
138161
Class C
139-
Public Sub M(p1 As IEnumerable(Of KeyValuePair(Of Integer, Integer)), p2 As List(Of KeyValuePair(Of Integer, Integer)), p3 As {collectionName}(Of Integer, Integer))
162+
Public Sub M(p1 As IEnumerable(Of KeyValuePair(Of Integer, Integer)), p2 As List(Of KeyValuePair(Of Integer, Integer)), p3 As {collectionName}(Of Integer, Integer), keyComparer As IEqualityComparer(Of Integer))
140163
' Allowed
141164
p1.To{collectionName}()
142165
p2.To{collectionName}()
166+
p3.To{collectionName}(keyComparer) ' Potentially modifies the collection
143167
144168
' No dataflow
145169
Dim l1 As IEnumerable(Of KeyValuePair(Of Integer, Integer)) = p3
@@ -153,7 +177,7 @@ End Class
153177

154178
#region Diagnostic Tests
155179

156-
[Theory(Skip = "https://github.com/dotnet/roslyn-analyzers/issues/1318")]
180+
[Theory]
157181
[MemberData(nameof(CollectionNames_Arity1))]
158182
public void DiagnosticCases_Arity1(string collectionName)
159183
{
@@ -208,7 +232,7 @@ End Class
208232
GetBasicResultAt(15, 3, collectionName));
209233
}
210234

211-
[Theory(Skip = "https://github.com/dotnet/roslyn-analyzers/issues/1318")]
235+
[Theory]
212236
[MemberData(nameof(CollectionNames_Arity2))]
213237
public void DiagnosticCases_Arity2(string collectionName)
214238
{

0 commit comments

Comments
 (0)