[X] RegisterSourceInfo for XamlC (#8579)
authorStephane Delcroix <stephane@delcroix.org>
Tue, 26 Nov 2019 00:29:40 +0000 (01:29 +0100)
committerSamantha Houts <samhouts@users.noreply.github.com>
Tue, 26 Nov 2019 00:29:40 +0000 (16:29 -0800)
When compiling in DEBUG, Register sourceInfo even for compiled code

Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs
Xamarin.Forms.Build.Tasks/ILContext.cs
Xamarin.Forms.Build.Tasks/ILRootNode.cs
Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs
Xamarin.Forms.Build.Tasks/XamlCTask.cs
Xamarin.Forms.Build.Tasks/XamlTask.cs
Xamarin.Forms.Xaml/Diagnostics/VisualDiagnostics.cs
Xamarin.Forms.Xaml/XamlNode.cs

index c6ecf5e..4c3824a 100644 (file)
@@ -506,7 +506,7 @@ namespace Xamarin.Forms.Build.Tasks
                                }
                                break;
                        case "System.Uri":
-                               if (hasValue && Uri.TryCreate(valueString, UriKind.RelativeOrAbsolute, out Uri outuri)) {
+                               if (hasValue && Uri.TryCreate(valueString, UriKind.RelativeOrAbsolute, out _)) {
                                        var vardef = new VariableDefinition(module.ImportReference(("System", "System", "Uri")));
                                        Context.Body.Variables.Add(vardef);
                                        //Use an extra temp var so we can push the value to the stack, just like other cases
index bcd483b..062476c 100644 (file)
@@ -39,5 +39,7 @@ namespace Xamarin.Forms.Build.Tasks
                public MethodBody Body { get; private set; }
 
                public ModuleDefinition Module { get; private set; }
+               public bool DefineDebug { get; internal set; }
+               public string XamlFilePath { get; internal set; }
        }
 }
\ No newline at end of file
index 77e1e8c..937f66b 100644 (file)
@@ -6,7 +6,7 @@ namespace Xamarin.Forms.Build.Tasks
 {
        class ILRootNode : RootNode
        {
-               public ILRootNode(XmlType xmlType, TypeReference typeReference, IXmlNamespaceResolver nsResolver) : base(xmlType, nsResolver)
+               public ILRootNode(XmlType xmlType, TypeReference typeReference, IXmlNamespaceResolver nsResolver, int linenumber = -1, int lineposition = -1) : base(xmlType, nsResolver, linenumber: linenumber, lineposition: lineposition)
                {
                        TypeReference = typeReference;
                }
index 921143f..ebe618c 100644 (file)
@@ -858,18 +858,18 @@ namespace Xamarin.Forms.Build.Tasks
 //                     IL_008e:  newobj instance void class [mscorlib]System.Tuple`2<class [mscorlib]System.Func`2<class ViewModel, object>, string>::'.ctor'(!0, !1)
 //                     IL_0093:  stelem.ref 
 
-                       yield return Instruction.Create(OpCodes.Ldc_I4, properties.Count);
-                       yield return Instruction.Create(OpCodes.Newarr, tupleRef);
+                       yield return Create(Ldc_I4, properties.Count);
+                       yield return Create(Newarr, tupleRef);
 
                        for (var i = 0; i < properties.Count; i++) {
-                               yield return Instruction.Create(OpCodes.Dup);
-                               yield return Instruction.Create(OpCodes.Ldc_I4, i);
-                               yield return Instruction.Create(OpCodes.Ldnull);
-                               yield return Instruction.Create(OpCodes.Ldftn, partGetters [i]);
-                               yield return Instruction.Create(OpCodes.Newobj, module.ImportReference(funcCtor));
-                               yield return Instruction.Create(OpCodes.Ldstr, properties [i].Item1.Name);
-                               yield return Instruction.Create(OpCodes.Newobj, module.ImportReference(tupleCtor));
-                               yield return Instruction.Create(OpCodes.Stelem_Ref);
+                               yield return Create(Dup);
+                               yield return Create(Ldc_I4, i);
+                               yield return Create(Ldnull);
+                               yield return Create(Ldftn, partGetters [i]);
+                               yield return Create(Newobj, module.ImportReference(funcCtor));
+                               yield return Create(Ldstr, properties [i].Item1.Name);
+                               yield return Create(Newobj, module.ImportReference(tupleCtor));
+                               yield return Create(Stelem_Ref);
                        }
                }
 
@@ -892,19 +892,55 @@ namespace Xamarin.Forms.Build.Tasks
 
                        //If it's a BP, SetValue ()
                        if (CanSetValue(bpRef, attached, valueNode, iXmlLineInfo, context))
-                               return SetValue(parent, bpRef, valueNode, iXmlLineInfo, context);
+                               return SetValue(parent, bpRef, valueNode, iXmlLineInfo, context).Concat(RegisterSourceInfo(context, valueNode));
 
                        //If it's a property, set it
                        if (CanSet(parent, localName, valueNode, context))
-                               return Set(parent, localName, valueNode, iXmlLineInfo, context);
+                               return Set(parent, localName, valueNode, iXmlLineInfo, context).Concat(RegisterSourceInfo(context, valueNode));
 
                        //If it's an already initialized property, add to it
                        if (CanAdd(parent, propertyName, valueNode, iXmlLineInfo, context))
-                               return Add(parent, propertyName, valueNode, iXmlLineInfo, context);
+                               return Add(parent, propertyName, valueNode, iXmlLineInfo, context).Concat(RegisterSourceInfo(context, valueNode));
 
                        throw new XamlParseException($"No property, bindable property, or event found for '{localName}', or mismatching type between value and property.", iXmlLineInfo);
                }
 
