Skip to content

Commit cfc8580

Browse files
committed
Generate auto-generated comments. Lots of docs
1 parent 15d2889 commit cfc8580

25 files changed

+902
-219
lines changed

.github/copilot-instructions.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Internal Agent Instructions
2+
3+
Purpose: Helper source files (embedded) for .NET incremental generators; keep output deterministic and public API stable.
4+
5+
## 1. Scope
6+
Chat = terse (summary + reason + minimal diff). Repo docs = rich (rationale, examples, edge cases, perf). Additive edits only.
7+
8+
## 2. Platform & Stability
9+
netstandard2.0 / C# 7.3. No newer BCL APIs. Preserve public type & member names.
10+
11+
## 3. Guards
12+
Each helper file:
13+
```
14+
#if !DATACUTE_EXCLUDE_<UPPERCASENAME>
15+
// contents
16+
#endif
17+
```
18+
Nest or document dependencies.
19+
20+
## 4. Editing & Diffs
21+
Show only changed lines (≤3 lines context). Fenced blocks for multi‑line examples. Short reason (perf / determinism / clarity / bug fix). No change‑log comments. UK English.
22+
23+
## 5. Documentation
24+
XML doc first sentence = summary; follow with behaviour / perf / pitfalls if useful. READMEs may include: Overview, Why, Key APIs, Examples, Performance, Dependencies, Exclusion Flags, Instrumentation. Document public surface only (internal/private only if cross‑file contract). Chat brevity does not apply to repo docs.
25+
26+
## 6. Chat Response Format
27+
1. Summary (1–2 lines) 2. Diff (changed lines) OR fenced example 3. Optional next steps (label “Optional”).
28+
29+
## 7. Assumptions
30+
If unspecified, state one reversible assumption and proceed.

IncrementalGeneratorExtensions.Content/Datacute/IncrementalGeneratorExtensions/AttributeContextAndData.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
// <auto-generated>
2-
// This file is part of the Datacute.IncrementalGeneratorExtensions package.
3-
// It is included as a source file and should not be modified.
4-
// </auto-generated>
5-
6-
#if !DATACUTE_EXCLUDE_ATTRIBUTECONTEXTANDDATA && !DATACUTE_EXCLUDE_TYPECONTEXT
1+
#if !DATACUTE_EXCLUDE_ATTRIBUTECONTEXTANDDATA // Feature: AttributeContextAndData
2+
#if DATACUTE_EXCLUDE_TYPECONTEXT
3+
#error AttributeContextAndData requires TypeContext (remove DATACUTE_EXCLUDE_TYPECONTEXT or also exclude DATACUTE_EXCLUDE_ATTRIBUTECONTEXTANDDATA)
4+
#endif
5+
#if DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAY
6+
#error AttributeContextAndData requires EquatableImmutableArray (remove DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAY or also exclude DATACUTE_EXCLUDE_ATTRIBUTECONTEXTANDDATA)
7+
#endif
78
using System;
89
using System.Collections.Immutable;
910
using System.Text;
@@ -338,4 +339,4 @@ private static bool BootstrapGetIsNullableContextEnabled(SemanticModel semanticM
338339
}
339340
}
340341
}
341-
#endif
342+
#endif // !DATACUTE_EXCLUDE_ATTRIBUTECONTEXTANDDATA

IncrementalGeneratorExtensions.Content/Datacute/IncrementalGeneratorExtensions/AttributeContextAndDataExtensions.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
// <auto-generated>
2-
// This file is part of the Datacute.IncrementalGeneratorExtensions package.
3-
// It is included as a source file and should not be modified.
4-
// </auto-generated>
5-
6-
#if !DATACUTE_EXCLUDE_ATTRIBUTECONTEXTANDDATAEXTENSIONS && !DATACUTE_EXCLUDE_ATTRIBUTECONTEXTANDDATA && !DATACUTE_EXCLUDE_TYPECONTEXT
1+
#if !DATACUTE_EXCLUDE_ATTRIBUTECONTEXTANDDATAEXTENSIONS // Feature: AttributeContextAndDataExtensions
2+
#if !DATACUTE_EXCLUDE_ATTRIBUTECONTEXTANDDATA // Dependency: AttributeContextAndData
73
using System;
84
using Microsoft.CodeAnalysis;
95

