Skip to content
This repository was archived by the owner on Jul 12, 2022. It is now read-only.

Commit 4c6cc9d

Browse files
committed
Initial support for VB private field name rules
1 parent 25b1b18 commit 4c6cc9d

File tree

5 files changed

+463
-212
lines changed

5 files changed

+463
-212
lines changed

src/Microsoft.DotNet.CodeFormatting.Tests/Rules/PrivateFieldNamingRuleTests.cs

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4+
using Microsoft.CodeAnalysis;
45
using Xunit;
56

67
namespace Microsoft.DotNet.CodeFormatting.Tests
@@ -12,10 +13,12 @@ internal override IGlobalSemanticFormattingRule Rule
1213
get { return new Rules.PrivateFieldNamingRule(); }
1314
}
1415

15-
[Fact]
16-
public void TestUnderScoreInPrivateFields()
16+
private sealed class CSharpFields : PrivateFieldNamingRuleTests
1717
{
18-
var text = @"
18+
[Fact]
19+
public void TestUnderScoreInPrivateFields()
20+
{
21+
var text = @"
1922
using System;
2023
class T
2124
{
@@ -29,7 +32,7 @@ class T
2932
[ThreadStatic] static int r;
3033
[ThreadStaticAttribute] static int b_r;
3134
}";
32-
var expected = @"
35+
var expected = @"
3336
using System;
3437
class T
3538
{
@@ -45,13 +48,13 @@ class T
4548
[ThreadStaticAttribute]
4649
static int t_r;
4750
}";
48-
Verify(text, expected);
49-
}
51+
Verify(text, expected);
52+
}
5053

51-
[Fact]
52-
public void CornerCaseNames()
53-
{
54-
var text = @"
54+
[Fact]
55+
public void CornerCaseNames()
56+
{
57+
var text = @"
5558
class C
5659
{
5760
private int x_;
@@ -61,7 +64,7 @@ class C
6164
private int field2_;
6265
";
6366

64-
var expected = @"
67+
var expected = @"
6568
class C
6669
{
6770
private int _x;
@@ -71,13 +74,13 @@ class C
7174
private int _field2;
7275
";
7376

74-
Verify(text, expected, runFormatter: false);
75-
}
77+
Verify(text, expected, runFormatter: false);
78+
}
7679

77-
[Fact]
78-
public void MultipleDeclarators()
79-
{
80-
var text = @"
80+
[Fact]
81+
public void MultipleDeclarators()
82+
{
83+
var text = @"
8184
class C1
8285
{
8386
private int field1, field2, field3;
@@ -94,7 +97,7 @@ class C3
9497
}
9598
";
9699

97-
var expected = @"
100+
var expected = @"
98101
class C1
99102
{
100103
private int _field1, _field2, _field3;
@@ -111,17 +114,17 @@ class C3
111114
}
112115
";
113116

114-
Verify(text, expected, runFormatter: true);
115-
}
116-
117-
/// <summary>
118-
/// If the name is pascal cased make it camel cased during the rewrite. If it is not
119-
/// pascal cased then do not change the casing.
120-
/// </summary>
121-
[Fact]
122-
public void NameCasingField()
123-
{
124-
var text = @"
117+
Verify(text, expected, runFormatter: true);
118+
}
119+
120+
/// <summary>
121+
/// If the name is pascal cased make it camel cased during the rewrite. If it is not
122+
/// pascal cased then do not change the casing.
123+
/// </summary>
124+
[Fact]
125+
public void NameCasingField()
126+
{
127+
var text = @"
125128
class C
126129
{
127130
int Field;
@@ -131,7 +134,7 @@ class C
131134
}
132135
";
133136

134-
var expected = @"
137+
var expected = @"
135138
class C
136139
{
137140
int _field;
@@ -141,8 +144,27 @@ class C
141144
}
142145
";
143146

144-
Verify(text, expected, runFormatter: false);
147+
Verify(text, expected, runFormatter: false);
148+
}
149+
}
145150

151+
private sealed class VisualBasicFields : PrivateFieldNamingRuleTests
152+
{
153+
[Fact]
154+
public void Simple()
155+
{
156+
var text = @"
157+
Class C
158+
Private Field As Integer
159+
End Class";
160+
161+
var expected = @"
162+
Class C
163+
Private _field As Integer
164+
End Class";
165+
166+
Verify(text, expected, runFormatter: false, languageName: LanguageNames.VisualBasic);
167+
}
146168
}
147169
}
148170
}

