Skip to content

Commit 068c555

Browse files
Extract all xml expression logic to a partial file
1 parent bd97bd1 commit 068c555

2 files changed

Lines changed: 167 additions & 158 deletions

File tree

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
using System.Xml.Linq;
2+
using Microsoft.CodeAnalysis.CSharp;
3+
using Microsoft.CodeAnalysis.CSharp.Syntax;
4+
5+
namespace ICSharpCode.CodeConverter.CSharp;
6+
7+
internal partial class ExpressionNodeVisitor : VBasic.VisualBasicSyntaxVisitor<Task<CSharpSyntaxNode>>
8+
{
9+
private readonly XmlImportContext _xmlImportContext;
10+
11+
public override async Task<CSharpSyntaxNode> VisitXmlEmbeddedExpression(VBSyntax.XmlEmbeddedExpressionSyntax node) =>
12+
await node.Expression.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor);
13+
14+
public override async Task<CSharpSyntaxNode> VisitXmlDocument(VBasic.Syntax.XmlDocumentSyntax node)
15+
{
16+
_extraUsingDirectives.Add("System.Xml.Linq");
17+
var arguments = SyntaxFactory.SeparatedList(
18+
(await node.PrecedingMisc.SelectAsync(async misc => SyntaxFactory.Argument(await misc.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor))))
19+
.Concat(SyntaxFactory.Argument(await node.Root.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor)).Yield())
20+
.Concat(await node.FollowingMisc.SelectAsync(async misc => SyntaxFactory.Argument(await misc.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor))))
21+
);
22+
return ApplyXmlImportsIfNecessary(node, SyntaxFactory.ObjectCreationExpression(ValidSyntaxFactory.IdentifierName("XDocument")).WithArgumentList(SyntaxFactory.ArgumentList(arguments)));
23+
}
24+
25+
public override async Task<CSharpSyntaxNode> VisitXmlElement(VBasic.Syntax.XmlElementSyntax node)
26+
{
27+
_extraUsingDirectives.Add("System.Xml.Linq");
28+
var arguments = SyntaxFactory.SeparatedList(
29+
SyntaxFactory.Argument(await node.StartTag.Name.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor)).Yield()
30+
.Concat(await node.StartTag.Attributes.SelectAsync(async attribute => SyntaxFactory.Argument(await attribute.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor))))
31+
.Concat(await node.Content.SelectAsync(async content => SyntaxFactory.Argument(await content.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor))))
32+
);
33+
return ApplyXmlImportsIfNecessary(node, SyntaxFactory.ObjectCreationExpression(ValidSyntaxFactory.IdentifierName("XElement")).WithArgumentList(SyntaxFactory.ArgumentList(arguments)));
34+
}
35+
36+
public override async Task<CSharpSyntaxNode> VisitXmlEmptyElement(VBSyntax.XmlEmptyElementSyntax node)
37+
{
38+
_extraUsingDirectives.Add("System.Xml.Linq");
39+
var arguments = SyntaxFactory.SeparatedList(
40+
SyntaxFactory.Argument(await node.Name.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor)).Yield()
41+
.Concat(await node.Attributes.SelectAsync(async attribute => SyntaxFactory.Argument(await attribute.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor))))
42+
);
43+
return ApplyXmlImportsIfNecessary(node, SyntaxFactory.ObjectCreationExpression(ValidSyntaxFactory.IdentifierName("XElement")).WithArgumentList(SyntaxFactory.ArgumentList(arguments)));
44+
}
45+
46+
private CSharpSyntaxNode ApplyXmlImportsIfNecessary(VBSyntax.XmlNodeSyntax vbNode, ObjectCreationExpressionSyntax creation)
47+
{
48+
if (!_xmlImportContext.HasImports || vbNode.Parent is VBSyntax.XmlNodeSyntax) return creation;
49+
return SyntaxFactory.InvocationExpression(
50+
SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, XmlImportContext.HelperClassShortIdentifierName, ValidSyntaxFactory.IdentifierName("Apply")),
51+
SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(creation))));
52+
}
53+
54+
public override async Task<CSharpSyntaxNode> VisitXmlAttribute(VBasic.Syntax.XmlAttributeSyntax node)
55+
{
56+
var arguments = SyntaxFactory.SeparatedList(
57+
SyntaxFactory.Argument(await node.Name.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor)).Yield()
58+
.Concat(SyntaxFactory.Argument(await node.Value.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor)).Yield())
59+
);
60+
return SyntaxFactory.ObjectCreationExpression(ValidSyntaxFactory.IdentifierName("XAttribute")).WithArgumentList(SyntaxFactory.ArgumentList(arguments));
61+
}
62+
63+
public override async Task<CSharpSyntaxNode> VisitXmlString(VBasic.Syntax.XmlStringSyntax node) =>
64+
CommonConversions.Literal(string.Join("", node.TextTokens.Select(b => b.Text)));
65+
66+
public override async Task<CSharpSyntaxNode> VisitXmlText(VBSyntax.XmlTextSyntax node) =>
67+
CommonConversions.Literal(string.Join("", node.TextTokens.Select(b => b.Text)));
68+
69+
public override async Task<CSharpSyntaxNode> VisitXmlCDataSection(VBSyntax.XmlCDataSectionSyntax node)
70+
{
71+
var xcDataTypeSyntax = SyntaxFactory.ParseTypeName(nameof(XCData));
72+
var argumentListSyntax = CommonConversions.Literal(string.Join("", node.TextTokens.Select(b => b.Text))).Yield().CreateCsArgList();
73+
return SyntaxFactory.ObjectCreationExpression(xcDataTypeSyntax).WithArgumentList(argumentListSyntax);
74+
}
75+
76+
/// <summary>
77+
/// https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/xml/accessing-xml
78+
/// </summary>
79+
public override async Task<CSharpSyntaxNode> VisitXmlMemberAccessExpression(
80+
VBasic.Syntax.XmlMemberAccessExpressionSyntax node)
81+
{
82+
_extraUsingDirectives.Add("System.Xml.Linq");
83+
84+
var xElementMethodName = GetXElementMethodName(node);
85+
86+
ExpressionSyntax elements = node.Base != null
87+
? SyntaxFactory.MemberAccessExpression(
88+
SyntaxKind.SimpleMemberAccessExpression,
89+
await node.Base.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor),
90+
ValidSyntaxFactory.IdentifierName(xElementMethodName)
91+
)
92+
: SyntaxFactory.MemberBindingExpression(
93+
ValidSyntaxFactory.IdentifierName(xElementMethodName)
94+
);
95+
96+
return SyntaxFactory.InvocationExpression(elements,
97+
ExpressionSyntaxExtensions.CreateArgList(
98+
await node.Name.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor))
99+
);
100+
}
101+
102+
private static string GetXElementMethodName(VBSyntax.XmlMemberAccessExpressionSyntax node)
103+
{
104+
if (node.Token2 == default(SyntaxToken)) {
105+
return "Elements";
106+
}
107+
108+
if (node.Token2.Text == "@") {
109+
return "Attributes";
110+
}
111+
112+
if (node.Token2.Text == ".") {
113+
return "Descendants";
114+
}
115+
116+
throw new NotImplementedException($"Xml member access operator: '{node.Token1}{node.Token2}{node.Token3}'");
117+
}
118+
119+
public override Task<CSharpSyntaxNode> VisitXmlBracketedName(VBSyntax.XmlBracketedNameSyntax node)
120+
{
121+
return node.Name.AcceptAsync<CSharpSyntaxNode>(TriviaConvertingExpressionVisitor);
122+
}
123+
124+
public override async Task<CSharpSyntaxNode> VisitXmlName(VBSyntax.XmlNameSyntax node)
125+
{
126+
if (node.Prefix != null) {
127+
switch (node.Prefix.Name.ValueText) {
128+
case "xml":
129+
case "xmlns":
130+
return SyntaxFactory.BinaryExpression(
131+
SyntaxKind.AddExpression,
132+
SyntaxFactory.MemberAccessExpression(
133+
SyntaxKind.SimpleMemberAccessExpression,
134+
ValidSyntaxFactory.IdentifierName("XNamespace"),
135+
ValidSyntaxFactory.IdentifierName(node.Prefix.Name.ValueText.ToPascalCase())
136+
),
137+
SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(node.LocalName.Text))
138+
);
139+
default:
140+
return SyntaxFactory.BinaryExpression(
141+
SyntaxKind.AddExpression,
142+
SyntaxFactory.MemberAccessExpression(
143+
SyntaxKind.SimpleMemberAccessExpression,
144+
XmlImportContext.HelperClassShortIdentifierName,
145+
ValidSyntaxFactory.IdentifierName(node.Prefix.Name.ValueText)
146+
),
147+
SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(node.LocalName.Text))
148+
);
149+
}
150+
}
151+
152+
if (_xmlImportContext.HasDefaultImport && node.Parent is not VBSyntax.XmlAttributeSyntax) {
153+
return SyntaxFactory.BinaryExpression(
154+
SyntaxKind.AddExpression,
155+
SyntaxFactory.MemberAccessExpression(
156+
SyntaxKind.SimpleMemberAccessExpression,
157+
XmlImportContext.HelperClassShortIdentifierName,
158+
XmlImportContext.DefaultIdentifierName
159+
),
160+
SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(node.LocalName.Text))
161+
);
162+
}
163+
164+
return SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(node.LocalName.Text));
165+
}
166+
}

