File: ToVBNetConvertVisitor.cs

package info (click to toggle)
monodevelop 2.4%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 54,088 kB
  • ctags: 67,523
  • sloc: cs: 436,824; xml: 18,137; makefile: 5,722; sh: 1,085; sed: 2
file content (383 lines) | stat: -rw-r--r-- 14,783 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
//     <version>$Revision: 4570 $</version>
// </file>

using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.AstBuilder;
using Attribute = ICSharpCode.NRefactory.Ast.Attribute;

namespace ICSharpCode.NRefactory.Visitors
{
	/// <summary>
	/// Converts elements not supported by VB to their VB representation.
	/// Not all elements are converted here, most simple elements (e.g. ConditionalExpression)
	/// are converted in the output visitor.
	/// </summary>
	public class ToVBNetConvertVisitor : ConvertVisitorBase
	{
		// The following conversions are implemented:
		//   Conflicting field/property names -> m_field
		//   Conflicting variable names inside methods
		//   Anonymous methods are put into new methods
		//   Simple event handler creation is replaced with AddressOfExpression
		//   Move Imports-statements out of namespaces
		//   Parenthesis around Cast expressions remove - these are syntax errors in VB.NET
		//   Decrease array creation size - VB specifies upper bound instead of array length
		//   Automatic properties are converted to explicit implementation
		
		List<INode> nodesToMoveToCompilationUnit = new List<INode>();
		
		public override object VisitCompilationUnit(CompilationUnit compilationUnit, object data)
		{
			base.VisitCompilationUnit(compilationUnit, data);
			for (int i = 0; i < nodesToMoveToCompilationUnit.Count; i++) {
				compilationUnit.Children.Insert(i, nodesToMoveToCompilationUnit[i]);
				nodesToMoveToCompilationUnit[i].Parent = compilationUnit;
			}
			return null;
		}
		
		public override object VisitUsingDeclaration(UsingDeclaration usingDeclaration, object data)
		{
			base.VisitUsingDeclaration(usingDeclaration, data);
			if (usingDeclaration.Parent is NamespaceDeclaration) {
				nodesToMoveToCompilationUnit.Add(usingDeclaration);
				RemoveCurrentNode();
			}
			return null;
		}
		
		TypeDeclaration currentType;
		
		public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
		{
			// fix default inner type visibility
			if (currentType != null && (typeDeclaration.Modifier & Modifiers.Visibility) == 0)
				typeDeclaration.Modifier |= Modifiers.Private;
			
			TypeDeclaration outerType = currentType;
			currentType = typeDeclaration;
			
			if ((typeDeclaration.Modifier & Modifiers.Static) == Modifiers.Static) {
				typeDeclaration.Modifier &= ~Modifiers.Static;
				typeDeclaration.Modifier |= Modifiers.Sealed;
				typeDeclaration.Children.Insert(0, new ConstructorDeclaration("#ctor", Modifiers.Private, null, null));
			}
			
			//   Conflicting field/property names -> m_field
			List<string> properties = new List<string>();
			foreach (object o in typeDeclaration.Children) {
				PropertyDeclaration pd = o as PropertyDeclaration;
				if (pd != null) {
					properties.Add(pd.Name);
				}
			}
			List<VariableDeclaration> conflicts = new List<VariableDeclaration>();
			foreach (object o in typeDeclaration.Children) {
				FieldDeclaration fd = o as FieldDeclaration;
				if (fd != null) {
					foreach (VariableDeclaration var in fd.Fields) {
						string name = var.Name;
						foreach (string propertyName in properties) {
							if (name.Equals(propertyName, StringComparison.InvariantCultureIgnoreCase)) {
								conflicts.Add(var);
							}
						}
					}
				}
			}
			new PrefixFieldsVisitor(conflicts, "m_").Run(typeDeclaration);
			base.VisitTypeDeclaration(typeDeclaration, data);
			currentType = outerType;
			
			return null;
		}
		
		public override object VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration, object data)
		{
			// fix default inner type visibility
			if (currentType != null && (delegateDeclaration.Modifier & Modifiers.Visibility) == 0)
				delegateDeclaration.Modifier |= Modifiers.Private;
			
			return base.VisitDelegateDeclaration(delegateDeclaration, data);
		}
		
