提交 ce8ce718 编写于 作者: A AlekseyTs

Fix NullReferenceException in BoundCall.DeriveArgument.

Fixes https://devdiv.visualstudio.com/DevDiv/_workitems?id=382240.
上级 57265d9e
......@@ -100,19 +100,19 @@ public override void Accept(OperationVisitor visitor)
return visitor.VisitInvocationExpression(this, argument);
}
internal static ImmutableArray<IArgument> DeriveArguments(ImmutableArray<BoundExpression> boundArguments, ImmutableArray<string> argumentNames, ImmutableArray<int> argumentsToParameters, ImmutableArray<RefKind> argumentRefKinds, ImmutableArray<Symbols.ParameterSymbol> parameters, SyntaxNode invocationSyntax)
internal static ImmutableArray<IArgument> DeriveArguments(ImmutableArray<BoundExpression> boundArguments, ImmutableArray<string> argumentNamesOpt, ImmutableArray<int> argumentsToParametersOpt, ImmutableArray<RefKind> argumentRefKindsOpt, ImmutableArray<Symbols.ParameterSymbol> parameters, SyntaxNode invocationSyntax)
{
ArrayBuilder<IArgument> arguments = ArrayBuilder<IArgument>.GetInstance(boundArguments.Length);
for (int parameterIndex = 0; parameterIndex < parameters.Length; parameterIndex++)
{
int argumentIndex = -1;
if (argumentsToParameters.IsDefault)
if (argumentsToParametersOpt.IsDefault)
{
argumentIndex = parameterIndex;
}
else
{
argumentIndex = argumentsToParameters.IndexOf(parameterIndex);
argumentIndex = argumentsToParametersOpt.IndexOf(parameterIndex);
}
if ((uint)argumentIndex >= (uint)boundArguments.Length)
......@@ -131,12 +131,12 @@ internal static ImmutableArray<IArgument> DeriveArguments(ImmutableArray<BoundEx
{
// 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, argumentNames, argumentRefKinds, parameters, invocationSyntax));
arguments.Add(DeriveArgument(parameterIndex, boundArguments.Length, boundArguments, argumentNamesOpt, argumentRefKindsOpt, parameters, invocationSyntax));
}
}
else
{
arguments.Add(DeriveArgument(parameterIndex, argumentIndex, boundArguments, argumentNames, argumentRefKinds, parameters, invocationSyntax));
arguments.Add(DeriveArgument(parameterIndex, argumentIndex, boundArguments, argumentNamesOpt, argumentRefKindsOpt, parameters, invocationSyntax));
}
}
......@@ -145,7 +145,7 @@ internal static ImmutableArray<IArgument> DeriveArguments(ImmutableArray<BoundEx
private static readonly ConditionalWeakTable<BoundExpression, IArgument> s_argumentMappings = new ConditionalWeakTable<BoundExpression, IArgument>();
private static IArgument DeriveArgument(int parameterIndex, int argumentIndex, ImmutableArray<BoundExpression> boundArguments, ImmutableArray<string> argumentNames, ImmutableArray<RefKind> argumentRefKinds, ImmutableArray<Symbols.ParameterSymbol> parameters, SyntaxNode invocationSyntax)
private static IArgument DeriveArgument(int parameterIndex, int argumentIndex, ImmutableArray<BoundExpression> boundArguments, ImmutableArray<string> argumentNamesOpt, ImmutableArray<RefKind> argumentRefKindsOpt, ImmutableArray<Symbols.ParameterSymbol> parameters, SyntaxNode invocationSyntax)
{
if ((uint)argumentIndex >= (uint)boundArguments.Length)
{
......@@ -167,16 +167,16 @@ private static IArgument DeriveArgument(int parameterIndex, int argumentIndex, I
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.Positional, parameter, argument);
return new Argument(ArgumentKind.Positional, parameterOpt, argument);
}
if (argumentIndex >= parameters.Length - 1 &&
......@@ -184,18 +184,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 SimpleArgument(parameter, argument);
return new SimpleArgument(parameterOpt, argument);
}
}
return new Argument(ArgumentKind.Named, parameter, argument);
return new Argument(ArgumentKind.Named, parameterOpt, argument);
});
}
......@@ -219,26 +220,25 @@ private static IOperation CreateParamArray(IParameterSymbol parameter, Immutable
return new InvalidExpression(invocationSyntax);
}
internal static IArgument ArgumentMatchingParameter(ImmutableArray<BoundExpression> arguments, ImmutableArray<int> argumentsToParameters, ImmutableArray<string> argumentNames, ImmutableArray<RefKind> argumentRefKinds, ISymbol targetMethod, ImmutableArray<Symbols.ParameterSymbol> parameters, IParameterSymbol parameter, SyntaxNode invocationSyntax)
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(argumentsToParameters, targetMethod, parameter);
int argumentIndex = ArgumentIndexMatchingParameter(argumentsToParametersOpt, targetMethod, parameter);
if (argumentIndex >= 0)
{
return DeriveArgument(parameter.Ordinal, argumentIndex, arguments, argumentNames, argumentRefKinds, parameters, invocationSyntax);
return DeriveArgument(parameter.Ordinal, argumentIndex, arguments, argumentNamesOpt, argumentRefKindsOpt, parameters, invocationSyntax);
}
return null;
}
private static int ArgumentIndexMatchingParameter(ImmutableArray<int> argumentsToParameters, ISymbol targetMethod, IParameterSymbol parameter)
private static int ArgumentIndexMatchingParameter(ImmutableArray<int> argumentsToParametersOpt, ISymbol targetMethod, IParameterSymbol parameter)
{
if (parameter.ContainingSymbol == targetMethod)
{
int parameterIndex = parameter.Ordinal;
ImmutableArray<int> parameterIndices = argumentsToParameters;
if (!parameterIndices.IsDefaultOrEmpty)
if (!argumentsToParametersOpt.IsDefaultOrEmpty)
{
return parameterIndices.IndexOf(parameterIndex);
return argumentsToParametersOpt.IndexOf(parameterIndex);
}
return parameterIndex;
......
......@@ -59,6 +59,7 @@
<Compile Include="Diagnostics\DiagnosticAnalyzerTests.AllInOne.cs" />
<Compile Include="Diagnostics\DiagnosticAnalyzerTests.cs" />
<Compile Include="Diagnostics\GetDiagnosticsTests.cs" />
<Compile Include="Diagnostics\IOperationTests.cs" />
<Compile Include="Diagnostics\OperationAnalyzerTests.cs" />
<Compile Include="FlowAnalysis\FlowDiagnosticTests.cs" />
<Compile Include="FlowAnalysis\FlowTestBase.cs" />
......@@ -156,4 +157,4 @@
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="..\..\..\..\..\build\Targets\Imports.targets" />
</Project>
</Project>
\ No newline at end of file
// 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.Test.Utilities;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using System.Linq;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public class IOperationTests : CompilingTestBase
{
[Fact]
[WorkItem(382240, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=382240")]
public void NullInPlaceOfParamArray()
{
var text = @"
public class Cls
{
public static void Main()
{
Test1(null);
Test2(new object(), null);
}
static void Test1(params int[] x)
{
}
static void Test2(int y, params int[] x)
{
}
}";
var compilation = CreateCompilationWithMscorlib(text, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular);
compilation.VerifyDiagnostics(
// (7,15): error CS1503: Argument 1: cannot convert from 'object' to 'int'
// Test2(new object(), null);
Diagnostic(ErrorCode.ERR_BadArgType, "new object()").WithArguments("1", "object", "int").WithLocation(7, 15)
);
var tree = compilation.SyntaxTrees.Single();
var nodes = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().ToArray();
compilation.VerifyOperationTree(nodes[0], expectedOperationTree:
@"IInvocationExpression (static void Cls.Test1(params System.Int32[] x)) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (Matching Parameter: x) (OperationKind.Argument)
IConversionExpression (ConversionKind.Cast, Implicit) (OperationKind.ConversionExpression, Type: System.Int32[], Constant: null)
ILiteralExpression (Text: null) (OperationKind.LiteralExpression, Type: null, Constant: null)");
compilation.VerifyOperationTree(nodes[1], expectedOperationTree:
@"IInvocationExpression (static void Cls.Test2(System.Int32 y, params System.Int32[] x)) (OperationKind.InvocationExpression, Type: System.Void, IsInvalid)
IArgument (Matching Parameter: y) (OperationKind.Argument)
IObjectCreationExpression (Constructor: System.Object..ctor()) (OperationKind.ObjectCreationExpression, Type: System.Object)
IArgument (Matching Parameter: x) (OperationKind.Argument)
ILiteralExpression (Text: null) (OperationKind.LiteralExpression, Type: null, Constant: null)");
}
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@
Imports Microsoft.CodeAnalysis.Semantics
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Roslyn.Test.Utilities
Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics
......@@ -288,5 +289,66 @@ Sub C.Foo()
ILocalReferenceExpression: i (OperationKind.LocalReferenceExpression, Type: System.Int32)
")
End Sub
<Fact>
<WorkItem(382240, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=382240")>
Public Sub NothingOrAddressOfInPlaceOfParamArray()
Dim source = <compilation>
<file name="c.vb">
<![CDATA[
Module Module1
Sub Main()
Test1(Nothing)
Test2(new System.Guid(), Nothing)
Test1(AddressOf Main)
Test2(new System.Guid(), AddressOf Main)
End Sub
Sub Test1(ParamArray x as Integer())
End Sub
Sub Test2(y As Integer, ParamArray x as Integer())
End Sub
End Module
]]>
</file>
</compilation>
Dim comp = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(source, parseOptions:=TestOptions.RegularWithIOperationFeature)
Dim tree = comp.SyntaxTrees.Single()
comp.AssertTheseDiagnostics(
<expected>
BC30311: Value of type 'Guid' cannot be converted to 'Integer'.
Test2(new System.Guid(), Nothing)
~~~~~~~~~~~~~~~~~
BC30581: 'AddressOf' expression cannot be converted to 'Integer' because 'Integer' is not a delegate type.
Test1(AddressOf Main)
~~~~~~~~~~~~~~
BC30311: Value of type 'Guid' cannot be converted to 'Integer'.
Test2(new System.Guid(), AddressOf Main)
~~~~~~~~~~~~~~~~~
BC30581: 'AddressOf' expression cannot be converted to 'Integer' because 'Integer' is not a delegate type.
Test2(new System.Guid(), AddressOf Main)
~~~~~~~~~~~~~~
</expected>)
Dim nodes = tree.GetRoot().DescendantNodes().OfType(Of InvocationExpressionSyntax)().ToArray()
comp.VerifyOperationTree(nodes(0), expectedOperationTree:=
"IInvocationExpression (static Sub Module1.Test1(ParamArray x As System.Int32())) (OperationKind.InvocationExpression, Type: System.Void)
IArgument (Matching Parameter: x) (OperationKind.Argument)
IConversionExpression (ConversionKind.Basic, Implicit) (OperationKind.ConversionExpression, Type: System.Int32(), Constant: null)
ILiteralExpression (OperationKind.LiteralExpression, Type: null, Constant: null)")
comp.VerifyOperationTree(nodes(1), expectedOperationTree:=
"IInvalidExpression (OperationKind.InvalidExpression, Type: System.Void, IsInvalid)")
comp.VerifyOperationTree(nodes(2), expectedOperationTree:=
"IInvalidExpression (OperationKind.InvalidExpression, Type: System.Void, IsInvalid)")
comp.VerifyOperationTree(nodes(3), expectedOperationTree:=
"IInvalidExpression (OperationKind.InvalidExpression, Type: System.Void, IsInvalid)")
End Sub
End Class
End Namespace
......@@ -790,7 +790,8 @@ public override void VisitLiteralExpression(ILiteralExpression operation)
{
LogString(nameof(ILiteralExpression));
if (operation.ConstantValue.HasValue && operation.ConstantValue.Value.ToString() == operation.Text)
object value;
if (operation.ConstantValue.HasValue && ((value = operation.ConstantValue.Value) == null ? "null" : value.ToString()) == operation.Text)
{
LogString($" (Text: {operation.Text})");
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册