diff options
author | Tianqi Zhang <tianzh@microsoft.com> | 2020-06-10 06:07:55 +0300 |
---|---|---|
committer | Joel Martinez <joelmartinez@gmail.com> | 2020-06-10 18:23:10 +0300 |
commit | eaba6771fbf0fe994accb8e17fe274474e8dee79 (patch) | |
tree | dd9d7c76df8304518b371f3a452570b3e4f7f819 /mdoc/Mono.Documentation/Updater | |
parent | 5721d52f5ffa2c6100886ea47f7db4ba4264e28c (diff) |
refactor attribute formatter to be standalone class
Diffstat (limited to 'mdoc/Mono.Documentation/Updater')
15 files changed, 214 insertions, 27 deletions
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/ApplePlatformEnumFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/ApplePlatformEnumFormatter.cs index ec3485df..55dd508f 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/ApplePlatformEnumFormatter.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/ApplePlatformEnumFormatter.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.Linq; using Mono.Cecil; -
+ namespace Mono.Documentation.Updater -{
+{ /// <summary>A custom formatter for the ObjCRuntime.Platform enumeration.</summary> class ApplePlatformEnumFormatter : AttributeValueFormatter { @@ -17,8 +17,8 @@ namespace Mono.Documentation.Updater if (typename.Contains ("ObjCRuntime.Platform") && valueDef.CustomAttributes.Any (ca => ca.AttributeType.FullName == "System.FlagsAttribute")) { - var values = MDocUpdater.GetEnumerationValues (valueDef); - long c = MDocUpdater.ToInt64 (v); + var values = GetEnumerationValues (valueDef); + long c = ToInt64 (v); returnvalue = Format (c, values, typename); return true; diff --git a/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/AttributeFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/AttributeFormatter.cs new file mode 100644 index 00000000..a0200d0d --- /dev/null +++ b/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/AttributeFormatter.cs @@ -0,0 +1,157 @@ +using Mono.Cecil; +using Mono.Documentation.Util; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Mono.Documentation.Updater.Formatters +{ + public class AttributeFormatter + { + public IEnumerable<string> GetCustomAttributes(MemberReference mi) + { + IEnumerable<string> attrs = Enumerable.Empty<string>(); + + ICustomAttributeProvider p = mi as ICustomAttributeProvider; + if (p != null) + attrs = attrs.Concat(GetCustomAttributes(p.CustomAttributes, "")); + + TypeDefinition typeDefinition = mi as TypeDefinition; + if (typeDefinition != null && typeDefinition.IsSerializable) + { + attrs = attrs.Concat(new[] { "System.Serializable" }); + } + + PropertyDefinition pd = mi as PropertyDefinition; + if (pd != null) + { + if (pd.GetMethod != null) + attrs = attrs.Concat(GetCustomAttributes(pd.GetMethod.CustomAttributes, "get: ")); + if (pd.SetMethod != null) + attrs = attrs.Concat(GetCustomAttributes(pd.SetMethod.CustomAttributes, "set: ")); + } + + EventDefinition ed = mi as EventDefinition; + if (ed != null) + { + if (ed.AddMethod != null) + attrs = attrs.Concat(GetCustomAttributes(ed.AddMethod.CustomAttributes, "add: ")); + if (ed.RemoveMethod != null) + attrs = attrs.Concat(GetCustomAttributes(ed.RemoveMethod.CustomAttributes, "remove: ")); + } + + return attrs; + } + + public IEnumerable<string> GetCustomAttributes(IList<CustomAttribute> attributes, string prefix) + { + foreach (CustomAttribute attribute in attributes.OrderBy(ca => ca.AttributeType.FullName).Where(i => !IsIgnoredAttribute(i))) + { + TypeDefinition attrType = attribute.AttributeType as TypeDefinition; + if (attrType != null && !DocUtils.IsPublic(attrType)) + continue; + if (FormatterManager.SlashdocFormatter.GetName(attribute.AttributeType) == null) + continue; + + if (Array.IndexOf(IgnorableAttributes, attribute.AttributeType.FullName) >= 0) + continue; + + var fields = new List<string>(); + + for (int i = 0; i < attribute.ConstructorArguments.Count; ++i) + { + CustomAttributeArgument argument = attribute.ConstructorArguments[i]; + fields.Add(MakeAttributesValueString( + argument.Value, + argument.Type)); + } + var namedArgs = + (from namedArg in attribute.Fields + select new { Type = namedArg.Argument.Type, Name = namedArg.Name, Value = namedArg.Argument.Value }) + .Concat( + (from namedArg in attribute.Properties + select new { Type = namedArg.Argument.Type, Name = namedArg.Name, Value = namedArg.Argument.Value })) + .OrderBy(v => v.Name); + foreach (var d in namedArgs) + fields.Add(string.Format("{0}={1}", d.Name, + MakeAttributesValueString(d.Value, d.Type))); + + string a2 = String.Join(", ", fields.ToArray()); + if (a2 != "") a2 = "(" + a2 + ")"; + + string name = attribute.GetDeclaringType(); + if (name.EndsWith("Attribute")) name = name.Substring(0, name.Length - "Attribute".Length); + yield return prefix + name + a2; + } + } + + public static string MakeAttributesValueString(object v, TypeReference valueType) + { + var formatters = new[] { + new AttributeValueFormatter (), + new ApplePlatformEnumFormatter (), + new StandardFlagsEnumFormatter (), + new DefaultAttributeValueFormatter (), + }; + + ResolvedTypeInfo type = new ResolvedTypeInfo(valueType); + + if (valueType is ArrayType && v is CustomAttributeArgument[]) + { + ArrayType atype = valueType as ArrayType; + CustomAttributeArgument[] args = v as CustomAttributeArgument[]; + var returnvalue = $"new {atype.FullName}{(atype.FullName.EndsWith("[]") ? "" : "[]")} {{ { string.Join(", ", args.Select(a => MakeAttributesValueString(a.Value, a.Type)).ToArray()) } }}"; + return returnvalue; + } + + foreach (var formatter in formatters) + { + string formattedValue; + if (formatter.TryFormatValue(v, type, out formattedValue)) + { + return formattedValue; + } + } + + // this should never occur because the DefaultAttributeValueFormatter will always + // successfully format the value ... but this is needed to satisfy the compiler :) + throw new InvalidDataException(string.Format("Unable to format attribute value ({0})", v.ToString())); + } + + private bool IsIgnoredAttribute(CustomAttribute customAttribute) + { + // An Obsolete attribute with a known string is added to all ref-like structs + // https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/span-safety.md#metadata-representation-or-ref-like-structs + return customAttribute.AttributeType.FullName == typeof(ObsoleteAttribute).FullName + && customAttribute.HasConstructorArguments + && customAttribute.ConstructorArguments.First().Value.ToString() == Consts.RefTypeObsoleteString; + } + + // FIXME: get TypeReferences instead of string comparison? + private static string[] IgnorableAttributes = { + // Security related attributes + "System.Reflection.AssemblyKeyFileAttribute", + "System.Reflection.AssemblyDelaySignAttribute", + // Present in @RefType + "System.Runtime.InteropServices.OutAttribute", + // For naming the indexer to use when not using indexers + "System.Reflection.DefaultMemberAttribute", + // for decimal constants + "System.Runtime.CompilerServices.DecimalConstantAttribute", + // compiler generated code + Consts.CompilerGeneratedAttribute, + // more compiler generated code, e.g. iterator methods + "System.Diagnostics.DebuggerHiddenAttribute", + "System.Runtime.CompilerServices.FixedBufferAttribute", + "System.Runtime.CompilerServices.UnsafeValueTypeAttribute", + "System.Runtime.CompilerServices.AsyncStateMachineAttribute", + // extension methods + "System.Runtime.CompilerServices.ExtensionAttribute", + // Used to differentiate 'object' from C#4 'dynamic' + "System.Runtime.CompilerServices.DynamicAttribute", + // F# compiler attribute + "Microsoft.FSharp.Core.CompilationMapping", + }; + } +} diff --git a/mdoc/Mono.Documentation/Updater/Formatters/AttributeValueFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/AttributeValueFormatter.cs index adefc633..e937e21d 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/AttributeValueFormatter.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/AttributeValueFormatter.cs @@ -1,11 +1,12 @@ using System; - +using System.Collections.Generic; +using System.Linq; using Mono.Cecil; using Mono.Documentation.Util; -
+ namespace Mono.Documentation.Updater -{
+{ /// <summary>Formats attribute values. Should return true if it is able to format the value.</summary> class AttributeValueFormatter { @@ -51,8 +52,8 @@ namespace Mono.Documentation.Updater } string typename = MDocUpdater.GetDocTypeFullName (valueType); - var values = MDocUpdater.GetEnumerationValues (valueDef); - long c = MDocUpdater.ToInt64 (v); + var values = GetEnumerationValues (valueDef); + long c = ToInt64 (v); if (values.ContainsKey (c)) { returnvalue = typename + "." + values[c]; @@ -62,5 +63,25 @@ namespace Mono.Documentation.Updater returnvalue = null; return false; } + + internal static IDictionary<long, string> GetEnumerationValues(TypeDefinition type) + { + var values = new Dictionary<long, string>(); + foreach (var f in + (from f in type.Fields + where !(f.IsRuntimeSpecialName || f.IsSpecialName) + select f)) + { + values[ToInt64(f.Constant)] = f.Name; + } + return values; + } + + internal static long ToInt64(object value) + { + if (value is ulong) + return (long)(ulong)value; + return Convert.ToInt64(value); + } } }
\ No newline at end of file diff --git a/mdoc/Mono.Documentation/Updater/Formatters/DefaultAttributeValueFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/DefaultAttributeValueFormatter.cs index f120b315..09c640a2 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/DefaultAttributeValueFormatter.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/DefaultAttributeValueFormatter.cs @@ -1,5 +1,5 @@ namespace Mono.Documentation.Updater -{
+{ /// <summary>The final value formatter in the pipeline ... if no other formatter formats the value, /// then this one will serve as the default implementation.</summary> class DefaultAttributeValueFormatter : AttributeValueFormatter diff --git a/mdoc/Mono.Documentation/Updater/Formatters/StandardFlagsEnumFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/StandardFlagsEnumFormatter.cs index 337b6877..16a1ebe0 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/StandardFlagsEnumFormatter.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/StandardFlagsEnumFormatter.cs @@ -1,9 +1,9 @@ using System.Linq; using Mono.Cecil; -
+ namespace Mono.Documentation.Updater -{
+{ /// <summary>Flags enum formatter that assumes powers of two values.</summary> /// <remarks>As described here: https://msdn.microsoft.com/en-us/library/vstudio/ms229062(v=vs.100).aspx</remarks> class StandardFlagsEnumFormatter : AttributeValueFormatter @@ -16,8 +16,8 @@ namespace Mono.Documentation.Updater { string typename = MDocUpdater.GetDocTypeFullName (valueType); - var values = MDocUpdater.GetEnumerationValues (valueDef); - long c = MDocUpdater.ToInt64 (v); + var values = GetEnumerationValues (valueDef); + long c = ToInt64 (v); returnvalue = string.Join (" | ", (from i in values.Keys where (c & i) == i && i != 0 diff --git a/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs index dff0099d..e63529bd 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs @@ -5,10 +5,9 @@ using System.Linq; using System.Text; using Mono.Cecil; - using Mono.Documentation.Util; -namespace Mono.Documentation.Updater +namespace Mono.Documentation.Updater.Formatters { public class CSharpFullMemberFormatter : MemberFormatter { @@ -542,7 +541,7 @@ namespace Mono.Documentation.Updater buf.Append (parameter.Name); if (parameter.HasDefault && parameter.IsOptional && parameter.HasConstant) { - var ReturnVal = MDocUpdater.MakeAttributesValueString(parameter.Constant, parameter.ParameterType); + var ReturnVal = AttributeFormatter.MakeAttributesValueString(parameter.Constant, parameter.ParameterType); buf.AppendFormat (" = {0}", ReturnVal == "null" ? "default" : ReturnVal); } return buf; diff --git a/mdoc/Mono.Documentation/Updater/Formatters/CSharpMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/CSharpMemberFormatter.cs index aa0bc31c..2c118281 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/CSharpMemberFormatter.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/CSharpMemberFormatter.cs @@ -2,7 +2,7 @@ using Mono.Cecil; -namespace Mono.Documentation.Updater +namespace Mono.Documentation.Updater.Formatters {
public class CSharpMemberFormatter : CSharpFullMemberFormatter { diff --git a/mdoc/Mono.Documentation/Updater/Formatters/CSharpNativeTypeMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/CSharpNativeTypeMemberFormatter.cs index 9d8c8bbb..a37f9848 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/CSharpNativeTypeMemberFormatter.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/CSharpNativeTypeMemberFormatter.cs @@ -1,4 +1,4 @@ -namespace Mono.Documentation.Updater +namespace Mono.Documentation.Updater.Formatters {
class CSharpNativeTypeMemberFormatter : CSharpFullMemberFormatter { diff --git a/mdoc/Mono.Documentation/Updater/Formatters/CppFormatters/CppWinRtFullMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/CppFormatters/CppWinRtFullMemberFormatter.cs index 08c2da19..c0316671 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/CppFormatters/CppWinRtFullMemberFormatter.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/CppFormatters/CppWinRtFullMemberFormatter.cs @@ -103,7 +103,7 @@ namespace Mono.Documentation.Updater.Formatters.CppFormatters if (parameter.HasDefault && parameter.IsOptional && parameter.HasConstant) { - buf.AppendFormat(" = {0}", MDocUpdater.MakeAttributesValueString(parameter.Constant, parameter.ParameterType)); + buf.AppendFormat(" = {0}", AttributeFormatter.MakeAttributesValueString(parameter.Constant, parameter.ParameterType)); } return buf; diff --git a/mdoc/Mono.Documentation/Updater/Formatters/FormatterManager.cs b/mdoc/Mono.Documentation/Updater/Formatters/FormatterManager.cs index 1969eb77..f47663d3 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/FormatterManager.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/FormatterManager.cs @@ -19,6 +19,8 @@ namespace Mono.Documentation.Updater.Formatters public static DocIdFormatter DocIdFormatter { get; private set; } = new DocIdFormatter(MDocUpdater.Instance.TypeMap); + public static MemberFormatter SlashdocFormatter { get; private set; } = new SlashDocMemberFormatter(MDocUpdater.Instance.TypeMap); + public static void AddFormatter(string langId) { MemberFormatter memberFormatter; @@ -62,5 +64,13 @@ namespace Mono.Documentation.Updater.Formatters TypeFormatters.Add(typeFormatter); MemberFormatters.Add(memberFormatter); } + + public static void UpdateTypeMap(TypeMap typeMap) + { + DocIdFormatter.TypeMap = typeMap; + SlashdocFormatter.TypeMap = typeMap; + foreach (var f in TypeFormatters.Union(MemberFormatters)) + f.TypeMap = typeMap; + } } } diff --git a/mdoc/Mono.Documentation/Updater/Formatters/ILFullMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/ILFullMemberFormatter.cs index 965355fa..4718f560 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/ILFullMemberFormatter.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/ILFullMemberFormatter.cs @@ -8,7 +8,7 @@ using Mono.Cecil; using Mono.Documentation.Util; -namespace Mono.Documentation.Updater +namespace Mono.Documentation.Updater.Formatters { public class ILFullMemberFormatter : MemberFormatter { @@ -184,7 +184,7 @@ namespace Mono.Documentation.Updater buf.Append (full.GetName (type.BaseType).Substring ("class ".Length)); } bool first = true; - foreach (var name in type.Interfaces.Where (i => MDocUpdater.IsPublic (i.InterfaceType.Resolve ())) + foreach (var name in type.Interfaces.Where (i => DocUtils.IsPublic (i.InterfaceType.Resolve ())) .Select (i => full.GetName (i.InterfaceType)) .OrderBy (n => n)) { diff --git a/mdoc/Mono.Documentation/Updater/Formatters/ILMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/ILMemberFormatter.cs index a6a902dc..673334ea 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/ILMemberFormatter.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/ILMemberFormatter.cs @@ -2,7 +2,7 @@ using Mono.Cecil; -namespace Mono.Documentation.Updater +namespace Mono.Documentation.Updater.Formatters {
public class ILMemberFormatter : ILFullMemberFormatter { diff --git a/mdoc/Mono.Documentation/Updater/Formatters/ILNativeTypeMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/ILNativeTypeMemberFormatter.cs index 053aa496..fa80db03 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/ILNativeTypeMemberFormatter.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/ILNativeTypeMemberFormatter.cs @@ -1,4 +1,4 @@ -namespace Mono.Documentation.Updater +namespace Mono.Documentation.Updater.Formatters {
class ILNativeTypeMemberFormatter : ILFullMemberFormatter { diff --git a/mdoc/Mono.Documentation/Updater/Formatters/VBFullMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/VBFullMemberFormatter.cs index cfa69406..35cd4762 100644 --- a/mdoc/Mono.Documentation/Updater/Formatters/VBFullMemberFormatter.cs +++ b/mdoc/Mono.Documentation/Updater/Formatters/VBFullMemberFormatter.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Text; using Mono.Cecil; +using Mono.Documentation.Updater.Formatters; using Mono.Documentation.Util; namespace Mono.Documentation.Updater @@ -583,7 +584,7 @@ namespace Mono.Documentation.Updater buf.Append(GetTypeName(parameter.ParameterType, new DynamicParserContext(parameter))); if (parameter.HasDefault && parameter.IsOptional && parameter.HasConstant) { - var parameterValue = MDocUpdater.MakeAttributesValueString(parameter.Constant, parameter.ParameterType); + var parameterValue = AttributeFormatter.MakeAttributesValueString(parameter.Constant, parameter.ParameterType); buf.AppendFormat(" = {0}", parameterValue == "null" ? "Nothing" : parameterValue); } return buf; diff --git a/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs index 12418e6f..204e0fd0 100644 --- a/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs +++ b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using Mono.Cecil; -using Mono.Cecil.Rocks; +using Mono.Documentation.Updater.Formatters; namespace Mono.Documentation.Updater.Frameworks { @@ -12,7 +12,6 @@ namespace Mono.Documentation.Updater.Frameworks Dictionary<string, bool> sigDocMap = new Dictionary<string, bool>(); ILFullMemberFormatter formatterField; - DocIdFormatter docidFormatterField; ILFullMemberFormatter formatter { get |