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

Commit b08e58c

Browse files
committed
Merge pull request #80 from jaredpar/fix-vb
Fix VB trivia handling with comments + attrs
2 parents 32fec62 + 72fc879 commit b08e58c

File tree

2 files changed

+193
-19
lines changed

2 files changed

+193
-19
lines changed

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

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,42 @@ Friend Enum E
448448
Verify(text, expected, runFormatter: false, languageName: LanguageNames.VisualBasic);
449449
}
450450

451+
[Fact]
452+
public void TypeWithCommentAndAttribute()
453+
{
454+
var text = @"
455+
' Hello
456+
<Attr>
457+
Class C
458+
End Class";
459+
460+
var expected = @"
461+
' Hello
462+
<Attr>
463+
Friend Class C
464+
End Class";
465+
466+
Verify(text, expected, runFormatter: false, languageName: LanguageNames.VisualBasic);
467+
}
468+
469+
[Fact]
470+
public void TypePartialWithCommentAndAttribute()
471+
{
472+
var text = @"
473+
' Hello
474+
<Attr>
475+
Partial Class C
476+
End Class";
477+
478+
var expected = @"
479+
' Hello
480+
<Attr>
481+
Friend Partial Class C
482+
End Class";
483+
484+
Verify(text, expected, runFormatter: false, languageName: LanguageNames.VisualBasic);
485+
}
486+
451487
/// <summary>
452488
/// It is interesting to note that nested typs in VB.Net default to public accessibility
453489
/// instead of private as C# does.
@@ -506,6 +542,28 @@ End Sub
506542
Verify(text, expected, runFormatter: false, languageName: LanguageNames.VisualBasic);
507543
}
508544

545+
[Fact]
546+
public void MethodWithCommentAndAttribute()
547+
{
548+
var text = @"
549+
Class C
550+
' A Comment
551+
<Attr>
552+
Sub M1()
553+
End Sub
554+
End Class";
555+
556+
var expected = @"
557+
Friend Class C
558+
' A Comment
559+
<Attr>
560+
Public Sub M1()
561+
End Sub
562+
End Class";
563+
564+
Verify(text, expected, runFormatter: false, languageName: LanguageNames.VisualBasic);
565+
}
566+
509567
[Fact]
510568
public void Fields()
511569
{
@@ -546,6 +604,36 @@ End Sub
546604
Verify(text, expected, runFormatter: false, languageName: LanguageNames.VisualBasic);
547605
}
548606