106
namespace Datacute.IncrementalGeneratorExtensions
117
{
8+
/// <summary>
9+
/// Extension methods for wiring up <see cref="AttributeContextAndData{T}"/> collection into an incremental generator pipeline.
10+
/// </summary>
1211
public static class AttributeContextAndDataExtensions
1312
{
1413
/// <summary>
@@ -42,11 +41,12 @@ public static IncrementalValuesProvider<AttributeContextAndData<T>> SelectAttrib
4241
predicate: AttributeContextAndData<T>.Predicate,
4342
transform: (syntaxContext, token) =>
4443
AttributeContextAndData<T>.Transform(syntaxContext, attributeDataCollector, token))
45-
#if !DATACUTE_EXCLUDE_LIGHTWEIGHTTRACEEXTENSIONS && !DATACUTE_EXCLUDE_LIGHTWEIGHT && !DATACUTE_EXCLUDE_GENERATORSTAGE
44+
#if !DATACUTE_EXCLUDE_LIGHTWEIGHTTRACEEXTENSIONS && !DATACUTE_EXCLUDE_LIGHTWEIGHTTRACE && !DATACUTE_EXCLUDE_GENERATORSTAGE
4645
.WithTrackingName(GeneratorStage.ForAttributeWithMetadataName);
4746
#else
4847
;
4948
#endif
5049
}
5150
}
52-
#endif
51+
#endif // !DATACUTE_EXCLUDE_ATTRIBUTECONTEXTANDDATA
52+
#endif // !DATACUTE_EXCLUDE_ATTRIBUTECONTEXTANDDATAEXTENSIONS
Lines changed: 76 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
1-
// <auto-generated>
2-
// This file is part of the Datacute.IncrementalGeneratorExtensions package.
3-
// It is included as a source file and should not be modified.
4-
// </auto-generated>
5-
6-
#if !DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAY
1+
#if !DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAY
72
using System;
83
using System.Collections;
9-
using System.Collections.Concurrent;
104
using System.Collections.Generic;
115
using System.Collections.Immutable;
126
using System.Threading;
@@ -20,32 +14,75 @@ namespace Datacute.IncrementalGeneratorExtensions
2014
public sealed class EquatableImmutableArray<T> : IEquatable<EquatableImmutableArray<T>>, IReadOnlyList<T>
2115
where T : IEquatable<T>
2216
{
17+
/// <summary>
18+
/// Gets a shared empty instance of <see cref="EquatableImmutableArray{T}"/>.
19+
/// </summary>
2320
public static EquatableImmutableArray<T> Empty { get; } = new EquatableImmutableArray<T>(ImmutableArray<T>.Empty, 0);
2421

2522
// Static factory method with singleton handling
26-
public static EquatableImmutableArray<T> Create(ImmutableArray<T> values, CancellationToken cancellationToken = default)
27-
=> EquatableImmutableArrayInstanceCache<T>.GetOrCreate(values, cancellationToken);
23+
/// <summary>
24+
/// Creates an <see cref="EquatableImmutableArray{T}"/> for the provided immutable array, reusing a cached instance when possible.
25+
/// </summary>
26+
/// <param name="values">The immutable array backing the equatable wrapper.</param>
27+
/// <param name="cancellationToken">A cancellation token.</param>
28+
/// <returns>An instance representing the supplied values (possibly a cached singleton for empty).</returns>
29+
public static EquatableImmutableArray<T> Create(ImmutableArray<T> values, CancellationToken cancellationToken = default)
30+
{
31+
if (values.IsEmpty)
32+
return Empty;
33+
#if DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAYINSTANCECACHE
34+
// Cache disabled: compute hash directly and return a new instance (no reuse / instrumentation events)
35+
var comparer = EqualityComparer<T>.Default;
36+
int hash = CalculateHashCode(values, comparer, 0, 0);
37+
return new EquatableImmutableArray<T>(values, hash);
38+
#else
39+
return EquatableImmutableArrayInstanceCache<T>.GetOrCreate(values, cancellationToken);
40+
#endif
41+
}
2842

2943
private readonly ImmutableArray<T> _values;
3044
private readonly int _hashCode;
31-
private readonly int _length;
3245

46+
/// <summary>
47+
/// Gets the element at the specified index.
48+
/// </summary>
49+
/// <param name="index">Zero-based index.</param>
3350
public T this[int index] => _values[index];
34-
public int Count => _length;
35-
51+
/// <summary>
52+
/// Gets the number of elements in the array.
53+
/// </summary>
54+
public int Count => _values.Length;
55+
3656
// Properties Duplicated from ImmutableArray<T>
37-
public int Length => _length;
38-
public bool IsEmpty => _length == 0;
57+
58+
/// <summary>
59+
/// Gets the number of elements in the array (alias of <see cref="Count"/>).
60+
/// </summary>
61+
public int Length => _values.Length;
62+
/// <summary>
63+
/// True if the underlying array has length 0.
64+
/// </summary>
65+
public bool IsEmpty => _values.Length == 0;
66+
/// <summary>
67+
/// True if the underlying immutable array is in its default (uninitialised) state.
68+
/// </summary>
3969
public bool IsDefault => _values.IsDefault;
70+
/// <summary>
71+
/// True if the underlying immutable array is either default or empty.
72+
/// </summary>
4073
public bool IsDefaultOrEmpty => _values.IsDefaultOrEmpty;
4174

4275
internal EquatableImmutableArray(ImmutableArray<T> values, int hashCode)
4376
{
4477
_values = values;
45-
_length = values.Length;
4678
_hashCode = hashCode;
4779
}
4880

81+
/// <summary>
82+
/// Determines value equality with another <see cref="EquatableImmutableArray{T}"/>.
83+
/// </summary>
84+
/// <param name="other">The other instance.</param>
85+
/// <returns>True if both contain the same sequence of values; otherwise false.</returns>
4986
public bool Equals(EquatableImmutableArray<T> other)
5087
{
5188
// Fast reference equality check
@@ -57,17 +94,18 @@ public bool Equals(EquatableImmutableArray<T> other)
5794
if (_hashCode != other._hashCode) return false;
5895

5996
// We're really unlikely to get here, as we're using an instance cache
60-
// so we've probably encountered a hash collision
61-
97+
// so we've probably encountered a hash collision,
98+
// or the instance cache is disabled.
99+
62100
// Compare array lengths
63-
if (_length != other._length) return false;
101+
if (_values.Length != other._values.Length) return false;
64102

65103
// If both are empty, they're equal
66-
if (_length == 0) return true;
104+
if (_values.Length == 0) return true;
67105

68106
// Element-by-element comparison
69107
var comparer = EqualityComparer<T>.Default;
70-
for (int i = 0; i < _length; i++)
108+
for (int i = 0; i < _values.Length; i++)
71109
{
72110
if (!comparer.Equals(_values[i], other._values[i]))
73111
return false;
@@ -76,12 +114,30 @@ public bool Equals(EquatableImmutableArray<T> other)
76114
return true;
77115
}
78116

117+
/// <inheritdoc />
79118
public override bool Equals(object obj) => obj is EquatableImmutableArray<T> other && Equals(other);
80119

120+
/// <inheritdoc />
81121
public override int GetHashCode() => _hashCode;
82122

83123
IEnumerator<T> IEnumerable<T>.GetEnumerator() => ((IEnumerable<T>)_values).GetEnumerator();
84124
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_values).GetEnumerator();
125+
126+
internal static int CalculateHashCode(ImmutableArray<T> values, EqualityComparer<T> comparer, int currentHash, int startIndex)
127+
{
128+
int hash = currentHash;
129+
for (var index = startIndex; index < values.Length; index++)
130+
{
131+
var value = values[index];
132+
hash = HashHelpers_Combine(hash, value == null ? 0 : comparer.GetHashCode(value));
133+
}
134+
return hash;
135+
}
136+
internal static int HashHelpers_Combine(int h1, int h2)
137+
{
138+
uint rol5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
139+
return ((int)rol5 + h1) ^ h2;
140+
}
85141
}
86142
}
87143
#endif

