// For dynamic activity property, we needs to collect the source location of // its default value when the value is inlined. private KeyValuePair <string, SourceLocation> TransformDynamicActivityProperty( XamlReader reader, XamlObjectWriter objectWriter, SourceTextScanner sourceTextScanner) { // (Number of SM -Number of EM) since SM DAP.Name is read. // SO DAP ---nameReadingLevel=0 // SM NAME ---nameReadingLevel=1 // SO String ---nameReadingLevel=1 // SM Initialize ---nameReadingLevel=2 // VA StringValue ---nameReadingLevel=2 // EM ---nameReadingLevel=1 // SO ---nameReadingLevel=1 // EM ---nameReadingLevel=0 // EO ---nameReadingLevel=0 int nameReadingLevel = 0; IXamlLineInfo lineInfo = (IXamlLineInfo)reader; SourceLocation defaultValueLocation = null; string propertyName = null; while (reader.Read()) { switch (reader.NodeType) { case XamlNodeType.StartMember: if (nameReadingLevel > 0 || reader.Member == this.dynamicActivityPropertyNameMember) { ++nameReadingLevel; } else if (reader.Member == this.dynamicActivityPropertyValueMember) { LineColumnPair startPoint = new LineColumnPair(lineInfo.LineNumber, lineInfo.LinePosition); defaultValueLocation = GetInlineAttributeValueLocation(startPoint, sourceTextScanner); } break; case XamlNodeType.EndMember: if (nameReadingLevel > 0) { --nameReadingLevel; } break; case XamlNodeType.Value: if (nameReadingLevel > 0) { propertyName = reader.Value as string; } break; } objectWriter.WriteNode(reader); } if (propertyName != null && defaultValueLocation != null) { return(new KeyValuePair <string, SourceLocation>(propertyName, defaultValueLocation)); } return(new KeyValuePair <string, SourceLocation>()); }
private object TransformAndGetPropertySourceLocation(XamlReader reader, SourceTextScanner sourceTextScanner, SourceLocationFoundCallback sourceLocationFoundCallback) { // <property name, value's start location> Dictionary <string, SourceLocation> propertyValueLocationMapping = new Dictionary <string, SourceLocation>(); object deserializedObject = null; object earlyResult = null; UsingXamlWriter( new XamlObjectWriter(reader.SchemaContext), delegate(XamlObjectWriter objectWriter) { if (this.XamlSchemaContext.HasLocalAssembly) { this.CopyNamespacesAndAddLocalAssembly(reader, objectWriter); } if (!(reader is IXamlLineInfo)) { XamlServices.Transform(reader, objectWriter); earlyResult = objectWriter.Result; return; } XamlType dynamicActivityPropertyType = this.XamlSchemaContext.GetXamlType(typeof(DynamicActivityProperty)); while (reader.Read()) { // read SubTree will moves the reader pointed to // element after its EO. So, we need to use a while while (!reader.IsEof && reader.NodeType == XamlNodeType.StartObject && dynamicActivityPropertyType == reader.Type) { KeyValuePair <string, SourceLocation> nameSourceLocation = this.TransformDynamicActivityProperty(reader.ReadSubtree(), objectWriter, sourceTextScanner); if (nameSourceLocation.Key != null && nameSourceLocation.Value != null && !propertyValueLocationMapping.ContainsKey(nameSourceLocation.Key)) { propertyValueLocationMapping.Add(nameSourceLocation.Key, nameSourceLocation.Value); } } if (!reader.IsEof) { objectWriter.WriteNode(reader); } } deserializedObject = objectWriter.Result; }); if (earlyResult != null) { return(earlyResult); } ActivityBuilder activityBuilder = deserializedObject as ActivityBuilder; if (activityBuilder == null) { return(deserializedObject); } foreach (KeyValuePair <string, SourceLocation> propertyValueLocation in propertyValueLocationMapping) { string propertyName = propertyValueLocation.Key; SourceLocation propertyLocation = propertyValueLocation.Value; if (!activityBuilder.Properties.Contains(propertyName)) { SharedFx.Assert(string.Format(CultureInfo.CurrentCulture, "no such property:{0}", propertyName)); continue; } DynamicActivityProperty property = activityBuilder.Properties[propertyName]; if (property == null || property.Value == null) { SharedFx.Assert(string.Format(CultureInfo.CurrentCulture, "no such property value:{0}", propertyName)); continue; } object expression = (property.Value is Argument) ? ((Argument)property.Value).Expression : null; if (expression != null) { sourceLocationFoundCallback(expression, propertyLocation); } else { sourceLocationFoundCallback(property.Value, propertyLocation); } } return(deserializedObject); }
// there are two kind of attribute: // 1) in lined : argument="some value" // 2) <argument> // <Expression ....../> // </argument> // here, for (1) return the source location of "some value". // for (2) return null private static SourceLocation GetInlineAttributeValueLocation(LineColumnPair startPoint, SourceTextScanner sourceTextScanner) { const char SingleQuote = '\''; const char DoubleQuote = '"'; const char StartAngleBracket = '<'; Tuple <LineColumnPair, char> start = sourceTextScanner.SearchCharAfter(startPoint, SingleQuote, DoubleQuote, StartAngleBracket); if (start == null) { return(null); } if (start.Item2 == StartAngleBracket) { return(null); } Tuple <LineColumnPair, char> end = sourceTextScanner.SearchCharAfter(start.Item1, start.Item2); if (end == null) { SharedFx.Assert("end of SourceLocation is not found"); return(null); } return(new SourceLocation(null, start.Item1.LineNumber, start.Item1.ColumnNumber, end.Item1.LineNumber, end.Item1.ColumnNumber)); }