Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,7 @@
<data name="AvoidOutRefTestMethodParametersFix" xml:space="preserve">
<value>Remove 'out' and 'ref' modifiers</value>
</data>
<data name="UseMSTestDescriptionAttributeInsteadFix" xml:space="preserve">
<value>Use MSTest 'Description' attribute instead</value>
</data>
</root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Immutable;
using System.Composition;

using Analyzer.Utilities;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

using MSTest.Analyzers.Helpers;

namespace MSTest.Analyzers;

/// <summary>
/// Code fixer for <see cref="DoNotUseSystemDescriptionAttributeAnalyzer"/>.
/// </summary>
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(DoNotUseSystemDescriptionAttributeFixer))]
[Shared]
public sealed class DoNotUseSystemDescriptionAttributeFixer : CodeFixProvider
{
/// <inheritdoc />
public override ImmutableArray<string> FixableDiagnosticIds { get; }
= ImmutableArray.Create(DiagnosticIds.DoNotUseSystemDescriptionAttributeRuleId);

/// <inheritdoc />
public override FixAllProvider GetFixAllProvider()
// See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/FixAllProvider.md for more information on Fix All Providers
=> WellKnownFixAllProviders.BatchFixer;

/// <inheritdoc />
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
SyntaxNode root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

Diagnostic diagnostic = context.Diagnostics[0];
SyntaxToken syntaxToken = root.FindToken(diagnostic.Location.SourceSpan.Start);
if (syntaxToken.Parent is null)
{
return;
}

MethodDeclarationSyntax? methodDeclaration = syntaxToken.Parent.AncestorsAndSelf().OfType<MethodDeclarationSyntax>().FirstOrDefault();
if (methodDeclaration is null)
{
return;
}

context.RegisterCodeFix(
CodeAction.Create(
title: CodeFixResources.UseMSTestDescriptionAttributeInsteadFix,
createChangedDocument: c => ReplaceWithMSTestDescriptionAttributeAsync(context.Document, methodDeclaration, c),
equivalenceKey: nameof(DoNotUseSystemDescriptionAttributeFixer)),
diagnostic);
}

