@@ -19,36 +19,41 @@ internal sealed class ExplicitVisibilityRule : IFormattingRule
19
19
{
20
20
private sealed class VisibilityRewriter : CSharpSyntaxRewriter
21
21
{
22
+ private readonly Document _document ;
23
+ private readonly CancellationToken _cancellationToken ;
24
+ private SemanticModel _semanticModel ;
25
+
26
+ internal VisibilityRewriter ( Document document , CancellationToken cancellationToken )
27
+ {
28
+ _document = document ;
29
+ _cancellationToken = cancellationToken ;
30
+ }
31
+
22
32
public override SyntaxNode VisitClassDeclaration ( ClassDeclarationSyntax node )
23
33
{
24
34
node = ( ClassDeclarationSyntax ) base . VisitClassDeclaration ( node ) ;
25
- SyntaxKind visibilityKind = GetTypeDefaultVisibility ( node ) ;
26
- return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , visibilityKind ) ;
35
+ return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , ( ) => GetTypeDefaultVisibility ( node ) ) ;
27
36
}
28
37
29
38
public override SyntaxNode VisitInterfaceDeclaration ( InterfaceDeclarationSyntax node )
30
39
{
31
- SyntaxKind visibilityKind = GetTypeDefaultVisibility ( node ) ;
32
- return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , visibilityKind ) ;
40
+ return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , ( ) => GetTypeDefaultVisibility ( node ) ) ;
33
41
}
34
42
35
43
public override SyntaxNode VisitStructDeclaration ( StructDeclarationSyntax node )
36
44
{
37
45
node = ( StructDeclarationSyntax ) base . VisitStructDeclaration ( node ) ;
38
- SyntaxKind visibilityKind = GetTypeDefaultVisibility ( node ) ;
39
- return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , visibilityKind ) ;
46
+ return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , ( ) => GetTypeDefaultVisibility ( node ) ) ;
40
47
}
41
48
42
49
public override SyntaxNode VisitDelegateDeclaration ( DelegateDeclarationSyntax node )
43
50
{
44
- SyntaxKind visibilityKind = GetTypeDefaultVisibility ( node ) ;
45
- return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , visibilityKind ) ;
51
+ return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , ( ) => GetDelegateTypeDefaultVisibility ( node ) ) ;
46
52
}
47
53
48
54
public override SyntaxNode VisitEnumDeclaration ( EnumDeclarationSyntax node )
49
55
{
50
- SyntaxKind visibilityKind = GetTypeDefaultVisibility ( node ) ;
51
- return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , visibilityKind ) ;
56
+ return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , ( ) => GetTypeDefaultVisibility ( node ) ) ;
52
57
}
53
58
54
59
public override SyntaxNode VisitConstructorDeclaration ( ConstructorDeclarationSyntax node )
@@ -58,7 +63,7 @@ public override SyntaxNode VisitConstructorDeclaration(ConstructorDeclarationSyn
58
63
return node ;
59
64
}
60
65
61
- return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , SyntaxKind . PrivateKeyword ) ;
66
+ return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , ( ) => SyntaxKind . PrivateKeyword ) ;
62
67
}
63
68
64
69
public override SyntaxNode VisitMethodDeclaration ( MethodDeclarationSyntax node )
@@ -68,7 +73,7 @@ public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
68
73
return node ;
69
74
}
70
75
71
- return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , SyntaxKind . PrivateKeyword ) ;
76
+ return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , ( ) => SyntaxKind . PrivateKeyword ) ;
72
77
}
73
78
74
79
public override SyntaxNode VisitPropertyDeclaration ( PropertyDeclarationSyntax node )
@@ -78,7 +83,7 @@ public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax no
78
83
return node ;
79
84
}
80
85
81
- return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , SyntaxKind . PrivateKeyword ) ;
86
+ return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , ( ) => SyntaxKind . PrivateKeyword ) ;
82
87
}
83
88
84
89
public override SyntaxNode VisitEventDeclaration ( EventDeclarationSyntax node )
@@ -88,24 +93,82 @@ public override SyntaxNode VisitEventDeclaration(EventDeclarationSyntax node)
88
93
return node ;
89
94
}
90
95
91
- return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , SyntaxKind . PrivateKeyword ) ;
96
+ return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , ( ) => SyntaxKind . PrivateKeyword ) ;
92
97
}
93
98
94
99
public override SyntaxNode VisitEventFieldDeclaration ( EventFieldDeclarationSyntax node )
95
100
{
96
- return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , SyntaxKind . PrivateKeyword ) ;
101
+ return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , ( ) => SyntaxKind . PrivateKeyword ) ;
97
102
}
98
103
99
104
public override SyntaxNode VisitFieldDeclaration ( FieldDeclarationSyntax node )
100
105
{
101
- return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , SyntaxKind . PrivateKeyword ) ;
106
+ return EnsureVisibility ( node , node . Modifiers , ( x , l ) => x . WithModifiers ( l ) , ( ) => SyntaxKind . PrivateKeyword ) ;
107
+ }
108
+
109
+ private SyntaxKind GetTypeDefaultVisibility ( BaseTypeDeclarationSyntax node )
110
+ {
111
+ // In the case of partial types we need to use the existing visibility if it exists
112
+ if ( node . Modifiers . Any ( x => x . CSharpContextualKind ( ) == SyntaxKind . PartialKeyword ) )
113
+ {
114
+ SyntaxKind ? kind = GetExistingPartialVisibility ( node ) ;
115
+ if ( kind . HasValue )
116
+ {
117
+ return kind . Value ;
118
+ }
119
+ }
120
+
121
+ return GetDelegateTypeDefaultVisibility ( node ) ;
102
122
}
103
123
104
- private static SyntaxKind GetTypeDefaultVisibility ( SyntaxNode node )
124
+ private SyntaxKind GetDelegateTypeDefaultVisibility ( SyntaxNode node )
105
125
{
106
126
return IsNestedDeclaration ( node ) ? SyntaxKind . PrivateKeyword : SyntaxKind . InternalKeyword ;
107
127
}
108
128
129
+ private SyntaxKind ? GetExistingPartialVisibility ( BaseTypeDeclarationSyntax declarationSyntax )
130
+ {
131
+ // Getting the SemanticModel is a relatively expensive operation. Can take a few seconds in
132
+ // projects of significant size. It is delay created to avoid this in files which already
133
+ // conform to the standards.
134
+ if ( _semanticModel == null )
135
+ {
136
+ _semanticModel = _document . GetSemanticModelAsync ( _cancellationToken ) . Result ;
137
+ }
138
+
139
+ var symbol = _semanticModel . GetDeclaredSymbol ( declarationSyntax , _cancellationToken ) ;
140
+ if ( symbol == null )
141
+ {
142
+ return null ;
143
+ }
144
+
145
+ switch ( symbol . DeclaredAccessibility )
146
+ {
147
+ case Accessibility . Friend :
148
+ return SyntaxKind . InternalKeyword ;
149
+ case Accessibility . Public :
150
+ return SyntaxKind . PublicKeyword ;
151
+ case Accessibility . Private :
152
+ return SyntaxKind . PrivateKeyword ;
153
+ case Accessibility . Protected :
154
+ return SyntaxKind . ProtectedKeyword ;
155
+ default : return null ;
156
+ }
157
+ }
158
+
159
+ private static SyntaxKind ? GetVisibilityModifier ( SyntaxTokenList list )
160
+ {
161
+ foreach ( var token in list )
162
+ {
163
+ if ( SyntaxFacts . IsAccessibilityModifier ( token . CSharpKind ( ) ) )
164
+ {
165
+ return token . CSharpKind ( ) ;
166
+ }
167
+ }
168
+
169
+ return null ;
170
+ }
171
+
109
172
private static bool IsNestedDeclaration ( SyntaxNode node )
110
173
{
111
174
var current = node . Parent ;
@@ -126,15 +189,16 @@ private static bool IsNestedDeclaration(SyntaxNode node)
126
189
/// Return a node declaration that has a visibility modifier. If one isn't present it will be added as the
127
190
/// first modifier. Any trivia before the node will be added as leading trivia to the added <see cref="SyntaxToken"/>.
128
191
/// </summary>
129
- private static MemberDeclarationSyntax EnsureVisibility < T > ( T node , SyntaxTokenList originalModifiers , Func < T , SyntaxTokenList , T > withModifiers , SyntaxKind visibilityKind ) where T : MemberDeclarationSyntax
192
+ private static MemberDeclarationSyntax EnsureVisibility < T > ( T node , SyntaxTokenList originalModifiers , Func < T , SyntaxTokenList , T > withModifiers , Func < SyntaxKind > getDefaultVisibility ) where T : MemberDeclarationSyntax
130
193
{
131
- Debug . Assert ( SyntaxFacts . IsAccessibilityModifier ( visibilityKind ) ) ;
132
-
133
194
if ( originalModifiers . Any ( x => SyntaxFacts . IsAccessibilityModifier ( x . CSharpKind ( ) ) ) )
134
195
{
135
196
return node ;
136
197
}
137
198
199
+ SyntaxKind visibilityKind = getDefaultVisibility ( ) ;
200
+ Debug . Assert ( SyntaxFacts . IsAccessibilityModifier ( visibilityKind ) ) ;
201
+
138
202
SyntaxTokenList modifierList ;
139
203
if ( originalModifiers . Count == 0 )
140
204
{
@@ -179,7 +243,7 @@ public async Task<Document> ProcessAsync(Document document, CancellationToken ca
179
243
return document ;
180
244
}
181
245
182
- var rewriter = new VisibilityRewriter ( ) ;
246
+ var rewriter = new VisibilityRewriter ( document , cancellationToken ) ;
183
247
var newNode = rewriter . Visit ( syntaxNode ) ;
184
248
return document . WithSyntaxRoot ( newNode ) ;
185
249
}
0 commit comments