Add EquatableAnalyzer diagnostic analyzer for collection/attribute validation#129
Add EquatableAnalyzer diagnostic analyzer for collection/attribute validation#129
Conversation
…ing collection attributes and EQ0010-EQ0013 for invalid attribute usage Agent-Logs-Url: https://github.com/loresoft/Equatable.Generator/sessions/00bd26b4-cc86-4bf1-a638-e609fc955d18 Co-authored-by: pwelter34 <1196837+pwelter34@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a Roslyn DiagnosticAnalyzer for the Equatable source generator to report missing/invalid equality attributes on properties of [Equatable] types, keeping these diagnostics out of the generator pipeline.
Changes:
- Introduces
EquatableAnalyzerwith diagnostics for missing collection/dictionary attributes and invalid attribute usage. - Adds new diagnostic descriptors
EQ0001/EQ0002and refines message formatting for existingEQ0010-EQ0013. - Adds an analyzer-focused test suite validating expected diagnostics and non-diagnostics.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
src/Equatable.SourceGenerator/EquatableAnalyzer.cs |
Implements the new analyzer logic and emits diagnostics based on property types/attributes. |
src/Equatable.SourceGenerator/DiagnosticDescriptors.cs |
Adds new descriptors for missing attributes and updates message formats for existing descriptors. |
test/Equatable.Generator.Tests/EquatableAnalyzerTest.cs |
Adds unit tests to validate analyzer behavior across valid, invalid, and missing-attribute scenarios. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| var properties = typeSymbol | ||
| .GetMembers() | ||
| .OfType<IPropertySymbol>() | ||
| .Where(p => !p.IsIndexer | ||
| && p.DeclaredAccessibility == Accessibility.Public | ||
| && !IsIgnored(p)); | ||
|
|
||
| foreach (var property in properties) | ||
| AnalyzeProperty(context, property); | ||
| } | ||
|
|
There was a problem hiding this comment.
AnalyzeNamedType only analyzes properties returned from typeSymbol.GetMembers(), so diagnostics won’t be produced for public properties declared on base types—even though the source generator can include base properties (see EquatableGenerator.GetProperties(...) looping currentSymbol = currentSymbol.BaseType). To keep analyzer feedback aligned with generated equality behavior, consider walking base types with similar include/exclusion rules (and de-duping by property name).
| var properties = typeSymbol | |
| .GetMembers() | |
| .OfType<IPropertySymbol>() | |
| .Where(p => !p.IsIndexer | |
| && p.DeclaredAccessibility == Accessibility.Public | |
| && !IsIgnored(p)); | |
| foreach (var property in properties) | |
| AnalyzeProperty(context, property); | |
| } | |
| foreach (var property in GetAnalyzableProperties(typeSymbol)) | |
| AnalyzeProperty(context, property); | |
| } | |
| private static IEnumerable<IPropertySymbol> GetAnalyzableProperties(INamedTypeSymbol typeSymbol) | |
| { | |
| var seenPropertyNames = new System.Collections.Generic.HashSet<string>(System.StringComparer.Ordinal); | |
| for (var currentSymbol = typeSymbol; currentSymbol != null; currentSymbol = currentSymbol.BaseType) | |
| { | |
| foreach (var property in currentSymbol | |
| .GetMembers() | |
| .OfType<IPropertySymbol>() | |
| .Where(p => !p.IsIndexer | |
| && p.DeclaredAccessibility == Accessibility.Public | |
| && !IsIgnored(p))) | |
| { | |
| if (seenPropertyNames.Add(property.Name)) | |
| yield return property; | |
| } | |
| } | |
| } |
|
@copilot apply changes based on the comments in this thread |
…uble spaces, add interface-typed property tests Agent-Logs-Url: https://github.com/loresoft/Equatable.Generator/sessions/5b8943ea-bd6f-4681-8ca8-834635a97745 Co-authored-by: pwelter34 <1196837+pwelter34@users.noreply.github.com>
Applied all review changes in commit
All 88 tests pass, 0 build warnings, 0 CodeQL alerts. |
EQ0001andEQ0002for missing collection/dictionary equality attributesEquatableAnalyzer.csas aDiagnosticAnalyzerEquatableAnalyzerTest.cswith tests for all diagnostic casesAllInterfacesbug: AddedImplementsDictionary(ITypeSymbol)andImplementsEnumerable(ITypeSymbol)helpers that check if the type IS the interface itself OR implements it — fixes false positives/negatives forIDictionary<,>/IEnumerable<T>-typed propertiesGetMembers()withGetAnalyzableProperties()that walks the base type chain (de-duplicating by name, matching generator behavior), stopping atObject/ValueTypeor at an[Equatable]base typeDiagnosticDescriptors.csmessage format strings (EQ0010–EQ0013)IDictionary<,>,IEnumerable<T>,IReadOnlyCollection<T>missing-attribute; valid[DictionaryEquality]/[SequenceEquality]on interface types; base-type inclusion/exclusion tests