IncrementalGeneratorExtensions.Content/Datacute/IncrementalGeneratorExtensions/EquatableImmutableArrayExtensions.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
// <auto-generated>
2-
// This file is part of the Datacute.IncrementalGeneratorExtensions package.
3-
// It is included as a source file and should not be modified.
4-
// </auto-generated>
5-
6-
#if !DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAYEXTENSIONS
1+
#if !DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAYEXTENSIONS // Feature: EquatableImmutableArrayExtensions
2+
#if !DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAY // Dependency: EquatableImmutableArray
73
using System;
84
using System.Collections.Generic;
95
using System.Collections.Immutable;
@@ -150,11 +146,18 @@ public static EquatableImmutableArray<T> ToEquatableImmutableArray<TSource,T>(th
150146
where TRight : IEquatable<TRight>
151147
=> provider1.Combine(provider2.CollectEquatable());
152148

149+
/// <summary>
150+
/// Collects an <see cref="IncrementalValuesProvider{T}"/> and converts the <see cref="ImmutableArray{T}"/> to an <see cref="EquatableImmutableArray{T}"/>.
151+
/// </summary>
152+
/// <param name="provider">The incremental values provider to collect.</param>
153+
/// <typeparam name="T">The type of the elements in the provider, which must implement <see cref="IEquatable{T}"/>.</typeparam>
154+
/// <returns>An <see cref="IncrementalValueProvider{T}"/> producing the collected values as an <see cref="EquatableImmutableArray{T}"/>.</returns>
153155
public static IncrementalValueProvider<EquatableImmutableArray<T>> CollectEquatable<T>(
154156
this IncrementalValuesProvider<T> provider)
155157
where T : IEquatable<T>
156158
=> provider.Collect().Select(EquatableImmutableArray<T>.Create);
157159

158160
}
159161
}
160-
#endif
162+
#endif // !DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAY
163+
#endif // !DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAYEXTENSIONS

