Skip to content

Commit d9be3b7

Browse files
committed
Added IgnoreAsyncCounterparts option for ignoring found async counterparts, fixes #73
1 parent f7deb40 commit d9be3b7

File tree

13 files changed

+261
-4
lines changed

13 files changed

+261
-4
lines changed

Source/AsyncGenerator.Core/Configuration/IFluentProjectAnalyzeConfiguration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ public interface IFluentProjectAnalyzeConfiguration
3838
/// </summary>
3939
IFluentProjectAnalyzeConfiguration FindAsyncCounterparts(Func<IMethodSymbol, ITypeSymbol, AsyncCounterpartsSearchOptions, IEnumerable<IMethodSymbol>> func);
4040

41+
/// <summary>
42+
/// Append a predicate that will decide if the found async counterparts can be used or not.
43+
/// <para>Default all found async counterparts will be used.</para>
44+
/// </summary>
45+
IFluentProjectAnalyzeConfiguration IgnoreAsyncCounterparts(Predicate<IMethodSymbol> predicate);
46+
4147
/// <summary>
4248
/// Append a predicate that will check if the given statement is a precondition
4349
/// </summary>

Source/AsyncGenerator.Core/FileConfiguration/ConfigurationShema.xsd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,13 @@
230230
</xs:sequence>
231231
</xs:complexType>
232232
</xs:element>
233+
<xs:element name="IgnoreAsyncCounterparts" minOccurs="0">
234+
<xs:complexType>
235+
<xs:sequence>
236+
<xs:element name="Method" type="MethodFilter" maxOccurs="unbounded" minOccurs="0"/>
237+
</xs:sequence>
238+
</xs:complexType>
239+
</xs:element>
233240
<xs:element name="IgnoreSearchForMethodReferences" minOccurs="0">
234241
<xs:complexType>
235242
<xs:sequence>

Source/AsyncGenerator.Core/FileConfiguration/FileConfiguration.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ public class Analyzation
145145
[XmlArrayItem("Method", IsNullable = false)]
146146
public List<MethodFilter> IgnoreSearchForAsyncCounterparts { get; set; }
147147
[XmlArrayItem("Method", IsNullable = false)]
148+
public List<MethodFilter> IgnoreAsyncCounterparts { get; set; }
149+
[XmlArrayItem("Method", IsNullable = false)]
148150
public List<MethodFilter> IgnoreSearchForMethodReferences { get; set; }
149151
[XmlElement(IsNullable = true)]
150152
public bool? CallForwarding { get; set; }
@@ -162,6 +164,7 @@ public Analyzation()
162164
AsyncExtensionMethods = new AsyncExtensionMethods();
163165
CancellationTokens = new CancellationTokens();
164166
IgnoreSearchForAsyncCounterparts = new List<MethodFilter>();
167+
IgnoreAsyncCounterparts = new List<MethodFilter>();
165168
IgnoreSearchForMethodReferences = new List<MethodFilter>();
166169
IgnoreDocuments = new List<DocumentFilter>();
167170
TypeConversion = new List<TypeConversionFilter>();
@@ -217,8 +220,22 @@ public class MemberFilter
217220
public string HasAttribute { get; set; }
218221
[XmlAttribute(AttributeName = "hasAttributeName")]
219222
public string HasAttributeName { get; set; }
223+
224+
public bool? HasDocumentationComment
225+
{
226+
get
227+
{
228+
if (bool.TryParse(HasDocumentationCommentString, out var value))
229+
{
230+
return value;
231+
}
232+
return null;
233+
}
234+
set => HasDocumentationCommentString = value?.ToString();
235+
}
236+
220237
[XmlAttribute(AttributeName = "hasDocumentationComment")]
221-
public bool? HasDocumentationComment { get; set; }
238+
internal string HasDocumentationCommentString { get; set; }
222239
[XmlAttribute(AttributeName = "containingNamespace")]
223240
public string ContainingNamespace { get; set; }
224241
[XmlAttribute(AttributeName = "containingType")]

