diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/NamingRules/RenameToAnyCodeFixProvider.cs b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/NamingRules/RenameToAnyCodeFixProvider.cs
new file mode 100644
index 000000000..484a745d5
--- /dev/null
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/NamingRules/RenameToAnyCodeFixProvider.cs
@@ -0,0 +1,82 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
+
+namespace StyleCop.Analyzers.NamingRules
+{
+ using System.Collections.Immutable;
+ using System.Composition;
+ using System.Threading.Tasks;
+ using Helpers;
+ using Microsoft.CodeAnalysis;
+ using Microsoft.CodeAnalysis.CodeActions;
+ using Microsoft.CodeAnalysis.CodeFixes;
+ using Microsoft.CodeAnalysis.CSharp;
+
+ ///
+ /// Implements a code fix for diagnostics which are fixed by renaming a symbol to a set of given new names.
+ ///
+ ///
+ /// To fix a violation of this rule, change the name of the symbol so that it is one of the set of new names.
+ ///
+ [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(RenameToAnyCodeFixProvider))]
+ [Shared]
+ internal class RenameToAnyCodeFixProvider : CodeFixProvider
+ {
+ private static char[] comma = { ',' };
+
+ ///
+ public override ImmutableArray FixableDiagnosticIds { get; } =
+ ImmutableArray.Create(
+ SA1314ParametersShouldMatchInheritedNames.DiagnosticId);
+
+ ///
+ public override FixAllProvider GetFixAllProvider()
+ {
+ return CustomFixAllProviders.BatchFixer;
+ }
+
+ ///
+ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var document = context.Document;
+ var root = await document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+
+ foreach (var diagnostic in context.Diagnostics)
+ {
+ var token = root.FindToken(diagnostic.Location.SourceSpan.Start);
+ if (string.IsNullOrEmpty(token.ValueText))
+ {
+ continue;
+ }
+
+ var originalName = token.ValueText;
+
+ var memberSyntax = RenameHelper.GetParentDeclaration(token);
+
+ SemanticModel semanticModel = await document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);
+
+ var declaredSymbol = semanticModel.GetDeclaredSymbol(memberSyntax);
+ if (declaredSymbol == null)
+ {
+ continue;
+ }
+
+ string[] newNames = diagnostic.Properties[nameof(newNames)].Split(comma);
+ foreach (var newName in newNames)
+ {
+ if (!await RenameHelper.IsValidNewMemberNameAsync(semanticModel, declaredSymbol, newName, context.CancellationToken).ConfigureAwait(false))
+ {
+ continue;
+ }
+
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ string.Format(NamingResources.RenameToCodeFix, newName),
+ cancellationToken => RenameHelper.RenameSymbolAsync(document, root, token, newName, cancellationToken),
+ nameof(RenameToAnyCodeFixProvider) + newName),
+ diagnostic);
+ }
+ }
+ }
+ }
+}
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/StyleCop.Analyzers.CodeFixes.csproj b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/StyleCop.Analyzers.CodeFixes.csproj
index 34f5504ae..23bab45b2 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/StyleCop.Analyzers.CodeFixes.csproj
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/StyleCop.Analyzers.CodeFixes.csproj
@@ -96,6 +96,7 @@
+
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/NamingRules/SA1314UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/NamingRules/SA1314UnitTests.cs
new file mode 100644
index 000000000..1d2d361df
--- /dev/null
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/NamingRules/SA1314UnitTests.cs
@@ -0,0 +1,297 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
+
+namespace StyleCop.Analyzers.Test.NamingRules
+{
+ using System.Collections.Generic;
+ using System.Threading;
+ using System.Threading.Tasks;
+ using Microsoft.CodeAnalysis.CodeFixes;
+ using Microsoft.CodeAnalysis.Diagnostics;
+ using StyleCop.Analyzers.NamingRules;
+ using TestHelper;
+ using Xunit;
+ using Microsoft.CodeAnalysis;
+ public class SA1314UnitTests : CodeFixVerifier
+ {
+ [Fact]
+ public async Task TestThatDiagnosticIsNotReportedForMethodWithoutArgumentsAsync()
+ {
+ var testCode = @"public class TypeName
+{
+ public void AMethod() { }
+}";
+
+ await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestThatDiagnosticIsNotReportedForMethodWithoutInheritNamesAsync()
+ {
+ var testCode = @"public class TypeName
+{
+ public void AMethod(string arg1, string arg2) { }
+}";
+
+ await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestThatDiagnosticIsNotReportedForMethodWithoutInheritNamesAndArglistAsync()
+ {
+ var testCode = @"public class TypeName
+{
+ public void AMethod(string arg1, string arg2, __arglist) { }
+}";
+
+ await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestThatDiagnosticIsNotReportedForMethodWithoutInheritNamesAnParamsAsync()
+ {
+ var testCode = @"public class TypeName
+{
+ public void AMethod(string arg1, string arg2, params string[] arg3) { }
+}";
+
+ await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestThatDiagnosticIsReportedForMethodWithInheritNamesAsync()
+ {
+ var testCode = @"public class TypeName : BaseClass
+{
+ public override void AMethod(string arg1, string arg2) { }
+}
+
+public abstract class BaseClass
+{
+ public abstract void AMethod(string baseArg1, string baseArg2);
+}";
+
+ var fixedCode = @"public class TypeName : BaseClass
+{
+ public override void AMethod(string baseArg1, string baseArg2) { }
+}
+
+public abstract class BaseClass
+{
+ public abstract void AMethod(string baseArg1, string baseArg2);
+}";
+
+ var expected = new[]
+ {
+ this.CSharpDiagnostic().WithLocation(3, 41),
+ this.CSharpDiagnostic().WithLocation(3, 54)
+ };
+
+ await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
+ await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
+ await this.VerifyCSharpFixAsync(testCode, fixedCode, numberOfFixAllIterations: 2).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestThatDiagnosticIsReportedForMethodWithInheritNamesAndArglistAsync()
+ {
+ var testCode = @"public class TypeName : BaseClass
+{
+ public override void AMethod(string arg1, string arg2, __arglist) { }
+}
+
+public abstract class BaseClass
+{
+ public abstract void AMethod(string baseArg1, string baseArg2, __arglist);
+}";
+
+ var fixedCode = @"public class TypeName : BaseClass
+{
+ public override void AMethod(string baseArg1, string baseArg2, __arglist) { }
+}
+
+public abstract class BaseClass
+{
+ public abstract void AMethod(string baseArg1, string baseArg2, __arglist);
+}";
+
+ var expected = new[]
+ {
+ this.CSharpDiagnostic().WithLocation(3, 41),
+ this.CSharpDiagnostic().WithLocation(3, 54)
+ };
+
+ await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
+ await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
+ await this.VerifyCSharpFixAsync(testCode, fixedCode, numberOfFixAllIterations: 2).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestThatDiagnosticIsReportedForMethodWithInheritNamesAnParamsAsync()
+ {
+ var testCode = @"public class TypeName : BaseClass
+{
+ public override void AMethod(string arg1, string arg2, params string[] arg3) { }
+}
+
+public abstract class BaseClass
+{
+ public abstract void AMethod(string baseArg1, string baseArg2, params string[] baseArg3);
+}";
+
+ var fixedCode = @"public class TypeName : BaseClass
+{
+ public override void AMethod(string baseArg1, string baseArg2, params string[] baseArg3) { }
+}
+
+public abstract class BaseClass
+{
+ public abstract void AMethod(string baseArg1, string baseArg2, params string[] baseArg3);
+}";
+
+ var expected = new[]
+ {
+ this.CSharpDiagnostic().WithLocation(3, 41),
+ this.CSharpDiagnostic().WithLocation(3, 54),
+ this.CSharpDiagnostic().WithLocation(3, 76)
+ };
+
+ await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
+ await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
+ await this.VerifyCSharpFixAsync(testCode, fixedCode, numberOfFixAllIterations: 3).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestThatDiagnosticIsReportedForMethodWithInheritNamesWithInterfaceAsync()
+ {
+ var testCode = @"public class TypeName : IBase
+{
+ public void AMethod(string arg1, string arg2) { }
+}
+
+public interface IBase
+{
+ void AMethod(string baseArg1, string baseArg2);
+}";
+
+ var fixedCode = @"public class TypeName : IBase
+{
+ public void AMethod(string baseArg1, string baseArg2) { }
+}
+
+public interface IBase
+{
+ void AMethod(string baseArg1, string baseArg2);
+}";
+
+ var expected = new[]
+ {
+ this.CSharpDiagnostic().WithLocation(3, 32),
+ this.CSharpDiagnostic().WithLocation(3, 45)
+ };
+
+ await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
+ await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
+ await this.VerifyCSharpFixAsync(testCode, fixedCode, numberOfFixAllIterations: 2).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestThatDiagnosticIsReportedForMethodWithInheritNamesAndArglistWithInterfaceAsync()
+ {
+ var testCode = @"public class TypeName : IBase
+{
+ public void AMethod(string arg1, string arg2, __arglist) { }
+}
+
+public interface IBase
+{
+ void AMethod(string baseArg1, string baseArg2, __arglist);
+}";
+
+ var fixedCode = @"public class TypeName : IBase
+{
+ public void AMethod(string baseArg1, string baseArg2, __arglist) { }
+}
+
+public interface IBase
+{
+ void AMethod(string baseArg1, string baseArg2, __arglist);
+}";
+
+ var expected = new[]
+ {
+ this.CSharpDiagnostic().WithLocation(3, 32),
+ this.CSharpDiagnostic().WithLocation(3, 45)
+ };
+
+ await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
+ await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
+ await this.VerifyCSharpFixAsync(testCode, fixedCode, numberOfFixAllIterations: 2).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestThatDiagnosticIsReportedForMethodWithInheritNamesAnParamsWithInterfaceAsync()
+ {
+ var testCode = @"public class TypeName : IBase
+{
+ public void AMethod(string arg1, string arg2, params string[] arg3) { }
+}
+
+public interface IBase
+{
+ void AMethod(string baseArg1, string baseArg2, params string[] baseArg3);
+}";
+
+ var fixedCode = @"public class TypeName : IBase
+{
+ public void AMethod(string baseArg1, string baseArg2, params string[] baseArg3) { }
+}
+
+public interface IBase
+{
+ void AMethod(string baseArg1, string baseArg2, params string[] baseArg3);
+}";
+
+ var expected = new[]
+ {
+ this.CSharpDiagnostic().WithLocation(3, 32),
+ this.CSharpDiagnostic().WithLocation(3, 45),
+ this.CSharpDiagnostic().WithLocation(3, 67)
+ };
+
+ await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
+ await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
+ await this.VerifyCSharpFixAsync(testCode, fixedCode, numberOfFixAllIterations: 3).ConfigureAwait(false);
+ }
+
+ [Fact]
+ public async Task TestThatDiagnosticIsNotReportedForInvalidOverrideAsync()
+ {
+ var testCode = @"public class TypeName
+{
+ public override void AMethod(string arg1, string arg2, params string[] arg3) { }
+}";
+
+ var expected =
+ new DiagnosticResult
+ {
+ Id = "CS0115",
+ Severity = DiagnosticSeverity.Error,
+ Message = "'TypeName.AMethod(string, string, params string[])': no suitable method found to override",
+ Locations = new[] { new DiagnosticResultLocation("Test0.cs", 3, 26) }
+ };
+
+ await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ protected override IEnumerable GetCSharpDiagnosticAnalyzers()
+ {
+ yield return new SA1314ParametersShouldMatchInheritedNames();
+ }
+
+ protected override CodeFixProvider GetCSharpCodeFixProvider()
+ {
+ return new RenameToAnyCodeFixProvider();
+ }
+ }
+}
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/StyleCop.Analyzers.Test.csproj b/StyleCop.Analyzers/StyleCop.Analyzers.Test/StyleCop.Analyzers.Test.csproj
index 9f69ba3fe..04a039f6d 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/StyleCop.Analyzers.Test.csproj
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/StyleCop.Analyzers.Test.csproj
@@ -265,6 +265,7 @@
+
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Helpers/NamedTypeHelpers.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Helpers/NamedTypeHelpers.cs
index 56050aec6..2c4b30f84 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/Helpers/NamedTypeHelpers.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/Helpers/NamedTypeHelpers.cs
@@ -4,6 +4,7 @@
namespace StyleCop.Analyzers.Helpers
{
using System;
+ using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -151,5 +152,25 @@ internal static bool IsImplementingAnInterfaceMember(ISymbol memberSymbol)
.Select(typeSymbol.FindImplementationForInterfaceMember)
.Any(x => memberSymbol.Equals(x));
}
+
+ internal static void GetOriginalDefinitions(List originalDefinitions, IMethodSymbol memberSymbol)
+ {
+ if (memberSymbol.IsOverride && memberSymbol.OverriddenMethod != null)
+ {
+ originalDefinitions.Add(memberSymbol.OverriddenMethod);
+ }
+
+ if (memberSymbol.ExplicitInterfaceImplementations.Length > 0)
+ {
+ originalDefinitions.AddRange(memberSymbol.ExplicitInterfaceImplementations);
+ }
+
+ var typeSymbol = memberSymbol.ContainingType;
+
+ originalDefinitions.AddRange(typeSymbol.AllInterfaces
+ .SelectMany(m => m.GetMembers(memberSymbol.Name))
+ .Where(m => typeSymbol.FindImplementationForInterfaceMember(m) != null)
+ .Cast());
+ }
}
}
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/NamingResources.Designer.cs b/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/NamingResources.Designer.cs
index fb46a7fff..a970ed8de 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/NamingResources.Designer.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/NamingResources.Designer.cs
@@ -1,10 +1,10 @@
//------------------------------------------------------------------------------
//
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.42000
+// Dieser Code wurde von einem Tool generiert.
+// Laufzeitversion:4.0.30319.42000
//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
+// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
+// der Code erneut generiert wird.
//
//------------------------------------------------------------------------------
@@ -14,12 +14,12 @@ namespace StyleCop.Analyzers.NamingRules {
///
- /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
///
- // This class was auto-generated by the StronglyTypedResourceBuilder
- // class via a tool like ResGen or Visual Studio.
- // To add or remove a member, edit your .ResX file then rerun ResGen
- // with the /str option, or rebuild your VS project.
+ // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
+ // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
+ // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
+ // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
@@ -34,7 +34,7 @@ internal NamingResources() {
}
///
- /// Returns the cached ResourceManager instance used by this class.
+ /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
///
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
@@ -48,8 +48,8 @@ internal NamingResources() {
}
///
- /// Overrides the current thread's CurrentUICulture property for all
- /// resource lookups using this strongly typed resource class.
+ /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
+ /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
///
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
@@ -62,7 +62,7 @@ internal NamingResources() {
}
///
- /// Looks up a localized string similar to Rename To '{0}'.
+ /// Sucht eine lokalisierte Zeichenfolge, die Rename To '{0}' ähnelt.
///
internal static string RenameToCodeFix {
get {
@@ -71,7 +71,7 @@ internal static string RenameToCodeFix {
}
///
- /// Looks up a localized string similar to Prefix interface name with 'I'.
+ /// Sucht eine lokalisierte Zeichenfolge, die Prefix interface name with 'I' ähnelt.
///
internal static string SA1302CodeFix {
get {
@@ -80,7 +80,7 @@ internal static string SA1302CodeFix {
}
///
- /// Looks up a localized string similar to The name of a variable in C# does not begin with a lower-case letter..
+ /// Sucht eine lokalisierte Zeichenfolge, die The name of a variable in C# does not begin with a lower-case letter. ähnelt.
///
internal static string SA1312Description {
get {
@@ -89,7 +89,7 @@ internal static string SA1312Description {
}
///
- /// Looks up a localized string similar to Variable '{0}' must begin with lower-case letter.
+ /// Sucht eine lokalisierte Zeichenfolge, die Variable '{0}' must begin with lower-case letter ähnelt.
///
internal static string SA1312MessageFormat {
get {
@@ -98,7 +98,7 @@ internal static string SA1312MessageFormat {
}
///
- /// Looks up a localized string similar to Variable names must begin with lower-case letter.
+ /// Sucht eine lokalisierte Zeichenfolge, die Variable names must begin with lower-case letter ähnelt.
///
internal static string SA1312Title {
get {
@@ -107,7 +107,7 @@ internal static string SA1312Title {
}
///
- /// Looks up a localized string similar to The name of a parameter in C# does not begin with a lower-case letter..
+ /// Sucht eine lokalisierte Zeichenfolge, die The name of a parameter in C# does not begin with a lower-case letter. ähnelt.
///
internal static string SA1313Description {
get {
@@ -116,7 +116,7 @@ internal static string SA1313Description {
}
///
- /// Looks up a localized string similar to Parameter '{0}' must begin with lower-case letter.
+ /// Sucht eine lokalisierte Zeichenfolge, die Parameter '{0}' must begin with lower-case letter ähnelt.
///
internal static string SA1313MessageFormat {
get {
@@ -125,12 +125,39 @@ internal static string SA1313MessageFormat {
}
///
- /// Looks up a localized string similar to Parameter names must begin with lower-case letter.
+ /// Sucht eine lokalisierte Zeichenfolge, die Parameter names must begin with lower-case letter ähnelt.
///
internal static string SA1313Title {
get {
return ResourceManager.GetString("SA1313Title", resourceCulture);
}
}
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die When a method overrides a method from a base class, or implements an interface method, the parameter names of the overriding method should match the names in the base definition. ähnelt.
+ ///
+ internal static string SA1314Description {
+ get {
+ return ResourceManager.GetString("SA1314Description", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Parameters should match inherited names ähnelt.
+ ///
+ internal static string SA1314MessageFormat {
+ get {
+ return ResourceManager.GetString("SA1314MessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Parameters should match inherited names ähnelt.
+ ///
+ internal static string SA1314Title {
+ get {
+ return ResourceManager.GetString("SA1314Title", resourceCulture);
+ }
+ }
}
}
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/NamingResources.resx b/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/NamingResources.resx
index 3e857f5d3..115e5cbb7 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/NamingResources.resx
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/NamingResources.resx
@@ -141,4 +141,13 @@
Parameter names must begin with lower-case letter
+
+ When a method overrides a method from a base class, or implements an interface method, the parameter names of the overriding method should match the names in the base definition.
+
+
+ Parameters should match inherited names
+
+
+ Parameters should match inherited names
+
\ No newline at end of file
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/SA1314ParametersShouldMatchInheritedNames.cs b/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/SA1314ParametersShouldMatchInheritedNames.cs
new file mode 100644
index 000000000..9c2d17c1d
--- /dev/null
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/SA1314ParametersShouldMatchInheritedNames.cs
@@ -0,0 +1,120 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
+
+namespace StyleCop.Analyzers.NamingRules
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.Immutable;
+ using System.Linq;
+ using Helpers;
+ using Helpers.ObjectPools;
+ using Microsoft.CodeAnalysis;
+ using Microsoft.CodeAnalysis.Diagnostics;
+
+ ///
+ /// Parameters should match inherited names
+ ///
+ ///
+ /// A violation of this rule occurs when the name of a parameter does not match its inherited name.
+ ///
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ internal class SA1314ParametersShouldMatchInheritedNames : DiagnosticAnalyzer
+ {
+ ///
+ /// The ID for diagnostics produced by the analyzer.
+ ///
+ public const string DiagnosticId = "SA1314";
+ private static readonly LocalizableString Title = new LocalizableResourceString(nameof(NamingResources.SA1314Title), NamingResources.ResourceManager, typeof(NamingResources));
+ private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(NamingResources.SA1314MessageFormat), NamingResources.ResourceManager, typeof(NamingResources));
+ private static readonly LocalizableString Description = new LocalizableResourceString(nameof(NamingResources.SA1314Description), NamingResources.ResourceManager, typeof(NamingResources));
+ private static readonly string HelpLink = "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1314.md";
+
+ private static readonly DiagnosticDescriptor Descriptor =
+ new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.NamingRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink);
+
+ private static readonly Action CompilationStartAction = HandleCompilationStart;
+ private static readonly Action HandleMethodAction = HandleMethod;
+
+ ///
+ public override ImmutableArray SupportedDiagnostics { get; } =
+ ImmutableArray.Create(Descriptor);
+
+ ///
+ public override void Initialize(AnalysisContext context)
+ {
+ context.RegisterCompilationStartAction(CompilationStartAction);
+ }
+
+ private static void HandleCompilationStart(CompilationStartAnalysisContext context)
+ {
+ context.RegisterSymbolAction(HandleMethodAction, SymbolKind.Method);
+ }
+
+ private static void HandleMethod(SymbolAnalysisContext context)
+ {
+ var symbol = context.Symbol as IMethodSymbol;
+
+ if (!symbol.IsOverride && !NamedTypeHelpers.IsImplementingAnInterfaceMember(symbol))
+ {
+ return;
+ }
+
+ if (!symbol.CanBeReferencedByName
+ || !symbol.Locations.Any(x => x.IsInSource)
+ || string.IsNullOrWhiteSpace(symbol.Name))
+ {
+ return;
+ }
+
+ var pool = SharedPools.Default>();
+
+ using (var pooledObject = pool.GetPooledObject())
+ {
+ var originalDefinitions = pooledObject.Object;
+ NamedTypeHelpers.GetOriginalDefinitions(originalDefinitions, symbol);
+
+ if (originalDefinitions.Count == 0)
+ {
+ // We did not find any original definitions so we don't have to do anything. This happens if the method has an override modifier
+ // but does not have any valid method it is overriding.
+ return;
+ }
+
+ for (int i = 0; i < symbol.Parameters.Length; i++)
+ {
+ var currentParameter = symbol.Parameters[i];
+ bool foundMatch = false;
+ foreach (var originalDefinition in originalDefinitions)
+ {
+ var originalParameter = originalDefinition.Parameters[i];
+
+ if (currentParameter.Name == originalParameter.Name)
+ {
+ foundMatch = true;
+ break;
+ }
+ }
+
+ if (!foundMatch)
+ {
+ var resultBuilder = StringBuilderPool.Allocate();
+
+ // originalDefinitions must have at least one entry
+ resultBuilder.Append(originalDefinitions[0].Parameters[i].Name);
+
+ for (int j = 1; j < originalDefinitions.Count; j++)
+ {
+ resultBuilder.Append(',');
+ resultBuilder.Append(originalDefinitions[j].Parameters[i].Name);
+ }
+
+ var properties = ImmutableDictionary.Empty.SetItem("newNames", StringBuilderPool.ReturnAndFree(resultBuilder));
+
+ context.ReportDiagnostic(Diagnostic.Create(Descriptor, currentParameter.Locations.First(), properties, null));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/StyleCop.Analyzers.csproj b/StyleCop.Analyzers/StyleCop.Analyzers/StyleCop.Analyzers.csproj
index 8b0c1d8ba..bdcc69655 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/StyleCop.Analyzers.csproj
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/StyleCop.Analyzers.csproj
@@ -203,6 +203,7 @@
+
diff --git a/StyleCopAnalyzers.sln b/StyleCopAnalyzers.sln
index e44366a7f..ec937b062 100644
--- a/StyleCopAnalyzers.sln
+++ b/StyleCopAnalyzers.sln
@@ -133,6 +133,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "documentation", "documentat
documentation\SA1311.md = documentation\SA1311.md
documentation\SA1312.md = documentation\SA1312.md
documentation\SA1313.md = documentation\SA1313.md
+ documentation\SA1314.md = documentation\SA1314.md
documentation\SA1400.md = documentation\SA1400.md
documentation\SA1401.md = documentation\SA1401.md
documentation\SA1402.md = documentation\SA1402.md
diff --git a/documentation/SA1314.md b/documentation/SA1314.md
new file mode 100644
index 000000000..011fe2b6c
--- /dev/null
+++ b/documentation/SA1314.md
@@ -0,0 +1,40 @@
+## SA1314
+
+
+
+
TypeName
+
SA1314ParametersShouldMatchInheritedNames
+
+
+
CheckId
+
SA1314
+
+
+
Category
+
Naming Rules
+
+
+
+:memo: This rule is new for StyleCop Analyzers, and was not present in StyleCop Classic.
+
+## Cause
+
+A violation of this rule occurs when the name of a parameter does not match its inherited name.
+
+## Rule description
+
+A violation of this rule occurs when the name of a parameter does not begin with a lower-case letter.
+
+## How to fix violations
+
+To fix a violation of this rule, change the name of the parameter so that it matches its inherited name.
+
+## How to suppress violations
+
+```csharp
+#pragma warning disable SA1314 // ParametersShouldMatchInheritedNames
+public override void Method(int parameter)
+#pragma warning restore SA1314 // ParametersShouldMatchInheritedNames
+{
+}
+```