Skip to content

Add logic to generate type forwarding information to ECMAXML #452

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion mdoc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ Test/DocTest-typeForwards-Second.dll:
$(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -debug -optimize -target:library -out:$@ Test/DocTest-typeForwards.cs /define:FIRST
$(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -debug -optimize -target:library -out:Test/DocTest-typeForwards-Second-First.dll /reference:$@ Test/DocTest-typeForwards.cs /define:SECOND

.PHONY: Test/DocTest-typeForwards-Third.dll
Test/DocTest-typeForwards-Third.dll:
rm -f $@
rm -f Test/DocTest-typeForwards-Third-First.dll
$(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -debug -optimize -target:library -out:$@ Test/DocTest-typeForwards.cs /define:FIRST
$(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -debug -optimize -target:library -out:Test/DocTest-typeForwards-Third-First.dll /reference:$@ Test/DocTest-typeForwards.cs /define:THIRD

.PHONY: Test/FrameworkTestData
Test/FrameworkTestData: Test/DocTest-addNonGeneric.dll Test/DocTest-DropNS-classic.dll Test/DocTest-DropNS-classic-secondary.dll
rm -rf Test/FrameworkTestData
Expand All @@ -169,19 +176,34 @@ Test/FrameworkTestData-fx-inheritance: Test/DocTest-framework-inheritance-one.dl
$(MONO) $(PROGRAM) fx-bootstrap Test/FrameworkTestData-fx-inheritance

.PHONY: check-monodocer-typeForwards
check-monodocer-typeForwards : Test/DocTest-typeForwards-First.dll Test/DocTest-typeForwards-Second.dll
check-monodocer-typeForwards : Test/DocTest-typeForwards-First.dll Test/DocTest-typeForwards-Second.dll Test/DocTest-typeForwards-Third.dll
-rm -Rf Test/en.actual

# set up the fx test data
# all frameworks One, Two, Three should have the type forwarding from DocTest-typeForwards-Second-First to DocTest-typeForwards-Second \
# so in xml should find no "FrameworkAlternate" attribute for this forwarding, the attribute is removed as expected since it is full frameworks list
# frameworks Two and Three should have the type forwarding from DocTest-typeForwards-Third-First to DocTest-typeForwards-third \
# in xml we should see FrameworkAlternate="Three;Two"
-rm -Rf Test/FrameworkTestData-fx-typeForwards
mkdir Test/FrameworkTestData-fx-typeForwards
mkdir Test/FrameworkTestData-fx-typeForwards/One
mkdir Test/FrameworkTestData-fx-typeForwards/Two
mkdir Test/FrameworkTestData-fx-typeForwards/Three
mkdir Test/FrameworkTestData-fx-typeForwards/dependencies
mkdir Test/FrameworkTestData-fx-typeForwards/dependencies/One
mkdir Test/FrameworkTestData-fx-typeForwards/dependencies/Two
mkdir Test/FrameworkTestData-fx-typeForwards/dependencies/Three
cp Test/DocTest-typeForwards-First.dll Test/FrameworkTestData-fx-typeForwards/One
cp Test/DocTest-typeForwards-Second-First.dll Test/FrameworkTestData-fx-typeForwards/One
cp Test/DocTest-typeForwards-Second.dll Test/FrameworkTestData-fx-typeForwards/dependencies/One
cp Test/DocTest-typeForwards-Second-First.dll Test/FrameworkTestData-fx-typeForwards/Two
cp Test/DocTest-typeForwards-Third-First.dll Test/FrameworkTestData-fx-typeForwards/Two
cp Test/DocTest-typeForwards-Second.dll Test/FrameworkTestData-fx-typeForwards/dependencies/Two
cp Test/DocTest-typeForwards-Third.dll Test/FrameworkTestData-fx-typeForwards/dependencies/Two
cp Test/DocTest-typeForwards-Second-First.dll Test/FrameworkTestData-fx-typeForwards/Three
cp Test/DocTest-typeForwards-Third-First.dll Test/FrameworkTestData-fx-typeForwards/Three
cp Test/DocTest-typeForwards-Second.dll Test/FrameworkTestData-fx-typeForwards/dependencies/Three
cp Test/DocTest-typeForwards-Third.dll Test/FrameworkTestData-fx-typeForwards/dependencies/Three
$(MONO) $(PROGRAM) fx-bootstrap Test/FrameworkTestData-fx-typeForwards

# now run mdoc update
Expand Down
104 changes: 102 additions & 2 deletions mdoc/Mono.Documentation/MDocUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2214,6 +2214,7 @@ public void UpdateType (XmlElement root, TypeDefinition type, FrameworkTypeEntry
}

AddAssemblyNameToNode (root, type);
UpdateTypeForwardingChain(root, typeEntry, type);

string assemblyInfoNodeFilter = MDocUpdater.HasDroppedNamespace (type) ? "[@apistyle='unified']" : "[not(@apistyle) or @apistyle='classic']";
Func<XmlElement, bool> assemblyFilter = x => x.SelectSingleNode ("AssemblyName").InnerText == type.Module.Assembly.Name.Name;
Expand Down Expand Up @@ -2420,6 +2421,7 @@ XmlElement AddAssemblyNameToNodeCore (XmlElement root, AssemblyNameReference ass
"TypeSignature",
"MemberOfLibrary",
"AssemblyInfo",
"TypeForwardingChain",
"ThreadingSafetyStatement",
"ThreadSafetyStatement",
"TypeParameters",
Expand Down Expand Up @@ -3100,11 +3102,109 @@ private static bool GetFieldConstValue (FieldDefinition field, out string value)
return true;
}
return false;
}

/// <summary>
/// Update forwarding inforamtion of a given type under specified Framework to XmlElement
/// </summary>
private void UpdateTypeForwardingChain(XmlElement root, FrameworkTypeEntry typeEntry, TypeDefinition type)
{
if (typeEntry.TimesProcessed > 1)
return;

string elementName = "TypeForwardingChain";

// Get type forwardings of current type and framkework
var forwardings = this.assemblies
.Where(a => a.Name == typeEntry.Framework.Name)
.SelectMany(a => a.ForwardingChains(type))
.ToList();

XmlElement exsitingChain = (XmlElement)root.SelectSingleNode(elementName);

// Clean up and gernate from scratch
if (typeEntry.Framework.IsFirstFrameworkForType(typeEntry))
{
ClearElement(root, elementName);
exsitingChain = null;
}

// Update
if (forwardings.Any())
{
exsitingChain = exsitingChain ?? root.OwnerDocument.CreateElement(elementName);
root.AppendChild(UpdateTypeForwarding(forwardings, typeEntry.Framework.Name, exsitingChain));
}

// Purge attribute if needed
if (typeEntry.Framework.IsLastFrameworkForType(typeEntry) && exsitingChain != null)
PurgeFrameworkAlternateAttribute(typeEntry, exsitingChain.SelectNodes("TypeForwarding").SafeCast<XmlElement>().ToList());
}

private XmlElement UpdateTypeForwarding(IEnumerable<MDocResolver.TypeForwardEventArgs> forwardings, string framework, XmlElement exsitingChain)
{
Func<IEnumerable<XmlElement>> elementsQuery = () => exsitingChain.SelectNodes("TypeForwarding").SafeCast<XmlElement>();

foreach (var forwarding in forwardings)
{
var existingElements = elementsQuery()
.Where(e => IsTypeForwardingFound(e, forwarding))
.FirstOrDefault();

// Add type forwarding with fxa
if (existingElements == null)
{
var newElement = exsitingChain.OwnerDocument.CreateElement("TypeForwarding");
exsitingChain.AppendChild(newElement);
newElement.SetAttribute("From", forwarding.From.Name);
newElement.SetAttribute("FromVersion", forwarding.From.Version.ToString());
newElement.SetAttribute("To", forwarding.To.Name);
newElement.SetAttribute("ToVersion", forwarding.To.Version.ToString());
newElement.SetAttribute(Consts.FrameworkAlternate, framework);
}

// Update and append fxa
else
{
string newfxa = FXUtils.AddFXToList(existingElements.GetAttribute(Consts.FrameworkAlternate), framework);
existingElements.SetAttribute(Consts.FrameworkAlternate, newfxa);
}
}

return exsitingChain;
}

// XML HELPER FUNCTIONS
/// <summary>
/// Purge FrameworkAlternate attribute if it includes all frameworks
/// </summary>
private void PurgeFrameworkAlternateAttribute(FrameworkTypeEntry typeEntry, IEnumerable<XmlElement> nodes)
{
var allFrameworks = typeEntry.Framework.AllFrameworksWithType(typeEntry);

foreach (var node in nodes)
{
// if FXAlternate is entire list, just remove it
if (node.HasAttribute(Consts.FrameworkAlternate) && node.GetAttribute(Consts.FrameworkAlternate) == allFrameworks)
{
node.RemoveAttribute(Consts.FrameworkAlternate);
}
}
}

internal static XmlElement WriteElement (XmlNode parent, string element, bool forceNewElement = false)
/// <summary>
/// Return true if same type forward found in Xml
/// </summary>
private static bool IsTypeForwardingFound(XmlElement element, MDocResolver.TypeForwardEventArgs typeForward)
{
return (element.GetAttribute("From") == typeForward.From.Name)
&& (element.GetAttribute("FromVersion") == typeForward.From.Version.ToString())
&& (element.GetAttribute("To") == typeForward.To.Name)
&& (element.GetAttribute("ToVersion") == typeForward.To.Version.ToString());
}

// XML HELPER FUNCTIONS

internal static XmlElement WriteElement (XmlNode parent, string element, bool forceNewElement = false)
{
XmlElement ret = parent.ChildNodes.SafeCast<XmlElement>().FirstOrDefault(e => e.LocalName == element);
if (ret == null || forceNewElement)
Expand Down
19 changes: 17 additions & 2 deletions mdoc/Mono.Documentation/Updater/Frameworks/AssemblySet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,21 @@ IEnumerable<AssemblyDefinition> LoadAllAssemblies ()
}
yield return assembly;
}
}
}
}

