diff --git a/Source/AsyncGenerator.Core/Configuration/IFluentProjectTransformConfiguration.cs b/Source/AsyncGenerator.Core/Configuration/IFluentProjectTransformConfiguration.cs index ff600f3..03c40ef 100644 --- a/Source/AsyncGenerator.Core/Configuration/IFluentProjectTransformConfiguration.cs +++ b/Source/AsyncGenerator.Core/Configuration/IFluentProjectTransformConfiguration.cs @@ -2,6 +2,7 @@ using System.Runtime.CompilerServices; using System.Threading.Tasks; using AsyncGenerator.Core.Transformation; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace AsyncGenerator.Core.Configuration @@ -60,5 +61,11 @@ public interface IFluentProjectTransformConfiguration /// Add a callback to configure the preprocessor directives generation /// IFluentProjectTransformConfiguration PreprocessorDirectives(Action action); + + /// + /// Set a function that will decide what type of generation to apply for a given method. + /// Default is chosen for all methods. + /// + IFluentProjectTransformConfiguration MethodGeneration(Func func); } } diff --git a/Source/AsyncGenerator.Core/FileConfiguration/ConfigurationShema.xsd b/Source/AsyncGenerator.Core/FileConfiguration/ConfigurationShema.xsd index 256e15b..1d7cecc 100644 --- a/Source/AsyncGenerator.Core/FileConfiguration/ConfigurationShema.xsd +++ b/Source/AsyncGenerator.Core/FileConfiguration/ConfigurationShema.xsd @@ -11,6 +11,13 @@ + + + + + + + @@ -117,6 +124,14 @@ + + + + + + + + @@ -219,8 +234,13 @@ + + + + + - + @@ -228,7 +248,14 @@ - + + + + + + + + @@ -464,9 +491,15 @@ - + + + + + + + @@ -481,7 +514,7 @@ - + diff --git a/Source/AsyncGenerator.Core/FileConfiguration/FileConfiguration.cs b/Source/AsyncGenerator.Core/FileConfiguration/FileConfiguration.cs index b35ea82..a6a6310 100644 --- a/Source/AsyncGenerator.Core/FileConfiguration/FileConfiguration.cs +++ b/Source/AsyncGenerator.Core/FileConfiguration/FileConfiguration.cs @@ -207,6 +207,18 @@ public class MethodConversionFilter : MethodFilter public MethodConversion Conversion { get; set; } } + [Serializable] + [DebuggerStepThrough] + [DesignerCategory("code")] + [XmlType(Namespace = "https://github.com/maca88/AsyncGenerator")] + [XmlRoot("MethodGenerationFilter")] + [EditorBrowsable(EditorBrowsableState.Never)] + public class MethodGenerationFilter : MethodFilter + { + [XmlAttribute(AttributeName = "generation")] + public MethodGeneration Generation { get; set; } + } + [Serializable] [DebuggerStepThrough] [DesignerCategory("code")] @@ -233,6 +245,7 @@ public class MethodPredicateFilter : MethodFilter [XmlInclude(typeof(MethodCancellationTokenFilter))] [XmlInclude(typeof(MethodConversionFilter))] + [XmlInclude(typeof(MethodGenerationFilter))] [XmlInclude(typeof(MethodPredicateFilter))] [XmlInclude(typeof(AsyncReturnTypeFilter))] [Serializable] @@ -268,6 +281,7 @@ public string ReturnsVoidString [XmlInclude(typeof(MethodFilter))] [XmlInclude(typeof(MethodCancellationTokenFilter))] [XmlInclude(typeof(MethodConversionFilter))] + [XmlInclude(typeof(MethodGenerationFilter))] [XmlInclude(typeof(MethodPredicateFilter))] [XmlInclude(typeof(AsyncReturnTypeFilter))] [Serializable] @@ -462,6 +476,8 @@ public MethodRule() [EditorBrowsable(EditorBrowsableState.Never)] public class Transformation { + [XmlArrayItem("Method", IsNullable = false)] + public List MethodGeneration { get; set; } [XmlElement(IsNullable = true)] public bool? Disable { get; set; } [XmlElement("AsyncFolder")] @@ -479,6 +495,7 @@ public class Transformation public Transformation() { + MethodGeneration = new List(); AsyncLock = new TransformationAsyncLock(); DocumentationComments = new DocumentationComments(); PreprocessorDirectives = new PreprocessorDirectives(); diff --git a/Source/AsyncGenerator.Core/FileConfiguration/FileConfigurator.cs b/Source/AsyncGenerator.Core/FileConfiguration/FileConfigurator.cs index 9c8e3fb..dfc5c12 100644 --- a/Source/AsyncGenerator.Core/FileConfiguration/FileConfigurator.cs +++ b/Source/AsyncGenerator.Core/FileConfiguration/FileConfigurator.cs @@ -291,6 +291,10 @@ private static void Configure(AsyncGenerator configuration, CancellationTokens c private static void Configure(AsyncGenerator configuration, Transformation config, IFluentProjectTransformConfiguration fluentConfig) { + if (config.MethodGeneration.Any()) + { + fluentConfig.MethodGeneration(CreateMethodGenerationFunction(configuration, config.MethodGeneration)); + } if (config.LocalFunctions.HasValue) { fluentConfig.LocalFunctions(config.LocalFunctions.Value); @@ -566,6 +570,22 @@ private static Func CreateMethodConversionFunct }; } + private static Func CreateMethodGenerationFunction(AsyncGenerator globalConfig, IList filters) + { + var rules = globalConfig.MethodRules.ToDictionary(o => o.Name, o => o.Filters); + return symbol => + { + foreach (var filter in filters) + { + if (CanApply(symbol, filter, rules)) + { + return filter.Generation; + } + } + return MethodGeneration.Generate; // Default value + }; + } + private static Func CreateAsyncReturnTypeFunction(AsyncGenerator globalConfig, IList filters) { var rules = globalConfig.MethodRules.ToDictionary(o => o.Name, o => o.Filters); diff --git a/Source/AsyncGenerator.Core/MethodGeneration.cs b/Source/AsyncGenerator.Core/MethodGeneration.cs new file mode 100644 index 0000000..fc91888 --- /dev/null +++ b/Source/AsyncGenerator.Core/MethodGeneration.cs @@ -0,0 +1,14 @@ +namespace AsyncGenerator.Core +{ + public enum MethodGeneration + { + /// + /// The method will be generated + /// + Generate = 1, + /// + /// The method won't be generated + /// + Ignore = 2 + } +} diff --git a/Source/AsyncGenerator.Tests/AsyncGenerator.Tests.csproj b/Source/AsyncGenerator.Tests/AsyncGenerator.Tests.csproj index ed9fa14..0f98af6 100644 --- a/Source/AsyncGenerator.Tests/AsyncGenerator.Tests.csproj +++ b/Source/AsyncGenerator.Tests/AsyncGenerator.Tests.csproj @@ -25,7 +25,6 @@ - diff --git a/Source/AsyncGenerator.Tests/MethodGeneration/Fixture.cs b/Source/AsyncGenerator.Tests/MethodGeneration/Fixture.cs new file mode 100644 index 0000000..ebfafc0 --- /dev/null +++ b/Source/AsyncGenerator.Tests/MethodGeneration/Fixture.cs @@ -0,0 +1,84 @@ +using System.Threading.Tasks; +using AsyncGenerator.Core; +using AsyncGenerator.Core.Transformation; +using NUnit.Framework; +using AsyncGenerator.Tests.Cref.Input; + +namespace AsyncGenerator.Tests.MethodGeneration +{ + [TestFixture] + public class Fixture : BaseFixture + { + [Test] + public Task TestAfterTransformation() + { + return ReadonlyTest(p => p + .ConfigureAnalyzation(a => a + .MethodConversion(symbol => MethodConversion.Smart) + ) + .ConfigureTransformation(t => t + .MethodGeneration(m => m.Name == "Read" ? Core.MethodGeneration.Ignore : Core.MethodGeneration.Generate) + .AfterTransformation(ValidateDocument) + ) + ); + } + + [Test] + public Task TestYamlAfterTransformation() + { + return YamlReadonlyTest(nameof(TestCase), + @"projects: +- filePath: AsyncGenerator.Tests.csproj + analyzation: + methodConversion: + - conversion: Smart + all: true + transformation: + methodGeneration: + - generation: Ignore + name: Read +", + p => p + .ConfigureTransformation(t => t + .AfterTransformation(ValidateDocument)) + ); + } + + [Test] + public Task TestXmlAfterTransformation() + { + return XmlReadonlyTest(nameof(TestCase), + @" + + + + + + + + + + + + + + + + +", + p => p + .ConfigureTransformation(t => t + .AfterTransformation(ValidateDocument)) + ); + } + + private void ValidateDocument(IProjectTransformationResult result) + { + AssertValidAnnotations(result); + Assert.AreEqual(1, result.Documents.Count); + var document = result.Documents[0]; + Assert.NotNull(document.OriginalModified); + Assert.AreEqual(GetOutputFile(nameof(TestCase)), document.Transformed.ToFullString()); + } + } +} diff --git a/Source/AsyncGenerator.Tests/MethodGeneration/Input/TestCase.cs b/Source/AsyncGenerator.Tests/MethodGeneration/Input/TestCase.cs new file mode 100644 index 0000000..ae3306c --- /dev/null +++ b/Source/AsyncGenerator.Tests/MethodGeneration/Input/TestCase.cs @@ -0,0 +1,17 @@ +using AsyncGenerator.TestCases; + +namespace AsyncGenerator.Tests.MethodGeneration.Input +{ + public class TestCase + { + public void Read() + { + SimpleFile.Read(); + } + + public void Read2() + { + Read(); + } + } +} diff --git a/Source/AsyncGenerator.Tests/MethodGeneration/Output/TestCase.txt b/Source/AsyncGenerator.Tests/MethodGeneration/Output/TestCase.txt new file mode 100644 index 0000000..28ab4b9 --- /dev/null +++ b/Source/AsyncGenerator.Tests/MethodGeneration/Output/TestCase.txt @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using AsyncGenerator.TestCases; + +namespace AsyncGenerator.Tests.MethodGeneration.Input +{ + using System.Threading.Tasks; + public partial class TestCase + { + + public Task Read2Async() + { + return ReadAsync(); + } + } +} diff --git a/Source/AsyncGenerator/Configuration/Internal/ProjectTransformConfiguration.cs b/Source/AsyncGenerator/Configuration/Internal/ProjectTransformConfiguration.cs index a284a9d..8b86d65 100644 --- a/Source/AsyncGenerator/Configuration/Internal/ProjectTransformConfiguration.cs +++ b/Source/AsyncGenerator/Configuration/Internal/ProjectTransformConfiguration.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using AsyncGenerator.Core; using AsyncGenerator.Core.Configuration; using AsyncGenerator.Core.Plugins; using AsyncGenerator.Core.Transformation; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -11,6 +13,7 @@ namespace AsyncGenerator.Configuration.Internal internal class ProjectTransformConfiguration : IFluentProjectTransformConfiguration, IProjectTransformConfiguration { private readonly IProjectConfiguration _projectConfiguration; + private Func _methodGenerationFunction; public ProjectTransformConfiguration(IProjectConfiguration projectConfiguration) { @@ -49,6 +52,11 @@ public ProjectTransformConfiguration(IProjectConfiguration projectConfiguration) public List> AfterTransformation { get; } = new List>(); + public MethodGeneration GetMethodGeneration(IMethodSymbol methodSymbol) + { + return _methodGenerationFunction?.Invoke(methodSymbol) ?? MethodGeneration.Generate; + } + #region IFluentProjectTransformConfiguration IProjectDocumentationCommentConfiguration IProjectTransformConfiguration.DocumentationComments => DocumentationComments; @@ -133,6 +141,12 @@ IFluentProjectTransformConfiguration IFluentProjectTransformConfiguration.AfterT return this; } + IFluentProjectTransformConfiguration IFluentProjectTransformConfiguration.MethodGeneration(Func func) + { + _methodGenerationFunction = func ?? throw new ArgumentNullException(nameof(func)); + return this; + } + #endregion } diff --git a/Source/AsyncGenerator/Transformation/Internal/ProjectTransformer.Type.cs b/Source/AsyncGenerator/Transformation/Internal/ProjectTransformer.Type.cs index 67d5cde..e884f82 100644 --- a/Source/AsyncGenerator/Transformation/Internal/ProjectTransformer.Type.cs +++ b/Source/AsyncGenerator/Transformation/Internal/ProjectTransformer.Type.cs @@ -329,7 +329,9 @@ private TypeDeclarationSyntax TransformField(FieldTransformationResult fieldTran private TypeDeclarationSyntax TransformMethod(MethodTransformationResult methodTransform, TypeDeclarationSyntax newTypeNode, TypeTransformationResult transformResult, INamespaceTransformationMetadata namespaceMetadata, SyntaxTrivia memberWhitespace, bool onlyMissingMembers) { - if (methodTransform.AnalyzationResult.Conversion == MethodConversion.Ignore || (onlyMissingMembers && !methodTransform.AnalyzationResult.Missing)) + if (methodTransform.AnalyzationResult.Conversion == MethodConversion.Ignore || + (onlyMissingMembers && !methodTransform.AnalyzationResult.Missing) || + _configuration.GetMethodGeneration(methodTransform.AnalyzationResult.Symbol) == MethodGeneration.Ignore) { // We need to add a whitespace trivia to keep directives as they will not have any leading whitespace newTypeNode = newTypeNode.RemoveNodeKeepDirectives(methodTransform.Annotation, memberWhitespace, transformResult.EndOfLineTrivia);