提交 3361cb03 编写于 作者: G Gen Lu

Address review comments

上级 648070f6
......@@ -215,7 +215,10 @@ ImmutableArray<IArgument> IHasArgumentsExpression.ArgumentsInEvaluationOrder
{
get
{
MethodSymbol accessor = this.IsLeftOfAssignment ? this.Indexer.SetMethod : this.Indexer.GetMethod;
MethodSymbol accessor = this.IsLeftOfAssignment && !this.Indexer.ReturnsByRef
? this.Indexer.GetOwnOrInheritedSetMethod()
: this.Indexer.GetOwnOrInheritedGetMethod();
return BoundCall.DeriveArguments(this,
this.BinderOpt,
this.Indexer,
......
......@@ -543,7 +543,8 @@ private static bool IsSafeForReordering(BoundExpression expression, RefKind kind
argumentsInEvaluationBuilder,
missingParametersBuilder);
AppendMissingOptionalArguments(syntax, optionalParametersMethod, expanded, binder, missingParametersBuilder.ToImmutableAndFree(), argumentsInEvaluationBuilder);
AppendMissingOptionalArguments(syntax, methodOrIndexer, optionalParametersMethod, expanded, binder, missingParametersBuilder, argumentsInEvaluationBuilder);
missingParametersBuilder.Free();
return argumentsInEvaluationBuilder.ToImmutableAndFree();
}
......@@ -681,7 +682,7 @@ private static ImmutableArray<RefKind> GetRefKindsOrNull(ArrayBuilder<RefKind> r
/* out */ ArrayBuilder<ParameterSymbol> missingParametersBuilder)
{
ImmutableArray<ParameterSymbol> parameters = methodOrIndexer.GetParameters();
ArrayBuilder<int> processedParameters = ArrayBuilder<int>.GetInstance(parameters.Length);
PooledHashSet<int> processedParameters = PooledHashSet<int>.GetInstance();
for (int a = 0; a < arguments.Length; ++a)
{
......@@ -986,13 +987,15 @@ private static BoundExpression MakeLiteral(SyntaxNode syntax, ConstantValue cons
}
}
private static void AppendMissingOptionalArguments(SyntaxNode syntax,
private static void AppendMissingOptionalArguments(SyntaxNode syntax,
Symbol methodOrIndexer,
MethodSymbol optionalParametersMethod,
bool expanded,
Binder binder,
ImmutableArray<ParameterSymbol> missingParameters,
ArrayBuilder<ParameterSymbol> missingParameters,
ArrayBuilder<IArgument> argumentsBuilder)
{
ImmutableArray<ParameterSymbol> parameters = methodOrIndexer.GetParameters();
ImmutableArray<ParameterSymbol> parametersOfOptionalParametersMethod = optionalParametersMethod.Parameters;
foreach (ParameterSymbol parameter in missingParameters)
......@@ -1001,11 +1004,11 @@ private static BoundExpression MakeLiteral(SyntaxNode syntax, ConstantValue cons
ArgumentKind kind;
// In case of indexer access, missing parameters are corresponding to the indexer symbol, we need to
// get default values base on actual accessor method parameter symbols (but still want to tie resulted IArgument
// get default values based on actual accessor method parameter symbols (but still want to tie resulted IArgument
// to the indexer parameter.)
ParameterSymbol parameterOfOptionalParametersMethod = parametersOfOptionalParametersMethod[parameter.Ordinal];
if (expanded && parameterOfOptionalParametersMethod.Ordinal == parametersOfOptionalParametersMethod.Length - 1)
if (expanded && parameterOfOptionalParametersMethod.Ordinal == parameters.Length - 1)
{
Debug.Assert(parameterOfOptionalParametersMethod.IsParams);
......@@ -1157,9 +1160,7 @@ private BoundExpression GetDefaultParameterValue(SyntaxNode syntax, ParameterSym
if (parameterType.IsNullableType())
{
TypeSymbol nullableType = parameterType.GetNullableUnderlyingType();
defaultValue = isLowering
? localRewriter.MakeConversionNode(lineLiteral, nullableType, false)
: MakeConversionForIOperation(lineLiteral, nullableType, syntax, compilation, diagnostics, false);
defaultValue = MakeConversionNode(lineLiteral, nullableType, @checked: false);
// wrap it in a nullable ctor.
defaultValue = new BoundObjectCreationExpression(
......@@ -1169,19 +1170,15 @@ private BoundExpression GetDefaultParameterValue(SyntaxNode syntax, ParameterSym
defaultValue);
}
else
{
defaultValue = isLowering
? localRewriter.MakeConversionNode(lineLiteral, parameterType, false)
: MakeConversionForIOperation(lineLiteral, parameterType, syntax, compilation, diagnostics, false);
{
defaultValue = MakeConversionNode(lineLiteral, parameterType, @checked: false);
}
}
else if (parameter.IsCallerFilePath && ((callerSourceLocation = GetCallerLocation(syntax, enableCallerInfo)) != null))
{
string path = callerSourceLocation.SourceTree.GetDisplayPath(callerSourceLocation.SourceSpan, compilation.Options.SourceReferenceResolver);
BoundExpression memberNameLiteral = MakeLiteral(syntax, ConstantValue.Create(path), compilation.GetSpecialType(SpecialType.System_String), localRewriter);
defaultValue = isLowering
? localRewriter.MakeConversionNode(memberNameLiteral, parameterType, false)
: MakeConversionForIOperation(memberNameLiteral, parameterType, syntax, compilation, diagnostics, false);
BoundExpression memberNameLiteral = MakeLiteral(syntax, ConstantValue.Create(path), compilation.GetSpecialType(SpecialType.System_String), localRewriter);
defaultValue = MakeConversionNode(memberNameLiteral, parameterType, @checked: false);
}
else if (parameter.IsCallerMemberName && ((callerSourceLocation = GetCallerLocation(syntax, enableCallerInfo)) != null))
{
......@@ -1246,10 +1243,8 @@ private BoundExpression GetDefaultParameterValue(SyntaxNode syntax, ParameterSym
memberName = binder.ContainingMember().GetMemberCallerName();
}
BoundExpression memberNameLiteral = MakeLiteral(syntax, ConstantValue.Create(memberName), compilation.GetSpecialType(SpecialType.System_String), localRewriter);
defaultValue = isLowering
? localRewriter.MakeConversionNode(memberNameLiteral, parameterType, false)
: MakeConversionForIOperation(memberNameLiteral, parameterType, syntax, compilation, diagnostics, false);
BoundExpression memberNameLiteral = MakeLiteral(syntax, ConstantValue.Create(memberName), compilation.GetSpecialType(SpecialType.System_String), localRewriter);
defaultValue = MakeConversionNode(memberNameLiteral, parameterType, @checked: false);
}
else if (defaultConstantValue == ConstantValue.NotAvailable)
{
......@@ -1284,9 +1279,7 @@ private BoundExpression GetDefaultParameterValue(SyntaxNode syntax, ParameterSym
// The parameter's underlying type might not match the constant type. For example, we might have
// a default value of 5 (an integer) but a parameter type of decimal?.
defaultValue = isLowering
? localRewriter.MakeConversionNode(defaultValue, parameterType.GetNullableUnderlyingType(), @checked: false, acceptFailingConversion: true)
: MakeConversionForIOperation(defaultValue, parameterType.GetNullableUnderlyingType(), syntax, compilation, diagnostics, @checked: false, acceptFailingConversion: true);
defaultValue = MakeConversionNode(defaultValue, parameterType.GetNullableUnderlyingType(), @checked: false, acceptFailingConversion: true);
// Finally, wrap it in a nullable ctor.
defaultValue = new BoundObjectCreationExpression(
......@@ -1306,13 +1299,23 @@ private BoundExpression GetDefaultParameterValue(SyntaxNode syntax, ParameterSym
TypeSymbol constantType = compilation.GetSpecialType(defaultConstantValue.SpecialType);
defaultValue = MakeLiteral(syntax, defaultConstantValue, constantType, localRewriter);
// The parameter type might not match the constant type.
defaultValue = isLowering
? localRewriter.MakeConversionNode(defaultValue, parameterType, @checked: false, acceptFailingConversion: true)
: MakeConversionForIOperation(defaultValue, parameterType, syntax, compilation, diagnostics, @checked: false, acceptFailingConversion: true);
defaultValue = MakeConversionNode(defaultValue, parameterType, @checked: false, acceptFailingConversion: true);
}
return defaultValue;
}
BoundExpression MakeConversionNode(BoundExpression operand, TypeSymbol type, bool @checked, bool acceptFailingConversion = false)
{
if (isLowering)
{
return localRewriter.MakeConversionNode(operand, type, @checked, acceptFailingConversion);
}
else
{
return MakeConversionForIOperation(operand, type, syntax, compilation, diagnostics, @checked, acceptFailingConversion);
}
}
}
private BoundExpression GetDefaultParameterSpecial(SyntaxNode syntax, ParameterSymbol parameter)
{
......
......@@ -506,7 +506,7 @@ private BoundExpression MakeConversionNode(BoundExpression rewrittenOperand, Typ
{
Conversion conversion = MakeConversion(operand, type, compilation, diagnostics, acceptFailingConversion);
if (conversion.Kind == ConversionKind.Identity)
if (conversion.IsIdentity)
{
return operand;
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Semantics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -1046,7 +1047,7 @@ void M1()
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<ElementAccessExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
VerifyOperationTreeAndDiagnosticsForTest<ElementAccessExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics, AdditionalOperationTreeVerifier: IndexerAccessArgumentVerifier.Verify);
}
[Fact]
......@@ -1076,7 +1077,7 @@ void M1()
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<ElementAccessExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
VerifyOperationTreeAndDiagnosticsForTest<ElementAccessExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics, AdditionalOperationTreeVerifier: IndexerAccessArgumentVerifier.Verify);
}
[Fact]
......@@ -1109,7 +1110,7 @@ void M1()
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<ElementAccessExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
VerifyOperationTreeAndDiagnosticsForTest<ElementAccessExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics, AdditionalOperationTreeVerifier: IndexerAccessArgumentVerifier.Verify);
}
[Fact]
......@@ -1141,7 +1142,7 @@ void M1()
Diagnostic(ErrorCode.ERR_PropertyLacksGet, "this[10]").WithArguments("P.this[int]").WithLocation(12, 27)
};
VerifyOperationTreeAndDiagnosticsForTest<ElementAccessExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
VerifyOperationTreeAndDiagnosticsForTest<ElementAccessExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics, AdditionalOperationTreeVerifier: IndexerAccessArgumentVerifier.Verify);
}
[Fact]
......@@ -1175,9 +1176,117 @@ void M1()
Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "this[10]").WithArguments("P.this[int]").WithLocation(12, 19)
};
VerifyOperationTreeAndDiagnosticsForTest<ElementAccessExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
VerifyOperationTreeAndDiagnosticsForTest<ElementAccessExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics, AdditionalOperationTreeVerifier: IndexerAccessArgumentVerifier.Verify);
}
[Fact]
public void OverridingIndexerWithDefaultArgument()
{
string source = @"
class Base
{
public virtual int this[int x = 0, int y = 1]
{
set { }
get { System.Console.Write(y); return 0; }
}
}
class Derived : Base
{
public override int this[int x = 8, int y = 9]
{
set { }
}
}
internal class P
{
static void Main()
{
var d = new Derived();
var x = /*<bind>*/d[0]/*</bind>*/;
}
}
";
string expectedOperationTree = @"
IIndexedPropertyReferenceExpression: System.Int32 Derived.this[[System.Int32 x = 8], [System.Int32 y = 9]] { set; } (OperationKind.IndexedPropertyReferenceExpression, Type: System.Int32) (Syntax: 'd[0]')
Instance Receiver: ILocalReferenceExpression: d (OperationKind.LocalReferenceExpression, Type: Derived) (Syntax: 'd')
Arguments(2): IArgument (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument) (Syntax: '0')
ILiteralExpression (Text: 0) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 0) (Syntax: '0')
IArgument (ArgumentKind.DefaultValue, Matching Parameter: y) (OperationKind.Argument) (Syntax: 'd[0]')
ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: 'd[0]')
";
var expectedDiagnostics = DiagnosticDescription.None;
string expectedOutput = @"1";
VerifyOperationTreeAndDiagnosticsForTest<ElementAccessExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics, AdditionalOperationTreeVerifier: IndexerAccessArgumentVerifier.Verify);
CompileAndVerify(new[] { source }, new[] { SystemRef }, expectedOutput: expectedOutput);
}
[Fact]
public void OmittedParamArrayArgumentInIndexerAccess()
{
string source = @"
class P
{
public int this[int x, params int[] y]
{
set { }
get { return 0; }
}
public void M()
{
/*<bind>*/this[0]/*</bind>*/ = 0;
}
}
";
string expectedOperationTree = @"
IIndexedPropertyReferenceExpression: System.Int32 P.this[System.Int32 x, params System.Int32[] y] { get; set; } (OperationKind.IndexedPropertyReferenceExpression, Type: System.Int32) (Syntax: 'this[0]')
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Explicit) (OperationKind.InstanceReferenceExpression, Type: P) (Syntax: 'this')
Arguments(2): IArgument (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument) (Syntax: '0')
ILiteralExpression (Text: 0) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 0) (Syntax: '0')
IArgument (ArgumentKind.ParamArray, Matching Parameter: y) (OperationKind.Argument) (Syntax: 'this[0]')
IArrayCreationExpression (Element Type: System.Int32) (OperationKind.ArrayCreationExpression, Type: System.Int32[]) (Syntax: 'this[0]')
Dimension Sizes(1): ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 0) (Syntax: 'this[0]')
Initializer: IArrayInitializer (0 elements) (OperationKind.ArrayInitializer) (Syntax: 'this[0]')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<ElementAccessExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics, AdditionalOperationTreeVerifier: IndexerAccessArgumentVerifier.Verify);
}
[Fact]
public void AssigningToReturnsByRefIndexer()
{
string source = @"
class P
{
ref int this[int x]
{
get => throw null;
}
public void M()
{
/*<bind>*/this[0]/*</bind>*/ = 0;
}
}
";
string expectedOperationTree = @"
IIndexedPropertyReferenceExpression: ref System.Int32 P.this[System.Int32 x] { get; } (OperationKind.IndexedPropertyReferenceExpression, Type: System.Int32, IsInvalid) (Syntax: 'this[0]')
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Explicit) (OperationKind.InstanceReferenceExpression, Type: P) (Syntax: 'this')
Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument) (Syntax: '0')
ILiteralExpression (Text: 0) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 0) (Syntax: '0')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<ElementAccessExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics, AdditionalOperationTreeVerifier: IndexerAccessArgumentVerifier.Verify);
}
[ClrOnlyFact(ClrOnlyReason.Ilasm)]
public void AssigningToIndexer_UsingDefaultArgumentFromSetter()
{
......@@ -1205,15 +1314,25 @@ .maxstack 8
{
.param [1] = int32(0x00000001)
.param [2] = int32(0x00000002)
// Code size 7 (0x7)
.maxstack 1
// Code size 35 (0x23)
.maxstack 3
.locals init ([0] int32 V_0)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
IL_0001: ldstr ""{0} {1}""
IL_0006: ldarg.1
IL_0007: box [mscorlib]System.Int32
IL_000c: ldarg.2
IL_000d: box [mscorlib]System.Int32
IL_0012: call string [mscorlib]System.String::Format(string,
object,
object)
IL_0017: call void [mscorlib]System.Console::WriteLine(string)
IL_001c: nop
IL_001d: ldc.i4.0
IL_001e: stloc.0
IL_001f: br.s IL_0021
IL_0021: ldloc.0
IL_0022: ret
} // end of method P::get_Item
.method public hidebysig specialname instance void
......@@ -1223,10 +1342,20 @@ .locals init ([0] int32 V_0)
{
.param [1] = int32(0x00000003)
.param [2] = int32(0x00000004)
// Code size 2 (0x2)
// Code size 30 (0x1e)
.maxstack 8
IL_0000: nop
IL_0001: ret
IL_0001: ldstr ""{0} {1}""
IL_0006: ldarg.1
IL_0007: box [mscorlib]System.Int32
IL_000c: ldarg.2
IL_000d: box [mscorlib]System.Int32
IL_0012: call string [mscorlib]System.String::Format(string,
object,
object)
IL_0017: call void [mscorlib]System.Console::WriteLine(string)
IL_001c: nop
IL_001d: ret
} // end of method P::set_Item
......@@ -1245,7 +1374,7 @@ .maxstack 8
var csharp = @"
class C
{
public void M1()
public static void Main(string[] args)
{
P p = new P();
/*<bind>*/p[10]/*</bind>*/ = 9;
......@@ -1260,8 +1389,12 @@ public void M1()
IArgument (ArgumentKind.DefaultValue, Matching Parameter: j) (OperationKind.Argument) (Syntax: 'p[10]')
ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 4) (Syntax: 'p[10]')";
var expectedDiagnostics = DiagnosticDescription.None;
var expectedOutput = @"10 4
";
VerifyOperationTreeAndDiagnosticsForTestWithIL<ElementAccessExpressionSyntax>(csharp, il, expectedOperationTree, expectedDiagnostics);
var ilReference = VerifyOperationTreeAndDiagnosticsForTestWithIL<ElementAccessExpressionSyntax>(csharp, il, expectedOperationTree, expectedDiagnostics, AdditionalOperationTreeVerifier: IndexerAccessArgumentVerifier.Verify);
CompileAndVerify(new[] { csharp }, new[] { SystemRef, ilReference }, expectedOutput: expectedOutput);
}
[ClrOnlyFact(ClrOnlyReason.Ilasm)]
......@@ -1291,28 +1424,48 @@ .maxstack 8
{
.param [1] = int32(0x00000001)
.param [2] = int32(0x00000002)
// Code size 7 (0x7)
.maxstack 1
// Code size 35 (0x23)
.maxstack 3
.locals init ([0] int32 V_0)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
IL_0001: ldstr ""{0} {1}""
IL_0006: ldarg.1
IL_0007: box [mscorlib]System.Int32
IL_000c: ldarg.2
IL_000d: box [mscorlib]System.Int32
IL_0012: call string [mscorlib]System.String::Format(string,
object,
object)
IL_0017: call void [mscorlib]System.Console::WriteLine(string)
IL_001c: nop
IL_001d: ldc.i4.0
IL_001e: stloc.0
IL_001f: br.s IL_0021
IL_0021: ldloc.0
IL_0022: ret
} // end of method P::get_Item
.method public hidebysig specialname instance void
set_Item([opt] int32 i,
[opt] int32 j,
int32 'value') cil managed
{
{
.param [1] = int32(0x00000003)
.param [2] = int32(0x00000004)
// Code size 2 (0x2)
// Code size 30 (0x1e)
.maxstack 8
IL_0000: nop
IL_0001: ret
IL_0001: ldstr ""{0} {1}""
IL_0006: ldarg.1
IL_0007: box [mscorlib]System.Int32
IL_000c: ldarg.2
IL_000d: box [mscorlib]System.Int32
IL_0012: call string [mscorlib]System.String::Format(string,
object,
object)
IL_0017: call void [mscorlib]System.Console::WriteLine(string)
IL_001c: nop
IL_001d: ret
} // end of method P::set_Item
......@@ -1331,7 +1484,7 @@ .maxstack 8
var csharp = @"
class C
{
public void M1()
public static void Main(string[] args)
{
P p = new P();
var x = /*<bind>*/p[10]/*</bind>*/;
......@@ -1348,7 +1501,12 @@ public void M1()
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTestWithIL<ElementAccessExpressionSyntax>(csharp, il, expectedOperationTree, expectedDiagnostics);
var expectedOutput = @"10 2
";
var ilReference = VerifyOperationTreeAndDiagnosticsForTestWithIL<ElementAccessExpressionSyntax>(csharp, il, expectedOperationTree, expectedDiagnostics, AdditionalOperationTreeVerifier: IndexerAccessArgumentVerifier.Verify);
CompileAndVerify(new[] { csharp }, new[] { SystemRef, ilReference }, expectedOutput: expectedOutput);
}
[ClrOnlyFact(ClrOnlyReason.Ilasm)]
......@@ -1378,28 +1536,48 @@ .maxstack 8
{
.param [1] = int32(0x00000001)
.param [2] = int32(0x00000002)
// Code size 7 (0x7)
.maxstack 1
// Code size 35 (0x23)
.maxstack 3
.locals init ([0] int32 V_0)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
IL_0001: ldstr ""{0} {1}""
IL_0006: ldarg.1
IL_0007: box [mscorlib]System.Int32
IL_000c: ldarg.2
IL_000d: box [mscorlib]System.Int32
IL_0012: call string [mscorlib]System.String::Format(string,
object,
object)
IL_0017: call void [mscorlib]System.Console::WriteLine(string)
IL_001c: nop
IL_001d: ldc.i4.0
IL_001e: stloc.0
IL_001f: br.s IL_0021
IL_0021: ldloc.0
IL_0022: ret
} // end of method P::get_Item
.method public hidebysig specialname instance void
set_Item([opt] int32 i,
[opt] int32 j,
int32 'value') cil managed
{
{
.param [1] = int32(0x00000003)
.param [2] = int32(0x00000004)
// Code size 2 (0x2)
// Code size 30 (0x1e)
.maxstack 8
IL_0000: nop
IL_0001: ret
IL_0001: ldstr ""{0} {1}""
IL_0006: ldarg.1
IL_0007: box [mscorlib]System.Int32
IL_000c: ldarg.2
IL_000d: box [mscorlib]System.Int32
IL_0012: call string [mscorlib]System.String::Format(string,
object,
object)
IL_0017: call void [mscorlib]System.Console::WriteLine(string)
IL_001c: nop
IL_001d: ret
} // end of method P::set_Item
......@@ -1418,7 +1596,7 @@ .maxstack 8
var csharp = @"
class C
{
public void M1()
public static void Main(string[] args)
{
P p = new P();
/*<bind>*/p[10]/*</bind>*/ += 99;
......@@ -1434,7 +1612,13 @@ public void M1()
ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2) (Syntax: 'p[10]')";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTestWithIL<ElementAccessExpressionSyntax>(csharp, il, expectedOperationTree, expectedDiagnostics);
var expectedOutput = @"10 2
10 2
";
var ilReference = VerifyOperationTreeAndDiagnosticsForTestWithIL<ElementAccessExpressionSyntax>(csharp, il, expectedOperationTree, expectedDiagnostics, AdditionalOperationTreeVerifier: IndexerAccessArgumentVerifier.Verify);
CompileAndVerify(new[] { csharp }, new[] { SystemRef, ilReference }, expectedOutput: expectedOutput);
}
[ClrOnlyFact(ClrOnlyReason.Ilasm)]
......@@ -1487,5 +1671,32 @@ public void M2()
VerifyOperationTreeAndDiagnosticsForTestWithIL<InvocationExpressionSyntax>(csharp, il, expectedOperationTree, expectedDiagnostics);
}
}
private class IndexerAccessArgumentVerifier : OperationWalker
{
public static void Verify(IOperation operation)
{
var walker = new IndexerAccessArgumentVerifier();
walker.Visit(operation);
}
public override void VisitIndexedPropertyReferenceExpression(IIndexedPropertyReferenceExpression operation)
{
if (operation.IsInvalid)
{
return;
}
// Check if the parameter symbol for argument is corresponding to indexer instead of accessor.
var indexerSymbol = operation.Property;
foreach (var argument in operation.ArgumentsInEvaluationOrder)
{
if (!argument.IsInvalid)
{
Assert.True(argument.Parameter.ContainingSymbol == indexerSymbol);
}
}
}
}
}
}
\ No newline at end of file
......@@ -221,8 +221,8 @@ protected CompilationUtils.SemanticInfoSummary GetSemanticInfoForTest(string tes
return GetSemanticInfoForTest<ExpressionSyntax>(testSrc);
}
protected string GetOperationTreeForTest<TSyntaxNode>(CSharpCompilation compilation)
where TSyntaxNode: SyntaxNode
protected IOperation GetOperationForTest<TSyntaxNode>(CSharpCompilation compilation)
where TSyntaxNode : SyntaxNode
{
var tree = compilation.SyntaxTrees[0];
var model = compilation.GetSemanticModel(tree);
......@@ -232,7 +232,18 @@ protected string GetOperationTreeForTest<TSyntaxNode>(CSharpCompilation compilat
return null;
}
var operation = model.GetOperationInternal(syntaxNode);
return model.GetOperationInternal(syntaxNode);
}
protected string GetOperationTreeForTest<TSyntaxNode>(CSharpCompilation compilation)
where TSyntaxNode: SyntaxNode
{
var operation = GetOperationForTest<TSyntaxNode>(compilation);
return operation != null ? OperationTreeVerifier.GetOperationTree(operation) : null;
}
protected string GetOperationTreeForTest(IOperation operation)
{
return operation != null ? OperationTreeVerifier.GetOperationTree(operation) : null;
}
......@@ -243,11 +254,13 @@ protected string GetOperationTreeForTest<TSyntaxNode>(string testSrc, string exp
return GetOperationTreeForTest<TSyntaxNode>(compilation);
}
protected void VerifyOperationTreeForTest<TSyntaxNode>(CSharpCompilation compilation, string expectedOperationTree)
protected void VerifyOperationTreeForTest<TSyntaxNode>(CSharpCompilation compilation, string expectedOperationTree, Action<IOperation> AdditionalOperationTreeVerifier = null)
where TSyntaxNode : SyntaxNode
{
var actualOperationTree = GetOperationTreeForTest<TSyntaxNode>(compilation);
var actualOperation = GetOperationForTest<TSyntaxNode>(compilation);
var actualOperationTree = GetOperationTreeForTest(actualOperation);
OperationTreeVerifier.Verify(expectedOperationTree, actualOperationTree);
AdditionalOperationTreeVerifier?.Invoke(actualOperation);
}
protected void VerifyOperationTreeForTest<TSyntaxNode>(string testSrc, string expectedOperationTree, CSharpCompilationOptions compilationOptions = null, CSharpParseOptions parseOptions = null)
......@@ -257,29 +270,43 @@ protected void VerifyOperationTreeForTest<TSyntaxNode>(string testSrc, string ex
OperationTreeVerifier.Verify(expectedOperationTree, actualOperationTree);
}
protected void VerifyOperationTreeAndDiagnosticsForTest<TSyntaxNode>(CSharpCompilation compilation, string expectedOperationTree, DiagnosticDescription[] expectedDiagnostics)
protected void VerifyOperationTreeAndDiagnosticsForTest<TSyntaxNode>(CSharpCompilation compilation, string expectedOperationTree, DiagnosticDescription[] expectedDiagnostics, Action<IOperation> AdditionalOperationTreeVerifier = null)
where TSyntaxNode : SyntaxNode
{
var actualDiagnostics = compilation.GetDiagnostics().Where(d => d.Severity != DiagnosticSeverity.Hidden);
actualDiagnostics.Verify(expectedDiagnostics);
VerifyOperationTreeForTest<TSyntaxNode>(compilation, expectedOperationTree);
VerifyOperationTreeForTest<TSyntaxNode>(compilation, expectedOperationTree, AdditionalOperationTreeVerifier);
}
private static readonly MetadataReference[] s_defaultOperationReferences = new[] { SystemRef, SystemCoreRef, ValueTupleRef, SystemRuntimeFacadeRef };
protected void VerifyOperationTreeAndDiagnosticsForTest<TSyntaxNode>(string testSrc, string expectedOperationTree, DiagnosticDescription[] expectedDiagnostics, CSharpCompilationOptions compilationOptions = null, CSharpParseOptions parseOptions = null, MetadataReference[] additionalReferences = null)
protected void VerifyOperationTreeAndDiagnosticsForTest<TSyntaxNode>(string testSrc,
string expectedOperationTree,
DiagnosticDescription[] expectedDiagnostics,
CSharpCompilationOptions compilationOptions = null,
CSharpParseOptions parseOptions = null,
MetadataReference[] additionalReferences = null,
Action<IOperation> AdditionalOperationTreeVerifier = null)
where TSyntaxNode : SyntaxNode
{
var references = additionalReferences == null ? s_defaultOperationReferences : additionalReferences.Concat(s_defaultOperationReferences);
var compilation = CreateStandardCompilation(testSrc, references, sourceFileName: "file.cs", options: compilationOptions ?? TestOptions.ReleaseDll, parseOptions: parseOptions);
VerifyOperationTreeAndDiagnosticsForTest<TSyntaxNode>(compilation, expectedOperationTree, expectedDiagnostics);
VerifyOperationTreeAndDiagnosticsForTest<TSyntaxNode>(compilation, expectedOperationTree, expectedDiagnostics, AdditionalOperationTreeVerifier);
}
protected void VerifyOperationTreeAndDiagnosticsForTestWithIL<TSyntaxNode>(string testSrc, string ilSource, string expectedOperationTree, DiagnosticDescription[] expectedDiagnostics, CSharpCompilationOptions compilationOptions = null, CSharpParseOptions parseOptions = null, MetadataReference[] additionalReferences = null)
protected MetadataReference VerifyOperationTreeAndDiagnosticsForTestWithIL<TSyntaxNode>(string testSrc,
string ilSource,
string expectedOperationTree,
DiagnosticDescription[] expectedDiagnostics,
CSharpCompilationOptions compilationOptions = null,
CSharpParseOptions parseOptions = null,
MetadataReference[] additionalReferences = null,
Action<IOperation> AdditionalOperationTreeVerifier = null)
where TSyntaxNode : SyntaxNode
{
var ilReference = CreateMetadataReferenceFromIlSource(ilSource);
VerifyOperationTreeAndDiagnosticsForTest<TSyntaxNode>(testSrc, expectedOperationTree, expectedDiagnostics, compilationOptions, parseOptions, new[] { ilReference });
VerifyOperationTreeAndDiagnosticsForTest<TSyntaxNode>(testSrc, expectedOperationTree, expectedDiagnostics, compilationOptions, parseOptions, new[] { ilReference }, AdditionalOperationTreeVerifier);
return ilReference;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册