提交 22fefe0c 编写于 作者: G Gen Lu 提交者: GitHub

Merge pull request #20379 from genlu/fix20330

Skip deriving IArgument if there's error in parameter type
......@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Semantics;
......@@ -115,11 +115,17 @@ internal static IArgument CreateArgumentOperation(ArgumentKind kind, IParameterS
return (ImmutableArray<IArgument>) s_callToArgumentsMappings.GetValue(
boundNode,
(n) =>
{
{
//TODO: https://github.com/dotnet/roslyn/issues/18722
// Right now, for erroneous code, we exposes all expression in place of arguments as IArgument with Parameter set to null,
// so user needs to check IsInvalid first before using anything we returned. Need to implement a new interface for invalid invocation instead.
if (n.HasErrors || (object)optionalParametersMethod == null)
// so user needs to check IsInvalid first before using anything we returned. Need to implement a new interface for invalid
// invocation instead.
// Note this check doesn't cover all scenarios. For example, when a parameter is a generic type but the type of the type argument
// is undefined.
if ((object)optionalParametersMethod == null
|| n.HasAnyErrors
|| parameters.Any(p => p.Type.IsErrorType())
|| optionalParametersMethod.GetUseSiteDiagnostic()?.DefaultSeverity == DiagnosticSeverity.Error)
{
// optionalParametersMethod can be null if we are writing to a readonly indexer or reading from an writeonly indexer,
// in which case HasErrors property would be true, but we still want to treat this as invalid invocation.
......
......@@ -1711,6 +1711,164 @@ public void M2()
VerifyOperationTreeAndDiagnosticsForTestWithIL<InvocationExpressionSyntax>(csharp, il, expectedOperationTree, expectedDiagnostics);
}
[Fact, WorkItem(20330, "https://github.com/dotnet/roslyn/issues/20330")]
public void DefaultValueNullForNullableTypeParameterWithMissingNullableReference()
{
string source = @"
class P
{
static void M1()
{
/*<bind>*/M2()/*</bind>*/;
}
static void M2(bool? x = null)
{
}
}
";
string expectedOperationTree = @"IInvocationExpression (static void P.M2([System.Boolean[missing]? x = null])) (OperationKind.InvocationExpression, Type: System.Void[missing]) (Syntax: 'M2()')";
var expectedDiagnostics = new DiagnosticDescription[] {
// (3,7): error CS0518: Predefined type 'System.Object' is not defined or imported
// class P
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "P").WithArguments("System.Object").WithLocation(2, 7),
// (10,20): error CS0518: Predefined type 'System.Nullable`1' is not defined or imported
// static void M2(bool? x = null)
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "bool?").WithArguments("System.Nullable`1").WithLocation(9, 20),
// (10,20): error CS0518: Predefined type 'System.Boolean' is not defined or imported
// static void M2(bool? x = null)
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "bool").WithArguments("System.Boolean").WithLocation(9, 20),
// (10,12): error CS0518: Predefined type 'System.Void' is not defined or imported
// static void M2(bool? x = null)
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "void").WithArguments("System.Void").WithLocation(9, 12),
// (5,12): error CS0518: Predefined type 'System.Void' is not defined or imported
// static void M1()
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "void").WithArguments("System.Void").WithLocation(4, 12),
// (7,19): error CS0518: Predefined type 'System.Object' is not defined or imported
// /*<bind>*/M2()/*</bind>*/;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "M2").WithArguments("System.Object").WithLocation(6, 19),
// (3,7): error CS1729: 'object' does not contain a constructor that takes 0 arguments
// class P
Diagnostic(ErrorCode.ERR_BadCtorArgCount, "P").WithArguments("object", "0").WithLocation(2, 7)
};
var compilation = CreateCompilation(source, options: Test.Utilities.TestOptions.ReleaseDll);
VerifyOperationTreeAndDiagnosticsForTest<InvocationExpressionSyntax>(compilation, expectedOperationTree, expectedDiagnostics);
}
[Fact, WorkItem(20330, "https://github.com/dotnet/roslyn/issues/20330")]
public void DefaultValueWithParameterErrorType()
{
string source = @"
class P
{
static void M1()
{
/*<bind>*/M2(1)/*</bind>*/;
}
static void M2(int x, S s = 0)
{
}
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2(System.Int32 x, [S s = null])) (OperationKind.InvocationExpression, Type: System.Void) (Syntax: 'M2(1)')
Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: null) (OperationKind.Argument, IsInvalid) (Syntax: '1')
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
";
var expectedDiagnostics = new DiagnosticDescription[] {
// file.cs(9,27): error CS0246: The type or namespace name 'S' could not be found (are you missing a using directive or an assembly reference?)
// static void M2(int x, S s = 0)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "S").WithArguments("S").WithLocation(9, 27),
// file.cs(9,29): error CS1750: A value of type 'int' cannot be used as a default parameter because there are no standard conversions to type 'S'
// static void M2(int x, S s = 0)
Diagnostic(ErrorCode.ERR_NoConversionForDefaultParam, "s").WithArguments("int", "S").WithLocation(9, 29)
};
VerifyOperationTreeAndDiagnosticsForTest<InvocationExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[Fact]
[WorkItem(18722, "https://github.com/dotnet/roslyn/issues/18722")]
public void DefaultValueForGenericWithUndefinedTypeArgument()
{
// TODO: https://github.com/dotnet/roslyn/issues/18722
// This should be treated as invalid invocation.
string source = @"
class P
{
static void M1()
{
/*<bind>*/M2(1)/*</bind>*/;
}
static void M2(int x, G<S> s = null)
{
}
}
class G<T>
{
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2(System.Int32 x, [G<S> s = null])) (OperationKind.InvocationExpression, Type: System.Void) (Syntax: 'M2(1)')
Arguments(2): IArgument (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument) (Syntax: '1')
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
IArgument (ArgumentKind.DefaultValue, Matching Parameter: s) (OperationKind.Argument) (Syntax: 'M2(1)')
ILiteralExpression (OperationKind.LiteralExpression, Type: G<S>, Constant: null) (Syntax: 'M2(1)')";
var expectedDiagnostics = new DiagnosticDescription[] {
// file.cs(9,29): error CS0246: The type or namespace name 'S' could not be found (are you missing a using directive or an assembly reference?)
// static void M2(int x, G<S> s = null)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "S").WithArguments("S").WithLocation(9, 29)
};
VerifyOperationTreeAndDiagnosticsForTest<InvocationExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[Fact]
[WorkItem(18722, "https://github.com/dotnet/roslyn/issues/18722")]
public void DefaultValueForNullableGenericWithUndefinedTypeArgument()
{
// TODO: https://github.com/dotnet/roslyn/issues/18722
// This should be treated as invalid invocation.
string source = @"
class P
{
static void M1()
{
/*<bind>*/M2(1)/*</bind>*/;
}
static void M2(int x, G<S>? s = null)
{
}
}
struct G<T>
{
}
";
string expectedOperationTree = @"
IInvocationExpression (static void P.M2(System.Int32 x, [G<S>? s = null])) (OperationKind.InvocationExpression, Type: System.Void) (Syntax: 'M2(1)')
Arguments(2): IArgument (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument) (Syntax: '1')
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
IArgument (ArgumentKind.DefaultValue, Matching Parameter: s) (OperationKind.Argument) (Syntax: 'M2(1)')
IDefaultValueExpression (OperationKind.DefaultValueExpression, Type: G<S>?) (Syntax: 'M2(1)')";
var expectedDiagnostics = new DiagnosticDescription[] {
// file.cs(9,29): error CS0246: The type or namespace name 'S' could not be found (are you missing a using directive or an assembly reference?)
// static void M2(int x, G<S> s = null)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "S").WithArguments("S").WithLocation(9, 29)
};
VerifyOperationTreeAndDiagnosticsForTest<InvocationExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
private class IndexerAccessArgumentVerifier : OperationWalker
{
public static readonly IndexerAccessArgumentVerifier Instance = new IndexerAccessArgumentVerifier();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册