607+
[Fact]
608+
public void ConstructorsWithCommentAndAttribute()
609+
{
610+
var text = @"
611+
Class C
612+
' Hello
613+
<Attr>
614+
Sub New()
615+
End Sub
616+
' Hello
617+
<Attr>
618+
Shared Sub New()
619+
End Sub
620+
End Class";
621+
622+
var expected = @"
623+
Friend Class C
624+
' Hello
625+
<Attr>
626+
Public Sub New()
627+
End Sub
628+
' Hello
629+
<Attr>
630+
Shared Sub New()
631+
End Sub
632+
End Class";
633+
634+
Verify(text, expected, runFormatter: false, languageName: LanguageNames.VisualBasic);
635+
}
636+
549637
[Fact]
550638
public void InterfaceMembers()
551639
{

src/Microsoft.DotNet.CodeFormatting/Rules/ExplicitVisibilityRule.VisualBasic.cs

Lines changed: 105 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,34 +31,64 @@ internal VisualBasicVisibilityRewriter(Document document, CancellationToken canc
3131
public override SyntaxNode VisitClassBlock(ClassBlockSyntax originalNode)
3232
{
3333
var node = (ClassBlockSyntax)base.VisitClassBlock(originalNode);
34-
var begin = (ClassStatementSyntax)EnsureVisibility(node.ClassStatement, node.ClassStatement.Modifiers, (x, l) => x.WithModifiers(l), () => GetTypeDefaultVisibility(originalNode));
34+
var begin = (ClassStatementSyntax)EnsureVisibility(
35+
node.ClassStatement,
36+
node.ClassStatement.ClassKeyword,
37+
node.ClassStatement.Modifiers,
38+
(x, k) => x.WithClassKeyword(k),
39+
(x, l) => x.WithModifiers(l),
40+
() => GetTypeDefaultVisibility(originalNode));
3541
return node.WithClassStatement(begin);
3642
}
3743

3844
public override SyntaxNode VisitStructureBlock(StructureBlockSyntax originalNode)
3945
{
4046
var node = (StructureBlockSyntax)base.VisitStructureBlock(originalNode);
41-
var begin = (StructureStatementSyntax)EnsureVisibility(node.StructureStatement, node.StructureStatement.Modifiers, (x, l) => x.WithModifiers(l), () => GetTypeDefaultVisibility(originalNode));
47+
var begin = (StructureStatementSyntax)EnsureVisibility(
48+
node.StructureStatement,
49+
node.StructureStatement.StructureKeyword,
50+
node.StructureStatement.Modifiers,
51+
(x, k) => x.WithStructureKeyword(k),
52+
(x, l) => x.WithModifiers(l),
53+
() => GetTypeDefaultVisibility(originalNode));
4254
return node.WithStructureStatement(begin);
4355
}
4456

4557
public override SyntaxNode VisitInterfaceBlock(InterfaceBlockSyntax originalNode)
4658
{
4759
var node = (InterfaceBlockSyntax)base.VisitInterfaceBlock(originalNode);
48-
var begin = (InterfaceStatementSyntax)EnsureVisibility(node.InterfaceStatement, node.InterfaceStatement.Modifiers, (x, l) => x.WithModifiers(l), () => GetTypeDefaultVisibility(originalNode));
60+
var begin = (InterfaceStatementSyntax)EnsureVisibility(
61+
node.InterfaceStatement,
62+
node.InterfaceStatement.InterfaceKeyword,
63+
node.InterfaceStatement.Modifiers,
64+
(x, k) => x.WithInterfaceKeyword(k),
65+
(x, l) => x.WithModifiers(l),
66+
() => GetTypeDefaultVisibility(originalNode));
4967
return node.WithInterfaceStatement(begin);
5068
}
5169

5270
public override SyntaxNode VisitModuleBlock(ModuleBlockSyntax node)
5371
{
5472
node = (ModuleBlockSyntax)base.VisitModuleBlock(node);
55-
var begin = (ModuleStatementSyntax)EnsureVisibility(node.ModuleStatement, node.ModuleStatement.Modifiers, (x, l) => x.WithModifiers(l), () => SyntaxKind.FriendKeyword);
73+
var begin = (ModuleStatementSyntax)EnsureVisibility(
74+
node.ModuleStatement,
75+
node.ModuleStatement.ModuleKeyword,
76+
node.ModuleStatement.Modifiers,
77+
(x, k) => x.WithModuleKeyword(k),
78+
(x, l) => x.WithModifiers(l),
79+
() => SyntaxKind.FriendKeyword);
5680
return node.WithModuleStatement(begin);
5781
}
5882

5983
public override SyntaxNode VisitEnumBlock(EnumBlockSyntax node)
6084
{
61-
var enumStatement = (EnumStatementSyntax)EnsureVisibility(node.EnumStatement, node.EnumStatement.Modifiers, (x, l) => x.WithModifiers(l), () => GetDelegateTypeDefaultVisibility(node));
85+
var enumStatement = (EnumStatementSyntax)EnsureVisibility(
86+
node.EnumStatement,
87+
node.EnumStatement.EnumKeyword,
88+
node.EnumStatement.Modifiers,
89+
(x, k) => x.WithEnumKeyword(k),
90+
(x, l) => x.WithModifiers(l),
91+
() => GetDelegateTypeDefaultVisibility(node));
6292
return node.WithEnumStatement(enumStatement);
6393
}
6494

@@ -69,7 +99,13 @@ public override SyntaxNode VisitMethodStatement(MethodStatementSyntax node)
6999
return node;
70100
}
71101

72-
return EnsureVisibility(node, node.Modifiers, (x, l) => x.WithModifiers(l), () => SyntaxKind.PublicKeyword);
102+
return EnsureVisibility(
103+
node,
104+
node.SubOrFunctionKeyword,
105+
node.Modifiers,
106+
(x, k) => x.WithSubOrFunctionKeyword(k),
107+
(x, l) => x.WithModifiers(l),
108+
() => SyntaxKind.PublicKeyword);
73109
}
74110

75111
public override SyntaxNode VisitSubNewStatement(SubNewStatementSyntax node)
@@ -79,12 +115,22 @@ public override SyntaxNode VisitSubNewStatement(SubNewStatementSyntax node)
79115
return node;
80116
}
81117

82-
return EnsureVisibility(node, node.Modifiers, (x, l) => x.WithModifiers(l), () => SyntaxKind.PublicKeyword);
118+
return EnsureVisibility(
119+
node,
120+
node.SubKeyword,
121+
node.Modifiers,
122+
(x, k) => x.WithSubKeyword(k),
123+
(x, l) => x.WithModifiers(l),
124+
() => SyntaxKind.PublicKeyword);
83125
}
84126

