提交 7b66f34c 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #20517 from CyrusNajmabadi/orderModifiers

Initial work to provide a code style for ordering modifiers.
......@@ -260,6 +260,7 @@
<Compile Include="GenerateFromMembers\GenerateEqualsAndGetHashCodeFromMembers\GenerateEqualsAndGetHashCodeFromMembersTests.cs" />
<Compile Include="GenerateOverrides\GenerateOverridesTests.cs" />
<Compile Include="InitializeParameter\InitializeMemberFromParameterTests.cs" />
<Compile Include="OrderModifiers\OrderModifiersTests.cs" />
<Compile Include="QualifyMemberAccess\QualifyMemberAccessTests.cs" />
<Compile Include="QualifyMemberAccess\QualifyMemberAccessTests_FixAllTests.cs" />
<Compile Include="Diagnostics\SpellCheck\SpellCheckTests.cs" />
......
// 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.CSharp.OrderModifiers;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.OrderModifiers
{
public class OrderModifiersTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
=> (new CSharpOrderModifiersDiagnosticAnalyzer(), new CSharpOrderModifiersCodeFixProvider());
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestClass()
{
await TestInRegularAndScript1Async(
@"[|static|] internal class C
{
}",
@"
internal static class C
{
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestStruct()
{
await TestInRegularAndScript1Async(
@"[|unsafe|] public struct C
{
}",
@"
public unsafe struct C
{
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestInterface()
{
await TestInRegularAndScript1Async(
@"[|unsafe|] public interface C
{
}",
@"
public unsafe interface C
{
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestEnum()
{
await TestInRegularAndScript1Async(
@"[|internal|] protected enum C
{
}",
@"
protected internal enum C
{
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestDelegate()
{
await TestInRegularAndScript1Async(
@"[|unsafe|] public delegate void D();",
@"public unsafe delegate void D();");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestMethod()
{
await TestInRegularAndScript1Async(
@"class C
{
[|unsafe|] public void M() { }
}",
@"
class C
{
public unsafe void M() { }
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestField()
{
await TestInRegularAndScript1Async(
@"class C
{
[|unsafe|] public int a;
}",
@"
class C
{
public unsafe int a;
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestConstructor()
{
await TestInRegularAndScript1Async(
@"class C
{
[|unsafe|] public C() { }
}",
@"
class C
{
public unsafe C() { }
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestProperty()
{
await TestInRegularAndScript1Async(
@"class C
{
[|unsafe|] public int P { get; }
}",
@"
class C
{
public unsafe int P { get; }
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestAccessor()
{
await TestInRegularAndScript1Async(
@"class C
{
int P { [|internal|] protected get; }
}",
@"
class C
{
int P { protected internal get; }
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestPropertyEvent()
{
await TestInRegularAndScript1Async(
@"class C
{
[|internal|] protected event Action P { add { } remove { } }
}",
@"
class C
{
protected internal event Action P { add { } remove { } }
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestFieldEvent()
{
await TestInRegularAndScript1Async(
@"class C
{
[|internal|] protected event Action P;
}",
@"
class C
{
protected internal event Action P;
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestOperator()
{
await TestInRegularAndScript1Async(
@"class C
{
[|static|] public C operator +(C c1, C c2) { }
}",
@"
class C
{
public static C operator +(C c1, C c2) { }
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestConversionOperator()
{
await TestInRegularAndScript1Async(
@"class C
{
[|static|] public implicit operator bool(C c1) { }
}",
@"
class C
{
public static implicit operator bool(C c1) { }
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestFixAll1()
{
await TestInRegularAndScript1Async(
@"{|FixAllInDocument:static|} internal class C
{
static internal class Nested { }
}",
@"
internal static class C
{
internal static class Nested { }
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestFixAll2()
{
await TestInRegularAndScript1Async(
@"static internal class C
{
{|FixAllInDocument:static|} internal class Nested { }
}",
@"
internal static class C
{
internal static class Nested { }
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestTrivia1()
{
await TestInRegularAndScript1Async(
@"
/// Doc comment
[|static|] internal class C
{
}",
@"
/// Doc comment
internal static class C
{
}", ignoreTrivia: false);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestTrivia2()
{
await TestInRegularAndScript1Async(
@"
/* start */ [|static|] /* middle */ internal /* end */ class C
{
}",
@"
/* start */ internal /* middle */ static /* end */ class C
{
}", ignoreTrivia: false);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)]
public async Task TestTrivia3()
{
await TestInRegularAndScript1Async(
@"
#if true
[|static|] internal class C
{
}
#endif
",
@"
#if true
internal static class C
{
}
#endif
", ignoreTrivia: false);
}
}
}
......@@ -80,6 +80,7 @@ public static class Features
public const string CodeActionsMoveDeclarationNearReference = "CodeActions.MoveDeclarationNearReference";
public const string CodeActionsMoveToTopOfFile = "CodeActions.MoveToTopOfFile";
public const string CodeActionsMoveType = "CodeActions.MoveType";
public const string CodeActionsOrderModifiers = "CodeActions.OrderModifiers";
public const string CodeActionsPopulateSwitch = "CodeActions.PopulateSwitch";
public const string CodeActionsQualifyMemberAccess = "CodeActions.QualifyMemberAccess";
public const string CodeActionsReplaceMethodWithProperty = "CodeActions.ReplaceMethodWithProperty";
......
......@@ -199,6 +199,7 @@
<Compile Include="CodeActions\UseNamedArguments\UseNamedArgumentsTests.vb" />
<Compile Include="Diagnostics\RemoveUnusedVariable\RemoveUnusedVariableTest.vb" />
<Compile Include="InitializeParameter\AddParameterCheckTests.vb" />
<Compile Include="OrderModifiers\OrderModifiersTests.vb" />
<Compile Include="Structure\CollectionInitializerStructureProviderTests.vb" />
<Compile Include="ConvertToInterpolatedString\ConvertPlaceholderToInterpolatedStringTests.vb" />
<Compile Include="CodeActions\EncapsulateField\EncapsulateFieldTests.vb" />
......
' 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.VisualBasic.OrderModifiers
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.OrderModifiers
Public Class OrderModifiersTests
Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest
Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider)
Return (New VisualBasicOrderModifiersDiagnosticAnalyzer(),
New VisualBasicOrderModifiersCodeFixProvider())
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestClass() As Task
Await TestInRegularAndScript1Async(
"[|friend|] protected class C
end class
",
"protected friend class C
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
public async Function TestStruct() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"[|friend|] protected structure C
end structure",
"
protected friend structure C
end structure")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestInterface() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"[|friend|] protected interface C
end interface",
"
protected friend interface C
end interface
")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestEnum() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"[|friend|] protected enum C
end enum",
"
protected friend enum C
end enum")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestDelegate() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"[|friend|] protected delegate sub D()",
"protected friend delegate sub D()")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestMethodStatement() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"class C
[|mustoverride|] protected sub M()
end class",
"
class C
protected mustoverride sub M()
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestMethodBlock() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"class C
[|friend|] protected sub M()
end sub
end class",
"
class C
protected friend sub M()
end sub
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestField() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"class C
[|friend|] protected dim a as integer
end class",
"
class C
protected friend dim a as integer
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestConstructor() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"class C
[|friend|] protected sub new()
end sub
end class",
"
class C
protected friend sub new()
end sub
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestPropertyStatement() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"class C
[|readonly|] protected property P as integer
end class",
"
class C
protected readonly property P as integer
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestPropertyBlock() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"class C
[|readonly|] protected property P as integer
get
end get
end property
end class",
"
class C
protected readonly property P as integer
get
end get
end property
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestAccessor() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"class C
public property P as integer
[|friend|] protected get
end get
end property
end class
",
"class C
public property P as integer
protected friend get
end get
end property
end class
")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestPropertyEvent() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"class C
[|friend|] protected custom event E as Action
end event
end class",
"
class C
protected friend custom event E as Action
end event
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestFieldEvent() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"class C
[|friend|] protected event E as Action
end class",
"
class C
protected friend event E as Action
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestOperator() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"class C
[|shared|] public operator +(c1 as integer, c2 as integer) as integer
end operator
end class
",
"
class C
public shared operator +(c1 as integer, c2 as integer) as integer
end operator
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestConversionOperator() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"class C
[|shared|] public widening operator CType(x as integer) as boolean
end operator
end class",
"
class C
public shared widening operator CType(x as integer) as boolean
end operator
end class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestFixAll1() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"{|FixAllInDocument:friend|} protected class C
friend protected class Nested
end class
end class",
"
protected friend class C
protected friend class Nested
end class
end class
")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestFixAll2() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"friend protected class C
{|FixAllInDocument:friend|} protected class Nested
end class
end class
",
"
protected friend class C
protected friend class Nested
end class
end class
")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestTrivia1() As Threading.Tasks.Task
Await TestInRegularAndScript1Async(
"
''' Doc comment
[|friend|] protected class C
end class
",
"
''' Doc comment
protected friend class C
end class
", ignoreTrivia:=False)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)>
Public Async Function TestTrivia3() As Task
Await TestInRegularAndScript1Async(
"
#if true
[|friend|] protected class C
end class
#end if
",
"
#if true
protected friend class C
end class
#end if
", ignoreTrivia:=False)
End Function
End Class
End Namespace
......@@ -88,6 +88,9 @@
<Compile Include="InitializeParameter\CSharpAddParameterCheckCodeRefactoringProvider.cs" />
<Compile Include="InitializeParameter\CSharpInitializeMemberFromParameterCodeRefactoringProvider.cs" />
<Compile Include="InitializeParameter\InitializeParameterHelpers.cs" />
<Compile Include="OrderModifiers\CSharpOrderModifiersCodeFixProvider.cs" />
<Compile Include="OrderModifiers\CSharpOrderModifiersDiagnosticAnalyzer.cs" />
<Compile Include="OrderModifiers\CSharpOrderModifiersHelper.cs" />
<Compile Include="RemoveUnreachableCode\CSharpRemoveUnreachableCodeCodeFixProvider.cs" />
<Compile Include="RemoveUnreachableCode\CSharpRemoveUnreachableCodeDiagnosticAnalyzer.cs" />
<Compile Include="RemoveUnreachableCode\RemoveUnreachableCodeHelpers.cs" />
......
// 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.Generic;
using System.Composition;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.OrderModifiers;
namespace Microsoft.CodeAnalysis.CSharp.OrderModifiers
{
[ExportCodeFixProvider(LanguageNames.CSharp), Shared]
internal class CSharpOrderModifiersCodeFixProvider : AbstractOrderModifiersCodeFixProvider
{
public CSharpOrderModifiersCodeFixProvider()
: base(CSharpSyntaxFactsService.Instance, CSharpCodeStyleOptions.PreferredModifierOrder, CSharpOrderModifiersHelper.Instance)
{
}
protected override SyntaxTokenList TokenList(IEnumerable<SyntaxToken> tokens)
=> SyntaxFactory.TokenList(tokens);
}
}
// 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.Generic;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.OrderModifiers;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CSharp.OrderModifiers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class CSharpOrderModifiersDiagnosticAnalyzer : AbstractOrderModifiersDiagnosticAnalyzer
{
public CSharpOrderModifiersDiagnosticAnalyzer()
: base(CSharpSyntaxFactsService.Instance, CSharpCodeStyleOptions.PreferredModifierOrder, CSharpOrderModifiersHelper.Instance)
{
}
protected override void Recurse(
SyntaxTreeAnalysisContext context,
Dictionary<int, int> preferredOrder,
DiagnosticDescriptor descriptor,
SyntaxNode root)
{
foreach (var child in root.ChildNodesAndTokens())
{
if (child.IsNode)
{
var node = child.AsNode();
if (node is MemberDeclarationSyntax memberDeclaration)
{
CheckModifiers(context, preferredOrder, descriptor, memberDeclaration);
// Recurse and check children. Note: we only do this if we're on an actual
// member declaration. Once we hit something that isn't, we don't need to
// keep recursing. This prevents us from actually entering things like method
// bodies.
Recurse(context, preferredOrder, descriptor, node);
}
else if (node is AccessorListSyntax accessorList)
{
foreach (var accessor in accessorList.Accessors)
{
CheckModifiers(context, preferredOrder, descriptor, accessor);
}
}
}
}
}
}
}
// 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.Generic;
using Microsoft.CodeAnalysis.OrderModifiers;
namespace Microsoft.CodeAnalysis.CSharp.OrderModifiers
{
internal class CSharpOrderModifiersHelper : AbstractOrderModifiersHelpers
{
public static readonly CSharpOrderModifiersHelper Instance = new CSharpOrderModifiersHelper();
private CSharpOrderModifiersHelper()
{
}
protected override int GetKeywordKind(string trimmed)
{
var kind = SyntaxFacts.GetKeywordKind(trimmed);
return (int)(kind == SyntaxKind.None ? SyntaxFacts.GetContextualKeywordKind(trimmed) : kind);
}
protected override bool TryParse(string value, out Dictionary<int, int> parsed)
{
if (!base.TryParse(value, out parsed))
{
return false;
}
// 'partial' must always go at the end in C#.
parsed[(int)SyntaxKind.PartialKeyword] = int.MaxValue;
return true;
}
}
}
\ No newline at end of file
......@@ -48,6 +48,8 @@ internal static class IDEDiagnosticIds
public const string RemoveUnreachableCodeDiagnosticId = "IDE0035";
public const string OrderModifiers = "IDE0036";
// Analyzer error Ids
public const string AnalyzerChangedId = "IDE1001";
public const string AnalyzerDependencyConflictId = "IDE1002";
......
......@@ -171,6 +171,9 @@
<Compile Include="InitializeParameter\AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs" />
<Compile Include="InitializeParameter\AbstractAddParameterCheckCodeRefactoringProvider.cs" />
<Compile Include="InitializeParameter\AbstractInitializeParameterCodeRefactoringProvider.cs" />
<Compile Include="OrderModifiers\AbstractOrderModifiersDiagnosticAnalyzer.cs" />
<Compile Include="OrderModifiers\AbstractOrderModifiersCodeFixProvider.cs" />
<Compile Include="OrderModifiers\OrderModifiersHelpers.cs" />
<Compile Include="PickMembers\IPickMembersService.cs" />
<Compile Include="PickMembers\PickMembersResult.cs" />
<Compile Include="GenerateFromMembers\SelectedMemberInfo.cs" />
......
......@@ -1926,6 +1926,15 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Modifiers are not ordered.
/// </summary>
internal static string Modifiers_are_not_ordered {
get {
return ResourceManager.GetString("Modifiers_are_not_ordered", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Modifying &apos;{0}&apos; which contains a static variable will prevent the debug session from continuing..
/// </summary>
......@@ -2201,6 +2210,15 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Order modifiers.
/// </summary>
internal static string Order_modifiers {
get {
return ResourceManager.GetString("Order_modifiers", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to overload.
/// </summary>
......
......@@ -1259,4 +1259,10 @@ This version used in: {2}</value>
<data name="Remove_unreachable_code" xml:space="preserve">
<value>Remove unreachable code</value>
</data>
<data name="Modifiers_are_not_ordered" xml:space="preserve">
<value>Modifiers are not ordered</value>
</data>
<data name="Order_modifiers" xml:space="preserve">
<value>Order modifiers</value>
</data>
</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.Generic;
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.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.OrderModifiers
{
internal abstract class AbstractOrderModifiersCodeFixProvider : SyntaxEditorBasedCodeFixProvider
{
private readonly ISyntaxFactsService _syntaxFacts;
private readonly Option<CodeStyleOption<string>> _option;
private readonly AbstractOrderModifiersHelpers _helpers;
protected AbstractOrderModifiersCodeFixProvider(
ISyntaxFactsService syntaxFacts,
Option<CodeStyleOption<string>> option,
AbstractOrderModifiersHelpers helpers)
{
_syntaxFacts = syntaxFacts;
_option = option;
_helpers = helpers;
}
public override ImmutableArray<string> FixableDiagnosticIds { get; } =
ImmutableArray.Create(IDEDiagnosticIds.OrderModifiers);
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 async Task FixAllAsync(
Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken)
{
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var option = options.GetOption(_option);
if (!_helpers.TryGetOrComputePreferredOrder(option.Value, out var preferredOrder))
{
return;
}
foreach (var diagnostic in diagnostics)
{
var memberDeclaration = diagnostic.Location.FindNode(cancellationToken);
editor.ReplaceNode(memberDeclaration, (currentNode, _) =>
{
var modifiers = _syntaxFacts.GetModifiers(currentNode);
var orderedModifiers = TokenList(
modifiers.OrderBy(CompareModifiers)
.Select((t, i) => t.WithTriviaFrom(modifiers[i])));
var updatedMemberDeclaration = _syntaxFacts.WithModifiers(currentNode, orderedModifiers);
return updatedMemberDeclaration;
});
}
return;
// Local functions
int CompareModifiers(SyntaxToken t1, SyntaxToken t2)
=> GetOrder(t1) - GetOrder(t2);
int GetOrder(SyntaxToken token)
=> preferredOrder.TryGetValue(token.RawKind, out var value) ? value : int.MaxValue;
}
protected abstract SyntaxTokenList TokenList(IEnumerable<SyntaxToken> tokens);
private class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument)
: base(FeaturesResources.Order_modifiers, createChangedDocument, FeaturesResources.Order_modifiers)
{
}
}
}
}
// 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.Generic;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.LanguageServices;
namespace Microsoft.CodeAnalysis.OrderModifiers
{
internal abstract class AbstractOrderModifiersDiagnosticAnalyzer : AbstractCodeStyleDiagnosticAnalyzer
{
private readonly ISyntaxFactsService _syntaxFacts;
private readonly Option<CodeStyleOption<string>> _option;
private readonly AbstractOrderModifiersHelpers _helpers;
protected AbstractOrderModifiersDiagnosticAnalyzer(
ISyntaxFactsService syntaxFacts,
Option<CodeStyleOption<string>> option,
AbstractOrderModifiersHelpers helpers)
: base(IDEDiagnosticIds.OrderModifiers,
new LocalizableResourceString(nameof(FeaturesResources.Order_modifiers), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
new LocalizableResourceString(nameof(FeaturesResources.Modifiers_are_not_ordered), FeaturesResources.ResourceManager, typeof(FeaturesResources)))
{
_syntaxFacts = syntaxFacts;
_option = option;
_helpers = helpers;
}
public override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SyntaxAnalysis;
public override bool OpenFileOnly(Workspace workspace) => false;
protected override void InitializeWorker(AnalysisContext context)
{
context.RegisterSyntaxTreeAction(AnalyzeSyntaxTree);
}
private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
{
var cancellationToken = context.CancellationToken;
var syntaxTree = context.Tree;
var root = syntaxTree.GetRoot(cancellationToken);
var optionSet = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();
if (optionSet == null)
{
return;
}
var option = optionSet.GetOption(_option);
if (!_helpers.TryGetOrComputePreferredOrder(option.Value, out var preferredOrder))
{
return;
}
var descriptor = GetDescriptorWithSeverity(option.Notification.Value);
Recurse(context, preferredOrder, descriptor, root);
}
protected abstract void Recurse(
SyntaxTreeAnalysisContext context,
Dictionary<int, int> preferredOrder,
DiagnosticDescriptor descriptor,
SyntaxNode root);
protected void CheckModifiers(
SyntaxTreeAnalysisContext context,
Dictionary<int, int> preferredOrder,
DiagnosticDescriptor descriptor,
SyntaxNode memberDeclaration)
{
var modifiers = _syntaxFacts.GetModifiers(memberDeclaration);
if (!IsOrdered(preferredOrder, modifiers))
{
if (descriptor.DefaultSeverity == DiagnosticSeverity.Hidden)
{
// If the severity is hidden, put the marker on all the modifiers so that the
// user can bring up the fix anywhere in the modifier list.
context.ReportDiagnostic(
Diagnostic.Create(descriptor, context.Tree.GetLocation(
TextSpan.FromBounds(modifiers.First().SpanStart, modifiers.Last().Span.End))));
}
else
{
// If the Severity is not hidden, then just put the user visible portion on the
// first token. That way we don't
context.ReportDiagnostic(
Diagnostic.Create(descriptor, modifiers.First().GetLocation()));
}
}
}
private bool IsOrdered(Dictionary<int, int> preferredOrder, SyntaxTokenList modifiers)
{
if (modifiers.Count >= 2)
{
var lastOrder = int.MinValue;
foreach (var modifier in modifiers)
{
var currentOrder = preferredOrder.TryGetValue(modifier.RawKind, out var value) ? value : int.MaxValue;
if (currentOrder < lastOrder)
{
return false;
}
lastOrder = currentOrder;
}
}
return true;
}
}
}
// 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.Generic;
using System.Threading;
namespace Microsoft.CodeAnalysis.OrderModifiers
{
internal abstract class AbstractOrderModifiersHelpers
{
private static readonly char[] s_comma = { ',' };
/// <remarks>
/// Reference type so we can read/write atomically.
/// </remarks>
private Tuple<string, Dictionary<int, int>> _lastParsed;
protected abstract int GetKeywordKind(string trimmed);
public bool TryGetOrComputePreferredOrder(string value, out Dictionary<int, int> preferredOrder)
{
if (string.IsNullOrWhiteSpace(value))
{
preferredOrder = null;
return false;
}
var lastParsed = Volatile.Read(ref _lastParsed);
if (lastParsed?.Item1 != value)
{
if (!TryParse(value, out var parsed))
{
preferredOrder = null;
return false;
}
lastParsed = Tuple.Create(value, parsed);
Volatile.Write(ref _lastParsed, lastParsed);
}
preferredOrder = lastParsed.Item2;
return true;
}
protected virtual bool TryParse(string value, out Dictionary<int, int> parsed)
{
var result = new Dictionary<int, int>();
var index = 0;
foreach (var piece in value.Split(s_comma, StringSplitOptions.RemoveEmptyEntries))
{
var trimmed = piece.Trim();
var kind = GetKeywordKind(trimmed);
if (kind == 0)
{
parsed = null;
return false;
}
result[kind] = index;
index++;
}
if (result.Count == 0)
{
parsed = null;
return false;
}
parsed = result;
return true;
}
}
}
\ No newline at end of file
......@@ -111,6 +111,9 @@
<Compile Include="CodeFixes\OverloadBase\OverloadBaseCodeFixProvider.vb" />
<Compile Include="ImplementInterface\VisualBasicImplementInterfaceCodeFixProvider.vb" />
<Compile Include="InitializeParameter\VisualBasicInitializeMemberFromParameterCodeRefactoringProvider.vb" />
<Compile Include="OrderModifiers\VisualBasicOrderModifiersHelper.vb" />
<Compile Include="OrderModifiers\VisualBasicOrderModifiersCodeFixProvider.vb" />
<Compile Include="OrderModifiers\VisualBasicOrderModifiersDiagnosticAnalyzer.vb" />
<Compile Include="Structure\Providers\CollectionInitializerStructureProvider.vb" />
<Compile Include="Structure\Providers\ObjectCreationInitializerStructureProvider.vb" />
<Compile Include="QualifyMemberAccess\VisualBasicQualifyMemberAccessCodeFixProvider.vb" />
......
' 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 System.Composition
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.OrderModifiers
Imports Microsoft.CodeAnalysis.VisualBasic.CodeStyle
Namespace Microsoft.CodeAnalysis.VisualBasic.OrderModifiers
<ExportCodeFixProvider(LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicOrderModifiersCodeFixProvider
Inherits AbstractOrderModifiersCodeFixProvider
Public Sub New()
MyBase.New(VisualBasicSyntaxFactsService.Instance,
VisualBasicCodeStyleOptions.PreferredModifierOrder,
VisualBasicOrderModifiersHelper.Instance)
End Sub
Protected Overrides Function TokenList(tokens As IEnumerable(Of SyntaxToken)) As SyntaxTokenList
Return SyntaxFactory.TokenList(tokens)
End Function
End Class
End Namespace
' 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.Diagnostics
Imports Microsoft.CodeAnalysis.OrderModifiers
Imports Microsoft.CodeAnalysis.VisualBasic.CodeStyle
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.OrderModifiers
<DiagnosticAnalyzer(LanguageNames.VisualBasic)>
Friend Class VisualBasicOrderModifiersDiagnosticAnalyzer
Inherits AbstractOrderModifiersDiagnosticAnalyzer
Public Sub New()
MyBase.New(VisualBasicSyntaxFactsService.Instance,
VisualBasicCodeStyleOptions.PreferredModifierOrder,
VisualBasicOrderModifiersHelper.Instance)
End Sub
Protected Overrides Sub Recurse(
context As SyntaxTreeAnalysisContext,
preferredOrder As Dictionary(Of Integer, Integer),
descriptor As DiagnosticDescriptor,
root As SyntaxNode)
For Each child In root.ChildNodesAndTokens()
If child.IsNode Then
Dim declarationStatement = TryCast(child.AsNode(), DeclarationStatementSyntax)
If declarationStatement IsNot Nothing Then
If ShouldCheck(declarationStatement) Then
CheckModifiers(context, preferredOrder, descriptor, declarationStatement)
End If
Recurse(context, preferredOrder, descriptor, declarationStatement)
End If
End If
Next
End Sub
Private Function ShouldCheck(statement As DeclarationStatementSyntax) As Boolean
Dim modifiers = statement.GetModifiers()
If modifiers.Count >= 2 Then
' We'll see modifiers twice in some circumstances. First, on a VB block
' construct, and then on the VB begin statement for that block. In order
' to not double report, only check the statement that teh modifier actually
' belongs to.
Return modifiers.First().Parent Is statement
End If
Return False
End Function
End Class
End Namespace
' 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 System.Collections.Generic
Imports Microsoft.CodeAnalysis.OrderModifiers
Namespace Microsoft.CodeAnalysis.VisualBasic.OrderModifiers
Friend Class VisualBasicOrderModifiersHelper
Inherits AbstractOrderModifiersHelpers
Public Shared ReadOnly Instance As New VisualBasicOrderModifiersHelper()
Private Sub New()
End Sub
Protected Overrides Function GetKeywordKind(trimmed As String) As Integer
Dim kind = SyntaxFacts.GetKeywordKind(trimmed)
Return If(kind = SyntaxKind.None, SyntaxFacts.GetContextualKeywordKind(trimmed), kind)
End Function
'Protected Overrides Function TryParse(String value, out Dictionary<int, int> parsed) As Boolean
'{
' If (!base.TryParse(value, out parsed))
' {
' Return False;
' }
' // 'partial' must always go at the end in C#.
' parsed[(int)SyntaxKind.PartialKeyword] = int.MaxValue;
' Return True;
'}
End Class
End Namespace
\ 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.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Options;
......@@ -140,6 +142,26 @@ internal static class CSharpCodeStyleOptions
EditorConfigStorageLocation.ForBoolCodeStyleOption("csharp_prefer_simple_default_expression"),
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(PreferSimpleDefaultExpression)}")});
private static readonly SyntaxKind[] s_preferredModifierOrderDefault =
{
SyntaxKind.PublicKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.InternalKeyword,
SyntaxKind.StaticKeyword,
SyntaxKind.ExternKeyword,
SyntaxKind.NewKeyword,
SyntaxKind.VirtualKeyword, SyntaxKind.AbstractKeyword, SyntaxKind.SealedKeyword, SyntaxKind.OverrideKeyword,
SyntaxKind.ReadOnlyKeyword,
SyntaxKind.UnsafeKeyword,
SyntaxKind.VolatileKeyword,
SyntaxKind.AsyncKeyword
};
public static readonly Option<CodeStyleOption<string>> PreferredModifierOrder = new Option<CodeStyleOption<string>>(
nameof(CodeStyleOptions), nameof(PreferredModifierOrder),
defaultValue: new CodeStyleOption<string>(string.Join(",", s_preferredModifierOrderDefault.Select(SyntaxFacts.GetText)), NotificationOption.None),
storageLocations: new OptionStorageLocation[] {
EditorConfigStorageLocation.ForStringCodeStyleOption("csharp_preferred_modifier_order"),
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(PreferredModifierOrder)}")});
public static IEnumerable<Option<CodeStyleOption<bool>>> GetCodeStyleOptions()
{
yield return UseImplicitTypeForIntrinsicTypes;
......
......@@ -47,6 +47,8 @@ public override void WriteTo(OptionSet options, ObjectWriter writer, Cancellatio
{
WriteOptionTo(options, option, writer, cancellationToken);
}
WriteOptionTo(options, CSharpCodeStyleOptions.PreferredModifierOrder, writer, cancellationToken);
}
public override OptionSet ReadOptionSetFrom(ObjectReader reader, CancellationToken cancellationToken)
......@@ -65,6 +67,8 @@ public override OptionSet ReadOptionSetFrom(ObjectReader reader, CancellationTok
options = ReadOptionFrom(options, option, reader, cancellationToken);
}
options = ReadOptionFrom(options, CSharpCodeStyleOptions.PreferredModifierOrder, reader, cancellationToken);
return options;
}
......
......@@ -1732,5 +1732,11 @@ public ImmutableArray<SyntaxNode> GetSelectedMembers(SyntaxNode root, TextSpan t
protected override bool ContainsInterleavedDirective(TextSpan span, SyntaxToken token, CancellationToken cancellationToken)
=> token.ContainsInterleavedDirective(span, cancellationToken);
public SyntaxTokenList GetModifiers(SyntaxNode node)
=> node.GetModifiers();
public SyntaxNode WithModifiers(SyntaxNode node, SyntaxTokenList modifiers)
=> node.WithModifiers(modifiers);
}
}
......@@ -7,7 +7,20 @@ namespace Microsoft.CodeAnalysis.CodeStyle
{
internal static class CodeStyleHelpers
{
public static bool TryParseEditorConfigCodeStyleOption(string arg, out CodeStyleOption<bool> option)
public static bool TryParseStringEditorConfigCodeStyleOption(string arg, out CodeStyleOption<string> option)
{
if (TryGetCodeStyleValueAndOptionalNotification(
arg, out string value, out NotificationOption notificationOpt))
{
option = new CodeStyleOption<string>(value, notificationOpt ?? NotificationOption.None);
return true;
}
option = null;
return false;
}
public static bool TryParseBoolEditorConfigCodeStyleOption(string arg, out CodeStyleOption<bool> option)
{
if (TryGetCodeStyleValueAndOptionalNotification(
arg, out string value, out NotificationOption notificationOpt))
......
......@@ -53,7 +53,11 @@ public CodeStyleOption(T value, NotificationOption notification)
private object GetValueForSerialization()
{
if (typeof(T) == typeof(bool))
if (typeof(T) == typeof(string))
{
return Value;
}
else if (typeof(T) == typeof(bool))
{
return Value;
}
......@@ -69,6 +73,10 @@ private object GetValueForSerialization()
private string GetTypeNameForSerialization()
{
if (typeof(T) == typeof(string))
{
return nameof(String);
}
if (typeof(T) == typeof(bool) || IsZeroOrOneValueOfEnum())
{
return nameof(Boolean);
......@@ -140,6 +148,8 @@ public static CodeStyleOption<T> FromXElement(XElement element)
return v => Convert(bool.Parse(v));
case nameof(Int32):
return v => Convert(int.Parse(v));
case nameof(String):
return v => (T)(object)v;
default:
throw new ArgumentException(nameof(type));
}
......
......@@ -295,6 +295,9 @@ internal interface ISyntaxFactsService : ILanguageService
bool ContainsInterleavedDirective(ImmutableArray<SyntaxNode> nodes, CancellationToken cancellationToken);
string GetBannerText(SyntaxNode documentationCommentTriviaSyntax, CancellationToken cancellationToken);
SyntaxTokenList GetModifiers(SyntaxNode node);
SyntaxNode WithModifiers(SyntaxNode node, SyntaxTokenList modifiers);
}
[Flags]
......
......@@ -16,6 +16,9 @@ public static EditorConfigStorageLocation<int> ForInt32Option(string keyName)
public static EditorConfigStorageLocation<CodeStyleOption<bool>> ForBoolCodeStyleOption(string keyName)
=> new EditorConfigStorageLocation<CodeStyleOption<bool>>(keyName, s_parseBoolCodeStyleOption);
public static EditorConfigStorageLocation<CodeStyleOption<string>> ForStringCodeStyleOption(string keyName)
=> new EditorConfigStorageLocation<CodeStyleOption<string>>(keyName, s_parseStringCodeStyleOption);
private static Func<string, Optional<bool>> s_parseBool = ParseBool;
private static Optional<bool> ParseBool(string str)
=> bool.TryParse(str, out var result) ? result : new Optional<bool>();
......@@ -26,6 +29,10 @@ private static Optional<int> ParseInt32(string str)
private static Func<string, Optional<CodeStyleOption<bool>>> s_parseBoolCodeStyleOption = ParseBoolCodeStyleOption;
private static Optional<CodeStyleOption<bool>> ParseBoolCodeStyleOption(string str)
=> CodeStyleHelpers.TryParseEditorConfigCodeStyleOption(str, out var result) ? result : new Optional<CodeStyleOption<bool>>();
=> CodeStyleHelpers.TryParseBoolEditorConfigCodeStyleOption(str, out var result) ? result : new Optional<CodeStyleOption<bool>>();
private static Func<string, Optional<CodeStyleOption<string>>> s_parseStringCodeStyleOption = ParseStringCodeStyleOption;
private static Optional<CodeStyleOption<string>> ParseStringCodeStyleOption(string str)
=> CodeStyleHelpers.TryParseStringEditorConfigCodeStyleOption(str, out var result) ? result : new Optional<CodeStyleOption<string>>();
}
}
......@@ -46,7 +46,7 @@ static void TestParseEditorConfigCodeStyleOption(string args, bool isEnabled, Di
var codeStyleOption = new CodeStyleOption<bool>(value: isEnabled, notification: notificationOption);
CodeStyleHelpers.TryParseEditorConfigCodeStyleOption(args, out var result);
CodeStyleHelpers.TryParseBoolEditorConfigCodeStyleOption(args, out var result);
Assert.True(result.Value == isEnabled,
$"Expected {nameof(isEnabled)} to be {isEnabled}, was {result.Value}");
Assert.True(result.Notification.Value == severity,
......
......@@ -95,6 +95,7 @@
<Compile Include="CodeGeneration\VisualBasicCodeGenerationServiceFactory.vb" />
<Compile Include="CodeGeneration\VisualBasicDeclarationComparer.vb" />
<Compile Include="CodeGeneration\VisualBasicSyntaxGenerator.vb" />
<Compile Include="CodeStyle\VisualBasicCodeStyleOptions.vb" />
<Compile Include="Composition\VisualBasicWorkspaceFeatures.vb" />
<Compile Include="Editing\VisualBasicImportAdder.vb" />
<Compile Include="Execution\VisualBasicOptionsSerializationService.vb" />
......
......@@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.Shared.Extensions
Imports System.Collections.Immutable
Imports Microsoft.CodeAnalysis.VisualBasic.CodeStyle
Namespace Microsoft.CodeAnalysis.CodeCleanup.Providers
<ExportCodeCleanupProvider(PredefinedCodeCleanupProviderNames.NormalizeModifiersOrOperators, LanguageNames.VisualBasic), [Shared]>
......@@ -42,15 +43,8 @@ Namespace Microsoft.CodeAnalysis.CodeCleanup.Providers
' list of modifier syntax kinds in order
' this order will be used when the rewriter re-order modifiers
' PERF: Using UShort instead of SyntaxKind as the element type so that the compiler can use array literal initialization
Private Shared ReadOnly s_modifierKindsInOrder As SyntaxKind() = DirectCast(New UShort() {
SyntaxKind.PartialKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.ProtectedKeyword,
SyntaxKind.PublicKeyword, SyntaxKind.FriendKeyword, SyntaxKind.NotOverridableKeyword, SyntaxKind.OverridableKeyword,
SyntaxKind.MustOverrideKeyword, SyntaxKind.OverloadsKeyword, SyntaxKind.OverridesKeyword, SyntaxKind.MustInheritKeyword,
SyntaxKind.NotInheritableKeyword, SyntaxKind.StaticKeyword, SyntaxKind.SharedKeyword, SyntaxKind.ShadowsKeyword,
SyntaxKind.ReadOnlyKeyword, SyntaxKind.WriteOnlyKeyword, SyntaxKind.DimKeyword, SyntaxKind.ConstKeyword,
SyntaxKind.WithEventsKeyword, SyntaxKind.WideningKeyword, SyntaxKind.NarrowingKeyword, SyntaxKind.CustomKeyword,
SyntaxKind.AsyncKeyword, SyntaxKind.IteratorKeyword},
SyntaxKind())
Private Shared ReadOnly s_modifierKindsInOrder As SyntaxKind() =
VisualBasicCodeStyleOptions.PreferredModifierOrderDefault.ToArray()
Private Shared ReadOnly s_removeDimKeywordSet As HashSet(Of SyntaxKind) = New HashSet(Of SyntaxKind)(SyntaxFacts.EqualityComparer) From {
SyntaxKind.PrivateKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.PublicKeyword, SyntaxKind.FriendKeyword,
......
' 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 System.Collections.Generic
imports System.Collections.Immutable
imports System.Linq
imports Microsoft.CodeAnalysis.CodeStyle
imports Microsoft.CodeAnalysis.Options
Namespace Microsoft.CodeAnalysis.VisualBasic.CodeStyle
Friend Module VisualBasicCodeStyleOptions
Public ReadOnly PreferredModifierOrderDefault As ImmutableArray(Of SyntaxKind) =
ImmutableArray.Create(
SyntaxKind.PartialKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.ProtectedKeyword,
SyntaxKind.PublicKeyword, SyntaxKind.FriendKeyword, SyntaxKind.NotOverridableKeyword, SyntaxKind.OverridableKeyword,
SyntaxKind.MustOverrideKeyword, SyntaxKind.OverloadsKeyword, SyntaxKind.OverridesKeyword, SyntaxKind.MustInheritKeyword,
SyntaxKind.NotInheritableKeyword, SyntaxKind.StaticKeyword, SyntaxKind.SharedKeyword, SyntaxKind.ShadowsKeyword,
SyntaxKind.ReadOnlyKeyword, SyntaxKind.WriteOnlyKeyword, SyntaxKind.DimKeyword, SyntaxKind.ConstKeyword,
SyntaxKind.WithEventsKeyword, SyntaxKind.WideningKeyword, SyntaxKind.NarrowingKeyword, SyntaxKind.CustomKeyword,
SyntaxKind.AsyncKeyword, SyntaxKind.IteratorKeyword)
Public ReadOnly PreferredModifierOrder As [Option](Of CodeStyleOption(Of String)) = New [Option](Of CodeStyleOption(Of String))(
NameOf(CodeStyleOptions), NameOf(PreferredModifierOrder),
New CodeStyleOption(Of String)(String.Join(",", PreferredModifierOrderDefault.Select(AddressOf SyntaxFacts.GetText)), NotificationOption.None),
EditorConfigStorageLocation.ForStringCodeStyleOption("visual_basic_preferred_modifier_order"),
New RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.{NameOf(PreferredModifierOrder)}"))
End Module
End Namespace
\ No newline at end of file
......@@ -6,6 +6,7 @@ Imports System.Threading
Imports Microsoft.CodeAnalysis.Execution
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.VisualBasic.CodeStyle
Namespace Microsoft.CodeAnalysis.VisualBasic.Execution
<ExportLanguageService(GetType(IOptionsSerializationService), LanguageNames.VisualBasic), [Shared]>
......@@ -48,8 +49,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Execution
End Sub
Public Overrides Sub WriteTo(options As OptionSet, writer As ObjectWriter, cancellationToken As CancellationToken)
' no vb specific options
WriteOptionSetTo(options, LanguageNames.VisualBasic, writer, cancellationToken)
WriteOptionTo(options, VisualBasicCodeStyleOptions.PreferredModifierOrder, writer, cancellationToken)
End Sub
Public Overrides Function ReadCompilationOptionsFrom(reader As ObjectReader, cancellationToken As CancellationToken) As CompilationOptions
......@@ -126,8 +127,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Execution
Public Overrides Function ReadOptionSetFrom(reader As ObjectReader, cancellationToken As CancellationToken) As OptionSet
Dim options As OptionSet = New SerializedPartialOptionSet()
' no vb specific options
Return ReadOptionSetFrom(options, LanguageNames.VisualBasic, reader, cancellationToken)
options = ReadOptionSetFrom(options, LanguageNames.VisualBasic, reader, cancellationToken)
options = ReadOptionFrom(options, VisualBasicCodeStyleOptions.PreferredModifierOrder, reader, cancellationToken)
Return options
End Function
End Class
End Namespace
......@@ -158,7 +158,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions
End Function
<Extension()>
Public Function GetModifiers(member As StatementSyntax) As IEnumerable(Of SyntaxToken)
Public Function GetModifiers(member As SyntaxNode) As SyntaxTokenList
If member IsNot Nothing Then
Select Case member.Kind
Case SyntaxKind.ClassBlock,
......@@ -212,11 +212,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions
End Select
End If
Return SpecializedCollections.EmptyEnumerable(Of SyntaxToken)()
Return Nothing
End Function
<Extension()>
Public Function WithModifiers(member As StatementSyntax, modifiers As SyntaxTokenList) As StatementSyntax
Public Function WithModifiers(Of TNode As SyntaxNode)(member As TNode, modifiers As SyntaxTokenList) As TNode
Return DirectCast(WithModifiersHelper(member, modifiers), TNode)
End Function
Private Function WithModifiersHelper(member As SyntaxNode, modifiers As SyntaxTokenList) As SyntaxNode
If member IsNot Nothing Then
Select Case member.Kind
Case SyntaxKind.ClassBlock
......
......@@ -1593,5 +1593,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Private Function ISyntaxFactsService_GetBannerText(documentationCommentTriviaSyntax As SyntaxNode, cancellationToken As CancellationToken) As String Implements ISyntaxFactsService.GetBannerText
Return GetBannerText(documentationCommentTriviaSyntax, cancellationToken)
End Function
Public Function GetModifiers(node As SyntaxNode) As SyntaxTokenList Implements ISyntaxFactsService.GetModifiers
Return node.GetModifiers()
End Function
Public Function WithModifiers(node As SyntaxNode, modifiers As SyntaxTokenList) As SyntaxNode Implements ISyntaxFactsService.WithModifiers
Return node.WithModifiers(modifiers)
End Function
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册