Source/AsyncGenerator.Core/FileConfiguration/FileConfigurator.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ private static void Configure(AsyncGenerator configuration, Analyzation config,
130130
{
131131
fluentConfig.SearchForAsyncCounterparts(CreateMethodPredicate(configuration, config.IgnoreSearchForAsyncCounterparts, false));
132132
}
133+
if (config.IgnoreAsyncCounterparts.Any())
134+
{
135+
fluentConfig.IgnoreAsyncCounterparts(CreateMethodPredicate(configuration, config.IgnoreAsyncCounterparts, true));
136+
}
133137
if (config.IgnoreSearchForMethodReferences.Any())
134138
{
135139
fluentConfig.SearchForMethodReferences(CreateMethodPredicate(configuration, config.IgnoreSearchForMethodReferences, false));

Source/AsyncGenerator.Tests/AsyncGenerator.Tests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@
210210
<Compile Include="DocumentationComments\Input\MissingMembers.cs" />
211211
<Compile Include="DocumentationComments\Input\Comments.cs" />
212212
<Compile Include="DocumentationComments\CommentsFixture.cs" />
213+
<Compile Include="IgnoreAsyncCounterparts\Fixture.cs" />
214+
<Compile Include="IgnoreAsyncCounterparts\Input\TestCase.cs" />
213215
<Compile Include="ParallelFor\Fixture.cs" />
214216
<Compile Include="CustomReturnType\Input\SameType.cs" />
215217
<Compile Include="ParallelFor\Input\NoLinq.cs" />
@@ -414,6 +416,7 @@
414416
<Folder Include="ArrowFunctions\" />
415417
<Folder Include="CastOmitAsync\Output\" />
416418
<Folder Include="CustomReturnType\Output\" />
419+
<Folder Include="IgnoreAsyncCounterparts\Output\" />
417420
<Folder Include="LocalFunctions\Output\" />
418421
<Folder Include="MethodAsArgument\Output\" />
419422
<Folder Include="OverloadWithDifferentParameters\Output\" />

Source/AsyncGenerator.Tests/BaseFixture.cs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
using System.Threading.Tasks;
1212
using AsyncGenerator.Analyzation;
1313
using AsyncGenerator.Configuration;
14+
using AsyncGenerator.Configuration.Yaml;
1415
using AsyncGenerator.Core;
1516
using AsyncGenerator.Core.Analyzation;
1617
using AsyncGenerator.Core.Configuration;
18+
using AsyncGenerator.Core.FileConfiguration;
1719
using AsyncGenerator.Core.Transformation;
1820
using AsyncGenerator.Internal;
1921
using AsyncGenerator.Transformation;
@@ -64,6 +66,20 @@ public async Task ReadonlyTest(string fileName, Action<IFluentProjectConfigurati
6466
await AsyncCodeGenerator.GenerateProject(project).ConfigureAwait(false);
6567
}
6668

69+
public async Task YamlReadonlyTest(string yamlConfig, Action<IFluentProjectConfiguration> action = null)
70+
{
71+
var configuration = ConfigureByYaml(yamlConfig, action).ProjectConfigurations.Single();
72+
var projectData = AsyncCodeGenerator.CreateProjectData(ReadonlyProject.Value, configuration);
73+
await AsyncCodeGenerator.GenerateProject(projectData).ConfigureAwait(false);
74+
}
75+
76+
public async Task XmlReadonlyTest(string xmlConfig, Action<IFluentProjectConfiguration> action = null)
77+
{
78+
var configuration = ConfigureByXml(xmlConfig, action).ProjectConfigurations.Single();
79+
var projectData = AsyncCodeGenerator.CreateProjectData(ReadonlyProject.Value, configuration);
80+
await AsyncCodeGenerator.GenerateProject(projectData).ConfigureAwait(false);
81+
}
82+
6783
public AsyncCodeConfiguration Configure(Action<IFluentProjectConfiguration> action = null)
6884
{
6985
var filePath = Path.GetFullPath(Path.Combine(GetBaseDirectory(), "..", "..", "AsyncGenerator.Tests.csproj"));
@@ -79,6 +95,18 @@ public AsyncCodeConfiguration Configure(Action<IFluentProjectConfiguration> acti
7995
;
8096
}
8197

98+
public AsyncCodeConfiguration ConfigureByYaml(string yamlConfig, Action<IFluentProjectConfiguration> action = null)
99+
{
100+
return AsyncCodeConfiguration.Create()
101+
.ConfigureFromStream(GenerateStreamFromString(yamlConfig), new TestProjectYamlFileConfigurator(InputFolderPath, action));
102+
}
103+
104+
public AsyncCodeConfiguration ConfigureByXml(string xmlConfig, Action<IFluentProjectConfiguration> action = null)
105+
{
106+
return AsyncCodeConfiguration.Create()
107+
.ConfigureFromStream(GenerateStreamFromString(xmlConfig), new TestProjectXmlFileConfigurator(InputFolderPath, action));
108+
}
109+
82110
public AsyncCodeConfiguration Configure(string fileName, Action<IFluentProjectConfiguration> action = null)
83111
{
84112
var slnFilePath = Path.GetFullPath(Path.Combine(GetBaseDirectory(), "..", "..", "..", "AsyncGenerator.sln"));
@@ -201,6 +229,67 @@ private static Microsoft.CodeAnalysis.Solution OpenSolution()
201229
var workspace = AsyncCodeGenerator.CreateWorkspace();
202230
return AsyncCodeGenerator.OpenSolution(workspace, filePath, ImmutableArray<Predicate<string>>.Empty).GetAwaiter().GetResult();
203231
}
232+
233+
private static Stream GenerateStreamFromString(string value)
234+
{
235+
return new MemoryStream(Encoding.UTF8.GetBytes(value ?? ""));
236+
}
237+
238+
private class TestProjectYamlFileConfigurator : TestProjectFileConfigurator
239+
{
240+
public TestProjectYamlFileConfigurator(string inputFolderPath, Action<IFluentProjectConfiguration> configureProjectAction)
241+
: base(new YamlFileConfigurator(), inputFolderPath, configureProjectAction)
242+
{
243+
}
244+
}
245+
246+
private class TestProjectXmlFileConfigurator : TestProjectFileConfigurator
247+
{
248+
public TestProjectXmlFileConfigurator(string inputFolderPath, Action<IFluentProjectConfiguration> configureProjectAction)
249+
: base(new XmlFileConfigurator(), inputFolderPath, configureProjectAction)
250+
{
251+
}
252+
}
253+
254+
private abstract class TestProjectFileConfigurator : IFileConfigurator
255+
{
256+
private readonly string _inputFolderPath;
257+
private readonly Action<IFluentProjectConfiguration> _configureProjectAction;
258+
private readonly IFileConfigurator _realConfigurator;
259+
260+
protected TestProjectFileConfigurator(IFileConfigurator realConfigurator, string inputFolderPath, Action<IFluentProjectConfiguration> configureProjectAction)
261+
{
262+
_inputFolderPath = inputFolderPath;
263+
_configureProjectAction = configureProjectAction;
264+
_realConfigurator = realConfigurator;
265+
}
266+
267+
public virtual Core.FileConfiguration.AsyncGenerator Parse(string content)
268+
{
269+
var config = _realConfigurator.Parse(content);
270+
foreach (var testProject in config.Projects.Where(o => o.FilePath == "AsyncGenerator.Tests.csproj"))
271+
{
272+
testProject.FilePath = Path.GetFullPath(Path.Combine(GetBaseDirectory(), "..", "..", "AsyncGenerator.Tests.csproj"));
273+
}
274+
return config;
275+
}
276+
277+
public void Configure(Core.FileConfiguration.AsyncGenerator configuration, Solution solution, IFluentSolutionConfiguration solutionConfiguration,
278+
Assembly assembly)
279+
{
280+
_realConfigurator.Configure(configuration, solution, solutionConfiguration, assembly);
281+
}
282+
283+
public virtual void Configure(Core.FileConfiguration.AsyncGenerator configuration, Project project, IFluentProjectConfiguration projectConfiguration,
284+
Assembly assembly)
285+
{
286+
_realConfigurator.Configure(configuration, project, projectConfiguration, assembly);
287+
projectConfiguration.ConfigureAnalyzation(a => a
288+
.DocumentSelection(o => string.Join("/", o.Folders) == _inputFolderPath)
289+
);
290+
_configureProjectAction?.Invoke(projectConfiguration);
291+
}
292+
}
204293
}
205294

206295
public abstract class BaseFixture<T> : BaseFixture

Source/AsyncGenerator.Tests/Formatting/Input/Async.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ public void Test()
3434
});
3535

