2
// <copyright see="prj:///doc/copyright.txt"/>
3
// <license see="prj:///doc/license.txt"/>
4
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
5
// <version>$Revision: 4570 $</version>
9
using System.Collections.Generic;
10
using ICSharpCode.OldNRefactory.Ast;
11
using ICSharpCode.OldNRefactory.AstBuilder;
12
using Attribute = ICSharpCode.OldNRefactory.Ast.Attribute;
14
namespace ICSharpCode.OldNRefactory.Visitors
17
/// Converts elements not supported by VB to their VB representation.
18
/// Not all elements are converted here, most simple elements (e.g. ConditionalExpression)
19
/// are converted in the output visitor.
21
public class ToVBNetConvertVisitor : ConvertVisitorBase
23
// The following conversions are implemented:
24
// Conflicting field/property names -> m_field
25
// Conflicting variable names inside methods
26
// Anonymous methods are put into new methods
27
// Simple event handler creation is replaced with AddressOfExpression
28
// Move Imports-statements out of namespaces
29
// Parenthesis around Cast expressions remove - these are syntax errors in VB.NET
30
// Decrease array creation size - VB specifies upper bound instead of array length
31
// Automatic properties are converted to explicit implementation
33
List<INode> nodesToMoveToCompilationUnit = new List<INode>();
35
public override object VisitCompilationUnit(CompilationUnit compilationUnit, object data)
37
base.VisitCompilationUnit(compilationUnit, data);
38
for (int i = 0; i < nodesToMoveToCompilationUnit.Count; i++) {
39
compilationUnit.Children.Insert(i, nodesToMoveToCompilationUnit[i]);
40
nodesToMoveToCompilationUnit[i].Parent = compilationUnit;
45
public override object VisitUsingDeclaration(UsingDeclaration usingDeclaration, object data)
47
base.VisitUsingDeclaration(usingDeclaration, data);
48
if (usingDeclaration.Parent is NamespaceDeclaration) {
49
nodesToMoveToCompilationUnit.Add(usingDeclaration);
55
TypeDeclaration currentType;
57
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
59
// fix default inner type visibility
60
if (currentType != null && (typeDeclaration.Modifier & Modifiers.Visibility) == 0)
61
typeDeclaration.Modifier |= Modifiers.Private;
63
TypeDeclaration outerType = currentType;
64
currentType = typeDeclaration;
66
if ((typeDeclaration.Modifier & Modifiers.Static) == Modifiers.Static) {
67
typeDeclaration.Modifier &= ~Modifiers.Static;
68
typeDeclaration.Modifier |= Modifiers.Sealed;
69
typeDeclaration.Children.Insert(0, new ConstructorDeclaration("#ctor", Modifiers.Private, null, null));
72
// Conflicting field/property names -> m_field
73
List<string> properties = new List<string>();
74
foreach (object o in typeDeclaration.Children) {
75
PropertyDeclaration pd = o as PropertyDeclaration;
77
properties.Add(pd.Name);
80
List<VariableDeclaration> conflicts = new List<VariableDeclaration>();
81
foreach (object o in typeDeclaration.Children) {
82
FieldDeclaration fd = o as FieldDeclaration;
84
foreach (VariableDeclaration var in fd.Fields) {
85
string name = var.Name;
86
foreach (string propertyName in properties) {
87
if (name.Equals(propertyName, StringComparison.InvariantCultureIgnoreCase)) {
94
new PrefixFieldsVisitor(conflicts, "m_").Run(typeDeclaration);
95
base.VisitTypeDeclaration(typeDeclaration, data);
96
currentType = outerType;
101
public override object VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration, object data)
103
// fix default inner type visibility
104
if (currentType != null && (delegateDeclaration.Modifier & Modifiers.Visibility) == 0)
105
delegateDeclaration.Modifier |= Modifiers.Private;
107
return base.VisitDelegateDeclaration(delegateDeclaration, data);
110
public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data)
112
base.VisitExpressionStatement(expressionStatement, data);
113
AssignmentExpression ass = expressionStatement.Expression as AssignmentExpression;
114
if (ass != null && ass.Right is AddressOfExpression) {
115
if (ass.Op == AssignmentOperatorType.Add) {
116
ReplaceCurrentNode(new AddHandlerStatement(ass.Left, ass.Right));
117
} else if (ass.Op == AssignmentOperatorType.Subtract) {
118
ReplaceCurrentNode(new RemoveHandlerStatement(ass.Left, ass.Right));
124
static string GetMemberNameOnThisReference(Expression expr)
126
IdentifierExpression ident = expr as IdentifierExpression;
128
return ident.Identifier;
129
MemberReferenceExpression fre = expr as MemberReferenceExpression;
130
if (fre != null && fre.TargetObject is ThisReferenceExpression)
131
return fre.MemberName;
135
public override object VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, object data)
137
base.VisitAnonymousMethodExpression(anonymousMethodExpression, data);
138
if (anonymousMethodExpression.Body.Children.Count == 1) {
139
ReturnStatement rs = anonymousMethodExpression.Body.Children[0] as ReturnStatement;
141
LambdaExpression lambda = new LambdaExpression();
142
lambda.ExpressionBody = rs.Expression;
143
lambda.Parameters = anonymousMethodExpression.Parameters;
144
ReplaceCurrentNode(lambda);
150
public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data)
152
base.VisitAssignmentExpression(assignmentExpression, data);
153
if (assignmentExpression.Op == AssignmentOperatorType.Assign && !(assignmentExpression.Parent is ExpressionStatement)) {
154
AddInlineAssignHelper();
156
new InvocationExpression(
157
new IdentifierExpression("InlineAssignHelper"),
158
new List<Expression> { assignmentExpression.Left, assignmentExpression.Right }
164
void AddInlineAssignHelper()
166
MethodDeclaration method;
167
foreach (INode node in currentType.Children) {
168
method = node as MethodDeclaration;
169
if (method != null && method.Name == "InlineAssignHelper") {
170
// inline assign helper already exists
175
method = new MethodDeclaration {
176
Name = "InlineAssignHelper",
177
Modifier = Modifiers.Private | Modifiers.Static,
178
TypeReference = new TypeReference("T"),
179
Parameters = new List<ParameterDeclarationExpression> {
180
new ParameterDeclarationExpression(new TypeReference("T"), "target", ParameterModifiers.Ref),
181
new ParameterDeclarationExpression(new TypeReference("T"), "value")
183
method.Templates.Add(new TemplateDefinition("T", null));
184
method.Body = new BlockStatement();
185
method.Body.AddChild(new ExpressionStatement(new AssignmentExpression(
186
new IdentifierExpression("target"),
187
AssignmentOperatorType.Assign,
188
new IdentifierExpression("value"))));
189
method.Body.AddChild(new ReturnStatement(new IdentifierExpression("value")));
190
currentType.AddChild(method);
193
bool IsClassType(ClassType c)
195
if (currentType == null) return false;
196
return currentType.Type == c;
199
public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
201
if (!IsClassType(ClassType.Interface) && (methodDeclaration.Modifier & Modifiers.Visibility) == 0)
202
methodDeclaration.Modifier |= Modifiers.Private;
204
base.VisitMethodDeclaration(methodDeclaration, data);
206
const Modifiers externStatic = Modifiers.Static | Modifiers.Extern;
207
if ((methodDeclaration.Modifier & externStatic) == externStatic
208
&& methodDeclaration.Body.IsNull)
210
foreach (AttributeSection sec in methodDeclaration.Attributes) {
211
foreach (Attribute att in sec.Attributes) {
212
if ("DllImport".Equals(att.Name, StringComparison.InvariantCultureIgnoreCase)) {
213
if (ConvertPInvoke(methodDeclaration, att)) {
214
sec.Attributes.Remove(att);
219
if (sec.Attributes.Count == 0) {
220
methodDeclaration.Attributes.Remove(sec);
226
ToVBNetRenameConflictingVariablesVisitor.RenameConflicting(methodDeclaration);
231
bool ConvertPInvoke(MethodDeclaration method, ICSharpCode.OldNRefactory.Ast.Attribute att)
233
if (att.PositionalArguments.Count != 1)
235
PrimitiveExpression pe = att.PositionalArguments[0] as PrimitiveExpression;
236
if (pe == null || !(pe.Value is string))
238
string libraryName = (string)pe.Value;
240
bool setLastError = false;
241
bool exactSpelling = false;
242
CharsetModifier charSet = CharsetModifier.Auto;
243
foreach (NamedArgumentExpression arg in att.NamedArguments) {
246
pe = arg.Expression as PrimitiveExpression;
247
if (pe != null && pe.Value is bool)
248
setLastError = (bool)pe.Value;
252
case "ExactSpelling":
253
pe = arg.Expression as PrimitiveExpression;
254
if (pe != null && pe.Value is bool)
255
exactSpelling = (bool)pe.Value;
261
MemberReferenceExpression fre = arg.Expression as MemberReferenceExpression;
262
if (fre == null || !(fre.TargetObject is IdentifierExpression))
264
if ((fre.TargetObject as IdentifierExpression).Identifier != "CharSet")
266
switch (fre.MemberName) {
268
charSet = CharsetModifier.Unicode;
271
charSet = CharsetModifier.Auto;
274
charSet = CharsetModifier.Ansi;
282
pe = arg.Expression as PrimitiveExpression;
284
alias = pe.Value as string;
290
if (setLastError && exactSpelling) {
291
// Only P/Invokes with SetLastError and ExactSpelling can be converted to a DeclareDeclaration
292
const Modifiers removeModifiers = Modifiers.Static | Modifiers.Extern;
293
DeclareDeclaration decl = new DeclareDeclaration(method.Name, method.Modifier &~ removeModifiers,
294
method.TypeReference,
297
libraryName, alias, charSet);
298
ReplaceCurrentNode(decl);
299
base.VisitDeclareDeclaration(decl, null);
306
public override object VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data)
308
if (!IsClassType(ClassType.Interface) && (propertyDeclaration.Modifier & Modifiers.Visibility) == 0)
309
propertyDeclaration.Modifier |= Modifiers.Private;
310
base.VisitPropertyDeclaration(propertyDeclaration, data);
312
ToVBNetRenameConflictingVariablesVisitor.RenameConflicting(propertyDeclaration);
314
if (!IsClassType(ClassType.Interface) && (propertyDeclaration.Modifier & Modifiers.Abstract) == 0) {
315
if (propertyDeclaration.HasGetRegion && propertyDeclaration.HasSetRegion) {
316
if (propertyDeclaration.GetRegion.Block.IsNull && propertyDeclaration.SetRegion.Block.IsNull) {
317
// automatically implemented property
318
string fieldName = "m_" + propertyDeclaration.Name;
319
Modifiers fieldModifier = propertyDeclaration.Modifier & ~(Modifiers.Visibility) | Modifiers.Private;
320
FieldDeclaration newField = new FieldDeclaration(null, propertyDeclaration.TypeReference, fieldModifier);
321
newField.Fields.Add(new VariableDeclaration(fieldName));
322
InsertAfterSibling(propertyDeclaration, newField);
324
propertyDeclaration.GetRegion.Block = new BlockStatement();
325
propertyDeclaration.GetRegion.Block.Return(ExpressionBuilder.Identifier(fieldName));
326
propertyDeclaration.SetRegion.Block = new BlockStatement();
327
propertyDeclaration.SetRegion.Block.Assign(ExpressionBuilder.Identifier(fieldName), ExpressionBuilder.Identifier("Value"));
336
public override object VisitEventDeclaration(EventDeclaration eventDeclaration, object data)
338
if (!IsClassType(ClassType.Interface) && (eventDeclaration.Modifier & Modifiers.Visibility) == 0)
339
eventDeclaration.Modifier |= Modifiers.Private;
340
return base.VisitEventDeclaration(eventDeclaration, data);
343
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
345
// make constructor private if visiblity is not set (unless constructor is static)
346
if ((constructorDeclaration.Modifier & (Modifiers.Visibility | Modifiers.Static)) == 0)
347
constructorDeclaration.Modifier |= Modifiers.Private;
348
base.VisitConstructorDeclaration(constructorDeclaration, data);
350
ToVBNetRenameConflictingVariablesVisitor.RenameConflicting(constructorDeclaration);
355
public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data)
357
base.VisitParenthesizedExpression(parenthesizedExpression, data);
358
if (parenthesizedExpression.Expression is CastExpression) {
359
ReplaceCurrentNode(parenthesizedExpression.Expression); // remove parenthesis around casts
360
} else if (parenthesizedExpression.Parent is CastExpression) {
361
ReplaceCurrentNode(parenthesizedExpression.Expression); // remove parenthesis inside casts
366
public override object VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression, object data)
368
for (int i = 0; i < arrayCreateExpression.Arguments.Count; i++) {
369
arrayCreateExpression.Arguments[i] = Expression.AddInteger(arrayCreateExpression.Arguments[i], -1);
371
return base.VisitArrayCreateExpression(arrayCreateExpression, data);
374
public override object VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression, object data)
376
base.VisitDefaultValueExpression(defaultValueExpression, data);
377
Expression defaultValue = ExpressionBuilder.CreateDefaultValueForType(defaultValueExpression.TypeReference);
378
if (!(defaultValue is DefaultValueExpression))
379
ReplaceCurrentNode(defaultValue);