From c0b13eadb7596965a09938a83a47d52d52a1f7ed Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 05:39:51 +0000 Subject: [PATCH 1/6] Initial plan From dad4ceb453fd3a7fef2cdbb72b68d54de5471e18 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 05:43:54 +0000 Subject: [PATCH 2/6] fix(adapter): Address review feedback - duplicate adapter detection, indexers, and internal ctor accessibility Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com> --- .../Adapter/AdapterGenerator.cs | 52 +++++++++++++++++-- .../AnalyzerReleases.Unshipped.md | 1 + 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/PatternKit.Generators/Adapter/AdapterGenerator.cs b/src/PatternKit.Generators/Adapter/AdapterGenerator.cs index e2565a3..9510700 100644 --- a/src/PatternKit.Generators/Adapter/AdapterGenerator.cs +++ b/src/PatternKit.Generators/Adapter/AdapterGenerator.cs @@ -38,6 +38,7 @@ public sealed class AdapterGenerator : IIncrementalGenerator private const string DiagIdMappingMethodNotAccessible = "PKADP015"; private const string DiagIdStaticMembersNotSupported = "PKADP016"; private const string DiagIdRefReturnNotSupported = "PKADP017"; + private const string DiagIdIndexersNotSupported = "PKADP018"; private static readonly DiagnosticDescriptor HostNotStaticPartialDescriptor = new( id: DiagIdHostNotStaticPartial, @@ -175,6 +176,14 @@ public sealed class AdapterGenerator : IIncrementalGenerator defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); + private static readonly DiagnosticDescriptor IndexersNotSupportedDescriptor = new( + id: DiagIdIndexersNotSupported, + title: "Indexers are not supported", + messageFormat: "Target type '{0}' contains indexer '{1}' which is not supported by the adapter generator", + category: "PatternKit.Generators.Adapter", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + public void Initialize(IncrementalGeneratorInitializationContext context) { // Find all class declarations with [GenerateAdapter] attribute @@ -192,11 +201,14 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var node = typeContext.TargetNode; + // Track generated adapter type names to detect conflicts (namespace -> type name -> location) + var generatedAdapters = new Dictionary>(); + // Process each [GenerateAdapter] attribute on the host foreach (var attr in typeContext.Attributes.Where(a => a.AttributeClass?.ToDisplayString() == "PatternKit.Generators.Adapter.GenerateAdapterAttribute")) { - GenerateAdapterForAttribute(spc, hostSymbol, attr, node, typeContext.SemanticModel); + GenerateAdapterForAttribute(spc, hostSymbol, attr, node, typeContext.SemanticModel, generatedAdapters); } }); } @@ -206,7 +218,8 @@ private void GenerateAdapterForAttribute( INamedTypeSymbol hostSymbol, AttributeData attribute, SyntaxNode node, - SemanticModel semanticModel) + SemanticModel semanticModel, + Dictionary> generatedAdapters) { // Validate host is static partial if (!IsStaticPartial(node)) @@ -281,7 +294,8 @@ private void GenerateAdapterForAttribute( (c.DeclaredAccessibility == Accessibility.Public || c.DeclaredAccessibility == Accessibility.Protected || c.DeclaredAccessibility == Accessibility.ProtectedOrInternal || - c.DeclaredAccessibility == Accessibility.Internal)); + (c.DeclaredAccessibility == Accessibility.Internal && + semanticModel.Compilation.IsSymbolAccessibleWithin(c, semanticModel.Compilation.Assembly)))); if (!hasAccessibleParameterlessCtor) { @@ -396,7 +410,7 @@ private void GenerateAdapterForAttribute( ? string.Empty : hostSymbol.ContainingNamespace.ToDisplayString()); - // Check for type name conflict (PKADP006) + // Check for type name conflict (PKADP006) - both in existing compilation and in current generator run if (HasTypeNameConflict(semanticModel.Compilation, ns, adapterTypeName)) { context.ReportDiagnostic(Diagnostic.Create( @@ -407,6 +421,24 @@ private void GenerateAdapterForAttribute( return; } + // Check for conflict with adapters being generated in this run + var normalizedNs = string.IsNullOrEmpty(ns) ? "" : ns; + if (!generatedAdapters.ContainsKey(normalizedNs)) + generatedAdapters[normalizedNs] = new Dictionary(); + + if (generatedAdapters[normalizedNs].TryGetValue(adapterTypeName, out var existingLocation)) + { + context.ReportDiagnostic(Diagnostic.Create( + TypeNameConflictDescriptor, + node.GetLocation(), + adapterTypeName, + string.IsNullOrEmpty(ns) ? "" : ns)); + return; + } + + // Track this adapter type name + generatedAdapters[normalizedNs][adapterTypeName] = node.GetLocation(); + // Generate adapter var source = GenerateAdapterCode( adapterTypeName, @@ -509,8 +541,18 @@ private List ValidateTargetMembers(INamedTypeSymbol targetType, Loca prop.Name)); } + // Check for indexers (not supported) + if (member is IPropertySymbol indexer && indexer.IsIndexer) + { + diagnostics.Add(Diagnostic.Create( + IndexersNotSupportedDescriptor, + location, + targetType.Name, + indexer.ToDisplayString())); + } + // Check for ref-return properties (not supported) - if (member is IPropertySymbol refProp && refProp.ReturnsByRef) + if (member is IPropertySymbol refProp && !refProp.IsIndexer && refProp.ReturnsByRef) { diagnostics.Add(Diagnostic.Create( RefReturnNotSupportedDescriptor, diff --git a/src/PatternKit.Generators/AnalyzerReleases.Unshipped.md b/src/PatternKit.Generators/AnalyzerReleases.Unshipped.md index 947541b..ce3dcad 100644 --- a/src/PatternKit.Generators/AnalyzerReleases.Unshipped.md +++ b/src/PatternKit.Generators/AnalyzerReleases.Unshipped.md @@ -115,3 +115,4 @@ PKADP014 | PatternKit.Generators.Adapter | Error | Nested or generic host not su PKADP015 | PatternKit.Generators.Adapter | Error | Mapping method must be accessible PKADP016 | PatternKit.Generators.Adapter | Error | Static members are not supported PKADP017 | PatternKit.Generators.Adapter | Error | Ref-return members are not supported +PKADP018 | PatternKit.Generators.Adapter | Error | Indexers are not supported From da354e345dd4ae20985b5b633a2e83380f3bf4c2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 05:44:29 +0000 Subject: [PATCH 3/6] docs(adapter): Add PKADP018 indexer diagnostic to documentation Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com> --- docs/generators/adapter.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/generators/adapter.md b/docs/generators/adapter.md index 7b5980a..1ac242d 100644 --- a/docs/generators/adapter.md +++ b/docs/generators/adapter.md @@ -248,6 +248,7 @@ public static partial class Adapters | **PKADP015** | Error | Mapping method must be accessible (public or internal) | | **PKADP016** | Error | Static members are not supported | | **PKADP017** | Error | Ref-return members are not supported | +| **PKADP018** | Error | Indexers are not supported | ## Limitations From 347aca6237687344a53dd1d37dbab2c18fa6753c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 05:45:53 +0000 Subject: [PATCH 4/6] fix(adapter): Improve variable naming and remove redundant indexer check in ref-return validation Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com> --- src/PatternKit.Generators/Adapter/AdapterGenerator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PatternKit.Generators/Adapter/AdapterGenerator.cs b/src/PatternKit.Generators/Adapter/AdapterGenerator.cs index 9510700..f6b9710 100644 --- a/src/PatternKit.Generators/Adapter/AdapterGenerator.cs +++ b/src/PatternKit.Generators/Adapter/AdapterGenerator.cs @@ -542,17 +542,17 @@ private List ValidateTargetMembers(INamedTypeSymbol targetType, Loca } // Check for indexers (not supported) - if (member is IPropertySymbol indexer && indexer.IsIndexer) + if (member is IPropertySymbol propertySymbol && propertySymbol.IsIndexer) { diagnostics.Add(Diagnostic.Create( IndexersNotSupportedDescriptor, location, targetType.Name, - indexer.ToDisplayString())); + propertySymbol.ToDisplayString())); } // Check for ref-return properties (not supported) - if (member is IPropertySymbol refProp && !refProp.IsIndexer && refProp.ReturnsByRef) + if (member is IPropertySymbol refProp && refProp.ReturnsByRef) { diagnostics.Add(Diagnostic.Create( RefReturnNotSupportedDescriptor, From 6260512f86dc158d408f7d835b5faa8da9a46dcf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 05:47:31 +0000 Subject: [PATCH 5/6] refactor(adapter): Improve code readability in constructor and property validation Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com> --- .../Adapter/AdapterGenerator.cs | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/PatternKit.Generators/Adapter/AdapterGenerator.cs b/src/PatternKit.Generators/Adapter/AdapterGenerator.cs index f6b9710..41995da 100644 --- a/src/PatternKit.Generators/Adapter/AdapterGenerator.cs +++ b/src/PatternKit.Generators/Adapter/AdapterGenerator.cs @@ -290,12 +290,23 @@ private void GenerateAdapterForAttribute( if (config.TargetType.TypeKind == TypeKind.Class && config.TargetType.IsAbstract) { var hasAccessibleParameterlessCtor = config.TargetType.InstanceConstructors - .Any(c => c.Parameters.Length == 0 && - (c.DeclaredAccessibility == Accessibility.Public || - c.DeclaredAccessibility == Accessibility.Protected || - c.DeclaredAccessibility == Accessibility.ProtectedOrInternal || - (c.DeclaredAccessibility == Accessibility.Internal && - semanticModel.Compilation.IsSymbolAccessibleWithin(c, semanticModel.Compilation.Assembly)))); + .Any(c => + { + if (c.Parameters.Length > 0) + return false; + + var accessibility = c.DeclaredAccessibility; + if (accessibility == Accessibility.Public || + accessibility == Accessibility.Protected || + accessibility == Accessibility.ProtectedOrInternal) + return true; + + // Internal constructors are only accessible if in the same assembly + if (accessibility == Accessibility.Internal) + return semanticModel.Compilation.IsSymbolAccessibleWithin(c, semanticModel.Compilation.Assembly); + + return false; + }); if (!hasAccessibleParameterlessCtor) { @@ -531,28 +542,28 @@ private List ValidateTargetMembers(INamedTypeSymbol targetType, Loca evt.Name)); } - // Check for settable properties (not supported) - if (member is IPropertySymbol prop && !prop.IsIndexer && prop.SetMethod is not null) + // Check for indexers (not supported) - must be checked before other property checks + if (member is IPropertySymbol propertySymbol && propertySymbol.IsIndexer) { diagnostics.Add(Diagnostic.Create( - SettablePropertiesNotSupportedDescriptor, + IndexersNotSupportedDescriptor, location, targetType.Name, - prop.Name)); + propertySymbol.ToDisplayString())); } - // Check for indexers (not supported) - if (member is IPropertySymbol propertySymbol && propertySymbol.IsIndexer) + // Check for settable properties (not supported) + if (member is IPropertySymbol prop && !prop.IsIndexer && prop.SetMethod is not null) { diagnostics.Add(Diagnostic.Create( - IndexersNotSupportedDescriptor, + SettablePropertiesNotSupportedDescriptor, location, targetType.Name, - propertySymbol.ToDisplayString())); + prop.Name)); } // Check for ref-return properties (not supported) - if (member is IPropertySymbol refProp && refProp.ReturnsByRef) + if (member is IPropertySymbol refProp && !refProp.IsIndexer && refProp.ReturnsByRef) { diagnostics.Add(Diagnostic.Create( RefReturnNotSupportedDescriptor, From 97b1fdc76c214efc1d2adf2c7cdc701b0a9b1a30 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 05:48:54 +0000 Subject: [PATCH 6/6] refactor(adapter): Use ContainsKey instead of TryGetValue for duplicate adapter check Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com> --- src/PatternKit.Generators/Adapter/AdapterGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PatternKit.Generators/Adapter/AdapterGenerator.cs b/src/PatternKit.Generators/Adapter/AdapterGenerator.cs index 41995da..85d8f5f 100644 --- a/src/PatternKit.Generators/Adapter/AdapterGenerator.cs +++ b/src/PatternKit.Generators/Adapter/AdapterGenerator.cs @@ -437,7 +437,7 @@ private void GenerateAdapterForAttribute( if (!generatedAdapters.ContainsKey(normalizedNs)) generatedAdapters[normalizedNs] = new Dictionary(); - if (generatedAdapters[normalizedNs].TryGetValue(adapterTypeName, out var existingLocation)) + if (generatedAdapters[normalizedNs].ContainsKey(adapterTypeName)) { context.ReportDiagnostic(Diagnostic.Create( TypeNameConflictDescriptor,