		public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data)
		{
			base.VisitExpressionStatement(expressionStatement, data);
			AssignmentExpression ass = expressionStatement.Expression as AssignmentExpression;
			if (ass != null && ass.Right is AddressOfExpression) {
				if (ass.Op == AssignmentOperatorType.Add) {
					ReplaceCurrentNode(new AddHandlerStatement(ass.Left, ass.Right));
				} else if (ass.Op == AssignmentOperatorType.Subtract) {
					ReplaceCurrentNode(new RemoveHandlerStatement(ass.Left, ass.Right));
				}
			}
			return null;
		}
		
		static string GetMemberNameOnThisReference(Expression expr)
		{
			IdentifierExpression ident = expr as IdentifierExpression;
			if (ident != null)
				return ident.Identifier;
			MemberReferenceExpression fre = expr as MemberReferenceExpression;
			if (fre != null && fre.TargetObject is ThisReferenceExpression)
				return fre.MemberName;
			return null;
		}
		
		public override object VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, object data)
		{
			base.VisitAnonymousMethodExpression(anonymousMethodExpression, data);
			if (anonymousMethodExpression.Body.Children.Count == 1) {
				ReturnStatement rs = anonymousMethodExpression.Body.Children[0] as ReturnStatement;
				if (rs != null) {
					LambdaExpression lambda = new LambdaExpression();
					lambda.ExpressionBody = rs.Expression;
					lambda.Parameters = anonymousMethodExpression.Parameters;
					ReplaceCurrentNode(lambda);
				}
			}
			return null;
		}
		
		public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data)
		{
			base.VisitAssignmentExpression(assignmentExpression, data);
			if (assignmentExpression.Op == AssignmentOperatorType.Assign && !(assignmentExpression.Parent is ExpressionStatement)) {
				AddInlineAssignHelper();
				ReplaceCurrentNode(
					new InvocationExpression(
						new IdentifierExpression("InlineAssignHelper"),
						new List<Expression> { assignmentExpression.Left, assignmentExpression.Right }
					));
			}
			return null;
		}
		
		void AddInlineAssignHelper()
		{
			MethodDeclaration method;
			foreach (INode node in currentType.Children) {
				method = node as MethodDeclaration;
				if (method != null && method.Name == "InlineAssignHelper") {
					// inline assign helper already exists
					return;
				}
			}
			
			method = new MethodDeclaration {
				Name = "InlineAssignHelper",
				Modifier = Modifiers.Private | Modifiers.Static,
				TypeReference = new TypeReference("T"),
				Parameters = new List<ParameterDeclarationExpression> {
					new ParameterDeclarationExpression(new TypeReference("T"), "target", ParameterModifiers.Ref),
					new ParameterDeclarationExpression(new TypeReference("T"), "value")
				}};
			method.Templates.Add(new TemplateDefinition("T", null));
			method.Body = new BlockStatement();
			method.Body.AddChild(new ExpressionStatement(new AssignmentExpression(
				new IdentifierExpression("target"),
				AssignmentOperatorType.Assign,
				new IdentifierExpression("value"))));
			method.Body.AddChild(new ReturnStatement(new IdentifierExpression("value")));
			currentType.AddChild(method);
		}
		
		bool IsClassType(ClassType c)
		{
			if (currentType == null) return false;
			return currentType.Type == c;
		}
		
		public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
		{
			if (!IsClassType(ClassType.Interface) && (methodDeclaration.Modifier & Modifiers.Visibility) == 0)
				methodDeclaration.Modifier |= Modifiers.Private;
			
			base.VisitMethodDeclaration(methodDeclaration, data);
			
			const Modifiers externStatic = Modifiers.Static | Modifiers.Extern;
			if ((methodDeclaration.Modifier & externStatic) == externStatic
			    && methodDeclaration.Body.IsNull)
			{
				foreach (AttributeSection sec in methodDeclaration.Attributes) {
					foreach (Attribute att in sec.Attributes) {
						if ("DllImport".Equals(att.Name, StringComparison.InvariantCultureIgnoreCase)) {
							if (ConvertPInvoke(methodDeclaration, att)) {
								sec.Attributes.Remove(att);
								break;
							}
						}
					}
					if (sec.Attributes.Count == 0) {
						methodDeclaration.Attributes.Remove(sec);
						break;
					}
				}
			}
			
			ToVBNetRenameConflictingVariablesVisitor.RenameConflicting(methodDeclaration);
			
			return null;
		}
		
		bool ConvertPInvoke(MethodDeclaration method, ICSharpCode.NRefactory.Ast.Attribute att)
		{
			if (att.PositionalArguments.Count != 1)
				return false;
			PrimitiveExpression pe = att.PositionalArguments[0] as PrimitiveExpression;
			if (pe == null || !(pe.Value is string))
				return false;
			string libraryName = (string)pe.Value;
			string alias = null;
			bool setLastError = false;
			bool exactSpelling = false;
			CharsetModifier charSet = CharsetModifier.Auto;
			foreach (NamedArgumentExpression arg in att.NamedArguments) {
				switch (arg.Name) {
					case "SetLastError":
						pe = arg.Expression as PrimitiveExpression;
						if (pe != null && pe.Value is bool)
							setLastError = (bool)pe.Value;
						else
							return false;
						break;
					case "ExactSpelling":
						pe = arg.Expression as PrimitiveExpression;
						if (pe != null && pe.Value is bool)
							exactSpelling = (bool)pe.Value;
						else
							return false;
						break;
					case "CharSet":
						{
							MemberReferenceExpression fre = arg.Expression as MemberReferenceExpression;
							if (fre == null || !(fre.TargetObject is IdentifierExpression))
								return false;
							if ((fre.TargetObject as IdentifierExpression).Identifier != "CharSet")
								return false;
							switch (fre.MemberName) {
								case "Unicode":
									charSet = CharsetModifier.Unicode;
									break;
								case "Auto":
									charSet = CharsetModifier.Auto;
									break;
								case "Ansi":
									charSet = CharsetModifier.Ansi;
									break;
								default:
									return false;
							}
						}
						break;
					case "EntryPoint":
						pe = arg.Expression as PrimitiveExpression;
						if (pe != null)
							alias = pe.Value as string;
						break;
					default:
						return false;
				}
			}
			if (setLastError && exactSpelling) {
				// Only P/Invokes with SetLastError and ExactSpelling can be converted to a DeclareDeclaration
				const Modifiers removeModifiers = Modifiers.Static | Modifiers.Extern;
				DeclareDeclaration decl = new DeclareDeclaration(method.Name, method.Modifier &~ removeModifiers,
				                                                 method.TypeReference,
				                                                 method.Parameters,
				                                                 method.Attributes,
				                                                 libraryName, alias, charSet);
				ReplaceCurrentNode(decl);
				base.VisitDeclareDeclaration(decl, null);
				return true;
			} else {
				return false;
			}
		}
		
		public override object VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data)
		{
			if (!IsClassType(ClassType.Interface) && (propertyDeclaration.Modifier & Modifiers.Visibility) == 0)
				propertyDeclaration.Modifier |= Modifiers.Private;
			base.VisitPropertyDeclaration(propertyDeclaration, data);
			
			ToVBNetRenameConflictingVariablesVisitor.RenameConflicting(propertyDeclaration);
			
			if (!IsClassType(ClassType.Interface) && (propertyDeclaration.Modifier & Modifiers.Abstract) == 0) {
				if (propertyDeclaration.HasGetRegion && propertyDeclaration.HasSetRegion) {
					if (propertyDeclaration.GetRegion.Block.IsNull && propertyDeclaration.SetRegion.Block.IsNull) {
						// automatically implemented property
						string fieldName = "m_" + propertyDeclaration.Name;
						Modifiers fieldModifier = propertyDeclaration.Modifier & ~(Modifiers.Visibility) | Modifiers.Private;
						FieldDeclaration newField = new FieldDeclaration(null, propertyDeclaration.TypeReference, fieldModifier);
						newField.Fields.Add(new VariableDeclaration(fieldName));
						InsertAfterSibling(propertyDeclaration, newField);
						
						propertyDeclaration.GetRegion.Block = new BlockStatement();
						propertyDeclaration.GetRegion.Block.Return(ExpressionBuilder.Identifier(fieldName));
						propertyDeclaration.SetRegion.Block = new BlockStatement();
						propertyDeclaration.SetRegion.Block.Assign(ExpressionBuilder.Identifier(fieldName), ExpressionBuilder.Identifier("Value"));
						
					}
				}
			}
			
			return null;
		}
		
		public override object VisitEventDeclaration(EventDeclaration eventDeclaration, object data)
		{
			if (!IsClassType(ClassType.Interface) && (eventDeclaration.Modifier & Modifiers.Visibility) == 0)
				eventDeclaration.Modifier |= Modifiers.Private;
			return base.VisitEventDeclaration(eventDeclaration, data);
		}
		
		public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
		{
			// make constructor private if visiblity is not set (unless constructor is static)
			if ((constructorDeclaration.Modifier & (Modifiers.Visibility | Modifiers.Static)) == 0)
				constructorDeclaration.Modifier |= Modifiers.Private;
			base.VisitConstructorDeclaration(constructorDeclaration, data);
			
			ToVBNetRenameConflictingVariablesVisitor.RenameConflicting(constructorDeclaration);
			
			return null;
		}
		
		public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data)
		{
			base.VisitParenthesizedExpression(parenthesizedExpression, data);
			if (parenthesizedExpression.Expression is CastExpression) {
				ReplaceCurrentNode(parenthesizedExpression.Expression); // remove parenthesis around casts
			} else if (parenthesizedExpression.Parent is CastExpression) {
				ReplaceCurrentNode(parenthesizedExpression.Expression); // remove parenthesis inside casts
			}
			return null;
		}
		
		public override object VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression, object data)
		{
			for (int i = 0; i < arrayCreateExpression.Arguments.Count; i++) {
				arrayCreateExpression.Arguments[i] = Expression.AddInteger(arrayCreateExpression.Arguments[i], -1);
			}
			return base.VisitArrayCreateExpression(arrayCreateExpression, data);
		}
		
		public override object VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression, object data)
		{
			base.VisitDefaultValueExpression(defaultValueExpression, data);
			Expression defaultValue = ExpressionBuilder.CreateDefaultValueForType(defaultValueExpression.TypeReference);
			if (!(defaultValue is DefaultValueExpression))
				ReplaceCurrentNode(defaultValue);
			return null;
		}
	}
}