From 83080f94fd0b46cc91239cba314452f5928cf1dd Mon Sep 17 00:00:00 2001 From: Beakona Date: Thu, 7 Dec 2023 23:28:28 +0100 Subject: [PATCH] Invalid interface/property match in AllowMissingMembers mode. --- AutoInterfaceSample/Program.cs | 15 +++++++- .../AutoInterfaceSourceGenerator.cs | 10 ++--- .../BeaKona.AutoInterfaceGenerator.csproj | 2 +- .../ComparerBySignature.cs | 37 +++++++++++++++++-- .../ITypeSymbolExtensions.cs | 12 +++--- 5 files changed, 60 insertions(+), 16 deletions(-) diff --git a/AutoInterfaceSample/Program.cs b/AutoInterfaceSample/Program.cs index c8cec6c..d299b4c 100644 --- a/AutoInterfaceSample/Program.cs +++ b/AutoInterfaceSample/Program.cs @@ -12,7 +12,9 @@ public static void Main() //int g = 1; //p.Method(1, out f, ref g, "t", 1, 2, 3); - //IPrintableComplex p = new Person2(); + IPrintableComplex p = new Person2(); + //var c = p.Count; + p.Count = 3; //p.Print(); //p.PrintComplex(); } @@ -22,12 +24,23 @@ interface IPrintableComplex { void Print(); void PrintComplex(); + int Count { set; } } public class SimplePrinter // : IPrintableComplex { public void Print() { Console.WriteLine("OK"); } public void PrintComplex() { Console.WriteLine("OKC"); } + public int Count + { + get + { + return 0; + } + set + { + } + } } public partial class Person2 /*: IPrintableComplex*/ diff --git a/BeaKona.AutoInterfaceGenerator/AutoInterfaceSourceGenerator.cs b/BeaKona.AutoInterfaceGenerator/AutoInterfaceSourceGenerator.cs index 072190b..e41967f 100644 --- a/BeaKona.AutoInterfaceGenerator/AutoInterfaceSourceGenerator.cs +++ b/BeaKona.AutoInterfaceGenerator/AutoInterfaceSourceGenerator.cs @@ -534,8 +534,8 @@ private static bool IsDuckImplementation(ITypeSymbol receiverType, ITypeSymbol i } else { - return receiverType.IsAllInterfaceMembersImplementedBySignature(interfaceType) && - (includeBaseInterfaces == false || interfaceType.AllInterfaces.All(i => receiverType.IsMatchByTypeOrImplementsInterface(i) || receiverType.IsAllInterfaceMembersImplementedBySignature(i))); + return receiverType.IsAllInterfaceMembersImplementedBySignature(interfaceType, true) && + (includeBaseInterfaces == false || interfaceType.AllInterfaces.All(i => receiverType.IsMatchByTypeOrImplementsInterface(i) || receiverType.IsAllInterfaceMembersImplementedBySignature(i, true))); } } @@ -619,14 +619,14 @@ bool ShouldGenerate(ISymbol member) { if (reference.AllowMissingMembers) { - if (reference.ReceiverType.IsMemberImplementedBySignature(member) == false) + if (reference.ReceiverType.IsMemberImplementedBySignature(member, false) == false) { return false; } } } - var memberImplementedBySignature = type.IsMemberImplementedBySignature(member); + var memberImplementedBySignature = type.IsMemberImplementedBySignature(member, true); var memberImplementedExplicitly = type.IsMemberImplementedExplicitly(member); foreach (var reference in references) @@ -645,7 +645,7 @@ bool ShouldBeReferenced(ISymbol member, IMemberInfo reference) if (reference.AllowMissingMembers) { //AllowMissingMembers case - return reference.ReceiverType.IsMemberImplementedBySignature(member); + return reference.ReceiverType.IsMemberImplementedBySignature(member, false); } else { diff --git a/BeaKona.AutoInterfaceGenerator/BeaKona.AutoInterfaceGenerator.csproj b/BeaKona.AutoInterfaceGenerator/BeaKona.AutoInterfaceGenerator.csproj index afeb031..a8cf1d8 100644 --- a/BeaKona.AutoInterfaceGenerator/BeaKona.AutoInterfaceGenerator.csproj +++ b/BeaKona.AutoInterfaceGenerator/BeaKona.AutoInterfaceGenerator.csproj @@ -13,7 +13,7 @@ https://github.com/beakona/AutoInterface git $(TargetsForTfmSpecificContentInPackage);_AddAnalyzersToOutput - 1.0.34 + 1.0.35 true true diff --git a/BeaKona.AutoInterfaceGenerator/ComparerBySignature.cs b/BeaKona.AutoInterfaceGenerator/ComparerBySignature.cs index 2fc3679..88d61a6 100644 --- a/BeaKona.AutoInterfaceGenerator/ComparerBySignature.cs +++ b/BeaKona.AutoInterfaceGenerator/ComparerBySignature.cs @@ -2,6 +2,12 @@ internal sealed class ComparerBySignature : IEqualityComparer { + public ComparerBySignature(bool strict) + { + this.strict = strict; + } + + private readonly bool strict; private readonly Dictionary> aliasesByKey = new(SymbolEqualityComparer.Default); public int GetHashCode(ISymbol obj) => throw new NotSupportedException();//SymbolEqualityComparer.Default.GetHashCode(obj); @@ -108,9 +114,34 @@ public bool Equals(ISymbol s1, ISymbol s2) { if (this.Equals(v1.Type, v2.Type)) { - static bool HasGetter(IPropertySymbol p) => p.GetMethod != null; - static bool HasSetter(IPropertySymbol p) => p.SetMethod != null; - if (HasGetter(v1) == HasGetter(v2) && HasSetter(v1) == HasSetter(v2)) + static bool IsMatch(IPropertySymbol x, IPropertySymbol y, bool strict) + { + static bool HasGetter(IPropertySymbol p) => p.GetMethod != null; + static bool HasSetter(IPropertySymbol p) => p.SetMethod != null; + + var hasGetter = HasGetter(x); + var requireGetter = HasGetter(y); + var hasSetter = HasSetter(x); + var requireSetter = HasSetter(y); + + if (strict) + { + return hasGetter == requireGetter && hasSetter == requireSetter; + } + else + { + if ((requireGetter && hasGetter == false) || (requireSetter && hasSetter == false)) + { + return false; + } + else + { + return true; + } + } + } + + if (IsMatch(v1, v2, this.strict)) { if (v1.IsIndexer) { diff --git a/BeaKona.AutoInterfaceGenerator/ITypeSymbolExtensions.cs b/BeaKona.AutoInterfaceGenerator/ITypeSymbolExtensions.cs index c24e3ce..808e48b 100644 --- a/BeaKona.AutoInterfaceGenerator/ITypeSymbolExtensions.cs +++ b/BeaKona.AutoInterfaceGenerator/ITypeSymbolExtensions.cs @@ -83,14 +83,14 @@ public static bool IsMemberImplementedExplicitly(this ITypeSymbol @this, ISymbol // return implementation is not null && implementation.IsStatic == false && implementation.ContainingType.Equals(@this, SymbolEqualityComparer.Default); //} - public static ISymbol? FindImplementationForInterfaceMemberBySignature(this ITypeSymbol @this, ISymbol interfaceMember) + public static ISymbol? FindImplementationForInterfaceMemberBySignature(this ITypeSymbol @this, ISymbol interfaceMember, bool strict) { string name = interfaceMember.Name; if (string.IsNullOrEmpty(name) == false) { foreach (ISymbol member in @this.GetMembers(name).Where(i => i.Kind == interfaceMember.Kind)) { - var comparer = new ComparerBySignature(); + var comparer = new ComparerBySignature(strict); if (comparer.Equals(member, interfaceMember)) { return member; @@ -101,12 +101,12 @@ public static bool IsMemberImplementedExplicitly(this ITypeSymbol @this, ISymbol return null; } - public static bool IsMemberImplementedBySignature(this ITypeSymbol @this, ISymbol member) + public static bool IsMemberImplementedBySignature(this ITypeSymbol @this, ISymbol member, bool strict) { - return @this.FindImplementationForInterfaceMemberBySignature(member) != null; + return @this.FindImplementationForInterfaceMemberBySignature(member, strict) != null; } - public static bool IsAllInterfaceMembersImplementedBySignature(this ITypeSymbol @this, ITypeSymbol @interface) + public static bool IsAllInterfaceMembersImplementedBySignature(this ITypeSymbol @this, ITypeSymbol @interface, bool strict) { if (@interface.TypeKind != TypeKind.Interface) { @@ -115,7 +115,7 @@ public static bool IsAllInterfaceMembersImplementedBySignature(this ITypeSymbol foreach (var member in @interface.GetMembers()) { - if (@this.IsMemberImplementedBySignature(member) == false) + if (@this.IsMemberImplementedBySignature(member, strict) == false) { return false; }