提交 dff4233f 编写于 作者: T Tomas Matousek

Handle all expression-bodied members correctly in TryGetActiveTokens

上级 e4b04d35
......@@ -488,6 +488,160 @@ public C(int a)
Array.Empty<string>());
}
[Fact]
public void Constructor_ExpressionBodied_LineChange1()
{
string src1 = @"
class C
{
int _a;
public C(int a) =>
_a = a;
}
";
string src2 = @"
class C
{
int _a;
public C(int a) =>
_a = a;
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(5, 6) },
Array.Empty<string>());
}
[Fact]
public void Constructor_ExpressionBodied_LineChange2()
{
string src1 = @"
class C
{
int _a;
public C(int a)
=> _a = a;
}
";
string src2 = @"
class C
{
int _a;
public C(int a)
=> _a = a;
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(5, 6) },
Array.Empty<string>());
}
[Fact]
public void Constructor_ExpressionBodied_LineChange3()
{
string src1 = @"
class C
{
int _a;
public C(int a) =>
_a = a;
}
";
string src2 = @"
class C
{
int _a;
public C(int a) =>
_a = a;
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(5, 6) },
Array.Empty<string>());
}
[Fact]
public void Constructor_ExpressionBodied_LineChange4()
{
string src1 = @"
class C
{
int _a;
public C(int a)
=>
_a = a;
}
";
string src2 = @"
class C
{
int _a;
public C(int a)
=>
_a = a;
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(6, 8) },
Array.Empty<string>());
}
[Fact]
public void Constructor_ExpressionBodiedWithBase_LineChange1()
{
string src1 = @"
class C
{
int _a;
public C(int a)
: base() => _a = a;
}
";
string src2 = @"
class C
{
int _a;
public C(int a)
: base() => _a = a;
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(5, 6) },
Array.Empty<string>());
}
[Fact]
public void Constructor_ExpressionBodiedWithBase_Recompile1()
{
string src1 = @"
class C
{
int _a;
public C(int a)
: base() =>
_a = a;
}
";
string src2 = @"
class C
{
int _a;
public C(int a)
: base() => _a = a;
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
Array.Empty<LineChange>(),
new string[] { "public C(int a)" });
}
[Fact]
public void Constructor_Recompile1()
{
......@@ -570,6 +724,77 @@ public C(int a)
#endregion
#region Destructors
[Fact]
public void Destructor_LineChange1()
{
string src1 = @"
class C
{
~C()
{
}
}
";
string src2 = @"
class C
{
~C()
{
}
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(5, 4) },
Array.Empty<string>());
}
[Fact]
public void Destructor_ExpressionBodied_LineChange1()
{
string src1 = @"
class C
{
~C() => F();
}
";
string src2 = @"
class C
{
~C() =>
F();
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(3, 4) },
Array.Empty<string>());
}
[Fact]
public void Destructor_ExpressionBodied_LineChange2()
{
string src1 = @"
class C
{
~C() => F();
}
";
string src2 = @"
class C
{
~C()
=> F();
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(3, 4) },
Array.Empty<string>());
}
#endregion
#region Field Initializers
[Fact]
......@@ -935,6 +1160,48 @@ class C
Array.Empty<string>());
}
[Fact]
public void Property_GetterExpressionBody1()
{
string src1 = @"
class C
{
int P { get => 1; }
}
";
string src2 = @"
class C
{
int P { get =>
1; }
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(3, 4) },
Array.Empty<string>());
}
[Fact]
public void Property_SetterExpressionBody1()
{
string src1 = @"
class C
{
int P { set => F(); }
}
";
string src2 = @"
class C
{
int P { set =>
F(); }
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(3, 4) },
Array.Empty<string>());
}
[Fact]
public void Property_Initializer1()
{
......@@ -998,5 +1265,158 @@ class C
}
#endregion
#region Events
[Fact]
public void Event_LineChange1()
{
string src1 = @"
class C
{
event Action E { add { } remove { } }
}
";
string src2 = @"
class C
{
event Action E { add { } remove { } }
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(3, 4), new LineChange(3, 4) },
Array.Empty<string>());
}
[Fact]
public void EventAdder_LineChangeAndRecompile1()
{
string src1 = @"
class C
{
event Action E { add {
} remove { } }
}
";
string src2 = @"
class C
{
event Action E { add { } remove { } }
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(4, 3) },
new string[] { "add { }" });
}
[Fact]
public void EventRemover_Recompile1()
{
string src1 = @"
class C
{
event Action E { add { } remove {
} }
}
";
string src2 = @"
class C
{
event Action E { add { } remove { } }
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
Array.Empty<LineChange>(),
new string[] { "remove { }" });
}
[Fact]
public void EventAdder_LineChange1()
{
string src1 = @"
class C
{
event Action E { add
{ } remove { } }
}
";
string src2 = @"
class C
{
event Action E { add { } remove { } }
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(4, 3), new LineChange(4, 3) },
Array.Empty<string>());
}
[Fact]
public void EventRemover_LineChange1()
{
string src1 = @"
class C
{
event Action E { add { } remove { } }
}
";
string src2 = @"
class C
{
event Action E { add { } remove
{ } }
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(3, 4) },
Array.Empty<string>());
}
[Fact]
public void Event_ExpressionBody1()
{
string src1 = @"
class C
{
event Action E { add => F(); remove => F(); }
}
";
string src2 = @"
class C
{
event Action E { add =>
F(); remove =>
F(); }
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(3, 4), new LineChange(3, 5) },
Array.Empty<string>());
}
[Fact]
public void Event_ExpressionBody2()
{
string src1 = @"
class C
{
event Action E { add
=> F(); remove
=> F(); }
}
";
string src2 = @"
class C
{
event Action E { add => F(); remove => F(); }
}";
var edits = GetTopEdits(src1, src2);
edits.VerifyLineEdits(
new[] { new LineChange(4, 3), new LineChange(5, 3) },
Array.Empty<string>());
}
#endregion
}
}
......@@ -150,7 +150,7 @@ where node.IsKind(SyntaxKind.IdentifierName)
/// <returns>
/// If <paramref name="node"/> is a method, accessor, operator, destructor, or constructor without an initializer,
/// tokens of its block body, or tokens of the expression body if applicable.
/// tokens of its block body, or tokens of the expression body.
///
/// If <paramref name="node"/> is an indexer declaration the tokens of its expression body.
///
......@@ -197,18 +197,18 @@ internal override IEnumerable<SyntaxToken> TryGetActiveTokens(SyntaxNode node)
return declarator.DescendantTokens();
}
var bodyTokens = SyntaxUtilities.TryGetMethodDeclarationBody(node)?.DescendantTokens();
if (node.IsKind(SyntaxKind.ConstructorDeclaration))
{
var ctor = (ConstructorDeclarationSyntax)node;
if (ctor.Initializer != null)
{
return ctor.Initializer.DescendantTokens().Concat(ctor.Body.DescendantTokens());
bodyTokens = ctor.Initializer.DescendantTokens().Concat(bodyTokens);
}
return ctor.Body.DescendantTokens();
}
return SyntaxUtilities.TryGetMethodDeclarationBody(node)?.DescendantTokens();
return bodyTokens;
}
protected override SyntaxNode GetEncompassingAncestorImpl(SyntaxNode bodyOrMatchRoot)
......
......@@ -12,37 +12,43 @@ internal static class SyntaxUtilities
{
public static SyntaxNode TryGetMethodDeclarationBody(SyntaxNode node)
{
SyntaxNode BlockOrExpression(BlockSyntax blockBodyOpt, ArrowExpressionClauseSyntax expressionBodyOpt)
=> (SyntaxNode)blockBodyOpt ?? expressionBodyOpt?.Expression;
SyntaxNode result;
switch (node.Kind())
{
case SyntaxKind.MethodDeclaration:
var methodDeclaration = (MethodDeclarationSyntax)node;
result = (SyntaxNode)methodDeclaration.Body ?? methodDeclaration.ExpressionBody?.Expression;
result = BlockOrExpression(methodDeclaration.Body, methodDeclaration.ExpressionBody);
break;
case SyntaxKind.ConversionOperatorDeclaration:
var conversionDeclaration = (ConversionOperatorDeclarationSyntax)node;
result = (SyntaxNode)conversionDeclaration.Body ?? conversionDeclaration.ExpressionBody?.Expression;
result = BlockOrExpression(conversionDeclaration.Body, conversionDeclaration.ExpressionBody);
break;
case SyntaxKind.OperatorDeclaration:
var operatorDeclaration = (OperatorDeclarationSyntax)node;
result = (SyntaxNode)operatorDeclaration.Body ?? operatorDeclaration.ExpressionBody?.Expression;
result = BlockOrExpression(operatorDeclaration.Body, operatorDeclaration.ExpressionBody);
break;
case SyntaxKind.SetAccessorDeclaration:
case SyntaxKind.AddAccessorDeclaration:
case SyntaxKind.RemoveAccessorDeclaration:
case SyntaxKind.GetAccessorDeclaration:
result = ((AccessorDeclarationSyntax)node).Body;
var accessorDeclaration = (AccessorDeclarationSyntax)node;
result = BlockOrExpression(accessorDeclaration.Body, accessorDeclaration.ExpressionBody);
break;
case SyntaxKind.ConstructorDeclaration:
result = ((ConstructorDeclarationSyntax)node).Body;
var constructorDeclaration = (ConstructorDeclarationSyntax)node;
result = BlockOrExpression(constructorDeclaration.Body, constructorDeclaration.ExpressionBody);
break;
case SyntaxKind.DestructorDeclaration:
result = ((DestructorDeclarationSyntax)node).Body;
var destructorDeclaration = (DestructorDeclarationSyntax)node;
result = BlockOrExpression(destructorDeclaration.Body, destructorDeclaration.ExpressionBody);
break;
case SyntaxKind.PropertyDeclaration:
......@@ -81,13 +87,13 @@ public static void AssertIsBody(SyntaxNode syntax, bool allowLambda)
return;
}
// method, constructor, destructor, operator, accessor body
// block body
if (syntax is BlockSyntax)
{
return;
}
// expression body of a method, operator, property, or indexer
// expression body
if (syntax is ExpressionSyntax && syntax.Parent is ArrowExpressionClauseSyntax)
{
return;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册