IncrementalGeneratorExtensions.Content/Datacute/IncrementalGeneratorExtensions/EquatableImmutableArrayInstanceCache.cs

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
// <auto-generated>
2-
// This file is part of the Datacute.IncrementalGeneratorExtensions package.
3-
// It is included as a source file and should not be modified.
4-
// </auto-generated>
5-
6-
#if !DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAY
1+
#if !DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAYINSTANCECACHE // Feature: EquatableImmutableArrayInstanceCache (optional)
2+
#if !DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAY // Dependency: EquatableImmutableArray
73
using System;
84
using System.Collections.Concurrent;
95
using System.Collections.Generic;
@@ -114,7 +110,7 @@ public static EquatableImmutableArray<T> GetOrCreate(ImmutableArray<T> values, C
114110
}
115111

116112
// No match found, calculate hash and create new instance
117-
var hash = CalculateHashCode(values, comparer, firstElementHash, 1);
113+
var hash = EquatableImmutableArray<T>.CalculateHashCode(values, comparer, firstElementHash, 1);
118114
#if !DATACUTE_EXCLUDE_LIGHTWEIGHTTRACE && !DATACUTE_EXCLUDE_GENERATORSTAGE
119115
// Record a histogram of the array sizes we are being asked to create
120116
LightweightTrace.IncrementCount(GeneratorStage.EquatableImmutableArrayCacheMiss, values.Length);
@@ -125,25 +121,7 @@ public static EquatableImmutableArray<T> GetOrCreate(ImmutableArray<T> values, C
125121
return newResult;
126122
}
127123
}
128-
129-
private static int CalculateHashCode(ImmutableArray<T> values, EqualityComparer<T> comparer, int currentHash, int hashedValues)
130-
{
131-
int hash = currentHash;
132-
for (var index = hashedValues; index < values.Length; index++)
133-
{
134-
var value = values[index];
135-
hash = HashHelpers_Combine(hash, value == null ? 0 : comparer.GetHashCode(value));
136-
}
137-
return hash;
138-
}
139-
140-
private static int HashHelpers_Combine(int h1, int h2)
141-
{
142-
// RyuJIT optimizes this to use the ROL instruction
143-
// Related GitHub pull request: https://github.com/dotnet/coreclr/pull/1830
144-
uint rol5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
145-
return ((int)rol5 + h1) ^ h2;
146-
}
147124
}
148125
}
149-
#endif
126+
#endif // !DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAY
127+
#endif // !DATACUTE_EXCLUDE_EQUATABLEIMMUTABLEARRAYINSTANCECACHE

