Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<ItemGroup>
<PackageVersion Include="TimeWarp.SourceGenerators" Version="$(Version)" />
<PackageVersion Include="TimeWarp.SourceGenerators" Version="1.0.0-beta.6" />
<PackageVersion Include="FakeItEasy" Version="7.3.1" />
<PackageVersion Include="Fixie" Version="3.2.0" />
<PackageVersion Include="Fixie.TestAdapter" Version="3.3.0" />
Expand Down
59 changes: 59 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>
{
[Implements]
private readonly ILogger Logger;

[Implements]
private readonly IDataProcessor<string> Processor;

public DataService(ILogger logger, IDataProcessor<string> 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.
Expand Down
2 changes: 1 addition & 1 deletion source/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<!-- Default package metadata (can be overridden in individual projects) -->
<PropertyGroup Label="Package Metadata">
<Version>1.0.0-beta.5</Version>
<Version>1.0.0-beta.6</Version>
<Authors>Steven T. Cramer</Authors>
<Product>TimeWarp.SourceGenerators</Product>
<PackageId>TimeWarp.SourceGenerators</PackageId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// <auto-generated/>
#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<TimeWarp.SourceGenerators.TestConsole.LogEventArgs>? LogWritten
{
add => _logger.LogWritten += value;
remove => _logger.LogWritten -= value;
}

// Delegation to _processor for TimeWarp.SourceGenerators.TestConsole.IDataProcessor<string>
public bool Validate(string input)
{
return _processor.Validate(input);
}

}