+               internal static IEnumerable<Instruction> RegisterSourceInfo(ILContext context, INode valueNode)
+               {
+                       if (!context.DefineDebug)
+                               yield break;
+                       if (!(valueNode is IXmlLineInfo lineInfo))
+                               yield break;
+                       if (!(valueNode is IElementNode elementNode))
+                               yield break;
+                       if (context.Variables[elementNode].VariableType.IsValueType)
+                               yield break;
+
+                       var module = context.Body.Method.Module;
+
+                       yield return Create(Ldloc, context.Variables[elementNode]);             //target
+
+                       yield return Create(Ldstr, context.XamlFilePath);
+                       yield return Create(Ldc_I4, (int)UriKind.RelativeOrAbsolute);
+                       yield return Create(Newobj, module.ImportCtorReference(("System", "System", "Uri"),
+                                                                                                                                  parameterTypes: new[] {
+                                                                                                                                          ("mscorlib", "System", "String"),
+                                                                                                                                          ("System", "System", "UriKind"),
+                                                                                                                                  }));         //uri
+
+                       yield return Create(Ldc_I4, lineInfo.LineNumber);                               //lineNumber
+                       yield return Create(Ldc_I4, lineInfo.LinePosition);             //linePosition
+
+                       yield return Create(Call, module.ImportMethodReference(("Xamarin.Forms.Xaml", "Xamarin.Forms.Xaml.Diagnostics", "VisualDiagnostics"),
+                                                                                                                                  methodName: "RegisterSourceInfo",
+                                                                                                                                  parameterTypes: new[] {
+                                                                                                                                          ("mscorlib", "System", "Object"),
+                                                                                                                                          ("System", "System", "Uri"),
+                                                                                                                                          ("mscorlib", "System", "Int32"),
+                                                                                                                                          ("mscorlib", "System", "Int32")},
+                                                                                                                                  isStatic: true));
+               }
+
                public static IEnumerable<Instruction> GetPropertyValue(VariableDefinition parent, XmlName propertyName, ILContext context, IXmlLineInfo lineInfo, out TypeReference propertyType)
                {
                        var module = context.Body.Method.Module;
@@ -1492,7 +1528,9 @@ namespace Xamarin.Forms.Build.Tasks
                        templateIl.Emit(OpCodes.Nop);
                        var templateContext = new ILContext(templateIl, loadTemplate.Body, module, parentValues)
                        {
-                               Root = root
+                               Root = root,
+                               DefineDebug = parentContext.DefineDebug,
+                               XamlFilePath = parentContext.XamlFilePath,
                        };
                        node.Accept(new CreateObjectVisitor(templateContext), null);
                        node.Accept(new SetNamescopesAndRegisterNamesVisitor(templateContext), null);
index 05cd863..401409c 100644 (file)
@@ -189,7 +189,7 @@ namespace Xamarin.Forms.Build.Tasks
 
                                                LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing {0}.InitializeComponent ()");
                                                Exception e;
-                                               if (!TryCoreCompile(initComp, initCompRuntime, rootnode, out e)) {
+                                               if (!TryCoreCompile(initComp, initCompRuntime, rootnode, xamlFilePath, out e)) {
                                                        success = false;
                                                        LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
                                                        (thrownExceptions = thrownExceptions ?? new List<Exception>()).Add(e);
@@ -263,7 +263,7 @@ namespace Xamarin.Forms.Build.Tasks
                        return success;
                }
 
-               bool TryCoreCompile(MethodDefinition initComp, MethodDefinition initCompRuntime, ILRootNode rootnode, out Exception exception)
+               bool TryCoreCompile(MethodDefinition initComp, MethodDefinition initCompRuntime, ILRootNode rootnode, string xamlFilePath, out Exception exception)
                {
                        try {
                                var body = new MethodBody(initComp);
@@ -328,7 +328,11 @@ namespace Xamarin.Forms.Build.Tasks
                                        il.Append(nop);
                                }
 
-                               var visitorContext = new ILContext(il, body, module);
+                               var visitorContext = new ILContext(il, body, module) {
+                                       DefineDebug = DebugSymbols || (!string.IsNullOrEmpty(DebugType) && DebugType.ToLowerInvariant() != "none"),
+                                       XamlFilePath = xamlFilePath
+                               };
+
 
                                rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null);
                                rootnode.Accept(new ExpandMarkupsVisitor(visitorContext), null);
@@ -339,6 +343,8 @@ namespace Xamarin.Forms.Build.Tasks
                                rootnode.Accept(new SetResourcesVisitor(visitorContext), null);
                                rootnode.Accept(new SetPropertiesVisitor(visitorContext, true), null);
 
+                               il.Append(SetPropertiesVisitor.RegisterSourceInfo(visitorContext, rootnode));
+
                                il.Emit(Ret);
                                initComp.Body = body;
                                exception = null;
index ae6cd8c..c506f75 100644 (file)
@@ -62,7 +62,7 @@ namespace Xamarin.Forms.Build.Tasks
                                        }
 
                                        XamlParser.ParseXaml(
-                                               rootnode = new ILRootNode(new XmlType(reader.NamespaceURI, reader.Name, null), typeReference, reader as IXmlNamespaceResolver), reader);
+                                               rootnode = new ILRootNode(new XmlType(reader.NamespaceURI, reader.Name, null), typeReference, reader as IXmlNamespaceResolver, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition), reader);
                                        break;
                                }
                        }