private static async Task<Document> ReplaceWithMSTestDescriptionAttributeAsync(Document document, MethodDeclarationSyntax methodDeclaration, CancellationToken cancellationToken)
{
SemanticModel semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

INamedTypeSymbol? systemDescriptionAttributeSymbol = semanticModel.Compilation.GetTypeByMetadataName(WellKnownTypeNames.SystemDescriptionAttribute);

if (systemDescriptionAttributeSymbol is null)
{
return document;
}

AttributeSyntax? systemDescriptionAttribute = null;

foreach (AttributeListSyntax attributeList in methodDeclaration.AttributeLists)
{
foreach (AttributeSyntax attribute in attributeList.Attributes)
{
if (semanticModel.GetSymbolInfo(attribute, cancellationToken).Symbol is IMethodSymbol { ContainingType: { } containingType }
&& SymbolEqualityComparer.Default.Equals(containingType, systemDescriptionAttributeSymbol))
{
systemDescriptionAttribute = attribute;
break;
}
}

if (systemDescriptionAttribute is not null)
{
break;
}
}

if (systemDescriptionAttribute is null)
{
return document;
}

// Replace the System.ComponentModel.Description attribute name with the MSTest Description attribute name.
// Since the MSTest namespace (Microsoft.VisualStudio.TestTools.UnitTesting) is already in scope,
// we can use just the simple name "Description" which will resolve to MSTest's DescriptionAttribute.
AttributeSyntax newAttribute = systemDescriptionAttribute.WithName(
Comment thread
Evangelink marked this conversation as resolved.
Outdated
SyntaxFactory.IdentifierName("Description")
.WithTriviaFrom(systemDescriptionAttribute.Name));

Comment thread
Evangelink marked this conversation as resolved.
Outdated
SyntaxNode root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

return document.WithSyntaxRoot(root.ReplaceNode(systemDescriptionAttribute, newAttribute));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
<target state="translated">Místo řetězcového argumentu použijte vlastnost DisplayName</target>
<note />
</trans-unit>
<trans-unit id="UseMSTestDescriptionAttributeInsteadFix">
<source>Use MSTest 'Description' attribute instead</source>
<target state="new">Use MSTest 'Description' attribute instead</target>
<note />
</trans-unit>
<trans-unit id="UseProperAssertMethodsFix">
<source>Use '{0}'</source>
<target state="translated">Použít {0}</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
<target state="translated">Verwenden Sie die Eigenschaft „DisplayName“ anstelle eines Zeichenfolgenarguments.</target>
<note />
</trans-unit>
<trans-unit id="UseMSTestDescriptionAttributeInsteadFix">
<source>Use MSTest 'Description' attribute instead</source>
<target state="new">Use MSTest 'Description' attribute instead</target>
<note />
</trans-unit>
<trans-unit id="UseProperAssertMethodsFix">
<source>Use '{0}'</source>
<target state="translated">"{0}" verwenden</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
<target state="translated">Usar la propiedad "DisplayName" en lugar del argumento de cadena</target>
<note />
</trans-unit>
<trans-unit id="UseMSTestDescriptionAttributeInsteadFix">
<source>Use MSTest 'Description' attribute instead</source>
<target state="new">Use MSTest 'Description' attribute instead</target>
<note />
</trans-unit>
<trans-unit id="UseProperAssertMethodsFix">
<source>Use '{0}'</source>
<target state="translated">Usar "{0}"</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
<target state="translated">Utilisez la propriété « DisplayName » au lieu d’un argument de type chaîne</target>
<note />
</trans-unit>
<trans-unit id="UseMSTestDescriptionAttributeInsteadFix">
<source>Use MSTest 'Description' attribute instead</source>
<target state="new">Use MSTest 'Description' attribute instead</target>
<note />
</trans-unit>
<trans-unit id="UseProperAssertMethodsFix">
<source>Use '{0}'</source>
<target state="translated">Utiliser « {0} »</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
<target state="translated">Usare la proprietà 'DisplayName' invece di un argomento stringa</target>
<note />
</trans-unit>
<trans-unit id="UseMSTestDescriptionAttributeInsteadFix">
<source>Use MSTest 'Description' attribute instead</source>
<target state="new">Use MSTest 'Description' attribute instead</target>
<note />
</trans-unit>
<trans-unit id="UseProperAssertMethodsFix">
<source>Use '{0}'</source>
<target state="translated">Usa '{0}'</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
<target state="translated">文字列引数の代わりに 'DisplayName' プロパティを使用する</target>
<note />
</trans-unit>
<trans-unit id="UseMSTestDescriptionAttributeInsteadFix">
<source>Use MSTest 'Description' attribute instead</source>
<target state="new">Use MSTest 'Description' attribute instead</target>
<note />
</trans-unit>
<trans-unit id="UseProperAssertMethodsFix">
<source>Use '{0}'</source>
<target state="translated">'{0}' を使用します</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
<target state="translated">문자열 인수 대신 'DisplayName' 속성 사용</target>
<note />
</trans-unit>
<trans-unit id="UseMSTestDescriptionAttributeInsteadFix">
<source>Use MSTest 'Description' attribute instead</source>
<target state="new">Use MSTest 'Description' attribute instead</target>
<note />
</trans-unit>
<trans-unit id="UseProperAssertMethodsFix">
<source>Use '{0}'</source>
<target state="translated">'{0}' 사용</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
<target state="translated">Użyj właściwości „DisplayName” zamiast argumentu ciągu</target>
<note />
</trans-unit>
<trans-unit id="UseMSTestDescriptionAttributeInsteadFix">
<source>Use MSTest 'Description' attribute instead</source>
<target state="new">Use MSTest 'Description' attribute instead</target>
<note />
</trans-unit>
<trans-unit id="UseProperAssertMethodsFix">
<source>Use '{0}'</source>
<target state="translated">Użyj „{0}”</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
<target state="translated">Usar a propriedade "DisplayName" em vez do argumento de cadeia de caracteres</target>
<note />
</trans-unit>
<trans-unit id="UseMSTestDescriptionAttributeInsteadFix">
<source>Use MSTest 'Description' attribute instead</source>
<target state="new">Use MSTest 'Description' attribute instead</target>
<note />
</trans-unit>
<trans-unit id="UseProperAssertMethodsFix">
<source>Use '{0}'</source>
<target state="translated">Usar '{0}'</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
<target state="translated">Использовать свойство "DisplayName" вместо строкового аргумента</target>
<note />
</trans-unit>
<trans-unit id="UseMSTestDescriptionAttributeInsteadFix">
<source>Use MSTest 'Description' attribute instead</source>
<target state="new">Use MSTest 'Description' attribute instead</target>
<note />
</trans-unit>
<trans-unit id="UseProperAssertMethodsFix">
<source>Use '{0}'</source>
<target state="translated">Использовать "{0}"</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
<target state="translated">Dize bağımsız değişkeni yerine 'DisplayName' özelliğini kullanın</target>
<note />
</trans-unit>
<trans-unit id="UseMSTestDescriptionAttributeInsteadFix">
<source>Use MSTest 'Description' attribute instead</source>
<target state="new">Use MSTest 'Description' attribute instead</target>
<note />
</trans-unit>
<trans-unit id="UseProperAssertMethodsFix">
<source>Use '{0}'</source>
<target state="translated">'{0}' kullan</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
<target state="translated">使用属性‘DisplayName’替代字符串参数</target>
<note />
</trans-unit>
<trans-unit id="UseMSTestDescriptionAttributeInsteadFix">
<source>Use MSTest 'Description' attribute instead</source>
<target state="new">Use MSTest 'Description' attribute instead</target>
<note />
</trans-unit>
<trans-unit id="UseProperAssertMethodsFix">
<source>Use '{0}'</source>
<target state="translated">使用“{0}”</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
<target state="translated">使用 'DisplayName' 屬性取代字串引數</target>
<note />
</trans-unit>
<trans-unit id="UseMSTestDescriptionAttributeInsteadFix">
<source>Use MSTest 'Description' attribute instead</source>
<target state="new">Use MSTest 'Description' attribute instead</target>
<note />
</trans-unit>
<trans-unit id="UseProperAssertMethodsFix">
<source>Use '{0}'</source>
<target state="translated">使用 '{0}'</target>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using VerifyCS = MSTest.Analyzers.Test.CSharpCodeFixVerifier<
MSTest.Analyzers.DoNotUseSystemDescriptionAttributeAnalyzer,
Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
MSTest.Analyzers.DoNotUseSystemDescriptionAttributeFixer>;

namespace MSTest.Analyzers.Test;

Expand All @@ -27,7 +27,21 @@ public class MyTestClass
}
""";

await VerifyCS.VerifyAnalyzerAsync(code);
string fixedCode = """
using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class MyTestClass
{
[TestMethod]
[Description("Description")]
public void MyTestMethod()
{
}
}
""";

await VerifyCS.VerifyCodeFixAsync(code, fixedCode);
Comment thread
Evangelink marked this conversation as resolved.
}

[TestMethod]
Comment thread
Evangelink marked this conversation as resolved.
Expand Down
Loading