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 Docs/pages/setup/03-indexers.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ interactions. See [Mockolate0002](../analyzers#mockolate0002) for when such a ty

Both facades are fully restricted: the fluent builders returned by `Returns`, `Throws`, `Do` and
`TransitionTo` stay on the narrowed surface, so no amount of chaining reaches the accessor the mock
does not intercept. Indexers with more than four keys keep the full surface.
does not intercept.

**Notes:**

Expand Down
53 changes: 27 additions & 26 deletions Source/Mockolate.SourceGenerators/MockGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,21 @@ void IIncrementalGenerator.Initialize(IncrementalGeneratorInitializationContext
});

// Aggregate inputs derived from per-mock projections — each aggregate caches independently.
IncrementalValueProvider<EquatableArray<int>> indexerSetupArities = collectedMocks
.Select(static (arr, _) => CollectIndexerSetupArities(arr));
IncrementalValueProvider<EquatableArray<IndexerSetupKey>> indexerSetupKeys = collectedMocks
.Select(static (arr, _) => CollectIndexerSetupKeys(arr));

context.RegisterSourceOutput(indexerSetupArities, static (spc, arities) =>
{
if (arities.Count > 0)
context.RegisterSourceOutput(
indexerSetupKeys.Combine(hasOverloadResolutionPriority),
static (spc, source) =>
{
if (source.Left.Count == 0)
{
return;
}

spc.AddSource("IndexerSetups.g.cs",
ToSource(Sources.Sources.IndexerSetups(ToHashSet(arities))));
}
});
ToSource(Sources.Sources.IndexerSetups(source.Left, source.Right)));
});

IncrementalValueProvider<EquatableArray<MethodSetupKey>> methodSetupKeys = collectedMocks
.Select(static (arr, _) => CollectMethodSetupKeys(arr));
Expand Down Expand Up @@ -212,18 +216,6 @@ private static EquatableArray<MockClass> Distinct(ImmutableArray<MockClass> mock
return new EquatableArray<MockClass>(distinct.ToArray());
}

private static HashSet<int> ToHashSet(EquatableArray<int> arities)
{
int[] arr = arities.AsArray();
HashSet<int> set = new();
foreach (int item in arr)
{
set.Add(item);
}

return set;
}

private static HashSet<(int, bool)> ToMethodSetupHashSet(EquatableArray<MethodSetupKey> keys)
{
MethodSetupKey[] arr = keys.AsArray();
Expand All @@ -236,24 +228,31 @@ private static HashSet<int> ToHashSet(EquatableArray<int> arities)
return set;
}

private static EquatableArray<int> CollectIndexerSetupArities(EquatableArray<MockClass> mocks)
private static EquatableArray<IndexerSetupKey> CollectIndexerSetupKeys(EquatableArray<MockClass> mocks)
{
MockClass[] arr = mocks.AsArray();
HashSet<int> set = new();
Dictionary<int, (bool NeedsGetterOnly, bool NeedsSetterOnly)> map = new();
foreach (MockClass mc in arr)
{
foreach (Property property in mc.AllProperties())
{
if (property.IndexerParameters?.Count > 4)
{
set.Add(property.IndexerParameters.Value.Count);
int arity = property.IndexerParameters.Value.Count;
bool needsGetterOnly = property is { Getter: not null, Setter: null, };
bool needsSetterOnly = property is { Getter: null, Setter: not null, };
map.TryGetValue(arity, out (bool NeedsGetterOnly, bool NeedsSetterOnly) existing);
map[arity] = (existing.NeedsGetterOnly || needsGetterOnly,
existing.NeedsSetterOnly || needsSetterOnly);
}
}
}

int[] sorted = set.ToArray();
Array.Sort(sorted);
return new EquatableArray<int>(sorted);
IndexerSetupKey[] sorted = map
.OrderBy(kvp => kvp.Key)
.Select(kvp => new IndexerSetupKey(kvp.Key, kvp.Value.NeedsGetterOnly, kvp.Value.NeedsSetterOnly))
.ToArray();
return new EquatableArray<IndexerSetupKey>(sorted);
}

private static EquatableArray<MethodSetupKey> CollectMethodSetupKeys(EquatableArray<MockClass> mocks)
Expand Down Expand Up @@ -544,6 +543,8 @@ private static bool IsValidMockDeclaration(MockClass mockClass)

internal readonly record struct RefStructIndexerSetup(int Arity, bool HasGetter, bool HasSetter);

internal readonly record struct IndexerSetupKey(int Arity, bool NeedsGetterOnly, bool NeedsSetterOnly);

internal readonly record struct MockAsExtensionPair(
string SourceName,
string SourceFullName,
Expand Down
Loading
Loading