-
Notifications
You must be signed in to change notification settings - Fork 509
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
620 additions
and
20 deletions.
There are no files selected for viewing
82 changes: 82 additions & 0 deletions
82
StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/NamingRules/RenameToAnyCodeFixProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
|
||
/// <summary> | ||
/// Implements a code fix for diagnostics which are fixed by renaming a symbol to a set of given new names. | ||
/// </summary> | ||
/// <remarks> | ||
/// <para>To fix a violation of this rule, change the name of the symbol so that it is one of the set of new names.</para> | ||
/// </remarks> | ||
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(RenameToAnyCodeFixProvider))] | ||
[Shared] | ||
internal class RenameToAnyCodeFixProvider : CodeFixProvider | ||
{ | ||
private static char[] comma = { ',' }; | ||
|
||
/// <inheritdoc/> | ||
public override ImmutableArray<string> FixableDiagnosticIds { get; } = | ||
ImmutableArray.Create( | ||
SA1314ParametersShouldMatchInheritedNames.DiagnosticId); | ||
|
||
/// <inheritdoc/> | ||
public override FixAllProvider GetFixAllProvider() | ||
{ | ||
return CustomFixAllProviders.BatchFixer; | ||
} | ||
|
||
/// <inheritdoc/> | ||
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); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
297 changes: 297 additions & 0 deletions
297
StyleCop.Analyzers/StyleCop.Analyzers.Test/NamingRules/SA1314UnitTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers() | ||
{ | ||
yield return new SA1314ParametersShouldMatchInheritedNames(); | ||
} | ||
|
||
protected override CodeFixProvider GetCSharpCodeFixProvider() | ||
{ | ||
return new RenameToAnyCodeFixProvider(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.