1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
5
using System.Collections.Generic;
6
using Boo.Lang.Compiler.Steps;
7
using ICSharpCode.Core;
8
using ICSharpCode.SharpDevelop.Dom;
9
using AST = Boo.Lang.Compiler.Ast;
11
namespace Grunwald.BooBinding.CodeCompletion
13
public class ConvertVisitor : AbstractVisitorCompilerStep
17
public ConvertVisitor(int[] _lineLength, IProjectContent pc)
19
this._lineLength = _lineLength;
20
this._cu = new DefaultCompilationUnit(pc);
23
DefaultCompilationUnit _cu;
25
public DefaultCompilationUnit Cu {
31
Stack<DefaultClass> _currentClass = new Stack<DefaultClass>();
32
bool _firstModule = true;
34
public override void Run()
37
_cu.Tag = CompileUnit;
39
} catch (Exception ex) {
40
MessageService.ShowException(ex);
44
protected override void OnError(AST.Node node, Exception error)
46
MessageService.ShowException(error, "error processing " + node.ToCodeString());
49
private ModifierEnum GetModifier(AST.TypeMember m)
51
ModifierEnum r = ModifierEnum.None;
52
if (m.IsPublic) r |= ModifierEnum.Public;
53
if (m.IsProtected) r |= ModifierEnum.Protected;
54
if (m.IsPrivate) r |= ModifierEnum.Private;
55
if (m.IsInternal) r |= ModifierEnum.Internal;
56
if (!m.IsVisibilitySet) {
57
if (IsStrictMode(_cu.ProjectContent))
58
r |= ModifierEnum.Private;
59
else if (m is AST.Field)
60
r |= ModifierEnum.Protected;
62
r |= ModifierEnum.Public;
65
if (m.IsStatic) r |= ModifierEnum.Static;
67
if (m.IsFinal) r |= ModifierEnum.Readonly;
69
if (m.IsFinal) r |= ModifierEnum.Sealed;
71
if (m.IsAbstract) r |= ModifierEnum.Abstract;
72
if (m.IsOverride) r |= ModifierEnum.Override;
73
if (m.IsSynthetic) r |= ModifierEnum.Synthetic;
74
if (m.IsPartial) r |= ModifierEnum.Partial;
76
if (m.LexicalInfo.IsValid && m.DeclaringType != null
77
&& m.LexicalInfo.Line < m.DeclaringType.LexicalInfo.Line)
78
{ // member added through attribute
79
r |= ModifierEnum.Synthetic;
84
public static AST.TypeMemberModifiers ConvertVisibilityBack(ModifierEnum modifier)
86
AST.TypeMemberModifiers r = AST.TypeMemberModifiers.None;
87
if ((modifier & ModifierEnum.Public) == ModifierEnum.Public)
88
r |= AST.TypeMemberModifiers.Public;
89
if ((modifier & ModifierEnum.Protected) == ModifierEnum.Protected)
90
r |= AST.TypeMemberModifiers.Protected;
91
if ((modifier & ModifierEnum.Internal) == ModifierEnum.Internal)
92
r |= AST.TypeMemberModifiers.Internal;
93
if ((modifier & ModifierEnum.Private) == ModifierEnum.Private)
94
r |= AST.TypeMemberModifiers.Private;
98
private int GetLineEnd(int line)
100
if (_lineLength == null || line < 1 || line > _lineLength.Length)
103
return _lineLength[line - 1] + 1;
106
private DomRegion GetRegion(AST.Node m)
108
AST.LexicalInfo l = m.LexicalInfo;
110
return DomRegion.Empty;
112
return new DomRegion(l.Line, 0 /*l.Column*/, l.Line, GetLineEnd(l.Line));
115
private DomRegion GetClientRegion(AST.Node m)
117
AST.LexicalInfo l = m.LexicalInfo;
119
return DomRegion.Empty;
120
AST.SourceLocation l2;
121
if (m is AST.Method) {
122
l2 = ((AST.Method)m).Body.EndSourceLocation;
123
} else if (m is AST.Property) {
124
AST.Property p = (AST.Property)m;
125
if (p.Getter != null && p.Getter.Body != null) {
126
l2 = p.Getter.Body.EndSourceLocation;
127
if (p.Setter != null && p.Setter.Body != null) {
128
if (p.Setter.Body.EndSourceLocation.Line > l2.Line)
129
l2 = p.Setter.Body.EndSourceLocation;
131
} else if (p.Setter != null && p.Setter.Body != null) {
132
l2 = p.Setter.Body.EndSourceLocation;
134
l2 = p.EndSourceLocation;
137
l2 = m.EndSourceLocation;
139
if (l2 == null || l2.Line < 0 || l.Line == l2.Line)
140
return DomRegion.Empty;
141
// TODO: use l.Column / l2.Column when the tab-bug has been fixed
142
return new DomRegion(l.Line, GetLineEnd(l.Line), l2.Line, GetLineEnd(l2.Line));
145
public override void OnImport(AST.Import p)
147
DefaultUsing u = new DefaultUsing(_cu.ProjectContent);
149
u.Usings.Add(p.Namespace);
151
u.AddAlias(p.Alias.Name, new GetClassReturnType(_cu.ProjectContent, p.Namespace, 0));
152
_cu.UsingScope.Usings.Add(u);
155
private IClass OuterClass {
157
if (_currentClass.Count > 0)
158
return _currentClass.Peek();
164
void ConvertTemplates(AST.Node node, DefaultClass c)
166
c.TypeParameters = DefaultTypeParameter.EmptyTypeParameterList;
169
void ConvertTemplates(AST.Node node, DefaultMethod m)
171
m.TypeParameters = DefaultTypeParameter.EmptyTypeParameterList;
174
void ConvertAttributes(AST.TypeMember node, AbstractEntity to)
176
if (node.Attributes.Count == 0) {
177
to.Attributes = DefaultAttribute.EmptyAttributeList;
181
context = new ClassFinder((IClass)to, node.LexicalInfo.Line, node.LexicalInfo.Column);
183
context = new ClassFinder(to.DeclaringType, node.LexicalInfo.Line, node.LexicalInfo.Column);
185
foreach (AST.Attribute a in node.Attributes) {
186
to.Attributes.Add(new DefaultAttribute(new AttributeReturnType(context, a.Name)) {
187
CompilationUnit = _cu,
188
Region = GetRegion(a)
192
to.Documentation = node.Documentation;
195
void ConvertParameters(AST.ParameterDeclarationCollection parameters, DefaultMethod m)
197
if (parameters == null || parameters.Count == 0) {
198
m.Parameters = DefaultParameter.EmptyParameterList;
200
AddParameters(parameters, m.Parameters, m, m.DeclaringType);
203
void ConvertParameters(AST.ParameterDeclarationCollection parameters, DefaultProperty p)
205
if (parameters == null || parameters.Count == 0) {
206
p.Parameters = DefaultParameter.EmptyParameterList;
208
AddParameters(parameters, p.Parameters, p, p.DeclaringType);
211
internal static void AddParameters(AST.ParameterDeclarationCollection parameters, IList<IParameter> output, IMethodOrProperty method, IClass c)
213
if (c == null) throw new ArgumentNullException("c");
214
DefaultParameter p = null;
215
foreach (AST.ParameterDeclaration par in parameters) {
216
p = new DefaultParameter(par.Name,
217
CreateReturnType(par.Type, c, method as IMethod, c.Region.BeginLine + 1, 1, c.ProjectContent),
218
new DomRegion(par.LexicalInfo.Line, par.LexicalInfo.Column));
219
if (par.IsByRef) p.Modifiers |= ParameterModifiers.Ref;
222
if (parameters.HasParamArray) {
223
p.Modifiers |= ParameterModifiers.Params;
227
IReturnType CreateReturnType(AST.TypeReference reference, IMethod method)
229
IClass c = OuterClass;
231
return CreateReturnType(reference, new DefaultClass(_cu, "___DummyClass"), method, 1, 1, _cu.ProjectContent);
233
return CreateReturnType(reference, c, method, c.Region.BeginLine + 1, 1, _cu.ProjectContent);
237
internal static bool IsStrictMode(IProjectContent projectContent)
239
BooProject project = projectContent.Project as BooProject;
241
return project.Strict;
246
internal static IReturnType GetDefaultReturnType(IProjectContent projectContent)
248
BooProject project = projectContent.Project as BooProject;
249
if (project != null && project.Ducky)
250
return new BooResolver.DuckClass(new DefaultCompilationUnit(projectContent)).DefaultReturnType;
252
return projectContent.SystemTypes.Object;
255
public static IReturnType CreateReturnType(AST.TypeReference reference, IClass callingClass,
256
IMethodOrProperty callingMember, int caretLine, int caretColumn,
257
IProjectContent projectContent)
259
System.Diagnostics.Debug.Assert(projectContent != null);
260
if (reference == null) {
261
return GetDefaultReturnType(projectContent);
263
if (reference is AST.ArrayTypeReference) {
264
AST.ArrayTypeReference arr = (AST.ArrayTypeReference)reference;
265
return new ArrayReturnType(projectContent,
266
CreateReturnType(arr.ElementType, callingClass, callingMember,
267
caretLine, caretColumn, projectContent),
268
(arr.Rank != null) ? (int)arr.Rank.Value : 1);
269
} else if (reference is AST.SimpleTypeReference) {
270
string name = ((AST.SimpleTypeReference)reference).Name;
272
int typeParameterCount = (reference is AST.GenericTypeReference) ? ((AST.GenericTypeReference)reference).GenericArguments.Count : 0;
274
rt = new BooResolver.DuckClass(new DefaultCompilationUnit(projectContent)).DefaultReturnType;
275
else if (BooAmbience.ReverseTypeConversionTable.ContainsKey(name))
276
rt = new GetClassReturnType(projectContent, BooAmbience.ReverseTypeConversionTable[name], typeParameterCount);
277
else if (callingClass == null)
278
rt = new GetClassReturnType(projectContent, name, typeParameterCount);
280
rt = new SearchClassReturnType(projectContent, callingClass, caretLine, caretColumn,
281
name, typeParameterCount);
282
if (typeParameterCount > 0) {
283
AST.TypeReferenceCollection arguments = ((AST.GenericTypeReference)reference).GenericArguments;
284
// GenericTypeReference derives from SimpleTypeReference
285
IReturnType[] typeArguments = new IReturnType[arguments.Count];
286
for (int i = 0; i < typeArguments.Length; i++) {
287
typeArguments[i] = CreateReturnType(arguments[i], callingClass, callingMember, caretLine, caretColumn,
290
rt = new ConstructedReturnType(rt, typeArguments);
293
} else if (reference is AST.CallableTypeReference) {
294
AST.CallableTypeReference ctr = (AST.CallableTypeReference)reference;
295
AnonymousMethodReturnType amrt = new AnonymousMethodReturnType(new DefaultCompilationUnit(projectContent));
296
if (ctr.ReturnType != null) {
297
amrt.MethodReturnType = CreateReturnType(ctr.ReturnType, callingClass, callingMember, caretLine, caretColumn, projectContent);
299
amrt.MethodParameters = new List<IParameter>();
300
AddParameters(ctr.Parameters, amrt.MethodParameters, callingMember, callingClass ?? new DefaultClass(new DefaultCompilationUnit(projectContent), "__Dummy"));
303
throw new NotSupportedException("unknown reference type: " + reference.ToString());
306
IReturnType CreateReturnType(AST.TypeReference reference)
308
return CreateReturnType(reference, null);
310
IReturnType CreateReturnType(AST.Field field)
312
if (field.Type == null) {
313
if (field.Initializer != null)
314
return new BooInferredReturnType(field.Initializer, OuterClass);
316
return GetDefaultReturnType(_cu.ProjectContent);
318
return CreateReturnType(field.Type);
321
IReturnType CreateReturnType(AST.Method node, IMethod method)
323
if (node.ReturnType == null)
324
return new BooInferredReturnType(node.Body, OuterClass, false);
325
return CreateReturnType(node.ReturnType, method);
327
IReturnType CreateReturnType(AST.Property property)
329
if (property.Type == null && property.Getter != null && property.Getter.Body != null)
330
return new BooInferredReturnType(property.Getter.Body, OuterClass, false);
331
return CreateReturnType(property.Type);
334
public override void OnCallableDefinition(AST.CallableDefinition node)
336
LoggingService.Debug("OnCallableDefinition: " + node.FullName);
337
DomRegion region = GetRegion(node);
338
DefaultClass c = new DefaultClass(_cu, ClassType.Delegate, GetModifier(node), region, OuterClass);
339
ConvertAttributes(node, c);
340
c.BaseTypes.Add(c.ProjectContent.SystemTypes.Delegate);
341
c.FullyQualifiedName = node.FullName;
342
if (_currentClass.Count > 0) {
343
OuterClass.InnerClasses.Add(c);
347
_currentClass.Push(c); // necessary for CreateReturnType
348
ConvertTemplates(node, c);
349
IReturnType returnType = CreateReturnType(node.ReturnType);
350
DefaultMethod invokeMethod = new DefaultMethod("Invoke", returnType, ModifierEnum.Public, DomRegion.Empty, DomRegion.Empty, c);
351
ConvertParameters(node.Parameters, invokeMethod);
352
c.Methods.Add(invokeMethod);
353
invokeMethod = new DefaultMethod("BeginInvoke", c.ProjectContent.SystemTypes.IAsyncResult, ModifierEnum.Public, DomRegion.Empty, DomRegion.Empty, c);
354
ConvertParameters(node.Parameters, invokeMethod);
355
if (invokeMethod.Parameters == DefaultParameter.EmptyParameterList) {
356
invokeMethod.Parameters = new List<IParameter>();
358
invokeMethod.Parameters.Add(new DefaultParameter("callback", c.ProjectContent.SystemTypes.AsyncCallback, DomRegion.Empty));
359
invokeMethod.Parameters.Add(new DefaultParameter("object", c.ProjectContent.SystemTypes.Object, DomRegion.Empty));
360
c.Methods.Add(invokeMethod);
361
invokeMethod = new DefaultMethod("EndInvoke", returnType, ModifierEnum.Public, DomRegion.Empty, DomRegion.Empty, c);
362
invokeMethod.Parameters.Add(new DefaultParameter("result", c.ProjectContent.SystemTypes.IAsyncResult, DomRegion.Empty));
363
c.Methods.Add(invokeMethod);
367
public override bool EnterClassDefinition(AST.ClassDefinition node)
369
EnterTypeDefinition(node, ClassType.Class);
370
return base.EnterClassDefinition(node);
373
public override bool EnterInterfaceDefinition(AST.InterfaceDefinition node)
375
EnterTypeDefinition(node, ClassType.Interface);
376
return base.EnterInterfaceDefinition(node);
379
public override bool EnterEnumDefinition(AST.EnumDefinition node)
381
EnterTypeDefinition(node, ClassType.Enum);
382
return base.EnterEnumDefinition(node);
385
// cannot override OnNamespaceDeclaration - it's visited too late (after the type definitions)
386
void HandleNamespaceDeclaration(AST.NamespaceDeclaration node)
390
string[] namespaceName = node.Name.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
391
foreach (string namePart in namespaceName) {
392
_cu.UsingScope = new DefaultUsingScope {
393
NamespaceName = PrependCurrentNamespace(namePart),
394
Parent = _cu.UsingScope
399
public override bool EnterModule(AST.Module node)
401
HandleNamespaceDeclaration(node.Namespace);
402
if (!_firstModule && node.Members.Count > 0) {
403
EnterTypeDefinition(node, ClassType.Module);
405
_firstModule = false;
406
return base.EnterModule(node);
409
private void EnterTypeDefinition(AST.TypeDefinition node, ClassType classType)
411
//LoggingService.Debug("Enter " + node.GetType().Name + " (" + node.FullName + ")");
412
foreach (AST.Attribute att in node.Attributes) {
413
if (att.Name == "Boo.Lang.ModuleAttribute")
414
classType = ClassType.Module;
416
DomRegion region = GetClientRegion(node);
417
DefaultClass c = new DefaultClass(_cu, classType, GetModifier(node), region, OuterClass);
418
c.FullyQualifiedName = node.FullName;
419
if (_currentClass.Count > 0)
420
_currentClass.Peek().InnerClasses.Add(c);
423
_currentClass.Push(c);
424
ConvertAttributes(node, c);
425
ConvertTemplates(node, c);
426
if (node.BaseTypes != null) {
427
foreach (AST.TypeReference r in node.BaseTypes) {
428
c.BaseTypes.Add(CreateReturnType(r));
433
public override void LeaveClassDefinition(AST.ClassDefinition node)
435
LeaveTypeDefinition(node);
436
base.LeaveClassDefinition(node);
439
public override void LeaveInterfaceDefinition(AST.InterfaceDefinition node)
441
LeaveTypeDefinition(node);
442
base.LeaveInterfaceDefinition(node);
445
public override void LeaveEnumDefinition(AST.EnumDefinition node)
447
LeaveTypeDefinition(node);
448
base.LeaveEnumDefinition(node);
451
public override void LeaveModule(AST.Module node)
453
if (_currentClass.Count != 0) LeaveTypeDefinition(node);
454
base.LeaveModule(node);
457
private void LeaveTypeDefinition(AST.TypeDefinition node)
459
DefaultClass c = _currentClass.Pop();
460
foreach (AST.Attribute att in node.Attributes) {
461
if (att.Name == "System.Reflection.DefaultMemberAttribute" && att.Arguments.Count == 1) {
462
AST.StringLiteralExpression sle = att.Arguments[0] as AST.StringLiteralExpression;
464
foreach (DefaultProperty p in c.Properties) {
465
if (p.Name == sle.Value) {
472
//LoggingService.Debug("Leave "+node.GetType().Name+" "+node.FullName+" (Class = "+c.FullyQualifiedName+")");
475
public override void OnMethod(AST.Method node)
477
//LoggingService.Debug("Method: " + node.FullName + " (" + node.Modifiers + ")");
478
DefaultMethod method = new DefaultMethod(node.Name, null, GetModifier(node), GetRegion(node), GetClientRegion(node), OuterClass);
480
foreach (AST.Attribute a in node.Attributes) {
481
if (a.Name == "Extension" || a.Name == "Boo.Lang.Extension"
482
|| a.Name == "ExtensionAttribute" || a.Name == "Boo.Lang.ExtensionAttribute")
484
method.IsExtensionMethod = true;
488
ConvertAttributes(node, method);
489
ConvertTemplates(node, method);
490
// return type must be assigned AFTER ConvertTemplates
491
method.ReturnType = CreateReturnType(node, method);
492
ConvertParameters(node.Parameters, method);
493
_currentClass.Peek().Methods.Add(method);
494
method.UserData = node;
497
public override void OnConstructor(AST.Constructor node)
499
if (node.IsSynthetic && node.Parameters.Count == 0) return;
500
Constructor ctor = new Constructor(GetModifier(node), GetRegion(node), GetClientRegion(node), OuterClass);
501
ConvertAttributes(node, ctor);
502
ConvertParameters(node.Parameters, ctor);
503
_currentClass.Peek().Methods.Add(ctor);
504
ctor.UserData = node;
507
public override void OnEnumMember(AST.EnumMember node)
509
DefaultField field = new DefaultField(OuterClass.DefaultReturnType, node.Name, ModifierEnum.Const | ModifierEnum.Public, GetRegion(node), OuterClass);
510
ConvertAttributes(node, field);
511
OuterClass.Fields.Add(field);
514
public override void OnField(AST.Field node)
516
DefaultField field = new DefaultField(CreateReturnType(node), node.Name, GetModifier(node), GetRegion(node), OuterClass);
517
ConvertAttributes(node, field);
518
OuterClass.Fields.Add(field);
521
public override void OnEvent(AST.Event node)
523
DomRegion region = GetRegion(node);
524
DefaultEvent e = new DefaultEvent(node.Name, CreateReturnType(node.Type), GetModifier(node), region, region, OuterClass);
525
ConvertAttributes(node, e);
526
OuterClass.Events.Add(e);
529
public override void OnProperty(AST.Property node)
531
DefaultProperty property = new DefaultProperty(node.Name, CreateReturnType(node), GetModifier(node), GetRegion(node), GetClientRegion(node), OuterClass);
532
ConvertAttributes(node, property);
533
ConvertParameters(node.Parameters, property);
534
if (node.Getter != null && node.Getter.Body != null) {
535
property.GetterRegion = GetClientRegion(node.Getter);
537
if (node.Setter != null && node.Setter.Body != null) {
538
property.SetterRegion = GetClientRegion(node.Setter);
540
property.IsIndexer = (node.Name == "self");
541
OuterClass.Properties.Add(property);
542
property.UserData = node;
545
string PrependCurrentNamespace(string name)
547
if (string.IsNullOrEmpty(_cu.UsingScope.NamespaceName))
550
return _cu.UsingScope.NamespaceName + "." + name;