/// <summary>
/// Return the type forwardings of given type.
/// </summary>
/// <param name="type">Type.</param>
/// <returns>Type forwardings.</returns>
public HashSet<MDocResolver.TypeForwardEventArgs> ForwardingChains(TypeDefinition type)
{
if (forwardedTypesTo.ContainsKey(type.FullName))
{
return forwardedTypesTo[type.FullName];
}
else
return new HashSet<MDocResolver.TypeForwardEventArgs>();
}
}
}
2 changes: 1 addition & 1 deletion mdoc/Test/DocTest-typeForwards.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if SECOND
#if SECOND || THIRD
using System.Runtime.CompilerServices;
[assembly:TypeForwardedToAttribute(typeof(TheNamespace.TheClass))]
#endif
Expand Down
1 change: 1 addition & 0 deletions mdoc/Test/en.expected.typeForwards/FrameworksIndex/One.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<Framework Name="One">
<Assemblies>
<Assembly Name="DocTest-typeForwards-First" Version="0.0.0.0" />
<Assembly Name="DocTest-typeForwards-Second-First" Version="0.0.0.0" />
</Assemblies>
<Namespace Name="TheNamespace">
<Type Name="TheNamespace.TheClass" Id="T:TheNamespace.TheClass">
Expand Down
12 changes: 12 additions & 0 deletions mdoc/Test/en.expected.typeForwards/FrameworksIndex/Three.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Framework Name="Three">
<Assemblies>
<Assembly Name="DocTest-typeForwards-Second-First" Version="0.0.0.0" />
<Assembly Name="DocTest-typeForwards-Third-First" Version="0.0.0.0" />
</Assemblies>
<Namespace Name="TheNamespace">
<Type Name="TheNamespace.TheClass" Id="T:TheNamespace.TheClass">
<Member Id="M:TheNamespace.TheClass.#ctor" />
</Type>
</Namespace>
</Framework>
1 change: 1 addition & 0 deletions mdoc/Test/en.expected.typeForwards/FrameworksIndex/Two.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<Framework Name="Two">
<Assemblies>
<Assembly Name="DocTest-typeForwards-Second-First" Version="0.0.0.0" />
<Assembly Name="DocTest-typeForwards-Third-First" Version="0.0.0.0" />
</Assemblies>
<Namespace Name="TheNamespace">
<Type Name="TheNamespace.TheClass" Id="T:TheNamespace.TheClass">
Expand Down
18 changes: 18 additions & 0 deletions mdoc/Test/en.expected.typeForwards/TheNamespace/TheClass.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@
<AssemblyInfo>
<AssemblyName>DocTest-typeForwards-Second-First</AssemblyName>
</AssemblyInfo>
<AssemblyInfo>
<AssemblyName>DocTest-typeForwards-Third</AssemblyName>
<AssemblyVersion>0.0.0.0</AssemblyVersion>
</AssemblyInfo>
<AssemblyInfo>
<AssemblyName>DocTest-typeForwards-Third-First</AssemblyName>
</AssemblyInfo>
<TypeForwardingChain>
<TypeForwarding From="DocTest-typeForwards-Second-First" FromVersion="0.0.0.0" To="DocTest-typeForwards-Second" ToVersion="0.0.0.0" />
<TypeForwarding From="DocTest-typeForwards-Third-First" FromVersion="0.0.0.0" To="DocTest-typeForwards-Third" ToVersion="0.0.0.0" FrameworkAlternate="Three;Two" />
</TypeForwardingChain>
<Base>
<BaseTypeName>System.Object</BaseTypeName>
</Base>
Expand All @@ -36,6 +47,13 @@
<AssemblyInfo>
<AssemblyName>DocTest-typeForwards-Second-First</AssemblyName>
</AssemblyInfo>
<AssemblyInfo>
<AssemblyName>DocTest-typeForwards-Third</AssemblyName>
<AssemblyVersion>0.0.0.0</AssemblyVersion>
</AssemblyInfo>
<AssemblyInfo>
<AssemblyName>DocTest-typeForwards-Third-First</AssemblyName>
</AssemblyInfo>
<Parameters />
<Docs>
<summary>To be added.</summary>
Expand Down
10 changes: 10 additions & 0 deletions mdoc/Test/en.expected.typeForwards/index.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@
</Attribute>
</Attributes>
</Assembly>
<Assembly Name="DocTest-typeForwards-Third-First" Version="0.0.0.0">
<Attributes>
<Attribute>
<AttributeName>System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.IgnoreSymbolStoreSequencePoints)</AttributeName>
</Attribute>
<Attribute>
<AttributeName>System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true)</AttributeName>
</Attribute>
</Attributes>
</Assembly>
</Assemblies>
<Remarks>To be added.</Remarks>
<Copyright>To be added.</Copyright>
Expand Down