// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using Debugger; using Debugger.MetaData; using ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.Visitors; namespace ICSharpCode.NRefactory.Ast { public static class ExpressionExtensionMethods { public static Value Evaluate(this Expression expression, Process process) { return ExpressionEvaluator.Evaluate(expression, process); } static M SetStaticType(this M expr, DebugType type) where M: AstNode { expr.AddAnnotation(type); return expr; } public static DebugType GetStaticType(this AstNode expr) { return expr.Annotation(); } public static Expression Parenthesize(this Expression expr) { if (expr is IdentifierExpression || expr is MemberReferenceExpression || expr is IndexerExpression || expr is ParenthesizedExpression || expr is PrimitiveExpression) return expr; return new ParenthesizedExpression() { Expression = expr }; } public static Expression CastTo(this Expression expresion, DebugType castTo) { // No need to cast if (expresion.GetStaticType() == castTo) return expresion; if (expresion is PrimitiveExpression) { object val = ((PrimitiveExpression)expresion).Value; if (val != null && val.GetType().FullName == castTo.FullName) return expresion; } return new CastExpression() { Expression = expresion.Clone().Parenthesize(), Type = castTo.GetTypeReference() }; } public static Expression GetExpression(this DebugLocalVariableInfo locVar) { return new IdentifierExpression(locVar.Name).SetStaticType((DebugType)locVar.LocalType); } public static Expression GetExpression(this DebugParameterInfo par) { return new IdentifierExpression(par.Name).SetStaticType((DebugType)par.ParameterType); } public static UnaryOperatorExpression AppendDereference(this Expression expression) { return new UnaryOperatorExpression(UnaryOperatorType.Dereference, new ParenthesizedExpression() { Expression = expression }); } public static IndexerExpression AppendIndexer(this Expression expression, params int[] indices) { IndexerExpression indexerExpr = new IndexerExpression() { Target = Parenthesize(expression) }; var args = new List(); foreach(int index in indices) { args.Add(new PrimitiveExpression(index)); } //indexerExpr.Arguments = args; DebugType staticType = expression.GetStaticType(); if (staticType != null && staticType.IsArray) indexerExpr.SetStaticType((DebugType)staticType.GetElementType()); if (staticType != null && staticType.FullNameWithoutGenericArguments == typeof(List<>).FullName) indexerExpr.SetStaticType((DebugType)staticType.GetGenericArguments()[0]); return indexerExpr; } public static Expression AppendMemberReference(this Expression expresion, IDebugMemberInfo memberInfo, params Expression[] args) { Expression target; if (memberInfo.IsStatic) { target = new TypeReferenceExpression() { Type = memberInfo.DeclaringType.GetTypeReference() }; } else { target = CastTo(expresion, (DebugType)memberInfo.DeclaringType); } if (memberInfo is DebugFieldInfo) { if (args.Length > 0) throw new DebuggerException("No arguments expected for a field"); var mre = new MemberReferenceExpression() { Target = target, MemberName = memberInfo.Name }; return mre.SetStaticType(memberInfo.MemberType); } if (memberInfo is MethodInfo) { var mre = new MemberReferenceExpression() { Target = target, MemberName = memberInfo.Name }; var ie = new InvocationExpression() { Target = mre/*, Arguments = AddExplicitTypes((MethodInfo)memberInfo, args) */ }; return ie.SetStaticType(memberInfo.MemberType); } if (memberInfo is PropertyInfo) { PropertyInfo propInfo = (PropertyInfo)memberInfo; if (args.Length > 0) { if (memberInfo.Name != "Item") throw new DebuggerException("Arguments expected only for the Item property"); return (new IndexerExpression() { Target = target/*, Arguments = AddExplicitTypes(propInfo.GetGetMethod() ?? propInfo.GetSetMethod() , args) */ } ).SetStaticType(memberInfo.MemberType); } else { return (new MemberReferenceExpression() { Target = target, MemberName = memberInfo.Name }).SetStaticType(memberInfo.MemberType); } } throw new DebuggerException("Unknown member type " + memberInfo.GetType().FullName); } static List AddExplicitTypes(MethodInfo method, Expression[] args) { if (args.Length != method.GetParameters().Length) throw new DebuggerException("Incorrect number of arguments"); List typedArgs = new List(args.Length); for(int i = 0; i < args.Length; i++) { typedArgs.Add(CastTo(args[i], (DebugType)method.GetParameters()[i].ParameterType)); } return typedArgs; } public static bool Is(this Type type) { return type.FullName == typeof(T).FullName; } public static bool CanPromoteTo(this Type type, Type toType) { return ((DebugType)type).CanImplicitelyConvertTo(toType); } public static string PrettyPrint(this AstNode code) { if (code == null) return string.Empty; using (var sw = new StringWriter()) { OutputVisitor csOutVisitor = new OutputVisitor(sw, new CSharpFormattingPolicy()); code.AcceptVisitor(csOutVisitor, null); return sw.ToString(); } } public static AstType GetTypeReference(this Type type) { return new SimpleType(type.Name).SetStaticType((DebugType)type); // List arrayRanks = new List(); // while(type.IsArray) { // // C# uses reverse array order // arrayRanks.Add(type.GetArrayRank() - 1); // type = type.GetElementType(); // } // // int pointerNest = 0; // while(type.IsPointer) { // pointerNest++; // type = type.GetElementType(); // } // // if (type.IsArray) // throw new DebuggerException("C# does not support pointers to arrays"); // // string name = type.Name; // if (name.IndexOf('`') != -1) // name = name.Substring(0, name.IndexOf('`')); // if (!string.IsNullOrEmpty(type.Namespace)) // name = type.Namespace + "." + name; // // List genArgs = new List(); // // This inludes the generic arguments of the outter types // genArgs.AddRange(type.GetGenericArguments()); // if (type.DeclaringType != null) // genArgs.RemoveRange(0, type.DeclaringType.GetGenericArguments().Length); // List genTypeRefs = new List(); // foreach(Type genArg in genArgs) { // genTypeRefs.Add(genArg.GetTypeReference()); // } // // if (type.DeclaringType != null) { // var outterRef = type.DeclaringType.GetTypeReference(); // var innerRef = new ComposedType() { // PointerRank = pointerNest, // //ArraySpecifiers = arrayRanks.ConvertAll(r => new ArraySpecifier(r)), //// BaseType = new MemberType() { //// Target = outterRef, MemberName = name, TypeArguments = genTypeRefs } // }; // // return innerRef.SetStaticType((DebugType)type); // } else { // return (new ComposedType() { // PointerRank = pointerNest, // //ArraySpecifiers = arrayRanks.ConvertAll(r => new ArraySpecifier(r)), // BaseType = new SimpleType() { // Identifier = name, // /*TypeArguments = genTypeRefs*/ }}).SetStaticType((DebugType)type); // } } /// /// Converts tree into nested TypeReference/InnerClassTypeReference. /// Dotted names are split into separate nodes. /// It does not normalize generic arguments. /// // static AstType NormalizeTypeReference(this AstNode expr) // { // if (expr is IdentifierExpression) { // return new SimpleType() { // Identifier = ((IdentifierExpression)expr).Identifier/*, // TypeArguments = ((IdentifierExpression)expr).TypeArguments*/ // }; // } else if (expr is MemberReferenceExpression) { // var outter = NormalizeTypeReference(((MemberReferenceExpression)expr).Target); // return new MemberType() { Target = outter, // MemberName = ((MemberReferenceExpression)expr).MemberName/*, // TypeArguments = ((MemberReferenceExpression)expr).TypeArguments*/ }; // } else if (expr is TypeReferenceExpression) { // return NormalizeTypeReference(((TypeReferenceExpression)expr).Type); // } else if (expr is ComposedType) { // Frist - it is also TypeReference // var typeRef = (ComposedType)expr; // string[] names = null; // if (typeRef.BaseType is SimpleType) // names = (((SimpleType)typeRef.BaseType)).Identifier.Split('.'); // else // names = (((MemberType)typeRef.BaseType)).MemberName.Split('.'); // // var newRef = NormalizeTypeReference(typeRef.BaseType) as ComposedType; // foreach(string name in names) { // newRef = new ComposedType() { // BaseType = new SimpleType() { Identifier = name/*, TypeArguments = new List() */} // }; // } // //(((MemberType)newRef).TypeArguments as List).AddRange(typeRef.TypeArguments); // newRef.PointerRank = typeRef.PointerRank; // //newRef.ArraySpecifiers = typeRef.ArraySpecifiers; // return newRef; // } else if (expr is SimpleType) { // var typeRef = (SimpleType)expr; // string[] names = typeRef.Identifier.Split('.'); // if (names.Length == 1) // return typeRef; // AstType newRef = null; // foreach(string name in names) { // if (newRef == null) { // newRef = new SimpleType() { Identifier = name/*, TypeArguments = new List()*/ }; // } else { // newRef = new MemberType() { Target = newRef, MemberName = name/*, TypeArguments = new List() */}; // } // } // //((List)newRef.TypeArguments).AddRange(typeRef.TypeArguments); // //newRef.PointerNestingLevel = typeRef.PointerNestingLevel; // //newRef.RankSpecifier = typeRef.RankSpecifier; // return newRef; // } else if (expr is PrimitiveType) { // return (PrimitiveType)expr; // } else { // throw new EvaluateException(expr, "Type expected. {0} seen.", expr.GetType().FullName); // } // } // // static string GetNameWithArgCounts(AstType typeRef) // { // string name = string.Empty; // // if (typeRef is SimpleType) // { // name = ((SimpleType)typeRef).Identifier; // if (((SimpleType)typeRef).TypeArguments.Count() > 0) // name += "`" + ((SimpleType)typeRef).TypeArguments.Count().ToString(); // } // // if (typeRef is MemberType) { // name = ((MemberType)typeRef).MemberName; // return GetNameWithArgCounts(((MemberType)typeRef).Target) + "." + name; // } else { // return name; // } // } // public static DebugType ResolveType(this AstNode expr, Debugger.AppDomain appDomain) { return expr.GetStaticType(); // if (expr is AstType && expr.GetStaticType() != null) // return expr.GetStaticType(); // if (expr is TypeReferenceExpression && ((TypeReferenceExpression)expr).Type.GetStaticType() != null) // return ((TypeReferenceExpression)expr).Type.GetStaticType(); // // appDomain.Process.TraceMessage("Resolving {0}", expr.PrettyPrint()); // // var typeRef = NormalizeTypeReference(expr); // // List genTypeRefs = null; // if (typeRef is MemberType) { // //FIXME genTypeRefs = ((MemberType)typeRef).CombineToNormalTypeReference().TypeArguments as List; // } else { // if (typeRef is SimpleType) { // //genTypeRefs = ((SimpleType)typeRef).TypeArguments as List; // } // } // // List genArgs = new List(); // foreach(var genTypeRef in genTypeRefs) { // genArgs.Add(ResolveType(genTypeRef, appDomain)); // } // // return ResolveTypeInternal(typeRef, genArgs.ToArray(), appDomain); } /// /// For performance this is separate method. /// 'genArgs' should hold type for each generic parameter in 'typeRef'. /// // static DebugType ResolveTypeInternal(AstType typeRef, DebugType[] genArgs, Debugger.AppDomain appDomain) // { // DebugType type = null; // // if (typeRef is SimpleType) { // // Try to construct non-nested type // // If there are generic types up in the tree, it must be nested type // var simple = (SimpleType)typeRef; // // if (genArgs.Length == simple.TypeArguments.Count()) { // string name = GetNameWithArgCounts(simple); // type = DebugType.CreateFromNameOrNull(appDomain, name, null, genArgs); // } // } // // Try to construct nested type // if (type == null && typeRef is MemberType) { // var member = (MemberType)typeRef; // DebugType[] outterGenArgs = genArgs; // // Do not pass our generic arguments to outter type // Array.Resize(ref outterGenArgs, genArgs.Length - member.TypeArguments.Count()); // // DebugType outter = ResolveTypeInternal(member.Target, outterGenArgs, appDomain); // string nestedName = member.TypeArguments.Count() == 0 ? // member.MemberName : member.MemberName + "`" + member.TypeArguments.Count(); // type = DebugType.CreateFromNameOrNull(appDomain, nestedName, outter, genArgs); // } // // if (type == null) // throw new GetValueException("Can not resolve " + typeRef.PrettyPrint()); // // if (typeRef is ComposedType) { // // for(int i = 0; i < ((ComposedType)typeRef).PointerRank; i++) { // type = (DebugType)type.MakePointerType(); // } // if (((ComposedType)typeRef).ArraySpecifiers != null) { // var enumerator = ((ComposedType)typeRef).ArraySpecifiers.Reverse().GetEnumerator(); // while (enumerator.MoveNext()) { // type = (DebugType)type.MakeArrayType(enumerator.Current.Dimensions + 1); // } // } // } // return type; // } } }