3636
#pragma warning disable CS0168 // Variable is declared but never used
37+
#pragma warning disable CS8321 // Local function is declared but never used
3738
void LocalDoubleRead()
39+
#pragma warning restore CS8321 // Local function is declared but never used
3840
#pragma warning restore CS0168 // Variable is declared but never used
3941
{
4042
SimpleFile.Read();

Source/AsyncGenerator.Tests/Formatting/Output/Async.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ namespace AsyncGenerator.Tests.Formatting.Input
4444
});
4545

4646
#pragma warning disable CS0168 // Variable is declared but never used
47+
#pragma warning disable CS8321 // Local function is declared but never used
4748
async void LocalDoubleRead()
49+
#pragma warning restore CS8321 // Local function is declared but never used
4850
#pragma warning restore CS0168 // Variable is declared but never used
4951
{
5052
await (SimpleFile.ReadAsync());
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
using System;
2+
using System.Linq;
3+
using System.Threading.Tasks;
4+
using AsyncGenerator.Analyzation;
5+
using AsyncGenerator.Core;
6+
using Microsoft.CodeAnalysis;
7+
using Microsoft.CodeAnalysis.CSharp.Syntax;
8+
using NUnit.Framework;
9+
using AsyncGenerator.Tests.IgnoreAsyncCounterparts.Input;
10+
11+
namespace AsyncGenerator.Tests.IgnoreAsyncCounterparts
12+
{
13+
[TestFixture]
14+
public class Fixture : BaseFixture<TestCase>
15+
{
16+
[Test]
17+
public Task TestAfterTransformation()
18+
{
19+
return ReadonlyTest(p => p
20+
.ConfigureAnalyzation(a => a
21+
.MethodConversion(symbol => MethodConversion.Smart)
22+
.IgnoreAsyncCounterparts(symbol => symbol.Name == "ReadAsync")
23+
)
24+
.ConfigureTransformation(t => t
25+
.AfterTransformation(result =>
26+
{
27+
Assert.AreEqual(0, result.Documents.Count);
28+
})
29+
)
30+
);
31+
}
32+
33+
[Test]
34+
public Task TestYamlAfterTransformation()
35+
{
36+
return YamlReadonlyTest(
37+
@"projects:
38+
- filePath: AsyncGenerator.Tests.csproj
39+
analyzation:
40+
methodConversion:
41+
- conversion: Smart
42+
all: true
43+
ignoreAsyncCounterparts:
44+
- name: ReadAsync
45+
",
46+
p => p
47+
.ConfigureTransformation(t => t
48+
.AfterTransformation(result =>
49+
{
50+
Assert.AreEqual(0, result.Documents.Count);
51+
})
52+
)
53+
);
54+
}
55+
56+
[Test]
57+
public Task TestXmlAfterTransformation()
58+
{
59+
return XmlReadonlyTest(
60+
@"
61+
<AsyncGenerator xmlns=""https://github.com/maca88/AsyncGenerator"">
62+
<Projects>
63+
<Project filePath=""AsyncGenerator.Tests.csproj"">
64+
<Analyzation>
65+
<MethodConversion>
66+
<Method conversion=""Smart"" all=""true"" />
67+
</MethodConversion>
68+
<IgnoreAsyncCounterparts>
69+
<Method name=""ReadAsync"" />
70+
</IgnoreAsyncCounterparts>
71+
</Analyzation>
72+
</Project>
73+
</Projects>
74+
</AsyncGenerator>
75+
",
76+
p => p
77+
.ConfigureTransformation(t => t
78+
.AfterTransformation(result =>
79+
{
80+
Assert.AreEqual(0, result.Documents.Count);
81+
})
82+
)
83+
);
84+
}
85+
}
86+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using AsyncGenerator.TestCases;
7+
8+
namespace AsyncGenerator.Tests.IgnoreAsyncCounterparts.Input
9+
{
10+
public class TestCase
11+
{
12+
public void Test()
13+
{
14+
Read();
15+
SimpleFile.Read();
16+
}
17+
18+
public void Read()
19+
{
20+
SimpleFile.Read();
21+
}
22+
23+
public Task ReadAsync()
24+
{
25+
return SimpleFile.ReadAsync();
26+
}
27+
}
28+
}

Source/AsyncGenerator/Analyzation/Internal/ProjectAnalyzer.Analyze.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,8 @@ private void FindAsyncCounterparts(BodyFunctionDataReference functionReferenceDa
667667
searchOptions |= AsyncCounterpartsSearchOptions.HasCancellationToken;
668668
}
669669
functionReferenceData.ReferenceAsyncSymbols = new HashSet<IMethodSymbol>(GetAsyncCounterparts(methodSymbol.OriginalDefinition,
670-
functionReferenceData.InvokedFromType, searchOptions));
670+
functionReferenceData.InvokedFromType, searchOptions)
671+
.Where(o => _configuration.IgnoreAsyncCounterpartsPredicates.All(p => !p(o))));
671672
}
672673

