diff --git a/build/Rulesets/Roslyn_BuildRules.ruleset b/build/Rulesets/Roslyn_BuildRules.ruleset
index cdd2d050c7ccdcdb63191cc6d937f0964d087f1b..c2da92b629f266430f0cb3cb2f6cdf54f10aa027 100644
--- a/build/Rulesets/Roslyn_BuildRules.ruleset
+++ b/build/Rulesets/Roslyn_BuildRules.ruleset
@@ -81,7 +81,7 @@
-
+
@@ -89,7 +89,7 @@
-
+
@@ -97,7 +97,7 @@
-
+
diff --git a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs
index 47f0d51a9218611026c7e21509e212e56df7bb33..deb9fe047a4c43ac0818b853403ca2b93e81cd4b 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs
+++ b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs
@@ -1,13 +1,13 @@
// 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.Concurrent;
+using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Runtime.CompilerServices;
-using Microsoft.CodeAnalysis.Collections;
-using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Semantics;
using Roslyn.Utilities;
+using Microsoft.CodeAnalysis.CSharp.Symbols;
+using Microsoft.CodeAnalysis.Collections;
namespace Microsoft.CodeAnalysis.CSharp
{
@@ -63,8 +63,8 @@ internal partial class BoundCall : IInvocationExpression
(this.Method.IsVirtual || this.Method.IsAbstract || this.Method.IsOverride) &&
!this.ReceiverOpt.SuppressVirtualCalls;
- ImmutableArray IHasArgumentsExpression.ArgumentsInEvaluationOrder
- => DeriveArgumentsInEvaluationOrder(this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Method.Parameters, this.Syntax);
+ ImmutableArray IHasArgumentsExpression.ArgumentsInEvaluationOrder
+ => DeriveArguments(this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Method.Parameters, this.Syntax);
protected override OperationKind ExpressionKind => OperationKind.InvocationExpression;
@@ -78,83 +78,56 @@ public override void Accept(OperationVisitor visitor)
return visitor.VisitInvocationExpression(this, argument);
}
- internal static ImmutableArray DeriveArgumentsInEvaluationOrder(ImmutableArray boundArguments, ImmutableArray argumentNames, ImmutableArray argumentsToParameters, ImmutableArray argumentRefKinds, ImmutableArray parameters, SyntaxNode invocationSyntax)
+ internal static ImmutableArray DeriveArguments(ImmutableArray boundArguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentsToParametersOpt, ImmutableArray argumentRefKindsOpt, ImmutableArray parameters, SyntaxNode invocationSyntax)
{
- PooledHashSet matchedParameters = PooledHashSet.GetInstance();
- ArrayBuilder evaluationOrderArguments = ArrayBuilder.GetInstance(parameters.Length);
+ ArrayBuilder sourceOrderArguments = ArrayBuilder.GetInstance(boundArguments.Length);
for (int argumentIndex = 0; argumentIndex < boundArguments.Length; argumentIndex++)
{
- 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))
+ IArgument argument = DeriveArgument(argumentsToParametersOpt.IsDefault ? argumentIndex : argumentsToParametersOpt[argumentIndex], argumentIndex, boundArguments, argumentNamesOpt, argumentRefKindsOpt, parameters, invocationSyntax);
+ sourceOrderArguments.Add(argument);
+ if (argument.ArgumentKind == ArgumentKind.ParamArray)
{
break;
}
}
- // Include implicit arguments after the explicit arguments.
- foreach (Symbols.ParameterSymbol parameter in parameters)
- {
- if (!matchedParameters.Contains(parameter.Ordinal))
- {
- evaluationOrderArguments.Add(DeriveArgument(parameter.Ordinal, -1, boundArguments, argumentNames, argumentRefKinds, parameters, invocationSyntax));
- }
- }
- matchedParameters.Free();
- return evaluationOrderArguments.ToImmutableAndFree();
- }
+ return sourceOrderArguments.ToImmutableAndFree();
+ }
private static readonly ConditionalWeakTable s_argumentMappings = new ConditionalWeakTable();
- private static readonly ConditionalWeakTable> s_omittedArgumentMappings = new ConditionalWeakTable>();
- private static IArgument DeriveArgument(int parameterIndex, int argumentIndex, ImmutableArray boundArguments, ImmutableArray argumentNames, ImmutableArray argumentRefKinds, ImmutableArray parameters, SyntaxNode invocationSyntax)
+ private static IArgument DeriveArgument(int parameterIndex, int argumentIndex, ImmutableArray boundArguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, ImmutableArray parameters, SyntaxNode invocationSyntax)
{
if ((uint)argumentIndex >= (uint)boundArguments.Length)
{
- ConcurrentDictionary omittedArguments = s_omittedArgumentMappings.GetValue(invocationSyntax, syntax => new ConcurrentDictionary());
-
- return omittedArguments.GetOrAdd(
- parameters[parameterIndex],
- (parameter) =>
+ // 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)
{
- // 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));
- }
+ return new Argument(ArgumentKind.ParamArray, lastParameter, CreateParamArray(lastParameter, boundArguments, argumentIndex, invocationSyntax));
+ }
+ }
- // 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));
- });
+ // 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.Empty));
}
return s_argumentMappings.GetValue(
boundArguments[argumentIndex],
(argument) =>
{
- string name = !argumentNames.IsDefaultOrEmpty ? argumentNames[argumentIndex] : null;
- Symbols.ParameterSymbol parameter = (uint)parameterIndex < (uint)parameters.Length ? parameters[parameterIndex] : null;
+ string nameOpt = !argumentNamesOpt.IsDefaultOrEmpty ? argumentNamesOpt[argumentIndex] : null;
+ Symbols.ParameterSymbol parameterOpt = (uint)parameterIndex < (uint)parameters.Length ? parameters[parameterIndex] : null;
- if ((object)name == null)
+ if ((object)nameOpt == null)
{
- RefKind refMode = argumentRefKinds.IsDefaultOrEmpty ? RefKind.None : argumentRefKinds[argumentIndex];
+ RefKind refMode = argumentRefKindsOpt.IsDefaultOrEmpty ? RefKind.None : argumentRefKindsOpt[argumentIndex];
if (refMode != RefKind.None)
{
- return new Argument(ArgumentKind.Explicit, parameter, argument);
+ return new Argument(ArgumentKind.Explicit, parameterOpt, argument);
}
if (argumentIndex >= parameters.Length - 1 &&
@@ -162,36 +135,19 @@ 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 ||
- argument.Type.TypeKind != TypeKind.Array ||
- !argument.Type.Equals(parameters[parameters.Length - 1].Type, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds)))
+ ((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)))))
{
return new Argument(ArgumentKind.ParamArray, parameters[parameters.Length - 1], CreateParamArray(parameters[parameters.Length - 1], boundArguments, argumentIndex, invocationSyntax));
}
else
{
- return new Argument(ArgumentKind.Explicit, parameter, argument);
+ return new SimpleArgument(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.Explicit, parameter, argument);
+ return new Argument(ArgumentKind.Explicit, parameterOpt, argument);
});
}
@@ -200,23 +156,15 @@ private static IOperation CreateParamArray(IParameterSymbol parameter, Immutable
if (parameter.Type.TypeKind == TypeKind.Array)
{
IArrayTypeSymbol arrayType = (IArrayTypeSymbol)parameter.Type;
- ImmutableArray paramArrayArguments;
-
- // If there are no matching arguments, then the argument index is negative.
- if (firstArgumentElementIndex >= 0)
+ ArrayBuilder builder = ArrayBuilder.GetInstance(boundArguments.Length - firstArgumentElementIndex);
+ for (int index = firstArgumentElementIndex; index < boundArguments.Length; index++)
{
- ArrayBuilder builder = ArrayBuilder.GetInstance(boundArguments.Length - firstArgumentElementIndex);
- for (int index = firstArgumentElementIndex; index < boundArguments.Length; index++)
- {
- builder.Add(boundArguments[index]);
- }
- paramArrayArguments = builder.ToImmutableAndFree();
- }
- else
- {
- paramArrayArguments = ImmutableArray.Empty;
+ builder.Add(boundArguments[index]);
}
+ 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);
}
@@ -224,34 +172,43 @@ private static IOperation CreateParamArray(IParameterSymbol parameter, Immutable
return new InvalidExpression(invocationSyntax, ImmutableArray.Empty);
}
- private static IOperation CreateParamArray(IParameterSymbol parameter, BoundExpression boundArgument)
+ internal static IArgument ArgumentMatchingParameter(ImmutableArray arguments, ImmutableArray argumentsToParametersOpt, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, ISymbol targetMethod, ImmutableArray parameters, IParameterSymbol parameter, SyntaxNode invocationSyntax)
{
- var Syntax = boundArgument.Syntax;
- if (parameter.Type.TypeKind == TypeKind.Array)
+ int argumentIndex = ArgumentIndexMatchingParameter(argumentsToParametersOpt, targetMethod, parameter);
+ if (argumentIndex >= 0)
{
- IArrayTypeSymbol arrayType = (IArrayTypeSymbol)parameter.Type;
- ImmutableArray paramArrayArguments = ImmutableArray.Create(boundArgument);
+ return DeriveArgument(parameter.Ordinal, argumentIndex, arguments, argumentNamesOpt, argumentRefKindsOpt, parameters, invocationSyntax);
+ }
- Debug.Assert(boundArgument.Syntax != null);
- return new ArrayCreationExpression(arrayType, paramArrayArguments, Syntax);
+ return null;
+ }
+
+ private static int ArgumentIndexMatchingParameter(ImmutableArray argumentsToParametersOpt, ISymbol targetMethod, IParameterSymbol parameter)
+ {
+ if (parameter.ContainingSymbol == targetMethod)
+ {
+ int parameterIndex = parameter.Ordinal;
+ if (!argumentsToParametersOpt.IsDefaultOrEmpty)
+ {
+ return argumentsToParametersOpt.IndexOf(parameterIndex);
+ }
+
+ return parameterIndex;
}
- return new InvalidExpression(Syntax);
+ return -1;
}
- private class Argument : IArgument
+ private abstract class ArgumentBase : IArgument
{
- public Argument(ArgumentKind kind, IParameterSymbol parameter, IOperation value)
+ public ArgumentBase(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; }
@@ -270,6 +227,8 @@ public Argument(ArgumentKind kind, IParameterSymbol parameter, IOperation value)
public Optional