diff options
author | Eugene Rozenfeld <erozen@microsoft.com> | 2017-03-24 09:07:13 +0300 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2017-04-01 09:06:26 +0300 |
commit | d6910ee0d3374b2bb1808d3b4edbf68a47c532c5 (patch) | |
tree | db05be6ebb80e299304309d8653c966af37a5f37 /linker | |
parent | 411ef52ceefaa8e08c8f52d0f9644c722b850d81 (diff) |
Mark methods and fields needed for types with debugger attributes.
Add an option (-v) to keep members needed for types with debugger attributes:
1. Keep the fields, methods, and properties specified in the string passed
to the constructor of DebuggerDisplayAttribute if they can be easily extracted
from the string; otherwise, keep all fields and methods in the type and its
base types .
2. Keep all fields and methods in proxy types from DebuggerTypeProxyAttribute.
Diffstat (limited to 'linker')
-rw-r--r-- | linker/Mono.Linker.Steps/MarkStep.cs | 87 | ||||
-rw-r--r-- | linker/Mono.Linker/Driver.cs | 4 | ||||
-rw-r--r-- | linker/Mono.Linker/LinkContext.cs | 7 |
3 files changed, 98 insertions, 0 deletions
diff --git a/linker/Mono.Linker.Steps/MarkStep.cs b/linker/Mono.Linker.Steps/MarkStep.cs index 9b2692588..1e48b68d4 100644 --- a/linker/Mono.Linker.Steps/MarkStep.cs +++ b/linker/Mono.Linker.Steps/MarkStep.cs @@ -30,6 +30,7 @@ using System; using System.Collections; using System.Linq; +using System.Text.RegularExpressions; using Mono.Cecil; using Mono.Cecil.Cil; @@ -365,6 +366,19 @@ namespace Mono.Linker.Steps { return null; } + MethodDefinition GetMethodWithNoParameters (TypeDefinition type, string methodname) + { + while (type != null) { + MethodDefinition method = type.Methods.FirstOrDefault (m => m.Name == methodname && !m.HasParameters); + if (method != null) + return method; + + type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null; + } + + return null; + } + void MarkCustomAttributeArguments (CustomAttribute ca) { if (!ca.HasConstructorArguments) @@ -596,6 +610,12 @@ namespace Mono.Linker.Steps { case "System.Xml.Serialization.XmlSchemaProviderAttribute": MarkXmlSchemaProvider (type, attribute); break; + case "System.Diagnostics.DebuggerDisplayAttribute": + MarkTypeWithDebuggerDisplayAttribute (type, attribute); + break; + case "System.Diagnostics.DebuggerTypeProxyAttribute": + MarkTypeWithDebuggerTypeProxyAttribute (type, attribute); + break; } } } @@ -623,6 +643,73 @@ namespace Mono.Linker.Steps { MarkNamedMethod (type, method_name); } + void MarkTypeWithDebuggerDisplayAttribute (TypeDefinition type, CustomAttribute attribute) + { + if (_context.KeepMembersForDebuggerAttributes) { + + string displayString = (string) attribute.ConstructorArguments[0].Value; + + Regex regex = new Regex ("{[^{}]+}", RegexOptions.Compiled); + + foreach (Match match in regex.Matches (displayString)) { + // Remove '{' and '}' + string realMatch = match.Value.Substring (1, match.Value.Length - 2); + + // Remove ",nq" suffix if present + // (it asks the expression evaluator to remove the quotes when displaying the final value) + if (Regex.IsMatch(realMatch, @".+,\s*nq")) { + realMatch = realMatch.Substring (0, realMatch.LastIndexOf (',')); + } + + if (realMatch.EndsWith ("()")) { + string methodName = realMatch.Substring (0, realMatch.Length - 2); + MethodDefinition method = GetMethodWithNoParameters (type, methodName); + if (method != null) { + MarkMethod (method); + continue; + } + } else { + FieldDefinition field = GetField (type, realMatch); + if (field != null) { + MarkField (field); + continue; + } + + PropertyDefinition property = GetProperty (type, realMatch); + if (property != null) { + if (property.GetMethod != null) { + MarkMethod (property.GetMethod); + } + if (property.SetMethod != null) { + MarkMethod (property.SetMethod); + } + continue; + } + } + + while (type != null) { + MarkMethods (type); + MarkFields (type, includeStatic: true); + type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null; + } + return; + } + } + } + + void MarkTypeWithDebuggerTypeProxyAttribute (TypeDefinition type, CustomAttribute attribute) + { + if (_context.KeepMembersForDebuggerAttributes) { + TypeReference proxyTypeReference = (TypeReference) attribute.ConstructorArguments [0].Value; + + MarkType (proxyTypeReference); + + TypeDefinition proxyType = ResolveTypeDefinition (proxyTypeReference); + MarkMethods (proxyType); + MarkFields (proxyType, includeStatic: true); + } + } + static bool TryGetStringArgument (CustomAttribute attribute, out string argument) { argument = null; diff --git a/linker/Mono.Linker/Driver.cs b/linker/Mono.Linker/Driver.cs index d2a32f178..28d8512bf 100644 --- a/linker/Mono.Linker/Driver.cs +++ b/linker/Mono.Linker/Driver.cs @@ -163,6 +163,9 @@ namespace Mono.Linker { if (!bool.Parse (GetParam ())) p.RemoveStep (typeof (RegenerateGuidStep)); break; + case 'v': + context.KeepMembersForDebuggerAttributes = bool.Parse (GetParam ()); + break; default: Usage ("Unknown option: `" + token [1] + "'"); break; @@ -293,6 +296,7 @@ namespace Mono.Linker { Console.WriteLine (" -d Add a directory where the linker will look for assemblies"); Console.WriteLine (" -b Generate debug symbols for each linked module (true or false)"); Console.WriteLine (" -g Generate a new unique guid for each linked module (true or false)"); + Console.WriteLine (" -v Keep memebers needed by debugger attributes (true or false)"); Console.WriteLine (" -l List of i18n assemblies to copy to the output directory"); Console.WriteLine (" separated with a comma: none,all,cjk,mideast,other,rare,west"); Console.WriteLine (" default is all"); diff --git a/linker/Mono.Linker/LinkContext.cs b/linker/Mono.Linker/LinkContext.cs index db7481a37..f5629ed56 100644 --- a/linker/Mono.Linker/LinkContext.cs +++ b/linker/Mono.Linker/LinkContext.cs @@ -44,6 +44,7 @@ namespace Mono.Linker { Hashtable _parameters; bool _linkSymbols; bool _keepTypeForwarderOnlyAssemblies; + bool _keepMembersForDebuggerAttributes; AssemblyResolver _resolver; @@ -82,6 +83,12 @@ namespace Mono.Linker { set { _keepTypeForwarderOnlyAssemblies = value; } } + public bool KeepMembersForDebuggerAttributes + { + get { return _keepMembersForDebuggerAttributes; } + set { _keepMembersForDebuggerAttributes = value; } + } + public IDictionary Actions { get { return _actions; } } |