[reflection] Coop handles icalls in System.Reflection and System.RuntimeTypeHandle...
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / Microsoft.Tools.Common / Microsoft / Activities / Presentation / Xaml / WorkflowDesignerXamlHelper.cs
1 // <copyright>
2 //   Copyright (c) Microsoft Corporation.  All rights reserved.
3 // </copyright>
4
5 namespace Microsoft.Activities.Presentation.Xaml
6 {
7     using System;
8     using System.Activities;
9     using System.Activities.Debugger;
10     using System.Activities.Debugger.Symbol;
11     using System.Activities.Presentation;
12     using System.Activities.Presentation.ViewState;
13     using System.Activities.Presentation.Xaml;
14     using System.Activities.XamlIntegration;
15     using System.Collections;
16     using System.Collections.Generic;
17     using System.Diagnostics;
18     using System.Globalization;
19     using System.IO;
20     using System.Runtime.Versioning;
21     using System.Xaml;
22
23     internal class WorkflowDesignerXamlHelper
24     {
25         private IWorkflowDesignerXamlHelperExecutionContext executionContext;
26
27         private XamlMember dynamicActivityPropertyNameMember;
28
29         private XamlMember dynamicActivityPropertyValueMember;
30
31         internal WorkflowDesignerXamlHelper(IWorkflowDesignerXamlHelperExecutionContext executionContext)
32         {
33             this.executionContext = executionContext;
34             SharedFx.Assert(this.executionContext != null, "this.executionContext != null");
35             SharedFx.Assert(this.executionContext.XamlSchemaContext != null, "this.executionContext.XamlSchemaContext != null");
36
37             this.dynamicActivityPropertyNameMember = new XamlMember(typeof(DynamicActivityProperty).GetProperty("Name"), this.XamlSchemaContext);
38             this.dynamicActivityPropertyValueMember = new XamlMember(typeof(DynamicActivityProperty).GetProperty("Value"), this.XamlSchemaContext);
39         }
40
41         private delegate void SourceLocationFoundCallback(object obj, SourceLocation sourceLocation);
42
43         internal enum DeserializationMode
44         {
45             Default,
46             ErrorTolerant,
47         }
48
49         public FrameworkName FrameworkName
50         {
51             get { return this.executionContext.FrameworkName; }
52         }
53
54         public WorkflowDesignerXamlSchemaContext XamlSchemaContext
55         {
56             get { return this.executionContext.XamlSchemaContext; }
57         }
58
59         public ViewStateIdManager IdManager
60         {
61             get { return this.executionContext.IdManager; }
62         }
63
64         public WorkflowSymbol LastWorkflowSymbol
65         {
66             get
67             {
68                 return this.executionContext.LastWorkflowSymbol;
69             }
70
71             set
72             {
73                 this.executionContext.LastWorkflowSymbol = value;
74             }
75         }
76
77         public string LocalAssemblyName
78         {
79             get { return this.executionContext.LocalAssemblyName; }
80         }
81
82         public void OnSerializationCompleted(Dictionary<object, object> sourceLocationObjectToModelItemObjectMapping)
83         {
84             this.executionContext.OnSerializationCompleted(sourceLocationObjectToModelItemObjectMapping);
85         }
86
87         public void OnBeforeDeserialize()
88         {
89             this.executionContext.OnBeforeDeserialize();
90         }
91
92         public void OnSourceLocationFound(object target, SourceLocation sourceLocation)
93         {
94             this.executionContext.OnSourceLocationFound(target, sourceLocation);
95         }
96
97         public void OnAfterDeserialize(Dictionary<string, SourceLocation> viewStateDataSourceLocationMapping)
98         {
99             this.executionContext.OnAfterDeserialize(viewStateDataSourceLocationMapping);
100         }
101
102         // Get root Activity. Currently only handle when the object is ActivityBuilder or Activity.
103         // May return null if it does not know how to get the root activity.
104         internal static Activity GetRootWorkflowElement(object rootModelObject)
105         {
106             SharedFx.Assert(rootModelObject != null, "Cannot pass null as rootModelObject");
107             Activity rootWorkflowElement;
108             IDebuggableWorkflowTree debuggableWorkflowTree = rootModelObject as IDebuggableWorkflowTree;
109             if (debuggableWorkflowTree != null)
110             {
111                 rootWorkflowElement = debuggableWorkflowTree.GetWorkflowRoot();
112             }
113             else
114             {
115                 // Loose xaml case.
116                 rootWorkflowElement = rootModelObject as Activity;
117             }
118
119             return rootWorkflowElement;
120         }
121
122         internal static Activity GetRootElementForSymbol(object rootInstance, Activity documentRootElement)
123         {
124             ActivityBuilder activityBuilder = rootInstance as ActivityBuilder;
125             if (activityBuilder != null)
126             {
127                 documentRootElement = activityBuilder.ConvertToDynamicActivity();
128             }
129
130             return documentRootElement;
131         }
132
133         // Copy the root namespaces from a reader to a writer.
134         // DesignTimeXamlWriter follows proper XAML convention by omitting the assembly name from
135         // clr-namespaces in the local assembly. However, VB Expressions aren't local-assembly-aware,
136         // and require an assembly name. So for every clr-namespace with no assembly name, we add an
137         // additional namespace record with an assembly name, to support VB.
138         // We only do this at the root level, since the designer only writes out namespaces at the root level.
139         internal void CopyNamespacesAndAddLocalAssembly(System.Xaml.XamlReader activityBuilderReader, System.Xaml.XamlWriter objectWriter)
140         {
141             // Designer loads alwas provide line info
142             IXamlLineInfo lineInfo = (IXamlLineInfo)activityBuilderReader;
143             IXamlLineInfoConsumer lineInfoConsumer = (IXamlLineInfoConsumer)objectWriter;
144             HashSet<string> definedPrefixes = new HashSet<string>();
145             List<NamespaceDeclaration> localAsmNamespaces = null;
146
147             while (activityBuilderReader.Read())
148             {
149                 lineInfoConsumer.SetLineInfo(lineInfo.LineNumber, lineInfo.LinePosition);
150
151                 if (activityBuilderReader.NodeType == XamlNodeType.NamespaceDeclaration)
152                 {
153                     definedPrefixes.Add(activityBuilderReader.Namespace.Prefix);
154                     if (this.XamlSchemaContext.IsClrNamespaceWithNoAssembly(activityBuilderReader.Namespace.Namespace))
155                     {
156                         if (localAsmNamespaces == null)
157                         {
158                             localAsmNamespaces = new List<NamespaceDeclaration>();
159                         }
160
161                         localAsmNamespaces.Add(activityBuilderReader.Namespace);
162                     }
163
164                     objectWriter.WriteNode(activityBuilderReader);
165                 }
166                 else
167                 {
168                     if (localAsmNamespaces != null)
169                     {
170                         foreach (NamespaceDeclaration ns in localAsmNamespaces)
171                         {
172                             string prefix = null;
173                             int i = 0;
174                             do
175                             {
176                                 i++;
177                                 prefix = ns.Prefix + i.ToString(CultureInfo.InvariantCulture);
178                             }
179                             while (definedPrefixes.Contains(prefix));
180                             string fullNs = this.XamlSchemaContext.AddLocalAssembly(ns.Namespace);
181                             objectWriter.WriteNamespace(new NamespaceDeclaration(fullNs, prefix));
182                             definedPrefixes.Add(prefix);
183                         }
184                     }
185
186                     objectWriter.WriteNode(activityBuilderReader);
187                     return;
188                 }
189             }
190         }
191
192         internal string SerializeToString(object obj, string fileName)
193         {
194             FrameworkName targetFramework = this.FrameworkName;
195
196             string sourceFile = null;
197             Activity rootWorkflowElement = GetRootWorkflowElement(obj);
198             Dictionary<int, object> modelItemObjectSequence = null;
199
200             // If the current target is 4.5 or Higher, let us not write the filename attribute as DebugSymbol eliminates the need for it.
201             // We will serialize without the Filename by removing it from the element and adding it back after serialization
202             if (targetFramework.Is45OrHigher())
203             {
204                 if (AttachablePropertyServices.TryGetProperty<string>(rootWorkflowElement, XamlDebuggerXmlReader.FileNameName, out sourceFile))
205                 {
206                     AttachablePropertyServices.RemoveProperty(rootWorkflowElement, XamlDebuggerXmlReader.FileNameName);
207                 }
208             }
209
210             TextWriter textWriter = new StringWriter(CultureInfo.InvariantCulture);
211
212             WorkflowDesignerXamlSchemaContext schemaContext = obj is ActivityBuilder ? this.XamlSchemaContext : new WorkflowDesignerXamlSchemaContext(null);
213
214             bool shouldWriteDebugSymbol = true;
215             if (targetFramework.IsLessThan45())
216             {
217                 shouldWriteDebugSymbol = false;
218             }
219
220             System.Xaml.XamlReader outerReader;
221             XamlObjectReaderWithSequence innerReader;
222
223             using (textWriter)
224             {
225                 UsingXamlWriter(
226                     new DesignTimeXamlWriter(textWriter, schemaContext, shouldWriteDebugSymbol),
227                     delegate(DesignTimeXamlWriter designTimeXamlWriter)
228                     {
229                         UsingXamlWriter(
230                             ActivityXamlServices.CreateBuilderWriter(designTimeXamlWriter),
231                             delegate(System.Xaml.XamlWriter activityBuilderWriter)
232                             {
233                                 UsingXamlWriter(
234                                     new ActivityTemplateFactoryBuilderWriter(activityBuilderWriter, schemaContext),
235                                     delegate(System.Xaml.XamlWriter writer)
236                                     {
237                                         // If ViewStateManager property is attached, remove it. It needs to be regenerated if we target 4.5. 
238                                         // It should be removed if we're targeting 4.0.
239                                         AttachablePropertyServices.RemoveProperty(obj, WorkflowViewState.ViewStateManagerProperty);
240
241                                         this.CreateXamlObjectReaders(obj, schemaContext, out outerReader, out innerReader);
242
243                                         using (innerReader)
244                                         {
245                                             using (outerReader)
246                                             {
247 #if ERROR_TOLERANT_SUPPORT
248                                                 if (ErrorActivity.GetHasErrorActivities(obj))
249                                                 {
250                                                     ErrorTolerantObjectWriter.TransformAndStripErrors(outerReader, writer);
251                                                 }
252                                                 else
253                                                 {
254 #endif
255                                                     XamlServices.Transform(outerReader, writer);
256 #if ERROR_TOLERANT_SUPPORT
257                                                 }
258 #endif
259                                             }
260                                         }
261
262                                         modelItemObjectSequence = innerReader.SequenceNumberToObjectMap;
263                                     });
264                             });
265                     });
266             }
267
268             string retVal = textWriter.ToString();
269
270             if (targetFramework.IsLessThan45())
271             {
272                 if (sourceFile != null)
273                 {
274                     XamlDebuggerXmlReader.SetFileName(rootWorkflowElement, sourceFile);
275                 }
276             }
277
278             IList<XamlLoadErrorInfo> loadErrors;
279             Dictionary<object, SourceLocation> sourceLocations;
280             object deserializedObject = this.DeserializeString(retVal, out loadErrors, out sourceLocations);
281
282             if (!string.IsNullOrEmpty(fileName) && targetFramework.Is45OrHigher())
283             {
284                 this.LastWorkflowSymbol = this.GetWorkflowSymbol(fileName, deserializedObject, sourceLocations);
285                 if (this.LastWorkflowSymbol != null)
286                 {
287                     retVal = retVal.Replace(DesignTimeXamlWriter.EmptyWorkflowSymbol, this.LastWorkflowSymbol.Encode());
288                 }
289             }
290
291             // The symbol is actually removed in GetAttachedWorkflowSymbol() after deserialization completes.
292             System.Xaml.AttachablePropertyServices.RemoveProperty(GetRootWorkflowElement(deserializedObject), DebugSymbol.SymbolName);
293             this.CreateXamlObjectReaders(deserializedObject, schemaContext, out outerReader, out innerReader);
294             Dictionary<object, object> sourceLocationObjectToModelItemObjectMapping = new Dictionary<object, object>(ObjectReferenceEqualityComparer<object>.Default);
295             using (innerReader)
296             {
297                 using (outerReader)
298                 {
299                     while (outerReader.Read())
300                     {
301                     }
302
303                     Dictionary<int, object> sourceLocationObjectSequence = innerReader.SequenceNumberToObjectMap;
304                     foreach (KeyValuePair<int, object> sourceLocationObjectEntry in sourceLocationObjectSequence)
305                     {
306                         int key = sourceLocationObjectEntry.Key;
307                         object sourceLocationObject = sourceLocationObjectEntry.Value;
308                         object modelItemObject;
309
310                         if (modelItemObjectSequence.TryGetValue(key, out modelItemObject))
311                         {
312                             sourceLocationObjectToModelItemObjectMapping.Add(sourceLocationObject, modelItemObject);
313                         }
314                     }
315                 }
316             }
317
318             this.OnSerializationCompleted(sourceLocationObjectToModelItemObjectMapping);
319             return retVal;
320         }
321
322         internal void CreateXamlObjectReaders(object deserializedObject, XamlSchemaContext schemaContext, out XamlReader newWorkflowReader, out XamlObjectReaderWithSequence deserializedObjectSequenceBuilder)
323         {
324             deserializedObjectSequenceBuilder = new XamlObjectReaderWithSequence(deserializedObject, schemaContext);
325             if (this.FrameworkName.Is45OrHigher())
326             {
327                 newWorkflowReader = ViewStateXamlHelper.ConvertAttachedPropertiesToViewState(deserializedObjectSequenceBuilder, this.IdManager);
328             }
329             else
330             {
331                 newWorkflowReader = ViewStateXamlHelper.RemoveIdRefs(deserializedObjectSequenceBuilder);
332             }
333         }
334
335         internal object DeserializeString(string text)
336         {
337             IList<XamlLoadErrorInfo> loadErrors;
338             Dictionary<object, SourceLocation> sourceLocations;
339             return this.DeserializeString(text, out loadErrors, out sourceLocations);
340         }
341
342         internal object DeserializeString(string text, out IList<XamlLoadErrorInfo> loadErrors, out Dictionary<object, SourceLocation> sourceLocations)
343         {
344             try
345             {
346                 return this.DeserializeString(text, DeserializationMode.Default, out loadErrors, out sourceLocations);
347             }
348             catch (XamlObjectWriterException)
349             {
350                 // Fall back to error-tolerant path. We don't do this by default for perf reasons.
351                 return this.DeserializeString(text, DeserializationMode.ErrorTolerant, out loadErrors, out sourceLocations);
352             }
353         }
354
355         //// XAML writer may throw exception during dispose, therefore the following code will cause exception masking
356         ////
357         //// using (XamlWriter xamlWriter)
358         //// {
359         ////      ...
360         //// }
361         ////
362         //// If there are any exception A thrown within the block, and if xamlWriter.Dispose() throws an exception B
363         //// The exception B will mask exception A and the exception is the ErrorTolerant scenario will be broken.
364         ////
365         //// The fix to this problem is to ---- any XamlException thrown during Dispose(), we are in general not
366         //// interested in those exceptions.
367         private static void UsingXamlWriter<T>(T xamlWriter, Action<T> work) where T : XamlWriter
368         {
369             if (xamlWriter != null)
370             {
371                 try
372                 {
373                     work(xamlWriter);
374                 }
375                 finally
376                 {
377                     try
378                     {
379                         xamlWriter.Close();
380                     }
381                     catch (XamlException e)
382                     {
383                         // ignore any XAML exception during closing a XamlWriter
384                         Trace.WriteLine(e.Message);
385                     }
386                 }
387             }
388         }
389
390         // there are two kind of attribute:
391         // 1) in lined : argument="some value"
392         // 2) <argument>
393         //       <Expression ....../>
394         //    </argument>
395         // here, for (1) return the source location of "some value".
396         // for (2) return null
397         private static SourceLocation GetInlineAttributeValueLocation(LineColumnPair startPoint, SourceTextScanner sourceTextScanner)
398         {
399             const char SingleQuote = '\'';
400             const char DoubleQuote = '"';
401             const char StartAngleBracket = '<';
402             Tuple<LineColumnPair, char> start = sourceTextScanner.SearchCharAfter(startPoint, SingleQuote, DoubleQuote, StartAngleBracket);
403             if (start == null)
404             {
405                 return null;
406             }
407
408             if (start.Item2 == StartAngleBracket)
409             {
410                 return null;
411             }
412
413             Tuple<LineColumnPair, char> end = sourceTextScanner.SearchCharAfter(start.Item1, start.Item2);
414             if (end == null)
415             {
416                 SharedFx.Assert("end of SourceLocation is not found");
417                 return null;
418             }
419
420             return new SourceLocation(null, start.Item1.LineNumber, start.Item1.ColumnNumber, end.Item1.LineNumber, end.Item1.ColumnNumber);
421         }
422
423         private WorkflowSymbol GetWorkflowSymbol(string fileName, object deserializedObject, Dictionary<object, SourceLocation> sourceLocations)
424         {
425             if (deserializedObject != null)
426             {
427                 Activity deserializedRootElement = GetRootWorkflowElement(deserializedObject);
428                 if (deserializedRootElement != null)
429                 {
430                     try
431                     {
432                         deserializedRootElement = GetRootElementForSymbol(deserializedObject, deserializedRootElement);
433                         return new WorkflowSymbol
434                         {
435                             FileName = fileName,
436                             Symbols = SourceLocationProvider.GetSymbols(deserializedRootElement, sourceLocations)
437                         };
438                     }
439                     catch (Exception ex)
440                     {
441                         if (SharedFx.IsFatal(ex))
442                         {
443                             throw;
444                         }
445
446                         // This happens when the workflow is invalid so GetSymbols fails.
447                         // ---- exception here.
448                     }
449                 }
450             }
451
452             return null;
453         }
454
455         private object DeserializeString(string text, DeserializationMode mode, out IList<XamlLoadErrorInfo> loadErrors, out Dictionary<object, SourceLocation> sourceLocations)
456         {
457             object result = null;
458             loadErrors = null;
459             Dictionary<object, SourceLocation> collectingSourceLocations = new Dictionary<object, SourceLocation>(ObjectReferenceEqualityComparer<object>.Default);
460             SourceLocationFoundCallback sourceLocationFoundCallback = new SourceLocationFoundCallback((obj, sourceLocation) =>
461             {
462                 // If an object appear more than once in the XAML stream (e.g. System.Type, which is cached by reflection)
463                 // we count the first occurrence.
464                 if (!collectingSourceLocations.ContainsKey(obj))
465                 {
466                     collectingSourceLocations.Add(obj, sourceLocation);
467                 }
468
469                 this.OnSourceLocationFound(obj, sourceLocation);
470             });
471
472             this.XamlSchemaContext.ContainsConversionRequiredType = false;
473             Dictionary<string, SourceLocation> viewStateDataSourceLocationMapping = null;
474             using (XamlDebuggerXmlReader debuggerReader = new XamlDebuggerXmlReader(new StringReader(text), this.XamlSchemaContext))
475             {
476                 using (System.Xaml.XamlReader activityBuilderReader = ActivityXamlServices.CreateBuilderReader(debuggerReader))
477                 {
478                     using (System.Xaml.XamlReader activityTemplateFactoryBuilderReader = new ActivityTemplateFactoryBuilderReader(activityBuilderReader, this.XamlSchemaContext))
479                     {
480                         debuggerReader.SourceLocationFound += delegate(object sender, SourceLocationFoundEventArgs args)
481                         {
482                             sourceLocationFoundCallback(args.Target, args.SourceLocation);
483                         };
484
485                         this.OnBeforeDeserialize();
486                         debuggerReader.CollectNonActivitySourceLocation = this.FrameworkName.Is45OrHigher();
487
488                         using (System.Xaml.XamlReader reader = ViewStateXamlHelper.ConvertViewStateToAttachedProperties(activityTemplateFactoryBuilderReader, this.IdManager, out viewStateDataSourceLocationMapping))
489                         {
490                             switch (mode)
491                             {
492 #if ERROR_TOLERANT_SUPPORT
493                                 case DeserializationMode.ErrorTolerant:
494                                     {
495                                         ErrorTolerantObjectWriter tolerantWriter = new ErrorTolerantObjectWriter(reader.SchemaContext);
496                                         tolerantWriter.LocalAssemblyName = this.LocalAssemblyName;
497                                         XamlServices.Transform(reader, tolerantWriter);
498                                         loadErrors = this.CheckFileFormatError(tolerantWriter.LoadErrors);
499                                         result = tolerantWriter.Result;
500                                         ErrorActivity.SetHasErrorActivities(result, true);
501                                     }
502
503                                     break;
504 #endif
505                                 case DeserializationMode.Default:
506                                     {
507                                         result = this.TransformAndGetPropertySourceLocation(reader, new SourceTextScanner(text), sourceLocationFoundCallback);
508
509                                         loadErrors = this.CheckFileFormatError(loadErrors);
510                                     }
511
512                                     break;
513                             }
514                         }
515                     }
516                 }
517             }
518
519             sourceLocations = collectingSourceLocations;
520             this.OnAfterDeserialize(viewStateDataSourceLocationMapping);
521             return result;
522         }
523
524         // For dynamic activity property, we needs to collect the source location of 
525         // its default value when the value is inlined.
526         private KeyValuePair<string, SourceLocation> TransformDynamicActivityProperty(
527             XamlReader reader,
528             XamlObjectWriter objectWriter,
529             SourceTextScanner sourceTextScanner)
530         {
531             // (Number of SM -Number of EM) since SM DAP.Name is read.
532             // SO DAP                   ---nameReadingLevel=0
533             //   SM NAME                ---nameReadingLevel=1
534             //     SO String            ---nameReadingLevel=1
535             //       SM Initialize      ---nameReadingLevel=2
536             //         VA StringValue   ---nameReadingLevel=2
537             //       EM                 ---nameReadingLevel=1
538             //     SO                   ---nameReadingLevel=1
539             //   EM                     ---nameReadingLevel=0
540             // EO                       ---nameReadingLevel=0
541             int nameReadingLevel = 0;
542
543             IXamlLineInfo lineInfo = (IXamlLineInfo)reader;
544             SourceLocation defaultValueLocation = null;
545             string propertyName = null;
546
547             while (reader.Read())
548             {
549                 switch (reader.NodeType)
550                 {
551                     case XamlNodeType.StartMember:
552                         if (nameReadingLevel > 0
553                             || reader.Member == this.dynamicActivityPropertyNameMember)
554                         {
555                             ++nameReadingLevel;
556                         }
557                         else if (reader.Member == this.dynamicActivityPropertyValueMember)
558                         {
559                             LineColumnPair startPoint = new LineColumnPair(lineInfo.LineNumber, lineInfo.LinePosition);
560                             defaultValueLocation = GetInlineAttributeValueLocation(startPoint, sourceTextScanner);
561                         }
562
563                         break;
564
565                     case XamlNodeType.EndMember:
566                         if (nameReadingLevel > 0)
567                         {
568                             --nameReadingLevel;
569                         }
570
571                         break;
572
573                     case XamlNodeType.Value:
574                         if (nameReadingLevel > 0)
575                         {
576                             propertyName = reader.Value as string;
577                         }
578
579                         break;
580                 }
581
582                 objectWriter.WriteNode(reader);
583             }
584
585             if (propertyName != null && defaultValueLocation != null)
586             {
587                 return new KeyValuePair<string, SourceLocation>(propertyName, defaultValueLocation);
588             }
589
590             return new KeyValuePair<string, SourceLocation>();
591         }
592
593         private object TransformAndGetPropertySourceLocation(XamlReader reader, SourceTextScanner sourceTextScanner, SourceLocationFoundCallback sourceLocationFoundCallback)
594         {
595             // <property name, value's start location>
596             Dictionary<string, SourceLocation> propertyValueLocationMapping = new Dictionary<string, SourceLocation>();
597
598             object deserializedObject = null;
599             object earlyResult = null;
600
601             UsingXamlWriter(
602                 new XamlObjectWriter(reader.SchemaContext),
603                 delegate(XamlObjectWriter objectWriter)
604                 {
605                     if (this.XamlSchemaContext.HasLocalAssembly)
606                     {
607                         this.CopyNamespacesAndAddLocalAssembly(reader, objectWriter);
608                     }
609
610                     if (!(reader is IXamlLineInfo))
611                     {
612                         XamlServices.Transform(reader, objectWriter);
613                         earlyResult = objectWriter.Result;
614                         return;
615                     }
616
617                     XamlType dynamicActivityPropertyType = this.XamlSchemaContext.GetXamlType(typeof(DynamicActivityProperty));
618                     while (reader.Read())
619                     {
620                         // read SubTree will moves the reader pointed to
621                         // element after its EO. So, we need to use a while
622                         while (!reader.IsEof && reader.NodeType == XamlNodeType.StartObject
623                             && dynamicActivityPropertyType == reader.Type)
624                         {
625                             KeyValuePair<string, SourceLocation> nameSourceLocation = this.TransformDynamicActivityProperty(reader.ReadSubtree(), objectWriter, sourceTextScanner);
626                             if (nameSourceLocation.Key != null && nameSourceLocation.Value != null && !propertyValueLocationMapping.ContainsKey(nameSourceLocation.Key))
627                             {
628                                 propertyValueLocationMapping.Add(nameSourceLocation.Key, nameSourceLocation.Value);
629                             }
630                         }
631
632                         if (!reader.IsEof)
633                         {
634                             objectWriter.WriteNode(reader);
635                         }
636                     }
637
638                     deserializedObject = objectWriter.Result;
639                 });
640
641             if (earlyResult != null)
642             {
643                 return earlyResult;
644             }
645
646             ActivityBuilder activityBuilder = deserializedObject as ActivityBuilder;
647             if (activityBuilder == null)
648             {
649                 return deserializedObject;
650             }
651
652             foreach (KeyValuePair<string, SourceLocation> propertyValueLocation in propertyValueLocationMapping)
653             {
654                 string propertyName = propertyValueLocation.Key;
655                 SourceLocation propertyLocation = propertyValueLocation.Value;
656                 if (!activityBuilder.Properties.Contains(propertyName))
657                 {
658                     SharedFx.Assert(string.Format(CultureInfo.CurrentCulture, "no such property:{0}", propertyName));
659                     continue;
660                 }
661
662                 DynamicActivityProperty property = activityBuilder.Properties[propertyName];
663
664                 if (property == null || property.Value == null)
665                 {
666                     SharedFx.Assert(string.Format(CultureInfo.CurrentCulture, "no such property value:{0}", propertyName));
667                     continue;
668                 }
669
670                 object expression = (property.Value is Argument) ? ((Argument)property.Value).Expression : null;
671                 if (expression != null)
672                 {
673                     sourceLocationFoundCallback(expression, propertyLocation);
674                 }
675                 else
676                 {
677                     sourceLocationFoundCallback(property.Value, propertyLocation);
678                 }
679             }
680
681             return deserializedObject;
682         }
683
684         private IList<XamlLoadErrorInfo> CheckFileFormatError(IList<XamlLoadErrorInfo> loadErrors)
685         {
686             IList<XamlLoadErrorInfo> result = loadErrors;
687
688             if (this.XamlSchemaContext.ContainsConversionRequiredType)
689             {
690                 if (result == null)
691                 {
692                     result = new List<XamlLoadErrorInfo>();
693                 }
694
695                 result.Add(new XamlLoadErrorInfo(SharedSR.FileFormatError, 0, 0));
696             }
697
698             return result;
699         }
700     }
701 }