diff --git a/Directory.Packages.props b/Directory.Packages.props index d7363a6..1e37705 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,6 +1,6 @@ - + diff --git a/readme.md b/readme.md index b343b89..3ac3e76 100644 --- a/readme.md +++ b/readme.md @@ -22,6 +22,65 @@ TimeWarp.SourceGenerators is our collection of source generators. If you like or are using this project please give it a star. Thank you! +## Features + +### Interface Delegation Generator + +Implements Delphi-style interface delegation for C#. Mark fields or properties with `[Implements]` to automatically generate forwarding methods for interface members. + +#### Usage + +```csharp +public partial class DataService : ILogger, IDataProcessor +{ + [Implements] + private readonly ILogger Logger; + + [Implements] + private readonly IDataProcessor Processor; + + public DataService(ILogger logger, IDataProcessor processor) + { + Logger = logger; + Processor = processor; + } + + // Optionally override specific methods + public string Process(string input) + { + // Custom implementation + return Processor.Process(input.ToUpper()); + } +} +``` + +The generator will automatically create forwarding implementations for all interface methods and properties, except those you explicitly implement. + +#### Requirements + +- Class must be marked as `partial` +- Class must implement the interface being delegated +- Field/property type must be the interface or implement the interface + +#### Diagnostics + +- **TW1001**: Class must be partial for interface delegation +- **TW1002**: Class does not implement the delegated interface +- **TW1003**: Multiple fields delegate the same interface + +### File Name Rule Analyzer + +Enforces kebab-case naming convention for C# files. + +#### Configuration + +Configure exceptions in `.editorconfig`: + +```ini +[*.cs] +dotnet_diagnostic.TWA001.excluded_files = Program.cs;Startup.cs;*.Designer.cs +``` + ## Getting started To quickly get started I recommend reviewing the samples in this repo. diff --git a/source/Directory.Build.props b/source/Directory.Build.props index e694002..93c8893 100644 --- a/source/Directory.Build.props +++ b/source/Directory.Build.props @@ -4,7 +4,7 @@ - 1.0.0-beta.5 + 1.0.0-beta.6 Steven T. Cramer TimeWarp.SourceGenerators TimeWarp.SourceGenerators diff --git a/source/timewarp-source-generators/interface-delegation-generator.cs b/source/timewarp-source-generators/interface-delegation-generator.cs index ee65410..1c54c17 100644 --- a/source/timewarp-source-generators/interface-delegation-generator.cs +++ b/source/timewarp-source-generators/interface-delegation-generator.cs @@ -320,13 +320,30 @@ private static string GeneratePropertyDelegation(IPropertySymbol property, strin string propertyType = property.Type.ToDisplayString(); string propertyName = property.Name; - string getter = property.GetMethod != null ? $" get => {delegateMemberName}.{propertyName};" : ""; - string setter = property.SetMethod != null ? $" set => {delegateMemberName}.{propertyName} = value;" : ""; + // Check if this is an indexer + if (property.IsIndexer) + { + string parameters = string.Join(", ", property.Parameters.Select(p => + $"{p.Type.ToDisplayString()} {p.Name}")); + string arguments = string.Join(", ", property.Parameters.Select(p => p.Name)); - return $@" public {propertyType} {propertyName} + string getter = property.GetMethod != null ? $" get => {delegateMemberName}[{arguments}];" : ""; + string setter = property.SetMethod != null ? $" set => {delegateMemberName}[{arguments}] = value;" : ""; + + return $@" public {propertyType} this[{parameters}] {{ {getter}{setter} }}"; + } + + // Regular property + string regularGetter = property.GetMethod != null ? $" get => {delegateMemberName}.{propertyName};" : ""; + string regularSetter = property.SetMethod != null ? $" set => {delegateMemberName}.{propertyName} = value;" : ""; + + return $@" public {propertyType} {propertyName} + {{ +{regularGetter}{regularSetter} + }}"; } private static string GenerateEventDelegation(IEventSymbol eventSymbol, string delegateMemberName) diff --git a/tests/timewarp-source-generators-test-console/generated/timewarp-source-generators/TimeWarp.SourceGenerators.InterfaceDelegationGenerator/DataService.implements.g.cs b/tests/timewarp-source-generators-test-console/generated/timewarp-source-generators/TimeWarp.SourceGenerators.InterfaceDelegationGenerator/DataService.implements.g.cs new file mode 100644 index 0000000..1a4e45f --- /dev/null +++ b/tests/timewarp-source-generators-test-console/generated/timewarp-source-generators/TimeWarp.SourceGenerators.InterfaceDelegationGenerator/DataService.implements.g.cs @@ -0,0 +1,37 @@ +// +#nullable enable + +namespace TimeWarp.SourceGenerators.TestConsole; + +// Interface delegation for DataService +public partial class DataService +{ + // Delegation to _logger for TimeWarp.SourceGenerators.TestConsole.ILogger + public void Log(string message) + { + _logger.Log(message); + } + + public void LogError(string message, System.Exception exception) + { + _logger.LogError(message, exception); + } + + public TimeWarp.SourceGenerators.TestConsole.LogLevel MinimumLevel + { + get => _logger.MinimumLevel; set => _logger.MinimumLevel = value; + } + + public event System.EventHandler? LogWritten + { + add => _logger.LogWritten += value; + remove => _logger.LogWritten -= value; + } + + // Delegation to _processor for TimeWarp.SourceGenerators.TestConsole.IDataProcessor + public bool Validate(string input) + { + return _processor.Validate(input); + } + +}