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

Commit 8290cef

Browse files
committed
Simple this removal support
This change supports very simple removal of explicit 'this.' usage. It does so when applied to private fields which match the naming guidelines. There is still some work to do here with preserving trivia but overall the rule is functional.
1 parent cf4b485 commit 8290cef

File tree

5 files changed

+174
-0
lines changed

5 files changed

+174
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
</ItemGroup>
106106
<ItemGroup>
107107
<Compile Include="CodeFormattingTestBase.cs" />
108+
<Compile Include="Rules\ExplicitThisRuleTests.cs" />
108109
<Compile Include="Rules\ExplicitVisibilityRuleTests.cs" />
109110
<Compile Include="Rules\HasNewLineBeforeFirstNamespaceFormattingRuleTests.cs" />
110111
<Compile Include="Rules\HasNoIllegalHeadersFormattingRuleTests.cs" />
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Xunit;
7+
8+
namespace Microsoft.DotNet.CodeFormatting.Tests
9+
{
10+
public sealed class ExplicitThisRuleTests : CodeFormattingTestBase
11+
{
12+
internal override IFormattingRule GetFormattingRule()
13+
{
14+
return new Rules.ExplicitThisRule();
15+
}
16+
17+
[Fact]
18+
public void TestFieldUse()
19+
{
20+
var text = @"
21+
class C1
22+
{
23+
int _field1;
24+
string _field2;
25+
string field3;
26+
27+
void Use(int i) { }
28+
29+
void M()
30+
{
31+
Use(_field1);
32+
Use(_field2);
33+
Use(field3);
34+
Use(this._field1);
35+
Use(this._field2);
36+
Use(this.field3);
37+
}
38+
}
39+
";
40+
41+
var expected = @"
42+
class C1
43+
{
44+
int _field1;
45+
string _field2;
46+
string field3;
47+
48+
void Use(int i) { }
49+
50+
void M()
51+
{
52+
Use(_field1);
53+
Use(_field2);
54+
Use(field3);
55+
Use(_field1);
56+
Use(_field2);
57+
Use(this.field3);
58+
}
59+
}
60+
";
61+
Verify(text, expected, runFormatter: false);
62+
}
63+
64+
[Fact]
65+
public void TestFieldAssignment()
66+
{
67+
var text = @"
68+
class C1
69+
{
70+
int _field1;
71+
string _field2;
72+
string field3;
73+
74+
void M()
75+
{
76+
this._field1 = 0;
77+
this._field2 = null;
78+
this.field3 = null;
79+
}
80+
}
81+
";
82+
83+
var expected = @"
84+
class C1
85+
{
86+
int _field1;
87+
string _field2;
88+
string field3;
89+
90+
void M()
91+
{
92+
_field1 = 0;
93+
_field2 = null;
94+
this.field3 = null;
95+
}
96+
}
97+
";
98+
Verify(text, expected, runFormatter: false);
99+
}
100+
}
101+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
<Compile Include="Rules\IsFormattedFormattingRule.cs" />
9595
<Compile Include="Rules\IsSimplifiedFormattingRule.cs" />
9696
<Compile Include="Rules\NonAsciiCharactersAreEscapedInLiteralsRule.cs" />
97+
<Compile Include="Rules\ExplicitThisRule.cs" />
9798
<Compile Include="Rules\RuleExtensions.cs" />
9899
<Compile Include="Rules\RuleOrder.cs" />
99100
<Compile Include="Rules\UsesXunitForTestsFormattingRule.cs" />
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using Microsoft.CodeAnalysis;
8+
using Microsoft.CodeAnalysis.CSharp;
9+
using Microsoft.CodeAnalysis.CSharp.Syntax;
10+
11+
namespace Microsoft.DotNet.CodeFormatting.Rules
12+
{
13+
[RuleOrder(RuleOrder.RemoveExplicitThisRule)]
14+
public sealed class ExplicitThisRule : IFormattingRule
15+
{
16+
private sealed class ExplicitThisRewriter : CSharpSyntaxRewriter
17+
{
18+
private readonly SemanticModel _semanticModel;
19+
private readonly CancellationToken _cancellationToken;
20+
21+
internal ExplicitThisRewriter(SemanticModel semanticModel, CancellationToken cancellationToken)
22+
{
23+
_semanticModel = semanticModel;
24+
}
25+
26+
public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node)
27+
{
28+
node = (MemberAccessExpressionSyntax)base.VisitMemberAccessExpression(node);
29+
var name = node.Name.Identifier.ValueText;
30+
if (node.Expression != null &&
31+
node.Expression.CSharpKind() == SyntaxKind.ThisExpression &&
32+
name.StartsWith("_", StringComparison.Ordinal))
33+
{
34+
var symbolInfo = _semanticModel.GetSymbolInfo(node, _cancellationToken);
35+
if (symbolInfo.Symbol != null && symbolInfo.Symbol.Kind == SymbolKind.Field)
36+
{
37+
var field = (IFieldSymbol)symbolInfo.Symbol;
38+
if (field.DeclaredAccessibility == Accessibility.Private)
39+
{
40+
return node.Name
41+
.WithLeadingTrivia(node.GetLeadingTrivia())
42+
.WithTrailingTrivia(node.GetTrailingTrivia());
43+
}
44+
}
45+
}
46+
47+
return node;
48+
}
49+
50+
public override SyntaxNode VisitAssignmentExpression(AssignmentExpressionSyntax node)
51+
{
52+
return base.VisitAssignmentExpression(node);
53+
}
54+
}
55+
56+
public async Task<Document> ProcessAsync(Document document, CancellationToken cancellationToken)
57+
{
58+
var syntaxNode = await document.GetSyntaxRootAsync(cancellationToken) as CSharpSyntaxNode;
59+
if (syntaxNode == null)
60+
{
61+
return document;
62+
}
63+
64+
var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
65+
var rewriter = new ExplicitThisRewriter(semanticModel, cancellationToken);
66+
var newNode = rewriter.Visit(syntaxNode);
67+
return document.WithSyntaxRoot(newNode);
68+
}
69+
}
70+
}

src/Microsoft.DotNet.CodeFormatting/Rules/RuleOrder.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ internal static class RuleOrder
2525
public const int IsFormattedFormattingRule = 11;
2626
public const int UsesXunitForTestsFormattingRule = 12;
2727
public const int NonAsciiChractersAreEscapedInLiterals = 13;
28+
public const int RemoveExplicitThisRule = 14;
2829
}
2930
}

0 commit comments

Comments
 (0)