提交 476bdda4 编写于 作者: I Ivan Basov 提交者: GitHub

ENC support for C# 7.0 features (#18723)

上级 970cf176
......@@ -5936,6 +5936,95 @@ public void SyntaxOffset_TupleIgnoreDeconstructionIfVariableDeclared()
#endregion
#region OutVar
[Fact]
public void SyntaxOffset_OutVarInConstructor()
{
var source = @"
class B
{
B(out int z) { z = 2; }
}
class C
{
int F = G(out var v1);
int P => G(out var v2);
C()
: base(out var v3)
{
G(out var v4);
}
int G(out int x)
{
x = 1;
return 2;
}
}
";
var c = CreateCompilationWithMscorlibAndSystemCore(source, options: TestOptions.DebugDll);
c.VerifyDiagnostics(
// (9,19): error CS8200: Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers.
// int F = G(out var v1);
Diagnostic(ErrorCode.ERR_ExpressionVariableInConstructorOrFieldInitializer, "var v1").WithLocation(9, 19),
// (9,13): error CS0236: A field initializer cannot reference the non-static field, method, or property 'C.G(out int)'
// int F = G(out var v1);
Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "G(out var v1)").WithArguments("C.G(out int)").WithLocation(9, 13),
// (13,16): error CS8200: Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers.
// : base(out var v3)
Diagnostic(ErrorCode.ERR_ExpressionVariableInConstructorOrFieldInitializer, "var v3").WithLocation(13, 16),
// (13,7): error CS1729: 'object' does not contain a constructor that takes 1 arguments
// : base(out var v3)
Diagnostic(ErrorCode.ERR_BadCtorArgCount, "base").WithArguments("object", "1").WithLocation(13, 7));
}
[Fact]
public void SyntaxOffset_OutVarInMethod()
{
var source = @"class C { int G(out int x) { int z = 1; G(out var y); G(out var w); return x = y; } }";
var c = CreateCompilationWithMscorlibAndSystemCore(source, options: TestOptions.DebugDll);
c.VerifyPdb("C.G", @"
<symbols>
<methods>
<method containingType=""C"" name=""G"" parameterNames=""x"">
<customDebugInfo>
<using>
<namespace usingCount=""0"" />
</using>
<encLocalSlotMap>
<slot kind=""0"" offset=""6"" />
<slot kind=""0"" offset=""23"" />
<slot kind=""0"" offset=""37"" />
<slot kind=""temp"" />
<slot kind=""21"" offset=""0"" />
</encLocalSlotMap>
</customDebugInfo>
<sequencePoints>
<entry offset=""0x0"" startLine=""1"" startColumn=""28"" endLine=""1"" endColumn=""29"" />
<entry offset=""0x1"" startLine=""1"" startColumn=""30"" endLine=""1"" endColumn=""40"" />
<entry offset=""0x3"" startLine=""1"" startColumn=""41"" endLine=""1"" endColumn=""54"" />
<entry offset=""0xc"" startLine=""1"" startColumn=""55"" endLine=""1"" endColumn=""68"" />
<entry offset=""0x15"" startLine=""1"" startColumn=""69"" endLine=""1"" endColumn=""82"" />
<entry offset=""0x1f"" startLine=""1"" startColumn=""83"" endLine=""1"" endColumn=""84"" />
</sequencePoints>
<scope startOffset=""0x0"" endOffset=""0x22"">
<local name=""z"" il_index=""0"" il_start=""0x0"" il_end=""0x22"" attributes=""0"" />
<local name=""y"" il_index=""1"" il_start=""0x0"" il_end=""0x22"" attributes=""0"" />
<local name=""w"" il_index=""2"" il_start=""0x0"" il_end=""0x22"" attributes=""0"" />
</scope>
</method>
</methods>
</symbols>
");
}
#endregion
[Fact, WorkItem(4370, "https://github.com/dotnet/roslyn/issues/4370")]
public void HeadingHiddenSequencePointsPickUpDocumentFromVisibleSequencePoint()
{
......
......@@ -6708,6 +6708,36 @@ public void TupleNames_TypeUpdate()
Diagnostic(RudeEditKind.TypeUpdate, "(int notA, int) M()", FeaturesResources.method));
}
[Fact]
public void TupleElementDelete()
{
var src1 = "class C { (int, int, int a) M() { return (1, 2, 3); } }";
var src2 = "class C { (int, int) M() { return (1, 2); } }";
var edits = GetTopEdits(src1, src2);
edits.VerifyEdits(
"Update [(int, int, int a) M() { return (1, 2, 3); }]@10 -> [(int, int) M() { return (1, 2); }]@10");
edits.VerifyRudeDiagnostics(
Diagnostic(RudeEditKind.TypeUpdate, "(int, int) M()", "method"));
}
[Fact]
public void TupleElementAdd()
{
var src1 = "class C { (int, int) M() { return (1, 2); } }";
var src2 = "class C { (int, int, int a) M() { return (1, 2, 3); } }";
var edits = GetTopEdits(src1, src2);
edits.VerifyEdits(
"Update [(int, int) M() { return (1, 2); }]@10 -> [(int, int, int a) M() { return (1, 2, 3); }]@10");
edits.VerifyRudeDiagnostics(
Diagnostic(RudeEditKind.TypeUpdate, "(int, int, int a) M()", "method"));
}
[Fact]
public void Indexer_ParameterUpdate()
{
......
......@@ -416,7 +416,9 @@ internal static class EditScriptTestUtils
{
public static void VerifyEdits<TNode>(this EditScript<TNode> actual, params string[] expected)
{
AssertEx.Equal(expected, actual.Edits.Select(e => e.GetDebuggerDisplay()), itemSeparator: ",\r\n");
AssertEx.Equal(
expected.Select(s => string.Format("\"{0}\"",s)),
actual.Edits.Select(e => string.Format("\"{0}\"", e.GetDebuggerDisplay())), itemSeparator: ",\r\n");
}
}
}
......@@ -1353,6 +1353,9 @@ internal static TextSpan GetDiagnosticSpanImpl(SyntaxKind kind, SyntaxNode node,
case SyntaxKind.RefExpression:
case SyntaxKind.DeclarationPattern:
case SyntaxKind.SimpleAssignmentExpression:
case SyntaxKind.WhenClause:
case SyntaxKind.SingleVariableDesignation:
case SyntaxKind.CasePatternSwitchLabel:
return node.Span;
default:
......
......@@ -163,7 +163,6 @@ internal enum Label
ForStatement,
ForStatementPart, // tied to parent
ForEachStatement,
ForEachComponentStatement,
UsingStatement,
FixedStatement,
LockStatement,
......@@ -174,6 +173,8 @@ internal enum Label
SwitchStatement,
SwitchSection,
CasePatternSwitchLabel, // tied to parent
WhenClause,
YieldStatement, // tied to parent
GotoStatement,
......@@ -184,6 +185,8 @@ internal enum Label
LabeledStatement,
LocalFunction,
// TODO:
// Ideally we could declare LocalVariableDeclarator tied to the first enclosing node that defines local scope (block, foreach, etc.)
// Also consider handling LocalDeclarationStatement as just a bag of variable declarators,
......@@ -192,10 +195,8 @@ internal enum Label
LocalVariableDeclaration, // tied to parent
LocalVariableDeclarator, // tied to parent
SingleVariableDesignation,
AwaitExpression,
LocalFunction,
Lambda,
FromClause,
......@@ -243,6 +244,7 @@ private static int TiedToAncestor(Label label)
case Label.JoinIntoClause:
case Label.GroupClauseLambda:
case Label.QueryContinuation:
case Label.CasePatternSwitchLabel:
return 1;
default:
......@@ -291,6 +293,9 @@ internal static Label Classify(SyntaxKind kind, SyntaxNode nodeOpt, out bool isL
case SyntaxKind.VariableDeclarator:
return Label.LocalVariableDeclarator;
case SyntaxKind.SingleVariableDesignation:
return Label.SingleVariableDesignation;
case SyntaxKind.LabeledStatement:
return Label.LabeledStatement;
......@@ -332,12 +337,10 @@ internal static Label Classify(SyntaxKind kind, SyntaxNode nodeOpt, out bool isL
case SyntaxKind.ForStatement:
return Label.ForStatement;
case SyntaxKind.ForEachVariableStatement:
case SyntaxKind.ForEachStatement:
return Label.ForEachStatement;
case SyntaxKind.ForEachVariableStatement:
return Label.ForEachComponentStatement;
case SyntaxKind.UsingStatement:
return Label.UsingStatement;
......@@ -373,6 +376,12 @@ internal static Label Classify(SyntaxKind kind, SyntaxNode nodeOpt, out bool isL
isLeaf = true;
return Label.Ignored;
case SyntaxKind.WhenClause:
return Label.WhenClause;
case SyntaxKind.CasePatternSwitchLabel:
return Label.CasePatternSwitchLabel;
case SyntaxKind.TryStatement:
return Label.TryStatement;
......@@ -456,6 +465,8 @@ internal static Label Classify(SyntaxKind kind, SyntaxNode nodeOpt, out bool isL
case SyntaxKind.ArrayRankSpecifier:
case SyntaxKind.PointerType:
case SyntaxKind.NullableType:
case SyntaxKind.TupleType:
case SyntaxKind.RefType:
case SyntaxKind.OmittedTypeArgument:
case SyntaxKind.NameColon:
case SyntaxKind.StackAllocArrayCreationExpression:
......@@ -472,6 +483,8 @@ internal static Label Classify(SyntaxKind kind, SyntaxNode nodeOpt, out bool isL
case SyntaxKind.TypeOfExpression:
case SyntaxKind.SizeOfExpression:
case SyntaxKind.DefaultExpression:
case SyntaxKind.ConstantPattern:
case SyntaxKind.DiscardDesignation:
// can't contain a lambda/await/anonymous type:
isLeaf = true;
return Label.Ignored;
......@@ -581,9 +594,11 @@ protected override bool TryComputeWeightedDistance(SyntaxNode leftNode, SyntaxNo
return true;
case SyntaxKind.ForEachStatement:
case SyntaxKind.ForEachVariableStatement:
{
var leftForEach = (ForEachStatementSyntax)leftNode;
var rightForEach = (ForEachStatementSyntax)rightNode;
var leftForEach = (CommonForEachStatementSyntax)leftNode;
var rightForEach = (CommonForEachStatementSyntax)rightNode;
distance = ComputeWeightedDistance(leftForEach, rightForEach);
return true;
}
......@@ -758,7 +773,7 @@ private bool TryComputeWeightedDistance(BlockSyntax leftBlock, BlockSyntax right
return true;
}
if (leftBlock.Parent.Kind() != rightBlock.Parent.Kind())
if (GetLabel(leftBlock.Parent) != GetLabel(rightBlock.Parent))
{
distance = 0.2 + 0.8 * ComputeWeightedBlockDistance(leftBlock, rightBlock);
return true;
......@@ -839,14 +854,22 @@ private static double ComputeWeightedDistance(CatchClauseSyntax left, CatchClaus
return AdjustForLocalsInBlock(distance, left.Block, right.Block, localsWeight: 0.3);
}
private static double ComputeWeightedDistance(ForEachStatementSyntax left, ForEachStatementSyntax right)
private static double ComputeWeightedDistance(
CommonForEachStatementSyntax leftCommonForEach,
CommonForEachStatementSyntax rightCommonForEach)
{
double statementDistance = ComputeDistance(left.Statement, right.Statement);
double expressionDistance = ComputeDistance(left.Expression, right.Expression);
double identifierDistance = ComputeDistance(left.Identifier, right.Identifier);
double statementDistance = ComputeDistance(leftCommonForEach.Statement, rightCommonForEach.Statement);
double expressionDistance = ComputeDistance(leftCommonForEach.Expression, rightCommonForEach.Expression);
List<SyntaxToken> leftLocals = null;
List<SyntaxToken> rightLocals = null;
GetLocalNames(leftCommonForEach, ref leftLocals);
GetLocalNames(rightCommonForEach, ref rightLocals);
double distance = identifierDistance * 0.7 + expressionDistance * 0.2 + statementDistance * 0.1;
return AdjustForLocalsInBlock(distance, left.Statement, right.Statement, localsWeight: 0.6);
double localNamesDistance = ComputeDistance(leftLocals, rightLocals);
double distance = localNamesDistance * 0.6 + expressionDistance * 0.2 + statementDistance * 0.2;
return AdjustForLocalsInBlock(distance, leftCommonForEach.Statement, rightCommonForEach.Statement, localsWeight: 0.6);
}
private static double ComputeWeightedDistance(ForStatementSyntax left, ForStatementSyntax right)
......@@ -979,15 +1002,81 @@ private static void GetLocalNames(VariableDeclarationSyntax localDeclaration, re
{
foreach (var local in localDeclaration.Variables)
{
if (result == null)
{
result = new List<SyntaxToken>();
}
GetLocalNames(local.Identifier, ref result);
}
}
private static void GetLocalNames(CommonForEachStatementSyntax commonForEach, ref List<SyntaxToken> result)
{
switch (commonForEach.Kind())
{
case SyntaxKind.ForEachStatement:
GetLocalNames(((ForEachStatementSyntax)commonForEach).Identifier, ref result);
return;
result.Add(local.Identifier);
case SyntaxKind.ForEachVariableStatement:
var forEachVariable = (ForEachVariableStatementSyntax)commonForEach;
GetLocalNames(forEachVariable.Variable, ref result);
return;
default: throw ExceptionUtilities.UnexpectedValue(commonForEach.Kind());
}
}
private static void GetLocalNames(ExpressionSyntax expression, ref List<SyntaxToken> result)
{
switch (expression.Kind())
{
case SyntaxKind.DeclarationExpression:
var declarationExpression = (DeclarationExpressionSyntax)expression;
var localDeclaration = declarationExpression.Designation;
GetLocalNames(localDeclaration, ref result);
return;
case SyntaxKind.TupleExpression:
var tupleExpression = (TupleExpressionSyntax)expression;
foreach(var argument in tupleExpression.Arguments)
{
GetLocalNames(argument.Expression, ref result);
}
return;
default:
// Do nothing for node that cannot have variable declarations inside.
return;
}
}
private static void GetLocalNames(VariableDesignationSyntax designation, ref List<SyntaxToken> result)
{
switch (designation.Kind())
{
case SyntaxKind.SingleVariableDesignation:
GetLocalNames(((SingleVariableDesignationSyntax)designation).Identifier, ref result);
return;
case SyntaxKind.ParenthesizedVariableDesignation:
var parenthesizedVariableDesignation = (ParenthesizedVariableDesignationSyntax)designation;
foreach(var variableDesignation in parenthesizedVariableDesignation.Variables)
{
GetLocalNames(variableDesignation, ref result);
}
return;
default: throw ExceptionUtilities.UnexpectedValue(designation.Kind());
}
}
private static void GetLocalNames(SyntaxToken syntaxToken, ref List<SyntaxToken> result)
{
if (result == null)
{
result = new List<SyntaxToken>();
}
result.Add(syntaxToken);
}
private static double CombineOptional(
double distance0,
SyntaxNode leftOpt1,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册