提交 dc2020ba 编写于 作者: C CyrusNajmabadi

Merge branch 'master' into extractMethodVar

...@@ -145,8 +145,10 @@ ...@@ -145,8 +145,10 @@
<AssemblyName>Roslyn.Services.Editor.CSharp.UnitTests</AssemblyName> <AssemblyName>Roslyn.Services.Editor.CSharp.UnitTests</AssemblyName>
<RoslynProjectType>UnitTest</RoslynProjectType> <RoslynProjectType>UnitTest</RoslynProjectType>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="PresentationCore" /> <Reference Include="PresentationCore" />
...@@ -336,6 +338,7 @@ ...@@ -336,6 +338,7 @@
<Compile Include="UseCollectionInitializer\UseCollectionInitializerTests.cs" /> <Compile Include="UseCollectionInitializer\UseCollectionInitializerTests.cs" />
<Compile Include="UseCoalesceExpression\UseCoalesceExpressionForNullableTests.cs" /> <Compile Include="UseCoalesceExpression\UseCoalesceExpressionForNullableTests.cs" />
<Compile Include="UseCoalesceExpression\UseCoalesceExpressionTests.cs" /> <Compile Include="UseCoalesceExpression\UseCoalesceExpressionTests.cs" />
<Compile Include="UseExplicitTupleName\UseExplicitTupleNameTests.cs" />
<Compile Include="UseNullPropagation\UseNullPropagationTests.cs" /> <Compile Include="UseNullPropagation\UseNullPropagationTests.cs" />
<Compile Include="UsePatternMatching\CSharpIsAndCastCheckTests_FixAllTests.cs" /> <Compile Include="UsePatternMatching\CSharpIsAndCastCheckTests_FixAllTests.cs" />
<Compile Include="UsePatternMatching\CSharpIsAndCastCheckTests.cs" /> <Compile Include="UsePatternMatching\CSharpIsAndCastCheckTests.cs" />
...@@ -600,4 +603,4 @@ ...@@ -600,4 +603,4 @@
<InternalsVisibleToTest Include="Roslyn.Services.Editor.CSharp.UnitTests2" /> <InternalsVisibleToTest Include="Roslyn.Services.Editor.CSharp.UnitTests2" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\..\build\Targets\Imports.targets" /> <Import Project="..\..\..\build\Targets\Imports.targets" />
</Project> </Project>
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.UseExplicitTupleName;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseExplicitTupleName
{
public class UseExplicitTupleNameTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal override Tuple<DiagnosticAnalyzer, CodeFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
{
return Tuple.Create<DiagnosticAnalyzer, CodeFixProvider>(
new UseExplicitTupleNameDiagnosticAnalyzer(),
new UseExplicitTupleNameCodeFixProvider());
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)]
public async Task TestNamedTuple1()
{
await TestAsync(
@"
class C
{
void M()
{
(int i, string s) v1 = default((int, string));
var v2 = v1.[|Item1|];
}
}",
@"
class C
{
void M()
{
(int i, string s) v1 = default((int, string));
var v2 = v1.i;
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)]
public async Task TestInArgument()
{
await TestAsync(
@"
class C
{
void M()
{
(int i, string s) v1 = default((int, string));
Foo(v1.[|Item1|]);
}
void Foo(int i) { }
}",
@"
class C
{
void M()
{
(int i, string s) v1 = default((int, string));
Foo(v1.i);
}
void Foo(int i) { }
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)]
public async Task TestNamedTuple2()
{
await TestAsync(
@"
class C
{
void M()
{
(int i, string s) v1 = default((int, string));
var v2 = v1.[|Item2|];
}
}",
@"
class C
{
void M()
{
(int i, string s) v1 = default((int, string));
var v2 = v1.s;
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)]
public async Task TestMissingOnMatchingName1()
{
await TestMissingAsync(
@"
class C
{
void M()
{
(int, string s) v1 = default((int, string));
var v2 = v1.[|Item1|];
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)]
public async Task TestMissingOnMatchingName2()
{
await TestMissingAsync(
@"
class C
{
void M()
{
(int Item1, string s) v1 = default((int, string));
var v2 = v1.[|Item1|];
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)]
public async Task TestWrongCasing()
{
await TestAsync(
@"
class C
{
void M()
{
(int item1, string s) v1 = default((int, string));
var v2 = v1.[|Item1|];
}
}",
@"
class C
{
void M()
{
(int item1, string s) v1 = default((int, string));
var v2 = v1.item1;
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)]
public async Task TestFixAll1()
{
await TestAsync(
@"
class C
{
void M()
{
(int i, string s) v1 = default((int, string));
var v2 = v1.{|FixAllInDocument:Item1|};
var v3 = v1.Item2;
}
}",
@"
class C
{
void M()
{
(int i, string s) v1 = default((int, string));
var v2 = v1.i;
var v3 = v1.s;
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)]
public async Task TestFixAll2()
{
await TestAsync(
@"
class C
{
void M()
{
(int i, int s) v1 = default((int, int));
v1.{|FixAllInDocument:Item1|} = v1.Item2;
}
}",
@"
class C
{
void M()
{
(int i, int s) v1 = default((int, int));
v1.i = v1.s;
}
}");
}
}
}
...@@ -88,6 +88,7 @@ public static class Features ...@@ -88,6 +88,7 @@ public static class Features
public const string CodeActionsUseExpressionBody = "CodeActions.UseExpressionBody"; public const string CodeActionsUseExpressionBody = "CodeActions.UseExpressionBody";
public const string CodeActionsUseImplicitType = "CodeActions.UseImplicitType"; public const string CodeActionsUseImplicitType = "CodeActions.UseImplicitType";
public const string CodeActionsUseExplicitType = "CodeActions.UseExplicitType"; public const string CodeActionsUseExplicitType = "CodeActions.UseExplicitType";
public const string CodeActionsUseExplicitTupleName = "CodeActions.UseExplicitTupleName";
public const string CodeActionsUseFrameworkType = "CodeActions.UseFrameworkType"; public const string CodeActionsUseFrameworkType = "CodeActions.UseFrameworkType";
public const string CodeActionsUseNullPropagation = "CodeActions.UseNullPropagation"; public const string CodeActionsUseNullPropagation = "CodeActions.UseNullPropagation";
public const string CodeActionsUseObjectInitializer = "CodeActions.UseObjectInitializer"; public const string CodeActionsUseObjectInitializer = "CodeActions.UseObjectInitializer";
......
...@@ -576,6 +576,7 @@ ...@@ -576,6 +576,7 @@
<Compile Include="TypeInferrer\TypeInferrerTests.vb" /> <Compile Include="TypeInferrer\TypeInferrerTests.vb" />
<Compile Include="UseCollectionInitializer\UseCollectionInitializerTests.vb" /> <Compile Include="UseCollectionInitializer\UseCollectionInitializerTests.vb" />
<Compile Include="UseCoalesceExpression\UseCoalesceExpressionForNullableTests.vb" /> <Compile Include="UseCoalesceExpression\UseCoalesceExpressionForNullableTests.vb" />
<Compile Include="UseExplicitTupleName\UseExplicitTupleNameTests.vb" />
<Compile Include="UseObjectInitializer\UseObjectInitializerTests.vb" /> <Compile Include="UseObjectInitializer\UseObjectInitializerTests.vb" />
<Compile Include="Utilities\CodeSnippets.vb" /> <Compile Include="Utilities\CodeSnippets.vb" />
<Compile Include="Utils.vb" /> <Compile Include="Utils.vb" />
...@@ -701,4 +702,4 @@ ...@@ -701,4 +702,4 @@
</Content> </Content>
</ItemGroup> </ItemGroup>
<Import Project="..\..\..\build\Targets\Imports.targets" /> <Import Project="..\..\..\build\Targets\Imports.targets" />
</Project> </Project>
\ No newline at end of file
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics
Imports Microsoft.CodeAnalysis.UseExplicitTupleName
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.UseExplicitTupleName
Public Class UseExplicitTupleNameTests
Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest
Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As Tuple(Of DiagnosticAnalyzer, CodeFixProvider)
Return Tuple.Create(Of DiagnosticAnalyzer, CodeFixProvider)(
New UseExplicitTupleNameDiagnosticAnalyzer(),
New UseExplicitTupleNameCodeFixProvider())
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)>
Public Async Function TestNamedTuple1() As Task
Await TestAsync(
"
class C
Sub M()
dim v1 as (i as integer, s as string)
dim v2 = v1.[|Item1|]
end sub
end class",
"
class C
Sub M()
dim v1 as (i as integer, s as string)
dim v2 = v1.i
end sub
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)>
Public Async Function TestInArgument() As Task
Await TestAsync(
"
class C
Sub M()
dim v1 as (i as integer, s as string)
Foo(v1.[|Item1|])
end sub
Sub Foo(i as integer)
end sub
end class",
"
class C
Sub M()
dim v1 as (i as integer, s as string)
Foo(v1.i)
end sub
Sub Foo(i as integer)
end sub
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)>
Public Async Function TestNamedTuple2() As Task
Await TestAsync(
"
class C
Sub M()
dim v1 as (i as integer, s as string)
dim v2 = v1.[|Item2|]
end sub
end class",
"
class C
Sub M()
dim v1 as (i as integer, s as string)
dim v2 = v1.s
end sub
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)>
Public Async Function TestMissingOnMatchingName1() As Task
Await TestMissingAsync(
"
class C
Sub M()
dim v1 as (integer, s as string)
dim v2 = v1.[|Item1|]
end sub
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)>
Public Async Function TestMissingOnMatchingName2() As Task
Await TestMissingAsync(
"
class C
Sub M()
dim v1 as (Item1 as integer, s as string)
dim v2 = v1.[|Item1|]
end sub
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)>
Public Async Function TestWrongCasing() As Task
Await TestMissingAsync(
"
class C
Sub M()
dim v1 as (item1 as integer, s as string)
dim v2 = v1.[|Item1|]
end sub
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)>
Public Async Function TestFixAll1() As Task
Await TestAsync(
"
class C
Sub M()
dim v1 as (i as integer, s as string)
dim v2 = v1.{|FixAllInDocument:Item1|}
dim v3 = v1.Item2
end sub
end class",
"
class C
Sub M()
dim v1 as (i as integer, s as string)
dim v2 = v1.i
dim v3 = v1.s
end sub
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitTupleName)>
Public Async Function TestFixAll2() As Task
Await TestAsync(
"
class C
Sub M()
dim v1 as (i as integer, s as integer)
v1.{|FixAllInDocument:Item1|} = v1.Item2
end sub
end class",
"
class C
Sub M()
dim v1 as (i as integer, s as integer)
v1.i = v1.s
end sub
end class")
End Function
End Class
End Namespace
\ No newline at end of file
...@@ -274,7 +274,9 @@ private static IEnumerable<SyntaxTrivia> MassageTrivia(IEnumerable<SyntaxTrivia> ...@@ -274,7 +274,9 @@ private static IEnumerable<SyntaxTrivia> MassageTrivia(IEnumerable<SyntaxTrivia>
private class MyCodeAction : CodeAction.DocumentChangeAction private class MyCodeAction : CodeAction.DocumentChangeAction
{ {
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument) public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument)
: base(FeaturesResources.Inline_variable_declaration, createChangedDocument) : base(FeaturesResources.Inline_variable_declaration,
createChangedDocument,
FeaturesResources.Inline_variable_declaration)
{ {
} }
} }
......
...@@ -42,6 +42,8 @@ internal static class IDEDiagnosticIds ...@@ -42,6 +42,8 @@ internal static class IDEDiagnosticIds
public const string UseAutoPropertyDiagnosticId = "IDE0031"; public const string UseAutoPropertyDiagnosticId = "IDE0031";
public const string UseExplicitTupleNameDiagnosticId = "IDE0032";
// Analyzer error Ids // Analyzer error Ids
public const string AnalyzerChangedId = "IDE1001"; public const string AnalyzerChangedId = "IDE1001";
public const string AnalyzerDependencyConflictId = "IDE1002"; public const string AnalyzerDependencyConflictId = "IDE1002";
......
...@@ -140,6 +140,7 @@ ...@@ -140,6 +140,7 @@
<Compile Include="UseCoalesceExpression\UseCoalesceExpressionForNullableCodeFixProvider.cs" /> <Compile Include="UseCoalesceExpression\UseCoalesceExpressionForNullableCodeFixProvider.cs" />
<Compile Include="UseCoalesceExpression\UseCoalesceExpressionCodeFixProvider.cs" /> <Compile Include="UseCoalesceExpression\UseCoalesceExpressionCodeFixProvider.cs" />
<Compile Include="UseCoalesceExpression\AbstractUseCoalesceExpressionDiagnosticAnalyzer.cs" /> <Compile Include="UseCoalesceExpression\AbstractUseCoalesceExpressionDiagnosticAnalyzer.cs" />
<Compile Include="UseExplicitTupleName\UseExplicitTupleNameCodeFixProvider.cs" />
<Compile Include="UseNullPropagation\AbstractUseNullPropagationCodeFixProvider.cs" /> <Compile Include="UseNullPropagation\AbstractUseNullPropagationCodeFixProvider.cs" />
<Compile Include="UseNullPropagation\AbstractUseNullPropagationDiagnosticAnalyzer.cs" /> <Compile Include="UseNullPropagation\AbstractUseNullPropagationDiagnosticAnalyzer.cs" />
<Compile Include="UseThrowExpression\AbstractUseThrowExpressionDiagnosticAnalyzer.cs" /> <Compile Include="UseThrowExpression\AbstractUseThrowExpressionDiagnosticAnalyzer.cs" />
...@@ -684,6 +685,7 @@ ...@@ -684,6 +685,7 @@
<Compile Include="UseAutoProperty\AbstractUseAutoPropertyAnalyzer.cs" /> <Compile Include="UseAutoProperty\AbstractUseAutoPropertyAnalyzer.cs" />
<Compile Include="UseObjectInitializer\AbstractUseObjectInitializerDiagnosticAnalyzer.cs" /> <Compile Include="UseObjectInitializer\AbstractUseObjectInitializerDiagnosticAnalyzer.cs" />
<Compile Include="UseObjectInitializer\AbstractUseObjectInitializerCodeFixProvider.cs" /> <Compile Include="UseObjectInitializer\AbstractUseObjectInitializerCodeFixProvider.cs" />
<Compile Include="UseExplicitTupleName\UseExplicitTupleNameDiagnosticAnalyzer.cs" />
<Compile Include="Workspace\BackgroundCompiler.cs" /> <Compile Include="Workspace\BackgroundCompiler.cs" />
<Compile Include="Workspace\BackgroundParser.cs" /> <Compile Include="Workspace\BackgroundParser.cs" />
<Compile Include="Workspace\ProjectCacheService.cs" /> <Compile Include="Workspace\ProjectCacheService.cs" />
......
...@@ -495,15 +495,6 @@ internal class FeaturesResources { ...@@ -495,15 +495,6 @@ internal class FeaturesResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Camel Case.
/// </summary>
internal static string Camel_Case {
get {
return ResourceManager.GetString("Camel_Case", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to can&apos;t not construct final tree. /// Looks up a localized string similar to can&apos;t not construct final tree.
/// </summary> /// </summary>
...@@ -2130,6 +2121,15 @@ internal class FeaturesResources { ...@@ -2130,6 +2121,15 @@ internal class FeaturesResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Prefer explicitly provided tuple element name.
/// </summary>
internal static string Prefer_explicitly_provided_tuple_element_name {
get {
return ResourceManager.GetString("Prefer_explicitly_provided_tuple_element_name", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Project. /// Looks up a localized string similar to Project.
/// </summary> /// </summary>
...@@ -3073,6 +3073,15 @@ internal class FeaturesResources { ...@@ -3073,6 +3073,15 @@ internal class FeaturesResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Use explicitly provided tuple name.
/// </summary>
internal static string Use_explicitly_provided_tuple_name {
get {
return ResourceManager.GetString("Use_explicitly_provided_tuple_name", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Use expression body for accessors. /// Looks up a localized string similar to Use expression body for accessors.
/// </summary> /// </summary>
......
...@@ -1139,9 +1139,6 @@ This version used in: {2}</value> ...@@ -1139,9 +1139,6 @@ This version used in: {2}</value>
<data name="All_uppercase" xml:space="preserve"> <data name="All_uppercase" xml:space="preserve">
<value>All uppercase</value> <value>All uppercase</value>
</data> </data>
<data name="Camel_Case" xml:space="preserve">
<value>Camel Case</value>
</data>
<data name="First_word_capitalized" xml:space="preserve"> <data name="First_word_capitalized" xml:space="preserve">
<value>First word capitalized</value> <value>First word capitalized</value>
</data> </data>
...@@ -1169,4 +1166,10 @@ This version used in: {2}</value> ...@@ -1169,4 +1166,10 @@ This version used in: {2}</value>
<data name="Simplify_object_initialization" xml:space="preserve"> <data name="Simplify_object_initialization" xml:space="preserve">
<value>Simplify object initialization</value> <value>Simplify object initialization</value>
</data> </data>
<data name="Prefer_explicitly_provided_tuple_element_name" xml:space="preserve">
<value>Prefer explicitly provided tuple element name</value>
</data>
<data name="Use_explicitly_provided_tuple_name" xml:space="preserve">
<value>Use explicitly provided tuple name</value>
</data>
</root> </root>
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Composition;
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;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.UseExplicitTupleName
{
[ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic), Shared]
internal partial class UseExplicitTupleNameCodeFixProvider : SyntaxEditorBasedCodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds { get; }
= ImmutableArray.Create(IDEDiagnosticIds.UseExplicitTupleNameDiagnosticId);
public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
context.RegisterCodeFix(new MyCodeAction(
c => FixAsync(context.Document, context.Diagnostics[0], c)),
context.Diagnostics);
return SpecializedTasks.EmptyTask;
}
protected override Task FixAllAsync(
Document document, ImmutableArray<Diagnostic> diagnostics,
SyntaxEditor editor, CancellationToken cancellationToken)
{
var root = editor.OriginalRoot;
var generator = editor.Generator;
foreach (var diagnostic in diagnostics)
{
var oldNameNode = diagnostic.Location.FindNode(
getInnermostNodeForTie: true, cancellationToken: cancellationToken);
var preferredName = diagnostic.Properties[nameof(UseExplicitTupleNameDiagnosticAnalyzer.ElementName)];
var newNameNode = generator.IdentifierName(preferredName).WithTriviaFrom(oldNameNode);
editor.ReplaceNode(oldNameNode, newNameNode);
}
return SpecializedTasks.EmptyTask;
}
private class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument)
: base(FeaturesResources.Use_explicitly_provided_tuple_name,
createChangedDocument,
FeaturesResources.Use_explicitly_provided_tuple_name)
{
}
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Threading;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Semantics;
namespace Microsoft.CodeAnalysis.UseExplicitTupleName
{
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
internal class UseExplicitTupleNameDiagnosticAnalyzer : AbstractCodeStyleDiagnosticAnalyzer
{
public const string ElementName = nameof(ElementName);
private static MethodInfo s_registerMethod = typeof(AnalysisContext).GetTypeInfo().GetDeclaredMethod("RegisterOperationActionImmutableArrayInternal");
public UseExplicitTupleNameDiagnosticAnalyzer()
: base(IDEDiagnosticIds.UseExplicitTupleNameDiagnosticId,
new LocalizableResourceString(nameof(FeaturesResources.Use_explicitly_provided_tuple_name), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
new LocalizableResourceString(nameof(FeaturesResources.Prefer_explicitly_provided_tuple_element_name), FeaturesResources.ResourceManager, typeof(FeaturesResources)))
{
}
protected override void InitializeWorker(AnalysisContext context)
=> s_registerMethod.Invoke(context, new object[]
{
new Action<OperationAnalysisContext>(AnalyzeOperation),
ImmutableArray.Create(OperationKind.FieldReferenceExpression)
});
private void AnalyzeOperation(OperationAnalysisContext context)
{
var optionSet = context.Options.GetOptionSet();
var option = optionSet.GetOption(CodeStyleOptions.PreferExplicitTupleNames, context.Compilation.Language);
var severity = option.Notification.Value;
if (severity == DiagnosticSeverity.Hidden)
{
return;
}
var cancellationToken = context.CancellationToken;
var fieldReferenceOperation = (IFieldReferenceExpression)context.Operation;
var field = fieldReferenceOperation.Field;
if (field.ContainingType.IsTupleType)
{
if (field.CorrespondingTupleField.Equals(field))
{
var namedField = GetNamedField(field.ContainingType, field, cancellationToken);
if (namedField != null)
{
var memberAccessSyntax = fieldReferenceOperation.Syntax;
var nameNode = memberAccessSyntax.ChildNodesAndTokens().Reverse().FirstOrDefault();
if (nameNode != null)
{
var properties = ImmutableDictionary<string, string>.Empty.Add(
nameof(ElementName), namedField.Name);
context.ReportDiagnostic(Diagnostic.Create(
CreateDescriptorWithSeverity(severity),
nameNode.GetLocation(),
properties));
}
}
}
}
}
private IFieldSymbol GetNamedField(
INamedTypeSymbol containingType, IFieldSymbol unnamedField, CancellationToken cancellationToken)
{
foreach (var member in containingType.GetMembers())
{
cancellationToken.ThrowIfCancellationRequested();
if (member.Kind == SymbolKind.Field)
{
var fieldSymbol = (IFieldSymbol)member;
if (unnamedField.Equals(fieldSymbol.CorrespondingTupleField) &&
!fieldSymbol.Name.Equals(unnamedField.Name))
{
return fieldSymbol;
}
}
}
return null;
}
}
}
\ No newline at end of file
...@@ -406,6 +406,26 @@ public Customer() ...@@ -406,6 +406,26 @@ public Customer()
//] //]
} }
} }
";
private static readonly string s_preferExplicitTupleName = @"
class Customer
{
public Customer()
{
//[
// Prefer:
(string name, int age) customer = GetCustomer();
var name = customer.name;
var age = customer.age;
// Over:
(string name, int age) customer = GetCustomer();
var name = customer.Item1;
var age = customer.Item2;
//]
}
}
"; ";
private static readonly string s_preferInlinedVariableDeclaration = @" private static readonly string s_preferInlinedVariableDeclaration = @"
...@@ -660,6 +680,7 @@ internal StyleViewModel(OptionSet optionSet, IServiceProvider serviceProvider) : ...@@ -660,6 +680,7 @@ internal StyleViewModel(OptionSet optionSet, IServiceProvider serviceProvider) :
CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferCollectionInitializer, ServicesVSResources.Prefer_collection_initializer, s_preferCollectionInitializer, s_preferCollectionInitializer, this, optionSet, expressionPreferencesGroupTitle)); CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferCollectionInitializer, ServicesVSResources.Prefer_collection_initializer, s_preferCollectionInitializer, s_preferCollectionInitializer, this, optionSet, expressionPreferencesGroupTitle));
CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferPatternMatchingOverIsWithCastCheck, CSharpVSResources.Prefer_pattern_matching_over_is_with_cast_check, s_preferPatternMatchingOverIsWithCastCheck, s_preferPatternMatchingOverIsWithCastCheck, this, optionSet, expressionPreferencesGroupTitle)); CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferPatternMatchingOverIsWithCastCheck, CSharpVSResources.Prefer_pattern_matching_over_is_with_cast_check, s_preferPatternMatchingOverIsWithCastCheck, s_preferPatternMatchingOverIsWithCastCheck, this, optionSet, expressionPreferencesGroupTitle));
CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferPatternMatchingOverAsWithNullCheck, CSharpVSResources.Prefer_pattern_matching_over_as_with_null_check, s_preferPatternMatchingOverAsWithNullCheck, s_preferPatternMatchingOverAsWithNullCheck, this, optionSet, expressionPreferencesGroupTitle)); CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferPatternMatchingOverAsWithNullCheck, CSharpVSResources.Prefer_pattern_matching_over_as_with_null_check, s_preferPatternMatchingOverAsWithNullCheck, s_preferPatternMatchingOverAsWithNullCheck, this, optionSet, expressionPreferencesGroupTitle));
CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferExplicitTupleNames, ServicesVSResources.Prefer_explicit_tuple_name, s_preferExplicitTupleName, s_preferExplicitTupleName, this, optionSet, expressionPreferencesGroupTitle));
// Variable preferences // Variable preferences
CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferInlinedVariableDeclaration, ServicesVSResources.Prefer_inlined_variable_declaration, s_preferInlinedVariableDeclaration, s_preferInlinedVariableDeclaration, this, optionSet, variablePreferencesGroupTitle)); CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferInlinedVariableDeclaration, ServicesVSResources.Prefer_inlined_variable_declaration, s_preferInlinedVariableDeclaration, s_preferInlinedVariableDeclaration, this, optionSet, variablePreferencesGroupTitle));
......
...@@ -1401,6 +1401,15 @@ internal class ServicesVSResources { ...@@ -1401,6 +1401,15 @@ internal class ServicesVSResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Prefer explicit tuple name.
/// </summary>
internal static string Prefer_explicit_tuple_name {
get {
return ResourceManager.GetString("Prefer_explicit_tuple_name", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Prefer framework type. /// Looks up a localized string similar to Prefer framework type.
/// </summary> /// </summary>
......
...@@ -816,6 +816,9 @@ Additional information: {1}</value> ...@@ -816,6 +816,9 @@ Additional information: {1}</value>
<data name="Prefer_null_propagation" xml:space="preserve"> <data name="Prefer_null_propagation" xml:space="preserve">
<value>Prefer null propagation</value> <value>Prefer null propagation</value>
</data> </data>
<data name="Prefer_explicit_tuple_name" xml:space="preserve">
<value>Prefer explicit tuple name</value>
</data>
<data name="Description" xml:space="preserve"> <data name="Description" xml:space="preserve">
<value>Description</value> <value>Description</value>
</data> </data>
......
...@@ -188,6 +188,24 @@ Class Customer ...@@ -188,6 +188,24 @@ Class Customer
End Sub End Sub
End Class" End Class"
Private Shared ReadOnly s_preferExplicitTupleName As String = "
Class Customer
Public Sub New()
//[
' Prefer:
Dim customer As (name As String, age As Integer)
Dim name = customer.name
Dim age = customer.age
' Over
Dim customer As (name As String, age As Integer)
Dim name = customer.Item1
Dim age = customer.Item2
//]
End Sub
end class
"
Private Shared ReadOnly s_preferCoalesceExpression As String = " Private Shared ReadOnly s_preferCoalesceExpression As String = "
Imports System Imports System
...@@ -262,6 +280,7 @@ End Class" ...@@ -262,6 +280,7 @@ End Class"
' expression preferences ' expression preferences
Me.CodeStyleItems.Add(New SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferObjectInitializer, ServicesVSResources.Prefer_object_initializer, s_preferObjectInitializer, s_preferObjectInitializer, Me, optionSet, expressionPreferencesGroupTitle)) Me.CodeStyleItems.Add(New SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferObjectInitializer, ServicesVSResources.Prefer_object_initializer, s_preferObjectInitializer, s_preferObjectInitializer, Me, optionSet, expressionPreferencesGroupTitle))
Me.CodeStyleItems.Add(New SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferCollectionInitializer, ServicesVSResources.Prefer_collection_initializer, s_preferCollectionInitializer, s_preferCollectionInitializer, Me, optionSet, expressionPreferencesGroupTitle)) Me.CodeStyleItems.Add(New SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferCollectionInitializer, ServicesVSResources.Prefer_collection_initializer, s_preferCollectionInitializer, s_preferCollectionInitializer, Me, optionSet, expressionPreferencesGroupTitle))
Me.CodeStyleItems.Add(New SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferExplicitTupleNames, ServicesVSResources.Prefer_explicit_tuple_name, s_preferExplicitTupleName, s_preferExplicitTupleName, Me, optionSet, expressionPreferencesGroupTitle))
' nothing preferences ' nothing preferences
Me.CodeStyleItems.Add(New SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferCoalesceExpression, ServicesVSResources.Prefer_coalesce_expression, s_preferCoalesceExpression, s_preferCoalesceExpression, Me, optionSet, nothingPreferencesGroupTitle)) Me.CodeStyleItems.Add(New SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferCoalesceExpression, ServicesVSResources.Prefer_coalesce_expression, s_preferCoalesceExpression, s_preferCoalesceExpression, Me, optionSet, nothingPreferencesGroupTitle))
......
...@@ -108,25 +108,7 @@ public SymbolSearchUpdateEngine(ISymbolSearchLogService logService) ...@@ -108,25 +108,7 @@ public SymbolSearchUpdateEngine(ISymbolSearchLogService logService)
return Task.FromResult(result.ToImmutableAndFree()); return Task.FromResult(result.ToImmutableAndFree());
} }
public async Task<ImmutableArray<PackageWithAssemblyResult>> FindPackagesWithAssemblyAsync( public Task<ImmutableArray<PackageWithAssemblyResult>> FindPackagesWithAssemblyAsync(
string source, string assemblyName)
{
var result = await FindPackagesWithAssemblyWorkerAsync(source, assemblyName).ConfigureAwait(false);
#if DEBUG
// For testing purposes, we hardcode this in if we're in DEBUG mode.
if (result.Length == 0 &&
source == NugetOrgSource &&
assemblyName == "System.ValueTuple")
{
return ImmutableArray.Create(new PackageWithAssemblyResult("System.ValueTuple", "", rank: 0));
}
#endif
return result;
}
public Task<ImmutableArray<PackageWithAssemblyResult>> FindPackagesWithAssemblyWorkerAsync(
string source, string assemblyName) string source, string assemblyName)
{ {
if (!_sourceToDatabase.TryGetValue(source, out var databaseWrapper)) if (!_sourceToDatabase.TryGetValue(source, out var databaseWrapper))
......
...@@ -99,5 +99,11 @@ public class CodeStyleOptions ...@@ -99,5 +99,11 @@ public class CodeStyleOptions
nameof(PreferInlinedVariableDeclaration), nameof(PreferInlinedVariableDeclaration),
defaultValue: TrueWithSuggestionEnforcement, defaultValue: TrueWithSuggestionEnforcement,
storageLocations: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PreferInlinedVariableDeclaration")); storageLocations: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PreferInlinedVariableDeclaration"));
internal static readonly PerLanguageOption<CodeStyleOption<bool>> PreferExplicitTupleNames = new PerLanguageOption<CodeStyleOption<bool>>(
nameof(CodeStyleOptions),
nameof(PreferExplicitTupleNames),
defaultValue: TrueWithSuggestionEnforcement,
storageLocations: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PreferExplicitTupleNames"));
} }
} }
\ No newline at end of file
...@@ -225,6 +225,7 @@ protected void WriteOptionSetTo(OptionSet options, string language, ObjectWriter ...@@ -225,6 +225,7 @@ protected void WriteOptionSetTo(OptionSet options, string language, ObjectWriter
WriteOptionTo(options, language, CodeStyleOptions.PreferCoalesceExpression, writer, cancellationToken); WriteOptionTo(options, language, CodeStyleOptions.PreferCoalesceExpression, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.PreferCollectionInitializer, writer, cancellationToken); WriteOptionTo(options, language, CodeStyleOptions.PreferCollectionInitializer, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.PreferExplicitTupleNames, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.PreferInlinedVariableDeclaration, writer, cancellationToken); WriteOptionTo(options, language, CodeStyleOptions.PreferInlinedVariableDeclaration, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.PreferNullPropagation, writer, cancellationToken); WriteOptionTo(options, language, CodeStyleOptions.PreferNullPropagation, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.PreferObjectInitializer, writer, cancellationToken); WriteOptionTo(options, language, CodeStyleOptions.PreferObjectInitializer, writer, cancellationToken);
...@@ -244,6 +245,7 @@ protected OptionSet ReadOptionSetFrom(OptionSet options, string language, Object ...@@ -244,6 +245,7 @@ protected OptionSet ReadOptionSetFrom(OptionSet options, string language, Object
options = ReadOptionFrom(options, language, CodeStyleOptions.PreferCoalesceExpression, reader, cancellationToken); options = ReadOptionFrom(options, language, CodeStyleOptions.PreferCoalesceExpression, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.PreferCollectionInitializer, reader, cancellationToken); options = ReadOptionFrom(options, language, CodeStyleOptions.PreferCollectionInitializer, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.PreferExplicitTupleNames, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.PreferInlinedVariableDeclaration, reader, cancellationToken); options = ReadOptionFrom(options, language, CodeStyleOptions.PreferInlinedVariableDeclaration, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.PreferNullPropagation, reader, cancellationToken); options = ReadOptionFrom(options, language, CodeStyleOptions.PreferNullPropagation, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.PreferObjectInitializer, reader, cancellationToken); options = ReadOptionFrom(options, language, CodeStyleOptions.PreferObjectInitializer, reader, cancellationToken);
......
using System.Collections.Generic; // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
namespace Microsoft.CodeAnalysis.FindSymbols namespace Microsoft.CodeAnalysis.FindSymbols
{ {
...@@ -8,6 +10,6 @@ namespace Microsoft.CodeAnalysis.FindSymbols ...@@ -8,6 +10,6 @@ namespace Microsoft.CodeAnalysis.FindSymbols
/// </summary> /// </summary>
internal interface IDeclarationInfo internal interface IDeclarationInfo
{ {
IReadOnlyList<DeclaredSymbolInfo> DeclaredSymbolInfos { get; } ImmutableArray<DeclaredSymbolInfo> DeclaredSymbolInfos { get; }
} }
} }
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic; using System.Collections.Immutable;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
...@@ -22,9 +22,9 @@ internal class SyntaxTreeDeclarationInfo : AbstractSyntaxTreeInfo, IDeclarationI ...@@ -22,9 +22,9 @@ internal class SyntaxTreeDeclarationInfo : AbstractSyntaxTreeInfo, IDeclarationI
private static readonly ConditionalWeakTable<BranchId, ConditionalWeakTable<DocumentId, AbstractSyntaxTreeInfo>> s_cache = private static readonly ConditionalWeakTable<BranchId, ConditionalWeakTable<DocumentId, AbstractSyntaxTreeInfo>> s_cache =
new ConditionalWeakTable<BranchId, ConditionalWeakTable<DocumentId, AbstractSyntaxTreeInfo>>(); new ConditionalWeakTable<BranchId, ConditionalWeakTable<DocumentId, AbstractSyntaxTreeInfo>>();
public IReadOnlyList<DeclaredSymbolInfo> DeclaredSymbolInfos { get; } public ImmutableArray<DeclaredSymbolInfo> DeclaredSymbolInfos { get; }
public SyntaxTreeDeclarationInfo(VersionStamp version, IReadOnlyList<DeclaredSymbolInfo> declaredSymbolInfos) public SyntaxTreeDeclarationInfo(VersionStamp version, ImmutableArray<DeclaredSymbolInfo> declaredSymbolInfos)
: base(version) : base(version)
{ {
DeclaredSymbolInfos = declaredSymbolInfos; DeclaredSymbolInfos = declaredSymbolInfos;
...@@ -32,7 +32,7 @@ public SyntaxTreeDeclarationInfo(VersionStamp version, IReadOnlyList<DeclaredSym ...@@ -32,7 +32,7 @@ public SyntaxTreeDeclarationInfo(VersionStamp version, IReadOnlyList<DeclaredSym
public override void WriteTo(ObjectWriter writer) public override void WriteTo(ObjectWriter writer)
{ {
writer.WriteInt32(DeclaredSymbolInfos.Count); writer.WriteInt32(DeclaredSymbolInfos.Length);
foreach (var declaredSymbolInfo in DeclaredSymbolInfos) foreach (var declaredSymbolInfo in DeclaredSymbolInfos)
{ {
declaredSymbolInfo.WriteTo(writer); declaredSymbolInfo.WriteTo(writer);
...@@ -60,13 +60,14 @@ private static SyntaxTreeDeclarationInfo ReadFrom(ObjectReader reader, VersionSt ...@@ -60,13 +60,14 @@ private static SyntaxTreeDeclarationInfo ReadFrom(ObjectReader reader, VersionSt
try try
{ {
var declaredSymbolCount = reader.ReadInt32(); var declaredSymbolCount = reader.ReadInt32();
var declaredSymbols = new DeclaredSymbolInfo[declaredSymbolCount]; var builder = ImmutableArray.CreateBuilder<DeclaredSymbolInfo>(declaredSymbolCount);
for (int i = 0; i < declaredSymbolCount; i++) for (int i = 0; i < declaredSymbolCount; i++)
{ {
declaredSymbols[i] = DeclaredSymbolInfo.ReadFrom(reader); builder.Add(DeclaredSymbolInfo.ReadFrom(reader));
} }
return new SyntaxTreeDeclarationInfo(version, declaredSymbols); return new SyntaxTreeDeclarationInfo(
version, builder.MoveToImmutable());
} }
catch (Exception) catch (Exception)
{ {
...@@ -75,4 +76,4 @@ private static SyntaxTreeDeclarationInfo ReadFrom(ObjectReader reader, VersionSt ...@@ -75,4 +76,4 @@ private static SyntaxTreeDeclarationInfo ReadFrom(ObjectReader reader, VersionSt
return null; return null;
} }
} }
} }
\ No newline at end of file
...@@ -146,7 +146,7 @@ private static async Task<(SyntaxTreeIdentifierInfo identifierInfo, SyntaxTreeCo ...@@ -146,7 +146,7 @@ private static async Task<(SyntaxTreeIdentifierInfo identifierInfo, SyntaxTreeCo
var predefinedTypes = (int)PredefinedType.None; var predefinedTypes = (int)PredefinedType.None;
var predefinedOperators = (int)PredefinedOperator.None; var predefinedOperators = (int)PredefinedOperator.None;
var declaredSymbolInfos = new List<DeclaredSymbolInfo>(); var declaredSymbolInfos = ArrayBuilder<DeclaredSymbolInfo>.GetInstance();
if (syntaxFacts != null) if (syntaxFacts != null)
{ {
...@@ -241,7 +241,7 @@ private static async Task<(SyntaxTreeIdentifierInfo identifierInfo, SyntaxTreeCo ...@@ -241,7 +241,7 @@ private static async Task<(SyntaxTreeIdentifierInfo identifierInfo, SyntaxTreeCo
containsIndexerMemberCref), containsIndexerMemberCref),
new SyntaxTreeDeclarationInfo( new SyntaxTreeDeclarationInfo(
version, version,
declaredSymbolInfos)); declaredSymbolInfos.ToImmutableAndFree()));
} }
finally finally
{ {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册