index 6fdeec1..8f63872 100644 (file)
@@ -1,21 +1,23 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 using System;
-using System.Collections.Generic;
-using System.Diagnostics;
+using System.ComponentModel;
 using System.Runtime.CompilerServices;
 
 namespace Xamarin.Forms.Xaml.Diagnostics
 {
-       class VisualDiagnostics
+       public class VisualDiagnostics
        {
                static ConditionalWeakTable<object, XamlSourceInfo> sourceInfos = new ConditionalWeakTable<object, XamlSourceInfo>();
-               internal static void RegisterSourceInfo(object target, Uri uri, int lineNumber, int linePosition)
+
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static void RegisterSourceInfo(object target, Uri uri, int lineNumber, int linePosition)
                {
-                       if (DebuggerHelper.DebuggerIsAttached && !sourceInfos.TryGetValue(target, out _))
+                       if (target != null && DebuggerHelper.DebuggerIsAttached && !sourceInfos.TryGetValue(target, out _))
                                sourceInfos.Add(target, new XamlSourceInfo(uri, lineNumber, linePosition));
                }
 
+               [EditorBrowsable(EditorBrowsableState.Never)]
                internal static void SendVisualTreeChanged(object parent, object child)
                {
                        if (DebuggerHelper.DebuggerIsAttached)
@@ -26,7 +28,7 @@ namespace Xamarin.Forms.Xaml.Diagnostics
                public static XamlSourceInfo GetXamlSourceInfo(object obj) => sourceInfos.TryGetValue(obj, out var sourceinfo) ? sourceinfo : null;
        }
 
-       class XamlSourceInfo
+       public class XamlSourceInfo
        {
                public XamlSourceInfo(Uri sourceUri, int lineNumber, int linePosition)
                {
@@ -47,7 +49,7 @@ namespace Xamarin.Forms.Xaml.Diagnostics
                }
        }
 
-       class VisualTreeChangeEventArgs : EventArgs
+       public class VisualTreeChangeEventArgs : EventArgs
        {
                public VisualTreeChangeEventArgs(object parent, object child, int childIndex, VisualTreeChangeType changeType)
                {
@@ -63,7 +65,7 @@ namespace Xamarin.Forms.Xaml.Diagnostics
                public VisualTreeChangeType ChangeType { get; }
        }
 
-       enum VisualTreeChangeType
+       public enum VisualTreeChangeType
        {
                Add = 0,
                Remove = 1
index a6eea39..8262cf9 100644 (file)
@@ -190,7 +190,7 @@ namespace Xamarin.Forms.Xaml
 
        abstract class RootNode : ElementNode
        {
-               protected RootNode(XmlType xmlType, IXmlNamespaceResolver nsResolver) : base(xmlType, xmlType.NamespaceUri, nsResolver)
+               protected RootNode(XmlType xmlType, IXmlNamespaceResolver nsResolver, int linenumber = -1, int lineposition = -1) : base(xmlType, xmlType.NamespaceUri, nsResolver, linenumber: linenumber, lineposition: lineposition)
                {
                }