src/Microsoft.DotNet.CodeFormatting/Microsoft.DotNet.CodeFormatting.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@
9292
<Compile Include="RuleOrderAttribute.cs" />
9393
<Compile Include="Properties\AssemblyInfo.cs" />
9494
<Compile Include="IOrderMetadata.cs" />
95+
<Compile Include="Rules\PrivateFieldNamingRule.CSharp.cs" />
96+
<Compile Include="Rules\PrivateFieldNamingRule.VisualBasic.cs" />
9597
<Compile Include="Rules\SyntaxFormattingRule.cs" />
9698
<Compile Include="Rules\BraceNewLineRule.cs" />
9799
<Compile Include="Rules\CopyrightHeaderRule.VisualBasic.cs" />
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Collections;
6+
using System.Collections.Generic;
7+
using System.ComponentModel.Composition;
8+
using System.Linq;
9+
using System.Text.RegularExpressions;
10+
using System.Threading;
11+
using System.Threading.Tasks;
12+
13+
using Microsoft.CodeAnalysis;
14+
using Microsoft.CodeAnalysis.CSharp;
15+
using Microsoft.CodeAnalysis.CSharp.Syntax;
16+
17+
namespace Microsoft.DotNet.CodeFormatting.Rules
18+
{
19+
internal partial class PrivateFieldNamingRule
20+
{
21+
private sealed class CSharpRule : CommonRule
22+
{
23+
protected override SyntaxNode AddPrivateFieldAnnotations(SyntaxNode syntaxNode, out int count)
24+
{
25+
return CSharpPrivateFieldAnnotationsRewriter.AddAnnotations(syntaxNode, out count);
26+
}
27+
28+
protected override SyntaxNode RemoveRenameAnnotations(SyntaxNode syntaxNode)
29+
{
30+
var rewriter = new CSharpRemoveRenameAnnotationsRewriter();
31+
return rewriter.Visit(syntaxNode);
32+
}
33+
}
34+
35+
/// <summary>
36+
/// This will add an annotation to any private field that needs to be renamed.
37+
/// </summary>
38+
internal sealed class CSharpPrivateFieldAnnotationsRewriter : CSharpSyntaxRewriter
39+
{
40+
private int _count;
41+
42+
internal static SyntaxNode AddAnnotations(SyntaxNode node, out int count)
43+
{
44+
var rewriter = new CSharpPrivateFieldAnnotationsRewriter();
45+
var newNode = rewriter.Visit(node);
46+
count = rewriter._count;
47+
return newNode;
48+
}
49+
50+
public override SyntaxNode VisitFieldDeclaration(FieldDeclarationSyntax node)
51+
{
52+
bool isInstance;
53+
if (NeedsRewrite(node, out isInstance))
54+
{
55+
var list = new List<VariableDeclaratorSyntax>(node.Declaration.Variables.Count);
56+
foreach (var v in node.Declaration.Variables)
57+
{
58+
if (IsGoodPrivateFieldName(v.Identifier.Text, isInstance))
59+
{
60+
list.Add(v);
61+
}
62+
else
63+
{
64+
list.Add(v.WithAdditionalAnnotations(s_markerAnnotation));
65+
_count++;
66+
}
67+
}
68+
69+
var declaration = node.Declaration.WithVariables(SyntaxFactory.SeparatedList(list));
70+
node = node.WithDeclaration(declaration);
71+
72+
return node;
73+
}
74+
75+
return node;
76+
}
77+
78+
private static bool NeedsRewrite(FieldDeclarationSyntax fieldSyntax, out bool isInstance)
79+
{
80+
if (!IsPrivateField(fieldSyntax, out isInstance))
81+
{
82+
return false;
83+
}
84+
85+
foreach (var v in fieldSyntax.Declaration.Variables)
86+
{
87+
if (!IsGoodPrivateFieldName(v.Identifier.ValueText, isInstance))
88+
{
89+
return true;
90+
}
91+
}
92+
93+
return false;
94+
}
95+
96+
private static bool IsPrivateField(FieldDeclarationSyntax fieldSyntax, out bool isInstance)
97+
{
98+
var isPrivate = true;
99+
isInstance = true;
100+
foreach (var modifier in fieldSyntax.Modifiers)
101+
{
102+
switch (modifier.CSharpKind())
103+
{
104+
case SyntaxKind.PublicKeyword:
105+
case SyntaxKind.ConstKeyword:
106+
case SyntaxKind.InternalKeyword:
107+
case SyntaxKind.ProtectedKeyword:
108+
isPrivate = false;
109+
break;
110+
case SyntaxKind.StaticKeyword:
111+
isInstance = false;
112+
break;
113+
}
114+
}
115+
116+
return isPrivate;
117+
}
118+
}
119+
120+
/// <summary>
121+
/// This rewriter exists to work around DevDiv 1086632 in Roslyn. The Rename action is
122+
/// leaving a set of annotations in the tree. These annotations slow down further processing
123+
/// and eventually make the rename operation unusable. As a temporary work around we manually
124+
/// remove these from the tree.
125+
/// </summary>
126+
private sealed class CSharpRemoveRenameAnnotationsRewriter : CSharpSyntaxRewriter
127+
{
128+
public override SyntaxNode Visit(SyntaxNode node)
129+
{
130+
node = base.Visit(node);
131+
if (node != null && node.ContainsAnnotations && node.GetAnnotations(s_renameAnnotationName).Any())
132+
{
133+
node = node.WithoutAnnotations(s_renameAnnotationName);
134+
}
135+
136+
return node;
137+
}
138+
139+
public override SyntaxToken VisitToken(SyntaxToken token)
140+
{
141+
token = base.VisitToken(token);
142+
if (token.ContainsAnnotations && token.GetAnnotations(s_renameAnnotationName).Any())
143+
{
144+
token = token.WithoutAnnotations(s_renameAnnotationName);
145+
}
146+
147+
return token;
148+
}
149+
}
150+
}
151+
}

0 commit comments

Comments
 (0)