Skip to content

Commit d7b2e9a

Browse files
committed
Simplify EquatableArray
1 parent 3d5039e commit d7b2e9a

File tree

2 files changed

+27
-84
lines changed

2 files changed

+27
-84
lines changed

src/ModelContextProtocol.Analyzers/EquatableArray.cs

Lines changed: 16 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,111 +2,54 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Collections;
5-
using System.Collections.Immutable;
65

76
namespace ModelContextProtocol.Analyzers;
87

98
/// <summary>An immutable, equatable array.</summary>
109
/// <typeparam name="T">The type of values in the array.</typeparam>
11-
internal readonly struct EquatableArray<T> : IEquatable<EquatableArray<T>>, IEnumerable<T>
12-
where T : IEquatable<T>
10+
internal readonly struct EquatableArray<T> : IEnumerable<T>, IEquatable<EquatableArray<T>>
1311
{
14-
/// <summary>
15-
/// The underlying <typeparamref name="T"/> array.
16-
/// </summary>
17-
private readonly ImmutableArray<T> _array;
12+
/// <summary>The underlying <typeparamref name="T"/> array.</summary>
13+
private readonly T[]? _array;
1814

1915
/// <param name="source">The source to enumerate and wrap.</param>
20-
public EquatableArray(IEnumerable<T> source) => _array = source.ToImmutableArray();
16+
public EquatableArray(IEnumerable<T> source) => _array = source.ToArray();
2117

2218
/// <param name="source">The source to wrap.</param>
23-
public EquatableArray(ImmutableArray<T> array) => _array = array;
19+
public EquatableArray(T[] array) => _array = array;
2420

25-
/// <summary>An empty <see cref="EquatableArray{T}"/>.</summary>
26-
public static EquatableArray<T> Empty => new(ImmutableArray<T>.Empty);
27-
28-
/// <summary>
29-
/// Gets a reference to an item at a specified position within the array.
30-
/// </summary>
21+
/// <summary>Gets a reference to an item at a specified position within the array.</summary>
3122
/// <param name="index">The index of the item to retrieve a reference to.</param>
3223
/// <returns>A reference to an item at a specified position within the array.</returns>
33-
public ref readonly T this[int index] => ref _array.ItemRef(index);
34-
35-
/// <summary>
36-
/// Gets a value indicating whether the current array is empty.
37-
/// </summary>
38-
public bool IsEmpty => _array.IsEmpty;
24+
public ref readonly T this[int index] => ref NonNullArray[index];
3925

40-
/// <summary>
41-
/// Gets a value indicating whether the current array is default or empty.
42-
/// </summary>
43-
public bool IsDefaultOrEmpty => _array.IsDefaultOrEmpty;
26+
/// <summary>Gets the backing array.</summary>
27+
private T[] NonNullArray => _array ?? [];
4428

45-
/// <summary>
46-
/// Gets the length of the current array.
47-
/// </summary>
48-
public int Length => _array.Length;
29+
/// <summary>Gets the length of the current array.</summary>
30+
public int Length => NonNullArray.Length;
4931

5032
/// <inheritdoc/>
51-
public bool Equals(EquatableArray<T> other) => _array.SequenceEqual(other._array);
33+
public bool Equals(EquatableArray<T> other) => NonNullArray.SequenceEqual(other.NonNullArray);
5234

5335
/// <inheritdoc/>
54-
public override bool Equals(object? obj) => obj is EquatableArray<T> array && Equals(array);
36+
public override bool Equals(object? obj) => obj is EquatableArray<T> array && Equals(array);
5537

5638
/// <inheritdoc/>
5739
public override int GetHashCode()
5840
{
59-
if (_array.IsDefault)
60-
{
61-
return 0;
62-
}
63-
6441
int hash = 17;
65-
foreach (T item in _array)
42+
foreach (T item in NonNullArray)
6643
{
6744
hash = hash * 31 + (item?.GetHashCode() ?? 0);
6845
}
6946

7047
return hash;
7148
}
7249

73-
/// <summary>
74-
/// Gets an <see cref="ImmutableArray{T}.Enumerator"/> value to traverse items in the current array.
75-
/// </summary>
76-
/// <returns>An <see cref="ImmutableArray{T}.Enumerator"/> value to traverse items in the current array.</returns>
77-
public ImmutableArray<T>.Enumerator GetEnumerator() => _array.GetEnumerator();
78-
7950
/// <inheritdoc/>
80-
IEnumerator<T> IEnumerable<T>.GetEnumerator() => ((IEnumerable<T>)_array).GetEnumerator();
51+
IEnumerator<T> IEnumerable<T>.GetEnumerator() => ((IEnumerable<T>)NonNullArray).GetEnumerator();
8152

8253
/// <inheritdoc/>
83-
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_array).GetEnumerator();
84-
85-
/// <summary>
86-
/// Implicitly converts an <see cref="ImmutableArray{T}"/> to <see cref="EquatableArray{T}"/>.
87-
/// </summary>
88-
/// <returns>An <see cref="EquatableArray{T}"/> instance from a given <see cref="ImmutableArray{T}"/>.</returns>
89-
public static implicit operator EquatableArray<T>(ImmutableArray<T> array) => new(array);
90-
91-
/// <summary>
92-
/// Implicitly converts an <see cref="EquatableArray{T}"/> to <see cref="ImmutableArray{T}"/>.
93-
/// </summary>
94-
/// <returns>An <see cref="ImmutableArray{T}"/> instance from a given <see cref="EquatableArray{T}"/>.</returns>
95-
public static implicit operator ImmutableArray<T>(EquatableArray<T> array) => array._array;
96-
97-
/// <summary>
98-
/// Checks whether two <see cref="EquatableArray{T}"/> values are the same.
99-
/// </summary>
100-
/// <param name="left">The first <see cref="EquatableArray{T}"/> value.</param>
101-
/// <param name="right">The second <see cref="EquatableArray{T}"/> value.</param>
102-
/// <returns>Whether <paramref name="left"/> and <paramref name="right"/> are equal.</returns>
103-
public static bool operator ==(EquatableArray<T> left, EquatableArray<T> right) => left.Equals(right);
104-
105-
/// <summary>
106-
/// Checks whether two <see cref="EquatableArray{T}"/> values are not the same.
107-
/// </summary>
108-
/// <param name="left">The first <see cref="EquatableArray{T}"/> value.</param>
109-
/// <param name="right">The second <see cref="EquatableArray{T}"/> value.</param>
110-
/// <returns>Whether <paramref name="left"/> and <paramref name="right"/> are not equal.</returns>
111-
public static bool operator !=(EquatableArray<T> left, EquatableArray<T> right) => !left.Equals(right);
54+
IEnumerator IEnumerable.GetEnumerator() => NonNullArray.GetEnumerator();
11255
}

