提交 5888f4bc 编写于 作者: M Manish Vasani

Add IOperation support for string interpolation

Fixes #18300
上级 c375ded0
......@@ -164,11 +164,6 @@ internal partial class BoundDynamicObjectCreationExpression
protected override ImmutableArray<BoundNode> Children => StaticCast<BoundNode>.From(this.Arguments.AddRange(BoundObjectCreationExpression.GetChildInitializers(this.InitializerExpressionOpt)));
}
internal partial class BoundInterpolatedString
{
protected override ImmutableArray<BoundNode> Children => StaticCast<BoundNode>.From(this.Parts);
}
internal partial class BoundNoPiaObjectCreationExpression
{
protected override ImmutableArray<BoundNode> Children => StaticCast<BoundNode>.From(BoundObjectCreationExpression.GetChildInitializers(this.InitializerExpressionOpt));
......@@ -179,11 +174,6 @@ internal partial class BoundObjectInitializerExpression
protected override ImmutableArray<BoundNode> Children => StaticCast<BoundNode>.From(this.Initializers);
}
internal partial class BoundStringInsert
{
protected override ImmutableArray<BoundNode> Children => ImmutableArray.Create<BoundNode>(this.Value, this.Alignment, this.Format);
}
partial class BoundThrowExpression
{
protected override ImmutableArray<BoundNode> Children => ImmutableArray.Create<BoundNode>(this.Expression);
......
......@@ -6,6 +6,7 @@
using System.Linq;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis.CSharp;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Semantics
{
......@@ -165,6 +166,10 @@ private static IOperation CreateInternal(BoundNode boundNode)
return CreateBoundLabeledStatementOperation((BoundLabeledStatement)boundNode);
case BoundKind.ExpressionStatement:
return CreateBoundExpressionStatementOperation((BoundExpressionStatement)boundNode);
case BoundKind.InterpolatedString:
return CreateBoundInterpolatedStringExpressionOperation((BoundInterpolatedString)boundNode);
case BoundKind.StringInsert:
throw ExceptionUtilities.UnexpectedValue(boundNode.Kind);
default:
var constantValue = ConvertToOptional((boundNode as BoundExpression)?.ConstantValue);
return Operation.CreateOperationNone(boundNode.HasErrors, boundNode.Syntax, constantValue, getChildren: () => GetIOperationChildren(boundNode));
......@@ -985,5 +990,62 @@ private static IExpressionStatement CreateBoundExpressionStatementOperation(Boun
Optional<object> constantValue = default(Optional<object>);
return new LazyExpressionStatement(expression, isInvalid, syntax, type, constantValue);
}
private static IInterpolatedStringExpression CreateBoundInterpolatedStringExpressionOperation(BoundInterpolatedString boundInterpolatedString)
{
Lazy<ImmutableArray<IInterpolatedStringContent>> parts = new Lazy<ImmutableArray<IInterpolatedStringContent>>(() => GetInterpolatedStringExpressionParts(boundInterpolatedString));
bool isInvalid = boundInterpolatedString.HasErrors;
SyntaxNode syntax = boundInterpolatedString.Syntax;
ITypeSymbol type = boundInterpolatedString.Type;
Optional<object> constantValue = ConvertToOptional(boundInterpolatedString.ConstantValue);
return new LazyInterpolatedStringExpression(parts, isInvalid, syntax, type, constantValue);
}
private static IInterpolatedStringContent CreateBoundInterpolatedStringContentOperation(BoundNode boundNode)
{
if (boundNode == null)
{
return null;
}
return (IInterpolatedStringContent)s_cache.GetValue(boundNode, n => CreateBoundInterpolatedStringContentCore(n));
}
private static IInterpolatedStringContent CreateBoundInterpolatedStringContentCore(BoundNode boundInterpolatedStringContent)
{
switch (boundInterpolatedStringContent.Kind)
{
case BoundKind.StringInsert:
return CreateBoundInterpolationOperation((BoundStringInsert)boundInterpolatedStringContent);
case BoundKind.Literal:
return CreateBoundInterpolatedStringTextOperation((BoundLiteral)boundInterpolatedStringContent);
default:
throw ExceptionUtilities.UnexpectedValue(boundInterpolatedStringContent.Kind);
}
}
private static IInterpolation CreateBoundInterpolationOperation(BoundStringInsert boundStringInsert)
{
Lazy<IOperation> expression = new Lazy<IOperation>(() => Create(boundStringInsert.Value));
Lazy<IOperation> alignment = new Lazy<IOperation>(() => Create(boundStringInsert.Alignment));
Lazy<IOperation> format = new Lazy<IOperation>(() => Create(boundStringInsert.Format));
bool isInvalid = boundStringInsert.HasErrors;
SyntaxNode syntax = boundStringInsert.Syntax;
ITypeSymbol type = null;
Optional<object> constantValue = default(Optional<object>);
return new LazyInterpolation(expression, alignment, format, isInvalid, syntax, type, constantValue);
}
private static IInterpolatedStringText CreateBoundInterpolatedStringTextOperation(BoundLiteral boundLiteral)
{
Lazy<IOperation> text = new Lazy<IOperation>(() => CreateInternal(boundLiteral));
bool isInvalid = boundLiteral.HasErrors;
SyntaxNode syntax = boundLiteral.Syntax;
ITypeSymbol type = null;
Optional<object> constantValue = default(Optional<object>);
return new LazyInterpolatedStringText(text, isInvalid, syntax, type, constantValue);
}
}
}
......@@ -340,6 +340,16 @@ private static ImmutableArray<IVariableDeclaration> GetVariableDeclarationStatem
OperationFactory.CreateVariableDeclaration(declaration.LocalSymbol, Create(declaration.InitializerOpt), declaration.Syntax)));
}
private static readonly ConditionalWeakTable<BoundInterpolatedString, object> s_interpolatedStringExpressionMappings =
new ConditionalWeakTable<BoundInterpolatedString, object>();
private static ImmutableArray<IInterpolatedStringContent> GetInterpolatedStringExpressionParts(BoundInterpolatedString boundInterpolatedString)
{
return (ImmutableArray<IInterpolatedStringContent>)s_interpolatedStringExpressionMappings.GetValue(boundInterpolatedString,
interpolatedString =>
interpolatedString.Parts.SelectAsArray(interpolatedStringContent => CreateBoundInterpolatedStringContentOperation(interpolatedStringContent)));
}
// TODO: We need to reuse the logic in `LocalRewriter.MakeArguments` instead of using private implementation.
// Also. this implementation here was for the (now removed) API `ArgumentsInParameter`, which doesn't fulfill
// the contract of `ArgumentsInEvaluationOrder` plus it doesn't handle various scenarios correctly even for parameter order,
......
......@@ -61,6 +61,7 @@
<Compile Include="Diagnostics\DiagnosticAnalyzerTests.AllInOne.cs" />
<Compile Include="Diagnostics\DiagnosticAnalyzerTests.cs" />
<Compile Include="Diagnostics\GetDiagnosticsTests.cs" />
<Compile Include="IOperation\IOperationTests_IInterpolatedStringExpression.cs" />
<Compile Include="IOperation\IOperationTests_IArgument.cs" />
<Compile Include="IOperation\IOperationTests_IIfStatement.cs" />
<Compile Include="IOperation\IOperationTests_IFieldReferenceExpression.cs" />
......
......@@ -333,8 +333,7 @@ private void M()
/*<bind>*/if (int.TryParse(s, out var i))
System.Console.WriteLine($""i ={i}, s ={s}"");
else
System.Console.WriteLine($""i ={ i}, s ={s}"");/*</bind>*/
System.Console.WriteLine($""i ={i}, s ={s}"");/*</bind>*/
}
}
";
......@@ -348,23 +347,27 @@ private void M()
IfTrue: IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'System.Cons ... , s ={s}"");')
IInvocationExpression (static void System.Console.WriteLine(System.String value)) (OperationKind.InvocationExpression, Type: System.Void) (Syntax: 'System.Cons ... }, s ={s}"")')
Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument) (Syntax: '$""i ={i}, s ={s}""')
IOperation: (OperationKind.None) (Syntax: '$""i ={i}, s ={s}""')
Children(4): ILiteralExpression (Text: i =) (OperationKind.LiteralExpression, Type: System.String, Constant: ""i ="") (Syntax: 'i =')
IOperation: (OperationKind.None) (Syntax: '{i}')
Children(1): ILocalReferenceExpression: i (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'i')
ILiteralExpression (Text: , s =) (OperationKind.LiteralExpression, Type: System.String, Constant: "", s ="") (Syntax: ', s =')
IOperation: (OperationKind.None) (Syntax: '{s}')
Children(1): ILocalReferenceExpression: s (OperationKind.LocalReferenceExpression, Type: System.String) (Syntax: 's')
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$""i ={i}, s ={s}""')
Parts(4): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'i =')
Text: ILiteralExpression (Text: i =) (OperationKind.LiteralExpression, Type: System.String, Constant: ""i ="") (Syntax: 'i =')
IInterpolation (OperationKind.Interpolation) (Syntax: '{i}')
Expression: ILocalReferenceExpression: i (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'i')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ', s =')
Text: ILiteralExpression (Text: , s =) (OperationKind.LiteralExpression, Type: System.String, Constant: "", s ="") (Syntax: ', s =')
IInterpolation (OperationKind.Interpolation) (Syntax: '{s}')
Expression: ILocalReferenceExpression: s (OperationKind.LocalReferenceExpression, Type: System.String) (Syntax: 's')
IfFalse: IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'System.Cons ... , s ={s}"");')
IInvocationExpression (static void System.Console.WriteLine(System.String value)) (OperationKind.InvocationExpression, Type: System.Void) (Syntax: 'System.Cons ... }, s ={s}"")')
Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument) (Syntax: '$""i ={ i}, s ={s}""')
IOperation: (OperationKind.None) (Syntax: '$""i ={ i}, s ={s}""')
Children(4): ILiteralExpression (Text: i =) (OperationKind.LiteralExpression, Type: System.String, Constant: ""i ="") (Syntax: 'i =')
IOperation: (OperationKind.None) (Syntax: '{ i}')
Children(1): ILocalReferenceExpression: i (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'i')
ILiteralExpression (Text: , s =) (OperationKind.LiteralExpression, Type: System.String, Constant: "", s ="") (Syntax: ', s =')
IOperation: (OperationKind.None) (Syntax: '{s}')
Children(1): ILocalReferenceExpression: s (OperationKind.LocalReferenceExpression, Type: System.String) (Syntax: 's')
Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument) (Syntax: '$""i ={i}, s ={s}""')
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$""i ={i}, s ={s}""')
Parts(4): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'i =')
Text: ILiteralExpression (Text: i =) (OperationKind.LiteralExpression, Type: System.String, Constant: ""i ="") (Syntax: 'i =')
IInterpolation (OperationKind.Interpolation) (Syntax: '{i}')
Expression: ILocalReferenceExpression: i (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'i')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ', s =')
Text: ILiteralExpression (Text: , s =) (OperationKind.LiteralExpression, Type: System.String, Constant: "", s ="") (Syntax: ', s =')
IInterpolation (OperationKind.Interpolation) (Syntax: '{s}')
Expression: ILocalReferenceExpression: s (OperationKind.LocalReferenceExpression, Type: System.String) (Syntax: 's')
";
var expectedDiagnostics = DiagnosticDescription.None;
......
// 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.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public partial class IOperationTests : SemanticModelTestBase
{
[Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")]
public void InterpolatedStringExpression_Empty()
{
string source = @"
using System;
internal class Class
{
public void M()
{
Console.WriteLine(/*<bind>*/$""""/*</bind>*/);
}
}
";
string expectedOperationTree = @"
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$""""')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<InterpolatedStringExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")]
public void InterpolatedStringExpression_OnlyTextPart()
{
string source = @"
using System;
internal class Class
{
public void M()
{
Console.WriteLine(/*<bind>*/$""Only text part""/*</bind>*/);
}
}
";
string expectedOperationTree = @"
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$""Only text part""')
Parts(1): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'Only text part')
Text: ILiteralExpression (Text: Only text part) (OperationKind.LiteralExpression, Type: System.String, Constant: ""Only text part"") (Syntax: 'Only text part')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<InterpolatedStringExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")]
public void InterpolatedStringExpression_OnlyInterpolationPart()
{
string source = @"
using System;
internal class Class
{
public void M()
{
Console.WriteLine(/*<bind>*/$""{1}""/*</bind>*/);
}
}
";
string expectedOperationTree = @"
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$""{1}""')
Parts(1): IInterpolation (OperationKind.Interpolation) (Syntax: '{1}')
Expression: ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<InterpolatedStringExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")]
public void InterpolatedStringExpression_TextAndInterpolationParts()
{
string source = @"
using System;
internal class Class
{
public void M(int x)
{
Console.WriteLine(/*<bind>*/$""String {x} and constant {1}""/*</bind>*/);
}
}
";
string expectedOperationTree = @"
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$""String {x ... nstant {1}""')
Parts(4): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'String ')
Text: ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: ""String "") (Syntax: 'String ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{x}')
Expression: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and constant ')
Text: ILiteralExpression (Text: and constant ) (OperationKind.LiteralExpression, Type: System.String, Constant: "" and constant "") (Syntax: ' and constant ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{1}')
Expression: ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<InterpolatedStringExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")]
public void InterpolatedStringExpression_FormatAndAlignment()
{
string source = @"
using System;
internal class Class
{
private string x = string.Empty;
private int y = 0;
public void M()
{
Console.WriteLine(/*<bind>*/$""String {x,20} and {y:D3} and constant {1}""/*</bind>*/);
}
}
";
string expectedOperationTree = @"
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$""String {x ... nstant {1}""')
Parts(6): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'String ')
Text: ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: ""String "") (Syntax: 'String ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{x,20}')
Expression: IFieldReferenceExpression: System.String Class.x (OperationKind.FieldReferenceExpression, Type: System.String) (Syntax: 'x')
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: Class) (Syntax: 'x')
Alignment: ILiteralExpression (Text: 20) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 20) (Syntax: '20')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and ')
Text: ILiteralExpression (Text: and ) (OperationKind.LiteralExpression, Type: System.String, Constant: "" and "") (Syntax: ' and ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{y:D3}')
Expression: IFieldReferenceExpression: System.Int32 Class.y (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'y')
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: Class) (Syntax: 'y')
FormatString: ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: ""D3"") (Syntax: ':D3')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and constant ')
Text: ILiteralExpression (Text: and constant ) (OperationKind.LiteralExpression, Type: System.String, Constant: "" and constant "") (Syntax: ' and constant ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{1}')
Expression: ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<InterpolatedStringExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")]
public void InterpolatedStringExpression_InvocationInInterpolation()
{
string source = @"
using System;
internal class Class
{
public void M()
{
string x = string.Empty;
int y = 0;
Console.WriteLine(/*<bind>*/$""String {x} and {M2(y)} and constant {1}""/*</bind>*/);
}
private string M2(int z) => z.ToString();
}
";
string expectedOperationTree = @"
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$""String {x ... nstant {1}""')
Parts(6): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'String ')
Text: ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: ""String "") (Syntax: 'String ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{x}')
Expression: ILocalReferenceExpression: x (OperationKind.LocalReferenceExpression, Type: System.String) (Syntax: 'x')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and ')
Text: ILiteralExpression (Text: and ) (OperationKind.LiteralExpression, Type: System.String, Constant: "" and "") (Syntax: ' and ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{M2(y)}')
Expression: IInvocationExpression ( System.String Class.M2(System.Int32 z)) (OperationKind.InvocationExpression, Type: System.String) (Syntax: 'M2(y)')
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: Class) (Syntax: 'M2')
Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: z) (OperationKind.Argument) (Syntax: 'y')
ILocalReferenceExpression: y (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'y')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and constant ')
Text: ILiteralExpression (Text: and constant ) (OperationKind.LiteralExpression, Type: System.String, Constant: "" and constant "") (Syntax: ' and constant ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{1}')
Expression: ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<InterpolatedStringExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")]
public void InterpolatedStringExpression_NestedInterpolation()
{
string source = @"
using System;
internal class Class
{
public void M()
{
string x = string.Empty;
int y = 0;
Console.WriteLine(/*<bind>*/$""String {M2($""{y}"")}""/*</bind>*/);
}
private int M2(string z) => Int32.Parse(z);
}
";
string expectedOperationTree = @"
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$""String {M2($""{y}"")}""')
Parts(2): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'String ')
Text: ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: ""String "") (Syntax: 'String ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{M2($""{y}"")}')
Expression: IInvocationExpression ( System.Int32 Class.M2(System.String z)) (OperationKind.InvocationExpression, Type: System.Int32) (Syntax: 'M2($""{y}"")')
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: Class) (Syntax: 'M2')
Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: z) (OperationKind.Argument) (Syntax: '$""{y}""')
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$""{y}""')
Parts(1): IInterpolation (OperationKind.Interpolation) (Syntax: '{y}')
Expression: ILocalReferenceExpression: y (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'y')
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<InterpolatedStringExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")]
public void InterpolatedStringExpression_InvalidExpressionInInterpolation()
{
string source = @"
using System;
internal class Class
{
public void M(int x)
{
Console.WriteLine(/*<bind>*/$""String {x1} and constant {Class}""/*</bind>*/);
}
}
";
string expectedOperationTree = @"
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String, IsInvalid) (Syntax: '$""String {x ... nt {Class}""')
Parts(4): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'String ')
Text: ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: ""String "") (Syntax: 'String ')
IInterpolation (OperationKind.Interpolation, IsInvalid) (Syntax: '{x1}')
Expression: IInvalidExpression (OperationKind.InvalidExpression, Type: ?, IsInvalid) (Syntax: 'x1')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and constant ')
Text: ILiteralExpression (Text: and constant ) (OperationKind.LiteralExpression, Type: System.String, Constant: "" and constant "") (Syntax: ' and constant ')
IInterpolation (OperationKind.Interpolation, IsInvalid) (Syntax: '{Class}')
Expression: IInvalidExpression (OperationKind.InvalidExpression, Type: Class, IsInvalid) (Syntax: 'Class')
Children(1): IOperation: (OperationKind.None) (Syntax: 'Class')
";
var expectedDiagnostics = new DiagnosticDescription[] {
// CS0103: The name 'x1' does not exist in the current context
// Console.WriteLine(/*<bind>*/$"String {x1} and constant {Class}"/*</bind>*/);
Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(8, 47),
// CS0119: 'Class' is a type, which is not valid in the given context
// Console.WriteLine(/*<bind>*/$"String {x1} and constant {Class}"/*</bind>*/);
Diagnostic(ErrorCode.ERR_BadSKunknown, "Class").WithArguments("Class", "type").WithLocation(8, 65)
};
VerifyOperationTreeAndDiagnosticsForTest<InterpolatedStringExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
}
}
\ No newline at end of file
......@@ -588,23 +588,26 @@ internal class Class
{
public void M(string x, int y)
{
Console.WriteLine(/*<bind>*/$""String {x, 20} and {y:D3} and constant {1}""/*</bind>*/);
Console.WriteLine(/*<bind>*/$""String {x,20} and {y:D3} and constant {1}""/*</bind>*/);
}
}
";
string expectedOperationTree = @"
IOperation: (OperationKind.None) (Syntax: '$""String {x ... nstant {1}""')
Children(6): ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: ""String "") (Syntax: 'String ')
IOperation: (OperationKind.None) (Syntax: '{x, 20}')
Children(2): IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.String) (Syntax: 'x')
ILiteralExpression (Text: 20) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 20) (Syntax: '20')
ILiteralExpression (Text: and ) (OperationKind.LiteralExpression, Type: System.String, Constant: "" and "") (Syntax: ' and ')
IOperation: (OperationKind.None) (Syntax: '{y:D3}')
Children(2): IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'y')
ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: ""D3"") (Syntax: ':D3')
ILiteralExpression (Text: and constant ) (OperationKind.LiteralExpression, Type: System.String, Constant: "" and constant "") (Syntax: ' and constant ')
IOperation: (OperationKind.None) (Syntax: '{1}')
Children(1): ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$""String {x ... nstant {1}""')
Parts(6): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'String ')
Text: ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: ""String "") (Syntax: 'String ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{x,20}')
Expression: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.String) (Syntax: 'x')
Alignment: ILiteralExpression (Text: 20) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 20) (Syntax: '20')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and ')
Text: ILiteralExpression (Text: and ) (OperationKind.LiteralExpression, Type: System.String, Constant: "" and "") (Syntax: ' and ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{y:D3}')
Expression: IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'y')
FormatString: ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: ""D3"") (Syntax: ':D3')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and constant ')
Text: ILiteralExpression (Text: and constant ) (OperationKind.LiteralExpression, Type: System.String, Constant: "" and constant "") (Syntax: ' and constant ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{1}')
Expression: ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
";
var expectedDiagnostics = DiagnosticDescription.None;
......
......@@ -54,6 +54,10 @@
<Compile Include="Operations\IBranchStatement.cs" />
<Compile Include="Operations\ICaseClause.cs" />
<Compile Include="Operations\ICatchClause.cs" />
<Compile Include="Operations\IInterpolatedStringText.cs" />
<Compile Include="Operations\IInterpolation.cs" />
<Compile Include="Operations\IInterpolatedStringContent.cs" />
<Compile Include="Operations\IInterpolatedStringExpression.cs" />
<Compile Include="Operations\ICompoundAssignmentExpression.cs" />
<Compile Include="Operations\IConditionalAccessExpression.cs" />
<Compile Include="Operations\IConditionalAccessInstanceExpression.cs" />
......@@ -96,7 +100,7 @@
<Compile Include="Operations\IOmittedArgumentExpression.cs" />
<Compile Include="Operations\IOperationWithChildren.cs" />
<Compile Include="Operations\Operation.cs" />
<Compile Include="Operations\IOperationKind.cs" />
<Compile Include="Operations\OperationKind.cs" />
<Compile Include="Operations\IParameterInitializer.cs" />
<Compile Include="Operations\IParameterReferenceExpression.cs" />
<Compile Include="Operations\IParenthesizedExpression.cs" />
......
......@@ -2003,6 +2003,205 @@ public override void Accept(OperationVisitor visitor)
}
}
/// <remarks>
/// Represents an interpolated string expression.
/// </remarks>
internal abstract partial class BaseInterpolatedStringExpression : Operation, IInterpolatedStringExpression
{
protected BaseInterpolatedStringExpression(bool isInvalid, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue) :
base(OperationKind.InterpolatedStringExpression, isInvalid, syntax, type, constantValue)
{
}
/// <summary>
/// Constituent parts of interpolated string, each of which is an <see cref="IInterpolatedStringContent"/>.
/// </summary>
public abstract ImmutableArray<IInterpolatedStringContent> Parts { get; }
public override void Accept(OperationVisitor visitor)
{
visitor.VisitInterpolatedStringExpression(this);
}
public override TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument)
{
return visitor.VisitInterpolatedStringExpression(this, argument);
}
}
/// <remarks>
/// Represents an interpolated string expression.
/// </remarks>
internal sealed partial class InterpolatedStringExpression : BaseInterpolatedStringExpression, IInterpolatedStringExpression
{
public InterpolatedStringExpression(ImmutableArray<IInterpolatedStringContent> parts, bool isInvalid, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue) :
base(isInvalid, syntax, type, constantValue)
{
Parts = parts;
}
/// <summary>
/// Constituent parts of interpolated string, each of which is an <see cref="IInterpolatedStringContent"/>.
/// </summary>
public override ImmutableArray<IInterpolatedStringContent> Parts { get; }
}
/// <remarks>
/// Represents an interpolated string expression.
/// </remarks>
internal sealed partial class LazyInterpolatedStringExpression : BaseInterpolatedStringExpression, IInterpolatedStringExpression
{
private readonly Lazy<ImmutableArray<IInterpolatedStringContent>> _lazyParts;
public LazyInterpolatedStringExpression(Lazy<ImmutableArray<IInterpolatedStringContent>> parts, bool isInvalid, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue) : base(isInvalid, syntax, type, constantValue)
{
_lazyParts = parts;
}
/// <summary>
/// Constituent parts of interpolated string, each of which is an <see cref="IInterpolatedStringContent"/>.
/// </summary>
public override ImmutableArray<IInterpolatedStringContent> Parts => _lazyParts.Value;
}
/// <remarks>
/// Represents a constituent string literal part of an interpolated string expression.
/// </remarks>
internal abstract partial class BaseInterpolatedStringText : Operation, IInterpolatedStringText
{
protected BaseInterpolatedStringText(bool isInvalid, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue) :
base(OperationKind.InterpolatedStringText, isInvalid, syntax, type, constantValue)
{
}
/// <summary>
/// Text content.
/// </summary>
public abstract IOperation Text { get; }
public override void Accept(OperationVisitor visitor)
{
visitor.VisitInterpolatedStringText(this);
}
public override TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument)
{
return visitor.VisitInterpolatedStringText(this, argument);
}
}
/// <remarks>
/// Represents a constituent string literal part of an interpolated string expression.
/// </remarks>
internal sealed partial class InterpolatedStringText : BaseInterpolatedStringText, IInterpolatedStringText
{
public InterpolatedStringText(IOperation text, bool isInvalid, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue) :
base(isInvalid, syntax, type, constantValue)
{
Text = text;
}
/// <summary>
/// Text content.
/// </summary>
public override IOperation Text { get; }
}
/// <remarks>
/// Represents a constituent string literal part of an interpolated string expression.
/// </remarks>
internal sealed partial class LazyInterpolatedStringText : BaseInterpolatedStringText, IInterpolatedStringText
{
private readonly Lazy<IOperation> _lazyText;
public LazyInterpolatedStringText(Lazy<IOperation> text, bool isInvalid, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue) : base(isInvalid, syntax, type, constantValue)
{
_lazyText = text;
}
/// <summary>
/// Text content.
/// </summary>
public override IOperation Text => _lazyText.Value;
}
/// <remarks>
/// Represents a constituent interpolation part of an interpolated string expression.
/// </remarks>
internal abstract partial class BaseInterpolation : Operation, IInterpolation
{
protected BaseInterpolation(bool isInvalid, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue) :
base(OperationKind.Interpolation, isInvalid, syntax, type, constantValue)
{
}
/// <summary>
/// Expression of the interpolation.
/// </summary>
public abstract IOperation Expression { get; }
/// <summary>
/// Optional alignment of the interpolation.
/// </summary>
public abstract IOperation Alignment { get; }
/// <summary>
/// Optional format string of the interpolation.
/// </summary>
public abstract IOperation FormatString { get; }
public override void Accept(OperationVisitor visitor)
{
visitor.VisitInterpolation(this);
}
public override TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument)
{
return visitor.VisitInterpolation(this, argument);
}
}
/// <remarks>
/// Represents a constituent interpolation part of an interpolated string expression.
/// </remarks>
internal sealed partial class Interpolation : BaseInterpolation, IInterpolation
{
public Interpolation(IOperation expression, IOperation alignment, IOperation formatString, bool isInvalid, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue) :
base(isInvalid, syntax, type, constantValue)
{
Expression = expression;
Alignment = alignment;
FormatString = formatString;
}
/// <summary>
/// Expression of the interpolation.
/// </summary>
public override IOperation Expression { get; }
/// <summary>
/// Optional alignment of the interpolation.
/// </summary>
public override IOperation Alignment { get; }
/// <summary>
/// Optional format string of the interpolation.
/// </summary>
public override IOperation FormatString { get; }
}
/// <remarks>
/// Represents a constituent interpolation part of an interpolated string expression.
/// </remarks>
internal sealed partial class LazyInterpolation : BaseInterpolation, IInterpolation
{
private readonly Lazy<IOperation> _lazyExpression;
private readonly Lazy<IOperation> _lazyAlignment;
private readonly Lazy<IOperation> _lazyFormatString;
public LazyInterpolation(Lazy<IOperation> expression, Lazy<IOperation> alignment, Lazy<IOperation> formatString, bool isInvalid, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue) :
base(isInvalid, syntax, type, constantValue)
{
_lazyExpression = expression;
_lazyAlignment = alignment;
_lazyFormatString = formatString;
}
/// <summary>
/// Expression of the interpolation.
/// </summary>
public override IOperation Expression => _lazyExpression.Value;
/// <summary>
/// Optional alignment of the interpolation.
/// </summary>
public override IOperation Alignment => _lazyAlignment.Value;
/// <summary>
/// Optional format string of the interpolation.
/// </summary>
public override IOperation FormatString => _lazyFormatString.Value;
}
/// <remarks>
/// This interface is reserved for implementation by its associated APIs. We reserve the right to
/// change it in the future.
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Semantics
{
/// <summary>
/// Represents a constituent part of an interpolated string.
/// </summary>
/// <remarks>
/// This interface is reserved for implementation by its associated APIs. We reserve the right to
/// change it in the future.
/// </remarks>
public interface IInterpolatedStringContent : IOperation
{
}
}
// 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.Immutable;
namespace Microsoft.CodeAnalysis.Semantics
{
/// <summary>
/// Represents an interpolated string expression.
/// </summary>
/// <remarks>
/// This interface is reserved for implementation by its associated APIs. We reserve the right to
/// change it in the future.
/// </remarks>
public interface IInterpolatedStringExpression : IOperation
{
/// <summary>
/// Constituent parts of interpolated string, each of which is an <see cref="IInterpolatedStringContent"/>.
/// </summary>
ImmutableArray<IInterpolatedStringContent> Parts { get; }
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Semantics
{
/// <summary>
/// Represents a constituent string literal part of an interpolated string expression.
/// </summary>
/// <remarks>
/// This interface is reserved for implementation by its associated APIs. We reserve the right to
/// change it in the future.
/// </remarks>
public interface IInterpolatedStringText : IInterpolatedStringContent
{
/// <summary>
/// Text content.
/// </summary>
IOperation Text { get; }
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Semantics
{
/// <summary>
/// Represents a constituent interpolation part of an interpolated string expression.
/// </summary>
/// <remarks>
/// This interface is reserved for implementation by its associated APIs. We reserve the right to
/// change it in the future.
/// </remarks>
public interface IInterpolation : IInterpolatedStringContent
{
/// <summary>
/// Expression of the interpolation.
/// </summary>
IOperation Expression { get; }
/// <summary>
/// Optional alignment of the interpolation.
/// </summary>
IOperation Alignment { get; }
/// <summary>
/// Optional format string of the interpolation.
/// </summary>
IOperation FormatString { get; }
}
}
......@@ -126,7 +126,9 @@ public enum OperationKind
ConditionalAccessExpression = 0x11c,
/// <summary>Indicates an <see cref="IConditionalAccessInstanceExpression"/>.</summary>
ConditionalAccessInstanceExpression = 0x11d,
/// <summary>Indicates an <see cref="IInterpolatedStringExpression"/>.</summary>
InterpolatedStringExpression = 0x11e,
// Expressions that occur only in C#.
/// <summary>Indicates an <see cref="IDefaultValueExpression"/>.</summary>
......@@ -185,5 +187,10 @@ public enum OperationKind
RelationalCaseClause = 0x40b,
/// <summary>Indicates an <see cref="IRangeCaseClause"/>.</summary>
RangeCaseClause = 0x40c,
/// <summary>Indicates an <see cref="IInterpolatedStringText"/>.</summary>
InterpolatedStringText = 0x40d,
/// <summary>Indicates an <see cref="IInterpolation"/>.</summary>
Interpolation = 0x40e,
}
}
......@@ -394,6 +394,21 @@ public virtual void VisitLocalFunctionStatement(IOperation operation)
{
DefaultVisit(operation);
}
public virtual void VisitInterpolatedStringExpression(IInterpolatedStringExpression operation)
{
DefaultVisit(operation);
}
public virtual void VisitInterpolatedStringText(IInterpolatedStringText operation)
{
DefaultVisit(operation);
}
public virtual void VisitInterpolation(IInterpolation operation)
{
DefaultVisit(operation);
}
}
/// <summary>
......@@ -794,5 +809,20 @@ public virtual TResult VisitLocalFunctionStatement(IOperation operation, TArgume
{
return DefaultVisit(operation, argument);
}
public virtual TResult VisitInterpolatedStringExpression(IInterpolatedStringExpression operation, TArgument argument)
{
return DefaultVisit(operation, argument);
}
public virtual TResult VisitInterpolatedStringText(IInterpolatedStringText operation, TArgument argument)
{
return DefaultVisit(operation, argument);
}
public virtual TResult VisitInterpolation(IInterpolation operation, TArgument argument)
{
return DefaultVisit(operation, argument);
}
}
}
......@@ -420,5 +420,22 @@ public override void VisitInvalidExpression(IInvalidExpression operation)
{
VisitArray(operation.Children);
}
public override void VisitInterpolatedStringExpression(IInterpolatedStringExpression operation)
{
VisitArray(operation.Parts);
}
public override void VisitInterpolatedStringText(IInterpolatedStringText operation)
{
Visit(operation.Text);
}
public override void VisitInterpolation(IInterpolation operation)
{
Visit(operation.Expression);
Visit(operation.Alignment);
Visit(operation.FormatString);
}
}
}
......@@ -80,6 +80,9 @@ Microsoft.CodeAnalysis.OperationKind.IfStatement = 5 -> Microsoft.CodeAnalysis.O
Microsoft.CodeAnalysis.OperationKind.IncrementExpression = 518 -> Microsoft.CodeAnalysis.OperationKind
Microsoft.CodeAnalysis.OperationKind.IndexedPropertyReferenceExpression = 267 -> Microsoft.CodeAnalysis.OperationKind
Microsoft.CodeAnalysis.OperationKind.InstanceReferenceExpression = 277 -> Microsoft.CodeAnalysis.OperationKind
Microsoft.CodeAnalysis.OperationKind.InterpolatedStringExpression = 286 -> Microsoft.CodeAnalysis.OperationKind
Microsoft.CodeAnalysis.OperationKind.InterpolatedStringText = 1037 -> Microsoft.CodeAnalysis.OperationKind
Microsoft.CodeAnalysis.OperationKind.Interpolation = 1038 -> Microsoft.CodeAnalysis.OperationKind
Microsoft.CodeAnalysis.OperationKind.InvalidExpression = 256 -> Microsoft.CodeAnalysis.OperationKind
Microsoft.CodeAnalysis.OperationKind.InvalidStatement = 1 -> Microsoft.CodeAnalysis.OperationKind
Microsoft.CodeAnalysis.OperationKind.InvocationExpression = 259 -> Microsoft.CodeAnalysis.OperationKind
......@@ -417,6 +420,15 @@ Microsoft.CodeAnalysis.Semantics.IIncrementExpression.IncrementOperationKind.get
Microsoft.CodeAnalysis.Semantics.IIndexedPropertyReferenceExpression
Microsoft.CodeAnalysis.Semantics.IInstanceReferenceExpression
Microsoft.CodeAnalysis.Semantics.IInstanceReferenceExpression.InstanceReferenceKind.get -> Microsoft.CodeAnalysis.Semantics.InstanceReferenceKind
Microsoft.CodeAnalysis.Semantics.IInterpolatedStringContent
Microsoft.CodeAnalysis.Semantics.IInterpolatedStringExpression
Microsoft.CodeAnalysis.Semantics.IInterpolatedStringExpression.Parts.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Semantics.IInterpolatedStringContent>
Microsoft.CodeAnalysis.Semantics.IInterpolatedStringText
Microsoft.CodeAnalysis.Semantics.IInterpolatedStringText.Text.get -> Microsoft.CodeAnalysis.IOperation
Microsoft.CodeAnalysis.Semantics.IInterpolation
Microsoft.CodeAnalysis.Semantics.IInterpolation.Alignment.get -> Microsoft.CodeAnalysis.IOperation
Microsoft.CodeAnalysis.Semantics.IInterpolation.Expression.get -> Microsoft.CodeAnalysis.IOperation
Microsoft.CodeAnalysis.Semantics.IInterpolation.FormatString.get -> Microsoft.CodeAnalysis.IOperation
Microsoft.CodeAnalysis.Semantics.IInvalidExpression
Microsoft.CodeAnalysis.Semantics.IInvalidExpression.Children.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.IOperation>
Microsoft.CodeAnalysis.Semantics.IInvalidStatement
......@@ -697,6 +709,9 @@ override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitIfStatement(Micro
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitIncrementExpression(Microsoft.CodeAnalysis.Semantics.IIncrementExpression operation) -> void
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitIndexedPropertyReferenceExpression(Microsoft.CodeAnalysis.Semantics.IIndexedPropertyReferenceExpression operation) -> void
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitInstanceReferenceExpression(Microsoft.CodeAnalysis.Semantics.IInstanceReferenceExpression operation) -> void
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitInterpolatedStringExpression(Microsoft.CodeAnalysis.Semantics.IInterpolatedStringExpression operation) -> void
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitInterpolatedStringText(Microsoft.CodeAnalysis.Semantics.IInterpolatedStringText operation) -> void
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitInterpolation(Microsoft.CodeAnalysis.Semantics.IInterpolation operation) -> void
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitInvalidExpression(Microsoft.CodeAnalysis.Semantics.IInvalidExpression operation) -> void
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitInvalidStatement(Microsoft.CodeAnalysis.Semantics.IInvalidStatement operation) -> void
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitInvocationExpression(Microsoft.CodeAnalysis.Semantics.IInvocationExpression operation) -> void
......@@ -795,6 +810,9 @@ virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor.VisitIfStatement(Micro
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor.VisitIncrementExpression(Microsoft.CodeAnalysis.Semantics.IIncrementExpression operation) -> void
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor.VisitIndexedPropertyReferenceExpression(Microsoft.CodeAnalysis.Semantics.IIndexedPropertyReferenceExpression operation) -> void
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor.VisitInstanceReferenceExpression(Microsoft.CodeAnalysis.Semantics.IInstanceReferenceExpression operation) -> void
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor.VisitInterpolatedStringExpression(Microsoft.CodeAnalysis.Semantics.IInterpolatedStringExpression operation) -> void
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor.VisitInterpolatedStringText(Microsoft.CodeAnalysis.Semantics.IInterpolatedStringText operation) -> void
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor.VisitInterpolation(Microsoft.CodeAnalysis.Semantics.IInterpolation operation) -> void
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor.VisitInvalidExpression(Microsoft.CodeAnalysis.Semantics.IInvalidExpression operation) -> void
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor.VisitInvalidStatement(Microsoft.CodeAnalysis.Semantics.IInvalidStatement operation) -> void
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor.VisitInvocationExpression(Microsoft.CodeAnalysis.Semantics.IInvocationExpression operation) -> void
......@@ -871,6 +889,9 @@ virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor<TArgument, TResult>.Vi
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor<TArgument, TResult>.VisitIncrementExpression(Microsoft.CodeAnalysis.Semantics.IIncrementExpression operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor<TArgument, TResult>.VisitIndexedPropertyReferenceExpression(Microsoft.CodeAnalysis.Semantics.IIndexedPropertyReferenceExpression operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor<TArgument, TResult>.VisitInstanceReferenceExpression(Microsoft.CodeAnalysis.Semantics.IInstanceReferenceExpression operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor<TArgument, TResult>.VisitInterpolatedStringExpression(Microsoft.CodeAnalysis.Semantics.IInterpolatedStringExpression operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor<TArgument, TResult>.VisitInterpolatedStringText(Microsoft.CodeAnalysis.Semantics.IInterpolatedStringText operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor<TArgument, TResult>.VisitInterpolation(Microsoft.CodeAnalysis.Semantics.IInterpolation operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor<TArgument, TResult>.VisitInvalidExpression(Microsoft.CodeAnalysis.Semantics.IInvalidExpression operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor<TArgument, TResult>.VisitInvalidStatement(Microsoft.CodeAnalysis.Semantics.IInvalidStatement operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Semantics.OperationVisitor<TArgument, TResult>.VisitInvocationExpression(Microsoft.CodeAnalysis.Semantics.IInvocationExpression operation, TArgument argument) -> TResult
......
......@@ -199,27 +199,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Property
End Class
Friend Partial Class BoundNameOfOperator
Partial Friend Class BoundNameOfOperator
Protected Overrides ReadOnly Property Children As ImmutableArray(Of BoundNode)
Get
Return ImmutableArray.Create(Of BoundNode)(Me.Argument)
End Get
End Property
End Class
Friend Partial Class BoundInterpolatedStringExpression
Protected Overrides ReadOnly Property Children As ImmutableArray(Of BoundNode)
Get
Return Me.Contents
End Get
End Property
End Class
Friend Partial Class BoundInterpolation
Protected Overrides ReadOnly Property Children As ImmutableArray(Of BoundNode)
Get
Return ImmutableArray.Create(Of BoundNode)(Me.Expression, Me.AlignmentOpt, Me.FormatStringOpt)
End Get
End Property
End Class
End Namespace
......@@ -161,6 +161,10 @@ Namespace Microsoft.CodeAnalysis.Semantics
Return CreateBoundAddHandlerStatementOperation(DirectCast(boundNode, BoundAddHandlerStatement))
Case BoundKind.RemoveHandlerStatement
Return CreateBoundRemoveHandlerStatementOperation(DirectCast(boundNode, BoundRemoveHandlerStatement))
Case BoundKind.InterpolatedStringExpression
Return CreateBoundInterpolatedStringExpressionOperation(DirectCast(boundNode, BoundInterpolatedStringExpression))
Case BoundKind.Interpolation
Throw ExceptionUtilities.UnexpectedValue(boundNode.Kind)
Case Else
Dim constantValue = ConvertToOptional(TryCast(boundNode, BoundExpression)?.ConstantValueOpt)
Return Operation.CreateOperationNone(boundNode.HasErrors, boundNode.Syntax, constantValue, Function() GetIOperationChildren(boundNode))
......@@ -1016,6 +1020,56 @@ Namespace Microsoft.CodeAnalysis.Semantics
Dim constantValue As [Optional](Of Object) = New [Optional](Of Object)()
Return New LazyExpressionStatement(expression, isInvalid, syntax, type, constantValue)
End Function
Private Shared Function CreateBoundInterpolatedStringExpressionOperation(boundInterpolatedString As BoundInterpolatedStringExpression) As IInterpolatedStringExpression
Dim parts As New Lazy(Of ImmutableArray(Of IInterpolatedStringContent))(Function() GetInterpolatedStringExpressionParts(boundInterpolatedString))
Dim isInvalid As Boolean = boundInterpolatedString.HasErrors
Dim syntax As SyntaxNode = boundInterpolatedString.Syntax
Dim type As ITypeSymbol = boundInterpolatedString.Type
Dim constantValue As [Optional](Of Object) = ConvertToOptional(boundInterpolatedString.ConstantValueOpt)
Return New LazyInterpolatedStringExpression(parts, isInvalid, syntax, type, constantValue)
End Function
Private Shared Function CreateBoundInterpolatedStringContentOperation(boundNode As BoundNode) As IInterpolatedStringContent
If boundNode Is Nothing Then
Return Nothing
End If
Return DirectCast(s_cache.GetValue(boundNode, Function(n) CreateBoundInterpolatedStringContentOperationCore(n)), IInterpolatedStringContent)
End Function
Private Shared Function CreateBoundInterpolatedStringContentOperationCore(boundInterpolatedStringContent As BoundNode) As IInterpolatedStringContent
Select Case boundInterpolatedStringContent.Kind
Case BoundKind.Interpolation
Return CreateBoundInterpolationOperation(DirectCast(boundInterpolatedStringContent, BoundInterpolation))
Case BoundKind.Literal
Return CreateBoundInterpolatedStringTextOperation(DirectCast(boundInterpolatedStringContent, BoundLiteral))
Case Else
Throw ExceptionUtilities.UnexpectedValue(boundInterpolatedStringContent.Kind)
End Select
End Function
Private Shared Function CreateBoundInterpolationOperation(boundInterpolation As BoundInterpolation) As IInterpolation
Dim expression As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(boundInterpolation.Expression))
Dim alignment As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(boundInterpolation.AlignmentOpt))
Dim format As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(boundInterpolation.FormatStringOpt))
Dim isInvalid As Boolean = boundInterpolation.HasErrors
Dim syntax As SyntaxNode = boundInterpolation.Syntax
Dim type As ITypeSymbol = Nothing
Dim constantValue As [Optional](Of Object) = Nothing
Return New LazyInterpolation(expression, alignment, format, isInvalid, syntax, type, constantValue)
End Function
Private Shared Function CreateBoundInterpolatedStringTextOperation(boundLiteral As BoundLiteral) As IInterpolatedStringText
Dim text As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() CreateInternal(boundLiteral))
Dim isInvalid As Boolean = boundLiteral.HasErrors
Dim syntax As SyntaxNode = boundLiteral.Syntax
Dim type As ITypeSymbol = Nothing
Dim constantValue As [Optional](Of Object) = Nothing
Return New LazyInterpolatedStringText(text, isInvalid, syntax, type, constantValue)
End Function
End Class
End Namespace
......
......@@ -489,6 +489,16 @@ Namespace Microsoft.CodeAnalysis.Semantics
End Function)
End Function
Private Shared ReadOnly s_interpolatedStringExpressionMappings As New ConditionalWeakTable(Of BoundInterpolatedStringExpression, Object)()
Private Shared Function GetInterpolatedStringExpressionParts(boundInterpolatedString As BoundInterpolatedStringExpression) As ImmutableArray(Of IInterpolatedStringContent)
Return DirectCast(s_interpolatedStringExpressionMappings.GetValue(
boundInterpolatedString,
Function(interpolatedString)
Return interpolatedString.Contents.SelectAsArray(Function(interpolatedStringContent) CreateBoundInterpolatedStringContentOperation(interpolatedStringContent))
End Function), ImmutableArray(Of IInterpolatedStringContent))
End Function
Friend Class Helper
Friend Shared Function DeriveUnaryOperationKind(operatorKind As UnaryOperatorKind) As UnaryOperationKind
Select Case operatorKind And UnaryOperatorKind.OpMask
......
......@@ -110,6 +110,7 @@
<Compile Include="IOperation\IOperationTests_IArgument.vb" />
<Compile Include="IOperation\IOperationTests_IFieldReferenceExpression.vb" />
<Compile Include="IOperation\IOperationTests_IObjectCreationExpression.vb" />
<Compile Include="IOperation\IOperationTests_IInterpolatedStringExpression.vb" />
<Compile Include="IOperation\IOperationTests_IParameterReferenceExpression.vb" />
<Compile Include="IOperation\IOperationTests_InvalidStatement.vb" />
<Compile Include="IOperation\IOperationTests_InvalidExpression.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, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")>
Public Sub InterpolatedStringExpression_Empty()
Dim source = <![CDATA[
Imports System
Friend Class [Class]
Public Sub M()
Console.WriteLine($"")'BIND:"$"""
End Sub
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$""')
]]>.Value
Dim expectedDiagnostics = String.Empty
VerifyOperationTreeAndDiagnosticsForTest(Of InterpolatedStringExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
<Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")>
Public Sub InterpolatedStringExpression_OnlyTextPart()
Dim source = <![CDATA[
Imports System
Friend Class [Class]
Public Sub M()
Console.WriteLine($"Only text part")'BIND:"$"Only text part""
End Sub
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$"Only text part"')
Parts(1): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'Only text part')
Text: ILiteralExpression (Text: Only text part) (OperationKind.LiteralExpression, Type: System.String, Constant: "Only text part") (Syntax: 'Only text part')
]]>.Value
Dim expectedDiagnostics = String.Empty
VerifyOperationTreeAndDiagnosticsForTest(Of InterpolatedStringExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
<Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")>
Public Sub InterpolatedStringExpression_OnlyInterpolationPart()
Dim source = <![CDATA[
Imports System
Friend Class [Class]
Public Sub M()
Console.WriteLine($"{1}")'BIND:"$"{1}""
End Sub
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$"{1}"')
Parts(1): IInterpolation (OperationKind.Interpolation) (Syntax: '{1}')
Expression: ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
]]>.Value
Dim expectedDiagnostics = String.Empty
VerifyOperationTreeAndDiagnosticsForTest(Of InterpolatedStringExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
<Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")>
Public Sub InterpolatedStringExpression_TextAndInterpolationParts()
Dim source = <![CDATA[
Imports System
Friend Class [Class]
Public Sub M(x As Integer)
Console.WriteLine($"String {x} and constant {1}")'BIND:"$"String {x} and constant {1}""
End Sub
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$"String {x ... nstant {1}"')
Parts(4): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'String ')
Text: ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: "String ") (Syntax: 'String ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{x}')
Expression: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and constant ')
Text: ILiteralExpression (Text: and constant ) (OperationKind.LiteralExpression, Type: System.String, Constant: " and constant ") (Syntax: ' and constant ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{1}')
Expression: ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
]]>.Value
Dim expectedDiagnostics = String.Empty
VerifyOperationTreeAndDiagnosticsForTest(Of InterpolatedStringExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
<Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")>
Public Sub InterpolatedStringExpression_FormatAndAlignment()
Dim source = <![CDATA[
Imports System
Friend Class [Class]
Private x As String = String.Empty
Private y As Integer = 0
Public Sub M()
Console.WriteLine($"String {x,20} and {y:D3} and constant {1}")'BIND:"$"String {x,20} and {y:D3} and constant {1}""
End Sub
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$"String {x ... nstant {1}"')
Parts(6): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'String ')
Text: ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: "String ") (Syntax: 'String ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{x,20}')
Expression: IFieldReferenceExpression: [Class].x As System.String (OperationKind.FieldReferenceExpression, Type: System.String) (Syntax: 'x')
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: [Class]) (Syntax: 'x')
Alignment: ILiteralExpression (Text: 20) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 20) (Syntax: '20')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and ')
Text: ILiteralExpression (Text: and ) (OperationKind.LiteralExpression, Type: System.String, Constant: " and ") (Syntax: ' and ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{y:D3}')
Expression: IFieldReferenceExpression: [Class].y As System.Int32 (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'y')
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: [Class]) (Syntax: 'y')
FormatString: ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: "D3") (Syntax: ':D3')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and constant ')
Text: ILiteralExpression (Text: and constant ) (OperationKind.LiteralExpression, Type: System.String, Constant: " and constant ") (Syntax: ' and constant ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{1}')
Expression: ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
]]>.Value
Dim expectedDiagnostics = String.Empty
VerifyOperationTreeAndDiagnosticsForTest(Of InterpolatedStringExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
<Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")>
Public Sub InterpolatedStringExpression_InvocationInInterpolation()
Dim source = <![CDATA[
Imports System
Friend Class [Class]
Public Sub M()
Dim x As String = String.Empty
Dim y As Integer = 0
Console.WriteLine($"String {x} and {M2(y)} and constant {1}")'BIND:"$"String {x} and {M2(y)} and constant {1}""
End Sub
Private Function M2(z As Integer) As String
Return z.ToString()
End Function
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$"String {x ... nstant {1}"')
Parts(6): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'String ')
Text: ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: "String ") (Syntax: 'String ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{x}')
Expression: ILocalReferenceExpression: x (OperationKind.LocalReferenceExpression, Type: System.String) (Syntax: 'x')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and ')
Text: ILiteralExpression (Text: and ) (OperationKind.LiteralExpression, Type: System.String, Constant: " and ") (Syntax: ' and ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{M2(y)}')
Expression: IInvocationExpression ( Function [Class].M2(z As System.Int32) As System.String) (OperationKind.InvocationExpression, Type: System.String) (Syntax: 'M2(y)')
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: [Class]) (Syntax: 'M2')
Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: z) (OperationKind.Argument) (Syntax: 'y')
ILocalReferenceExpression: y (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'y')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and constant ')
Text: ILiteralExpression (Text: and constant ) (OperationKind.LiteralExpression, Type: System.String, Constant: " and constant ") (Syntax: ' and constant ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{1}')
Expression: ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
]]>.Value
Dim expectedDiagnostics = String.Empty
VerifyOperationTreeAndDiagnosticsForTest(Of InterpolatedStringExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
<Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")>
Public Sub InterpolatedStringExpression_NestedInterpolation()
Dim source = <![CDATA[
Imports System
Friend Class [Class]
Public Sub M()
Dim x As String = String.Empty
Dim y As Integer = 0
Console.WriteLine($"String {M2($"{y}")}")'BIND:"$"String {M2($"{y}")}""
End Sub
Private Function M2(z As String) As Integer
Return Int32.Parse(z)
End Function
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$"String {M2($"{y}")}"')
Parts(2): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'String ')
Text: ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: "String ") (Syntax: 'String ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{M2($"{y}")}')
Expression: IInvocationExpression ( Function [Class].M2(z As System.String) As System.Int32) (OperationKind.InvocationExpression, Type: System.Int32) (Syntax: 'M2($"{y}")')
Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: [Class]) (Syntax: 'M2')
Arguments(1): IArgument (ArgumentKind.Explicit, Matching Parameter: z) (OperationKind.Argument) (Syntax: '$"{y}"')
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$"{y}"')
Parts(1): IInterpolation (OperationKind.Interpolation) (Syntax: '{y}')
Expression: ILocalReferenceExpression: y (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'y')
]]>.Value
Dim expectedDiagnostics = String.Empty
VerifyOperationTreeAndDiagnosticsForTest(Of InterpolatedStringExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
<Fact, WorkItem(18300, "https://github.com/dotnet/roslyn/issues/18300")>
Public Sub InterpolatedStringExpression_InvalidExpressionInInterpolation()
Dim source = <![CDATA[
Imports System
Friend Class [Class]
Public Sub M(x As Integer)
Console.WriteLine($"String {x1} and constant {[Class]}")'BIND:"$"String {x1} and constant {[Class]}""
End Sub
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String, IsInvalid) (Syntax: '$"String {x ... {[Class]}"')
Parts(4): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'String ')
Text: ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: "String ") (Syntax: 'String ')
IInterpolation (OperationKind.Interpolation, IsInvalid) (Syntax: '{x1}')
Expression: IInvalidExpression (OperationKind.InvalidExpression, Type: ?, IsInvalid) (Syntax: 'x1')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and constant ')
Text: ILiteralExpression (Text: and constant ) (OperationKind.LiteralExpression, Type: System.String, Constant: " and constant ") (Syntax: ' and constant ')
IInterpolation (OperationKind.Interpolation, IsInvalid) (Syntax: '{[Class]}')
Expression: IOperation: (OperationKind.None, IsInvalid) (Syntax: '[Class]')
]]>.Value
Dim expectedDiagnostics = <![CDATA[
BC30451: 'x1' is not declared. It may be inaccessible due to its protection level.
Console.WriteLine($"String {x1} and constant {[Class]}")'BIND:"$"String {x1} and constant {[Class]}""
~~
BC30109: '[Class]' is a class type and cannot be used as an expression.
Console.WriteLine($"String {x1} and constant {[Class]}")'BIND:"$"String {x1} and constant {[Class]}""
~~~~~~~
]]>.Value
VerifyOperationTreeAndDiagnosticsForTest(Of InterpolatedStringExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub
End Class
End Namespace
......@@ -469,18 +469,21 @@ Friend Class [Class]
End Class]]>.Value
Dim expectedOperationTree = <![CDATA[
IOperation: (OperationKind.None) (Syntax: '$"String {x ... nstant {1}"')
Children(6): ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: "String ") (Syntax: 'String ')
IOperation: (OperationKind.None) (Syntax: '{x,20}')
Children(2): IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.String) (Syntax: 'x')
ILiteralExpression (Text: 20) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 20) (Syntax: '20')
ILiteralExpression (Text: and ) (OperationKind.LiteralExpression, Type: System.String, Constant: " and ") (Syntax: ' and ')
IOperation: (OperationKind.None) (Syntax: '{y:D3}')
Children(2): IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'y')
ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: "D3") (Syntax: ':D3')
ILiteralExpression (Text: and constant ) (OperationKind.LiteralExpression, Type: System.String, Constant: " and constant ") (Syntax: ' and constant ')
IOperation: (OperationKind.None) (Syntax: '{1}')
Children(1): ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
IInterpolatedStringExpression (OperationKind.InterpolatedStringExpression, Type: System.String) (Syntax: '$"String {x ... nstant {1}"')
Parts(6): IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: 'String ')
Text: ILiteralExpression (Text: String ) (OperationKind.LiteralExpression, Type: System.String, Constant: "String ") (Syntax: 'String ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{x,20}')
Expression: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.String) (Syntax: 'x')
Alignment: ILiteralExpression (Text: 20) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 20) (Syntax: '20')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and ')
Text: ILiteralExpression (Text: and ) (OperationKind.LiteralExpression, Type: System.String, Constant: " and ") (Syntax: ' and ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{y:D3}')
Expression: IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'y')
FormatString: ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: "D3") (Syntax: ':D3')
IInterpolatedStringText (OperationKind.InterpolatedStringText) (Syntax: ' and constant ')
Text: ILiteralExpression (Text: and constant ) (OperationKind.LiteralExpression, Type: System.String, Constant: " and constant ") (Syntax: ' and constant ')
IInterpolation (OperationKind.Interpolation) (Syntax: '{1}')
Expression: ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1')
]]>.Value
Dim expectedDiagnostics = String.Empty
......
......@@ -1100,6 +1100,32 @@ public override void VisitRangeCaseClause(IRangeCaseClause operation)
Visit(operation.MaximumValue, "Max");
}
public override void VisitInterpolatedStringExpression(IInterpolatedStringExpression operation)
{
LogString(nameof(IInterpolatedStringExpression));
LogCommonPropertiesAndNewLine(operation);
VisitArray(operation.Parts, "Parts", logElementCount: true);
}
public override void VisitInterpolatedStringText(IInterpolatedStringText operation)
{
LogString(nameof(IInterpolatedStringText));
LogCommonPropertiesAndNewLine(operation);
Visit(operation.Text, "Text");
}
public override void VisitInterpolation(IInterpolation operation)
{
LogString(nameof(IInterpolation));
LogCommonPropertiesAndNewLine(operation);
Visit(operation.Expression, "Expression");
Visit(operation.Alignment, "Alignment");
Visit(operation.FormatString, "FormatString");
}
#endregion
}
}
\ No newline at end of file
......@@ -512,5 +512,20 @@ public override void VisitInvalidExpression(IInvalidExpression operation)
{
base.VisitInvalidExpression(operation);
}
public override void VisitInterpolatedStringExpression(IInterpolatedStringExpression operation)
{
base.VisitInterpolatedStringExpression(operation);
}
public override void VisitInterpolatedStringText(IInterpolatedStringText operation)
{
base.VisitInterpolatedStringText(operation);
}
public override void VisitInterpolation(IInterpolation operation)
{
base.VisitInterpolation(operation);
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册