CodeConverter/CSharp/ExpressionNodeVisitor.cs

Lines changed: 1 addition & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
using System.Collections.Immutable;
22
using System.Data;
33
using System.Globalization;
4-
using System.Linq.Expressions;
5-
using System.Runtime.CompilerServices;
6-
using System.Xml.Linq;
74
using ICSharpCode.CodeConverter.CSharp.Replacements;
85
using ICSharpCode.CodeConverter.Util.FromRoslyn;
96
using Microsoft.CodeAnalysis.CSharp;
@@ -22,13 +19,12 @@ namespace ICSharpCode.CodeConverter.CSharp;
2219
/// http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis.CSharp/Binder/Binder_Expressions.cs,365
2320
/// http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis.VisualBasic/Binding/Binder_Expressions.vb,43
2421
/// </summary>
25-
internal class ExpressionNodeVisitor : VBasic.VisualBasicSyntaxVisitor<Task<CSharpSyntaxNode>>
22+
internal partial class ExpressionNodeVisitor : VBasic.VisualBasicSyntaxVisitor<Task<CSharpSyntaxNode>>
2623
{
2724
private static readonly Type ConvertType = typeof(Conversions);
2825
public CommentConvertingVisitorWrapper TriviaConvertingExpressionVisitor { get; }
2926
private readonly SemanticModel _semanticModel;
3027
private readonly HashSet<string> _extraUsingDirectives;
31-
private readonly XmlImportContext _xmlImportContext;
3228
private readonly IOperatorConverter _operatorConverter;
3329
private readonly VisualBasicEqualityComparison _visualBasicEqualityComparison;
3430
private readonly Stack<ExpressionSyntax> _withBlockLhs = new();
@@ -95,159 +91,6 @@ public override async Task<CSharpSyntaxNode> DefaultVisit(SyntaxNode node)
9591
.WithNodeInformation(node);
9692
}
9793

