Merge pull request #18 from mlemanczyk/codex/stworz-generator-kodu-zrodowego-w-c#

Mark version increments for source generation
This commit is contained in:
Marek Lemańczyk authored and GitHub committed 2025-07-14 21:34:13 +02:00
commit ed23fd7f69
7 files changed
+262 -10

No files matched your search

@@ -2,7 +2,8 @@
<PropertyGroup>
<TargetFrameworks>net8.0;net7.0;net6.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Nullable>enable</Nullable>
<DefineConstants>$(DefineConstants);WITH_VERSIONING</DefineConstants>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>Recyclable.Collections</PackageId>
<PackageVersion>0.0.6</PackageVersion>
@@ -30,8 +31,12 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="7.0.5" />
<PackageReference Include="morelinq" Version="3.4.2" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="7.0.5" />
<PackageReference Include="morelinq" Version="3.4.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VersionedCollectionsGenerator\VersionedCollectionsGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>
@@ -126,8 +126,9 @@ namespace Recyclable.Collections
list._count = currentItemsCount;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static void AddRange<T>(this RecyclableList<T> list, in Array items)
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
[VersionedCollectionsGenerator.RewriteForVersioned]
public static void AddRange<T>(this RecyclableList<T> list, in Array items)
{
if (list._capacity < list._count + items.Length)
{
@@ -136,7 +137,9 @@ namespace Recyclable.Collections
Array.Copy(items, items.GetLowerBound(0), list._memoryBlock, list._count, items.Length);
list._count += items.Length;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -149,7 +152,9 @@ namespace Recyclable.Collections
new ReadOnlySpan<T>(items).CopyTo(new Span<T>(list._memoryBlock, list._count, items.Length));
list._count += items.Length;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -162,7 +167,9 @@ namespace Recyclable.Collections
items.CopyTo(new Span<T>(list._memoryBlock, list._count, items.Length));
list._count += items.Length;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -175,7 +182,9 @@ namespace Recyclable.Collections
items.CopyTo(new Span<T>(list._memoryBlock, list._count, items.Length));
list._count += items.Length;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -188,7 +197,9 @@ namespace Recyclable.Collections
items.CopyTo(list._memoryBlock, list._count);
list._count += items.Count;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -201,7 +212,9 @@ namespace Recyclable.Collections
items.CopyTo(list._memoryBlock, list._count);
list._count += items.Count;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -214,7 +227,9 @@ namespace Recyclable.Collections
items.CopyTo(list._memoryBlock, list._count);
list._count += items.Count;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -227,7 +242,9 @@ namespace Recyclable.Collections
new ReadOnlySpan<T>(items._memoryBlock, 0, items._count).CopyTo(new Span<T>(list._memoryBlock, list._count, items._count));
list._count += items._count;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -278,7 +295,9 @@ namespace Recyclable.Collections
}
list._count = targetCapacity;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -309,7 +328,9 @@ namespace Recyclable.Collections
}
list._count = targetCapacity;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -349,7 +370,9 @@ namespace Recyclable.Collections
}
list._count = targetCapacity;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -372,7 +395,9 @@ namespace Recyclable.Collections
new ReadOnlySpan<T>(items._items, 0, sourceCount).CopyTo(new Span<T>(list._memoryBlock, oldCount, sourceCount));
list._count = targetCapacity;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -411,7 +436,9 @@ namespace Recyclable.Collections
}
list._count = targetCapacity;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -434,7 +461,9 @@ namespace Recyclable.Collections
new ReadOnlySpan<T>(items._heap, 0, sourceCount).CopyTo(new Span<T>(list._memoryBlock, oldCount, sourceCount));
list._count = targetCapacity;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -473,7 +502,9 @@ namespace Recyclable.Collections
}
list._count = targetCapacity;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -505,7 +536,9 @@ namespace Recyclable.Collections
}
list._count = targetCapacity;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -532,7 +565,9 @@ namespace Recyclable.Collections
}
list._count = targetCapacity;
#if WITH_VERSIONING
list._version++;
#endif
}
public static IEnumerator AddRange<T>(this RecyclableList<T> list, IEnumerable source, int growByCount = RecyclableDefaults.MinPooledArrayLength)
@@ -656,12 +691,16 @@ namespace Recyclable.Collections
else if (items.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity) && requiredAdditionalCapacity != 0)
{
AddRangeWithKnownCount(list, items, list._count, requiredAdditionalCapacity);
#if WITH_VERSIONING
list._version++;
#endif
}
else
{
AddRangeEnumerated(list, items, growByCount);
#if WITH_VERSIONING
list._version++;
#endif
}
}
}
@@ -79,7 +79,9 @@ namespace Recyclable.Collections
}
list._count += requiredAdditionalCapacity;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -94,7 +96,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
Array.Copy(items, items.GetLowerBound(0), memoryBlock, index, items.Length);
list._count += items.Length;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -109,7 +113,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
new ReadOnlySpan<T>(items).CopyTo(new Span<T>(memoryBlock, index, items.Length));
list._count += items.Length;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -124,7 +130,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
items.CopyTo(new Span<T>(memoryBlock, index, items.Length));
list._count += items.Length;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -139,7 +147,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
items.CopyTo(new Span<T>(memoryBlock, index, items.Length));
list._count += items.Length;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -154,7 +164,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
items.CopyTo(memoryBlock, index);
list._count += items.Count;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -169,7 +181,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
items.CopyTo(list._memoryBlock, index);
list._count += items.Count;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -184,7 +198,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
items.CopyTo(memoryBlock, index);
list._count += items.Count;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -199,7 +215,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
new ReadOnlySpan<T>(items._memoryBlock, 0, items._count).CopyTo(new(list._memoryBlock, index, items._count));
list._count += items._count;
#if WITH_VERSIONING
list._version++;
#endif
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -251,7 +269,9 @@ namespace Recyclable.Collections
}
list._count = targetCapacity;
#if WITH_VERSIONING
list._version++;
#endif
}
public static IEnumerator InsertRange<T>(this RecyclableList<T> list, int index, IEnumerable source, int growByCount = RecyclableDefaults.MinPooledArrayLength)
@@ -101,7 +101,9 @@ namespace Recyclable.Collections
}
list._count -= foundItemsCount;
#if WITH_VERSIONING
list._version++;
#endif
return foundItemsCount;
}
@@ -125,43 +127,57 @@ namespace Recyclable.Collections
}
list._count -= count;
#if WITH_VERSIONING
list._version++;
#endif
}
public static void Reverse<T>(this RecyclableList<T> list)
{
Array.Reverse(list._memoryBlock, 0, list._count);
#if WITH_VERSIONING
list._version++;
#endif
}
public static void Reverse<T>(this RecyclableList<T> list, int index, int count)
{
Array.Reverse(list._memoryBlock, index, count);
#if WITH_VERSIONING
list._version++;
#endif
}
public static void Sort<T>(this RecyclableList<T> list)
{
Array.Sort(list._memoryBlock, 0, list._count);
#if WITH_VERSIONING
list._version++;
#endif
}
public static void Sort<T>(this RecyclableList<T> list, Comparison<T> comparison)
{
Array.Sort(list._memoryBlock, 0, list._count, new ComparisonToComparerAdapter<T>(comparison));
#if WITH_VERSIONING
list._version++;
#endif
}
public static void Sort<T>(this RecyclableList<T> list, IComparer<T>? comparer)
{
Array.Sort(list._memoryBlock, 0, list._count, comparer);
#if WITH_VERSIONING
list._version++;
#endif
}
public static void Sort<T>(this RecyclableList<T> list, int index, int count, IComparer<T>? comparer)
{
Array.Sort(list._memoryBlock, index, count, comparer);
#if WITH_VERSIONING
list._version++;
#endif
}
public static T[] ToArray<T>(this RecyclableList<T> list)
+23 -3
View File
@@ -5,8 +5,9 @@ using Recyclable.Collections.Pools;
namespace Recyclable.Collections
{
[Serializable]
public sealed partial class RecyclableList<T> : IList<T>, IReadOnlyList<T>, IDisposable
[Serializable]
[VersionedCollectionsGenerator.GenerateVersioned]
public sealed partial class RecyclableList<T> : IList<T>, IReadOnlyList<T>, IDisposable
{
internal static readonly bool _needsClearing = !typeof(T).IsValueType;
@@ -17,7 +18,8 @@ namespace Recyclable.Collections
#nullable restore
internal ulong _version;
public ulong Version => _version;
[VersionedCollectionsGenerator.CloneForVersioned]
public ulong Version => _version;
public RecyclableList()
{
@@ -172,7 +174,9 @@ namespace Recyclable.Collections
set
{
_memoryBlock[index] = value;
#if WITH_VERSIONING
_version++;
#endif
}
}
@@ -185,7 +189,9 @@ namespace Recyclable.Collections
if (_capacity != value)
{
_capacity = RecyclableListHelpers<T>.EnsureCapacity(this, _count, checked((int)BitOperations.RoundUpToPowerOf2((uint)value)));
#if WITH_VERSIONING
_version++;
#endif
}
}
}
@@ -204,7 +210,9 @@ namespace Recyclable.Collections
}
_count = value;
#if WITH_VERSIONING
_version++;
#endif
}
}
}
@@ -243,7 +251,9 @@ namespace Recyclable.Collections
}
_memoryBlock[_count++] = item;
#if WITH_VERSIONING
_version++;
#endif
}
public T[] AsArray => _memoryBlock;
@@ -262,7 +272,9 @@ namespace Recyclable.Collections
}
_count = 0;
#if WITH_VERSIONING
_version++;
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -295,7 +307,9 @@ namespace Recyclable.Collections
_memoryBlock[index] = item;
_count++;
#if WITH_VERSIONING
_version++;
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
@@ -315,7 +329,9 @@ namespace Recyclable.Collections
_memoryBlock[_count] = default;
}
#if WITH_VERSIONING
_version++;
#endif
return true;
}
@@ -342,7 +358,9 @@ namespace Recyclable.Collections
_memoryBlock[_count] = default;
}
#if WITH_VERSIONING
_version++;
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -356,7 +374,9 @@ namespace Recyclable.Collections
public void Dispose()
{
#if WITH_VERSIONING
_version++;
#endif
if (_count != 0)
{
if (_needsClearing)
@@ -0,0 +1,133 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace VersionedCollectionsGenerator
{
[Generator]
public sealed class VersionedCollectionsGenerator : ISourceGenerator
{
private const string AttributeText = """
using System;
namespace VersionedCollectionsGenerator
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
internal sealed class GenerateVersionedAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
internal sealed class CloneForVersionedAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
internal sealed class RewriteForVersionedAttribute : Attribute
{
}
}
""";
public void Initialize(GeneratorInitializationContext context)
{
context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
context.AddSource("GenerateVersionedAttribute.g.cs", SourceText.From(AttributeText, Encoding.UTF8));
if (context.SyntaxReceiver is not SyntaxReceiver receiver)
{
return;
}
foreach (var candidate in receiver.Candidates)
{
var model = context.Compilation.GetSemanticModel(candidate.SyntaxTree);
var symbol = model.GetDeclaredSymbol(candidate) as INamedTypeSymbol;
if (symbol is null)
{
continue;
}
if (!symbol.GetAttributes().Any(a => a.AttributeClass?.ToDisplayString() == "VersionedCollectionsGenerator.GenerateVersionedAttribute"))
{
continue;
}
string originalName = symbol.Name;
string newName = $"{originalName}Versioned";
var partials = GetAllPartials(context.Compilation, originalName);
int index = 0;
foreach (var partial in partials)
{
var tree = partial.SyntaxTree;
var root = tree.GetRoot();
var rewriter = new RenameRewriter(originalName, newName);
var newRoot = rewriter.Visit(root);
var text = newRoot.ToFullString()
.Replace("#if WITH_VERSIONING", string.Empty)
.Replace("#endif", string.Empty);
context.AddSource($"{newName}_{index++}.g.cs", SourceText.From(text, Encoding.UTF8));
}
}
}
private static IEnumerable<ClassDeclarationSyntax> GetAllPartials(Compilation compilation, string className)
{
foreach (var tree in compilation.SyntaxTrees)
{
var root = tree.GetRoot();
foreach (var cls in root.DescendantNodes().OfType<ClassDeclarationSyntax>())
{
if (cls.Identifier.ValueText == className)
{
yield return cls;
}
}
}
}
private sealed class RenameRewriter : CSharpSyntaxRewriter
{
private readonly string _oldName;
private readonly string _newName;
public RenameRewriter(string oldName, string newName)
{
_oldName = oldName;
_newName = newName;
}
public override SyntaxToken VisitToken(SyntaxToken token)
{
if (token.ValueText == _oldName)
{
return SyntaxFactory.Identifier(token.LeadingTrivia, _newName, token.TrailingTrivia);
}
return base.VisitToken(token);
}
}
private sealed class SyntaxReceiver : ISyntaxReceiver
{
public List<ClassDeclarationSyntax> Candidates { get; } = new();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
if (syntaxNode is ClassDeclarationSyntax classDecl && classDecl.AttributeLists.Count > 0)
{
Candidates.Add(classDecl);
}
}
}
}
}
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net7.0;net6.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
<EnforceExtendedAnalyzerRules>True</EnforceExtendedAnalyzerRules>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
</ItemGroup>
</Project>