673674
private bool SetAsyncCounterpart(BodyFunctionDataReference functionReferenceData)

Source/AsyncGenerator/Configuration/AsyncCodeConfiguration.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public AsyncCodeConfiguration ConfigureProject(string projectFilePath, Action<IF
8080
return ConfigureFromStream(stream, new T(), basePath);
8181
}
8282

83-
private AsyncCodeConfiguration ConfigureFromFile(string filePath, IFileConfigurator fileConfigurator)
83+
internal AsyncCodeConfiguration ConfigureFromFile(string filePath, IFileConfigurator fileConfigurator)
8484
{
8585
if (filePath == null)
8686
{
@@ -95,7 +95,7 @@ private AsyncCodeConfiguration ConfigureFromFile(string filePath, IFileConfigura
9595
return ConfigureFromStream(File.OpenRead(filePath), fileConfigurator, Path.GetDirectoryName(filePath));
9696
}
9797

98-
private AsyncCodeConfiguration ConfigureFromStream(Stream stream, IFileConfigurator fileConfigurator, string basePath = null)
98+
internal AsyncCodeConfiguration ConfigureFromStream(Stream stream, IFileConfigurator fileConfigurator, string basePath = null)
9999
{
100100
if (stream == null)
101101
{

0 commit comments

Comments
 (0)