From 2933883b0041a987310594b56f2f73f2fadc3263 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 7 Dec 2015 14:43:22 -0800 Subject: [PATCH] Add support for generating operators in SyntaxGenerator. --- .../CodeGeneration/CSharpSyntaxGenerator.cs | 62 ++++++++ .../CodeGeneration/SyntaxGeneratorTests.cs | 118 +++++++++++++++ .../Core/Portable/Editing/OperatorKind.cs | 143 ++++++++++++++++++ .../Core/Portable/Editing/SyntaxGenerator.cs | 70 +++++++++ .../Core/Portable/PublicAPI.Unshipped.txt | 29 ++++ .../Core/Portable/Workspaces.csproj | 1 + .../VisualBasicSyntaxGenerator.vb | 94 +++++++++++- .../CodeGeneration/SyntaxGeneratorTests.vb | 128 ++++++++++++++++ 8 files changed, 643 insertions(+), 2 deletions(-) create mode 100644 src/Workspaces/Core/Portable/Editing/OperatorKind.cs diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs index 23ee5486b69..81c5f111b7e 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs @@ -149,6 +149,68 @@ private SyntaxTokenList GetParameterModifiers(RefKind refKind) !hasBody ? SyntaxFactory.Token(SyntaxKind.SemicolonToken) : default(SyntaxToken)); } + public override SyntaxNode OperatorDeclaration(OperatorKind kind, IEnumerable parameters = null, SyntaxNode returnType = null, Accessibility accessibility = Accessibility.NotApplicable, DeclarationModifiers modifiers = default(DeclarationModifiers), IEnumerable statements = null) + { + var hasBody = !modifiers.IsAbstract && (!modifiers.IsPartial || statements != null); + var returnTypeNode = returnType != null ? (TypeSyntax)returnType : SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)); + var parameterList = AsParameterList(parameters); + var body = hasBody ? CreateBlock(statements) : null; + var semicolon = !hasBody ? SyntaxFactory.Token(SyntaxKind.SemicolonToken) : default(SyntaxToken); + var modifierList = AsModifierList(accessibility, modifiers, SyntaxKind.OperatorDeclaration); + var attributes = default(SyntaxList); + + if (kind == OperatorKind.ImplicitConversion || kind == OperatorKind.ExplicitConversion) + { + return SyntaxFactory.ConversionOperatorDeclaration( + attributes, modifierList, SyntaxFactory.Token(GetTokenKind(kind)), + SyntaxFactory.Token(SyntaxKind.OperatorKeyword), + returnTypeNode, parameterList, body, semicolon); + } + else + { + return SyntaxFactory.OperatorDeclaration( + attributes, modifierList, returnTypeNode, + SyntaxFactory.Token(SyntaxKind.OperatorKeyword), + SyntaxFactory.Token(GetTokenKind(kind)), + parameterList, body, semicolon); + } + } + + private SyntaxKind GetTokenKind(OperatorKind kind) + { + switch (kind) + { + case OperatorKind.ImplicitConversion: return SyntaxKind.ImplicitKeyword; + case OperatorKind.ExplicitConversion: return SyntaxKind.ExplicitKeyword; + case OperatorKind.Addition: return SyntaxKind.PlusToken; + case OperatorKind.BitwiseAnd: return SyntaxKind.AmpersandToken; + case OperatorKind.BitwiseOr:return SyntaxKind.BarToken; + case OperatorKind.Decrement: return SyntaxKind.MinusMinusToken; + case OperatorKind.Division: return SyntaxKind.SlashToken; + case OperatorKind.Equality: return SyntaxKind.EqualsEqualsToken; + case OperatorKind.ExclusiveOr: return SyntaxKind.CaretToken; + case OperatorKind.False: return SyntaxKind.FalseKeyword; + case OperatorKind.GreaterThan: return SyntaxKind.GreaterThanToken; + case OperatorKind.GreaterThanOrEqual: return SyntaxKind.GreaterThanEqualsToken; + case OperatorKind.Increment: return SyntaxKind.PlusPlusToken; + case OperatorKind.Inequality: return SyntaxKind.ExclamationEqualsToken; + case OperatorKind.LeftShift: return SyntaxKind.LessThanLessThanToken; + case OperatorKind.LessThan: return SyntaxKind.LessThanToken; + case OperatorKind.LessThanOrEqual: return SyntaxKind.LessThanEqualsToken; + case OperatorKind.LogicalNot: return SyntaxKind.ExclamationToken; + case OperatorKind.Modulus:return SyntaxKind.PercentToken; + case OperatorKind.Multiply:return SyntaxKind.AsteriskToken; + case OperatorKind.OnesComplement:return SyntaxKind.TildeToken; + case OperatorKind.RightShift:return SyntaxKind.GreaterThanGreaterThanToken; + case OperatorKind.Subtraction: return SyntaxKind.MinusToken; + case OperatorKind.True: return SyntaxKind.TrueKeyword; + case OperatorKind.UnaryNegation: return SyntaxKind.MinusToken; + case OperatorKind.UnaryPlus: return SyntaxKind.PlusToken; + default: + throw new ArgumentException("Unknown operator kind."); + } + } + private ParameterListSyntax AsParameterList(IEnumerable parameters) { return parameters != null diff --git a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs index 7cd7a7fd958..17bae14b093 100644 --- a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs +++ b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs @@ -724,6 +724,124 @@ public void TestMethodDeclarations() "partial void m()\r\n{\r\n y;\r\n}"); } + [Fact] + public void TestOperatorDeclaration() + { + var parameterTypes = new[] + { + _emptyCompilation.GetSpecialType(SpecialType.System_Int32), + _emptyCompilation.GetSpecialType(SpecialType.System_String) + }; + var parameters = parameterTypes.Select((t, i) => _g.ParameterDeclaration("p" + i, _g.TypeExpression(t))).ToList(); + var returnType = _g.TypeExpression(SpecialType.System_Boolean); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.Addition, parameters, returnType), + "bool operator +(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.BitwiseAnd, parameters, returnType), + "bool operator &(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.BitwiseOr, parameters, returnType), + "bool operator |(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.Decrement, parameters, returnType), + "bool operator --(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.Division, parameters, returnType), + "bool operator /(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.Equality, parameters, returnType), + "bool operator ==(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.ExclusiveOr, parameters, returnType), + "bool operator ^(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.False, parameters, returnType), + "bool operator false (System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.GreaterThan, parameters, returnType), + "bool operator>(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.GreaterThanOrEqual, parameters, returnType), + "bool operator >=(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.Increment, parameters, returnType), + "bool operator ++(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.Inequality, parameters, returnType), + "bool operator !=(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.LeftShift, parameters, returnType), + "bool operator <<(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.LessThan, parameters, returnType), + "bool operator <(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.LessThanOrEqual, parameters, returnType), + "bool operator <=(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.LogicalNot, parameters, returnType), + "bool operator !(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.Modulus, parameters, returnType), + "bool operator %(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.Multiply, parameters, returnType), + "bool operator *(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.OnesComplement, parameters, returnType), + "bool operator ~(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.RightShift, parameters, returnType), + "bool operator >>(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.Subtraction, parameters, returnType), + "bool operator -(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.True, parameters, returnType), + "bool operator true (System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.UnaryNegation, parameters, returnType), + "bool operator -(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.UnaryPlus, parameters, returnType), + "bool operator +(System.Int32 p0, System.String p1)\r\n{\r\n}"); + + // Conversion operators + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.ImplicitConversion, parameters, returnType), + "implicit operator bool (System.Int32 p0, System.String p1)\r\n{\r\n}"); + + VerifySyntax( + _g.OperatorDeclaration(OperatorKind.ExplicitConversion, parameters, returnType), + "explicit operator bool (System.Int32 p0, System.String p1)\r\n{\r\n}"); + } + [Fact] public void TestConstructorDeclaration() { diff --git a/src/Workspaces/Core/Portable/Editing/OperatorKind.cs b/src/Workspaces/Core/Portable/Editing/OperatorKind.cs new file mode 100644 index 00000000000..ec85b1b301c --- /dev/null +++ b/src/Workspaces/Core/Portable/Editing/OperatorKind.cs @@ -0,0 +1,143 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.Editing +{ + public enum OperatorKind + { + /// + /// The name assigned to an implicit (widening) conversion. + /// + ImplicitConversion, + + /// + /// The name assigned to an explicit (narrowing) conversion. + /// + ExplicitConversion, + + /// + /// The name assigned to the Addition operator. + /// + Addition, + + /// + /// The name assigned to the BitwiseAnd operator. + /// + BitwiseAnd, + + /// + /// The name assigned to the BitwiseOr operator. + /// + BitwiseOr, + + /// + /// The name assigned to the Decrement operator. + /// + Decrement, + + /// + /// The name assigned to the Division operator. + /// + Division, + + /// + /// The name assigned to the Equality operator. + /// + Equality, + + /// + /// The name assigned to the ExclusiveOr operator. + /// + ExclusiveOr, + + /// + /// The name assigned to the False operator. + /// + False, + + /// + /// The name assigned to the GreaterThan operator. + /// + GreaterThan, + + /// + /// The name assigned to the GreaterThanOrEqual operator. + /// + GreaterThanOrEqual, + + /// + /// The name assigned to the Increment operator. + /// + Increment, + + /// + /// The name assigned to the Inequality operator. + /// + Inequality, + + /// + /// The name assigned to the LeftShift operator. + /// + LeftShift, + + /// + /// The name assigned to the LessThan operator. + /// + LessThan, + + /// + /// The name assigned to the LessThanOrEqual operator. + /// + LessThanOrEqual, + + /// + /// The name assigned to the LogicalNot operator. + /// + LogicalNot, + + /// + /// The name assigned to the Modulus operator. + /// + Modulus, + + /// + /// The name assigned to the Multiply operator. + /// + Multiply, + + /// + /// The name assigned to the OnesComplement operator. + /// + OnesComplement, + + /// + /// The name assigned to the RightShift operator. + /// + RightShift, + + /// + /// The name assigned to the Subtraction operator. + /// + Subtraction, + + /// + /// The name assigned to the True operator. + /// + True, + + /// + /// The name assigned to the UnaryNegation operator. + /// + UnaryNegation, + + /// + /// The name assigned to the UnaryPlus operator. + /// + UnaryPlus, + } +} \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs index 457aa861692..5729e2bf07b 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs @@ -154,6 +154,73 @@ public SyntaxNode MethodDeclaration(IMethodSymbol method, IEnumerable + /// Creates a method declaration. + /// + public abstract SyntaxNode OperatorDeclaration( + OperatorKind kind, + IEnumerable parameters = null, + SyntaxNode returnType = null, + Accessibility accessibility = Accessibility.NotApplicable, + DeclarationModifiers modifiers = default(DeclarationModifiers), + IEnumerable statements = null); + + /// + /// Creates a method declaration matching an existing method symbol. + /// + public SyntaxNode OperatorDeclaration(IMethodSymbol method, IEnumerable statements = null) + { + if (method.MethodKind != MethodKind.UserDefinedOperator) + { + throw new ArgumentException("Method is not an operator."); + } + + var decl = OperatorDeclaration( + GetOperatorKind(method), + parameters: method.Parameters.Select(p => ParameterDeclaration(p)), + returnType: method.ReturnType.IsSystemVoid() ? null : TypeExpression(method.ReturnType), + accessibility: method.DeclaredAccessibility, + modifiers: DeclarationModifiers.From(method), + statements: statements); + + return decl; + } + + private OperatorKind GetOperatorKind(IMethodSymbol method) + { + switch (method.Name) + { + case WellKnownMemberNames.ImplicitConversionName: return OperatorKind.ImplicitConversion; + case WellKnownMemberNames.ExplicitConversionName: return OperatorKind.ExplicitConversion; + case WellKnownMemberNames.AdditionOperatorName: return OperatorKind.Addition; + case WellKnownMemberNames.BitwiseAndOperatorName: return OperatorKind.BitwiseAnd; + case WellKnownMemberNames.BitwiseOrOperatorName: return OperatorKind.BitwiseOr; + case WellKnownMemberNames.DecrementOperatorName: return OperatorKind.Decrement; + case WellKnownMemberNames.DivisionOperatorName: return OperatorKind.Division; + case WellKnownMemberNames.EqualityOperatorName: return OperatorKind.Equality; + case WellKnownMemberNames.ExclusiveOrOperatorName: return OperatorKind.ExclusiveOr; + case WellKnownMemberNames.FalseOperatorName: return OperatorKind.False; + case WellKnownMemberNames.GreaterThanOperatorName: return OperatorKind.GreaterThan; + case WellKnownMemberNames.GreaterThanOrEqualOperatorName: return OperatorKind.GreaterThanOrEqual; + case WellKnownMemberNames.IncrementOperatorName: return OperatorKind.Increment; + case WellKnownMemberNames.InequalityOperatorName: return OperatorKind.Inequality; + case WellKnownMemberNames.LeftShiftOperatorName: return OperatorKind.LeftShift; + case WellKnownMemberNames.LessThanOperatorName: return OperatorKind.LessThan; + case WellKnownMemberNames.LessThanOrEqualOperatorName: return OperatorKind.LessThanOrEqual; + case WellKnownMemberNames.LogicalNotOperatorName: return OperatorKind.LogicalNot; + case WellKnownMemberNames.ModulusOperatorName: return OperatorKind.Modulus; + case WellKnownMemberNames.MultiplyOperatorName: return OperatorKind.Multiply; + case WellKnownMemberNames.OnesComplementOperatorName: return OperatorKind.OnesComplement; + case WellKnownMemberNames.RightShiftOperatorName: return OperatorKind.RightShift; + case WellKnownMemberNames.SubtractionOperatorName: return OperatorKind.Subtraction; + case WellKnownMemberNames.TrueOperatorName: return OperatorKind.True; + case WellKnownMemberNames.UnaryNegationOperatorName: return OperatorKind.UnaryNegation; + case WellKnownMemberNames.UnaryPlusOperatorName: return OperatorKind.UnaryPlus; + default: + throw new ArgumentException("Unknown operator kind."); + } + } + /// /// Creates a parameter declaration. /// @@ -436,6 +503,9 @@ public SyntaxNode Declaration(ISymbol symbol) case MethodKind.Ordinary: return MethodDeclaration(method); + + case MethodKind.UserDefinedOperator: + return OperatorDeclaration(method); } break; diff --git a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt index ea0263980df..07e670006e6 100644 --- a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt @@ -1,7 +1,36 @@ +Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.Addition = 2 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.BitwiseAnd = 3 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.BitwiseOr = 4 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.Decrement = 5 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.Division = 6 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.Equality = 7 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.ExclusiveOr = 8 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.ExplicitConversion = 1 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.False = 9 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.GreaterThan = 10 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.GreaterThanOrEqual = 11 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.ImplicitConversion = 0 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.Increment = 12 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.Inequality = 13 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.LeftShift = 14 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.LessThan = 15 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.LessThanOrEqual = 16 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.LogicalNot = 17 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.Modulus = 18 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.Multiply = 19 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.OnesComplement = 20 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.RightShift = 21 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.Subtraction = 22 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.True = 23 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.UnaryNegation = 24 -> Microsoft.CodeAnalysis.Editing.OperatorKind +Microsoft.CodeAnalysis.Editing.OperatorKind.UnaryPlus = 25 -> Microsoft.CodeAnalysis.Editing.OperatorKind Microsoft.CodeAnalysis.Editing.SyntaxEditor.RemoveNode(Microsoft.CodeAnalysis.SyntaxNode node, Microsoft.CodeAnalysis.SyntaxRemoveOptions options) -> void +Microsoft.CodeAnalysis.Editing.SyntaxGenerator.OperatorDeclaration(Microsoft.CodeAnalysis.IMethodSymbol method, System.Collections.Generic.IEnumerable statements = null) -> Microsoft.CodeAnalysis.SyntaxNode Microsoft.CodeAnalysis.Project.IsSubmission.get -> bool Microsoft.CodeAnalysis.Workspace.UpdateReferencesAfterAdd() -> void abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ArrayCreationExpression(Microsoft.CodeAnalysis.SyntaxNode elementType, Microsoft.CodeAnalysis.SyntaxNode size) -> Microsoft.CodeAnalysis.SyntaxNode abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.ArrayCreationExpression(Microsoft.CodeAnalysis.SyntaxNode elementType, System.Collections.Generic.IEnumerable elements) -> Microsoft.CodeAnalysis.SyntaxNode +abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.OperatorDeclaration(Microsoft.CodeAnalysis.Editing.OperatorKind kind, System.Collections.Generic.IEnumerable parameters = null, Microsoft.CodeAnalysis.SyntaxNode returnType = null, Microsoft.CodeAnalysis.Accessibility accessibility = Microsoft.CodeAnalysis.Accessibility.NotApplicable, Microsoft.CodeAnalysis.Editing.DeclarationModifiers modifiers = default(Microsoft.CodeAnalysis.Editing.DeclarationModifiers), System.Collections.Generic.IEnumerable statements = null) -> Microsoft.CodeAnalysis.SyntaxNode static Microsoft.CodeAnalysis.Editing.SyntaxGenerator.GetGenerator(Microsoft.CodeAnalysis.Project project) -> Microsoft.CodeAnalysis.Editing.SyntaxGenerator virtual Microsoft.CodeAnalysis.Editing.SyntaxGenerator.RemoveNode(Microsoft.CodeAnalysis.SyntaxNode root, Microsoft.CodeAnalysis.SyntaxNode node, Microsoft.CodeAnalysis.SyntaxRemoveOptions options) -> Microsoft.CodeAnalysis.SyntaxNode \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/Workspaces.csproj b/src/Workspaces/Core/Portable/Workspaces.csproj index 9a6c3837a9a..f4086b7f51b 100644 --- a/src/Workspaces/Core/Portable/Workspaces.csproj +++ b/src/Workspaces/Core/Portable/Workspaces.csproj @@ -340,6 +340,7 @@ + diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb index 2bf9ed13de1..277935f28a1 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb @@ -652,6 +652,95 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End If End Function + Public Overrides Function OperatorDeclaration(kind As OperatorKind, + Optional parameters As IEnumerable(Of SyntaxNode) = Nothing, + Optional returnType As SyntaxNode = Nothing, + Optional accessibility As Accessibility = Accessibility.NotApplicable, + Optional modifiers As DeclarationModifiers = Nothing, + Optional statements As IEnumerable(Of SyntaxNode) = Nothing) As SyntaxNode + + Dim statement As OperatorStatementSyntax + Dim asClause = If(returnType IsNot Nothing, SyntaxFactory.SimpleAsClause(DirectCast(returnType, TypeSyntax)), Nothing) + Dim parameterList = GetParameterList(parameters) + Dim operatorToken = SyntaxFactory.Token(GetTokenKind(kind)) + Dim modifierList As SyntaxTokenList = GetModifierList(accessibility, modifiers And s_methodModifiers) + + If kind = OperatorKind.ImplicitConversion OrElse kind = OperatorKind.ExplicitConversion Then + modifierList = modifierList.Add(SyntaxFactory.Token( + If(kind = OperatorKind.ImplicitConversion, SyntaxKind.WideningKeyword, SyntaxKind.NarrowingKeyword))) + statement = SyntaxFactory.OperatorStatement( + attributeLists:=Nothing, modifiers:=modifierList, operatorToken:=operatorToken, + parameterList:=parameterList, asClause:=asClause) + Else + statement = SyntaxFactory.OperatorStatement( + attributeLists:=Nothing, modifiers:=modifierList, + operatorToken:=operatorToken, parameterList:=parameterList, + asClause:=asClause) + End If + + + If modifiers.IsAbstract Then + Return statement + Else + Return SyntaxFactory.OperatorBlock( + operatorStatement:=statement, + statements:=GetStatementList(statements), + endOperatorStatement:=SyntaxFactory.EndOperatorStatement()) + End If + End Function + + Private Function GetTokenKind(kind As OperatorKind) As SyntaxKind + Select Case kind + Case OperatorKind.ImplicitConversion, + OperatorKind.ExplicitConversion + Return SyntaxKind.CTypeKeyword + Case OperatorKind.Addition + Return SyntaxKind.PlusToken + Case OperatorKind.BitwiseAnd + Return SyntaxKind.AndKeyword + Case OperatorKind.BitwiseOr + Return SyntaxKind.OrKeyword + Case OperatorKind.Division + Return SyntaxKind.SlashToken + Case OperatorKind.Equality + Return SyntaxKind.EqualsToken + Case OperatorKind.ExclusiveOr + Return SyntaxKind.XorKeyword + Case OperatorKind.False + Return SyntaxKind.IsFalseKeyword + Case OperatorKind.GreaterThan + Return SyntaxKind.GreaterThanToken + Case OperatorKind.GreaterThanOrEqual + Return SyntaxKind.GreaterThanEqualsToken + Case OperatorKind.Inequality + Return SyntaxKind.LessThanGreaterThanToken + Case OperatorKind.LeftShift + Return SyntaxKind.LessThanLessThanToken + Case OperatorKind.LessThan + Return SyntaxKind.LessThanToken + Case OperatorKind.LessThanOrEqual + Return SyntaxKind.LessThanEqualsToken + Case OperatorKind.LogicalNot + Return SyntaxKind.NotKeyword + Case OperatorKind.Modulus + Return SyntaxKind.ModKeyword + Case OperatorKind.Multiply + Return SyntaxKind.AsteriskToken + Case OperatorKind.RightShift + Return SyntaxKind.GreaterThanGreaterThanToken + Case OperatorKind.Subtraction + Return SyntaxKind.MinusToken + Case OperatorKind.True + Return SyntaxKind.IsTrueKeyword + Case OperatorKind.UnaryNegation + Return SyntaxKind.MinusToken + Case OperatorKind.UnaryPlus + Return SyntaxKind.PlusToken + Case Else + Throw New ArgumentException($"Operator {kind} cannot be generated in Visual Basic.") + End Select + End Function + Private Function GetParameterList(parameters As IEnumerable(Of SyntaxNode)) As ParameterListSyntax Return If(parameters IsNot Nothing, SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters.Cast(Of ParameterSyntax)())), SyntaxFactory.ParameterList()) End Function @@ -3203,7 +3292,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration If accessor IsNot Nothing Then accessor = DirectCast(Me.WithStatements(accessor, statements), AccessorBlockSyntax) Return Me.WithAccessorBlock(declaration, kind, accessor) - ElseIf Me.CanHaveAccessors(declaration.Kind) + ElseIf Me.CanHaveAccessors(declaration.Kind) Then accessor = Me.AccessorBlock(kind, statements, Me.ClearTrivia(Me.GetType(declaration))) Return Me.WithAccessorBlock(declaration, kind, accessor) Else @@ -3226,7 +3315,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Dim currentAccessor = Me.GetAccessorBlock(declaration, kind) If currentAccessor IsNot Nothing Then Return Me.ReplaceNode(declaration, currentAccessor, accessor) - ElseIf accessor IsNot Nothing + ElseIf accessor IsNot Nothing Then + Select Case declaration.Kind Case SyntaxKind.PropertyBlock Dim pb = DirectCast(declaration, PropertyBlockSyntax) diff --git a/src/Workspaces/VisualBasicTest/CodeGeneration/SyntaxGeneratorTests.vb b/src/Workspaces/VisualBasicTest/CodeGeneration/SyntaxGeneratorTests.vb index 600690b479f..2b4593dbde4 100644 --- a/src/Workspaces/VisualBasicTest/CodeGeneration/SyntaxGeneratorTests.vb +++ b/src/Workspaces/VisualBasicTest/CodeGeneration/SyntaxGeneratorTests.vb @@ -812,6 +812,134 @@ End Function.Value) End Sub.Value) End Sub + + Public Sub TestOperatorDeclaration() + Dim parameterTypes = { + _emptyCompilation.GetSpecialType(SpecialType.System_Int32), + _emptyCompilation.GetSpecialType(SpecialType.System_String) + } + + Dim parameters = parameterTypes.Select(Function(t, i) _g.ParameterDeclaration("p" & i, _g.TypeExpression(t))).ToList() + Dim returnType = _g.TypeExpression(SpecialType.System_Boolean) + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.Addition, parameters, returnType), +"Operator +(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.BitwiseAnd, parameters, returnType), +"Operator And(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.BitwiseOr, parameters, returnType), +"Operator Or(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.Division, parameters, returnType), +"Operator /(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.Equality, parameters, returnType), +"Operator =(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.ExclusiveOr, parameters, returnType), +"Operator Xor(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.False, parameters, returnType), +"Operator IsFalse(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.GreaterThan, parameters, returnType), +"Operator>(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.GreaterThanOrEqual, parameters, returnType), +"Operator >=(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.Inequality, parameters, returnType), +"Operator <>(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.LeftShift, parameters, returnType), +"Operator <<(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.LessThan, parameters, returnType), +"Operator <(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.LessThanOrEqual, parameters, returnType), +"Operator <=(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.LogicalNot, parameters, returnType), +"Operator Not(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.Modulus, parameters, returnType), +"Operator Mod(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.Multiply, parameters, returnType), +"Operator *(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.RightShift, parameters, returnType), +"Operator >>(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.Subtraction, parameters, returnType), +"Operator -(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.True, parameters, returnType), +"Operator IsTrue(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.UnaryNegation, parameters, returnType), +"Operator -(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.UnaryPlus, parameters, returnType), +"Operator +(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + ' Conversion operators + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.ImplicitConversion, parameters, returnType), +"Widening Operator CType(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + + VerifySyntax(Of OperatorBlockSyntax)( + _g.OperatorDeclaration(OperatorKind.ExplicitConversion, parameters, returnType), +"Narrowing Operator CType(p0 As System.Int32, p1 As System.String) As Boolean +End Operator") + End Sub + Public Sub MethodDeclarationCanRoundTrip() Dim tree = VisualBasicSyntaxTree.ParseText( -- GitLab