IList <ICompletionItem> CreatePropertyPathCompletion(XamlCompletionContext context) { bool isExplicit; IType typeName = GetType(context, out isExplicit); IList <ICompletionItem> list = new List <ICompletionItem>(); string value = context.ValueStartOffset > -1 ? context.RawAttributeValue.Substring(0, Math.Min(context.ValueStartOffset + 1, context.RawAttributeValue.Length)) : ""; if (value.EndsWithAny(']', ')')) { return(list); } var segments = PropertyPathParser.Parse(value).ToList(); int completionStart; bool isAtDot = false; IType propertyPathType = ResolvePropertyPath(segments, context, typeName, out completionStart); if (completionStart < segments.Count) { PropertyPathSegment seg = segments[completionStart]; switch (seg.Kind) { case SegmentKind.ControlChar: if (seg.Content == ".") { AddAttributes(propertyPathType, list, false); isAtDot = true; } break; case SegmentKind.AttachedProperty: AddAttributes(seg.Resolve(context, propertyPathType), list, false); isAtDot = seg.Content.Contains("."); break; case SegmentKind.PropertyOrType: AddAttributes(propertyPathType, list, false); isAtDot = true; break; } } else if (typeName != null) { AddAttributes(typeName, list, false); } if (!isAtDot) { foreach (var item in GetAllTypes(context)) { list.Add(item); } } return(list); }
public static IType Resolve(this PropertyPathSegment segment, XamlCompletionContext context, IType previousType) { if (segment.Kind == SegmentKind.SourceTraversal) { return(previousType); } if (segment.Kind == SegmentKind.ControlChar) { return(previousType); } string content = segment.Content; if (segment.Kind == SegmentKind.AttachedProperty && content.StartsWith("(", StringComparison.Ordinal)) { content = content.TrimStart('('); if (content.Contains(".")) { content = content.Remove(content.IndexOf('.')); } } ICompilation compilation = SD.ParserService.GetCompilationForFile(context.Editor.FileName); XamlResolver resolver = new XamlResolver(compilation); ResolveResult rr = resolver.ResolveExpression(content, context); IType type = rr.Type; if (previousType != null) { IMember member = previousType.GetMemberByName(content); if (member != null) { type = member.ReturnType; } } else if (rr is MemberResolveResult) { MemberResolveResult mrr = rr as MemberResolveResult; if (mrr.Member != null) { type = mrr.Member.ReturnType; } } return(type); }
static IType ResolvePropertyPath(IList <PropertyPathSegment> segments, XamlCompletionContext context, IType parentType, out int lastIndex) { IType type = parentType; for (lastIndex = 0; lastIndex < segments.Count - 1; lastIndex++) { PropertyPathSegment segment = segments[lastIndex]; switch (segment.Kind) { case SegmentKind.AttachedProperty: // do we need to take account of previous results? type = segment.Resolve(context, null); break; case SegmentKind.ControlChar: if (segment.Content == "[" || segment.Content == "(" || segment.Content == "/") { return(null); } return(type); case SegmentKind.PropertyOrType: type = segment.Resolve(context, type); break; case SegmentKind.Indexer: if (type != null) { IProperty prop = type.GetProperties(p => p.IsIndexer).FirstOrDefault(); if (prop != null) { type = prop.ReturnType; } } break; case SegmentKind.SourceTraversal: // ignore return(null); } } return(type); }