提交 b7f4f2c8 编写于 作者: G Gen Lu

Fix IHasArgumentsExpression implementation

上级 aa38ba15
......@@ -7,6 +7,8 @@
using Microsoft.CodeAnalysis.Semantics;
using Roslyn.Utilities;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Collections;
using System.Collections.Concurrent;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -62,12 +64,8 @@ internal partial class BoundCall : IInvocationExpression
(this.Method.IsVirtual || this.Method.IsAbstract || this.Method.IsOverride) &&
!this.ReceiverOpt.SuppressVirtualCalls;
ImmutableArray<IArgument> IHasArgumentsExpression.ArgumentsInEvaluationOrder => DeriveArguments(this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Method.Parameters, this.Syntax);
IArgument IHasArgumentsExpression.GetArgumentMatchingParameter(IParameterSymbol parameter)
{
return ArgumentMatchingParameter(this.Arguments, this.ArgsToParamsOpt, this.ArgumentNamesOpt, this.ArgumentRefKindsOpt, parameter.ContainingSymbol, ((Symbols.MethodSymbol)parameter.ContainingSymbol).Parameters, parameter, this.Syntax);
}
ImmutableArray<IArgument> IHasArgumentsExpression.ArgumentsInEvaluationOrder
=> DeriveArgumentsInEvaluationOrder(this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Method.Parameters, this.Syntax);
protected override OperationKind ExpressionKind => OperationKind.InvocationExpression;
......@@ -81,83 +79,83 @@ public override void Accept(OperationVisitor visitor)
return visitor.VisitInvocationExpression(this, argument);
}
internal static ImmutableArray<IArgument> DeriveArguments(ImmutableArray<BoundExpression> boundArguments, ImmutableArray<string> argumentNamesOpt, ImmutableArray<int> argumentsToParametersOpt, ImmutableArray<RefKind> argumentRefKindsOpt, ImmutableArray<Symbols.ParameterSymbol> parameters, SyntaxNode invocationSyntax)
internal static ImmutableArray<IArgument> DeriveArgumentsInEvaluationOrder(ImmutableArray<BoundExpression> boundArguments, ImmutableArray<string> argumentNames, ImmutableArray<int> argumentsToParameters, ImmutableArray<RefKind> argumentRefKinds, ImmutableArray<Symbols.ParameterSymbol> parameters, SyntaxNode invocationSyntax)
{
ArrayBuilder<IArgument> arguments = ArrayBuilder<IArgument>.GetInstance(boundArguments.Length);
for (int parameterIndex = 0; parameterIndex < parameters.Length; parameterIndex++)
PooledHashSet<int> matchedParameters = PooledHashSet<int>.GetInstance();
ArrayBuilder<IArgument> evaluationOrderArguments = ArrayBuilder<IArgument>.GetInstance(parameters.Length);
for (int argumentIndex = 0; argumentIndex < boundArguments.Length; argumentIndex++)
{
int argumentIndex = -1;
if (argumentsToParametersOpt.IsDefault)
{
argumentIndex = parameterIndex;
}
else
int parameterIndex = argumentsToParameters.IsDefault ? argumentIndex : argumentsToParameters[argumentIndex];
IArgument argument = DeriveArgument(parameterIndex, argumentIndex, boundArguments, argumentNames, argumentRefKinds, parameters, invocationSyntax);
evaluationOrderArguments.Add(argument);
matchedParameters.Add(parameterIndex);
// If the current argument matches a params parameter and is unnamed, following explicit arguments are treated as part of the params arrray.
if ((uint)parameterIndex < parameters.Length && parameters[parameterIndex].IsParams && (argumentNames.IsDefaultOrEmpty || argumentNames[argumentIndex] == null))
{
argumentIndex = argumentsToParametersOpt.IndexOf(parameterIndex);
break;
}
}
if ((uint)argumentIndex >= (uint)boundArguments.Length)
{
// No argument has been supplied for the parameter at `parameterIndex`:
// 1. `argumentIndex == -1' when the arguments are specified out of parameter order, and no argument is provided for parameter corresponding to `parameters[parameterIndex]`.
// 2. `argumentIndex >= boundArguments.Length` when the arguments are specified in parameter order, and no argument is provided at `parameterIndex`.
Symbols.ParameterSymbol parameter = parameters[parameterIndex];
if (parameter.HasExplicitDefaultValue)
{
// The parameter is optional with a default value.
arguments.Add(new Argument(ArgumentKind.DefaultValue, parameter, new LiteralExpression(parameter.ExplicitDefaultConstantValue, parameter.Type, invocationSyntax)));
}
else
{
// If the invocation is semantically valid, the parameter will be a params array and an empty array will be provided.
// If the argument is otherwise omitted for a parameter with no default value, the invocation is not valid and a null argument will be provided.
arguments.Add(DeriveArgument(parameterIndex, boundArguments.Length, boundArguments, argumentNamesOpt, argumentRefKindsOpt, parameters, invocationSyntax));
}
}
else
// Include implicit arguments after the explicit arguments.
foreach (Symbols.ParameterSymbol parameter in parameters)
{
if (!matchedParameters.Contains(parameter.Ordinal))
{
arguments.Add(DeriveArgument(parameterIndex, argumentIndex, boundArguments, argumentNamesOpt, argumentRefKindsOpt, parameters, invocationSyntax));
evaluationOrderArguments.Add(DeriveArgument(parameter.Ordinal, -1, boundArguments, argumentNames, argumentRefKinds, parameters, invocationSyntax));
}
}
return arguments.ToImmutableAndFree();
}
matchedParameters.Free();
return evaluationOrderArguments.ToImmutableAndFree();
}
private static readonly ConditionalWeakTable<BoundExpression, IArgument> s_argumentMappings = new ConditionalWeakTable<BoundExpression, IArgument>();
private static readonly ConditionalWeakTable<SyntaxNode, ConcurrentDictionary<Symbols.ParameterSymbol, IArgument>> s_omittedArgumentMappings = new ConditionalWeakTable<SyntaxNode, ConcurrentDictionary<Symbols.ParameterSymbol, IArgument>>();
private static IArgument DeriveArgument(int parameterIndex, int argumentIndex, ImmutableArray<BoundExpression> boundArguments, ImmutableArray<string> argumentNamesOpt, ImmutableArray<RefKind> argumentRefKindsOpt, ImmutableArray<Symbols.ParameterSymbol> parameters, SyntaxNode invocationSyntax)
private static IArgument DeriveArgument(int parameterIndex, int argumentIndex, ImmutableArray<BoundExpression> boundArguments, ImmutableArray<string> argumentNames, ImmutableArray<RefKind> argumentRefKinds, ImmutableArray<Symbols.ParameterSymbol> parameters, SyntaxNode invocationSyntax)
{
if ((uint)argumentIndex >= (uint)boundArguments.Length)
{
// Check for an omitted argument that becomes an empty params array.
if (parameters.Length > 0)
{
Symbols.ParameterSymbol lastParameter = parameters[parameters.Length - 1];
if (lastParameter.IsParams)
ConcurrentDictionary<Symbols.ParameterSymbol, IArgument> omittedArguments = s_omittedArgumentMappings.GetValue(invocationSyntax, syntax => new ConcurrentDictionary<Symbols.ParameterSymbol, IArgument>());
return omittedArguments.GetOrAdd(
parameters[parameterIndex],
(parameter) =>
{
return new Argument(ArgumentKind.ParamArray, lastParameter, CreateParamArray(lastParameter, boundArguments, argumentIndex, invocationSyntax));
}
}
// No argument has been supplied for the parameter at `parameterIndex`:
// 1. `argumentIndex == -1' when the arguments are specified out of parameter order, and no argument is provided for the parameter corresponding to `parameters[parameterIndex]`.
// 2. `argumentIndex >= boundArguments.Length` when the arguments are specified in parameter order, and no argument is provided at `parameterIndex`.
// Check for a parameter with a default value.
if (parameter.HasExplicitDefaultValue)
{
return new Argument(ArgumentKind.DefaultValue, parameter, new LiteralExpression(parameter.ExplicitDefaultConstantValue, parameter.Type, invocationSyntax));
}
// Check for an omitted argument that becomes an empty params array.
if (parameter.IsParams)
{
return new Argument(ArgumentKind.ParamArray, parameter, CreateParamArray(parameter, boundArguments, argumentIndex, invocationSyntax));
}
// There is no supplied argument and there is no params parameter. Any action is suspect at this point.
return new SimpleArgument(null, new InvalidExpression(invocationSyntax, ImmutableArray<IOperation>.Empty));
// There is no supplied argument and there is no params parameter. Any action is suspect at this point.
return new Argument(ArgumentKind.DefaultValue, parameter, new InvalidExpression(invocationSyntax));
});
}
return s_argumentMappings.GetValue(
boundArguments[argumentIndex],
(argument) =>
{
string nameOpt = !argumentNamesOpt.IsDefaultOrEmpty ? argumentNamesOpt[argumentIndex] : null;
Symbols.ParameterSymbol parameterOpt = (uint)parameterIndex < (uint)parameters.Length ? parameters[parameterIndex] : null;
string name = !argumentNames.IsDefaultOrEmpty ? argumentNames[argumentIndex] : null;
Symbols.ParameterSymbol parameter = (uint)parameterIndex < (uint)parameters.Length ? parameters[parameterIndex] : null;
if ((object)nameOpt == null)
if ((object)name == null)
{
RefKind refMode = argumentRefKindsOpt.IsDefaultOrEmpty ? RefKind.None : argumentRefKindsOpt[argumentIndex];
RefKind refMode = argumentRefKinds.IsDefaultOrEmpty ? RefKind.None : argumentRefKinds[argumentIndex];
if (refMode != RefKind.None)
{
return new Argument(ArgumentKind.Positional, parameterOpt, argument);
return new Argument(ArgumentKind.Positional, parameter, argument);
}
if (argumentIndex >= parameters.Length - 1 &&
......@@ -165,19 +163,36 @@ private static IArgument DeriveArgument(int parameterIndex, int argumentIndex, I
parameters[parameters.Length - 1].IsParams &&
// An argument that is an array of the appropriate type is not a params argument.
(boundArguments.Length > argumentIndex + 1 ||
((object)argument.Type != null && // If argument type is null, we are in an error scenario and cannot tell if it is a param array, or not.
(argument.Type.TypeKind != TypeKind.Array ||
!argument.Type.Equals(parameters[parameters.Length - 1].Type, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds)))))
argument.Type.TypeKind != TypeKind.Array ||
!argument.Type.Equals(parameters[parameters.Length - 1].Type, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds)))
{
return new Argument(ArgumentKind.ParamArray, parameters[parameters.Length - 1], CreateParamArray(parameters[parameters.Length - 1], boundArguments, argumentIndex, invocationSyntax));
}
else
{
return new SimpleArgument(parameterOpt, argument);
return new Argument(ArgumentKind.Positional, parameter, argument);
}
}
return new Argument(ArgumentKind.Named, parameterOpt, argument);
// A named argument which is also the only argument for a params parameter
// is a IArgument of ArgumentKind.ParamArray. e.g.
//
// static void M1(string[] args)
// {
// M2(array: 1, str: "");
// }
// static void M2(string str, params int[] array) { }
if (parameter?.IsParams == true &&
// An argument that is an array of the appropriate type is not a params argument.
(argument.Type.TypeKind != TypeKind.Array ||
!argument.Type.Equals(parameter.Type, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds)))
{
Debug.Assert(parameterIndex == parameters.Length - 1);
return new Argument(ArgumentKind.ParamArray, parameter, CreateParamArray(parameter, argument));
}
return new Argument(ArgumentKind.Named, parameter, argument);
});
}
......@@ -186,14 +201,22 @@ private static IOperation CreateParamArray(IParameterSymbol parameter, Immutable
if (parameter.Type.TypeKind == TypeKind.Array)
{
IArrayTypeSymbol arrayType = (IArrayTypeSymbol)parameter.Type;
ArrayBuilder<IOperation> builder = ArrayBuilder<IOperation>.GetInstance(boundArguments.Length - firstArgumentElementIndex);
for (int index = firstArgumentElementIndex; index < boundArguments.Length; index++)
ImmutableArray<IOperation> paramArrayArguments;
// If there are no matching arguments, then the argument index is negative.
if (firstArgumentElementIndex >= 0)
{
builder.Add(boundArguments[index]);
ArrayBuilder<IOperation> builder = ArrayBuilder<IOperation>.GetInstance(boundArguments.Length - firstArgumentElementIndex);
for (int index = firstArgumentElementIndex; index < boundArguments.Length; index++)
{
builder.Add(boundArguments[index]);
}
paramArrayArguments = builder.ToImmutableAndFree();
}
else
{
paramArrayArguments = ImmutableArray<IOperation>.Empty;
}
var paramArrayArguments = builder.ToImmutableAndFree();
// Use the invocation syntax node if there is no actual syntax available for the argument (because the paramarray is empty.)
return new ArrayCreationExpression(arrayType, paramArrayArguments, paramArrayArguments.Length > 0 ? paramArrayArguments[0].Syntax : invocationSyntax);
......@@ -202,43 +225,34 @@ private static IOperation CreateParamArray(IParameterSymbol parameter, Immutable
return new InvalidExpression(invocationSyntax, ImmutableArray<IOperation>.Empty);
}
internal static IArgument ArgumentMatchingParameter(ImmutableArray<BoundExpression> arguments, ImmutableArray<int> argumentsToParametersOpt, ImmutableArray<string> argumentNamesOpt, ImmutableArray<RefKind> argumentRefKindsOpt, ISymbol targetMethod, ImmutableArray<Symbols.ParameterSymbol> parameters, IParameterSymbol parameter, SyntaxNode invocationSyntax)
{
int argumentIndex = ArgumentIndexMatchingParameter(argumentsToParametersOpt, targetMethod, parameter);
if (argumentIndex >= 0)
{
return DeriveArgument(parameter.Ordinal, argumentIndex, arguments, argumentNamesOpt, argumentRefKindsOpt, parameters, invocationSyntax);
}
return null;
}
private static int ArgumentIndexMatchingParameter(ImmutableArray<int> argumentsToParametersOpt, ISymbol targetMethod, IParameterSymbol parameter)
private static IOperation CreateParamArray(IParameterSymbol parameter, BoundExpression boundArgument)
{
if (parameter.ContainingSymbol == targetMethod)
var Syntax = boundArgument.Syntax;
if (parameter.Type.TypeKind == TypeKind.Array)
{
int parameterIndex = parameter.Ordinal;
if (!argumentsToParametersOpt.IsDefaultOrEmpty)
{
return argumentsToParametersOpt.IndexOf(parameterIndex);
}
IArrayTypeSymbol arrayType = (IArrayTypeSymbol)parameter.Type;
ImmutableArray<IOperation> paramArrayArguments = ImmutableArray.Create<IOperation>(boundArgument);
return parameterIndex;
Debug.Assert(boundArgument.Syntax != null);
return new ArrayCreationExpression(arrayType, paramArrayArguments, Syntax);
}
return -1;
return new InvalidExpression(Syntax);
}
private abstract class ArgumentBase : IArgument
private class Argument : IArgument
{
public ArgumentBase(IParameterSymbol parameter, IOperation value)
public Argument(ArgumentKind kind, IParameterSymbol parameter, IOperation value)
{
Debug.Assert(value != null);
this.ArgumentKind = kind;
this.Value = value;
this.Parameter = parameter;
}
public ArgumentKind ArgumentKind { get; }
public IParameterSymbol Parameter { get; }
public IOperation Value { get; }
......@@ -257,8 +271,6 @@ public ArgumentBase(IParameterSymbol parameter, IOperation value)
public Optional<object> ConstantValue => default(Optional<object>);
public abstract ArgumentKind ArgumentKind { get; }
void IOperation.Accept(OperationVisitor visitor)
{
visitor.VisitArgument(this);
......@@ -269,26 +281,6 @@ void IOperation.Accept(OperationVisitor visitor)
return visitor.VisitArgument(this, argument);
}
}
private sealed class SimpleArgument : ArgumentBase
{
public SimpleArgument(IParameterSymbol parameter, IOperation value)
: base(parameter, value)
{ }
public override ArgumentKind ArgumentKind => ArgumentKind.Positional;
}
private sealed class Argument : ArgumentBase
{
public Argument(ArgumentKind kind, IParameterSymbol parameter, IOperation value)
: base(parameter, value)
{
this.ArgumentKind = kind;
}
public override ArgumentKind ArgumentKind { get; }
}
}
internal partial class BoundLocal : ILocalReferenceExpression
......@@ -358,12 +350,8 @@ internal partial class BoundIndexerAccess : IIndexedPropertyReferenceExpression
ISymbol IMemberReferenceExpression.Member => this.Indexer;
ImmutableArray<IArgument> IHasArgumentsExpression.ArgumentsInEvaluationOrder => BoundCall.DeriveArguments(this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Indexer.Parameters, this.Syntax);
IArgument IHasArgumentsExpression.GetArgumentMatchingParameter(IParameterSymbol parameter)
{
return BoundCall.ArgumentMatchingParameter(this.Arguments, this.ArgsToParamsOpt, this.ArgumentNamesOpt, this.ArgumentRefKindsOpt, this.Indexer, this.Indexer.Parameters, parameter, this.Syntax);
}
ImmutableArray<IArgument> IHasArgumentsExpression.ArgumentsInEvaluationOrder
=> BoundCall.DeriveArgumentsInEvaluationOrder(this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Indexer.Parameters, this.Syntax);
protected override OperationKind ExpressionKind => OperationKind.IndexedPropertyReferenceExpression;
......@@ -519,12 +507,8 @@ internal partial class BoundObjectCreationExpression : IObjectCreationExpression
IMethodSymbol IObjectCreationExpression.Constructor => this.Constructor;
ImmutableArray<IArgument> IHasArgumentsExpression.ArgumentsInEvaluationOrder => BoundCall.DeriveArguments(this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Constructor.Parameters, this.Syntax);
IArgument IHasArgumentsExpression.GetArgumentMatchingParameter(IParameterSymbol parameter)
{
return BoundCall.ArgumentMatchingParameter(this.Arguments, this.ArgsToParamsOpt, this.ArgumentNamesOpt, this.ArgumentRefKindsOpt, this.Constructor, this.Constructor.Parameters, parameter, this.Syntax);
}
ImmutableArray<IArgument> IHasArgumentsExpression.ArgumentsInEvaluationOrder
=> BoundCall.DeriveArgumentsInEvaluationOrder(this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Constructor.Parameters, this.Syntax);
ImmutableArray<ISymbolInitializer> IObjectCreationExpression.MemberInitializers
{
......
......@@ -59,6 +59,7 @@
<Compile Include="Diagnostics\DiagnosticAnalyzerTests.AllInOne.cs" />
<Compile Include="Diagnostics\DiagnosticAnalyzerTests.cs" />
<Compile Include="Diagnostics\GetDiagnosticsTests.cs" />
<Compile Include="IOperation\IOperationTests_IArgument.cs" />
<Compile Include="IOperation\IOperationTests_IIfStatement.cs" />
<Compile Include="IOperation\IOperationTests_ISymbolInitializer.cs" />
<Compile Include="IOperation\IOperationTests_InvalidExpression.cs" />
......
// 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.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public partial class IOperationTests : SemanticModelTestBase
{
[Fact]
public void ExplicitSimpleArgument()
{
string source = @"
class P
{
static void M1()
{
/*<bind>*/M2(1, """")/*</bind>*/;
}
static void M2(int x, string y) { }
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2(System.Int32 x, System.String y)) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (ArgumentKind.Positional Matching Parameter: x) (OperationKind.Argument)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
IArgument (ArgumentKind.Positional Matching Parameter: y) (OperationKind.Argument)
ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: )
";
VerifyOperationTreeForTest<InvocationExpressionSyntax>(source, expectedOperationTree);
}
[Fact]
public void DefaultSimpleArgument()
{
string source = @"
class P
{
static void M1()
{
/*<bind>*/M2(1)/*</bind>*/;
}
static void M2(int x, string y = null) { }
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2(System.Int32 x, [System.String y = null])) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (ArgumentKind.Positional Matching Parameter: x) (OperationKind.Argument)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
IArgument (ArgumentKind.DefaultValue Matching Parameter: y) (OperationKind.Argument)
ILiteralExpression (Text: null) (OperationKind.LiteralExpression, Type: System.String, Constant: null)
";
VerifyOperationTreeForTest<InvocationExpressionSyntax>(source, expectedOperationTree);
}
[Fact]
public void DefaultAndExplicitNamedArguments()
{
string source = @"
class P
{
static void M1()
{
/*<bind>*/M2(1, z: 10)/*</bind>*/;
}
static void M2(int x = 1, int y = 2, int z = 3) { }
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2([System.Int32 x = 1], [System.Int32 y = 2], [System.Int32 z = 3])) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (ArgumentKind.Positional Matching Parameter: x) (OperationKind.Argument)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
IArgument (ArgumentKind.Named Matching Parameter: z) (OperationKind.Argument)
ILiteralExpression (Text: 10) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 10)
IArgument (ArgumentKind.DefaultValue Matching Parameter: y) (OperationKind.Argument)
ILiteralExpression (Text: 2) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2)
";
VerifyOperationTreeForTest<InvocationExpressionSyntax>(source, expectedOperationTree);
}
[Fact]
public void ExplicitNamedArgument()
{
string source = @"
class P
{
static void M1()
{
/*<bind>*/M2(x: 1, y: """")/*</bind>*/;
}
static void M2(int x, string y = null) { }
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2(System.Int32 x, [System.String y = null])) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (ArgumentKind.Named Matching Parameter: x) (OperationKind.Argument)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
IArgument (ArgumentKind.Named Matching Parameter: y) (OperationKind.Argument)
ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: )
";
VerifyOperationTreeForTest<InvocationExpressionSyntax>(source, expectedOperationTree);
}
[Fact]
public void OutOfOrderExplicitNamedArgument()
{
string source = @"
class P
{
static void M1()
{
/*<bind>*/M2(y: """", x: 1)/*</bind>*/;
}
static void M2(int x = 1, string y = null) { }
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2([System.Int32 x = 1], [System.String y = null])) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (ArgumentKind.Named Matching Parameter: y) (OperationKind.Argument)
ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: )
IArgument (ArgumentKind.Named Matching Parameter: x) (OperationKind.Argument)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
";
VerifyOperationTreeForTest<InvocationExpressionSyntax>(source, expectedOperationTree);
}
[Fact]
public void DefaultNamedArgument()
{
string source = @"
class P
{
static void M1()
{
/*<bind>*/M2(y: """")/*</bind>*/;
}
static void M2(int x = 1, string y = null) { }
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2([System.Int32 x = 1], [System.String y = null])) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (ArgumentKind.Named Matching Parameter: y) (OperationKind.Argument)
ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: )
IArgument (ArgumentKind.DefaultValue Matching Parameter: x) (OperationKind.Argument)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
";
VerifyOperationTreeForTest<InvocationExpressionSyntax>(source, expectedOperationTree);
}
[Fact]
public void RefAndOutArguments()
{
string source = @"
class P
{
void M1()
{
int a = 1;
int b;
/*<bind>*/M2(ref a, out b)/*</bind>*/;
}
void M2(ref int x, out int y) { y = 10; }
}
";
string expectedOperationTree = @"
IInvocationExpression ( void P.M2(ref System.Int32 x, out System.Int32 y)) (OperationKind.InvocationExpression, Type: System.Void)
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: P)
IArgument (ArgumentKind.Positional Matching Parameter: x) (OperationKind.Argument)
ILocalReferenceExpression: a (OperationKind.LocalReferenceExpression, Type: System.Int32)
IArgument (ArgumentKind.Positional Matching Parameter: y) (OperationKind.Argument)
ILocalReferenceExpression: b (OperationKind.LocalReferenceExpression, Type: System.Int32)
";
VerifyOperationTreeForTest<InvocationExpressionSyntax>(source, expectedOperationTree);
}
[Fact]
public void NamedRefAndOutArguments()
{
string source = @"
class P
{
void M1()
{
int a = 1;
int b;
/*<bind>*/M2(y: out b, x: ref a)/*</bind>*/;
}
void M2(ref int x, out int y) { y = 10; }
}
";
string expectedOperationTree = @"
IInvocationExpression ( void P.M2(ref System.Int32 x, out System.Int32 y)) (OperationKind.InvocationExpression, Type: System.Void)
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: P)
IArgument (ArgumentKind.Named Matching Parameter: y) (OperationKind.Argument)
ILocalReferenceExpression: b (OperationKind.LocalReferenceExpression, Type: System.Int32)
IArgument (ArgumentKind.Named Matching Parameter: x) (OperationKind.Argument)
ILocalReferenceExpression: a (OperationKind.LocalReferenceExpression, Type: System.Int32)
";
VerifyOperationTreeForTest<InvocationExpressionSyntax>(source, expectedOperationTree);
}
[Fact]
public void OmittedParamsArrayArgument()
{
string source = @"
class P
{
static void M1(string[] args)
{
/*<bind>*/M2("""")/*</bind>*/;
}
static void M2(string str, params int[] array) { }
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2(System.String str, params System.Int32[] array)) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (ArgumentKind.Positional Matching Parameter: str) (OperationKind.Argument)
ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: )
IArgument (ArgumentKind.ParamArray Matching Parameter: array) (OperationKind.Argument)
IArrayCreationExpression (Dimension sizes: 1, Element Type: System.Int32) (OperationKind.ArrayCreationExpression, Type: System.Int32[])
ILiteralExpression (Text: 0) (OperationKind.LiteralExpression, Type: null, Constant: 0)
IArrayInitializer (OperationKind.ArrayInitializer)
";
VerifyOperationTreeForTest<InvocationExpressionSyntax>(source, expectedOperationTree);
}
[Fact]
public void ParamsArrayArguments()
{
string source = @"
class P
{
static void M1(string[] args)
{
/*<bind>*/M2("""", 1, 2)/*</bind>*/;
}
static void M2(string str, params int[] array) { }
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2(System.String str, params System.Int32[] array)) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (ArgumentKind.Positional Matching Parameter: str) (OperationKind.Argument)
ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: )
IArgument (ArgumentKind.ParamArray Matching Parameter: array) (OperationKind.Argument)
IArrayCreationExpression (Dimension sizes: 1, Element Type: System.Int32) (OperationKind.ArrayCreationExpression, Type: System.Int32[])
ILiteralExpression (Text: 2) (OperationKind.LiteralExpression, Type: null, Constant: 2)
IArrayInitializer (OperationKind.ArrayInitializer)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
ILiteralExpression (Text: 2) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2)
";
VerifyOperationTreeForTest<InvocationExpressionSyntax>(source, expectedOperationTree);
}
[Fact]
public void ArrayAsParamsArrayArgument()
{
string source = @"
class P
{
static void M1(string[] args)
{
/*<bind>*/M2("""", new int[] { 1, 2 })/*</bind>*/;
}
static void M2(string str, params int[] array) { }
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2(System.String str, params System.Int32[] array)) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (ArgumentKind.Positional Matching Parameter: str) (OperationKind.Argument)
ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: )
IArgument (ArgumentKind.Positional Matching Parameter: array) (OperationKind.Argument)
IArrayCreationExpression (Dimension sizes: 1, Element Type: System.Int32) (OperationKind.ArrayCreationExpression, Type: System.Int32[])
ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2)
IArrayInitializer (OperationKind.ArrayInitializer)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
ILiteralExpression (Text: 2) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2)
";
VerifyOperationTreeForTest<InvocationExpressionSyntax>(source, expectedOperationTree);
}
[Fact]
public void NamedParamsArrayArgument()
{
string source = @"
class P
{
static void M1(string[] args)
{
/*<bind>*/M2(array: 1, str: """")/*</bind>*/;
}
static void M2(string str, params int[] array) { }
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2(System.String str, params System.Int32[] array)) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (ArgumentKind.ParamArray Matching Parameter: array) (OperationKind.Argument)
IArrayCreationExpression (Dimension sizes: 1, Element Type: System.Int32) (OperationKind.ArrayCreationExpression, Type: System.Int32[])
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: null, Constant: 1)
IArrayInitializer (OperationKind.ArrayInitializer)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
IArgument (ArgumentKind.Named Matching Parameter: str) (OperationKind.Argument)
ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: )
";
VerifyOperationTreeForTest<InvocationExpressionSyntax>(source, expectedOperationTree);
}
[Fact]
public void ArrayAsNamedParamsArrayArgument()
{
string source = @"
class P
{
static void M1(string[] args)
{
/*<bind>*/M2(array: new[] { 1 }, str: """")/*</bind>*/;
}
static void M2(string str, params int[] array) { }
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2(System.String str, params System.Int32[] array)) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (ArgumentKind.Named Matching Parameter: array) (OperationKind.Argument)
IArrayCreationExpression (Dimension sizes: 1, Element Type: System.Int32) (OperationKind.ArrayCreationExpression, Type: System.Int32[])
ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
IArrayInitializer (OperationKind.ArrayInitializer)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
IArgument (ArgumentKind.Named Matching Parameter: str) (OperationKind.Argument)
ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: )
";
VerifyOperationTreeForTest<InvocationExpressionSyntax>(source, expectedOperationTree);
}
}
}
......@@ -11,7 +11,7 @@ internal partial class IndexedPropertyReferenceExpression : IHasArgumentsExpress
/// and params/ParamArray arguments have been collected into arrays. Default values are supplied for
/// optional arguments missing in source.
/// </summary>
public ImmutableArray<IArgument> ArgumentsInParameterOrder { get; }
public ImmutableArray<IArgument> ArgumentsInEvaluationOrder { get; }
/// <summary>
/// Find the argument supplied for a given parameter of the target method.
/// </summary>
......
......@@ -11,7 +11,7 @@ internal partial class InvocationExpression : IHasArgumentsExpression
/// and params/ParamArray arguments have been collected into arrays. Default values are supplied for
/// optional arguments missing in source.
/// </summary>
public ImmutableArray<IArgument> ArgumentsInParameterOrder { get; }
public ImmutableArray<IArgument> ArgumentsInEvaluationOrder { get; }
/// <summary>
/// Find the argument supplied for a given parameter of the target method.
/// </summary>
......
......@@ -11,7 +11,7 @@ internal partial class ObjectCreationExpression : IHasArgumentsExpression
/// and params/ParamArray arguments have been collected into arrays. Default values are supplied for
/// optional arguments missing in source.
/// </summary>
public ImmutableArray<IArgument> ArgumentsInParameterOrder { get; }
public ImmutableArray<IArgument> ArgumentsInEvaluationOrder { get; }
/// <summary>
/// Find the argument supplied for a given parameter of the target method.
/// </summary>
......
// 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 System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using Roslyn.Utilities;
......@@ -11,12 +12,17 @@ public static class OperationExtensions
/// <summary>
/// Find the argument supplied for a given parameter of the target method.
/// </summary>
/// <param name="hasArgumentExpression">The IHasArgumentsExpression object to get matching argument object from.</param>
/// <param name="hasArgumentsExpression">The IHasArgumentsExpression object to get matching argument object from.</param>
/// <param name="parameter">Parameter of the target method.</param>
/// <returns>Argument corresponding to the parameter.</returns>
public static IArgument GetArgumentMatchingParameter(this IHasArgumentsExpression hasArgumentExpression, IParameterSymbol parameter)
public static IArgument GetArgumentMatchingParameter(this IHasArgumentsExpression hasArgumentsExpression, IParameterSymbol parameter)
{
foreach (var argument in hasArgumentExpression.ArgumentsInEvaluationOrder)
if (hasArgumentsExpression == null || parameter == null)
{
return null;
}
foreach (var argument in hasArgumentsExpression.ArgumentsInEvaluationOrder)
{
if (argument.Parameter == parameter)
{
......@@ -26,6 +32,43 @@ public static IArgument GetArgumentMatchingParameter(this IHasArgumentsExpressio
return null;
}
/// <summary>
/// Arguments of the invocation, excluding the instance argument. Arguments are in parameter order,
/// and params/ParamArray arguments have been collected into arrays. Default values are supplied for
/// optional arguments missing in source.
/// </summary>
public static ImmutableArray<IArgument> ArgumentsInParameterOrder(this IHasArgumentsExpression hasArgumentsExpression)
{
ImmutableArray<IArgument> argumentsInEvaluationOrder = hasArgumentsExpression.ArgumentsInEvaluationOrder;
// If all of the arguments were specified positionally the evaluation order is the same as the parameter order.
if (ArgumentsAreInParameterOrder(argumentsInEvaluationOrder))
{
return argumentsInEvaluationOrder;
}
return argumentsInEvaluationOrder.Sort(
(x, y) =>
{
int x1 = x.Parameter.Ordinal;
int y1 = y.Parameter.Ordinal;
return x1 == y1 ? 0 : (x1 < y1 ? -1 : 1);
});
bool ArgumentsAreInParameterOrder(ImmutableArray<IArgument> arguments)
{
for (int argumentIndex = 0; argumentIndex < arguments.Length; argumentIndex++)
{
if (arguments[argumentIndex].Parameter.Ordinal != argumentIndex)
{
return false;
}
}
return true;
}
}
public static IEnumerable<IOperation> Descendants(this IOperation operation)
{
if (operation == null)
......
......@@ -293,10 +293,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Partial Friend Class BoundCall
Implements IInvocationExpression
Private Function IHasArgumentsExpression_GetArgumentMatchingParameter(parameter As IParameterSymbol) As IArgument Implements IHasArgumentsExpression.GetArgumentMatchingParameter
Return ArgumentMatchingParameter(Me.Arguments, parameter, Me.Method.Parameters)
End Function
Private ReadOnly Property IHasArgumentsExpression_ArgumentsInEvaluationOrder As ImmutableArray(Of IArgument) Implements IHasArgumentsExpression.ArgumentsInEvaluationOrder
Get
Return DeriveArguments(Me.Arguments, Me.Method.Parameters)
......@@ -340,23 +336,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return visitor.VisitInvocationExpression(Me, argument)
End Function
Friend Shared Function ArgumentMatchingParameter(arguments As ImmutableArray(Of BoundExpression), parameter As IParameterSymbol, parameters As ImmutableArray(Of Symbols.ParameterSymbol)) As IArgument
Dim index As Integer = parameter.Ordinal
If index <= arguments.Length Then
Return DeriveArgument(index, arguments(index), parameters)
End If
Return Nothing
End Function
Friend Shared Function DeriveArguments(boundArguments As ImmutableArray(Of BoundExpression), parameters As ImmutableArray(Of Symbols.ParameterSymbol)) As ImmutableArray(Of IArgument)
Dim argumentsLength As Integer = boundArguments.Length
Dim arguments As ImmutableArray(Of IArgument).Builder = ImmutableArray.CreateBuilder(Of IArgument)(argumentsLength)
Dim arguments As ArrayBuilder(Of IArgument) = ArrayBuilder(Of IArgument).GetInstance(argumentsLength)
For index As Integer = 0 To argumentsLength - 1 Step 1
arguments.Add(DeriveArgument(index, boundArguments(index), parameters))
Next
Return arguments.ToImmutable()
Return arguments.ToImmutableAndFree()
End Function
Private Shared ReadOnly s_argumentMappings As New System.Runtime.CompilerServices.ConditionalWeakTable(Of BoundExpression, IArgument)
......@@ -1168,10 +1155,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Private Shared ReadOnly s_memberInitializersMappings As New System.Runtime.CompilerServices.ConditionalWeakTable(Of BoundObjectCreationExpression, Object)
Private Function IHasArgumentExpression_GetArgumentMatchingParameter(parameter As IParameterSymbol) As IArgument Implements IHasArgumentsExpression.GetArgumentMatchingParameter
Return BoundCall.ArgumentMatchingParameter(Me.Arguments, parameter, Me.ConstructorOpt.Parameters)
End Function
Private ReadOnly Property IObjectCreationExpression_Constructor As IMethodSymbol Implements IObjectCreationExpression.Constructor
Get
Return Me.ConstructorOpt
......@@ -1463,10 +1446,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Get
End Property
Private Function IHasArgumentsExpression_GetArgumentMatchingParameter(parameter As IParameterSymbol) As IArgument Implements IHasArgumentsExpression.GetArgumentMatchingParameter
Return BoundCall.ArgumentMatchingParameter(Me.Arguments, parameter, Me.PropertySymbol.Parameters)
End Function
Protected Overrides Function ExpressionKind() As OperationKind
Return If(Me.Arguments.Length > 0, OperationKind.IndexedPropertyReferenceExpression, OperationKind.PropertyReferenceExpression)
End Function
......
......@@ -98,6 +98,7 @@
<Compile Include="Diagnostics\GetDiagnosticsTests.vb" />
<Compile Include="IOperation\IOperationTests_InvalidStatement.vb" />
<Compile Include="IOperation\IOperationTests_InvalidExpression.vb" />
<Compile Include="IOperation\IOperationTests_IArgument.vb" />
<Compile Include="IOperation\IOperationTests_IBlockStatement_MethodBlocks.vb" />
<Compile Include="IOperation\IOperationTests_IIfStatement.vb" />
<Compile Include="IOperation\IOperationTests_ISymbolInitializer.vb" />
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Roslyn.Test.Utilities
Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics
Partial Public Class IOperationTests
Inherits SemanticModelTestBase
<Fact()>
Public Sub ExplicitSimpleArgument()
Dim source = <![CDATA[
Module P
Sub M1()
M2(1, "")'BIND:"M2(1, "")"
End Sub
Sub M2(x As Integer, y As String)
End Sub
End Module]]>.Value
Dim expectedOperationTree = <![CDATA[
IInvocationExpression (static Sub P.M2(x As System.Int32, y As System.String)) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (ArgumentKind.Positional Matching Parameter: x) (OperationKind.Argument)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
IArgument (ArgumentKind.Positional Matching Parameter: y) (OperationKind.Argument)
ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: )
]]>.Value
VerifyOperationTreeForTest(Of InvocationExpressionSyntax)(source, expectedOperationTree)
End Sub
<Fact()>
Public Sub ExplicitSimpleArgumentByName()
Dim source = <![CDATA[
Class P
Sub M1()
M2(y:=1, x:=2)'BIND:"M2(y:=1, x:=2)"
End Sub
Sub M2(x As Integer, y As Integer)
End Sub
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IInvocationExpression ( Sub P.M2(x As System.Int32, y As System.Int32)) (OperationKind.InvocationExpression, Type: System.Void)
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: P)
IArgument (ArgumentKind.Positional Matching Parameter: x) (OperationKind.Argument)
ILiteralExpression (Text: 2) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2)
IArgument (ArgumentKind.Positional Matching Parameter: y) (OperationKind.Argument)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
]]>.Value
VerifyOperationTreeForTest(Of InvocationExpressionSyntax)(source, expectedOperationTree)
End Sub
<Fact()>
Public Sub DefaultArgument()
Dim source = <![CDATA[
Class P
Sub M1()
M2(1)'BIND:"M2(1)"
End Sub
Sub M2(x As Integer, Optional y As Integer = 10)
End Sub
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IInvocationExpression ( Sub P.M2(x As System.Int32, [y As System.Int32 = 10])) (OperationKind.InvocationExpression, Type: System.Void)
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: P)
IArgument (ArgumentKind.Positional Matching Parameter: x) (OperationKind.Argument)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
IArgument (ArgumentKind.Positional Matching Parameter: y) (OperationKind.Argument)
ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 10)
]]>.Value
VerifyOperationTreeForTest(Of InvocationExpressionSyntax)(source, expectedOperationTree)
End Sub
<Fact()>
Public Sub ParamArrayArgument()
Dim source = <![CDATA[
Class P
Sub M1()
M2(1, 2, 3)'BIND:"M2(1, 2, 3)"
End Sub
Sub M2(a As Integer, ParamArray c As Integer())
End Sub
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IInvocationExpression ( Sub P.M2(a As System.Int32, ParamArray c As System.Int32())) (OperationKind.InvocationExpression, Type: System.Void)
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: P)
IArgument (ArgumentKind.Positional Matching Parameter: a) (OperationKind.Argument)
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1)
IArgument (ArgumentKind.ParamArray Matching Parameter: c) (OperationKind.Argument)
IArrayCreationExpression (Dimension sizes: 1, Element Type: System.Int32) (OperationKind.ArrayCreationExpression, Type: System.Int32())
ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2)
IArrayInitializer (OperationKind.ArrayInitializer)
ILiteralExpression (Text: 2) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2)
ILiteralExpression (Text: 3) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 3)
]]>.Value
VerifyOperationTreeForTest(Of InvocationExpressionSyntax)(source, expectedOperationTree)
End Sub
End Class
End Namespace
......@@ -536,12 +536,13 @@ public override void VisitInvocationExpression(IInvocationExpression operation)
private void VisitArguments(IHasArgumentsExpression operation)
{
VisitArray(operation.ArgumentsInParameterOrder, "Arguments", logElementCount: true);
VisitArray(operation.ArgumentsInEvaluationOrder, "Arguments", logElementCount: true);
}
public override void VisitArgument(IArgument operation)
{
LogString($"{nameof(IArgument)} (");
LogString($"{nameof(ArgumentKind)}.{operation.ArgumentKind} ");
LogSymbol(operation.Parameter, header: "Matching Parameter", logDisplayString: false);
LogString(")");
LogCommonPropertiesAndNewLine(operation);
......@@ -706,6 +707,7 @@ public override void VisitIndexedPropertyReferenceExpression(IIndexedPropertyRef
LogString($": {operation.Property.ToTestDisplayString()}");
VisitMemberReferenceExpressionCommon(operation);
VisitArguments(operation);
}
public override void VisitUnaryOperatorExpression(IUnaryOperatorExpression operation)
......
......@@ -67,7 +67,7 @@ public sealed override void Initialize(AnalysisContext context)
(operationContext) =>
{
IInvocationExpression invocation = (IInvocationExpression)operationContext.Operation;
foreach (IArgument argument in invocation.ArgumentsInParameterOrder)
foreach (IArgument argument in invocation.ArgumentsInEvaluationOrder)
{
if (argument.Parameter.RefKind == RefKind.Out || argument.Parameter.RefKind == RefKind.Ref)
{
......
......@@ -59,7 +59,7 @@ public sealed override void Initialize(AnalysisContext context)
(operationContext) =>
{
IInvocationExpression invocation = (IInvocationExpression)operationContext.Operation;
foreach (IArgument argument in invocation.ArgumentsInParameterOrder)
foreach (IArgument argument in invocation.ArgumentsInEvaluationOrder)
{
if (argument.Parameter.RefKind == RefKind.Out || argument.Parameter.RefKind == RefKind.Ref)
{
......
......@@ -53,7 +53,7 @@ public sealed override void Initialize(AnalysisContext context)
(operationContext) =>
{
IInvocationExpression invocation = (IInvocationExpression)operationContext.Operation;
foreach (IArgument argument in invocation.ArgumentsInParameterOrder)
foreach (IArgument argument in invocation.ArgumentsInEvaluationOrder)
{
if (argument.Parameter.RefKind == RefKind.Out || argument.Parameter.RefKind == RefKind.Ref)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册