// 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.Runtime.Remoting.Messaging; using System.Text; using System.Linq; using ICSharpCode.NRefactory; using ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.Visitors; namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver { /// /// Resolves expressions. /// sealed class ResolveVisitor : AbstractAstVisitor { NRefactoryResolver resolver; public ResolveVisitor(NRefactoryResolver resolver) { this.resolver = resolver; } ResolveResult CreateResolveResult(TypeReference reference) { return CreateResolveResult(TypeVisitor.CreateReturnType(reference, resolver)); } ResolveResult CreateResolveResult(Expression expression) { return CreateResolveResult(ResolveType(expression)); } ResolveResult CreateResolveResult(IReturnType resolvedType) { if (resolvedType == null) return null; else return new ResolveResult(resolver.CallingClass, resolver.CallingMember, resolvedType); } TypeResolveResult CreateTypeResolveResult(IReturnType resolvedType) { if (resolvedType == null) { return null; } else { IReturnType rt = resolvedType; while (rt != null && rt.IsArrayReturnType) { rt = rt.CastToArrayReturnType().ArrayElementType; } IClass resolvedClass = rt != null ? rt.GetUnderlyingClass() : null; return new TypeResolveResult(resolver.CallingClass, resolver.CallingMember, resolvedType, resolvedClass); } } MemberResolveResult CreateMemberResolveResult(IMember member) { if (member == null) return null; else return new MemberResolveResult(resolver.CallingClass, resolver.CallingMember, member); } readonly Dictionary cachedResults = new Dictionary(); public ResolveResult Resolve(Expression expression) { ResolveResult rr; if (!cachedResults.TryGetValue(expression, out rr)) { rr = (ResolveResult)expression.AcceptVisitor(this, null); if (rr != null) rr.Freeze(); cachedResults[expression] = rr; } return rr; } public IReturnType ResolveType(Expression expression) { ResolveResult rr = Resolve(expression); if (rr != null) return rr.ResolvedType; else return null; } public override object VisitAddressOfExpression(AddressOfExpression addressOfExpression, object data) { bool oldValue = resolver.allowMethodGroupResolveResult; resolver.allowMethodGroupResolveResult = true; object result = base.VisitAddressOfExpression(addressOfExpression, data); resolver.allowMethodGroupResolveResult = oldValue; return result; } public override object VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, object data) { return CreateResolveResult(new LambdaReturnType(anonymousMethodExpression, resolver)); } public override object VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression, object data) { if (arrayCreateExpression.IsImplicitlyTyped) { return CreateResolveResult(arrayCreateExpression.ArrayInitializer); } else { return CreateTypeResolveResult(TypeVisitor.CreateReturnType(arrayCreateExpression.CreateType, resolver)); } } public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data) { return CreateResolveResult(assignmentExpression.Left); } public override object VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression, object data) { if (resolver.CallingClass == null) { return null; } if (resolver.Language == SupportedLanguage.VBNet && IsInstanceConstructor(resolver.CallingMember)) { return new VBBaseOrThisReferenceInConstructorResolveResult( resolver.CallingClass, resolver.CallingMember, resolver.CallingClass.BaseType); } else { return new BaseResolveResult(resolver.CallingClass, resolver.CallingMember, resolver.CallingClass.BaseType); } } public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data) { switch (binaryOperatorExpression.Op) { case BinaryOperatorType.NullCoalescing: return CreateResolveResult(binaryOperatorExpression.Right); case BinaryOperatorType.DivideInteger: return CreateResolveResult(resolver.ProjectContent.SystemTypes.Int32); case BinaryOperatorType.Concat: return CreateResolveResult(resolver.ProjectContent.SystemTypes.String); case BinaryOperatorType.Equality: case BinaryOperatorType.InEquality: case BinaryOperatorType.ReferenceEquality: case BinaryOperatorType.ReferenceInequality: case BinaryOperatorType.LogicalAnd: case BinaryOperatorType.LogicalOr: case BinaryOperatorType.LessThan: case BinaryOperatorType.LessThanOrEqual: case BinaryOperatorType.GreaterThan: case BinaryOperatorType.GreaterThanOrEqual: return CreateResolveResult(resolver.ProjectContent.SystemTypes.Boolean); default: return CreateResolveResult(MemberLookupHelper.GetCommonType( resolver.ProjectContent, ResolveType(binaryOperatorExpression.Left), ResolveType(binaryOperatorExpression.Right))); } } public override object VisitCastExpression(CastExpression castExpression, object data) { return CreateResolveResult(castExpression.CastTo); } public override object VisitCheckedExpression(CheckedExpression checkedExpression, object data) { return CreateResolveResult(checkedExpression.Expression); } public override object VisitClassReferenceExpression(ClassReferenceExpression classReferenceExpression, object data) { if (resolver.CallingClass != null) return CreateResolveResult(resolver.CallingClass.DefaultReturnType); else return null; } public override object VisitCollectionInitializerExpression(CollectionInitializerExpression collectionInitializerExpression, object data) { // used for implicitly typed arrays if (collectionInitializerExpression.CreateExpressions.Count == 0) return null; IReturnType combinedRT = ResolveType(collectionInitializerExpression.CreateExpressions[0]); for (int i = 1; i < collectionInitializerExpression.CreateExpressions.Count; i++) { IReturnType rt = ResolveType(collectionInitializerExpression.CreateExpressions[i]); combinedRT = MemberLookupHelper.GetCommonType(resolver.ProjectContent, combinedRT, rt); } if (combinedRT == null) return null; return CreateResolveResult(new ArrayReturnType(resolver.ProjectContent, combinedRT, 1)); } public override object VisitConditionalExpression(ConditionalExpression conditionalExpression, object data) { return CreateResolveResult(MemberLookupHelper.GetCommonType( resolver.ProjectContent, ResolveType(conditionalExpression.TrueExpression), ResolveType(conditionalExpression.FalseExpression))); } public override object VisitConstructorInitializer(ConstructorInitializer constructorInitializer, object data) { return null; } public override object VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression, object data) { return CreateResolveResult(defaultValueExpression.TypeReference); } public override object VisitDirectionExpression(DirectionExpression directionExpression, object data) { return CreateResolveResult(new ReferenceReturnType(ResolveType(directionExpression.Expression))); } public override object VisitIdentifierExpression(IdentifierExpression identifierExpression, object data) { return resolver.ResolveIdentifier(identifierExpression, ExpressionContext.Default); } public override object VisitIndexerExpression(IndexerExpression indexerExpression, object data) { IReturnType target = ResolveType(indexerExpression.TargetObject); return CreateMemberResolveResult( GetIndexer(target, indexerExpression.Indexes) ); } IProperty GetIndexer(IReturnType target, List indexes) { if (target == null) return null; return MemberLookupHelper.FindOverload( target.GetProperties().Where((IProperty p) => p.IsIndexer).ToList(), indexes.Select(ResolveType).ToArray() ); } IProperty GetVisualBasicIndexer(InvocationExpression invocationExpression) { ResolveResult targetRR = Resolve(invocationExpression.TargetObject); if (targetRR != null) { // Visual Basic can call indexers in two ways: // collection(index) - use indexer // collection.Item(index) - use parametrized property if (invocationExpression.TargetObject is IdentifierExpression || invocationExpression.TargetObject is MemberReferenceExpression) { // only IdentifierExpression/MemberReferenceExpression can represent a parametrized property // - the check is necessary because collection.Items and collection.Item(index) both // resolve to the same property, but we want to use the default indexer for the second call in // collection.Item(index1)(index2) MemberResolveResult memberRR = targetRR as MemberResolveResult; if (memberRR != null) { IProperty p = memberRR.ResolvedMember as IProperty; if (p != null && p.Parameters.Count > 0) { // this is a parametrized property return p; } } } // not a parametrized property - try normal indexer return GetIndexer(targetRR.ResolvedType, invocationExpression.Arguments); } else { return null; } } public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data) { if (resolver.Language == SupportedLanguage.CSharp && resolver.CallingClass != null) { if (invocationExpression.TargetObject is ThisReferenceExpression) { // call to constructor return ResolveConstructorOverload(resolver.CallingClass, invocationExpression.Arguments); } else if (invocationExpression.TargetObject is BaseReferenceExpression) { return ResolveConstructorOverload(resolver.CallingClass.BaseType, invocationExpression.Arguments); } } ResolveResult rr = Resolve(invocationExpression.TargetObject); MixedResolveResult mixedRR = rr as MixedResolveResult; if (mixedRR != null) { rr = mixedRR.PrimaryResult; } MethodGroupResolveResult mgrr = rr as MethodGroupResolveResult; if (mgrr != null) { if (resolver.Language == SupportedLanguage.VBNet) { if (mgrr.Methods.All(mg => mg.Count == 0)) return CreateMemberResolveResult(GetVisualBasicIndexer(invocationExpression)); // IMethod empty = mgrr.GetMethodWithEmptyParameterList(); // if (empty != null) // return CreateMemberResolveResult(empty); } IReturnType[] argumentTypes = invocationExpression.Arguments.Select(ResolveType).ToArray(); MemberResolveResult firstResult = null; foreach (MethodGroup methodGroup in mgrr.Methods) { bool resultIsAcceptable; IMethod method; if (methodGroup.IsExtensionMethodGroup) { IReturnType[] extendedTypes = new IReturnType[argumentTypes.Length + 1]; extendedTypes[0] = mgrr.ContainingType; argumentTypes.CopyTo(extendedTypes, 1); method = MemberLookupHelper.FindOverload(methodGroup, extendedTypes, out resultIsAcceptable); } else { method = MemberLookupHelper.FindOverload(methodGroup, argumentTypes, out resultIsAcceptable); } MemberResolveResult result = CreateMemberResolveResult(method); if (result != null && methodGroup.IsExtensionMethodGroup) result.IsExtensionMethodCall = true; if (resultIsAcceptable) return result; if (firstResult == null) firstResult = result; } if (firstResult != null) { return firstResult; } else { return FallbackResolveMethod(invocationExpression, mgrr, argumentTypes); } } else if (rr != null && rr.ResolvedType != null) { IClass c = rr.ResolvedType.GetUnderlyingClass(); if (c != null && c.ClassType == ClassType.Delegate) { // We don't want to show "System.EventHandler.Invoke" in the tooltip // of "EventCall(this, EventArgs.Empty)", we just show the event/delegate for now // but for DelegateCall(params).* completion, we use the delegate's // return type instead of the delegate type itself IMethod method = rr.ResolvedType.GetMethods().FirstOrDefault(innerMethod => innerMethod.Name == "Invoke"); if (method != null) { return new DelegateCallResolveResult(rr, method); } } } if (resolver.Language == SupportedLanguage.VBNet) { return CreateMemberResolveResult(GetVisualBasicIndexer(invocationExpression)); } return resolver.CreateUnknownMethodResolveResult(invocationExpression); } ResolveResult FallbackResolveMethod(InvocationExpression invocation, MethodGroupResolveResult mgrr, IReturnType[] argumentTypes) { // method not found, let's try if we can find a method if we violate the // accessibility rules MemberReferenceExpression mre = invocation.TargetObject as MemberReferenceExpression; if (mre != null) { List methods = mgrr.ContainingType.GetMethods().Where(m => resolver.IsSameName(m.Name, mre.MemberName)).ToList(); bool resultIsAcceptable; IMethod result = MemberLookupHelper.FindOverload( methods, argumentTypes, out resultIsAcceptable); if (result != null) { return CreateMemberResolveResult(result); } } return resolver.CreateUnknownMethodResolveResult(invocation); } public override object VisitLambdaExpression(LambdaExpression lambdaExpression, object data) { return CreateResolveResult(new LambdaReturnType(lambdaExpression, resolver)); } public override object VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data) { IReturnType type; if (string.IsNullOrEmpty(memberReferenceExpression.MemberName)) { // NRefactory creates this "dummy" fieldReferenceExpression when it should // parse a primitive type name (int, short; Integer, Decimal) if (memberReferenceExpression.TargetObject is TypeReferenceExpression) { type = TypeVisitor.CreateReturnType(((TypeReferenceExpression)memberReferenceExpression.TargetObject).TypeReference, resolver); return CreateTypeResolveResult(type); } } ResolveResult targetRR = Resolve(memberReferenceExpression.TargetObject); if (targetRR == null) return null; type = GetType(targetRR); if (targetRR is NamespaceResolveResult) { return ResolveMemberInNamespace(((NamespaceResolveResult)targetRR).Name, memberReferenceExpression); } else if (type != null) { TypeResolveResult typeRR = targetRR as TypeResolveResult; if (typeRR != null && typeRR.ResolvedClass != null) { foreach (IClass c1 in typeRR.ResolvedClass.ClassInheritanceTree) { foreach (IClass c in c1.InnerClasses) { if (resolver.IsSameName(memberReferenceExpression.MemberName, c.Name) && c.TypeParameters.Count == memberReferenceExpression.TypeArguments.Count) { return CreateTypeResolveResult(resolver.ConstructType(c.DefaultReturnType, memberReferenceExpression.TypeArguments)); } } } } var memberRR = resolver.ResolveMember(type, memberReferenceExpression.MemberName, memberReferenceExpression.TypeArguments, NRefactoryResolver.IsInvoked(memberReferenceExpression), typeRR == null, // allow extension methods only for non-static method calls targetRR is BaseResolveResult ? (bool?)true : null // allow calling protected members using "base." ); // MethodGroupResolveResult mgRR = memberRR as MethodGroupResolveResult; // // if (mgRR == null) // mgRR = targetRR as MethodGroupResolveResult; // // if (mgRR != null && !resolver.allowMethodGroupResolveResult) // return CreateMemberResolveResult(mgRR.GetMethodWithEmptyParameterList()); return memberRR; } return null; } IReturnType GetType(ResolveResult targetRR) { if (targetRR.ResolvedType != null) return targetRR.ResolvedType; if (targetRR is MixedResolveResult && ((MixedResolveResult)targetRR).TypeResult != null) return ((MixedResolveResult)targetRR).TypeResult.ResolvedType; return null; } ResolveResult ResolveMemberInNamespace(string namespaceName, MemberReferenceExpression mre) { string combinedName; if (string.IsNullOrEmpty(namespaceName)) combinedName = mre.MemberName; else combinedName = namespaceName + "." + mre.MemberName; if (resolver.ProjectContent.NamespaceExists(combinedName)) { return new NamespaceResolveResult(resolver.CallingClass, resolver.CallingMember, combinedName); } IClass c = resolver.GetClass(combinedName, mre.TypeArguments.Count); if (c != null) { return CreateTypeResolveResult(resolver.ConstructType(c.DefaultReturnType, mre.TypeArguments)); } if (resolver.LanguageProperties.ImportModules) { // go through the members of the modules List possibleMembers = new List(); foreach (object o in resolver.ProjectContent.GetNamespaceContents(namespaceName)) { IMember member = o as IMember; if (member != null && resolver.IsSameName(member.Name, mre.MemberName)) { possibleMembers.Add(member); } } return resolver.CreateMemberOrMethodGroupResolveResult( null, mre.MemberName, new IList[] { possibleMembers }, false, null); } return null; } public override object VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data) { if (objectCreateExpression.IsAnonymousType) { return CreateResolveResult(CreateAnonymousTypeClass(objectCreateExpression.ObjectInitializer).DefaultReturnType); } else { IReturnType rt = TypeVisitor.CreateReturnType(objectCreateExpression.CreateType, resolver); if (rt == null) return new UnknownConstructorCallResolveResult(resolver.CallingClass, resolver.CallingMember, objectCreateExpression.CreateType.ToString()); return ResolveConstructorOverload(rt, objectCreateExpression.Parameters) ?? CreateResolveResult(rt); } } internal ResolveResult ResolveConstructorOverload(IReturnType rt, List arguments) { if (rt == null) return null; List methods = rt.GetMethods().Where(m => m.IsConstructor && !m.IsStatic).ToList(); IReturnType[] argumentTypes = arguments.Select(ResolveType).ToArray(); bool resultIsAcceptable; IMethod result = MemberLookupHelper.FindOverload(methods, argumentTypes, out resultIsAcceptable); ResolveResult rr = CreateMemberResolveResult(result); if (rr != null) rr.ResolvedType = rt; return rr; } internal ResolveResult ResolveConstructorOverload(IClass c, List arguments) { if (c == null) return null; else return ResolveConstructorOverload(c.DefaultReturnType, arguments); } DefaultClass CreateAnonymousTypeClass(CollectionInitializerExpression initializer) { List fieldTypes = new List(); List fieldNames = new List(); foreach (Expression expr in initializer.CreateExpressions) { if (expr is NamedArgumentExpression) { // use right part only fieldTypes.Add( ResolveType(((NamedArgumentExpression)expr).Expression) ); } else { fieldTypes.Add( ResolveType(expr) ); } fieldNames.Add(GetAnonymousTypeFieldName(expr)); } StringBuilder nameBuilder = new StringBuilder(); nameBuilder.Append('{'); for (int i = 0; i < fieldTypes.Count; i++) { if (i > 0) nameBuilder.Append(", "); nameBuilder.Append(fieldNames[i]); nameBuilder.Append(" : "); if (fieldTypes[i] != null) { nameBuilder.Append(fieldTypes[i].DotNetName); } } nameBuilder.Append('}'); DefaultClass c = new DefaultClass(new DefaultCompilationUnit(resolver.ProjectContent), nameBuilder.ToString()); c.Modifiers = ModifierEnum.Internal | ModifierEnum.Synthetic | ModifierEnum.Sealed; for (int i = 0; i < fieldTypes.Count; i++) { DefaultProperty p = new DefaultProperty(fieldNames[i], fieldTypes[i], ModifierEnum.Public | ModifierEnum.Synthetic, DomRegion.Empty, DomRegion.Empty, c); p.CanGet = true; p.CanSet = false; c.Properties.Add(p); } return c; } static string GetAnonymousTypeFieldName(Expression expr) { if (expr is MemberReferenceExpression) { return ((MemberReferenceExpression)expr).MemberName; } else if (expr is NamedArgumentExpression) { return ((NamedArgumentExpression)expr).Name; } else if (expr is IdentifierExpression) { return ((IdentifierExpression)expr).Identifier; } else { return "?"; } } public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data) { return CreateResolveResult(parenthesizedExpression.Expression); } public override object VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression, object data) { ResolveResult targetRR = Resolve(pointerReferenceExpression.TargetObject); if (targetRR == null || targetRR.ResolvedType == null) return null; PointerReturnType type = targetRR.ResolvedType.CastToDecoratingReturnType(); if (type != null) { return resolver.ResolveMember(type.BaseType, pointerReferenceExpression.MemberName, pointerReferenceExpression.TypeArguments, NRefactoryResolver.IsInvoked(pointerReferenceExpression), true, null ); } return null; } public override object VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data) { if (primitiveExpression.Value == null) { return CreateResolveResult(NullReturnType.Instance); } else if (primitiveExpression.Value is int) { return new IntegerLiteralResolveResult(resolver.CallingClass, resolver.CallingMember, resolver.ProjectContent.SystemTypes.Int32); } else { return CreateResolveResult(resolver.ProjectContent.SystemTypes.CreatePrimitive(primitiveExpression.Value.GetType())); } } public override object VisitQueryExpression(QueryExpression queryExpression, object data) { QueryExpressionSelectClause selectClause = queryExpression.SelectOrGroupClause as QueryExpressionSelectClause; QueryExpressionGroupClause groupClause = queryExpression.SelectOrGroupClause as QueryExpressionGroupClause; if (selectClause != null) { // Fake a call to 'Select' var fakeInvocation = new InvocationExpression(new MemberReferenceExpression( queryExpression.FromClause.Sources.First().Expression, "Select")); var selector = new LambdaExpression(); selector.Parameters.Add(new ParameterDeclarationExpression(null, "__rangeVariable")); selector.ExpressionBody = selectClause.Projection; selector.Parent = fakeInvocation; fakeInvocation.Arguments.Add(selector); return CreateResolveResult(ResolveType(fakeInvocation)); } else if (groupClause != null) { // Fake a call to 'GroupBy' var fakeInvocation = new InvocationExpression(new MemberReferenceExpression( queryExpression.FromClause.Sources.First().Expression, "GroupBy")); var keySelector = new LambdaExpression(); keySelector.Parameters.Add(new ParameterDeclarationExpression(null, "__rangeVariable")); keySelector.ExpressionBody = groupClause.GroupBy; keySelector.Parent = fakeInvocation; var elementSelector = new LambdaExpression(); elementSelector.Parameters.Add(new ParameterDeclarationExpression(null, "__rangeVariable")); elementSelector.ExpressionBody = groupClause.Projection; elementSelector.Parent = fakeInvocation; fakeInvocation.Arguments.Add(keySelector); fakeInvocation.Arguments.Add(elementSelector); return CreateResolveResult(ResolveType(fakeInvocation)); } else { return null; } } public override object VisitSizeOfExpression(SizeOfExpression sizeOfExpression, object data) { return CreateResolveResult(resolver.ProjectContent.SystemTypes.Int32); } public override object VisitStackAllocExpression(StackAllocExpression stackAllocExpression, object data) { return null; } public override object VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, object data) { if (resolver.CallingClass == null) return null; if (resolver.Language == SupportedLanguage.VBNet && IsInstanceConstructor(resolver.CallingMember)) { return new VBBaseOrThisReferenceInConstructorResolveResult( resolver.CallingClass, resolver.CallingMember, resolver.CallingClass.DefaultReturnType); } else { return CreateResolveResult(resolver.CallingClass.DefaultReturnType); } } static bool IsInstanceConstructor(IMember member) { IMethod m = member as IMethod; return m != null && m.IsConstructor && !m.IsStatic; } public override object VisitTypeOfExpression(TypeOfExpression typeOfExpression, object data) { return CreateResolveResult(resolver.ProjectContent.SystemTypes.Type); } public override object VisitTypeOfIsExpression(TypeOfIsExpression typeOfIsExpression, object data) { return CreateResolveResult(resolver.ProjectContent.SystemTypes.Boolean); } public override object VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, object data) { TypeReference reference = typeReferenceExpression.TypeReference; ResolveResult rr = CreateTypeResolveResult(TypeVisitor.CreateReturnType(reference, resolver)); if (rr == null && reference.GenericTypes.Count == 0 && !reference.IsArrayType) { // reference to namespace is possible if (reference.IsGlobal) { if (resolver.ProjectContent.NamespaceExists(reference.Type)) return new NamespaceResolveResult(resolver.CallingClass, resolver.CallingMember, reference.Type); } else { string name = resolver.SearchNamespace(reference.Type, typeReferenceExpression.StartLocation); if (name != null) return new NamespaceResolveResult(resolver.CallingClass, resolver.CallingMember, name); } } if (rr != null) { return rr; } else { return new UnknownIdentifierResolveResult(resolver.CallingClass, resolver.CallingMember, reference.Type); } } public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data) { IReturnType type = ResolveType(unaryOperatorExpression.Expression); if (type == null) return null; switch (unaryOperatorExpression.Op) { case UnaryOperatorType.AddressOf: return CreateResolveResult(new PointerReturnType(type)); case UnaryOperatorType.Dereference: PointerReturnType prt = type.CastToDecoratingReturnType(); if (prt != null) { return CreateResolveResult(prt.BaseType); } else { return null; } default: return CreateResolveResult(type); } } public override object VisitUncheckedExpression(UncheckedExpression uncheckedExpression, object data) { return CreateResolveResult(uncheckedExpression.Expression); } #region XML Literal resolver public override object VisitXmlContentExpression(XmlContentExpression xmlContentExpression, object data) { switch (xmlContentExpression.Type) { case XmlContentType.Comment: return CreateResolveResult(new TypeReference("System.Xml.Linq.XComment")); case XmlContentType.Text: return CreateResolveResult(new TypeReference("System.Xml.Linq.XText")); case XmlContentType.CData: return CreateResolveResult(new TypeReference("System.Xml.Linq.XCData")); case XmlContentType.ProcessingInstruction: if (xmlContentExpression.Content.StartsWith("xml ", StringComparison.OrdinalIgnoreCase)) return CreateResolveResult(new TypeReference("System.Xml.Linq.XDocumentType")); return CreateResolveResult(new TypeReference("System.Xml.Linq.XProcessingInstruction")); default: throw new Exception("Invalid value for XmlContentType"); } } public override object VisitXmlDocumentExpression(XmlDocumentExpression xmlDocumentExpression, object data) { return CreateResolveResult(new TypeReference("System.Xml.Linq.XDocument")); } public override object VisitXmlElementExpression(XmlElementExpression xmlElementExpression, object data) { return CreateResolveResult(new TypeReference("System.Xml.Linq.XElement")); } public override object VisitXmlMemberAccessExpression(XmlMemberAccessExpression xmlMemberAccessExpression, object data) { switch (xmlMemberAccessExpression.AxisType) { case XmlAxisType.Element: case XmlAxisType.Descendents: return CreateResolveResult( new TypeReference("System.Collections.Generic.IEnumerable", new List { new TypeReference("System.Xml.Linq.XElement") { IsGlobal = true } } ) { IsGlobal = true } ); case XmlAxisType.Attribute: return CreateResolveResult(new TypeReference("System.String", true) { IsGlobal = true }); default: throw new Exception("Invalid value for XmlAxisType"); } } #endregion } }