PageRenderTime 70ms CodeModel.GetById 17ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 1ms

/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TypeSystemAstBuilder.cs

http://github.com/icsharpcode/ILSpy
C# | 981 lines | 798 code | 79 blank | 104 comment | 267 complexity | f0434825ad05db0a40857671dc7c926d MD5 | raw file
  1// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
  2// 
  3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4// software and associated documentation files (the "Software"), to deal in the Software
  5// without restriction, including without limitation the rights to use, copy, modify, merge,
  6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7// to whom the Software is furnished to do so, subject to the following conditions:
  8// 
  9// The above copyright notice and this permission notice shall be included in all copies or
 10// substantial portions of the Software.
 11// 
 12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 17// DEALINGS IN THE SOFTWARE.
 18
 19using System;
 20using System.Collections.Generic;
 21using System.Diagnostics;
 22using System.Linq;
 23using ICSharpCode.NRefactory.CSharp.Resolver;
 24using ICSharpCode.NRefactory.CSharp.TypeSystem;
 25using ICSharpCode.NRefactory.Semantics;
 26using ICSharpCode.NRefactory.TypeSystem;
 27using ICSharpCode.NRefactory.TypeSystem.Implementation;
 28using ICSharpCode.NRefactory.Utils;
 29
 30namespace ICSharpCode.NRefactory.CSharp.Refactoring
 31{
 32	/// <summary>
 33	/// Converts from type system to the C# AST.
 34	/// </summary>
 35	public class TypeSystemAstBuilder
 36	{
 37		readonly CSharpResolver resolver;
 38		
 39		#region Constructor
 40		/// <summary>
 41		/// Creates a new TypeSystemAstBuilder.
 42		/// </summary>
 43		/// <param name="resolver">
 44		/// A resolver initialized for the position where the type will be inserted.
 45		/// </param>
 46		public TypeSystemAstBuilder(CSharpResolver resolver)
 47		{
 48			if (resolver == null)
 49				throw new ArgumentNullException("resolver");
 50			this.resolver = resolver;
 51			InitProperties();
 52		}
 53		
 54		/// <summary>
 55		/// Creates a new TypeSystemAstBuilder.
 56		/// </summary>
 57		public TypeSystemAstBuilder()
 58		{
 59			InitProperties();
 60		}
 61		#endregion
 62		
 63		#region Properties
 64		void InitProperties()
 65		{
 66			this.ShowAccessibility = true;
 67			this.ShowModifiers = true;
 68			this.ShowBaseTypes = true;
 69			this.ShowTypeParameters = true;
 70			this.ShowTypeParameterConstraints = true;
 71			this.ShowParameterNames = true;
 72			this.ShowConstantValues = true;
 73			this.UseAliases = true;
 74		}
 75		
 76		/// <summary>
 77		/// Specifies whether the ast builder should add annotations to type references.
 78		/// The default value is <c>false</c>.
 79		/// </summary>
 80		public bool AddAnnotations { get; set; }
 81		
 82		/// <summary>
 83		/// Controls the accessibility modifiers are shown.
 84		/// The default value is <c>true</c>.
 85		/// </summary>
 86		public bool ShowAccessibility { get; set; }
 87		
 88		/// <summary>
 89		/// Controls the non-accessibility modifiers are shown.
 90		/// The default value is <c>true</c>.
 91		/// </summary>
 92		public bool ShowModifiers { get; set; }
 93		
 94		/// <summary>
 95		/// Controls whether base type references are shown.
 96		/// The default value is <c>true</c>.
 97		/// </summary>
 98		public bool ShowBaseTypes { get; set; }
 99		
100		/// <summary>
101		/// Controls whether type parameter declarations are shown.
102		/// The default value is <c>true</c>.
103		/// </summary>
104		public bool ShowTypeParameters { get; set; }
105		
106		/// <summary>
107		/// Controls whether constraints on type parameter declarations are shown.
108		/// Has no effect if ShowTypeParameters is false.
109		/// The default value is <c>true</c>.
110		/// </summary>
111		public bool ShowTypeParameterConstraints { get; set; }
112		
113		/// <summary>
114		/// Controls whether the names of parameters are shown.
115		/// The default value is <c>true</c>.
116		/// </summary>
117		public bool ShowParameterNames { get; set; }
118		
119		/// <summary>
120		/// Controls whether to show default values of optional parameters, and the values of constant fields.
121		/// The default value is <c>true</c>.
122		/// </summary>
123		public bool ShowConstantValues { get; set; }
124		
125		/// <summary>
126		/// Controls whether to use fully-qualified type names or short type names.
127		/// The default value is <c>false</c>.
128		/// </summary>
129		public bool AlwaysUseShortTypeNames { get; set; }
130		
131		/// <summary>
132		/// Controls whether to generate a body that throws a <c>System.NotImplementedException</c>.
133		/// The default value is <c>false</c>.
134		/// </summary>
135		public bool GenerateBody { get; set; }
136		
137		/// <summary>
138		/// Controls whether to generate custom events.
139		/// The default value is <c>false</c>.
140		/// </summary>
141		public bool UseCustomEvents { get; set; }
142
143		/// <summary>
144		/// Controls if unbound type argument names are inserted in the ast or not.
145		/// The default value is <c>false</c>.
146		/// </summary>
147		public bool ConvertUnboundTypeArguments { get; set;}
148
149		/// <summary>
150		/// Controls if aliases should be used inside the type name or not.
151		/// The default value is <c>true</c>.
152		/// </summary>
153		public bool UseAliases { get; set;}
154		#endregion
155		
156		#region Convert Type
157		public AstType ConvertType(IType type)
158		{
159			if (type == null)
160				throw new ArgumentNullException("type");
161			AstType astType = ConvertTypeHelper(type);
162			if (AddAnnotations)
163				astType.AddAnnotation(type);
164			return astType;
165		}
166		
167		public AstType ConvertType(FullTypeName fullTypeName)
168		{
169			if (resolver != null) {
170				foreach (var asm in resolver.Compilation.Assemblies) {
171					var def = asm.GetTypeDefinition(fullTypeName);
172					if (def != null) {
173						return ConvertType(def);
174					}
175				}
176			}
177			TopLevelTypeName top = fullTypeName.TopLevelTypeName;
178			AstType type;
179			if (string.IsNullOrEmpty(top.Namespace)) {
180				type = new SimpleType(top.Name);
181			} else {
182				type = new SimpleType(top.Namespace).MemberType(top.Name);
183			}
184			for (int i = 0; i < fullTypeName.NestingLevel; i++) {
185				type = type.MemberType(fullTypeName.GetNestedTypeName(i));
186			}
187			return type;
188		}
189		
190		AstType ConvertTypeHelper(IType type)
191		{
192			TypeWithElementType typeWithElementType = type as TypeWithElementType;
193			if (typeWithElementType != null) {
194				if (typeWithElementType is PointerType) {
195					return ConvertType(typeWithElementType.ElementType).MakePointerType();
196				} else if (typeWithElementType is ArrayType) {
197					return ConvertType(typeWithElementType.ElementType).MakeArrayType(((ArrayType)type).Dimensions);
198				} else {
199					// e.g. ByReferenceType; not supported as type in C#
200					return ConvertType(typeWithElementType.ElementType);
201				}
202			}
203			ParameterizedType pt = type as ParameterizedType;
204			if (pt != null) {
205				if (pt.Name == "Nullable" && pt.Namespace == "System" && pt.TypeParameterCount == 1) {
206					return ConvertType(pt.TypeArguments[0]).MakeNullableType();
207				}
208				return ConvertTypeHelper(pt.GetDefinition(), pt.TypeArguments);
209			}
210			ITypeDefinition typeDef = type as ITypeDefinition;
211			if (typeDef != null) {
212				if (typeDef.TypeParameterCount > 0) {
213					// Unbound type
214					IType[] typeArguments = new IType[typeDef.TypeParameterCount];
215					for (int i = 0; i < typeArguments.Length; i++) {
216						typeArguments[i] = SpecialType.UnboundTypeArgument;
217					}
218					return ConvertTypeHelper(typeDef, typeArguments);
219				} else {
220					return ConvertTypeHelper(typeDef, EmptyList<IType>.Instance);
221				}
222			}
223			return new SimpleType(type.Name);
224		}
225		
226		AstType ConvertTypeHelper(ITypeDefinition typeDef, IList<IType> typeArguments)
227		{
228			Debug.Assert(typeArguments.Count >= typeDef.TypeParameterCount);
229			
230			string keyword = KnownTypeReference.GetCSharpNameByTypeCode(typeDef.KnownTypeCode);
231			if (keyword != null)
232				return new PrimitiveType(keyword);
233			
234			// The number of type parameters belonging to outer classes
235			int outerTypeParameterCount;
236			if (typeDef.DeclaringType != null)
237				outerTypeParameterCount = typeDef.DeclaringType.TypeParameterCount;
238			else
239				outerTypeParameterCount = 0;
240			
241			if (resolver != null) {
242				// Look if there's an alias to the target type
243				if (UseAliases) {
244					for (ResolvedUsingScope usingScope = resolver.CurrentUsingScope; usingScope != null; usingScope = usingScope.Parent) {
245						foreach (var pair in usingScope.UsingAliases) {
246							if (pair.Value is TypeResolveResult) {
247								if (TypeMatches(pair.Value.Type, typeDef, typeArguments))
248									return new SimpleType(pair.Key);
249							}
250						}
251					}
252				}
253				
254				IList<IType> localTypeArguments;
255				if (typeDef.TypeParameterCount > outerTypeParameterCount) {
256					localTypeArguments = new IType[typeDef.TypeParameterCount - outerTypeParameterCount];
257					for (int i = 0; i < localTypeArguments.Count; i++) {
258						localTypeArguments[i] = typeArguments[outerTypeParameterCount + i];
259					}
260				} else {
261					localTypeArguments = EmptyList<IType>.Instance;
262				}
263				ResolveResult rr = resolver.ResolveSimpleName(typeDef.Name, localTypeArguments);
264				TypeResolveResult trr = rr as TypeResolveResult;
265				if (trr != null || (localTypeArguments.Count == 0 && resolver.IsVariableReferenceWithSameType(rr, typeDef.Name, out trr))) {
266					if (!trr.IsError && TypeMatches(trr.Type, typeDef, typeArguments)) {
267						// We can use the short type name
268						SimpleType shortResult = new SimpleType(typeDef.Name);
269						AddTypeArguments(shortResult, typeDef, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount);
270						return shortResult;
271					}
272				}
273			}
274			
275			if (AlwaysUseShortTypeNames) {
276				var shortResult = new SimpleType(typeDef.Name);
277				AddTypeArguments(shortResult, typeDef, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount);
278				return shortResult;
279			}
280			MemberType result = new MemberType();
281			if (typeDef.DeclaringTypeDefinition != null) {
282				// Handle nested types
283				result.Target = ConvertTypeHelper(typeDef.DeclaringTypeDefinition, typeArguments);
284			} else {
285				// Handle top-level types
286				if (string.IsNullOrEmpty(typeDef.Namespace)) {
287					result.Target = new SimpleType("global");
288					result.IsDoubleColon = true;
289				} else {
290					result.Target = ConvertNamespace(typeDef.Namespace);
291				}
292			}
293			result.MemberName = typeDef.Name;
294			AddTypeArguments(result, typeDef, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount);
295			return result;
296		}
297		
298		/// <summary>
299		/// Gets whether 'type' is the same as 'typeDef' parameterized with the given type arguments.
300		/// </summary>
301		bool TypeMatches(IType type, ITypeDefinition typeDef, IList<IType> typeArguments)
302		{
303			if (typeDef.TypeParameterCount == 0) {
304				return typeDef.Equals(type);
305			} else {
306				if (!typeDef.Equals(type.GetDefinition()))
307					return false;
308				ParameterizedType pt = type as ParameterizedType;
309				if (pt == null) {
310					return typeArguments.All(t => t.Kind == TypeKind.UnboundTypeArgument);
311				}
312				var ta = pt.TypeArguments;
313				for (int i = 0; i < ta.Count; i++) {
314					if (!ta[i].Equals(typeArguments[i]))
315						return false;
316				}
317				return true;
318			}
319		}
320		
321		/// <summary>
322		/// Adds type arguments to the result type.
323		/// </summary>
324		/// <param name="result">The result AST node (a SimpleType or MemberType)</param>
325		/// <param name="typeDef">The type definition that owns the type parameters</param>
326		/// <param name="typeArguments">The list of type arguments</param>
327		/// <param name="startIndex">Index of first type argument to add</param>
328		/// <param name="endIndex">Index after last type argument to add</param>
329		void AddTypeArguments(AstType result, ITypeDefinition typeDef, IList<IType> typeArguments, int startIndex, int endIndex)
330		{
331			Debug.Assert(endIndex <= typeDef.TypeParameterCount);
332			for (int i = startIndex; i < endIndex; i++) {
333				if (ConvertUnboundTypeArguments && typeArguments[i].Kind == TypeKind.UnboundTypeArgument) {
334					result.AddChild(new SimpleType(typeDef.TypeParameters[i].Name), Roles.TypeArgument);
335				} else {
336					result.AddChild(ConvertType(typeArguments[i]), Roles.TypeArgument);
337				}
338			}
339		}
340		
341		public AstType ConvertNamespace(string namespaceName)
342		{
343			if (resolver != null) {
344				// Look if there's an alias to the target namespace
345				if (UseAliases) {
346					for (ResolvedUsingScope usingScope = resolver.CurrentUsingScope; usingScope != null; usingScope = usingScope.Parent) {
347						foreach (var pair in usingScope.UsingAliases) {
348							NamespaceResolveResult nrr = pair.Value as NamespaceResolveResult;
349							if (nrr != null && nrr.NamespaceName == namespaceName)
350								return new SimpleType(pair.Key);
351						}
352					}
353				}
354			}
355			
356			int pos = namespaceName.LastIndexOf('.');
357			if (pos < 0) {
358				if (IsValidNamespace(namespaceName)) {
359					return new SimpleType(namespaceName);
360				} else {
361					return new MemberType {
362						Target = new SimpleType("global"),
363						IsDoubleColon = true,
364						MemberName = namespaceName
365					};
366				}
367			} else {
368				string parentNamespace = namespaceName.Substring(0, pos);
369				string localNamespace = namespaceName.Substring(pos + 1);
370				return new MemberType {
371					Target = ConvertNamespace(parentNamespace),
372					MemberName = localNamespace
373				};
374			}
375		}
376		
377		bool IsValidNamespace(string firstNamespacePart)
378		{
379			if (resolver == null)
380				return true; // just assume namespaces are valid if we don't have a resolver
381			NamespaceResolveResult nrr = resolver.ResolveSimpleName(firstNamespacePart, EmptyList<IType>.Instance) as NamespaceResolveResult;
382			return nrr != null && !nrr.IsError && nrr.NamespaceName == firstNamespacePart;
383		}
384		#endregion
385		
386		#region Convert Attribute
387		public Attribute ConvertAttribute(IAttribute attribute)
388		{
389			Attribute attr = new Attribute();
390			attr.Type = ConvertType(attribute.AttributeType);
391			SimpleType st = attr.Type as SimpleType;
392			MemberType mt = attr.Type as MemberType;
393			if (st != null && st.Identifier.EndsWith("Attribute", StringComparison.Ordinal)) {
394				st.Identifier = st.Identifier.Substring(0, st.Identifier.Length - 9);
395			} else if (mt != null && mt.MemberName.EndsWith("Attribute", StringComparison.Ordinal)) {
396				mt.MemberName = mt.MemberName.Substring(0, mt.MemberName.Length - 9);
397			}
398			foreach (ResolveResult arg in attribute.PositionalArguments) {
399				attr.Arguments.Add(ConvertConstantValue(arg));
400			}
401			foreach (var pair in attribute.NamedArguments) {
402				attr.Arguments.Add(new NamedExpression(pair.Key.Name, ConvertConstantValue(pair.Value)));
403			}
404			return attr;
405		}
406		#endregion
407		
408		#region Convert Constant Value
409		public Expression ConvertConstantValue(ResolveResult rr)
410		{
411			if (rr == null)
412				throw new ArgumentNullException("rr");
413			if (rr is ConversionResolveResult) {
414				// unpack ConversionResolveResult if necessary
415				// (e.g. a boxing conversion or string->object reference conversion)
416				rr = ((ConversionResolveResult)rr).Input;
417			}
418			
419			if (rr is TypeOfResolveResult) {
420				return new TypeOfExpression(ConvertType(rr.Type));
421			} else if (rr is ArrayCreateResolveResult) {
422				ArrayCreateResolveResult acrr = (ArrayCreateResolveResult)rr;
423				ArrayCreateExpression ace = new ArrayCreateExpression();
424				ace.Type = ConvertType(acrr.Type);
425				ComposedType composedType = ace.Type as ComposedType;
426				if (composedType != null) {
427					composedType.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers);
428					if (!composedType.HasNullableSpecifier && composedType.PointerRank == 0)
429						ace.Type = composedType.BaseType;
430				}
431				
432				if (acrr.SizeArguments != null && acrr.InitializerElements == null) {
433					ace.AdditionalArraySpecifiers.FirstOrNullObject().Remove();
434					ace.Arguments.AddRange(acrr.SizeArguments.Select(ConvertConstantValue));
435				}
436				if (acrr.InitializerElements != null) {
437					ArrayInitializerExpression initializer = new ArrayInitializerExpression();
438					initializer.Elements.AddRange(acrr.InitializerElements.Select(ConvertConstantValue));
439					ace.Initializer = initializer;
440				}
441				return ace;
442			} else if (rr.IsCompileTimeConstant) {
443				return ConvertConstantValue(rr.Type, rr.ConstantValue);
444			} else {
445				return new ErrorExpression();
446			}
447		}
448		
449		public Expression ConvertConstantValue(IType type, object constantValue)
450		{
451			if (type == null)
452				throw new ArgumentNullException("type");
453			if (constantValue == null) {
454				if (type.IsReferenceType == true)
455					return new NullReferenceExpression();
456				else
457					return new DefaultValueExpression(ConvertType(type));
458			} else if (type.Kind == TypeKind.Enum) {
459				return ConvertEnumValue(type, (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, constantValue, false));
460			} else {
461				return new PrimitiveExpression(constantValue);
462			}
463		}
464		
465		bool IsFlagsEnum(ITypeDefinition type)
466		{
467			IType flagsAttributeType = type.Compilation.FindType(typeof(System.FlagsAttribute));
468			return type.GetAttribute(flagsAttributeType) != null;
469		}
470		
471		Expression ConvertEnumValue(IType type, long val)
472		{
473			ITypeDefinition enumDefinition = type.GetDefinition();
474			TypeCode enumBaseTypeCode = ReflectionHelper.GetTypeCode(enumDefinition.EnumUnderlyingType);
475			foreach (IField field in enumDefinition.Fields) {
476				if (field.IsConst && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.ConstantValue, false), val))
477					return ConvertType(type).Member(field.Name);
478			}
479			if (IsFlagsEnum(enumDefinition)) {
480				long enumValue = val;
481				Expression expr = null;
482				long negatedEnumValue = ~val;
483				// limit negatedEnumValue to the appropriate range
484				switch (enumBaseTypeCode) {
485					case TypeCode.Byte:
486					case TypeCode.SByte:
487						negatedEnumValue &= byte.MaxValue;
488						break;
489					case TypeCode.Int16:
490					case TypeCode.UInt16:
491						negatedEnumValue &= ushort.MaxValue;
492						break;
493					case TypeCode.Int32:
494					case TypeCode.UInt32:
495						negatedEnumValue &= uint.MaxValue;
496						break;
497				}
498				Expression negatedExpr = null;
499				foreach (IField field in enumDefinition.Fields.Where(fld => fld.IsConst)) {
500					long fieldValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.ConstantValue, false);
501					if (fieldValue == 0)
502						continue;	// skip None enum value
503
504					if ((fieldValue & enumValue) == fieldValue) {
505						var fieldExpression = ConvertType(type).Member(field.Name);
506						if (expr == null)
507							expr = fieldExpression;
508						else
509							expr = new BinaryOperatorExpression(expr, BinaryOperatorType.BitwiseOr, fieldExpression);
510
511						enumValue &= ~fieldValue;
512					}
513					if ((fieldValue & negatedEnumValue) == fieldValue) {
514						var fieldExpression = ConvertType(type).Member(field.Name);
515						if (negatedExpr == null)
516							negatedExpr = fieldExpression;
517						else
518							negatedExpr = new BinaryOperatorExpression(negatedExpr, BinaryOperatorType.BitwiseOr, fieldExpression);
519
520						negatedEnumValue &= ~fieldValue;
521					}
522				}
523				if (enumValue == 0 && expr != null) {
524					if (!(negatedEnumValue == 0 && negatedExpr != null && negatedExpr.Descendants.Count() < expr.Descendants.Count())) {
525						return expr;
526					}
527				}
528				if (negatedEnumValue == 0 && negatedExpr != null) {
529					return new UnaryOperatorExpression(UnaryOperatorType.BitNot, negatedExpr);
530				}
531			}
532			return new PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(type));
533		}
534		
535		#endregion
536		
537		#region Convert Parameter
538		public ParameterDeclaration ConvertParameter(IParameter parameter)
539		{
540			if (parameter == null)
541				throw new ArgumentNullException("parameter");
542			ParameterDeclaration decl = new ParameterDeclaration();
543			if (parameter.IsRef) {
544				decl.ParameterModifier = ParameterModifier.Ref;
545			} else if (parameter.IsOut) {
546				decl.ParameterModifier = ParameterModifier.Out;
547			} else if (parameter.IsParams) {
548				decl.ParameterModifier = ParameterModifier.Params;
549			}
550			decl.Type = ConvertType(parameter.Type);
551			if (this.ShowParameterNames) {
552				decl.Name = parameter.Name;
553			}
554			if (parameter.IsOptional && this.ShowConstantValues) {
555				decl.DefaultExpression = ConvertConstantValue(parameter.Type, parameter.ConstantValue);
556			}
557			return decl;
558		}
559		#endregion
560		
561		#region Convert Entity
562		public AstNode ConvertSymbol(ISymbol symbol)
563		{
564			if (symbol == null)
565				throw new ArgumentNullException("symbol");
566			switch (symbol.SymbolKind) {
567				case SymbolKind.Namespace:
568					return ConvertNamespaceDeclaration((INamespace)symbol);
569				case SymbolKind.Variable:
570					return ConvertVariable((IVariable)symbol);
571				case SymbolKind.Parameter:
572					return ConvertParameter((IParameter)symbol);
573				case SymbolKind.TypeParameter:
574					return ConvertTypeParameter((ITypeParameter)symbol);
575				default:
576					IEntity entity = symbol as IEntity;
577					if (entity != null)
578						return ConvertEntity(entity);
579					throw new ArgumentException("Invalid value for SymbolKind: " + symbol.SymbolKind);
580			}
581		}
582		
583		public EntityDeclaration ConvertEntity(IEntity entity)
584		{
585			if (entity == null)
586				throw new ArgumentNullException("entity");
587			switch (entity.SymbolKind) {
588				case SymbolKind.TypeDefinition:
589					return ConvertTypeDefinition((ITypeDefinition)entity);
590				case SymbolKind.Field:
591					return ConvertField((IField)entity);
592				case SymbolKind.Property:
593					return ConvertProperty((IProperty)entity);
594				case SymbolKind.Indexer:
595					return ConvertIndexer((IProperty)entity);
596				case SymbolKind.Event:
597					return ConvertEvent((IEvent)entity);
598				case SymbolKind.Method:
599					return ConvertMethod((IMethod)entity);
600				case SymbolKind.Operator:
601					return ConvertOperator((IMethod)entity);
602				case SymbolKind.Constructor:
603					return ConvertConstructor((IMethod)entity);
604				case SymbolKind.Destructor:
605					return ConvertDestructor((IMethod)entity);
606				case SymbolKind.Accessor:
607					IMethod accessor = (IMethod)entity;
608					return ConvertAccessor(accessor, accessor.AccessorOwner != null ? accessor.AccessorOwner.Accessibility : Accessibility.None);
609				default:
610					throw new ArgumentException("Invalid value for SymbolKind: " + entity.SymbolKind);
611			}
612		}
613		
614		EntityDeclaration ConvertTypeDefinition(ITypeDefinition typeDefinition)
615		{
616			Modifiers modifiers = Modifiers.None;
617			if (this.ShowAccessibility) {
618				modifiers |= ModifierFromAccessibility(typeDefinition.Accessibility);
619			}
620			if (this.ShowModifiers) {
621				if (typeDefinition.IsStatic) {
622					modifiers |= Modifiers.Static;
623				} else if (typeDefinition.IsAbstract) {
624					modifiers |= Modifiers.Abstract;
625				} else if (typeDefinition.IsSealed) {
626					modifiers |= Modifiers.Sealed;
627				}
628				if (typeDefinition.IsShadowing) {
629					modifiers |= Modifiers.New;
630				}
631			}
632			
633			ClassType classType;
634			switch (typeDefinition.Kind) {
635				case TypeKind.Struct:
636					classType = ClassType.Struct;
637					modifiers &= ~Modifiers.Sealed;
638					break;
639				case TypeKind.Enum:
640					classType = ClassType.Enum;
641					modifiers &= ~Modifiers.Sealed;
642					break;
643				case TypeKind.Interface:
644					classType = ClassType.Interface;
645					modifiers &= ~Modifiers.Abstract;
646					break;
647				case TypeKind.Delegate:
648					IMethod invoke = typeDefinition.GetDelegateInvokeMethod();
649					if (invoke != null) {
650						return ConvertDelegate(invoke, modifiers);
651					} else {
652						goto default;
653					}
654				default:
655					classType = ClassType.Class;
656					break;
657			}
658			
659			var decl = new TypeDeclaration();
660			decl.ClassType = classType;
661			decl.Modifiers = modifiers;
662			decl.Name = typeDefinition.Name;
663			
664			int outerTypeParameterCount = (typeDefinition.DeclaringTypeDefinition == null) ? 0 : typeDefinition.DeclaringTypeDefinition.TypeParameterCount;
665			
666			if (this.ShowTypeParameters) {
667				foreach (ITypeParameter tp in typeDefinition.TypeParameters.Skip(outerTypeParameterCount)) {
668					decl.TypeParameters.Add(ConvertTypeParameter(tp));
669				}
670			}
671			
672			if (this.ShowBaseTypes) {
673				foreach (IType baseType in typeDefinition.DirectBaseTypes) {
674					decl.BaseTypes.Add(ConvertType(baseType));
675				}
676			}
677			
678			if (this.ShowTypeParameters && this.ShowTypeParameterConstraints) {
679				foreach (ITypeParameter tp in typeDefinition.TypeParameters) {
680					var constraint = ConvertTypeParameterConstraint(tp);
681					if (constraint != null)
682						decl.Constraints.Add(constraint);
683				}
684			}
685			return decl;
686		}
687		
688		DelegateDeclaration ConvertDelegate(IMethod invokeMethod, Modifiers modifiers)
689		{
690			ITypeDefinition d = invokeMethod.DeclaringTypeDefinition;
691			
692			DelegateDeclaration decl = new DelegateDeclaration();
693			decl.Modifiers = modifiers & ~Modifiers.Sealed;
694			decl.ReturnType = ConvertType(invokeMethod.ReturnType);
695			decl.Name = d.Name;
696			
697			if (this.ShowTypeParameters) {
698				foreach (ITypeParameter tp in d.TypeParameters) {
699					decl.TypeParameters.Add(ConvertTypeParameter(tp));
700				}
701			}
702			
703			foreach (IParameter p in invokeMethod.Parameters) {
704				decl.Parameters.Add(ConvertParameter(p));
705			}
706			
707			if (this.ShowTypeParameters && this.ShowTypeParameterConstraints) {
708				foreach (ITypeParameter tp in d.TypeParameters) {
709					var constraint = ConvertTypeParameterConstraint(tp);
710					if (constraint != null)
711						decl.Constraints.Add(constraint);
712				}
713			}
714			return decl;
715		}
716		
717		FieldDeclaration ConvertField(IField field)
718		{
719			FieldDeclaration decl = new FieldDeclaration();
720			if (ShowModifiers) {
721				Modifiers m = GetMemberModifiers(field);
722				if (field.IsConst) {
723					m &= ~Modifiers.Static;
724					m |= Modifiers.Const;
725				} else if (field.IsReadOnly) {
726					m |= Modifiers.Readonly;
727				} else if (field.IsVolatile) {
728					m |= Modifiers.Volatile;
729				}
730				decl.Modifiers = m;
731			}
732			decl.ReturnType = ConvertType(field.ReturnType);
733			Expression initializer = null;
734			if (field.IsConst && this.ShowConstantValues)
735				initializer = ConvertConstantValue(field.Type, field.ConstantValue);
736			decl.Variables.Add(new VariableInitializer(field.Name, initializer));
737			return decl;
738		}
739		
740		BlockStatement GenerateBodyBlock()
741		{
742			if (GenerateBody) {
743				return new BlockStatement {
744					new ThrowStatement(new ObjectCreateExpression(ConvertType(new TopLevelTypeName("System", "NotImplementedException", 0))))
745				};
746			} else {
747				return BlockStatement.Null;
748			}
749		}
750		
751		Accessor ConvertAccessor(IMethod accessor, Accessibility ownerAccessibility)
752		{
753			if (accessor == null)
754				return Accessor.Null;
755			Accessor decl = new Accessor();
756			if (this.ShowAccessibility && accessor.Accessibility != ownerAccessibility)
757				decl.Modifiers = ModifierFromAccessibility(accessor.Accessibility);
758			decl.Body = GenerateBodyBlock();
759			return decl;
760		}
761		
762		PropertyDeclaration ConvertProperty(IProperty property)
763		{
764			PropertyDeclaration decl = new PropertyDeclaration();
765			decl.Modifiers = GetMemberModifiers(property);
766			decl.ReturnType = ConvertType(property.ReturnType);
767			decl.Name = property.Name;
768			decl.Getter = ConvertAccessor(property.Getter, property.Accessibility);
769			decl.Setter = ConvertAccessor(property.Setter, property.Accessibility);
770			return decl;
771		}
772		
773		IndexerDeclaration ConvertIndexer(IProperty indexer)
774		{
775			IndexerDeclaration decl = new IndexerDeclaration();
776			decl.Modifiers = GetMemberModifiers(indexer);
777			decl.ReturnType = ConvertType(indexer.ReturnType);
778			foreach (IParameter p in indexer.Parameters) {
779				decl.Parameters.Add(ConvertParameter(p));
780			}
781			decl.Getter = ConvertAccessor(indexer.Getter, indexer.Accessibility);
782			decl.Setter = ConvertAccessor(indexer.Setter, indexer.Accessibility);
783			return decl;
784		}
785		
786		EntityDeclaration ConvertEvent(IEvent ev)
787		{
788			if (this.UseCustomEvents) {
789				CustomEventDeclaration decl = new CustomEventDeclaration();
790				decl.Modifiers = GetMemberModifiers(ev);
791				decl.ReturnType = ConvertType(ev.ReturnType);
792				decl.Name = ev.Name;
793				decl.AddAccessor    = ConvertAccessor(ev.AddAccessor, ev.Accessibility);
794				decl.RemoveAccessor = ConvertAccessor(ev.RemoveAccessor, ev.Accessibility);
795				return decl;
796			} else {
797				EventDeclaration decl = new EventDeclaration();
798				decl.Modifiers = GetMemberModifiers(ev);
799				decl.ReturnType = ConvertType(ev.ReturnType);
800				decl.Variables.Add(new VariableInitializer(ev.Name));
801				return decl;
802			}
803		}
804		
805		MethodDeclaration ConvertMethod(IMethod method)
806		{
807			MethodDeclaration decl = new MethodDeclaration();
808			decl.Modifiers = GetMemberModifiers(method);
809			if (method.IsAsync && ShowModifiers)
810				decl.Modifiers |= Modifiers.Async;
811			decl.ReturnType = ConvertType(method.ReturnType);
812			decl.Name = method.Name;
813			
814			if (this.ShowTypeParameters) {
815				foreach (ITypeParameter tp in method.TypeParameters) {
816					decl.TypeParameters.Add(ConvertTypeParameter(tp));
817				}
818			}
819			
820			foreach (IParameter p in method.Parameters) {
821				decl.Parameters.Add(ConvertParameter(p));
822			}
823			if (method.IsExtensionMethod && method.ReducedFrom == null && decl.Parameters.Any() && decl.Parameters.First().ParameterModifier == ParameterModifier.None)
824				decl.Parameters.First().ParameterModifier = ParameterModifier.This;
825			
826			if (this.ShowTypeParameters && this.ShowTypeParameterConstraints && !method.IsOverride && !method.IsExplicitInterfaceImplementation) {
827				foreach (ITypeParameter tp in method.TypeParameters) {
828					var constraint = ConvertTypeParameterConstraint(tp);
829					if (constraint != null)
830						decl.Constraints.Add(constraint);
831				}
832			}
833			decl.Body = GenerateBodyBlock();
834			return decl;
835		}
836		
837		EntityDeclaration ConvertOperator(IMethod op)
838		{
839			OperatorType? opType = OperatorDeclaration.GetOperatorType(op.Name);
840			if (opType == null)
841				return ConvertMethod(op);
842			
843			OperatorDeclaration decl = new OperatorDeclaration();
844			decl.Modifiers = GetMemberModifiers(op);
845			decl.OperatorType = opType.Value;
846			decl.ReturnType = ConvertType(op.ReturnType);
847			foreach (IParameter p in op.Parameters) {
848				decl.Parameters.Add(ConvertParameter(p));
849			}
850			decl.Body = GenerateBodyBlock();
851			return decl;
852		}
853		
854		ConstructorDeclaration ConvertConstructor(IMethod ctor)
855		{
856			ConstructorDeclaration decl = new ConstructorDeclaration();
857			decl.Modifiers = GetMemberModifiers(ctor);
858			if (ctor.DeclaringTypeDefinition != null)
859				decl.Name = ctor.DeclaringTypeDefinition.Name;
860			foreach (IParameter p in ctor.Parameters) {
861				decl.Parameters.Add(ConvertParameter(p));
862			}
863			decl.Body = GenerateBodyBlock();
864			return decl;
865		}
866		
867		DestructorDeclaration ConvertDestructor(IMethod dtor)
868		{
869			DestructorDeclaration decl = new DestructorDeclaration();
870			if (dtor.DeclaringTypeDefinition != null)
871				decl.Name = dtor.DeclaringTypeDefinition.Name;
872			decl.Body = GenerateBodyBlock();
873			return decl;
874		}
875		#endregion
876		
877		#region Convert Modifiers
878		public static Modifiers ModifierFromAccessibility(Accessibility accessibility)
879		{
880			switch (accessibility) {
881				case Accessibility.Private:
882					return Modifiers.Private;
883				case Accessibility.Public:
884					return Modifiers.Public;
885				case Accessibility.Protected:
886					return Modifiers.Protected;
887				case Accessibility.Internal:
888					return Modifiers.Internal;
889				case Accessibility.ProtectedOrInternal:
890				case Accessibility.ProtectedAndInternal:
891					return Modifiers.Protected | Modifiers.Internal;
892				default:
893					return Modifiers.None;
894			}
895		}
896		
897		Modifiers GetMemberModifiers(IMember member)
898		{
899			bool isInterfaceMember = member.DeclaringType.Kind == TypeKind.Interface;
900			Modifiers m = Modifiers.None;
901			if (this.ShowAccessibility && !isInterfaceMember) {
902				m |= ModifierFromAccessibility(member.Accessibility);
903			}
904			if (this.ShowModifiers) {
905				if (member.IsStatic) {
906					m |= Modifiers.Static;
907				} else {
908					if (member.IsAbstract && !isInterfaceMember)
909						m |= Modifiers.Abstract;
910					if (member.IsOverride)
911						m |= Modifiers.Override;
912					if (member.IsVirtual && !member.IsAbstract && !member.IsOverride)
913						m |= Modifiers.Virtual;
914					if (member.IsSealed)
915						m |= Modifiers.Sealed;
916				}
917				if (member.IsShadowing)
918					m |= Modifiers.New;
919			}
920			return m;
921		}
922		#endregion
923		
924		#region Convert Type Parameter
925		TypeParameterDeclaration ConvertTypeParameter(ITypeParameter tp)
926		{
927			TypeParameterDeclaration decl = new TypeParameterDeclaration();
928			decl.Variance = tp.Variance;
929			decl.Name = tp.Name;
930			return decl;
931		}
932		
933		Constraint ConvertTypeParameterConstraint(ITypeParameter tp)
934		{
935			if (!tp.HasDefaultConstructorConstraint && !tp.HasReferenceTypeConstraint && !tp.HasValueTypeConstraint && tp.DirectBaseTypes.All(IsObjectOrValueType)) {
936				return null;
937			}
938			Constraint c = new Constraint();
939			c.TypeParameter = new SimpleType (tp.Name);
940			if (tp.HasReferenceTypeConstraint) {
941				c.BaseTypes.Add(new PrimitiveType("class"));
942			} else if (tp.HasValueTypeConstraint) {
943				c.BaseTypes.Add(new PrimitiveType("struct"));
944			}
945			foreach (IType t in tp.DirectBaseTypes) {
946				if (!IsObjectOrValueType(t))
947					c.BaseTypes.Add(ConvertType(t));
948			}
949			if (tp.HasDefaultConstructorConstraint) {
950				c.BaseTypes.Add(new PrimitiveType("new"));
951			}
952			return c;
953		}
954		
955		static bool IsObjectOrValueType(IType type)
956		{
957			ITypeDefinition d = type.GetDefinition();
958			return d != null && (d.KnownTypeCode == KnownTypeCode.Object || d.KnownTypeCode == KnownTypeCode.ValueType);
959		}
960		#endregion
961		
962		#region Convert Variable
963		public VariableDeclarationStatement ConvertVariable(IVariable v)
964		{
965			VariableDeclarationStatement decl = new VariableDeclarationStatement();
966			decl.Modifiers = v.IsConst ? Modifiers.Const : Modifiers.None;
967			decl.Type = ConvertType(v.Type);
968			Expression initializer = null;
969			if (v.IsConst)
970				initializer = ConvertConstantValue(v.Type, v.ConstantValue);
971			decl.Variables.Add(new VariableInitializer(v.Name, initializer));
972			return decl;
973		}
974		#endregion
975		
976		NamespaceDeclaration ConvertNamespaceDeclaration(INamespace ns)
977		{
978			return new NamespaceDeclaration(ns.FullName);
979		}
980	}
981}