src/ModelContextProtocol.Analyzers/XmlToDescriptionGenerator.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
5555
allMethods.Select(static (methods, _) => new EquatableArray<MethodToGenerate>(methods.Where(m => m.NeedsGeneration))),
5656
static (spc, methods) =>
5757
{
58-
if (!methods.IsDefaultOrEmpty)
58+
if (methods.Length > 0)
5959
{
6060
spc.AddSource(GeneratedFileName, SourceText.From(GenerateSourceFile(methods), Encoding.UTF8));
6161
}
@@ -113,7 +113,7 @@ private static MethodToGenerate ExtractMethodInfo(
113113
// For partial methods with invalid XML, report diagnostic but still generate partial declaration.
114114
EquatableArray<DiagnosticInfo> diagnostics = hasInvalidXml ?
115115
new EquatableArray<DiagnosticInfo>(ImmutableArray.Create(new DiagnosticInfo("MCP001", methodSymbol.Locations.FirstOrDefault(), methodSymbol.Name))) :
116-
EquatableArray<DiagnosticInfo>.Empty;
116+
default;
117117

118118
bool needsMethodDescription = xmlDocs is not null &&
119119
!string.IsNullOrWhiteSpace(xmlDocs.MethodDescription) &&
@@ -191,7 +191,7 @@ private static TypeInfo ExtractTypeInfo(INamedTypeSymbol? typeSymbol)
191191
{
192192
if (typeSymbol is null)
193193
{
194-
return new TypeInfo(string.Empty, EquatableArray<TypeDeclarationInfo>.Empty);
194+
return new TypeInfo(string.Empty, default);
195195
}
196196

197197
// Build list of nested types from innermost to outermost
@@ -475,21 +475,21 @@ private readonly record struct MethodToGenerate(
475475
Modifiers: string.Empty,
476476
ReturnType: string.Empty,
477477
MethodName: string.Empty,
478-
Parameters: EquatableArray<ParameterInfo>.Empty,
478+
Parameters: default,
479479
MethodDescription: null,
480480
ReturnDescription: null,
481-
Diagnostics: EquatableArray<DiagnosticInfo>.Empty);
481+
Diagnostics: default);
482482

483483
public static MethodToGenerate CreateDiagnosticOnly(DiagnosticInfo diagnostic) => new(
484484
NeedsGeneration: false,
485485
TypeInfo: default,
486486
Modifiers: string.Empty,
487487
ReturnType: string.Empty,
488488
MethodName: string.Empty,
489-
Parameters: EquatableArray<ParameterInfo>.Empty,
489+
Parameters: default,
490490
MethodDescription: null,
491491
ReturnDescription: null,
492-
Diagnostics: ImmutableArray.Create(diagnostic));
492+
Diagnostics: new([diagnostic]));
493493
}
494494

495495
/// <summary>Holds information about a method parameter.</summary>
@@ -498,20 +498,20 @@ private readonly record struct ParameterInfo(
498498
string Name,
499499
bool HasDescriptionAttribute,
500500
string? XmlDescription,
501-
string? DefaultValue) : IEquatable<ParameterInfo>;
501+
string? DefaultValue);
502502

503503
/// <summary>Holds information about a type containing MCP methods.</summary>
504504
private readonly record struct TypeInfo(
505505
string Namespace,
506-
EquatableArray<TypeDeclarationInfo> Types) : IEquatable<TypeInfo>;
506+
EquatableArray<TypeDeclarationInfo> Types);
507507

508508
/// <summary>Holds information about a type declaration.</summary>
509509
private readonly record struct TypeDeclarationInfo(
510510
string Name,
511-
string TypeKeyword) : IEquatable<TypeDeclarationInfo>;
511+
string TypeKeyword);
512512

513513
/// <summary>Holds diagnostic information to be reported.</summary>
514-
private readonly struct DiagnosticInfo : IEquatable<DiagnosticInfo>
514+
private readonly struct DiagnosticInfo
515515
{
516516
public string Id { get; }
517517
public Location? Location { get; }

0 commit comments

Comments
 (0)