98-
public override async Task<CSharpSyntaxNode> VisitXmlEmbeddedExpression(VBSyntax.XmlEmbeddedExpressionSyntax node) =>
99-
await node.Expression.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor);
100-
101-
public override async Task<CSharpSyntaxNode> VisitXmlDocument(VBasic.Syntax.XmlDocumentSyntax node)
102-
{
103-
_extraUsingDirectives.Add("System.Xml.Linq");
104-
var arguments = SyntaxFactory.SeparatedList(
105-
(await node.PrecedingMisc.SelectAsync(async misc => SyntaxFactory.Argument(await misc.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor))))
106-
.Concat(SyntaxFactory.Argument(await node.Root.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor)).Yield())
107-
.Concat(await node.FollowingMisc.SelectAsync(async misc => SyntaxFactory.Argument(await misc.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor))))
108-
);
109-
return ApplyXmlImportsIfNecessary(node, SyntaxFactory.ObjectCreationExpression(ValidSyntaxFactory.IdentifierName("XDocument")).WithArgumentList(SyntaxFactory.ArgumentList(arguments)));
110-
}
111-
112-
public override async Task<CSharpSyntaxNode> VisitXmlElement(VBasic.Syntax.XmlElementSyntax node)
113-
{
114-
_extraUsingDirectives.Add("System.Xml.Linq");
115-
var arguments = SyntaxFactory.SeparatedList(
116-
SyntaxFactory.Argument(await node.StartTag.Name.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor)).Yield()
117-
.Concat(await node.StartTag.Attributes.SelectAsync(async attribute => SyntaxFactory.Argument(await attribute.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor))))
118-
.Concat(await node.Content.SelectAsync(async content => SyntaxFactory.Argument(await content.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor))))
119-
);
120-
return ApplyXmlImportsIfNecessary(node, SyntaxFactory.ObjectCreationExpression(ValidSyntaxFactory.IdentifierName("XElement")).WithArgumentList(SyntaxFactory.ArgumentList(arguments)));
121-
}
122-
123-
public override async Task<CSharpSyntaxNode> VisitXmlEmptyElement(VBSyntax.XmlEmptyElementSyntax node)
124-
{
125-
_extraUsingDirectives.Add("System.Xml.Linq");
126-
var arguments = SyntaxFactory.SeparatedList(
127-
SyntaxFactory.Argument(await node.Name.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor)).Yield()
128-
.Concat(await node.Attributes.SelectAsync(async attribute => SyntaxFactory.Argument(await attribute.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor))))
129-
);
130-
return ApplyXmlImportsIfNecessary(node, SyntaxFactory.ObjectCreationExpression(ValidSyntaxFactory.IdentifierName("XElement")).WithArgumentList(SyntaxFactory.ArgumentList(arguments)));
131-
}
132-
133-
private CSharpSyntaxNode ApplyXmlImportsIfNecessary(VBSyntax.XmlNodeSyntax vbNode, ObjectCreationExpressionSyntax creation)
134-
{
135-
if (!_xmlImportContext.HasImports || vbNode.Parent is VBSyntax.XmlNodeSyntax) return creation;
136-
return SyntaxFactory.InvocationExpression(
137-
SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, XmlImportContext.HelperClassShortIdentifierName, ValidSyntaxFactory.IdentifierName("Apply")),
138-
SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(creation))));
139-
}
140-
141-
public override async Task<CSharpSyntaxNode> VisitXmlAttribute(VBasic.Syntax.XmlAttributeSyntax node)
142-
{
143-
var arguments = SyntaxFactory.SeparatedList(
144-
SyntaxFactory.Argument(await node.Name.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor)).Yield()
145-
.Concat(SyntaxFactory.Argument(await node.Value.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor)).Yield())
146-
);
147-
return SyntaxFactory.ObjectCreationExpression(ValidSyntaxFactory.IdentifierName("XAttribute")).WithArgumentList(SyntaxFactory.ArgumentList(arguments));
148-
}
149-
150-
public override async Task<CSharpSyntaxNode> VisitXmlString(VBasic.Syntax.XmlStringSyntax node) =>
151-
CommonConversions.Literal(string.Join("", node.TextTokens.Select(b => b.Text)));
152-
153-
public override async Task<CSharpSyntaxNode> VisitXmlText(VBSyntax.XmlTextSyntax node) =>
154-
CommonConversions.Literal(string.Join("", node.TextTokens.Select(b => b.Text)));
155-
156-
public override async Task<CSharpSyntaxNode> VisitXmlCDataSection(VBSyntax.XmlCDataSectionSyntax node)
157-
{
158-
var xcDataTypeSyntax = SyntaxFactory.ParseTypeName(nameof(XCData));
159-
var argumentListSyntax = CommonConversions.Literal(string.Join("", node.TextTokens.Select( b=> b.Text))).Yield().CreateCsArgList();
160-
return SyntaxFactory.ObjectCreationExpression(xcDataTypeSyntax).WithArgumentList(argumentListSyntax);
161-
}
162-
163-
/// <summary>
164-
/// https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/xml/accessing-xml
165-
/// </summary>
166-
public override async Task<CSharpSyntaxNode> VisitXmlMemberAccessExpression(
167-
VBasic.Syntax.XmlMemberAccessExpressionSyntax node)
168-
{
169-
_extraUsingDirectives.Add("System.Xml.Linq");
170-
171-
var xElementMethodName = GetXElementMethodName(node);
172-
173-
ExpressionSyntax elements = node.Base != null ? SyntaxFactory.MemberAccessExpression(
174-
SyntaxKind.SimpleMemberAccessExpression,
175-
await node.Base.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor),
176-
ValidSyntaxFactory.IdentifierName(xElementMethodName)
177-
) : SyntaxFactory.MemberBindingExpression(
178-
ValidSyntaxFactory.IdentifierName(xElementMethodName)
179-
);
180-
181-
return SyntaxFactory.InvocationExpression(elements,
182-
ExpressionSyntaxExtensions.CreateArgList(
183-
await node.Name.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor))
184-
);
185-
}
186-
187-
private static string GetXElementMethodName(VBSyntax.XmlMemberAccessExpressionSyntax node)
188-
{
189-
if (node.Token2 == default(SyntaxToken)) {
190-
return "Elements";
191-
}
192-
193-
if (node.Token2.Text == "@") {
194-
return "Attributes";
195-
}
196-
197-
if (node.Token2.Text == ".") {
198-
return "Descendants";
199-
}
200-
throw new NotImplementedException($"Xml member access operator: '{node.Token1}{node.Token2}{node.Token3}'");
201-
}
202-
203-
public override Task<CSharpSyntaxNode> VisitXmlBracketedName(VBSyntax.XmlBracketedNameSyntax node)
204-
{
205-
return node.Name.AcceptAsync<CSharpSyntaxNode>(TriviaConvertingExpressionVisitor);
206-
}
207-
208-
public override async Task<CSharpSyntaxNode> VisitXmlName(VBSyntax.XmlNameSyntax node)
209-
{
210-
if (node.Prefix != null) {
211-
switch (node.Prefix.Name.ValueText) {
212-
case "xml":
213-
case "xmlns":
214-
return SyntaxFactory.BinaryExpression(
215-
SyntaxKind.AddExpression,
216-
SyntaxFactory.MemberAccessExpression(
217-
SyntaxKind.SimpleMemberAccessExpression,
218-
ValidSyntaxFactory.IdentifierName("XNamespace"),
219-
ValidSyntaxFactory.IdentifierName(node.Prefix.Name.ValueText.ToPascalCase())
220-
),
221-
SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(node.LocalName.Text))
222-
);
223-
default:
224-
return SyntaxFactory.BinaryExpression(
225-
SyntaxKind.AddExpression,
226-
SyntaxFactory.MemberAccessExpression(
227-
SyntaxKind.SimpleMemberAccessExpression,
228-
XmlImportContext.HelperClassShortIdentifierName,
229-
ValidSyntaxFactory.IdentifierName(node.Prefix.Name.ValueText)
230-
),
231-
SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(node.LocalName.Text))
232-
);
233-
}
234-
}
235-
236-
if (_xmlImportContext.HasDefaultImport && node.Parent is not VBSyntax.XmlAttributeSyntax) {
237-
return SyntaxFactory.BinaryExpression(
238-
SyntaxKind.AddExpression,
239-
SyntaxFactory.MemberAccessExpression(
240-
SyntaxKind.SimpleMemberAccessExpression,
241-
XmlImportContext.HelperClassShortIdentifierName,
242-
XmlImportContext.DefaultIdentifierName
243-
),
244-
SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(node.LocalName.Text))
245-
);
246-
}
247-
248-
return SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(node.LocalName.Text));
249-
}
250-
25194
public override async Task<CSharpSyntaxNode> VisitGetTypeExpression(VBasic.Syntax.GetTypeExpressionSyntax node)
25295
{
25396
return SyntaxFactory.TypeOfExpression(await node.Type.AcceptAsync<TypeSyntax>(TriviaConvertingExpressionVisitor));

0 commit comments

Comments
 (0)