IncrementalGeneratorExtensions.Content/Datacute/IncrementalGeneratorExtensions/GeneratorStage.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
// <auto-generated>
2-
// This file is part of the Datacute.IncrementalGeneratorExtensions package.
3-
// It is included as a source file and should not be modified.
4-
// </auto-generated>
5-
6-
#if !DATACUTE_EXCLUDE_GENERATORSTAGE
1+
#if !DATACUTE_EXCLUDE_GENERATORSTAGE
72
namespace Datacute.IncrementalGeneratorExtensions
83
{
94
/// <summary>

IncrementalGeneratorExtensions.Content/Datacute/IncrementalGeneratorExtensions/GeneratorStageDescriptions.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
// <auto-generated>
2-
// This file is part of the Datacute.IncrementalGeneratorExtensions package.
3-
// It is included as a source file and should not be modified.
4-
// </auto-generated>
5-
6-
#if !DATACUTE_EXCLUDE_GENERATORSTAGEDESCRIPTIONS && !DATACUTE_EXCLUDE_GENERATORSTAGE
1+
#if !DATACUTE_EXCLUDE_GENERATORSTAGEDESCRIPTIONS // Feature: GeneratorStageDescriptions
2+
#if !DATACUTE_EXCLUDE_GENERATORSTAGE // Dependency: GeneratorStage
73
using System.Collections.Generic;
84

95
namespace Datacute.IncrementalGeneratorExtensions
@@ -74,4 +70,5 @@ public static class GeneratorStageDescriptions
7470
};
7571
}
7672
}
77-
#endif
73+
#endif // !DATACUTE_EXCLUDE_GENERATORSTAGE
74+
#endif // !DATACUTE_EXCLUDE_GENERATORSTAGEDESCRIPTIONS

IncrementalGeneratorExtensions.Content/Datacute/IncrementalGeneratorExtensions/IndentingLineAppender.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
// <auto-generated>
2-
// This file is part of the Datacute.IncrementalGeneratorExtensions package.
3-
// It is included as a source file and should not be modified.
4-
// </auto-generated>
5-
6-
#if !DATACUTE_EXCLUDE_INDENTINGLINEAPPENDER
1+
#if !DATACUTE_EXCLUDE_INDENTINGLINEAPPENDER
72
using System;
83
using System.Collections.Generic;
94
using System.IO;

IncrementalGeneratorExtensions.Content/Datacute/IncrementalGeneratorExtensions/LightweightTrace.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
// <auto-generated>
2-
// This file is part of the Datacute.IncrementalGeneratorExtensions package.
3-
// It is included as a source file and should not be modified.
4-
// </auto-generated>
5-
6-
#if !DATACUTE_EXCLUDE_LIGHTWEIGHTTRACE
1+
#if !DATACUTE_EXCLUDE_LIGHTWEIGHTTRACE
72
using System;
83
using System.Collections.Concurrent;
94
using System.Collections.Generic;
@@ -15,7 +10,9 @@
1510
namespace Datacute.IncrementalGeneratorExtensions
1611
{
1712
/// <summary>
18-
/// A lightweight tracing utility that allows for efficient logging of events and counters.
13+
/// Zero-allocation instrumentation core for incremental source generators.
14+
/// <para>Features: ring-buffer timestamped event trace; composite-key counters (id + value + mapping flag) for histograms & categorical counts; automatic method-call frequency counting; method entry/exit tagging; single-int key encoding to minimize memory & dictionary churn; unified AppendDiagnosticsComment output (counters + trace) embeddable in generated code.</para>
15+
/// <para>Goal: fast, in-process behavioral visibility without external profilers or large allocations.</para>
1916
/// </summary>
2017
public static class LightweightTrace
2118
{

0 commit comments

Comments
 (0)