diff --git a/ReSharper.FSharp/src/FSharp/FSharp.Psi/src/Impl/Tree/AbstractMemberDeclaration.cs b/ReSharper.FSharp/src/FSharp/FSharp.Psi/src/Impl/Tree/AbstractMemberDeclaration.cs index 21a164143c..47a2d55b65 100644 --- a/ReSharper.FSharp/src/FSharp/FSharp.Psi/src/Impl/Tree/AbstractMemberDeclaration.cs +++ b/ReSharper.FSharp/src/FSharp/FSharp.Psi/src/Impl/Tree/AbstractMemberDeclaration.cs @@ -8,6 +8,7 @@ using JetBrains.ReSharper.Plugins.FSharp.Psi.Util; using JetBrains.ReSharper.Plugins.FSharp.Util; using JetBrains.ReSharper.Psi; +using JetBrains.Util; namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree { @@ -36,23 +37,21 @@ public bool HasDefaultImplementation private static bool CalcHasDefaultImplementation([CanBeNull] FSharpMemberOrFunctionOrValue mfv) { - if (mfv is not {IsDispatchSlot: true}) + if (mfv is not { IsDispatchSlot: true }) return false; - var mfvEntity = mfv.DeclaringEntity; + var mfvEntity = mfv.DeclaringEntity?.Value; if (mfvEntity == null) return false; var logicalName = mfv.LogicalName; - var mfvType = mfv.FullType.GenericArguments[1]; - return mfvEntity.Value.MembersFunctionsAndValues.Any(m => + return mfvEntity.MembersFunctionsAndValues.Any(m => m.IsOverrideOrExplicitInterfaceImplementation && logicalName == m.LogicalName && - (m.XmlDocSig == mfv.XmlDocSig && m.ImplementedAbstractSignatures.Count == 0 || - mfvType.Equals(m.FullType) && - m.ImplementedAbstractSignatures.Count == 1 && - m.ImplementedAbstractSignatures[0].DeclaringType.Equals(mfvEntity.Value.AsType()))); + m.XmlDocSig == mfv.XmlDocSig && + m.ImplementedAbstractSignatures.SingleItem() is { DeclaringType: { HasTypeDefinition: true } declaringType } && + declaringType.TypeDefinition.Equals(mfvEntity)); } protected override string DeclaredElementName => NameIdentifier.GetCompiledName(Attributes); diff --git a/ReSharper.FSharp/test/data/cache/csharpResolve/Members 02 - Virtual.cs b/ReSharper.FSharp/test/data/cache/csharpResolve/Members 02 - Virtual.cs new file mode 100644 index 0000000000..53dc90cdf1 --- /dev/null +++ b/ReSharper.FSharp/test/data/cache/csharpResolve/Members 02 - Virtual.cs @@ -0,0 +1,43 @@ +public class InheritAbstractClass : Module.AbstractClass; + +public class InheritAbstractClassOverrides : Module.AbstractClass +{ + public override void M1() => base.M1(); + public override void M2(int i) => base.M2(i); + public override void M3(int i) => base.M3(i); + public override void M4(P1 p1) => base.M4(p1); + public override int P1 { get; } +} + +public class InheritGenericAbstract : Module.GenericAbstractClass; + +public class InheritGenericAbstractOverrides : Module.GenericAbstractClass +{ + public override void M1() => base.M1(); + public override void M2(int i) => base.M2(i); + public override void M3(int i) => base.M3(i); + public override void M4(P1 p1) => base.M4(p1); + public override void M5(P1 p1, int i) => base.M5(p1, i); + public override int P1 { get; } +} + +public class InheritGeneric : Module.GenericClass; + +public class InheritGenericOverrides : Module.GenericClass +{ + public override void M() => base.M(); + public override void M2(int i) => base.M2(i); + public override void M3(int i) => base.M3(i); + public override void M4(int i) => base.M4(i); + public override void M5(P1 p1, int i) => base.M5(p1, i); +} + +public sealed class Counter; +public sealed class CounterState; + +public class InheritGenericCommand2 : Module.GenericAbstractClass2; + +public class InheritGenericCommand2Overrides : Module.GenericAbstractClass2 +{ + public override bool M(CounterState state, bool input) => base.M(state, input); +} diff --git a/ReSharper.FSharp/test/data/cache/csharpResolve/Members 02 - Virtual.fs b/ReSharper.FSharp/test/data/cache/csharpResolve/Members 02 - Virtual.fs new file mode 100644 index 0000000000..7f88c774ba --- /dev/null +++ b/ReSharper.FSharp/test/data/cache/csharpResolve/Members 02 - Virtual.fs @@ -0,0 +1,59 @@ +module Module + +[] +type AbstractClass() = + abstract member M1: unit -> unit + default this.M1() = () + + abstract member M2: int -> unit + default this.M2(i: int) = () + + abstract member M3<'P1>: int -> unit + default this.M3<'P1>(i: int) = () + + abstract member M4: 'P1 -> unit + default this.M4(p: 'P1) = () + + abstract member P1: int + default this.P1 = 1 + +[] +type GenericAbstractClass<'TOuter>() = + abstract member M1: unit -> unit + default this.M1() = () + + abstract member M2: int -> unit + default this.M2(i: int) = () + + abstract member M3<'P1>: int -> unit + default this.M3<'P1>(i: int) = () + + abstract member M4<'P1>: 'P1 -> unit + default this.M4<'P1>(i: 'P1) = () + + abstract member M5<'P1>: 'P1 * 'TOuter -> unit + default this.M5<'P1>(i1: 'P1, i2: 'TOuter) = () + + abstract member P1: 'TOuter + default this.P1 = Unchecked.defaultof<'TOuter> + +[] +type GenericAbstractClass2<'TSystem, 'TState, 'TInput, 'TOutput>() = + abstract member M: state: 'TState * input: 'TInput -> bool + default this.M(_, _) = true + +type GenericClass<'TOuter>() = + abstract member M: unit -> unit + default this.M() = () + + abstract member M2: int -> unit + default this.M2(i: int) = () + + abstract member M3<'P1>: int -> unit + default this.M3<'P1>(i: int) = () + + abstract member M4: 'TOuter -> unit + default this.M4(p: 'TOuter) = () + + abstract member M5<'P1>: 'P1 * 'TOuter -> unit + default this.M5<'P1>(i1: 'P1, i2: 'TOuter) = () diff --git a/ReSharper.FSharp/test/data/cache/csharpResolve/Members 02 - Virtual.gold b/ReSharper.FSharp/test/data/cache/csharpResolve/Members 02 - Virtual.gold new file mode 100644 index 0000000000..343dcd999b --- /dev/null +++ b/ReSharper.FSharp/test/data/cache/csharpResolve/Members 02 - Virtual.gold @@ -0,0 +1,75 @@ +public class InheritAbstractClass : Module.AbstractClass; + +public class InheritAbstractClassOverrides : Module.AbstractClass +{ + public override void M1() => base.M1(); + public override void M2(int i) => base.M2(i); + public override void M3(int i) => base.M3(i); + public override void M4(P1 p1) => base.M4(p1); + public override int P1 { get; } +} + +public class InheritGenericAbstract : Module.GenericAbstractClass; + +public class InheritGenericAbstractOverrides : Module.GenericAbstractClass +{ + public override void M1() => base.M1(); + public override void M2(int i) => base.M2(i); + public override void M3(int i) => base.M3(i); + public override void M4(P1 p1) => base.M4(p1); + public override void M5(P1 p1, int i) => base.M5(p1, i); + public override int P1 { get; } +} + +public class InheritGeneric : Module.GenericClass; + +public class InheritGenericOverrides : Module.GenericClass +{ + public override void M() => base.M(); + public override void M2(int i) => base.M2(i); + public override void M3(int i) => base.M3(i); + public override void M4(int i) => base.M4(i); + public override void M5(P1 p1, int i) => base.M5(p1, i); +} + +public sealed class Counter; +public sealed class CounterState; + +public class InheritGenericCommand2 : Module.GenericAbstractClass2; + +public class InheritGenericCommand2Overrides : Module.GenericAbstractClass2 +{ + public override bool M(CounterState state, bool input) => base.M(state, input); +} + +--------------------------------------------------------- +M:Module.AbstractClass.M1 +M:Module.AbstractClass.M1 +M:Module.AbstractClass.M2(System.Int32) +M:Module.AbstractClass.M2(System.Int32) +M:Module.AbstractClass.M3``1(System.Int32) +M:Module.AbstractClass.M3``1(System.Int32) +M:Module.AbstractClass.M4``1(`0) +M:Module.AbstractClass.M4``1(`0) +M:Module.GenericAbstractClass`1.M1 +M:Module.GenericAbstractClass`1.M1 +M:Module.GenericAbstractClass`1.M2(System.Int32) +M:Module.GenericAbstractClass`1.M2(System.Int32) +M:Module.GenericAbstractClass`1.M3``1(System.Int32) +M:Module.GenericAbstractClass`1.M3``1(System.Int32) +M:Module.GenericAbstractClass`1.M4``1(`0) +M:Module.GenericAbstractClass`1.M4``1(`0) +M:Module.GenericAbstractClass`1.M5``1(`0,`0) +M:Module.GenericAbstractClass`1.M5``1(`0,`0) +M:Module.GenericClass`1.M +M:Module.GenericClass`1.M +M:Module.GenericClass`1.M2(System.Int32) +M:Module.GenericClass`1.M2(System.Int32) +M:Module.GenericClass`1.M3``1(System.Int32) +M:Module.GenericClass`1.M3``1(System.Int32) +M:Module.GenericClass`1.M4(`0) +M:Module.GenericClass`1.M4(`0) +M:Module.GenericClass`1.M5``1(`0,`0) +M:Module.GenericClass`1.M5``1(`0,`0) +M:Module.GenericAbstractClass2`4.M(`1,`2) +M:Module.GenericAbstractClass2`4.M(`1,`2) diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Cache/CSharpResolveTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Cache/CSharpResolveTest.fs index 00ca5b7c3f..84af3c4f2f 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Cache/CSharpResolveTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Cache/CSharpResolveTest.fs @@ -74,6 +74,7 @@ type CSharpResolveTest() = [] member x.``Auto properties 02, compiled name``() = x.DoNamedTest() [] member x.``Members 01 - Virtual``() = x.DoNamedTest() + [] member x.``Members 02 - Virtual``() = x.DoNamedTest() [] member x.``Methods 01``() = x.DoNamedTest() [] member x.``Methods 02, compiled name``() = x.DoNamedTest()