From fc0a8f61f5bfda8befe0bf2a7ba7b7965ba34da2 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Wed, 24 Feb 2016 21:24:46 -0800 Subject: [PATCH] Add InvalidExpression concrete type Also fixes crash in `ArgumentBase.IsInvalid` property when code has error. --- .../CSharp/Portable/BoundTree/Expression.cs | 7 +++-- .../Diagnostics/OperationAnalyzerTests.cs | 30 +++++++++++++++++++ .../Diagnostics/OperationTestAnalyzer.cs | 17 ++++++++++- .../Core/Portable/Compilation/Expression.cs | 28 +++++++++++++++++ 4 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs index c02cbd83d61..ceadf5f1bf3 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis; @@ -141,7 +142,7 @@ private static IArgument DeriveArgument(int parameterIndex, int argumentIndex, I } // There is no supplied argument and there is no params parameter. Any action is suspect at this point. - return new SimpleArgument(null, null); + return new SimpleArgument(null, new InvalidExpression(invocationSyntax)); } return s_argumentMappings.GetValue( @@ -197,7 +198,7 @@ private static IOperation CreateParamArray(IParameterSymbol parameter, Immutable return new ArrayCreation(arrayType, paramArrayArguments, paramArrayArguments.Length > 0 ? paramArrayArguments[0].Syntax : invocationSyntax); } - return null; + return new InvalidExpression(invocationSyntax); } internal static IArgument ArgumentMatchingParameter(ImmutableArray arguments, ImmutableArray argumentsToParameters, ImmutableArray argumentNames, ImmutableArray argumentRefKinds, ISymbol targetMethod, ImmutableArray parameters, IParameterSymbol parameter, SyntaxNode invocationSyntax) @@ -232,6 +233,8 @@ private abstract class ArgumentBase : IArgument { public ArgumentBase(IParameterSymbol parameter, IOperation value) { + Debug.Assert(value != null); + this.Value = value; this.Parameter = parameter; } diff --git a/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs b/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs index 5c7971842ac..438f68d7f24 100644 --- a/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs @@ -1502,6 +1502,36 @@ public void Increment(string f) Diagnostic(InvalidOperatorExpressionTestAnalyzer.InvalidIncrementDescriptor.Id, "f++").WithLocation(16, 9)); } + [WorkItem(9114, "https://github.com/dotnet/roslyn/issues/9114")] + [Fact] + public void InvalidArgumentCSharp() + { + const string source = @" +public class A +{ + public static void Foo(params int a) {} + + public static int Main() + { + Foo(); + Foo(1); + return 1; + } +} +"; + CreateCompilationWithMscorlib45(source) + .VerifyDiagnostics( + // (4,28): error CS0225: The params parameter must be a single dimensional array + // public static void Foo(params int a) {} + Diagnostic(ErrorCode.ERR_ParamsMustBeArray, "params").WithLocation(4, 28), + // (8,9): error CS7036: There is no argument given that corresponds to the required formal parameter 'a' of 'A.Foo(params int)' + // Foo(); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "Foo").WithArguments("a", "A.Foo(params int)").WithLocation(8, 9)) + .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new InvocationTestAnalyzer() }, null, null, false, + Diagnostic(InvocationTestAnalyzer.InvalidArgumentDescriptor.Id, "Foo()").WithLocation(8, 9), + Diagnostic(InvocationTestAnalyzer.InvalidArgumentDescriptor.Id, "Foo(1)").WithLocation(9, 9)); + } + [Fact] public void ConditionalAccessOperationsCSharp() { diff --git a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/OperationTestAnalyzer.cs b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/OperationTestAnalyzer.cs index e540bf69800..d3d301d5388 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/OperationTestAnalyzer.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/OperationTestAnalyzer.cs @@ -493,6 +493,14 @@ public class InvocationTestAnalyzer : DiagnosticAnalyzer DiagnosticSeverity.Warning, isEnabledByDefault: true); + public static readonly DiagnosticDescriptor InvalidArgumentDescriptor = new DiagnosticDescriptor( + "InvalidArgument", + "Invalid argument", + "Invocation has invalid argument", + ReliabilityCategory, + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + /// Gets the set of supported diagnostic descriptors from this analyzer. public sealed override ImmutableArray SupportedDiagnostics { @@ -500,7 +508,8 @@ public sealed override ImmutableArray SupportedDiagnostics { return ImmutableArray.Create(BigParamArrayArgumentsDescriptor, OutOfNumericalOrderArgumentsDescriptor, - UseDefaultArgumentDescriptor); + UseDefaultArgumentDescriptor, + InvalidArgumentDescriptor); } } @@ -513,6 +522,12 @@ public sealed override void Initialize(AnalysisContext context) long priorArgumentValue = long.MinValue; foreach (IArgument argument in invocation.ArgumentsInParameterOrder) { + if (argument.IsInvalid) + { + operationContext.ReportDiagnostic(Diagnostic.Create(InvalidArgumentDescriptor, argument.Syntax.GetLocation())); + return; + } + if (argument.ArgumentKind == ArgumentKind.DefaultValue) { operationContext.ReportDiagnostic(Diagnostic.Create(UseDefaultArgumentDescriptor, invocation.Syntax.GetLocation(), argument.Parameter.Name)); diff --git a/src/Compilers/Core/Portable/Compilation/Expression.cs b/src/Compilers/Core/Portable/Compilation/Expression.cs index be313caf607..aef8d039510 100644 --- a/src/Compilers/Core/Portable/Compilation/Expression.cs +++ b/src/Compilers/Core/Portable/Compilation/Expression.cs @@ -450,4 +450,32 @@ public void Accept(OperationVisitor visitor) } } } + + internal sealed class InvalidExpression : IInvalidExpression + { + public InvalidExpression(SyntaxNode syntax) + { + this.Syntax = syntax; + } + + public Optional ConstantValue => default(Optional); + + public bool IsInvalid => true; + + public OperationKind Kind => OperationKind.InvalidExpression; + + public SyntaxNode Syntax { get; } + + public ITypeSymbol Type => null; + + public void Accept(OperationVisitor visitor) + { + visitor.VisitInvalidExpression(this); + } + + public TResult Accept(OperationVisitor visitor, TArgument argument) + { + return visitor.VisitInvalidExpression(this, argument); + } + } } -- GitLab