85127
public override SyntaxNode VisitFieldDeclaration(FieldDeclarationSyntax node)
86128
{
87-
node = (FieldDeclarationSyntax)EnsureVisibility(node, node.Modifiers, (x, l) => x.WithModifiers(l), () => SyntaxKind.PrivateKeyword);
129+
node = (FieldDeclarationSyntax)EnsureVisibility(
130+
node,
131+
node.Modifiers,
132+
(x, l) => x.WithModifiers(l),
133+
() => SyntaxKind.PrivateKeyword);
88134

89135
// Now that the field has an explicit modifier remove any Dim modifiers on it
90136
// as it is now redundant
@@ -204,11 +250,59 @@ private static bool IsNestedDeclaration(SyntaxNode node)
204250
return false;
205251
}
206252

253+
private static SyntaxNode EnsureVisibility<T>(T node, SyntaxToken keyword, SyntaxTokenList originalModifiers, Func<T, SyntaxToken, T> withKeyword, Func<T, SyntaxTokenList, T> withModifiers, Func<SyntaxKind> getDefaultVisibility) where T : SyntaxNode
254+
{
255+
Func<SyntaxKind, T> withFirstModifier = (visibilityKind) =>
256+
{
257+
var leadingTrivia = keyword.LeadingTrivia;
258+
node = withKeyword(node, keyword.WithLeadingTrivia());
259+
260+
var visibilityToken = SyntaxFactory.Token(
261+
leadingTrivia,
262+
visibilityKind,
263+
SyntaxFactory.TriviaList(SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, " ")));
264+
265+
var modifierList = SyntaxFactory.TokenList(visibilityToken);
266+
return withModifiers(node, modifierList);
267+
};
268+
269+
return EnsureVisibilityCore(
270+
node,
271+
originalModifiers,
272+
withFirstModifier,
273+
withModifiers,
274+
getDefaultVisibility);
275+
}
276+
277+
private static SyntaxNode EnsureVisibility<T>(T node, SyntaxTokenList originalModifiers, Func<T, SyntaxTokenList, T> withModifiers, Func<SyntaxKind> getDefaultVisibility) where T : SyntaxNode
278+
{
279+
Func<SyntaxKind, T> withFirstModifier = (visibilityKind) =>
280+
{
281+
var leadingTrivia = node.GetLeadingTrivia();
282+
node = node.WithLeadingTrivia();
283+
284+
var visibilityToken = SyntaxFactory.Token(
285+
leadingTrivia,
286+
visibilityKind,
287+
SyntaxFactory.TriviaList(SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, " ")));
288+
289+
var modifierList = SyntaxFactory.TokenList(visibilityToken);
290+
return withModifiers(node, modifierList);
291+
};
292+
293+
return EnsureVisibilityCore(
294+
node,
295+
originalModifiers,
296+
withFirstModifier,
297+
withModifiers,
298+
getDefaultVisibility);
299+
}
300+
207301
/// <summary>
208302
/// Return a node declaration that has a visibility modifier. If one isn't present it will be added as the
209303
/// first modifier. Any trivia before the node will be added as leading trivia to the added <see cref="SyntaxToken"/>.
210304
/// </summary>
211-
private static SyntaxNode EnsureVisibility<T>(T node, SyntaxTokenList originalModifiers, Func<T, SyntaxTokenList, T> withModifiers, Func<SyntaxKind> getDefaultVisibility) where T : SyntaxNode
305+
private static SyntaxNode EnsureVisibilityCore<T>(T node, SyntaxTokenList originalModifiers, Func<SyntaxKind, T> withFirstModifier, Func<T, SyntaxTokenList, T> withModifiers, Func<SyntaxKind> getDefaultVisibility) where T : SyntaxNode
212306
{
213307
if (originalModifiers.Any(x => SyntaxFacts.IsAccessibilityModifier(x.Kind())))
214308
{
@@ -221,15 +315,7 @@ private static SyntaxNode EnsureVisibility<T>(T node, SyntaxTokenList originalMo
221315
SyntaxTokenList modifierList;
222316
if (originalModifiers.Count == 0)
223317
{
224-
var leadingTrivia = node.GetLeadingTrivia();
225-
node = node.WithLeadingTrivia();
226-
227-
var visibilityToken = SyntaxFactory.Token(
228-
leadingTrivia,
229-
visibilityKind,
230-
SyntaxFactory.TriviaList(SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, " ")));
231-
232-
modifierList = SyntaxFactory.TokenList(visibilityToken);
318+
return withFirstModifier(visibilityKind);
233319
}
234320
else
235321
{
@@ -248,9 +334,9 @@ private static SyntaxNode EnsureVisibility<T>(T node, SyntaxTokenList originalMo
248334
}
249335

250336
modifierList = SyntaxFactory.TokenList(list);
337+
return withModifiers(node, modifierList);
251338
}
252339

253-
return withModifiers(node, modifierList);
254340
}
255341
}
256342
}

0 commit comments

Comments
 (0)