Skip to content

Commit

Permalink
Support F# style Attribute rendering (#503)
Browse files Browse the repository at this point in the history
  • Loading branch information
TianqiZhang authored and joelmartinez committed Sep 1, 2020
1 parent 7faef8f commit 426d664
Show file tree
Hide file tree
Showing 477 changed files with 3,556 additions and 2,068 deletions.
1 change: 1 addition & 0 deletions mdoc/Consts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public static class Consts
public const string CppCli = "C++ CLI";
public const string CppCx = "C++ CX";
public const string CppWinRt = "C++ WINRT";
public const string CSharp = "C#";
public const string VbNet = "VB.NET";
public const string DocIdLowCase = "docid";
public const string VbNetLowCase = "vb.net";
Expand Down
444 changes: 219 additions & 225 deletions mdoc/Mono.Documentation/MDocUpdater.cs

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions mdoc/Mono.Documentation/Updater/DocUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static class DocUtils

public static void AddElementWithFx(FrameworkTypeEntry typeEntry, XmlElement parent, bool isFirst, bool isLast, Lazy<string> allfxstring, Action<XmlElement> clear, Func<XmlElement, XmlElement> findExisting, Func<XmlElement, XmlElement> addItem)
{
if (typeEntry.TimesProcessed > 1)
if (typeEntry != null && typeEntry.TimesProcessed > 1)
return;

if (isFirst)
Expand All @@ -33,7 +33,10 @@ public static void AddElementWithFx(FrameworkTypeEntry typeEntry, XmlElement par
item = addItem(parent);
}

item.AddFrameworkToElement(typeEntry.Framework);
if (typeEntry != null)
{
item.AddFrameworkToElement(typeEntry.Framework);
}

if (isLast)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,81 +9,114 @@ namespace Mono.Documentation.Updater.Formatters
{
public class AttributeFormatter
{
public IEnumerable<string> GetCustomAttributes(MemberReference mi)
{
IEnumerable<string> attrs = Enumerable.Empty<string>();
public virtual string PrefixBrackets { get; } = "";
public virtual string SurfixBrackets { get; } = "";
public virtual string Language { get; } = "";

ICustomAttributeProvider p = mi as ICustomAttributeProvider;
if (p != null)
attrs = attrs.Concat(GetCustomAttributes(p.CustomAttributes, ""));
public static IEnumerable<(CustomAttribute, string)> GetCustomAttributes(MemberReference mi)
{
List<(CustomAttribute, string)> customAttributes = new List<(CustomAttribute, string)>();
if (mi is ICustomAttributeProvider p && p.CustomAttributes?.Count > 0)
{
customAttributes.AddRange(PreProcessCustomAttributes(p.CustomAttributes));
}

TypeDefinition typeDefinition = mi as TypeDefinition;
if (typeDefinition != null && typeDefinition.IsSerializable)
if (mi is TypeDefinition typeDefinition && typeDefinition.IsSerializable)
{
attrs = attrs.Concat(new[] { "System.Serializable" });
customAttributes.Add((null, "System.Serializable"));
}

PropertyDefinition pd = mi as PropertyDefinition;
if (pd != null)
if (mi is PropertyDefinition pd)
{
if (pd.GetMethod != null)
attrs = attrs.Concat(GetCustomAttributes(pd.GetMethod.CustomAttributes, "get: "));
{
customAttributes.AddRange(PreProcessCustomAttributes(pd.GetMethod.CustomAttributes, "get: "));
}
if (pd.SetMethod != null)
attrs = attrs.Concat(GetCustomAttributes(pd.SetMethod.CustomAttributes, "set: "));
{
customAttributes.AddRange(PreProcessCustomAttributes(pd.SetMethod.CustomAttributes, "set: "));
}
}

EventDefinition ed = mi as EventDefinition;
if (ed != null)
if (mi is EventDefinition ed)
{
if (ed.AddMethod != null)
attrs = attrs.Concat(GetCustomAttributes(ed.AddMethod.CustomAttributes, "add: "));
{
customAttributes.AddRange(PreProcessCustomAttributes(ed.AddMethod.CustomAttributes, "add: "));
}
if (ed.RemoveMethod != null)
attrs = attrs.Concat(GetCustomAttributes(ed.RemoveMethod.CustomAttributes, "remove: "));
{
customAttributes.AddRange(PreProcessCustomAttributes(ed.RemoveMethod.CustomAttributes, "remove: "));
}
}
return customAttributes;
}

return attrs;
public static IEnumerable<(CustomAttribute, string)> PreProcessCustomAttributes(IEnumerable<CustomAttribute> customAttributes, string prefix = "")
{
return customAttributes?.OrderBy(ca => ca.AttributeType.FullName).Select(attr => (attr, prefix));
}

public IEnumerable<string> GetCustomAttributes(IList<CustomAttribute> attributes, string prefix)
public virtual bool TryGetAttributeString(CustomAttribute attribute, out string rval, string prefix = null, bool withBrackets = true)
{
foreach (CustomAttribute attribute in attributes.OrderBy(ca => ca.AttributeType.FullName).Where(i => !IsIgnoredAttribute(i)))
if (attribute == null)
{
TypeDefinition attrType = attribute.AttributeType as TypeDefinition;
if (attrType != null && !DocUtils.IsPublic(attrType))
continue;
if (FormatterManager.SlashdocFormatter.GetName(attribute.AttributeType) == null)
continue;
if (string.IsNullOrEmpty(prefix))
{
rval = null;
return false;
}
rval = withBrackets ? PrefixBrackets + prefix + SurfixBrackets : prefix;
return true;
}

if (Array.IndexOf(IgnorableAttributes, attribute.AttributeType.FullName) >= 0)
continue;
if (IsIgnoredAttribute(attribute))
{
rval = null;
return false;
}

TypeDefinition attrType = attribute.AttributeType as TypeDefinition;
if (attrType != null && !DocUtils.IsPublic(attrType)
|| (FormatterManager.SlashdocFormatter.GetName(attribute.AttributeType) == null)
|| Array.IndexOf(IgnorableAttributes, attribute.AttributeType.FullName) >= 0)
{
rval = null;
return false;
}

var fields = new List<string>();
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;
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(MakeNamedArgumentString(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);
rval = withBrackets ? PrefixBrackets + prefix + name + a2 + SurfixBrackets
: prefix + name + a2;
return true;
}

protected virtual string MakeNamedArgumentString(string name, string value)
{
return $"{name}={value}";
}

public static string MakeAttributesValueString(object v, TypeReference valueType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ public virtual bool TryFormatValue (object v, ResolvedTypeInfo type, out string
}
if (valueType.FullName == "System.String")
{
returnvalue = "\"" + MDocUpdater.FilterSpecialChars (v.ToString ()) + "\"";
returnvalue = "\"" + FilterSpecialChars (v.ToString ()) + "\"";
return true;
}
if (valueType.FullName == "System.Char")
{
returnvalue = "'" + MDocUpdater.FilterSpecialChars (v.ToString ()) + "'";
returnvalue = "'" + FilterSpecialChars (v.ToString ()) + "'";
return true;
}
if (v is Boolean)
Expand Down Expand Up @@ -83,5 +83,15 @@ internal static long ToInt64(object value)
return (long)(ulong)value;
return Convert.ToInt64(value);
}

public static string FilterSpecialChars(string value)
{
return value.Replace("\0", "\\0")
.Replace("\t", "\\t")
.Replace("\n", "\\n")
.Replace("\r", "\\r")
.Replace("\f", "\\f")
.Replace("\b", "\\b");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Mono.Documentation.Updater.Formatters
{
class CSharpAttributeFormatter : AttributeFormatter
{
public override string PrefixBrackets { get; } = "[";
public override string SurfixBrackets { get; } = "]";
public override string Language => Consts.CSharp;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class DefaultAttributeValueFormatter : AttributeValueFormatter
{
public override bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue)
{
returnvalue = "(" + MDocUpdater.GetDocTypeFullName (type.Reference) + ") " + MDocUpdater.FilterSpecialChars(v.ToString ());
returnvalue = "(" + MDocUpdater.GetDocTypeFullName (type.Reference) + ") " + FilterSpecialChars(v.ToString ());
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Mono.Documentation.Updater.Formatters
{
class FSharpAttributeFormatter : AttributeFormatter
{
public override string PrefixBrackets { get; } = "[<";
public override string SurfixBrackets { get; } = ">]";
public override string Language => Consts.FSharp;
}
}
56 changes: 30 additions & 26 deletions mdoc/Mono.Documentation/Updater/Formatters/FormatterManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,70 +7,74 @@ namespace Mono.Documentation.Updater.Formatters
{
static class FormatterManager
{
public static List<MemberFormatter> TypeFormatters { get; private set; } = new List<MemberFormatter>{
new CSharpMemberFormatter(MDocUpdater.Instance.TypeMap),
new ILMemberFormatter(MDocUpdater.Instance.TypeMap),
};
public static List<MemberFormatter> TypeFormatters { get; private set; } = new List<MemberFormatter>
{
new CSharpMemberFormatter(MDocUpdater.Instance.TypeMap),
new ILMemberFormatter(MDocUpdater.Instance.TypeMap),
};

public static List<MemberFormatter> MemberFormatters { get; private set; } = new List<MemberFormatter>
{
new CSharpFullMemberFormatter (MDocUpdater.Instance.TypeMap),
new ILFullMemberFormatter (MDocUpdater.Instance.TypeMap),
};

public static List<MemberFormatter> MemberFormatters { get; private set; } = new List<MemberFormatter>{
new CSharpFullMemberFormatter (MDocUpdater.Instance.TypeMap),
new ILFullMemberFormatter (MDocUpdater.Instance.TypeMap),
};
public static AttributeFormatter CSharpAttributeFormatter { get; private set; } = new CSharpAttributeFormatter();
public static List<AttributeFormatter> AdditionalAttributeFormatters { get; private set; } = new List<AttributeFormatter> { };

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;
MemberFormatter typeFormatter;
langId = langId.ToLower();
var map = MDocUpdater.Instance.TypeMap;
switch (langId)
{
case Consts.DocIdLowCase:
typeFormatter = DocIdFormatter;
memberFormatter = DocIdFormatter;
TypeFormatters.Add(DocIdFormatter);
MemberFormatters.Add(DocIdFormatter);
break;
case Consts.VbNetLowCase:
typeFormatter = new VBMemberFormatter(map);
memberFormatter = new VBMemberFormatter(map);
TypeFormatters.Add(new VBMemberFormatter(map));
MemberFormatters.Add(new VBMemberFormatter(map));
break;
case Consts.CppCliLowCase:
typeFormatter = new CppMemberFormatter(map);
memberFormatter = new CppFullMemberFormatter(map);
TypeFormatters.Add(new CppMemberFormatter(map));
MemberFormatters.Add(new CppFullMemberFormatter(map));
break;
case Consts.CppCxLowCase:
typeFormatter = new CppCxMemberFormatter(map);
memberFormatter = new CppCxFullMemberFormatter(map);
TypeFormatters.Add(new CppCxMemberFormatter(map));
MemberFormatters.Add(new CppCxFullMemberFormatter(map));
break;
case Consts.CppWinRtLowCase:
typeFormatter = new CppWinRtMemberFormatter(map);
memberFormatter = new CppWinRtFullMemberFormatter(map);
TypeFormatters.Add(new CppWinRtMemberFormatter(map));
MemberFormatters.Add(new CppWinRtFullMemberFormatter(map));
break;
case Consts.FSharpLowCase:
case "fsharp":
typeFormatter = new FSharpMemberFormatter(map);
memberFormatter = new FSharpFullMemberFormatter(map);
TypeFormatters.Add(new FSharpMemberFormatter(map));
MemberFormatters.Add(new FSharpFullMemberFormatter(map));
AdditionalAttributeFormatters.Add(new FSharpAttributeFormatter());
break;
case Consts.JavascriptLowCase:
typeFormatter = new JsMemberFormatter(map);
memberFormatter = new JsMemberFormatter(map);
TypeFormatters.Add(new JsMemberFormatter(map));
MemberFormatters.Add(new JsMemberFormatter(map));
break;
default:
throw new ArgumentException("Unsupported formatter id '" + langId + "'.");
}
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;
}
}
}
}
Loading

0 comments on commit 426d664

Please sign in to comment.