diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/MaintainabilityRules/SA1414CSharp7UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/MaintainabilityRules/SA1414CSharp7UnitTests.cs index 4c9543c85..569492f1f 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/MaintainabilityRules/SA1414CSharp7UnitTests.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/MaintainabilityRules/SA1414CSharp7UnitTests.cs @@ -5,6 +5,7 @@ namespace StyleCop.Analyzers.Test.CSharp7.MaintainabilityRules { + using System; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Testing; @@ -117,5 +118,61 @@ public static explicit operator TestClass({typeExpression} p1) await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false); } + + [Fact] + public async Task ValidateTuplesFromInterfaceAsync() + { + const string testCode = @" +using System.Collections.Generic; + +namespace Test { + class StringTupleComparer : IEqualityComparer<(string, string)> + { + public bool Equals((string, string) x, (string, string) y) => throw null; + + public int GetHashCode((string, string) obj) => throw null; + } +}"; + await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + } + + [Fact] + public async Task ValidateTuplesFromExplicitInterfaceImplementationAsync() + { + const string testCode = @" +using System.Collections.Generic; + +namespace Test { + class StringTupleComparer : IEqualityComparer<(string, string)> + { + bool IEqualityComparer<(string, string)>.Equals((string, string) x, (string, string) y) => throw null; + + int IEqualityComparer<(string, string)>.GetHashCode((string, string) obj) => throw null; + } +}"; + await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + } + + [Fact] + public async Task ValidateTuplesFromBaseClassAsync() + { + const string testCode = @" +namespace Test { + class A : B + { + public override (string, string) Run((string, string) x) => throw null; + + public override (int, int) Run((int, int) y) => throw null; + } + + abstract class B + { + public abstract ([|string|], [|string|]) Run(([|string|], [|string|]) x); + + public virtual ([|int|], [|int|]) Run(([|int|], [|int|]) y) => throw null; + } +}"; + await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + } } } diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1414TupleTypesInSignaturesShouldHaveElementNames.cs b/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1414TupleTypesInSignaturesShouldHaveElementNames.cs index 27afb2d93..0105c038a 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1414TupleTypesInSignaturesShouldHaveElementNames.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1414TupleTypesInSignaturesShouldHaveElementNames.cs @@ -7,6 +7,7 @@ namespace StyleCop.Analyzers.MaintainabilityRules { using System; using System.Collections.Immutable; + using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -62,6 +63,10 @@ private static void HandleMethodDeclaration(SyntaxNodeAnalysisContext context) } var methodDeclaration = (MethodDeclarationSyntax)context.Node; + if (methodDeclaration.Modifiers.Any(SyntaxKind.OverrideKeyword)) + { + return; + } CheckType(context, methodDeclaration.ReturnType); CheckParameterList(context, methodDeclaration.ParameterList); @@ -161,7 +166,7 @@ private static void CheckTupleType(SyntaxNodeAnalysisContext context, TupleTypeS { CheckType(context, tupleElementSyntax.Type); - if (tupleElementSyntax.Identifier.IsKind(SyntaxKind.None)) + if (tupleElementSyntax.Identifier.IsKind(SyntaxKind.None) && !NamedTypeHelpers.IsImplementingAnInterfaceMember(context.SemanticModel.GetDeclaredSymbol(context.Node))) { var location = tupleElementSyntax.SyntaxNode.GetLocation(); context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));