未验证 提交 7b2d5013 编写于 作者: J Jonathon Marolf 提交者: GitHub

Merge pull request #45806 from dotnet/feature/convertNameOf

Feature/convert name of
......@@ -18,6 +18,7 @@
<Compile Include="$(MSBuildThisFileDirectory)AddAccessibilityModifiers\CSharpAddAccessibilityModifiersDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AddBraces\CSharpAddBracesDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AddRequiredParentheses\CSharpAddRequiredPatternParenthesesDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertTypeofToNameof\CSharpConvertTypeOfToNameOfDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessarySuppressions\CSharpRemoveUnnecessaryPragmaSuppressionsDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessarySuppressions\CSharpRemoveUnnecessaryAttributeSuppressionsDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessaryParentheses\CSharpRemoveUnnecessaryPatternParenthesesDiagnosticAnalyzer.cs" />
......@@ -102,4 +103,4 @@
<ItemGroup Condition="'$(DefaultLanguageSourceExtension)' != '' AND '$(BuildingInsideVisualStudio)' != 'true'">
<ExpectedCompile Include="$(MSBuildThisFileDirectory)**\*$(DefaultLanguageSourceExtension)" />
</ItemGroup>
</Project>
\ No newline at end of file
</Project>
......@@ -289,4 +289,7 @@
<data name="Suppression_operator_has_no_effect_and_can_be_misinterpreted" xml:space="preserve">
<value>Suppression operator has no effect and can be misinterpreted</value>
</data>
<data name="typeof_can_be_converted_ to_nameof" xml:space="preserve">
<value>'typeof' can be converted to 'nameof'</value>
</data>
</root>
\ No newline at end of file
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.ConvertTypeOfToNameOf;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Microsoft.CodeAnalysis.CSharp.ConvertTypeOfToNameOf
{
/// <summary>
/// Finds code like typeof(someType).Name and determines whether it can be changed to nameof(someType), if yes then it offers a diagnostic
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class CSharpConvertTypeOfToNameOfDiagnosticAnalyzer : AbstractConvertTypeOfToNameOfDiagnosticAnalyzer
{
private static readonly string s_title = CSharpAnalyzersResources.typeof_can_be_converted__to_nameof;
public CSharpConvertTypeOfToNameOfDiagnosticAnalyzer() : base(s_title, LanguageNames.CSharp)
{
}
protected override bool IsValidTypeofAction(OperationAnalysisContext context)
{
var node = context.Operation.Syntax;
var syntaxTree = node.SyntaxTree;
// nameof was added in CSharp 6.0, so don't offer it for any languages before that time
if (((CSharpParseOptions)syntaxTree.Options).LanguageVersion < LanguageVersion.CSharp6)
{
return false;
}
// Make sure that the syntax that we're looking at is actually a typeof expression and that
// the parent syntax is a member access expression otherwise the syntax is not the kind of
// expression that we want to analyze
return node is TypeOfExpressionSyntax { Parent: MemberAccessExpressionSyntax _ };
}
}
}
......@@ -262,6 +262,11 @@
<target state="translated">Příkaz if lze zjednodušit.</target>
<note />
</trans-unit>
<trans-unit id="typeof_can_be_converted_ to_nameof">
<source>'typeof' can be converted to 'nameof'</source>
<target state="new">'typeof' can be converted to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="use_var_instead_of_explicit_type">
<source>use 'var' instead of explicit type</source>
<target state="translated">Použít var místo explicitního typu</target>
......
......@@ -262,6 +262,11 @@
<target state="translated">Die If-Anweisung kann vereinfacht werden.</target>
<note />
</trans-unit>
<trans-unit id="typeof_can_be_converted_ to_nameof">
<source>'typeof' can be converted to 'nameof'</source>
<target state="new">'typeof' can be converted to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="use_var_instead_of_explicit_type">
<source>use 'var' instead of explicit type</source>
<target state="translated">"var" anstelle des expliziten Typs verwenden</target>
......
......@@ -262,6 +262,11 @@
<target state="translated">La instrucción "if" se puede simplificar</target>
<note />
</trans-unit>
<trans-unit id="typeof_can_be_converted_ to_nameof">
<source>'typeof' can be converted to 'nameof'</source>
<target state="new">'typeof' can be converted to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="use_var_instead_of_explicit_type">
<source>use 'var' instead of explicit type</source>
<target state="translated">Usar 'var' en lugar de un tipo explícito</target>
......
......@@ -262,6 +262,11 @@
<target state="translated">L'instruction 'if' peut être simplifiée</target>
<note />
</trans-unit>
<trans-unit id="typeof_can_be_converted_ to_nameof">
<source>'typeof' can be converted to 'nameof'</source>
<target state="new">'typeof' can be converted to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="use_var_instead_of_explicit_type">
<source>use 'var' instead of explicit type</source>
<target state="translated">utiliser 'var' au lieu d'un type explicite</target>
......
......@@ -262,6 +262,11 @@
<target state="translated">L'istruzione 'If' può essere semplificata</target>
<note />
</trans-unit>
<trans-unit id="typeof_can_be_converted_ to_nameof">
<source>'typeof' can be converted to 'nameof'</source>
<target state="new">'typeof' can be converted to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="use_var_instead_of_explicit_type">
<source>use 'var' instead of explicit type</source>
<target state="translated">usa 'var' invece del tipo esplicito</target>
......
......@@ -262,6 +262,11 @@
<target state="translated">'if' ステートメントは簡素化できます</target>
<note />
</trans-unit>
<trans-unit id="typeof_can_be_converted_ to_nameof">
<source>'typeof' can be converted to 'nameof'</source>
<target state="new">'typeof' can be converted to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="use_var_instead_of_explicit_type">
<source>use 'var' instead of explicit type</source>
<target state="translated">明示的な型ではなく 'var' を使用します</target>
......
......@@ -262,6 +262,11 @@
<target state="translated">'if' 문을 간단하게 줄일 수 있습니다.</target>
<note />
</trans-unit>
<trans-unit id="typeof_can_be_converted_ to_nameof">
<source>'typeof' can be converted to 'nameof'</source>
<target state="new">'typeof' can be converted to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="use_var_instead_of_explicit_type">
<source>use 'var' instead of explicit type</source>
<target state="translated">대신 명시적 형식의 'var'을 사용합니다.</target>
......
......@@ -262,6 +262,11 @@
<target state="translated">Instrukcja „if” może zostać uproszczona</target>
<note />
</trans-unit>
<trans-unit id="typeof_can_be_converted_ to_nameof">
<source>'typeof' can be converted to 'nameof'</source>
<target state="new">'typeof' can be converted to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="use_var_instead_of_explicit_type">
<source>use 'var' instead of explicit type</source>
<target state="translated">użyj deklaracji „var” zamiast jawnego typu</target>
......
......@@ -262,6 +262,11 @@
<target state="translated">A instrução 'if' pode ser simplificada</target>
<note />
</trans-unit>
<trans-unit id="typeof_can_be_converted_ to_nameof">
<source>'typeof' can be converted to 'nameof'</source>
<target state="new">'typeof' can be converted to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="use_var_instead_of_explicit_type">
<source>use 'var' instead of explicit type</source>
<target state="translated">usar 'var' em vez do tipo explícito</target>
......
......@@ -262,6 +262,11 @@
<target state="translated">Оператор if можно упростить</target>
<note />
</trans-unit>
<trans-unit id="typeof_can_be_converted_ to_nameof">
<source>'typeof' can be converted to 'nameof'</source>
<target state="new">'typeof' can be converted to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="use_var_instead_of_explicit_type">
<source>use 'var' instead of explicit type</source>
<target state="translated">Использовать var вместо явного типа</target>
......
......@@ -262,6 +262,11 @@
<target state="translated">'If' deyimi basitleştirilebilir</target>
<note />
</trans-unit>
<trans-unit id="typeof_can_be_converted_ to_nameof">
<source>'typeof' can be converted to 'nameof'</source>
<target state="new">'typeof' can be converted to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="use_var_instead_of_explicit_type">
<source>use 'var' instead of explicit type</source>
<target state="translated">açık tür yerine 'var' kullan</target>
......
......@@ -262,6 +262,11 @@
<target state="translated">可简化“If”语句</target>
<note />
</trans-unit>
<trans-unit id="typeof_can_be_converted_ to_nameof">
<source>'typeof' can be converted to 'nameof'</source>
<target state="new">'typeof' can be converted to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="use_var_instead_of_explicit_type">
<source>use 'var' instead of explicit type</source>
<target state="translated">用 "var" 代替显式类型</target>
......
......@@ -262,6 +262,11 @@
<target state="translated">'if' 陳述式可簡化</target>
<note />
</trans-unit>
<trans-unit id="typeof_can_be_converted_ to_nameof">
<source>'typeof' can be converted to 'nameof'</source>
<target state="new">'typeof' can be converted to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="use_var_instead_of_explicit_type">
<source>use 'var' instead of explicit type</source>
<target state="translated">使用 'var',而非明確類型</target>
......
......@@ -16,6 +16,7 @@
<Compile Include="$(MSBuildThisFileDirectory)AddAccessibilityModifiers\CSharpAddAccessibilityModifiersCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AddBraces\CSharpAddBracesCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertAnonymousTypeToTuple\CSharpConvertAnonymousTypeToTupleCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertTypeOfToNameOf\CSharpConvertTypeOfToNameOfCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertSwitchStatementToExpression\ConvertSwitchStatementToExpressionCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertSwitchStatementToExpression\ConvertSwitchStatementToExpressionCodeFixProvider.Rewriter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)FileHeaders\CSharpFileHeaderCodeFixProvider.cs" />
......
......@@ -132,4 +132,7 @@
<data name="Warning_colon_Adding_parameters_to_local_function_declaration_may_produce_invalid_code" xml:space="preserve">
<value>Warning: Adding parameters to local function declaration may produce invalid code.</value>
</data>
<data name="Convert_typeof_to_nameof" xml:space="preserve">
<value>Convert 'typeof' to 'nameof'</value>
</data>
</root>
\ No newline at end of file
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Composition;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.ConvertTypeOfToNameOf;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CSharp.ConvertTypeOfToNameOf
{
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CSharpConvertTypeOfToNameOfCodeFixProvider)), Shared]
internal class CSharpConvertTypeOfToNameOfCodeFixProvider : AbstractConvertTypeOfToNameOfCodeFixProvider
{
[ImportingConstructor]
[SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")]
public CSharpConvertTypeOfToNameOfCodeFixProvider()
{
}
protected override string GetCodeFixTitle()
=> CSharpCodeFixesResources.Convert_typeof_to_nameof;
protected override SyntaxNode? GetSymbolTypeExpression(SemanticModel model, SyntaxNode node)
{
if (node is MemberAccessExpressionSyntax { Expression: TypeOfExpressionSyntax typeOfExpression })
{
var typeSymbol = model.GetSymbolInfo(typeOfExpression.Type).Symbol.GetSymbolType();
return typeSymbol?.GenerateTypeSyntax();
}
return null;
}
}
}
......@@ -7,6 +7,11 @@
<target state="translated">Přidejte položku this.</target>
<note />
</trans-unit>
<trans-unit id="Convert_typeof_to_nameof">
<source>Convert 'typeof' to 'nameof'</source>
<target state="new">Convert 'typeof' to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="Pass_in_captured_variables_as_arguments">
<source>Pass in captured variables as arguments</source>
<target state="translated">Předat zachycené proměnné jako argumenty</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">"this." hinzufügen</target>
<note />
</trans-unit>
<trans-unit id="Convert_typeof_to_nameof">
<source>Convert 'typeof' to 'nameof'</source>
<target state="new">Convert 'typeof' to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="Pass_in_captured_variables_as_arguments">
<source>Pass in captured variables as arguments</source>
<target state="translated">Erfasste Variablen als Argumente übergeben</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Agregar "this."</target>
<note />
</trans-unit>
<trans-unit id="Convert_typeof_to_nameof">
<source>Convert 'typeof' to 'nameof'</source>
<target state="new">Convert 'typeof' to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="Pass_in_captured_variables_as_arguments">
<source>Pass in captured variables as arguments</source>
<target state="translated">Pasar variables capturadas como argumentos</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Ajouter 'this.'</target>
<note />
</trans-unit>
<trans-unit id="Convert_typeof_to_nameof">
<source>Convert 'typeof' to 'nameof'</source>
<target state="new">Convert 'typeof' to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="Pass_in_captured_variables_as_arguments">
<source>Pass in captured variables as arguments</source>
<target state="translated">Passer les variables capturées en tant qu'arguments</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Aggiungi 'this.'</target>
<note />
</trans-unit>
<trans-unit id="Convert_typeof_to_nameof">
<source>Convert 'typeof' to 'nameof'</source>
<target state="new">Convert 'typeof' to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="Pass_in_captured_variables_as_arguments">
<source>Pass in captured variables as arguments</source>
<target state="translated">Passa le variabili catturate come argomenti</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">this' を追加します。</target>
<note />
</trans-unit>
<trans-unit id="Convert_typeof_to_nameof">
<source>Convert 'typeof' to 'nameof'</source>
<target state="new">Convert 'typeof' to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="Pass_in_captured_variables_as_arguments">
<source>Pass in captured variables as arguments</source>
<target state="translated">キャプチャした変数を引数として渡す</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">this'를 추가합니다.</target>
<note />
</trans-unit>
<trans-unit id="Convert_typeof_to_nameof">
<source>Convert 'typeof' to 'nameof'</source>
<target state="new">Convert 'typeof' to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="Pass_in_captured_variables_as_arguments">
<source>Pass in captured variables as arguments</source>
<target state="translated">캡처된 변수를 인수로 전달</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Dodaj „this.”</target>
<note />
</trans-unit>
<trans-unit id="Convert_typeof_to_nameof">
<source>Convert 'typeof' to 'nameof'</source>
<target state="new">Convert 'typeof' to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="Pass_in_captured_variables_as_arguments">
<source>Pass in captured variables as arguments</source>
<target state="translated">Przekaż przechwycone zmienne jako argumenty</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Adicionar 'isso.'</target>
<note />
</trans-unit>
<trans-unit id="Convert_typeof_to_nameof">
<source>Convert 'typeof' to 'nameof'</source>
<target state="new">Convert 'typeof' to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="Pass_in_captured_variables_as_arguments">
<source>Pass in captured variables as arguments</source>
<target state="translated">Passar variáveis capturadas como argumentos</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Добавьте "this".</target>
<note />
</trans-unit>
<trans-unit id="Convert_typeof_to_nameof">
<source>Convert 'typeof' to 'nameof'</source>
<target state="new">Convert 'typeof' to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="Pass_in_captured_variables_as_arguments">
<source>Pass in captured variables as arguments</source>
<target state="translated">Передача зафиксированных переменных в качестве аргументов</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">this' ekleyin.</target>
<note />
</trans-unit>
<trans-unit id="Convert_typeof_to_nameof">
<source>Convert 'typeof' to 'nameof'</source>
<target state="new">Convert 'typeof' to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="Pass_in_captured_variables_as_arguments">
<source>Pass in captured variables as arguments</source>
<target state="translated">Yakalanan değişkenleri bağımsız değişken olarak geçir</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">添加 "this."</target>
<note />
</trans-unit>
<trans-unit id="Convert_typeof_to_nameof">
<source>Convert 'typeof' to 'nameof'</source>
<target state="new">Convert 'typeof' to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="Pass_in_captured_variables_as_arguments">
<source>Pass in captured variables as arguments</source>
<target state="translated">以参数形式传入捕获的变量</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">新增 'this.'</target>
<note />
</trans-unit>
<trans-unit id="Convert_typeof_to_nameof">
<source>Convert 'typeof' to 'nameof'</source>
<target state="new">Convert 'typeof' to 'nameof'</target>
<note />
</trans-unit>
<trans-unit id="Pass_in_captured_variables_as_arguments">
<source>Pass in captured variables as arguments</source>
<target state="translated">以引數形式傳入擷取到的變數</target>
......
......@@ -15,6 +15,8 @@
<Compile Include="$(MSBuildThisFileDirectory)AddRequiredParentheses\AddRequiredPatternParenthesesTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AddRequiredParentheses\AddRequiredExpressionParenthesesTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertAnonymousTypeToTuple\ConvertAnonymousTypeToTupleTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertTypeOfToNameOf\ConvertTypeOfToNameOfFixAllTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertTypeOfToNameOf\ConvertTypeOfToNameOfTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)InlineDeclaration\CSharpInlineDeclarationTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)InlineDeclaration\CSharpInlineDeclarationTests_FixAllTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)InvokeDelegateWithConditionalAccess\InvokeDelegateWithConditionalAccessTests.cs" />
......@@ -97,4 +99,7 @@
<ItemGroup Condition="'$(DefaultLanguageSourceExtension)' != '' AND '$(BuildingInsideVisualStudio)' != 'true'">
<ExpectedCompile Include="$(MSBuildThisFileDirectory)**\*$(DefaultLanguageSourceExtension)" />
</ItemGroup>
<ItemGroup>
<Folder Include="$(MSBuildThisFileDirectory)ConvertTypeOfToNameOf\" />
</ItemGroup>
</Project>
\ No newline at end of file
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConvertTypeOfToNameOf
{
public partial class ConvertTypeOfToNameOfTests
{
[Fact]
[Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
[Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)]
public async Task FixAllDocumentBasic()
{
var input = @"class Test
{
static void Main()
{
var typeName1 = {|FixAllInDocument:typeof(Test).Name|};
var typeName2 = typeof(Test).Name;
var typeName3 = typeof(Test).Name;
}
}
";
var expected = @"class Test
{
static void Main()
{
var typeName1 = nameof(Test);
var typeName2 = nameof(Test);
var typeName3 = nameof(Test);
}
}
";
await TestInRegularAndScriptAsync(input, expected);
}
[Fact]
[Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
[Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)]
public async Task FixAllDocumentVariedSingleLine()
{
var input = @"class Test
{
static void Main()
{
var typeName1 = {|FixAllInDocument:typeof(Test).Name|}; var typeName2 = typeof(int).Name; var typeName3 = typeof(System.String).Name;
}
}
";
var expected = @"class Test
{
static void Main()
{
var typeName1 = nameof(Test); var typeName2 = nameof(System.Int32); var typeName3 = nameof(System.String);
}
}
";
await TestInRegularAndScriptAsync(input, expected);
}
[Fact]
[Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
[Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)]
public async Task FixAllDocumentVariedWithUsing()
{
var input = @"using System;
class Test
{
static void Main()
{
var typeName1 = typeof(Test).Name;
var typeName2 = typeof(int).Name;
var typeName3 = typeof(String).Name;
var typeName4 = {|FixAllInDocument:typeof(System.Double).Name|};
}
}
";
var expected = @"using System;
class Test
{
static void Main()
{
var typeName1 = nameof(Test);
var typeName2 = nameof(Int32);
var typeName3 = nameof(String);
var typeName4 = nameof(Double);
}
}
";
await TestInRegularAndScriptAsync(input, expected);
}
[Fact]
[Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
[Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)]
public async Task FixAllProject()
{
var input = @"
<Workspace>
<Project Language=""C#"" AssemblyName=""Assembly1"" CommonReferences=""true"">
<Document>
class Test1
{
static void Main()
{
var typeName1 = {|FixAllInProject:typeof(Test1).Name|};
var typeName2 = typeof(Test1).Name;
var typeName3 = typeof(Test1).Name;
}
}
</Document>
<Document>
using System;
class Test2
{
static void Main()
{
var typeName1 = typeof(Test1).Name;
var typeName2 = typeof(int).Name;
var typeName3 = typeof(System.String).Name;
var typeName4 = typeof(Double).Name;
}
}
</Document>
</Project>
</Workspace>";
var expected = @"
<Workspace>
<Project Language=""C#"" AssemblyName=""Assembly1"" CommonReferences=""true"">
<Document>
class Test1
{
static void Main()
{
var typeName1 = nameof(Test1);
var typeName2 = nameof(Test1);
var typeName3 = nameof(Test1);
}
}
</Document>
<Document>
using System;
class Test2
{
static void Main()
{
var typeName1 = nameof(Test1);
var typeName2 = nameof(Int32);
var typeName3 = nameof(String);
var typeName4 = nameof(Double);
}
}
</Document>
</Project>
</Workspace>";
await TestInRegularAndScriptAsync(input, expected);
}
[Fact]
[Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
[Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)]
public async Task FixAllSolution()
{
var input = @"
<Workspace>
<Project Language=""C#"" AssemblyName=""Assembly1"" CommonReferences=""true"">
<Document>
class Test1
{
static void Main()
{
var typeName1 = {|FixAllInSolution:typeof(Test1).Name|};
var typeName2 = typeof(Test1).Name;
var typeName3 = typeof(Test1).Name;
}
}
</Document>
<Document>
using System;
class Test2
{
static void Main()
{
var typeName1 = typeof(Test1).Name;
var typeName2 = typeof(int).Name;
var typeName3 = typeof(System.String).Name;
var typeName4 = typeof(Double).Name;
}
}
</Document>
</Project>
<Project Language=""C#"" AssemblyName=""Assembly2"" CommonReferences=""true"">
<Document>
class Test3
{
static void Main()
{
var typeName2 = typeof(int).Name; var typeName3 = typeof(System.String).Name;
}
}
</Document>
</Project>
</Workspace>";
var expected = @"
<Workspace>
<Project Language=""C#"" AssemblyName=""Assembly1"" CommonReferences=""true"">
<Document>
class Test1
{
static void Main()
{
var typeName1 = nameof(Test1);
var typeName2 = nameof(Test1);
var typeName3 = nameof(Test1);
}
}
</Document>
<Document>
using System;
class Test2
{
static void Main()
{
var typeName1 = nameof(Test1);
var typeName2 = nameof(Int32);
var typeName3 = nameof(String);
var typeName4 = nameof(Double);
}
}
</Document>
</Project>
<Project Language=""C#"" AssemblyName=""Assembly2"" CommonReferences=""true"">
<Document>
class Test3
{
static void Main()
{
var typeName2 = nameof(System.Int32); var typeName3 = nameof(System.String);
}
}
</Document>
</Project>
</Workspace>";
await TestInRegularAndScriptAsync(input, expected);
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.ConvertTypeOfToNameOf;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConvertTypeOfToNameOf
{
public partial class ConvertTypeOfToNameOfTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
=> (new CSharpConvertTypeOfToNameOfDiagnosticAnalyzer(), new CSharpConvertTypeOfToNameOfCodeFixProvider());
[Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
public async Task BasicType()
{
var text = @"
class Test
{
void Method()
{
var typeName = [||]typeof(Test).Name;
}
}
";
var expected = @"
class Test
{
void Method()
{
var typeName = [||]nameof(Test);
}
}
";
await TestInRegularAndScriptAsync(text, expected);
}
[Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
public async Task ClassLibraryType()
{
var text = @"
class Test
{
void Method()
{
var typeName = [||]typeof(System.String).Name;
}
}
";
var expected = @"
class Test
{
void Method()
{
var typeName = [||]nameof(System.String);
}
}
";
await TestInRegularAndScriptAsync(text, expected);
}
[Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
public async Task ClassLibraryTypeWithUsing()
{
var text = @"
using System;
class Test
{
void Method()
{
var typeName = [||]typeof(String).Name;
}
}
";
var expected = @"
using System;
class Test
{
void Method()
{
var typeName = [||]nameof(String);
}
}
";
await TestInRegularAndScriptAsync(text, expected);
}
[Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
public async Task NestedCall()
{
var text = @"
class Test
{
void Method()
{
var typeName = Foo([||]typeof(System.String).Name);
}
void Foo(String typeName) {
return;
}
}
";
var expected = @"
class Test
{
void Method()
{
var typeName = Foo([||]nameof(System.String));
}
void Foo(String typeName) {
return;
}
}
";
await TestInRegularAndScriptAsync(text, expected);
}
[Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
public async Task NotOnVariableContainingType()
{
var text = @"using System;
class Test
{
void Method()
{
var typeVar = typeof(String);[||]
var typeName = typeVar.Name;
}
}
";
await TestMissingInRegularAndScriptAsync(text);
}
[Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
public async Task PrimitiveType()
{
var text = @"class Test
{
void Method()
{
var typeName = [||]typeof(int).Name;
}
}
";
var expected = @"class Test
{
void Method()
{
var typeName = [||]nameof(System.Int32);
}
}
";
await TestInRegularAndScriptAsync(text, expected);
}
[Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
public async Task PrimitiveTypeWithUsing()
{
var text = @"using System;
class Test
{
void Method()
{
var typeName = [||]typeof(int).Name;
}
}
";
var expected = @"using System;
class Test
{
void Method()
{
var typeName = [||]nameof(Int32);
}
}
";
await TestInRegularAndScriptAsync(text, expected);
}
[Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
public async Task NotOnGenericType()
{
var text = @"class Test<T>
{
void Method()[||]
{
var typeName = typeof(T).Name;
}
}
";
await TestMissingInRegularAndScriptAsync(text);
}
[Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
public async Task NotOnSimilarStatements()
{
var text = @"class Test
{
void Method()[||]
{
var typeName1 = typeof(Test);
var typeName2 = typeof(Test).toString();
var typeName3 = typeof(Test).FullName;
}
}
";
await TestMissingInRegularAndScriptAsync(text);
}
[Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)]
public async Task NotOnGenericClass()
{
var text = @"class Test
{
class Goo<T>
{
class Bar
{
void M()
{
_ = [||]typeof(Bar).Name;
}
}
}
}
";
await TestMissingInRegularAndScriptAsync(text);
}
}
}
......@@ -21,6 +21,7 @@
<Compile Include="$(MSBuildThisFileDirectory)AddRequiredParentheses\AbstractAddRequiredParenthesesDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AddRequiredParentheses\AddRequiredParenthesesConstants.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertAnonymousTypeToTuple\AbstractConvertAnonymousTypeToTupleDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertTypeofToNameof\AbstractConvertTypeOfToNameOfDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DiagnosticCustomTags.cs" />
<Compile Include="$(MSBuildThisFileDirectory)FileHeaders\AbstractFileHeaderDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)FileHeaders\AbstractFileHeaderHelper.cs" />
......@@ -88,4 +89,4 @@
<ItemGroup Condition="'$(DefaultLanguageSourceExtension)' != '' AND '$(BuildingInsideVisualStudio)' != 'true'">
<ExpectedCompile Include="$(MSBuildThisFileDirectory)**\*$(DefaultLanguageSourceExtension)" />
</ItemGroup>
</Project>
\ No newline at end of file
</Project>
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
#if CODE_STYLE
using OptionSet = Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptions;
#endif
namespace Microsoft.CodeAnalysis.ConvertTypeOfToNameOf
{
internal abstract class AbstractConvertTypeOfToNameOfDiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer
{
protected AbstractConvertTypeOfToNameOfDiagnosticAnalyzer(LocalizableString title, string language)
: base(diagnosticId: IDEDiagnosticIds.ConvertTypeOfToNameOfDiagnosticId,
option: null,
language: language,
title: title)
{
}
public override DiagnosticAnalyzerCategory GetAnalyzerCategory()
=> DiagnosticAnalyzerCategory.SemanticSpanAnalysis;
protected abstract bool IsValidTypeofAction(OperationAnalysisContext context);
protected override void InitializeWorker(AnalysisContext context)
{
context.RegisterOperationAction(AnalyzeAction, OperationKind.TypeOf);
}
protected void AnalyzeAction(OperationAnalysisContext context)
{
if (!IsValidTypeofAction(context) || !IsValidOperation(context.Operation))
{
return;
}
var node = context.Operation.Syntax;
var parent = node.Parent;
// If the parent node is null then it cannot be a member access, so do not report a diagnostic
if (parent is null)
{
return;
}
var location = parent.GetLocation();
var options = context.Compilation.Options;
context.ReportDiagnostic(
DiagnosticHelper.Create(Descriptor,
location,
Descriptor.GetEffectiveSeverity(options),
additionalLocations: null,
properties: null));
}
private static bool IsValidOperation(IOperation operation)
{
// Cast to a typeof operation & check parent is a property reference and member access
var typeofOperation = (ITypeOfOperation)operation;
if (!(operation.Parent is IPropertyReferenceOperation))
{
return false;
}
// Check Parent is a .Name access
var operationParent = (IPropertyReferenceOperation)operation.Parent;
var parentProperty = operationParent.Property.Name;
if (parentProperty != nameof(System.Type.Name) && parentProperty != "Name")
{
return false;
}
// If it's a generic type, do not offer the fix because nameof(T) and typeof(T).Name are not
// semantically equivalent, the resulting string is formatted differently, where typeof(T).Name
// return "T`1" and nameof just returns "T"
if (typeofOperation.TypeOperand is IErrorTypeSymbol)
{
return false;
}
return typeofOperation.TypeOperand is INamedTypeSymbol namedType && !namedType.IsGenericType;
}
}
}
......@@ -140,6 +140,8 @@ internal static class IDEDiagnosticIds
public const string RemoveConfusingSuppressionForIsExpressionDiagnosticId = "IDE0080";
public const string RemoveUnnecessaryByValDiagnosticId = "IDE0081";
public const string ConvertTypeOfToNameOfDiagnosticId = "IDE0082";
// Analyzer error Ids
public const string AnalyzerChangedId = "IDE1001";
public const string AnalyzerDependencyConflictId = "IDE1002";
......
......@@ -16,6 +16,7 @@
<Compile Include="$(MSBuildThisFileDirectory)AddAccessibilityModifiers\AbstractAddAccessibilityModifiersCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AddRequiredParentheses\AddRequiredParenthesesCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertAnonymousTypeToTuple\AbstractConvertAnonymousTypeToTupleCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertTypeOfToNameOf\AbstractConvertTypeOfToNameOfCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)FileHeaders\AbstractFileHeaderCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MakeFieldReadonly\AbstractMakeFieldReadonlyCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)NamingStyle\NamingStyleCodeFixProvider.cs" />
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.ConvertTypeOfToNameOf
{
internal abstract class AbstractConvertTypeOfToNameOfCodeFixProvider : SyntaxEditorBasedCodeFixProvider
{
private static string s_codeFixTitle;
public AbstractConvertTypeOfToNameOfCodeFixProvider()
{
s_codeFixTitle = GetCodeFixTitle();
}
public sealed override ImmutableArray<string> FixableDiagnosticIds
=> ImmutableArray.Create(IDEDiagnosticIds.ConvertTypeOfToNameOfDiagnosticId);
internal sealed override CodeFixCategory CodeFixCategory => CodeFixCategory.CodeStyle;
public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
context.RegisterCodeFix(new MyCodeAction(
c => FixAsync(context.Document, context.Diagnostics.First(), c)),
context.Diagnostics);
return Task.CompletedTask;
}
protected override async Task FixAllAsync(
Document document, ImmutableArray<Diagnostic> diagnostics,
SyntaxEditor editor, CancellationToken cancellationToken)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
foreach (var diagnostic in diagnostics)
{
var node = editor.OriginalRoot.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
ConvertTypeOfToNameOf(semanticModel, editor, node);
}
}
/// <Summary>
/// Method converts typeof(...).Name to nameof(...)
/// </Summary>
public void ConvertTypeOfToNameOf(SemanticModel semanticModel, SyntaxEditor editor, SyntaxNode nodeToReplace)
{
var typeExpression = GetSymbolTypeExpression(semanticModel, nodeToReplace);
var nameOfSyntax = editor.Generator.NameOfExpression(typeExpression);
editor.ReplaceNode(nodeToReplace, nameOfSyntax);
}
protected abstract SyntaxNode GetSymbolTypeExpression(SemanticModel model, SyntaxNode node);
protected abstract string GetCodeFixTitle();
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument)
: base(s_codeFixTitle, createChangedDocument, s_codeFixTitle)
{
}
}
}
}
......@@ -21,6 +21,7 @@ internal static class PredefinedCodeFixProviderNames
public const string ConvertToAsync = nameof(ConvertToAsync);
public const string ConvertToIterator = nameof(ConvertToIterator);
public const string CorrectNextControlVariable = nameof(CorrectNextControlVariable);
public const string ConvertTypeOfToNameOf = nameof(ConvertTypeOfToNameOf);
public const string RemoveDocCommentNode = nameof(RemoveDocCommentNode);
public const string AddMissingReference = nameof(AddMissingReference);
public const string AddImport = nameof(AddImport);
......
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.ConvertTypeOfToNameOf
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.ConvertTypeOfToNameOf
<DiagnosticAnalyzer(LanguageNames.VisualBasic)>
Friend NotInheritable Class VisualBasicConvertTypeOfToNameOfDiagnosticAnalyzer
Inherits AbstractConvertTypeOfToNameOfDiagnosticAnalyzer
Private Shared ReadOnly s_title As String = VisualBasicAnalyzersResources.GetType_can_be_converted_to_NameOf
Public Sub New()
MyBase.New(s_title, LanguageNames.VisualBasic)
End Sub
Protected Overrides Function IsValidTypeofAction(context As OperationAnalysisContext) As Boolean
Dim node = context.Operation.Syntax
Dim compilation = context.Compilation
Dim isValidLanguage = DirectCast(compilation, VisualBasicCompilation).LanguageVersion >= LanguageVersion.VisualBasic14
Dim isValidType = node.IsKind(SyntaxKind.GetTypeExpression)
Dim isParentValid = node.Parent.GetType() Is GetType(MemberAccessExpressionSyntax)
Return isValidLanguage And isValidType And isParentValid
End Function
End Class
End Namespace
......@@ -16,6 +16,7 @@
<Compile Include="$(MSBuildThisFileDirectory)AddAccessibilityModifiers\VisualBasicAddAccessibilityModifiersDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)AddRequiredParentheses\VisualBasicAddRequiredParenthesesDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertAnonymousTypeToTuple\VisualBasicConvertAnonymousTypeToTupleDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertTypeofToNameof\VisualBasicConvertTypeOfToNameOfDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)FileHeaders\VisualBasicFileHeaderDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)FileHeaders\VisualBasicFileHeaderHelper.vb" />
<Compile Include="$(MSBuildThisFileDirectory)NamingStyle\VisualBasicNamingStyleDiagnosticAnalyzer.vb" />
......@@ -51,4 +52,4 @@
<ItemGroup Condition="'$(DefaultLanguageSourceExtension)' != '' AND '$(BuildingInsideVisualStudio)' != 'true'">
<ExpectedCompile Include="$(MSBuildThisFileDirectory)**\*$(DefaultLanguageSourceExtension)" />
</ItemGroup>
</Project>
\ No newline at end of file
</Project>
......@@ -133,4 +133,7 @@
<value>'ByVal' keyword is unnecessary and can be removed.</value>
<comment>{locked: ByVal}This is a Visual Basic keyword and should not be localized or have its casing changed</comment>
</data>
</root>
<data name="GetType_can_be_converted_to_NameOf" xml:space="preserve">
<value>'GetType' can be converted to 'NameOf'</value>
</data>
</root>
\ No newline at end of file
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="cs" original="../VisualBasicAnalyzersResources.resx">
<body>
<trans-unit id="GetType_can_be_converted_to_NameOf">
<source>'GetType' can be converted to 'NameOf'</source>
<target state="new">'GetType' can be converted to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="If_statement_can_be_simplified">
<source>'If' statement can be simplified</source>
<target state="translated">Příkaz if lze zjednodušit.</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="de" original="../VisualBasicAnalyzersResources.resx">
<body>
<trans-unit id="GetType_can_be_converted_to_NameOf">
<source>'GetType' can be converted to 'NameOf'</source>
<target state="new">'GetType' can be converted to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="If_statement_can_be_simplified">
<source>'If' statement can be simplified</source>
<target state="translated">Die If-Anweisung kann vereinfacht werden.</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="es" original="../VisualBasicAnalyzersResources.resx">
<body>
<trans-unit id="GetType_can_be_converted_to_NameOf">
<source>'GetType' can be converted to 'NameOf'</source>
<target state="new">'GetType' can be converted to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="If_statement_can_be_simplified">
<source>'If' statement can be simplified</source>
<target state="translated">La instrucción "if" se puede simplificar</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="fr" original="../VisualBasicAnalyzersResources.resx">
<body>
<trans-unit id="GetType_can_be_converted_to_NameOf">
<source>'GetType' can be converted to 'NameOf'</source>
<target state="new">'GetType' can be converted to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="If_statement_can_be_simplified">
<source>'If' statement can be simplified</source>
<target state="translated">L'instruction 'If' peut être simplifiée</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="it" original="../VisualBasicAnalyzersResources.resx">
<body>
<trans-unit id="GetType_can_be_converted_to_NameOf">
<source>'GetType' can be converted to 'NameOf'</source>
<target state="new">'GetType' can be converted to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="If_statement_can_be_simplified">
<source>'If' statement can be simplified</source>
<target state="translated">L'istruzione 'If' può essere semplificata</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="ja" original="../VisualBasicAnalyzersResources.resx">
<body>
<trans-unit id="GetType_can_be_converted_to_NameOf">
<source>'GetType' can be converted to 'NameOf'</source>
<target state="new">'GetType' can be converted to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="If_statement_can_be_simplified">
<source>'If' statement can be simplified</source>
<target state="translated">'if' ステートメントは簡素化できます</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="ko" original="../VisualBasicAnalyzersResources.resx">
<body>
<trans-unit id="GetType_can_be_converted_to_NameOf">
<source>'GetType' can be converted to 'NameOf'</source>
<target state="new">'GetType' can be converted to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="If_statement_can_be_simplified">
<source>'If' statement can be simplified</source>
<target state="translated">'if' 문을 간단하게 줄일 수 있습니다.</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="pl" original="../VisualBasicAnalyzersResources.resx">
<body>
<trans-unit id="GetType_can_be_converted_to_NameOf">
<source>'GetType' can be converted to 'NameOf'</source>
<target state="new">'GetType' can be converted to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="If_statement_can_be_simplified">
<source>'If' statement can be simplified</source>
<target state="translated">Instrukcja „if” może zostać uproszczona</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="pt-BR" original="../VisualBasicAnalyzersResources.resx">
<body>
<trans-unit id="GetType_can_be_converted_to_NameOf">
<source>'GetType' can be converted to 'NameOf'</source>
<target state="new">'GetType' can be converted to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="If_statement_can_be_simplified">
<source>'If' statement can be simplified</source>
<target state="translated">A instrução 'If' pode ser simplificada</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="ru" original="../VisualBasicAnalyzersResources.resx">
<body>
<trans-unit id="GetType_can_be_converted_to_NameOf">
<source>'GetType' can be converted to 'NameOf'</source>
<target state="new">'GetType' can be converted to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="If_statement_can_be_simplified">
<source>'If' statement can be simplified</source>
<target state="translated">Оператор if можно упростить</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="tr" original="../VisualBasicAnalyzersResources.resx">
<body>
<trans-unit id="GetType_can_be_converted_to_NameOf">
<source>'GetType' can be converted to 'NameOf'</source>
<target state="new">'GetType' can be converted to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="If_statement_can_be_simplified">
<source>'If' statement can be simplified</source>
<target state="translated">'If' deyimi basitleştirilebilir</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="zh-Hans" original="../VisualBasicAnalyzersResources.resx">
<body>
<trans-unit id="GetType_can_be_converted_to_NameOf">
<source>'GetType' can be converted to 'NameOf'</source>
<target state="new">'GetType' can be converted to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="If_statement_can_be_simplified">
<source>'If' statement can be simplified</source>
<target state="translated">可简化“If”语句</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="zh-Hant" original="../VisualBasicAnalyzersResources.resx">
<body>
<trans-unit id="GetType_can_be_converted_to_NameOf">
<source>'GetType' can be converted to 'NameOf'</source>
<target state="new">'GetType' can be converted to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="If_statement_can_be_simplified">
<source>'If' statement can be simplified</source>
<target state="translated">'If' 陳述式可簡化</target>
......
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
Imports System.Composition
Imports System.Diagnostics.CodeAnalysis
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.ConvertTypeOfToNameOf
Imports Microsoft.CodeAnalysis.Simplification
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.ConvertTypeOfToNameOf
<ExportCodeFixProvider(LanguageNames.VisualBasic, Name:=PredefinedCodeFixProviderNames.ConvertTypeOfToNameOf), [Shared]>
Friend Class VisualBasicConvertGetTypeToNameOfCodeFixProvider
Inherits AbstractConvertTypeOfToNameOfCodeFixProvider
<ImportingConstructor>
<SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification:="Used in test code: https://github.com/dotnet/roslyn/issues/42814")>
Public Sub New()
End Sub
Protected Overrides Function GetCodeFixTitle() As String
Return VisualBasicCodeFixesResources.Convert_GetType_to_NameOf
End Function
Protected Overrides Function GetSymbolTypeExpression(semanticModel As SemanticModel, node As SyntaxNode) As SyntaxNode
Dim expression = DirectCast(node, MemberAccessExpressionSyntax).Expression
Dim type = DirectCast(expression, GetTypeExpressionSyntax).Type
Dim symbolType = semanticModel.GetSymbolInfo(type).Symbol.GetSymbolType()
Dim symbolExpression = symbolType.GenerateExpressionSyntax()
If TypeOf symbolExpression Is IdentifierNameSyntax OrElse TypeOf symbolExpression Is MemberAccessExpressionSyntax Then
Return symbolExpression
End If
If TypeOf symbolExpression Is QualifiedNameSyntax Then
Dim qualifiedName = DirectCast(symbolExpression, QualifiedNameSyntax)
Return SyntaxFactory.SimpleMemberAccessExpression(qualifiedName.Left, qualifiedName.Right) _
.WithAdditionalAnnotations(Simplifier.Annotation)
End If
Return Nothing
End Function
End Class
End Namespace
......@@ -15,6 +15,7 @@
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)AddAccessibilityModifiers\VisualBasicAddAccessibilityModifiersCodeFixProvider.vb" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertAnonymousTypeToTuple\VisualBasicConvertAnonymousTypeToTupleCodeFixProvider.vb" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertTypeOfToNameOf\VisualBasicConvertGetTypeToNameOfCodeFixProvider.vb" />
<Compile Include="$(MSBuildThisFileDirectory)FileHeaders\VisualBasicFileHeaderCodeFixProvider.vb" />
<Compile Include="$(MSBuildThisFileDirectory)MakeFieldReadonly\VisualBasicMakeFieldReadonlyCodeFixProvider.vb" />
<Compile Include="$(MSBuildThisFileDirectory)OrderModifiers\VisualBasicOrderModifiersCodeFixProvider.vb" />
......
......@@ -123,4 +123,7 @@
<data name="Add_Me" xml:space="preserve">
<value>Add 'Me.'</value>
</data>
<data name="Convert_GetType_to_NameOf" xml:space="preserve">
<value>Convert 'GetType' to 'NameOf'</value>
</data>
</root>
\ No newline at end of file
......@@ -7,6 +7,11 @@
<target state="translated">Přidejte položku Me.</target>
<note />
</trans-unit>
<trans-unit id="Convert_GetType_to_NameOf">
<source>Convert 'GetType' to 'NameOf'</source>
<target state="new">Convert 'GetType' to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unnecessary_Imports">
<source>Remove Unnecessary Imports</source>
<target state="translated">Odebrat nepotřebné importy</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">"Me." hinzufügen</target>
<note />
</trans-unit>
<trans-unit id="Convert_GetType_to_NameOf">
<source>Convert 'GetType' to 'NameOf'</source>
<target state="new">Convert 'GetType' to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unnecessary_Imports">
<source>Remove Unnecessary Imports</source>
<target state="translated">Unnötige Import-Direktiven entfernen</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Agregar "Me."</target>
<note />
</trans-unit>
<trans-unit id="Convert_GetType_to_NameOf">
<source>Convert 'GetType' to 'NameOf'</source>
<target state="new">Convert 'GetType' to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unnecessary_Imports">
<source>Remove Unnecessary Imports</source>
<target state="translated">Quitar instrucciones Import innecesarias</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Ajouter 'Me.'</target>
<note />
</trans-unit>
<trans-unit id="Convert_GetType_to_NameOf">
<source>Convert 'GetType' to 'NameOf'</source>
<target state="new">Convert 'GetType' to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unnecessary_Imports">
<source>Remove Unnecessary Imports</source>
<target state="translated">Supprimer les importations superflues</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Aggiungi 'Me.'</target>
<note />
</trans-unit>
<trans-unit id="Convert_GetType_to_NameOf">
<source>Convert 'GetType' to 'NameOf'</source>
<target state="new">Convert 'GetType' to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unnecessary_Imports">
<source>Remove Unnecessary Imports</source>
<target state="translated">Rimuovi Import non necessari</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Me' を追加します。</target>
<note />
</trans-unit>
<trans-unit id="Convert_GetType_to_NameOf">
<source>Convert 'GetType' to 'NameOf'</source>
<target state="new">Convert 'GetType' to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unnecessary_Imports">
<source>Remove Unnecessary Imports</source>
<target state="translated">不要なインポートの削除</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Me'를 추가하세요.</target>
<note />
</trans-unit>
<trans-unit id="Convert_GetType_to_NameOf">
<source>Convert 'GetType' to 'NameOf'</source>
<target state="new">Convert 'GetType' to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unnecessary_Imports">
<source>Remove Unnecessary Imports</source>
<target state="translated">불필요한 Imports 제거</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Dodaj „mnie”.</target>
<note />
</trans-unit>
<trans-unit id="Convert_GetType_to_NameOf">
<source>Convert 'GetType' to 'NameOf'</source>
<target state="new">Convert 'GetType' to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unnecessary_Imports">
<source>Remove Unnecessary Imports</source>
<target state="translated">Usuń niepotrzebne importy</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Adicionar 'Me.'</target>
<note />
</trans-unit>
<trans-unit id="Convert_GetType_to_NameOf">
<source>Convert 'GetType' to 'NameOf'</source>
<target state="new">Convert 'GetType' to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unnecessary_Imports">
<source>Remove Unnecessary Imports</source>
<target state="translated">Remover Importações Desnecessárias</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Добавьте "'Me".</target>
<note />
</trans-unit>
<trans-unit id="Convert_GetType_to_NameOf">
<source>Convert 'GetType' to 'NameOf'</source>
<target state="new">Convert 'GetType' to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unnecessary_Imports">
<source>Remove Unnecessary Imports</source>
<target state="translated">Удалить ненужные импорты</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">Me' ekleyin.</target>
<note />
</trans-unit>
<trans-unit id="Convert_GetType_to_NameOf">
<source>Convert 'GetType' to 'NameOf'</source>
<target state="new">Convert 'GetType' to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unnecessary_Imports">
<source>Remove Unnecessary Imports</source>
<target state="translated">Gereksiz İçeri Aktarmaları Kaldır</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">添加 "Me."</target>
<note />
</trans-unit>
<trans-unit id="Convert_GetType_to_NameOf">
<source>Convert 'GetType' to 'NameOf'</source>
<target state="new">Convert 'GetType' to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unnecessary_Imports">
<source>Remove Unnecessary Imports</source>
<target state="translated">删除不必要的导入</target>
......
......@@ -7,6 +7,11 @@
<target state="translated">新增 'Me.'</target>
<note />
</trans-unit>
<trans-unit id="Convert_GetType_to_NameOf">
<source>Convert 'GetType' to 'NameOf'</source>
<target state="new">Convert 'GetType' to 'NameOf'</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unnecessary_Imports">
<source>Remove Unnecessary Imports</source>
<target state="translated">移除不必要的匯入</target>
......
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics
Imports Microsoft.CodeAnalysis.VisualBasic.ConvertTypeOfToNameOf
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ConvertGetTypeToNameOf
Partial Public Class ConvertGetTypeToNameOfTests
Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest
Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider)
Return (New VisualBasicConvertTypeOfToNameOfDiagnosticAnalyzer(), New VisualBasicConvertGetTypeToNameOfCodeFixProvider())
End Function
<Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)>
Public Async Function BasicType() As Task
Dim text = "
class Test
sub Method()
dim typeName = [||]GetType(Test).Name
end sub
end class
"
Dim expected = "
class Test
sub Method()
dim typeName = [||]NameOf(Test)
end sub
end class
"
Await TestInRegularAndScriptAsync(text, expected)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)>
Public Async Function ClassLibraryType() As Task
Dim text = "
class Test
sub Method()
dim typeName = [||]GetType(System.String).Name
end sub
end class
"
Dim expected = "
class Test
sub Method()
dim typeName = [||]NameOf(System.String)
end sub
end class
"
Await TestInRegularAndScriptAsync(text, expected)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)>
Public Async Function ClassLibraryTypeWithImport() As Task
Dim text = "
Imports System
class Test
sub Method()
dim typeName = [||]GetType(String).Name
end sub
end class
"
Dim expected = "
Imports System
class Test
sub Method()
dim typeName = [||]NameOf([String])
end sub
end class
"
Await TestInRegularAndScriptAsync(text, expected)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.ConvertTypeOfToNameOf)>
Public Async Function NestedCall() As Task
Dim text = "
Imports System
class Test
sub Method()
dim typeName = Foo([||]GetType(String).Name)
end sub
sub Foo(ByVal typeName As String)
end sub
end class
"
Dim expected = "
Imports System
class Test
sub Method()
dim typeName = Foo([||]NameOf([String]))
end sub
sub Foo(ByVal typeName As String)
end sub
end class
"
Await TestInRegularAndScriptAsync(text, expected)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertAnonymousTypeToTuple)>
Public Async Function NotOnVariableContainingType() As Task
Await TestMissingInRegularAndScriptAsync("
import System
class Test
sub Method()
dim typeVar = [||]GetType(String)
dim typeName = typeVar.Name
end sub
end class
")
End Function
End Class
End Namespace
......@@ -12,6 +12,7 @@
<Compile Include="$(MSBuildThisFileDirectory)AddAccessibilityModifiers\AddAccessibilityModifiersTests.vb" />
<Compile Include="$(MSBuildThisFileDirectory)AddRequiredParentheses\AddRequiredParenthesesTests.vb" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertAnonymousTypeToTuple\ConvertAnonymousTypeToTupleTests.vb" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertGetTypeToNameOf\ConvertGetTypeToNameOfTests.vb" />
<Compile Include="$(MSBuildThisFileDirectory)FileHeaders\FileHeaderTests.vb" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessaryByVal\RemoveUnnecessaryByValTests.vb" />
<Compile Include="$(MSBuildThisFileDirectory)UpdateLegacySuppressions\UpdateLegacySuppressionsTests.vb" />
......
......@@ -8,9 +8,7 @@ Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports TypeKind = Microsoft.CodeAnalysis.TypeKind
Imports Microsoft.CodeAnalysis.VisualBasic.SyntaxFacts
Imports Microsoft.CodeAnalysis.Collections
Namespace Microsoft.CodeAnalysis.VisualBasic
......
......@@ -391,6 +391,9 @@ public void CSharp_VerifyIDEDiagnosticSeveritiesAreConfigurable()
# IDE0080
dotnet_diagnostic.IDE0080.severity = %value%
# IDE0082
dotnet_diagnostic.IDE0082.severity = %value%
# IDE1005
csharp_style_conditional_delegate_call = true:suggestion
......@@ -543,6 +546,9 @@ public void VisualBasic_VerifyIDEDiagnosticSeveritiesAreConfigurable()
# IDE0081
dotnet_diagnostic.IDE0081.severity = %value%
# IDE0082
dotnet_diagnostic.IDE0082.severity = %value%
# IDE1006
dotnet_diagnostic.IDE1006.severity = %value%
......@@ -924,6 +930,9 @@ public void CSharp_VerifyIDECodeStyleOptionsAreConfigurable()
# IDE0080
No editorconfig based code style option
# IDE0082
No editorconfig based code style option
# IDE1005, PreferConditionalDelegateCall
csharp_style_conditional_delegate_call = true:suggestion
......@@ -1109,6 +1118,9 @@ public void VisualBasic_VerifyIDECodeStyleOptionsAreConfigurable()
# IDE0081
No editorconfig based code style option
# IDE0082
No editorconfig based code style option
# IDE1006
No editorconfig based code style option
......
......@@ -203,6 +203,7 @@ public static class Features
public const string CompleteStatement = nameof(CompleteStatement);
public const string Completion = nameof(Completion);
public const string ConvertAutoPropertyToFullProperty = nameof(ConvertAutoPropertyToFullProperty);
public const string ConvertTypeOfToNameOf = nameof(ConvertTypeOfToNameOf);
public const string DebuggingBreakpoints = "Debugging.Breakpoints";
public const string DebuggingDataTips = "Debugging.DataTips";
public const string DebuggingEditAndContinue = "Debugging.EditAndContinue";
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册