Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/api-doc-tools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Martinez <joelmartinez@gmail.com>2018-03-19 23:50:15 +0300
committerJoel Martinez <joelmartinez@gmail.com>2018-03-20 00:17:53 +0300
commit5e2012309f32b9ab42825c24e6641fe33c73ab55 (patch)
tree340bacfa935e186ba8ad12a5e1dba06cffd0a2d3
parent9a8af0960234d808c9e682ad26601a5979b2b062 (diff)
mdoc: parameters and member signatures now use FrameworkAlternate when different
Resolves #116
-rw-r--r--apidoctools.sln5
-rw-r--r--mdoc/GlobalSuppressions.cs8
-rw-r--r--mdoc/Makefile46
-rw-r--r--mdoc/Mono.Documentation/MDocUpdater.cs450
-rw-r--r--mdoc/Mono.Documentation/Updater/DocUtils.cs1
-rw-r--r--mdoc/Mono.Documentation/Updater/DocsNodeInfo.cs2
-rw-r--r--mdoc/Mono.Documentation/Updater/DocumentationEnumerator.cs9
-rw-r--r--mdoc/Mono.Documentation/Updater/DocumentationImporter.cs2
-rw-r--r--mdoc/Mono.Documentation/Updater/DocumentationMember.cs33
-rw-r--r--mdoc/Mono.Documentation/Updater/EcmaDocumentationEnumerator.cs12
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/AssemblySet.cs12
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/FXUtils.cs48
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/FrameworkEntry.cs61
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/FrameworkIndex.cs2
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs37
-rw-r--r--mdoc/Mono.Documentation/Updater/XmlSyncer.cs269
-rw-r--r--mdoc/Mono.Documentation/mdoc.cs2
-rw-r--r--mdoc/Test/DocTest-frameworkalternate.cs13
-rw-r--r--mdoc/Test/en.expected-frameworkalternate-aligned/FrameworksIndex/One.xml9
-rw-r--r--mdoc/Test/en.expected-frameworkalternate-aligned/FrameworksIndex/Three.xml9
-rw-r--r--mdoc/Test/en.expected-frameworkalternate-aligned/FrameworksIndex/Two.xml9
-rw-r--r--mdoc/Test/en.expected-frameworkalternate-aligned/Monodoc.Test/MyClass.xml68
-rw-r--r--mdoc/Test/en.expected-frameworkalternate-aligned/index.xml32
-rw-r--r--mdoc/Test/en.expected-frameworkalternate-aligned/ns-Monodoc.Test.xml6
-rw-r--r--mdoc/Test/en.expected-frameworkalternate/FrameworksIndex/One.xml9
-rw-r--r--mdoc/Test/en.expected-frameworkalternate/FrameworksIndex/Three.xml9
-rw-r--r--mdoc/Test/en.expected-frameworkalternate/FrameworksIndex/Two.xml9
-rw-r--r--mdoc/Test/en.expected-frameworkalternate/Monodoc.Test/MyClass.xml72
-rw-r--r--mdoc/Test/en.expected-frameworkalternate/index.xml32
-rw-r--r--mdoc/Test/en.expected-frameworkalternate/ns-Monodoc.Test.xml6
-rw-r--r--mdoc/Test/en.expected-fsharp/Delegates+Delegate10.xml1
-rw-r--r--mdoc/Test/en.expected-fsharp/Delegates+Delegate2.xml1
-rw-r--r--mdoc/Test/en.expected-fsharp/Delegates+Delegate3.xml1
-rw-r--r--mdoc/mdoc.Test/FrameworkAlternateTests.cs27
-rw-r--r--mdoc/mdoc.Test/UwpTestWinRtComponentCpp/UwpTestWinRtComponentCpp.vcxproj4
-rw-r--r--mdoc/mdoc.Test/XmlUpdateTests.cs663
-rw-r--r--mdoc/mdoc.Test/mdoc.Test.csproj4
-rw-r--r--mdoc/mdoc.csproj2
38 files changed, 1833 insertions, 152 deletions
diff --git a/apidoctools.sln b/apidoctools.sln
index 5704f200..45054cc3 100644
--- a/apidoctools.sln
+++ b/apidoctools.sln
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.27004.2002
+VisualStudioVersion = 15.0.27130.2020
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mdoc", "mdoc\mdoc.csproj", "{7DA7CD97-614F-4BCD-A2FA-B379590CEA48}"
EndProject
@@ -23,6 +23,9 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mdoc.Test.Cplusplus", "mdoc.Test.Cplusplus\mdoc.Test.Cplusplus.vcxproj", "{9398D4E3-1779-44FD-AF8C-BB46562DCD88}"
EndProject
Global
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
diff --git a/mdoc/GlobalSuppressions.cs b/mdoc/GlobalSuppressions.cs
new file mode 100644
index 00000000..064d383f
--- /dev/null
+++ b/mdoc/GlobalSuppressions.cs
@@ -0,0 +1,8 @@
+
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage ("Potential Code Quality Issues", "RECS0022:A catch clause that catches System.Exception and has an empty body", Justification = "<Pending>", Scope = "member", Target = "~M:Mono.Documentation.Updater.Frameworks.FrameworkTypeEntry.ProcessMember(Mono.Cecil.MemberReference)")]
+
diff --git a/mdoc/Makefile b/mdoc/Makefile
index eb29d13a..a5669ec5 100644
--- a/mdoc/Makefile
+++ b/mdoc/Makefile
@@ -475,6 +475,46 @@ check-monodocer-members-implementation:
$(MONO) $(PROGRAM) update -o Test/en.actual Test/TestInterfaceImplementation/bin/Release/TestInterfaceImplementation.dll
$(DIFF) Test/en.expected.members-implementation Test/en.actual
+# ------- Framework Alternate Test(s) -------
+Test/FrameworkTestData-frameworkalternate: Test/DocTest-frameworkalternate-one.dll Test/DocTest-frameworkalternate-two.dll
+ rm -rf Test/FrameworkTestData
+ mkdir Test/FrameworkTestData
+ mkdir Test/FrameworkTestData/One
+ mkdir Test/FrameworkTestData/Two
+ mkdir Test/FrameworkTestData/Three
+ cp Test/DocTest-frameworkalternate-one.dll Test/FrameworkTestData/One/
+ cp Test/DocTest-frameworkalternate-two.dll Test/FrameworkTestData/Two/
+ cp Test/DocTest-frameworkalternate-one.dll Test/FrameworkTestData/Three/
+ $(MONO) $(PROGRAM) fx-bootstrap Test/FrameworkTestData
+
+Test/DocTest-frameworkalternate-one.dll:
+ $(CSCOMPILE) $(TEST_CSCFLAGS) -debug -target:library -out:$@ Test/DocTest-frameworkalternate.cs /define:FXONE
+
+Test/DocTest-frameworkalternate-two.dll:
+ $(CSCOMPILE) $(TEST_CSCFLAGS) -debug -target:library -out:$@ Test/DocTest-frameworkalternate.cs /define:FXTWO
+
+.PHONY: check-monodocer-frameworkalternate
+check-monodocer-frameworkalternate: Test/FrameworkTestData-frameworkalternate
+ -rm -Rf Test/en.actual
+
+ # Run Test
+ $(MONO) $(PROGRAM) update -o Test/en.actual -frameworks Test/FrameworkTestData
+ $(DIFF) Test/en.expected-frameworkalternate Test/en.actual
+ # run test again to make sure subsequent runs maintain data
+ $(MONO) $(PROGRAM) update -o Test/en.actual -frameworks Test/FrameworkTestData
+ $(DIFF) Test/en.expected-frameworkalternate Test/en.actual
+
+ # Test Future FX Alignment ...
+ # compile new version of `two` that looks like `one`
+ rm Test/DocTest-frameworkalternate-two.dll
+ $(CSCOMPILE) $(TEST_CSCFLAGS) -debug -target:library -out:Test/DocTest-frameworkalternate-two.dll Test/DocTest-frameworkalternate.cs /define:FXONE
+ yes | cp Test/DocTest-frameworkalternate-two.dll Test/FrameworkTestData/Two/DocTest-frameworkalternate-two.dll
+ # mdoc update fxmode again
+ $(MONO) $(PROGRAM) update -o Test/en.actual -frameworks Test/FrameworkTestData
+ # diff against aligned but with FrameworkAlternate="one;two;three"
+ $(DIFF) Test/en.expected-frameworkalternate-aligned Test/en.actual
+
+# ------- Framework Alternate Test(s) -------
.PHONY: check-monodocer-import-fx
check-monodocer-import-fx: check-monodocer-import-fx-work
@@ -554,7 +594,7 @@ check-mdoc-export-msxdoc-update:
check-mdoc-export-msxdoc:
$(MONO) $(PROGRAM) export-msxdoc -o - Test/en.expected.importslashdoc \
- | $(DIFF_QUIET) - Test/msxdoc-expected.importslashdoc.xml
+ | $(DIFF) - Test/msxdoc-expected.importslashdoc.xml
my_abs_top_srcdir = $(shell cd . && pwd)
@@ -604,7 +644,6 @@ check-doc-tools: check-monodocer-since \
check-mdoc-validate \
check-monodocer-dropns-classic \
check-monodocer-dropns-classic-withsecondary \
- check-monodocer-dropns-delete \
check-monodocer-internal-interface \
check-monodocer-addNonGeneric \
check-monodocer-membergroup \
@@ -631,8 +670,9 @@ check-doc-tools: check-monodocer-since \
check-monodocer-cppwinrtDocTest\
check-monodocer-cppwinrt\
check-monodocer-cppwinrtUwp\
+ check-monodocer-frameworkalternate \
-
+#check-monodocer-dropns-delete
check-doc-tools-update: check-monodocer-since-update \
check-monodocer-importecmadoc-update \
check-monodocer-importslashdoc-update \
diff --git a/mdoc/Mono.Documentation/MDocUpdater.cs b/mdoc/Mono.Documentation/MDocUpdater.cs
index 840e9217..ec7380a2 100644
--- a/mdoc/Mono.Documentation/MDocUpdater.cs
+++ b/mdoc/Mono.Documentation/MDocUpdater.cs
@@ -25,7 +25,7 @@ using StringToXmlNodeMap = System.Collections.Generic.Dictionary<string, System.
namespace Mono.Documentation
{
- class MDocUpdater : MDocCommand
+ public class MDocUpdater : MDocCommand
{
string srcPath;
List<AssemblySet> assemblies = new List<AssemblySet> ();
@@ -111,6 +111,9 @@ namespace Mono.Documentation
FrameworkIndex frameworksCache;
IEnumerable<XDocument> oldFrameworkXmls;
+ /// <summary>For unit tests to initialize the cache</summary>
+ public void InitializeFrameworksCache (FrameworkIndex fi) => frameworksCache = fi;
+
private StatisticsCollector statisticsCollector = new StatisticsCollector();
static List<string> droppedAssemblies = new List<string> ();
@@ -124,6 +127,8 @@ namespace Mono.Documentation
public override void Run (IEnumerable<string> args)
{
+ Console.WriteLine ("mdoc {0}", Consts.MonoVersion);
+
Instance = this;
show_exceptions = DebugOutput;
var types = new List<string> ();
@@ -656,35 +661,38 @@ namespace Mono.Documentation
{
foreach (AssemblyDefinition assembly in assemblySet.Assemblies)
{
- var typeSet = new HashSet<string> ();
- var namespacesSet = new HashSet<string> ();
- memberSet = new HashSet<string> ();
+ using (assembly)
+ {
+ var typeSet = new HashSet<string>();
+ var namespacesSet = new HashSet<string>();
+ memberSet = new HashSet<string>();
- var frameworkEntry = frameworks.StartProcessingAssembly (assembly, assemblySet.Importers, assemblySet.Id, assemblySet.Version);
+ var frameworkEntry = frameworks.StartProcessingAssembly(assembly, assemblySet.Importers, assemblySet.Id, assemblySet.Version);
- foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, typenames))
- {
- var typeEntry = frameworkEntry.ProcessType (type);
+ foreach (TypeDefinition type in docEnum.GetDocumentationTypes(assembly, typenames))
+ {
+ var typeEntry = frameworkEntry.ProcessType(type);
- string relpath = DoUpdateType (type, typeEntry, basepath, dest);
- if (relpath == null)
- continue;
+ string relpath = DoUpdateType(type, typeEntry, basepath, dest);
+ if (relpath == null)
+ continue;
- found.Add (type.FullName);
+ found.Add(type.FullName);
- if (index == null)
- continue;
+ if (index == null)
+ continue;
- index.Add (assembly);
- index.Add (type);
+ index.Add(assembly);
+ index.Add(type);
- namespacesSet.Add (type.Namespace);
- typeSet.Add (type.FullName);
- }
+ namespacesSet.Add(type.Namespace);
+ typeSet.Add(type.FullName);
+ }
- statisticsCollector.AddMetric (frameworkEntry.Name, StatisticsItem.Types, StatisticsMetrics.Total, typeSet.Count);
- statisticsCollector.AddMetric (frameworkEntry.Name, StatisticsItem.Namespaces, StatisticsMetrics.Total, namespacesSet.Count);
- statisticsCollector.AddMetric (frameworkEntry.Name, StatisticsItem.Members, StatisticsMetrics.Total, memberSet.Count);
+ statisticsCollector.AddMetric(frameworkEntry.Name, StatisticsItem.Types, StatisticsMetrics.Total, typeSet.Count);
+ statisticsCollector.AddMetric(frameworkEntry.Name, StatisticsItem.Namespaces, StatisticsMetrics.Total, namespacesSet.Count);
+ statisticsCollector.AddMetric(frameworkEntry.Name, StatisticsItem.Members, StatisticsMetrics.Total, memberSet.Count);
+ }
}
}
}
@@ -1002,9 +1010,12 @@ namespace Mono.Documentation
{
foreach (AssemblyDefinition assm in assemblySet.Assemblies)
{
- AddIndexAssembly (assm, index_assemblies);
- DoUpdateAssembly (assemblySet, assm, index_types, source, dest, goodfiles);
- processedAssemblyCount++;
+ using (assm)
+ {
+ AddIndexAssembly(assm, index_assemblies);
+ DoUpdateAssembly(assemblySet, assm, index_types, source, dest, goodfiles);
+ processedAssemblyCount++;
+ }
}
}
}
@@ -1105,7 +1116,7 @@ namespace Mono.Documentation
}
}
- abstract class XmlNodeComparer : IComparer, IComparer<XmlNode>
+ public abstract class XmlNodeComparer : IComparer, IComparer<XmlNode>
{
public abstract int Compare (XmlNode x, XmlNode y);
@@ -1115,6 +1126,41 @@ namespace Mono.Documentation
}
}
+ public class MemberParameterNameComparer : XmlNodeComparer
+ {
+ Dictionary<string, int> order = new Dictionary<string, int> ();
+
+ public MemberParameterNameComparer(XmlElement parent, string tagName = "Parameter")
+ {
+ var s = parent.GetElementsByTagName (tagName).Cast<XmlElement> ();
+
+ int currentIndex = 0;
+ foreach(var param in s.Select (p => new {Element=p, Name = p.SelectSingleNode ("@Name"), Index=p.SelectSingleNode ("@Index")})) {
+ if (param.Name == null)
+ throw new Exception (param.Element.OuterXml);
+ order[param.Name.Value] = currentIndex;
+
+ currentIndex++;
+ }
+ }
+ public override int Compare (XmlNode x, XmlNode y)
+ {
+ return Compare (x as XmlElement, y as XmlElement);
+ }
+
+ int Compare(XmlElement x, XmlElement y)
+ {
+ string xname = x.GetAttribute ("name");
+ string yname = y.GetAttribute ("name");
+
+ int xindex, yindex;
+ order.TryGetValue (xname, out xindex);
+ order.TryGetValue (yname, out yindex);
+
+ return xindex.CompareTo (yindex);
+ }
+ }
+
class AttributeNameComparer : XmlNodeComparer
{
string attribute;
@@ -1392,7 +1438,7 @@ namespace Mono.Documentation
Dictionary<string, List<MemberReference>> implementedMembers = DocUtils.GetImplementedMembersFingerprintLookup(type);
- foreach (DocsNodeInfo info in docEnum.GetDocumentationMembers (basefile, type))
+ foreach (DocsNodeInfo info in docEnum.GetDocumentationMembers (basefile, type, typeEntry))
{
XmlElement oldmember = info.Node;
MemberReference oldmember2 = info.Member;
@@ -1461,6 +1507,7 @@ namespace Mono.Documentation
else
{
DeleteMember ("Duplicate Member Found", output, oldmember, todelete, type);
+
statisticsCollector.AddMetric(typeEntry.Framework.Name, StatisticsItem.Members, StatisticsMetrics.Removed);
}
continue;
@@ -1994,7 +2041,9 @@ namespace Mono.Documentation
{
MakeTypeParameters (root, type.GenericParameters, type, MDocUpdater.HasDroppedNamespace (type));
var member = type.GetMethod ("Invoke");
- MakeParameters (root, member, member.Parameters);
+
+ bool fxAlternateTriggered = false;
+ MakeParameters (root, member, member.Parameters, typeEntry, ref fxAlternateTriggered);
MakeReturnValue (root, member);
}
@@ -2082,10 +2131,6 @@ namespace Mono.Documentation
XmlElement me = (XmlElement)info.Node;
MemberReference mi = info.Member;
typeEntry.ProcessMember (mi);
- foreach (MemberFormatter f in memberFormatters)
- {
- UpdateSignature(f, mi, me);
- }
WriteElementText (me, "MemberType", GetMemberType (mi));
AddImplementedMembers(mi, implementedMembers, me);
@@ -2115,7 +2160,8 @@ namespace Mono.Documentation
if (mb.IsGenericMethod ())
MakeTypeParameters (me, mb.GenericParameters, mi, MDocUpdater.HasDroppedNamespace (mi));
}
- MakeParameters (me, mi, MDocUpdater.HasDroppedNamespace (mi));
+ bool fxAlternateTriggered = false;
+ MakeParameters (me, mi, typeEntry, ref fxAlternateTriggered, MDocUpdater.HasDroppedNamespace (mi));
string fieldValue;
if (mi is FieldDefinition && GetFieldConstValue ((FieldDefinition)mi, out fieldValue))
@@ -2123,6 +2169,12 @@ namespace Mono.Documentation
info.Node = WriteElement (me, "Docs");
MakeDocNode (info, typeEntry.Framework.Importers);
+
+ foreach (MemberFormatter f in memberFormatters)
+ {
+ UpdateSignature (f, mi, me, typeEntry, fxAlternateTriggered);
+ }
+
OrderMemberNodes (me, me.ChildNodes);
UpdateExtensionMethods (me, info);
}
@@ -2148,7 +2200,7 @@ namespace Mono.Documentation
type);
}
- private static void UpdateSignature(MemberFormatter formatter, MemberReference member, XmlElement xmlElement)
+ public static void UpdateSignature(MemberFormatter formatter, MemberReference member, XmlElement xmlElement, FrameworkTypeEntry typeEntry, bool fxAlternateTriggered)
{
var valueToUse = formatter.GetDeclaration(member);
var usageSample = formatter.UsageFormatter?.GetDeclaration(member);
@@ -2160,9 +2212,88 @@ namespace Mono.Documentation
out var valueMatches,
out var setValue,
out var makeNewNode);
-
+
+ /*
+ * 1. 'normal'
+ */
+ /// Handle framework alternate scenarios
+ string currentFX = typeEntry.Framework.Name;
+ var existingNodes = xmlElement.SelectNodes (elementXPath).Cast<XmlElement> ().ToArray ();
+ if (existingNodes.Count () > 1) {
+ // find the right one to update based on `currentFX`
+
+ if (existingNodes.Any (e => e.HasAttribute ("FrameworkAlternate"))) {
+ var nodesWithFX = existingNodes.Where (e => e.HasAttribute ("FrameworkAlternate"));
+ if (nodesWithFX.Any ()) {
+ // one exists, we can continue
+ if (!fxAlternateTriggered)
+ {
+ var matchingSignature = nodesWithFX.FirstOrDefault (nfx => nfx.GetAttribute ("Value") == valueToUse && !nfx.GetAttribute ("FrameworkAlternate").Contains (currentFX));
+ if (matchingSignature!= null) {
+ // The current implementation has changed
+ matchingSignature.SetAttribute ("FrameworkAlternate", FXUtils.AddFXToList (matchingSignature.GetAttribute ("FrameworkAlternate"), currentFX));
+ foreach (var n in nodesWithFX.Where (nfx => nfx != matchingSignature))
+ {
+ string nfx = n.GetAttribute ("FrameworkAlternate");
+ string nfixed = FXUtils.RemoveFXFromList (nfx, currentFX);
+ if (string.IsNullOrEmpty (nfixed))
+ {
+ n.ParentNode.RemoveChild (n);
+ var nodesWithoutFX = existingNodes
+ .Where (e => e.HasAttribute ("FrameworkAlternate") && !e.GetAttribute ("FrameworkAlternate").Contains (currentFX))
+ .Select (e => new { Element = e, FX = e.GetAttribute ("FrameworkAlternate") });
+ foreach (var nwofx in nodesWithoutFX)
+ {
+ nwofx.Element.SetAttribute ("FrameworkAlternate", FXUtils.AddFXToList (nwofx.FX, currentFX));
+ }
+ }
+ else
+ n.SetAttribute ("FrameworkAlternate", nfixed);
+ }
+ }
+
+ }
+ return;
+ }
+ else {
+ // none exist, we must add one with `currentFX`
+ throw new Exception ("FX, this shouldn't happen");
+ }
+ }
+ else {
+ // there are multiple, but none contain a `FrameworkAlternate`
+ // this shouldn't happen
+ throw new Exception ("FX, this shouldn't happen");
+ }
+ }
+ else if (fxAlternateTriggered && existingNodes.Count () == 1 && typeEntry.Framework.Frameworks.Count () > 1) {
+ // need to add alternate
+ string previousFX = FXUtils.PreviouslyProcessedFXString (typeEntry);
+ if (!string.IsNullOrWhiteSpace (previousFX))
+ {
+ var node = existingNodes.First ();
+ node.SetAttribute ("FrameworkAlternate", previousFX);
+ }
+ else
+ {
+ // there was no previous FX, so remove the existing node
+ var node = existingNodes.First ();
+ node.ParentNode.RemoveChild (node);
+ }
+
+ var newelement = makeNewNode ();
+ newelement.SetAttribute ("FrameworkAlternate", currentFX);
+ return;
+ }
+ else if (!fxAlternateTriggered && existingNodes.Count () == 1 && typeEntry.Framework.Frameworks.Count () > 1 && existingNodes.First ().HasAttribute ("FrameworkAlternate")) {
+ var node = existingNodes.First ();
+ string newfxvalue = FXUtils.AddFXToList (node.GetAttribute ("FrameworkAlternate"), typeEntry.Framework.Name);
+ node.SetAttribute ("FrameworkAlternate", newfxvalue);
+ return;
+ }
+
AddXmlNode(
- xmlElement.SelectNodes(elementXPath).Cast<XmlElement>().ToArray(),
+ existingNodes,
valueMatches,
setValue,
makeNewNode,
@@ -2573,7 +2704,7 @@ namespace Mono.Documentation
internal static XmlElement WriteElement (XmlNode parent, string element, bool forceNewElement = false)
{
- XmlElement ret = (XmlElement)parent.SelectSingleNode (element);
+ XmlElement ret = parent.ChildNodes.Cast<XmlElement>().FirstOrDefault(e => e.LocalName == element); //(XmlElement)parent.SelectSingleNode (element);
if (ret == null || forceNewElement)
{
string[] path = element.Split ('/');
@@ -2747,10 +2878,11 @@ namespace Mono.Documentation
private void UpdateParameters (XmlElement e, string element, string[] values)
{
+ string parentElement = element == "typeparam" ? "TypeParameter" : "Parameter";
+ string rootParentElement = element == "typeparam" ? "TypeParameters" : "Parameters";
+
if (values != null)
{
- XmlNode[] paramnodes = new XmlNode[values.Length];
-
// Some documentation had param nodes with leading spaces.
foreach (XmlElement paramnode in e.SelectNodes (element))
{
@@ -2769,18 +2901,31 @@ namespace Mono.Documentation
// Pick out existing and still-valid param nodes, and
// create nodes for parameters not in the file.
Hashtable seenParams = new Hashtable ();
+ var roots = e.ParentNode.SelectNodes ($"{rootParentElement}/{parentElement}")
+ .Cast<XmlElement> ()
+ .GroupBy (pe => pe.GetAttribute ("Name"))
+ .ToDictionary (k => k.Key, k => k);
for (int pi = 0; pi < values.Length; pi++)
{
string p = values[pi];
seenParams[p] = pi;
- paramnodes[pi] = e.SelectSingleNode (element + "[@name='" + p + "']");
- if (paramnodes[pi] != null) continue;
+ var nodes = e.SelectNodes(element + "[@name='" + p + "']");
+ if (nodes.Count > 0) {
+ // check and see if there _should_ be more than one
+ if (roots.ContainsKey (p) && nodes.Count < roots[p].Count ())
+ {
+ // we should have more
+ }
+ else // let's keep moving
+ continue;
+ }
+
XmlElement pe = e.OwnerDocument.CreateElement (element);
pe.SetAttribute ("name", p);
pe.InnerText = "To be added.";
- paramnodes[pi] = pe;
+ e.AppendChild (pe);
reinsert = true;
}
@@ -2790,6 +2935,8 @@ namespace Mono.Documentation
foreach (XmlElement paramnode in e.SelectNodes (element))
{
string name = paramnode.GetAttribute ("name");
+ // TODO: pick the right parameters
+ XmlNode realParamNode = e.ParentNode.SelectSingleNode ($"./{rootParentElement}/{parentElement}[@Name='{paramnode.GetAttribute ("name")}']");
if (!seenParams.ContainsKey (name))
{
if (!delete && !paramnode.InnerText.StartsWith ("To be added"))
@@ -2811,14 +2958,21 @@ namespace Mono.Documentation
}
Warning ("\tValue={0}", paramnode.OuterXml);
}
- else
+ else if (realParamNode == null)
{
todelete.Add (paramnode);
}
continue;
}
- if ((int)seenParams[name] != idx)
+ int idxToUse = idx;
+ if (realParamNode != null)
+ {
+ int explicitIndex;
+ if (int.TryParse (((XmlElement)realParamNode).GetAttribute ("Index"), out explicitIndex))
+ idxToUse = explicitIndex;
+ }
+ if ((int)seenParams[name] != idxToUse)
reinsert = true;
idx++;
@@ -2831,15 +2985,22 @@ namespace Mono.Documentation
// Re-insert the parameter nodes at the top of the doc section.
if (reinsert)
- for (int pi = values.Length - 1; pi >= 0; pi--)
- e.PrependChild (paramnodes[pi]);
+ {
+ var paramParent = e.ParentNode.SelectSingleNode (rootParentElement);
+ if (paramParent != null)
+ SortXmlNodes (
+ e,
+ e.SelectNodes (element),
+ new MemberParameterNameComparer(paramParent as XmlElement, parentElement));
+
+ }
}
else
{
// Clear all existing param nodes
foreach (XmlNode paramnode in e.SelectNodes (element))
{
- if (!delete && !paramnode.InnerText.StartsWith ("To be added"))
+ if (!delete && !paramnode.InnerText.StartsWith ("To be added", StringComparison.Ordinal))
{
Console.WriteLine ("The following param node can only be deleted if the --delete option is given:");
Console.WriteLine (paramnode.OuterXml);
@@ -2866,10 +3027,6 @@ namespace Mono.Documentation
class CrefComparer : XmlNodeComparer
{
- public CrefComparer ()
- {
- }
-
public override int Compare (XmlNode x, XmlNode y)
{
string xType = x.Attributes["cref"].Value;
@@ -3152,64 +3309,165 @@ namespace Mono.Documentation
return Convert.ToInt64 (value);
}
- private void MakeParameters (XmlElement root, MemberReference member, IList<ParameterDefinition> parameters, bool shouldDuplicateWithNew = false)
+ public void MakeParameters (XmlElement root, MemberReference member, IList<ParameterDefinition> parameters, FrameworkTypeEntry typeEntry, ref bool fxAlternateTriggered, bool shouldDuplicateWithNew = false)
{
XmlElement e = WriteElement (root, "Parameters");
- int i = 0;
- foreach (ParameterDefinition p in parameters)
+ #region helper functions
+ /// addParameter does the work of adding the actual parameter to the XML
+ Action<ParameterDefinition, XmlElement, string, int, bool, string, bool> addParameter = (ParameterDefinition param, XmlElement nextTo, string paramType, int index, bool addIndex, string fx, bool addfx) =>
{
- XmlElement pe;
+ var pe = root.OwnerDocument.CreateElement ("Parameter");
- // param info
- var ptype = GetDocParameterType (p.ParameterType);
- var newPType = ptype;
+ if (nextTo == null)
+ e.AppendChild (pe);
+ else
+ e.InsertAfter (pe, nextTo);
- if (MDocUpdater.SwitchingToMagicTypes)
+ pe.SetAttribute ("Name", param.Name);
+ pe.SetAttribute ("Type", paramType);
+ if (param.ParameterType is ByReferenceType)
{
- newPType = NativeTypeManager.ConvertFromNativeType (ptype);
+ if (param.IsOut)
+ pe.SetAttribute ("RefType", "out");
+ else
+ pe.SetAttribute ("RefType", "ref");
}
+ if (addIndex)
+ pe.SetAttribute ("Index", index.ToString ());
+ if (addfx)
+ pe.SetAttribute ("FrameworkAlternate", fx);
- // now find the existing node, if it's there so we can reuse it.
- var nodes = root.SelectSingleNode ("Parameters").SelectNodes ("Parameter")
- .Cast<XmlElement> ().Where (x => x.GetAttribute ("Name") == p.Name)
- .ToArray ();
+ MakeAttributes (pe, GetCustomAttributes (param.CustomAttributes, ""));
+ };
+ /// addFXAttributes, adds the index attribute to all existing elements.
+ /// Used when we first detect the scenario which requires this.
+ Action<IEnumerable<XmlElement>> addFXAttributes = nodes =>
+ {
+ var i = 0;
+ foreach (var node in nodes)
+ {
+ node.SetAttribute ("Index", i.ToString ());
+ i++;
+ }
+ };
+ #endregion
- if (nodes.Count () == 0)
+ // Gather information about this method's parameters
+ var pdata = parameters.Select ((p, i) =>
+ {
+ return new
{
- // wasn't found, let's make sure it wasn't just cause the param name was changed
- nodes = root.SelectSingleNode ("Parameters").SelectNodes ("Parameter")
- .Cast<XmlElement> ()
- .Skip (i) // this makes sure we don't inadvertently "reuse" nodes when adding new ones
- .Where (x => x.GetAttribute ("Name") != p.Name && (x.GetAttribute ("Type") == ptype || x.GetAttribute ("Type") == newPType))
- .Take (1) // there might be more than one that meets this parameter ... only take the first.
- .ToArray ();
+ Name = p.Name,
+ Type = GetDocParameterType(p.ParameterType),
+ Index = i,
+ IsOut = p.IsOut,
+ IsIn = p.IsIn,
+ Definition = p
+ };
+ }).ToArray ();
+
+ // Gather information about current XMl state
+ var xdata = e.GetElementsByTagName ("Parameter")
+ .Cast<XmlElement> ()
+ .Select ((n, i) =>
+ {
+ int actualIndex = i;
+ if (n.HasAttribute ("Index"))
+ int.TryParse (n.GetAttribute ("Index"), out actualIndex);
+
+
+ return new
+ {
+ Element = n,
+ Name = n.GetAttribute ("Name"),
+ Type = n.GetAttribute ("Type"),
+ ChildIndex = i,
+ ActualIndex = actualIndex,
+ FrameworkAlternates = n.GetAttribute ("FrameworkAlternate")
+ };
+ })
+ .ToArray ();
+
+ // Now sync up the state
+ int pindex = 0;
+ for (int i=0; i < pdata.Length; i++) {
+ var p = pdata[i];
+ // check for name
+ var xitem = xdata.FirstOrDefault (x => x.Name == p.Name);
+ if (xitem != null)
+ {
+ var xelement = xitem.Element;
+ if (xelement.HasAttribute ("FrameworkAlternate") && !xelement.GetAttribute ("FrameworkAlternate").Contains (typeEntry.Framework.Name))
+ xelement.SetAttribute ("FrameworkAlternate", FXUtils.AddFXToList (xelement.GetAttribute ("FrameworkAlternate"), typeEntry.Framework.Name));
+
+
+ continue;
}
+ else {
+ // if no check actualIndex and type
+ if (xdata.Any (x => x.ActualIndex == i && x.Type == p.Type))
+ {
+ addFXAttributes (xdata.Select (x => x.Element));
+ //-find type in previous frameworks
- AddXmlNode (nodes,
- x => x.GetAttribute ("Type") == ptype,
- x => x.SetAttribute ("Type", ptype),
- () =>
+
+ string fxList = FXUtils.PreviouslyProcessedFXString (typeEntry);
+
+ //-find < parameter where index = currentIndex >
+ var currentNode = xdata[i].Element;
+ currentNode.SetAttribute ("FrameworkAlternate", fxList);
+
+ addParameter (p.Definition, currentNode, p.Type, i, true, typeEntry.Framework.Name, true);
+
+ fxAlternateTriggered = true;
+ }
+ else
{
- pe = root.OwnerDocument.CreateElement ("Parameter");
- e.AppendChild (pe);
+ // if no, make it
+ int lastIndex = i - 1;
+ XmlElement lastElement = lastIndex > -1 && lastIndex < xdata.Length ? xdata[lastIndex].Element : null;
+ addParameter (p.Definition, lastElement, p.Type, i, false, typeEntry.Framework.Name, false);
+ }
+ }
- pe.SetAttribute ("Name", p.Name);
- pe.SetAttribute ("Type", ptype);
- if (p.ParameterType is ByReferenceType)
- {
- if (p.IsOut)
- pe.SetAttribute ("RefType", "out");
- else
- pe.SetAttribute ("RefType", "ref");
- }
- MakeAttributes (pe, GetCustomAttributes (p.CustomAttributes, ""));
- return pe;
- },
- member);
+ }
- i++;
+ //-purge `typeEntry.Framework` from any<parameter> that
+ // has FrameworkAlternate, and “name” doesn’t match any
+ // `parameters`
+ var paramNodes = e.GetElementsByTagName ("Parameter");
+ var alternates = paramNodes
+ .Cast<XmlElement> ()
+ .Select (p => new
+ {
+ Element = p,
+ Name = p.GetAttribute ("Name"),
+ HasFrameworkAlternate = p.HasAttribute ("FrameworkAlternate"),
+ FrameworkAlternate = p.GetAttribute ("FrameworkAlternate")
+ })
+ .Where (p =>
+ p.HasFrameworkAlternate &&
+ ((!string.IsNullOrWhiteSpace (p.FrameworkAlternate) &&
+ p.FrameworkAlternate.Contains (typeEntry.Framework.Name)) ||
+ (string.IsNullOrWhiteSpace (p.FrameworkAlternate))) &&
+ !parameters.Any (param => param.Name == p.Name))
+ .ToArray ();
+ if (alternates.Any ())
+ {
+ foreach (var a in alternates)
+ {
+ string newValue = FXUtils.RemoveFXFromList (a.FrameworkAlternate, typeEntry.Framework.Name);
+ if (string.IsNullOrWhiteSpace (newValue))
+ {
+ a.Element.ParentNode.RemoveChild (a.Element);
+ }
+ else
+ {
+ a.Element.SetAttribute ("FrameworkAlternate", newValue);
+ }
+ }
}
}
@@ -3287,15 +3545,15 @@ namespace Mono.Documentation
}
}
- private void MakeParameters (XmlElement root, MemberReference mi, bool shouldDuplicateWithNew)
+ private void MakeParameters (XmlElement root, MemberReference mi, FrameworkTypeEntry typeEntry, ref bool fxAlternateTriggered, bool shouldDuplicateWithNew)
{
if (mi is MethodDefinition && ((MethodDefinition)mi).IsConstructor)
- MakeParameters (root, mi, ((MethodDefinition)mi).Parameters, shouldDuplicateWithNew);
+ MakeParameters (root, mi, ((MethodDefinition)mi).Parameters, typeEntry, ref fxAlternateTriggered, shouldDuplicateWithNew);
else if (mi is MethodDefinition)
{
MethodDefinition mb = (MethodDefinition)mi;
IList<ParameterDefinition> parameters = mb.Parameters;
- MakeParameters (root, mi, parameters, shouldDuplicateWithNew);
+ MakeParameters (root, mi, parameters, typeEntry, ref fxAlternateTriggered, shouldDuplicateWithNew);
if (parameters.Count > 0 && DocUtils.IsExtensionMethod (mb))
{
XmlElement p = (XmlElement)root.SelectSingleNode ("Parameters/Parameter[position()=1]");
@@ -3306,7 +3564,7 @@ namespace Mono.Documentation
{
IList<ParameterDefinition> parameters = ((PropertyDefinition)mi).Parameters;
if (parameters.Count > 0)
- MakeParameters (root, mi, parameters, shouldDuplicateWithNew);
+ MakeParameters (root, mi, parameters, typeEntry, ref fxAlternateTriggered, shouldDuplicateWithNew);
else
return;
}
diff --git a/mdoc/Mono.Documentation/Updater/DocUtils.cs b/mdoc/Mono.Documentation/Updater/DocUtils.cs
index 83543f90..f362d113 100644
--- a/mdoc/Mono.Documentation/Updater/DocUtils.cs
+++ b/mdoc/Mono.Documentation/Updater/DocUtils.cs
@@ -14,7 +14,6 @@ namespace Mono.Documentation.Updater
{
static class DocUtils
{
-
public static bool DoesNotHaveApiStyle (this XmlElement element, ApiStyle style)
{
string styleString = style.ToString ().ToLowerInvariant ();
diff --git a/mdoc/Mono.Documentation/Updater/DocsNodeInfo.cs b/mdoc/Mono.Documentation/Updater/DocsNodeInfo.cs
index d262fc84..a17278d9 100644
--- a/mdoc/Mono.Documentation/Updater/DocsNodeInfo.cs
+++ b/mdoc/Mono.Documentation/Updater/DocsNodeInfo.cs
@@ -8,7 +8,7 @@ using Mono.Documentation.Util;
namespace Mono.Documentation.Updater
{
- class DocsNodeInfo
+ public class DocsNodeInfo
{
public DocsNodeInfo (XmlElement node)
{
diff --git a/mdoc/Mono.Documentation/Updater/DocumentationEnumerator.cs b/mdoc/Mono.Documentation/Updater/DocumentationEnumerator.cs
index d5f35fc7..23c9c375 100644
--- a/mdoc/Mono.Documentation/Updater/DocumentationEnumerator.cs
+++ b/mdoc/Mono.Documentation/Updater/DocumentationEnumerator.cs
@@ -7,10 +7,11 @@ using Mono.Cecil;
using StringList = System.Collections.Generic.List<string>;
using Mono.Documentation.Util;
+using Mono.Documentation.Updater.Frameworks;
namespace Mono.Documentation.Updater
-{
- class DocumentationEnumerator
+{
+ public class DocumentationEnumerator
{
public virtual IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes)
@@ -30,7 +31,7 @@ namespace Mono.Documentation.Updater
}
}
- public virtual IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type)
+ public virtual IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type, FrameworkTypeEntry typeEntry)
{
foreach (XmlElement oldmember in basefile.SelectNodes ("Type/Members/Member"))
{
@@ -39,7 +40,7 @@ namespace Mono.Documentation.Updater
oldmember.RemoveAttribute ("__monodocer-seen__");
continue;
}
- MemberReference m = GetMember (type, new DocumentationMember (oldmember));
+ MemberReference m = GetMember (type, new DocumentationMember (oldmember, typeEntry));
if (m == null)
{
yield return new DocsNodeInfo (oldmember);
diff --git a/mdoc/Mono.Documentation/Updater/DocumentationImporter.cs b/mdoc/Mono.Documentation/Updater/DocumentationImporter.cs
index 7c448ca4..516f3708 100644
--- a/mdoc/Mono.Documentation/Updater/DocumentationImporter.cs
+++ b/mdoc/Mono.Documentation/Updater/DocumentationImporter.cs
@@ -1,6 +1,6 @@
namespace Mono.Documentation.Updater
{
- abstract class DocumentationImporter
+ public abstract class DocumentationImporter
{
public abstract void ImportDocumentation (DocsNodeInfo info);
diff --git a/mdoc/Mono.Documentation/Updater/DocumentationMember.cs b/mdoc/Mono.Documentation/Updater/DocumentationMember.cs
index c581daeb..afb00f02 100644
--- a/mdoc/Mono.Documentation/Updater/DocumentationMember.cs
+++ b/mdoc/Mono.Documentation/Updater/DocumentationMember.cs
@@ -1,11 +1,13 @@
using System;
using System.Xml;
+using System.Linq;
using StringList = System.Collections.Generic.List<string>;
using StringToStringMap = System.Collections.Generic.Dictionary<string, string>;
-
+using Mono.Documentation.Updater.Frameworks;
+
namespace Mono.Documentation.Updater
{
- class DocumentationMember
+ public class DocumentationMember
{
public StringToStringMap MemberSignatures = new StringToStringMap ();
public string ReturnType;
@@ -97,7 +99,7 @@ namespace Mono.Documentation.Updater
CleanTypes ();
}
- public DocumentationMember (XmlNode node)
+ public DocumentationMember (XmlNode node, FrameworkTypeEntry typeEntry)
{
MemberName = node.Attributes["MemberName"].Value;
foreach (XmlNode n in node.SelectNodes ("MemberSignature"))
@@ -113,12 +115,19 @@ namespace Mono.Documentation.Updater
XmlNode rt = node.SelectSingleNode ("ReturnValue/ReturnType[not(@apistyle) or @apistyle='classic']");
if (rt != null)
ReturnType = rt.InnerText;
- XmlNodeList p = node.SelectNodes ("Parameters/Parameter[not(@apistyle) or @apistyle='classic']");
- if (p.Count > 0)
+ var p = node.SelectNodes ("Parameters/Parameter[not(@apistyle) or @apistyle='classic']").Cast<XmlElement>().ToArray ();
+ if (p.Length > 0)
{
- Parameters = new StringList (p.Count);
- for (int i = 0; i < p.Count; ++i)
- Parameters.Add (p[i].Attributes["Type"].Value);
+ Parameters = new StringList (p.Length);
+ for (int i = 0; i < p.Length; ++i)
+ {
+ var param = p[i];
+ if (param.HasAttribute ("FrameworkAlternate")) {
+ if (!param.GetAttribute ("FrameworkAlternate").Contains (typeEntry.Framework.Name))
+ continue;
+ }
+ Parameters.Add (param.GetAttribute("Type"));
+ }
}
XmlNodeList tp = node.SelectNodes ("TypeParameters/TypeParameter[not(@apistyle) or @apistyle='classic']");
if (tp.Count > 0)
@@ -147,5 +156,13 @@ namespace Mono.Documentation.Updater
TypeParameters = new StringList (tparams);
}
}
+
+ public override string ToString ()
+ {
+ if (MemberSignatures.Count > 0)
+ return MemberSignatures.Values.First ();
+ else
+ return $"{MemberType}{ReturnType} {MemberName}<{TypeParameters.Count}> ({Parameters.Count})";
+ }
}
} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/EcmaDocumentationEnumerator.cs b/mdoc/Mono.Documentation/Updater/EcmaDocumentationEnumerator.cs
index 86cce337..5f1c211f 100644
--- a/mdoc/Mono.Documentation/Updater/EcmaDocumentationEnumerator.cs
+++ b/mdoc/Mono.Documentation/Updater/EcmaDocumentationEnumerator.cs
@@ -4,7 +4,7 @@ using System.Linq;
using System.Xml;
using Mono.Cecil;
-
+using Mono.Documentation.Updater.Frameworks;
using Mono.Documentation.Util;
namespace Mono.Documentation.Updater
@@ -78,13 +78,13 @@ namespace Mono.Documentation.Updater
}
}
- public override IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type)
+ public override IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type, FrameworkTypeEntry typeEntry)
{
- return GetMembers (basefile, type)
- .Concat (base.GetDocumentationMembers (basefile, type));
+ return GetMembers (basefile, type, typeEntry)
+ .Concat (base.GetDocumentationMembers (basefile, type, typeEntry));
}
- private IEnumerable<DocsNodeInfo> GetMembers (XmlDocument basefile, TypeDefinition type)
+ private IEnumerable<DocsNodeInfo> GetMembers (XmlDocument basefile, TypeDefinition type, FrameworkTypeEntry typeEntry)
{
while (ecmadocs.Name != "Members" && ecmadocs.Read ())
{
@@ -141,7 +141,7 @@ namespace Mono.Documentation.Updater
}
else
{
- m = GetMember (type, new DocumentationMember (oldmember));
+ m = GetMember (type, new DocumentationMember (oldmember, typeEntry));
if (m == null)
{
app.Warning ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
diff --git a/mdoc/Mono.Documentation/Updater/Frameworks/AssemblySet.cs b/mdoc/Mono.Documentation/Updater/Frameworks/AssemblySet.cs
index 70d9483e..6affe4cd 100644
--- a/mdoc/Mono.Documentation/Updater/Frameworks/AssemblySet.cs
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/AssemblySet.cs
@@ -12,9 +12,9 @@ namespace Mono.Documentation.Updater.Frameworks
/// </summary>
class AssemblySet : IDisposable
{
- readonly BaseAssemblyResolver resolver = new Frameworks.MDocResolver ();
- IAssemblyResolver cachedResolver;
- IMetadataResolver metadataResolver;
+ static readonly BaseAssemblyResolver resolver = new Frameworks.MDocResolver ();
+ static IAssemblyResolver cachedResolver;
+ static IMetadataResolver metadataResolver;
HashSet<string> assemblyPaths = new HashSet<string> ();
Dictionary<string, bool> assemblyPathsMap = new Dictionary<string, bool> ();
@@ -27,8 +27,8 @@ namespace Mono.Documentation.Updater.Frameworks
public AssemblySet (string name, IEnumerable<string> paths, IEnumerable<string> resolverSearchPaths, IEnumerable<string> imports = null, string version = null, string id = null)
{
- this.cachedResolver = new CachedResolver (this.resolver);
- this.metadataResolver = new Frameworks.MDocMetadataResolver (this.cachedResolver);
+ cachedResolver = cachedResolver ?? new CachedResolver (resolver);
+ metadataResolver = metadataResolver ?? new Frameworks.MDocMetadataResolver (cachedResolver);
Name = name;
Version = version;
@@ -130,7 +130,7 @@ namespace Mono.Documentation.Updater.Frameworks
IEnumerable<AssemblyDefinition> LoadAllAssemblies ()
{
foreach (var path in this.assemblyPaths) {
- var assembly = MDocUpdater.Instance.LoadAssembly (path, this.metadataResolver, this.cachedResolver);
+ var assembly = MDocUpdater.Instance.LoadAssembly (path, metadataResolver, cachedResolver);
if (assembly != null) {
foreach (var type in assembly.MainModule.ExportedTypes.Where (t => t.IsForwarder).Select (t => t.FullName))
forwardedTypes.Add (type);
diff --git a/mdoc/Mono.Documentation/Updater/Frameworks/FXUtils.cs b/mdoc/Mono.Documentation/Updater/Frameworks/FXUtils.cs
new file mode 100644
index 00000000..c009b110
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/FXUtils.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+namespace Mono.Documentation.Updater.Frameworks
+{
+ public static class FXUtils
+ {
+ public static string AddFXToList (string existingValue, string newFX)
+ {
+ var splitValue = SplitList (existingValue);
+ if (!splitValue.Contains (newFX)) splitValue.Add (newFX);
+ return JoinList (splitValue);
+ }
+
+ public static string RemoveFXFromList (string existingValue, string FXToRemove)
+ {
+ var splitValue = SplitList (existingValue);
+ splitValue.Remove (FXToRemove);
+ return JoinList (splitValue);
+ }
+
+ /// <summary>Returns a list of all previously processed frameworks (not including the current)</summary>
+ internal static string PreviouslyProcessedFXString (FrameworkTypeEntry typeEntry)
+ {
+ if (typeEntry == null)
+ return string.Empty;
+
+ return string.Join (";", typeEntry
+ .PreviouslyProcessedFrameworkTypes
+ .Select (previous => previous?.Framework?.Name)
+ .Where (n => !string.IsNullOrWhiteSpace (n))
+ .ToArray ());
+ }
+
+
+ static List<string> SplitList (string existingValue)
+ {
+ existingValue = existingValue ?? string.Empty;
+
+ return existingValue.Split (new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList ();
+ }
+
+ static string JoinList (List<string> splitValue)
+ {
+ return string.Join (";", splitValue.ToArray ());
+ }
+ }
+}
diff --git a/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkEntry.cs b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkEntry.cs
index 5bd6f346..b3bde88e 100644
--- a/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkEntry.cs
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkEntry.cs
@@ -6,31 +6,46 @@ using Mono.Cecil.Rocks;
namespace Mono.Documentation.Updater.Frameworks
{
- class FrameworkEntry
- {
- SortedSet<FrameworkTypeEntry> types = new SortedSet<FrameworkTypeEntry> ();
+ public class FrameworkEntry
+ {
+ SortedSet<FrameworkTypeEntry> types = new SortedSet<FrameworkTypeEntry> ();
- List<FrameworkEntry> allframeworks;
+ IList<FrameworkEntry> allframeworks;
+ public int index = 0;
- public FrameworkEntry (List<FrameworkEntry> frameworks)
- {
- allframeworks = frameworks;
- if (allframeworks == null)
- allframeworks = new List<FrameworkEntry> (0);
- }
+ public FrameworkEntry (IList<FrameworkEntry> frameworks)
+ {
+ allframeworks = frameworks;
+ if (allframeworks == null)
+ allframeworks = new List<FrameworkEntry> (0);
+
+ index = allframeworks.Count;
+ }
+
+ public string Name { get; set; }
+ public string Version { get; set; }
+ public string Id { get; set; }
- public string Name { get; set; }
- public string Version { get; set; }
- public string Id { get; set; }
+ /// <summary>Only Use in Unit Tests</summary>
+ public string Replace="";
- public IEnumerable<DocumentationImporter> Importers { get; set; }
+ /// <summary>Only Use in Unit Tests</summary>
+ public string With ="";
- public ISet<FrameworkTypeEntry> Types { get { return this.types; } }
+ public IEnumerable<DocumentationImporter> Importers { get; set; }
+
+ public ISet<FrameworkTypeEntry> Types { get { return this.types; } }
Dictionary<string, FrameworkTypeEntry> typeMap = new Dictionary<string, FrameworkTypeEntry> ();
+ public FrameworkTypeEntry FindTypeEntry (FrameworkTypeEntry type)
+ {
+ return FindTypeEntry (Str(type.Name));
+ }
+
+ /// <param name="name">The value from <see cref="FrameworkTypeEntry.Name"/>.</param>
public FrameworkTypeEntry FindTypeEntry (string name) {
FrameworkTypeEntry entry;
- typeMap.TryGetValue (name, out entry);
+ typeMap.TryGetValue (Str(name), out entry);
return entry;
}
@@ -42,17 +57,23 @@ namespace Mono.Documentation.Updater.Frameworks
{
FrameworkTypeEntry entry;
- if (!typeMap.TryGetValue (type.FullName, out entry)) {
+ if (!typeMap.TryGetValue (Str(type.FullName), out entry)) {
var docid = DocCommentId.GetDocCommentId (type);
- entry = new FrameworkTypeEntry (this) { Id = docid, Name = type.FullName, Namespace = type.Namespace };
+ entry = new FrameworkTypeEntry (this) { Id = Str(docid), Name = Str(type.FullName), Namespace = Str(type.Namespace) };
types.Add (entry);
- typeMap.Add (entry.Name, entry);
+ typeMap.Add (Str(entry.Name), entry);
}
return entry;
}
- public override string ToString () => this.Name;
+ string Str(string value) {
+ if (!string.IsNullOrWhiteSpace (Replace))
+ return value.Replace (Replace, With);
+ return value;
+ }
+
+ public override string ToString () => Str(this.Name);
class EmptyFrameworkEntry : FrameworkEntry
{
diff --git a/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkIndex.cs b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkIndex.cs
index 4e0185cc..4adb0494 100644
--- a/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkIndex.cs
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkIndex.cs
@@ -10,7 +10,7 @@ using Mono.Cecil;
namespace Mono.Documentation.Updater.Frameworks
{
- class FrameworkIndex
+ public class FrameworkIndex
{
List<FrameworkEntry> frameworks = new List<FrameworkEntry> ();
string path;
diff --git a/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs
index aaf3b322..a6886c8c 100644
--- a/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs
@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Rocks;
namespace Mono.Documentation.Updater.Frameworks
{
- class FrameworkTypeEntry : IComparable<FrameworkTypeEntry>
+ public class FrameworkTypeEntry : IComparable<FrameworkTypeEntry>
{
SortedSet<string> members = new SortedSet<string> ();
SortedSet<string> memberscsharpsig = new SortedSet<string> ();
@@ -16,6 +17,35 @@ namespace Mono.Documentation.Updater.Frameworks
FrameworkEntry fx;
+ Lazy<FrameworkTypeEntry[]> previouslyProcessedFXTypes;
+
+ /// <summary>
+ /// Returns a list of all corresponding type entries,
+ /// which have already been processed.
+ /// </summary>
+ public FrameworkTypeEntry[] PreviouslyProcessedFrameworkTypes {
+ get
+ {
+ if (previouslyProcessedFXTypes == null)
+ {
+ if (this.Framework == null || this.Framework.Frameworks == null)
+ {
+ previouslyProcessedFXTypes = new Lazy<FrameworkTypeEntry[]> (() => new FrameworkTypeEntry[0]);
+ }
+ else
+ {
+ previouslyProcessedFXTypes = new Lazy<FrameworkTypeEntry[]> (
+ () => this.Framework.Frameworks
+ .Where (f => f.index < this.Framework.index)
+ .Select (f => f.FindTypeEntry (this))
+ .ToArray ()
+ );
+ }
+ }
+ return previouslyProcessedFXTypes.Value;
+ }
+ }
+
public static FrameworkTypeEntry Empty = new EmptyTypeEntry (FrameworkEntry.Empty) { Name = "Empty" };
public FrameworkTypeEntry (FrameworkEntry fx)
@@ -76,6 +106,11 @@ namespace Mono.Documentation.Updater.Frameworks
return this.Name.Equals (other.Name);
}
+ public override int GetHashCode ()
+ {
+ return this.Name?.GetHashCode () ?? base.GetHashCode ();
+ }
+
class EmptyTypeEntry : FrameworkTypeEntry
{
public EmptyTypeEntry (FrameworkEntry fx) : base (fx) { }
diff --git a/mdoc/Mono.Documentation/Updater/XmlSyncer.cs b/mdoc/Mono.Documentation/Updater/XmlSyncer.cs
new file mode 100644
index 00000000..4bc3a40c
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/XmlSyncer.cs
@@ -0,0 +1,269 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml;
+using Mono.Cecil;
+using Mono.Documentation.Updater.Frameworks;
+
+namespace Mono.Documentation.Updater
+{
+ public static class XmlSyncer
+ {
+ public static void MakeParameters (XmlElement root, MemberReference member, IList<ParameterDefinition> parameters, FrameworkTypeEntry typeEntry, ref bool fxAlternateTriggered)
+ {
+ XmlElement e = DocUtils.WriteElement (root, "Parameters");
+
+ /// addParameter does the work of adding the actual parameter to the XML
+ Action<ParameterDefinition, XmlElement, string, int, bool, string, bool> addParameter = (ParameterDefinition param, XmlElement nextTo, string paramType, int index, bool addIndex, string fx, bool addfx) =>
+ {
+ var pe = root.OwnerDocument.CreateElement ("Parameter");
+
+ if (nextTo == null)
+ e.AppendChild (pe);
+ else
+ e.InsertAfter (pe, nextTo);
+
+ pe.SetAttribute ("Name", param.Name);
+ pe.SetAttribute ("Type", paramType);
+ if (param.ParameterType is ByReferenceType)
+ {
+ if (param.IsOut)
+ pe.SetAttribute ("RefType", "out");
+ else
+ pe.SetAttribute ("RefType", "ref");
+ }
+ if (addIndex)
+ pe.SetAttribute ("Index", index.ToString ());
+ if (addfx)
+ pe.SetAttribute ("FrameworkAlternate", fx);
+
+ MakeAttributes (pe, GetCustomAttributes (param.CustomAttributes, ""));
+ };
+
+ /// addFXAttributes, adds the index attribute to all existing elements.
+ /// Used when we first detect the scenario which requires this.
+ Action<XmlNodeList> addFXAttributes = nodes =>
+ {
+ var i = 0;
+ foreach (var node in nodes.Cast<XmlElement> ())
+ {
+ node.SetAttribute ("Index", i.ToString ());
+ i++;
+ }
+ };
+
+ int parameterIndex = 0;
+ int parameterIndexOffset = 0;
+
+ var paramNodes = e.GetElementsByTagName ("Parameter");
+ bool inFXMode = frameworksCache.Frameworks.Count () > 1;
+
+ foreach (ParameterDefinition p in parameters)
+ {
+ var ptype = GetDocParameterType (p.ParameterType);
+ if (parameterIndex >= paramNodes.Count)
+ {
+ // this parameter hasn't been added yet
+ bool hasParameterName = string.IsNullOrWhiteSpace (p.Name);
+ addParameter (p, null, ptype, parameterIndex, false, "", false);
+ }
+ else // there's enough nodes, see if it truly exists
+ {
+ //look for < parameter > that matches position
+ XmlElement parameterNode = e.ChildNodes[parameterIndex + parameterIndexOffset] as XmlElement;
+
+
+ if (parameterNode != null)
+ {
+ //Assert Type Matches (if not, throw?)
+ if (parameterNode.HasAttribute ("Name") && parameterNode.Attributes["Name"].Value == p.Name)
+ {
+ // we're good, continue on.
+ }
+ else
+ { // name doesn't match
+ if (parameterNode.HasAttribute ("Index"))
+ {
+ // TODO: add a FrameworkAlternate check, and set offset correctly
+ int pindex;
+ if (int.TryParse (parameterNode.GetAttribute ("Index"), out pindex) && pindex < parameterIndex)
+ {
+ parameterIndexOffset++;
+
+ continue;
+ }
+ }
+ else
+ {
+ if (!inFXMode) throw new Exception ("shit");
+ addFXAttributes (paramNodes);
+ //-find type in previous frameworks
+
+
+ string fxList = FXUtils.PreviouslyProcessedFXString (typeEntry);
+
+ //-find < parameter where index = currentIndex >
+ var currentNode = paramNodes[parameterIndex] as XmlElement;
+ currentNode.SetAttribute ("FrameworkAlternate", fxList);
+
+ addParameter (p, parameterNode, ptype, parameterIndex - parameterIndexOffset, true, typeEntry.Framework.Name, true);
+ parameterIndexOffset++;
+ fxAlternateTriggered = true;
+ }
+ }
+
+ }
+ else
+ { // no element at this index
+ // TODO: does this ever happen?
+ throw new Exception ("This wasn't supposed to happen");
+ //addParameter (p);
+ }
+ /*
+ - If found
+ - Assert Type Matches (if not, throw?)
+ -If Name Matches …
+ - if “FrameworkAlternate”
+ -Add typeEntry.Framework.Name to list
+ - done!
+ -Else (exists, but name doesn’t match … FrameworkAlternate path)
+ - check if inFXMode if not, throw
+ -AddFXParameters
+ - adds Index to all existing<parameters
+ -find type in previous frameworks
+ -find < parameter where index = currentIndex >
+ -Add FrameworkAlternate = allPreviousFrameworks and Index = currentIndex
+ - Add new node with Index = currentIndex
+ - else not found
+ -add
+ */
+ }
+ parameterIndex++;
+ }
+ //-purge `typeEntry.Framework` from any<parameter> that
+ // has FrameworkAlternate, and “name” doesn’t match any
+ // `parameters`
+ var alternates = paramNodes
+ .Cast<XmlElement> ()
+ .Select (p => new
+ {
+ Element = p,
+ Name = p.GetAttribute ("Name"),
+ FrameworkAlternate = p.GetAttribute ("FrameworkAlternate")
+ })
+ .Where (p =>
+ !string.IsNullOrWhiteSpace (p.FrameworkAlternate) &&
+ p.FrameworkAlternate.Contains (typeEntry.Framework.Name) &&
+ !parameters.Any (param => param.Name == p.Name))
+ .ToArray ();
+ if (alternates.Any ())
+ {
+ foreach (var a in alternates)
+ {
+ string newValue = FXUtils.RemoveFXFromList (a.FrameworkAlternate, typeEntry.Framework.Name);
+ if (string.IsNullOrWhiteSpace (newValue))
+ {
+ a.Element.RemoveAttribute ("FrameworkAlternate");
+ }
+ else
+ {
+ a.Element.SetAttribute ("FrameworkAlternate", newValue);
+ }
+ }
+ }
+
+ return;
+ /*
+ // old code
+ foreach (ParameterDefinition p in parameters)
+ {
+ XmlElement pe;
+
+ // param info
+ var ptype = GetDocParameterType (p.ParameterType);
+ var newPType = ptype;
+
+ if (MDocUpdater.SwitchingToMagicTypes)
+ {
+ newPType = NativeTypeManager.ConvertFromNativeType (ptype);
+ }
+
+ // now find the existing node, if it's there so we can reuse it.
+ var nodes = root.SelectSingleNode ("Parameters").SelectNodes ("Parameter")
+ .Cast<XmlElement> ().Where (x => x.GetAttribute ("Name") == p.Name)
+ .ToArray ();
+
+ // FYI: Exists? No?
+ if (nodes.Count () == 0)
+ {
+ // TODO: instead of this. Needs to be replaced with a better
+ // check for Parameter index ... should I add parameter index?
+
+ // are we in frameworks mode?
+ // add Index to all existing parameter nodes if they don't have them
+ // match existing to position and type
+ bool _inFXMode = typeEntry.Framework.Frameworks.Count () > 1;
+
+ // when I find the one, name won't match ...
+
+ // find all "previous" frameworks
+ // Add FrameworkAlternate with previous frameworks to found/pre-existing node
+ var allPreviousTypes_ = typeEntry.Framework.Frameworks
+ .Where (f => f.index < typeEntry.Framework.index)
+ .Select (f => f.FindTypeEntry (typeEntry))
+ .ToArray ();
+
+ var allPreviousFrameworks = allPreviousTypes.Value.Select (previous => previous.Framework.Name).ToArray ();
+ string fxList = string.Join (";", allPreviousFrameworks);
+
+ // find the parameters in `root` that have an index == this parameter's index
+ // if they don't match, then we need to make a new one for this
+
+ // Create new "Parameter" node, with FrameworkAlternate = this
+
+ // Legacy: wasn't found, let's make sure it wasn't just cause the param name was changed
+ nodes = root.SelectSingleNode ("Parameters").SelectNodes ("Parameter")
+ .Cast<XmlElement> ()
+ .Skip (parameterIndex) // this makes sure we don't inadvertently "reuse" nodes when adding new ones
+ .Where (x => x.GetAttribute ("Name") != p.Name && (x.GetAttribute ("Type") == ptype || x.GetAttribute ("Type") == newPType))
+ .Take (1) // there might be more than one that meets this parameter ... only take the first.
+ .ToArray ();
+ }
+
+ AddXmlNode (nodes,
+ x => x.GetAttribute ("Type") == ptype,
+ x => x.SetAttribute ("Type", ptype),
+ () =>
+ {
+ pe = root.OwnerDocument.CreateElement ("Parameter");
+ e.AppendChild (pe);
+
+ pe.SetAttribute ("Name", p.Name);
+ pe.SetAttribute ("Type", ptype);
+ if (p.ParameterType is ByReferenceType)
+ {
+ if (p.IsOut)
+ pe.SetAttribute ("RefType", "out");
+ else
+ pe.SetAttribute ("RefType", "ref");
+ }
+
+ MakeAttributes (pe, GetCustomAttributes (p.CustomAttributes, ""));
+ return pe;
+ },
+ member);
+
+ parameterIndex++;
+ }
+
+ // TODO: was there a `Parameter` that we didn't process that has FrameworkAlternate?
+ // if yes, remove this framework from that FrameworkAlternate
+ // if that makes the list empty, remove the node and corresponding /Docs/parameter node
+ */
+ }
+
+
+
+
+ }
+}
diff --git a/mdoc/Mono.Documentation/mdoc.cs b/mdoc/Mono.Documentation/mdoc.cs
index bb1c4c65..4b0a63ba 100644
--- a/mdoc/Mono.Documentation/mdoc.cs
+++ b/mdoc/Mono.Documentation/mdoc.cs
@@ -63,7 +63,7 @@ namespace Mono.Documentation {
var extra = p.Parse (args);
- if (showVersion) {
+ if (showVersion) {
Console.WriteLine ("mdoc {0}", Consts.MonoVersion);
return;
}
diff --git a/mdoc/Test/DocTest-frameworkalternate.cs b/mdoc/Test/DocTest-frameworkalternate.cs
new file mode 100644
index 00000000..28a81f70
--- /dev/null
+++ b/mdoc/Test/DocTest-frameworkalternate.cs
@@ -0,0 +1,13 @@
+namespace Monodoc.Test
+{
+ public class MyClass
+ {
+ #if FXONE
+ public void Meth(int a, string b, int c) {}
+ #endif
+
+ #if FXTWO
+ public void Meth(int a, string d, int c) {}
+ #endif
+ }
+} \ No newline at end of file
diff --git a/mdoc/Test/en.expected-frameworkalternate-aligned/FrameworksIndex/One.xml b/mdoc/Test/en.expected-frameworkalternate-aligned/FrameworksIndex/One.xml
new file mode 100644
index 00000000..8248544a
--- /dev/null
+++ b/mdoc/Test/en.expected-frameworkalternate-aligned/FrameworksIndex/One.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Framework Name="One">
+ <Namespace Name="Monodoc.Test">
+ <Type Name="Monodoc.Test.MyClass" Id="T:Monodoc.Test.MyClass">
+ <Member Id="M:Monodoc.Test.MyClass.#ctor" />
+ <Member Id="M:Monodoc.Test.MyClass.Meth(System.Int32,System.String,System.Int32)" />
+ </Type>
+ </Namespace>
+</Framework> \ No newline at end of file
diff --git a/mdoc/Test/en.expected-frameworkalternate-aligned/FrameworksIndex/Three.xml b/mdoc/Test/en.expected-frameworkalternate-aligned/FrameworksIndex/Three.xml
new file mode 100644
index 00000000..9bb0a092
--- /dev/null
+++ b/mdoc/Test/en.expected-frameworkalternate-aligned/FrameworksIndex/Three.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Framework Name="Three">
+ <Namespace Name="Monodoc.Test">
+ <Type Name="Monodoc.Test.MyClass" Id="T:Monodoc.Test.MyClass">
+ <Member Id="M:Monodoc.Test.MyClass.#ctor" />
+ <Member Id="M:Monodoc.Test.MyClass.Meth(System.Int32,System.String,System.Int32)" />
+ </Type>
+ </Namespace>
+</Framework> \ No newline at end of file
diff --git a/mdoc/Test/en.expected-frameworkalternate-aligned/FrameworksIndex/Two.xml b/mdoc/Test/en.expected-frameworkalternate-aligned/FrameworksIndex/Two.xml
new file mode 100644
index 00000000..7ba7f611
--- /dev/null
+++ b/mdoc/Test/en.expected-frameworkalternate-aligned/FrameworksIndex/Two.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Framework Name="Two">
+ <Namespace Name="Monodoc.Test">
+ <Type Name="Monodoc.Test.MyClass" Id="T:Monodoc.Test.MyClass">
+ <Member Id="M:Monodoc.Test.MyClass.#ctor" />
+ <Member Id="M:Monodoc.Test.MyClass.Meth(System.Int32,System.String,System.Int32)" />
+ </Type>
+ </Namespace>
+</Framework> \ No newline at end of file
diff --git a/mdoc/Test/en.expected-frameworkalternate-aligned/Monodoc.Test/MyClass.xml b/mdoc/Test/en.expected-frameworkalternate-aligned/Monodoc.Test/MyClass.xml
new file mode 100644
index 00000000..8a01c986
--- /dev/null
+++ b/mdoc/Test/en.expected-frameworkalternate-aligned/Monodoc.Test/MyClass.xml
@@ -0,0 +1,68 @@
+<Type Name="MyClass" FullName="Monodoc.Test.MyClass">
+ <TypeSignature Language="C#" Value="public class MyClass" />
+ <TypeSignature Language="ILAsm" Value=".class public auto ansi beforefieldinit MyClass extends System.Object" />
+ <AssemblyInfo>
+ <AssemblyName>DocTest-frameworkalternate-one</AssemblyName>
+ <AssemblyVersion>0.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <AssemblyInfo>
+ <AssemblyName>DocTest-frameworkalternate-two</AssemblyName>
+ <AssemblyVersion>0.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <Base>
+ <BaseTypeName>System.Object</BaseTypeName>
+ </Base>
+ <Interfaces />
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ <Members>
+ <Member MemberName=".ctor">
+ <MemberSignature Language="C#" Value="public MyClass ();" />
+ <MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor() cil managed" />
+ <MemberType>Constructor</MemberType>
+ <AssemblyInfo>
+ <AssemblyName>DocTest-frameworkalternate-one</AssemblyName>
+ <AssemblyVersion>0.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <AssemblyInfo>
+ <AssemblyName>DocTest-frameworkalternate-two</AssemblyName>
+ <AssemblyVersion>0.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <Parameters />
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>
+ <Member MemberName="Meth">
+ <MemberSignature Language="C#" Value="public void Meth (int a, string b, int c);" FrameworkAlternate="One;Three;Two" />
+ <MemberSignature Language="ILAsm" Value=".method public hidebysig instance void Meth(int32 a, string b, int32 c) cil managed" FrameworkAlternate="One;Three;Two" />
+ <MemberType>Method</MemberType>
+ <AssemblyInfo>
+ <AssemblyName>DocTest-frameworkalternate-one</AssemblyName>
+ <AssemblyVersion>0.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <AssemblyInfo>
+ <AssemblyName>DocTest-frameworkalternate-two</AssemblyName>
+ <AssemblyVersion>0.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name="a" Type="System.Int32" Index="0" />
+ <Parameter Name="b" Type="System.String" Index="1" FrameworkAlternate="One;Three;Two" />
+ <Parameter Name="c" Type="System.Int32" Index="2" />
+ </Parameters>
+ <Docs>
+ <param name="a">To be added.</param>
+ <param name="b">To be added.</param>
+ <param name="c">To be added.</param>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>
+ </Members>
+</Type>
diff --git a/mdoc/Test/en.expected-frameworkalternate-aligned/index.xml b/mdoc/Test/en.expected-frameworkalternate-aligned/index.xml
new file mode 100644
index 00000000..264c4b95
--- /dev/null
+++ b/mdoc/Test/en.expected-frameworkalternate-aligned/index.xml
@@ -0,0 +1,32 @@
+<Overview>
+ <Assemblies>
+ <Assembly Name="DocTest-frameworkalternate-one" Version="0.0.0.0">
+ <Attributes>
+ <Attribute>
+ <AttributeName>System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.DisableOptimizations | System.Diagnostics.DebuggableAttribute+DebuggingModes.IgnoreSymbolStoreSequencePoints)</AttributeName>
+ </Attribute>
+ <Attribute>
+ <AttributeName>System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true)</AttributeName>
+ </Attribute>
+ </Attributes>
+ </Assembly>
+ <Assembly Name="DocTest-frameworkalternate-two" Version="0.0.0.0">
+ <Attributes>
+ <Attribute>
+ <AttributeName>System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.DisableOptimizations | 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>
+ <Types>
+ <Namespace Name="Monodoc.Test">
+ <Type Name="MyClass" Kind="Class" />
+ </Namespace>
+ </Types>
+ <Title>Untitled</Title>
+</Overview>
diff --git a/mdoc/Test/en.expected-frameworkalternate-aligned/ns-Monodoc.Test.xml b/mdoc/Test/en.expected-frameworkalternate-aligned/ns-Monodoc.Test.xml
new file mode 100644
index 00000000..47a0e25c
--- /dev/null
+++ b/mdoc/Test/en.expected-frameworkalternate-aligned/ns-Monodoc.Test.xml
@@ -0,0 +1,6 @@
+<Namespace Name="Monodoc.Test">
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+</Namespace>
diff --git a/mdoc/Test/en.expected-frameworkalternate/FrameworksIndex/One.xml b/mdoc/Test/en.expected-frameworkalternate/FrameworksIndex/One.xml
new file mode 100644
index 00000000..8248544a
--- /dev/null
+++ b/mdoc/Test/en.expected-frameworkalternate/FrameworksIndex/One.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Framework Name="One">
+ <Namespace Name="Monodoc.Test">
+ <Type Name="Monodoc.Test.MyClass" Id="T:Monodoc.Test.MyClass">
+ <Member Id="M:Monodoc.Test.MyClass.#ctor" />
+ <Member Id="M:Monodoc.Test.MyClass.Meth(System.Int32,System.String,System.Int32)" />
+ </Type>
+ </Namespace>
+</Framework> \ No newline at end of file
diff --git a/mdoc/Test/en.expected-frameworkalternate/FrameworksIndex/Three.xml b/mdoc/Test/en.expected-frameworkalternate/FrameworksIndex/Three.xml
new file mode 100644
index 00000000..9bb0a092
--- /dev/null
+++ b/mdoc/Test/en.expected-frameworkalternate/FrameworksIndex/Three.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Framework Name="Three">
+ <Namespace Name="Monodoc.Test">
+ <Type Name="Monodoc.Test.MyClass" Id="T:Monodoc.Test.MyClass">
+ <Member Id="M:Monodoc.Test.MyClass.#ctor" />
+ <Member Id="M:Monodoc.Test.MyClass.Meth(System.Int32,System.String,System.Int32)" />
+ </Type>
+ </Namespace>
+</Framework> \ No newline at end of file
diff --git a/mdoc/Test/en.expected-frameworkalternate/FrameworksIndex/Two.xml b/mdoc/Test/en.expected-frameworkalternate/FrameworksIndex/Two.xml
new file mode 100644
index 00000000..7ba7f611
--- /dev/null
+++ b/mdoc/Test/en.expected-frameworkalternate/FrameworksIndex/Two.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Framework Name="Two">
+ <Namespace Name="Monodoc.Test">
+ <Type Name="Monodoc.Test.MyClass" Id="T:Monodoc.Test.MyClass">
+ <Member Id="M:Monodoc.Test.MyClass.#ctor" />
+ <Member Id="M:Monodoc.Test.MyClass.Meth(System.Int32,System.String,System.Int32)" />
+ </Type>
+ </Namespace>
+</Framework> \ No newline at end of file
diff --git a/mdoc/Test/en.expected-frameworkalternate/Monodoc.Test/MyClass.xml b/mdoc/Test/en.expected-frameworkalternate/Monodoc.Test/MyClass.xml
new file mode 100644
index 00000000..a0559f3b
--- /dev/null
+++ b/mdoc/Test/en.expected-frameworkalternate/Monodoc.Test/MyClass.xml
@@ -0,0 +1,72 @@
+<Type Name="MyClass" FullName="Monodoc.Test.MyClass">
+ <TypeSignature Language="C#" Value="public class MyClass" />
+ <TypeSignature Language="ILAsm" Value=".class public auto ansi beforefieldinit MyClass extends System.Object" />
+ <AssemblyInfo>
+ <AssemblyName>DocTest-frameworkalternate-one</AssemblyName>
+ <AssemblyVersion>0.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <AssemblyInfo>
+ <AssemblyName>DocTest-frameworkalternate-two</AssemblyName>
+ <AssemblyVersion>0.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <Base>
+ <BaseTypeName>System.Object</BaseTypeName>
+ </Base>
+ <Interfaces />
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ <Members>
+ <Member MemberName=".ctor">
+ <MemberSignature Language="C#" Value="public MyClass ();" />
+ <MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor() cil managed" />
+ <MemberType>Constructor</MemberType>
+ <AssemblyInfo>
+ <AssemblyName>DocTest-frameworkalternate-one</AssemblyName>
+ <AssemblyVersion>0.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <AssemblyInfo>
+ <AssemblyName>DocTest-frameworkalternate-two</AssemblyName>
+ <AssemblyVersion>0.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <Parameters />
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>
+ <Member MemberName="Meth">
+ <MemberSignature Language="C#" Value="public void Meth (int a, string b, int c);" FrameworkAlternate="One;Three" />
+ <MemberSignature Language="ILAsm" Value=".method public hidebysig instance void Meth(int32 a, string b, int32 c) cil managed" FrameworkAlternate="One;Three" />
+ <MemberSignature Language="C#" Value="public void Meth (int a, string d, int c);" FrameworkAlternate="Two" />
+ <MemberSignature Language="ILAsm" Value=".method public hidebysig instance void Meth(int32 a, string d, int32 c) cil managed" FrameworkAlternate="Two" />
+ <MemberType>Method</MemberType>
+ <AssemblyInfo>
+ <AssemblyName>DocTest-frameworkalternate-one</AssemblyName>
+ <AssemblyVersion>0.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <AssemblyInfo>
+ <AssemblyName>DocTest-frameworkalternate-two</AssemblyName>
+ <AssemblyVersion>0.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name="a" Type="System.Int32" Index="0" />
+ <Parameter Name="b" Type="System.String" Index="1" FrameworkAlternate="One;Three" />
+ <Parameter Name="d" Type="System.String" Index="1" FrameworkAlternate="Two" />
+ <Parameter Name="c" Type="System.Int32" Index="2" />
+ </Parameters>
+ <Docs>
+ <param name="a">To be added.</param>
+ <param name="b">To be added.</param>
+ <param name="d">To be added.</param>
+ <param name="c">To be added.</param>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>
+ </Members>
+</Type>
diff --git a/mdoc/Test/en.expected-frameworkalternate/index.xml b/mdoc/Test/en.expected-frameworkalternate/index.xml
new file mode 100644
index 00000000..264c4b95
--- /dev/null
+++ b/mdoc/Test/en.expected-frameworkalternate/index.xml
@@ -0,0 +1,32 @@
+<Overview>
+ <Assemblies>
+ <Assembly Name="DocTest-frameworkalternate-one" Version="0.0.0.0">
+ <Attributes>
+ <Attribute>
+ <AttributeName>System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.DisableOptimizations | System.Diagnostics.DebuggableAttribute+DebuggingModes.IgnoreSymbolStoreSequencePoints)</AttributeName>
+ </Attribute>
+ <Attribute>
+ <AttributeName>System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true)</AttributeName>
+ </Attribute>
+ </Attributes>
+ </Assembly>
+ <Assembly Name="DocTest-frameworkalternate-two" Version="0.0.0.0">
+ <Attributes>
+ <Attribute>
+ <AttributeName>System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.DisableOptimizations | 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>
+ <Types>
+ <Namespace Name="Monodoc.Test">
+ <Type Name="MyClass" Kind="Class" />
+ </Namespace>
+ </Types>
+ <Title>Untitled</Title>
+</Overview>
diff --git a/mdoc/Test/en.expected-frameworkalternate/ns-Monodoc.Test.xml b/mdoc/Test/en.expected-frameworkalternate/ns-Monodoc.Test.xml
new file mode 100644
index 00000000..47a0e25c
--- /dev/null
+++ b/mdoc/Test/en.expected-frameworkalternate/ns-Monodoc.Test.xml
@@ -0,0 +1,6 @@
+<Namespace Name="Monodoc.Test">
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+</Namespace>
diff --git a/mdoc/Test/en.expected-fsharp/Delegates+Delegate10.xml b/mdoc/Test/en.expected-fsharp/Delegates+Delegate10.xml
index 67610d30..ad81f914 100644
--- a/mdoc/Test/en.expected-fsharp/Delegates+Delegate10.xml
+++ b/mdoc/Test/en.expected-fsharp/Delegates+Delegate10.xml
@@ -16,6 +16,7 @@
</Attributes>
<Parameters>
<Parameter Name="" Type="System.Int32" />
+ <Parameter Name="" Type="System.Int32" />
</Parameters>
<ReturnValue>
<ReturnType>System.Char</ReturnType>
diff --git a/mdoc/Test/en.expected-fsharp/Delegates+Delegate2.xml b/mdoc/Test/en.expected-fsharp/Delegates+Delegate2.xml
index 08ecd38a..335aae0a 100644
--- a/mdoc/Test/en.expected-fsharp/Delegates+Delegate2.xml
+++ b/mdoc/Test/en.expected-fsharp/Delegates+Delegate2.xml
@@ -16,6 +16,7 @@
</Attributes>
<Parameters>
<Parameter Name="" Type="System.Int32" />
+ <Parameter Name="" Type="System.Int32" />
</Parameters>
<ReturnValue>
<ReturnType>System.Int32</ReturnType>
diff --git a/mdoc/Test/en.expected-fsharp/Delegates+Delegate3.xml b/mdoc/Test/en.expected-fsharp/Delegates+Delegate3.xml
index dd567554..3f31d6de 100644
--- a/mdoc/Test/en.expected-fsharp/Delegates+Delegate3.xml
+++ b/mdoc/Test/en.expected-fsharp/Delegates+Delegate3.xml
@@ -15,6 +15,7 @@
</Attribute>
</Attributes>
<Parameters>
+ <Parameter Name="" Type="System.Int32" />
<Parameter Name="" Type="System.Char" />
</Parameters>
<ReturnValue>
diff --git a/mdoc/mdoc.Test/FrameworkAlternateTests.cs b/mdoc/mdoc.Test/FrameworkAlternateTests.cs
new file mode 100644
index 00000000..1727106d
--- /dev/null
+++ b/mdoc/mdoc.Test/FrameworkAlternateTests.cs
@@ -0,0 +1,27 @@
+using Mono.Documentation.Updater.Frameworks;
+using NUnit.Framework;
+using System;
+using System.Linq;
+
+namespace mdoc.Test
+{
+ [TestFixture ()]
+ public class FrameworkAlternateTests
+ {
+ [Test ()]
+ public void AddToEmptyList()
+ {
+ string newValue = FXUtils.AddFXToList ("", "One");
+
+ Assert.AreEqual ("One", newValue);
+ }
+
+
+ [Test ()]
+ public void RemoveFromList()
+ {
+ string newValue = FXUtils.RemoveFXFromList ("One", "One");
+ Assert.AreEqual ("", newValue);
+ }
+ }
+}
diff --git a/mdoc/mdoc.Test/UwpTestWinRtComponentCpp/UwpTestWinRtComponentCpp.vcxproj b/mdoc/mdoc.Test/UwpTestWinRtComponentCpp/UwpTestWinRtComponentCpp.vcxproj
index cf1008fc..eb64cca7 100644
--- a/mdoc/mdoc.Test/UwpTestWinRtComponentCpp/UwpTestWinRtComponentCpp.vcxproj
+++ b/mdoc/mdoc.Test/UwpTestWinRtComponentCpp/UwpTestWinRtComponentCpp.vcxproj
@@ -34,8 +34,8 @@
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
- <WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
- <WindowsTargetPlatformMinVersion>10.0.10586.0</WindowsTargetPlatformMinVersion>
+ <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
+ <WindowsTargetPlatformMinVersion>10.0.16299.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
diff --git a/mdoc/mdoc.Test/XmlUpdateTests.cs b/mdoc/mdoc.Test/XmlUpdateTests.cs
new file mode 100644
index 00000000..4d4aba38
--- /dev/null
+++ b/mdoc/mdoc.Test/XmlUpdateTests.cs
@@ -0,0 +1,663 @@
+using NUnit.Framework;
+using System;
+using Mono.Documentation;
+using System.Xml;
+using System.Linq;
+using Mono.Cecil;
+using System.Collections.Generic;
+using Mono.Documentation.Updater.Frameworks;
+using Mono.Documentation.Updater;
+
+namespace mdoc.Test2
+{
+ public class MyClass
+ {
+ public void Meth (int a, string b, int c) { }
+ }
+ public class MyClass2
+ {
+ public void Meth (int d, string e, int f) { }
+ }
+}
+namespace mdoc.Test
+{
+ public class MyClass
+ {
+ public void Meth(int a, string d, int c) {}
+
+ }
+ public class MyClass2
+ {
+ public void Meth (int a, string b, int c) { }
+ }
+
+ /// <summary>
+ /// Tests functions that update the EcmaXMl under various conditions from
+ /// corresponding classes.
+ /// </summary>
+ [TestFixture ()]
+ public class XmlUpdateTests
+ {
+ class ParamContext {
+ public XmlDocument doc;
+ public string beforeXML;
+ public MethodReference method;
+ public List<ParameterDefinition> parameters;
+ public MDocUpdater updater;
+ public FrameworkIndex fx;
+ }
+
+ #region Myclass Tests
+ [Test ()]
+ public void Parameters_Updating_Normal ()
+ {
+ var context = InitContext <MyClass>(startingEmptyXml, 0);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[0].Types.First ();
+ bool fxAlternateTriggered = false;
+
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry, ref fxAlternateTriggered);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (Normalize(normalSingleXml), afterXML);
+
+ }
+
+ [Test ()]
+ public void Parameters_Updating_Normal2 ()
+ {
+ var context = InitContext <MyClass>(normalSingleXml,1);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[1].Types.First ();
+ bool fxAlternateTriggered = false;
+
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry, ref fxAlternateTriggered);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (Normalize (normalSingleXml), afterXML);
+
+ }
+
+ [Test ()]
+ public void Parameters_Updating_Normal3 ()
+ {
+ var context = InitContext <MyClass>(normalSingleXml, 2);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[2].Types.First ();
+ bool fxAlternateTriggered = false;
+
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry, ref fxAlternateTriggered);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (Normalize (multiFrameworkXml), afterXML);
+
+ }
+
+ [Test ()]
+ public void Parameters_Updating_Existing_MultiFramework ()
+ {
+ var context = InitContext <MyClass>(multiFrameworkXml, 0);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[0].Types.First ();
+ bool fxAlternateTriggered = false;
+
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry, ref fxAlternateTriggered);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (context.beforeXML, Normalize(afterXML));
+
+ }
+
+ [Test ()]
+ public void Parameters_Updating_Existing_MultiFramework2 ()
+ {
+ var context = InitContext <MyClass>(multiFrameworkXml, 2);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[2].Types.First ();
+ bool fxAlternateTriggered = false;
+
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry, ref fxAlternateTriggered);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (context.beforeXML, Normalize (afterXML));
+
+ }
+
+
+
+ [Test ()]
+ public void Parameters_Updating_Existing_Align ()
+ {
+ var context = InitContext<MyClass> (multiFrameworkXml, 2, forceAlignment: true);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[2].Types.First ();
+ bool fxAlternateTriggered = false;
+
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry, ref fxAlternateTriggered);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.IsFalse (fxAlternateTriggered);
+ Assert.AreEqual (Normalize (multiFrameworkAligned), Normalize (afterXML));
+
+ }
+ #endregion
+
+ #region MyClass2 tests
+
+ [Test ()]
+ public void Parameters2_Updating_Normal ()
+ {
+ var context = InitContext<MyClass2> (startingEmptyXml, 0);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[0].Types.First ();
+ bool fxAlternateTriggered = false;
+
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry, ref fxAlternateTriggered);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (Normalize (normalSingleXml2), afterXML);
+
+ }
+
+ [Test ()]
+ public void Parameters_Updating_Normal22 ()
+ {
+ var context = InitContext<MyClass2> (normalSingleXml2, 1);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[1].Types.First ();
+ bool fxAlternateTriggered = false;
+
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry, ref fxAlternateTriggered);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (Normalize (multiFrameworkXml2_Second), afterXML);
+
+ }
+
+ [Test ()]
+ public void Parameters_Updating_Normal32 ()
+ {
+ var context = InitContext<MyClass2> (multiFrameworkXml2_Second, 2);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[2].Types.First ();
+ bool fxAlternateTriggered = false;
+
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry, ref fxAlternateTriggered);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (Normalize (multiFrameworkXml2), afterXML);
+
+ }
+
+ [Test ()]
+ public void Parameters_Updating_Existing_MultiFramework22 ()
+ {
+ var context = InitContext<MyClass2> (multiFrameworkXml2, 0);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[0].Types.First ();
+ bool fxAlternateTriggered = false;
+
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry, ref fxAlternateTriggered);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (context.beforeXML, Normalize (afterXML));
+
+ }
+
+ [Test ()]
+ public void Parameters_Updating_Existing_MultiFramework222 ()
+ {
+ var context = InitContext<MyClass2> (multiFrameworkXml2, 2);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[2].Types.First ();
+ bool fxAlternateTriggered = false;
+
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry, ref fxAlternateTriggered);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (context.beforeXML, Normalize (afterXML));
+
+ }
+
+
+
+ [Test ()]
+ public void Parameters_Updating_Existing_Align2 ()
+ {
+ var context = InitContext<MyClass2> (multiFrameworkXml2, 1, forceAlignment: true);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[1].Types.First ();
+ bool fxAlternateTriggered = false;
+
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry, ref fxAlternateTriggered);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.IsFalse (fxAlternateTriggered);
+ Assert.AreEqual (Normalize (multiFrameworkAligned2), Normalize (afterXML));
+
+ }
+ #endregion
+
+ #region Simple Parameter Change across multi FX
+
+ [Test ()]
+ public void Parameters_Updating_Existing_NameChange ()
+ {
+ var context = InitContext<MyClass2> (normalSingleXml2, 1, forceAlignment: false);
+
+ Func<int, FrameworkTypeEntry> typeEntry = i => context.fx.Frameworks[i].Types.First ();
+ bool fxAlternateTriggered = false;
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry(0), ref fxAlternateTriggered);
+ Assert.IsTrue (fxAlternateTriggered);
+
+ fxAlternateTriggered = false;
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry (1), ref fxAlternateTriggered);
+ Assert.IsFalse (fxAlternateTriggered);
+
+ fxAlternateTriggered = false;
+ context.updater.MakeParameters (context.doc.FirstChild as XmlElement, context.method, context.parameters, typeEntry (2), ref fxAlternateTriggered);
+ Assert.IsFalse (fxAlternateTriggered);
+
+ var afterXML = context.doc.OuterXml;
+ Assert.AreEqual (Normalize (multiFrameworkAlignedOther), Normalize (afterXML));
+
+ }
+ #endregion
+
+
+ [Test ()]
+ public void MemberSignature_Updating_Existing_Align ()
+ {
+ var context = InitContext <MyClass>(SigmultiFrameworkXml, 0, forceAlignment: true);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[0].Types.First ();
+
+
+ var sig = new CSharpMemberFormatter ();
+ MDocUpdater.UpdateSignature (sig, context.method, context.doc.FirstChild as XmlElement, typeEntry, fxAlternateTriggered:false);
+
+ var afterXML = context.doc.OuterXml;
+ // first framework looks like it already looked, so no need to update
+ Assert.AreEqual (Normalize (SigmultiFrameworkXml), Normalize (afterXML));
+
+ }
+
+ [Test ()]
+ public void MemberSignature_Updating_Existing_Align2 ()
+ {
+ var context = InitContext <MyClass>(SigmultiFrameworkXml, 2, forceAlignment: true);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[2].Types.First ();
+
+
+ var sig = new CSharpMemberFormatter ();
+ MDocUpdater.UpdateSignature (sig, context.method, context.doc.FirstChild as XmlElement, typeEntry, fxAlternateTriggered: false);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (Normalize (SigmultiFrameworkAligned), Normalize (afterXML));
+
+ }
+
+ [Test ()]
+ public void MemberSignature_Updating_Existing_NoChange ()
+ {
+ var context = InitContext <MyClass>(SigmultiFrameworkXml, 2, forceAlignment: false);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[2].Types.First ();
+
+
+ var sig = new CSharpMemberFormatter ();
+ MDocUpdater.UpdateSignature (sig, context.method, context.doc.FirstChild as XmlElement, typeEntry, fxAlternateTriggered: false);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (Normalize (SigmultiFrameworkXml), Normalize (afterXML));
+
+ }
+
+
+ [Test ()]
+ public void MemberSignature_Updating_Existing_NoChange_regular ()
+ {
+ var context = InitContext<MyClass> (SigRegular, 1, forceAlignment: false);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[1].Types.First ();
+
+
+ var sig = new CSharpMemberFormatter ();
+ MDocUpdater.UpdateSignature (sig, context.method, context.doc.FirstChild as XmlElement, typeEntry, fxAlternateTriggered: false);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (Normalize (SigRegular), Normalize (afterXML));
+
+ }
+
+
+
+ [Test ()]
+ public void MemberSignature_Updating_Existing_NameChanged_SingleFX()
+ {
+ // handles the case
+ var context = InitContext<MyClass> (SigRegular, 2, forceAlignment: false);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[0].Types.First ();
+ context.fx.Frameworks.RemoveAt (2);
+ context.fx.Frameworks.RemoveAt (1);
+
+ var sig = new CSharpMemberFormatter ();
+ MDocUpdater.UpdateSignature (sig, context.method, context.doc.FirstChild as XmlElement, typeEntry, fxAlternateTriggered: true);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (Normalize (SigRegularChanged), Normalize (afterXML));
+
+ }
+
+ [Test ()]
+ public void MemberSignature_Updating_Existing_NameChanged_MultiFX ()
+ {
+ // handles the case
+ var context = InitContext<MyClass> (SigRegular, 2, forceAlignment: false);
+
+ Func<int, FrameworkTypeEntry> typeEntry = i => context.fx.Frameworks[i].Types.First ();
+
+ var sig = new CSharpMemberFormatter ();
+ MDocUpdater.UpdateSignature (sig, context.method, context.doc.FirstChild as XmlElement, typeEntry(0), fxAlternateTriggered: true);
+ MDocUpdater.UpdateSignature (sig, context.method, context.doc.FirstChild as XmlElement, typeEntry(1), fxAlternateTriggered: false);
+ MDocUpdater.UpdateSignature (sig, context.method, context.doc.FirstChild as XmlElement, typeEntry(2), fxAlternateTriggered: false);
+
+ var afterXML = context.doc.OuterXml;
+
+ Assert.AreEqual (Normalize (SigRegularAllAligned), Normalize (afterXML));
+
+ }
+
+ [Test ()]
+ public void DocMemberEnumerator()
+ {
+ var context = InitContext <MyClass>(string.Format (typeFrameXml, multiFrameworkXml), 1, forceAlignment: true);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[1].Types.First ();
+
+ var enumerator = new DocumentationEnumerator ();
+ var matches = enumerator.GetDocumentationMembers (context.doc, context.method.DeclaringType.Resolve (), typeEntry);
+
+ Assert.IsTrue (matches.Any (m => m.Member == context.method && m.Node != null), "didn't match the member");
+ }
+
+ [Test ()]
+ public void DocMemberEnumerator2 ()
+ {
+ var context = InitContext <MyClass>(string.Format (typeFrameXml, multiFrameworkXml), 2, forceAlignment: true);
+
+ FrameworkTypeEntry typeEntry = context.fx.Frameworks[2].Types.First ();
+
+ var enumerator = new DocumentationEnumerator ();
+ var matches = enumerator.GetDocumentationMembers (context.doc, context.method.DeclaringType.Resolve (), typeEntry);
+
+ Assert.IsTrue (matches.Any (m => m.Member == context.method && m.Node != null), "didn't match the member");
+ }
+
+ string Normalize(string xml) {
+ XmlDocument doc = new XmlDocument ();
+
+ doc.LoadXml (xml);
+ return doc.OuterXml;
+ }
+ string typeFrameXml = @"<Type><Members>{0}</Members></Type>";
+
+ #region MyClass XML
+ string startingEmptyXml = @"<Member MemberName=""Meth"">
+ <MemberType>Method</MemberType>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ </Parameters>
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>";
+ string normalSingleXml = @"<Member MemberName=""Meth"">
+ <MemberType>Method</MemberType>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name = ""a"" Type=""System.Int32"" />
+ <Parameter Name = ""d"" Type=""System.String"" />
+ <Parameter Name = ""c"" Type=""System.Int32"" />
+ </Parameters>
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>";
+
+ string multiFrameworkXml = @"<Member MemberName=""Meth"">
+ <MemberType>Method</MemberType>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name = ""a"" Type=""System.Int32"" Index=""0"" />
+ <Parameter Name = ""d"" Type=""System.String"" Index=""1"" FrameworkAlternate=""One;Three"" />
+ <Parameter Name = ""b"" Type=""System.String"" Index=""1"" FrameworkAlternate=""Two"" />
+ <Parameter Name = ""c"" Type=""System.Int32"" Index=""2"" />
+ </Parameters>
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>";
+
+ string multiFrameworkAligned = @"<Member MemberName=""Meth"">
+ <MemberType>Method</MemberType>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name = ""a"" Type=""System.Int32"" Index=""0"" />
+ <Parameter Name = ""d"" Type=""System.String"" Index=""1"" FrameworkAlternate=""One;Three;Two"" />
+ <Parameter Name = ""c"" Type=""System.Int32"" Index=""2"" />
+ </Parameters>
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>";
+ #endregion
+
+ #region MyClass2 XML
+
+ string normalSingleXml2 = @"<Member MemberName=""Meth"">
+ <MemberType>Method</MemberType>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name = ""a"" Type=""System.Int32"" />
+ <Parameter Name = ""b"" Type=""System.String"" />
+ <Parameter Name = ""c"" Type=""System.Int32"" />
+ </Parameters>
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>";
+
+ string multiFrameworkXml2_Second = @"<Member MemberName=""Meth"">
+ <MemberType>Method</MemberType>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name = ""a"" Type=""System.Int32"" Index=""0"" FrameworkAlternate=""One"" />
+ <Parameter Name = ""d"" Type=""System.Int32"" Index=""0"" FrameworkAlternate=""Three"" />
+ <Parameter Name = ""b"" Type=""System.String"" Index=""1"" FrameworkAlternate=""One"" />
+ <Parameter Name = ""e"" Type=""System.String"" Index=""1"" FrameworkAlternate=""Three"" />
+ <Parameter Name = ""c"" Type=""System.Int32"" Index=""2"" FrameworkAlternate=""One"" />
+ <Parameter Name = ""f"" Type=""System.Int32"" Index=""2"" FrameworkAlternate=""Three"" />
+ </Parameters>
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>";
+
+ string multiFrameworkXml2 = @"<Member MemberName=""Meth"">
+ <MemberType>Method</MemberType>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name = ""a"" Type=""System.Int32"" Index=""0"" FrameworkAlternate=""One;Two"" />
+ <Parameter Name = ""d"" Type=""System.Int32"" Index=""0"" FrameworkAlternate=""Three"" />
+ <Parameter Name = ""b"" Type=""System.String"" Index=""1"" FrameworkAlternate=""One;Two"" />
+ <Parameter Name = ""e"" Type=""System.String"" Index=""1"" FrameworkAlternate=""Three"" />
+ <Parameter Name = ""c"" Type=""System.Int32"" Index=""2"" FrameworkAlternate=""One;Two"" />
+ <Parameter Name = ""f"" Type=""System.Int32"" Index=""2"" FrameworkAlternate=""Three"" />
+ </Parameters>
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>";
+
+ string multiFrameworkAligned2 = @"<Member MemberName=""Meth"">
+ <MemberType>Method</MemberType>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name = ""a"" Type=""System.Int32"" Index=""0"" FrameworkAlternate=""One;Two;Three"" />
+ <Parameter Name = ""b"" Type=""System.String"" Index=""1"" FrameworkAlternate=""One;Two;Three"" />
+ <Parameter Name = ""c"" Type=""System.Int32"" Index=""2"" FrameworkAlternate=""One;Two;Three"" />
+ </Parameters>
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>";
+
+ string multiFrameworkAlignedOther = @"<Member MemberName=""Meth"">
+ <MemberType>Method</MemberType>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name = ""d"" Type=""System.Int32"" Index=""0"" FrameworkAlternate=""One;Three;Two"" />
+ <Parameter Name = ""e"" Type=""System.String"" Index=""1"" FrameworkAlternate=""One;Three;Two"" />
+ <Parameter Name = ""f"" Type=""System.Int32"" Index=""2"" FrameworkAlternate=""One;Three;Two"" />
+ </Parameters>
+ <Docs>
+ <summary>To be added.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>";
+
+ #endregion
+
+ string SigmultiFrameworkXml = @"<Member MemberName=""Meth"">
+ <MemberSignature Language=""C#"" Value=""public void Meth (int a, string d, int c);"" FrameworkAlternate=""One;Three"" />
+ <MemberSignature Language=""C#"" Value=""public void Meth (int a, string b, int c);"" FrameworkAlternate=""Two"" />
+
+ </Member>";
+
+ string SigmultiFrameworkAligned = @"<Member MemberName=""Meth"">
+ <MemberSignature Language=""C#"" Value=""public void Meth (int a, string d, int c);"" FrameworkAlternate=""One;Three;Two"" />
+
+ </Member>";
+
+ string SigRegular = @"<Member MemberName=""Meth"">
+ <MemberSignature Language=""C#"" Value=""public void Meth (int a, string d, int c);"" />
+ </Member>";
+ string SigRegularChanged = @"<Member MemberName=""Meth"">
+ <MemberSignature Language=""C#"" Value=""public void Meth (int a, string b, int c);"" />
+ </Member>";
+ string SigRegularAllAligned = @"<Member MemberName=""Meth"">
+ <MemberSignature Language=""C#"" Value=""public void Meth (int a, string b, int c);"" FrameworkAlternate=""One;Three;Two"" />
+ </Member>";
+
+
+
+ private ParamContext InitContext <T>(string methodXml, int fxIndex, bool forceAlignment=false)
+ {
+ Func<int, bool> indexCheck = fi => fi < 2;
+ if (typeof(T) == typeof(MyClass2))
+ indexCheck = fi => fi != 1;
+
+ bool useFirst = forceAlignment || indexCheck(fxIndex);
+ var doc = new XmlDocument ();
+ //doc.PreserveWhitespace = true;
+ doc.LoadXml (methodXml);
+ var beforeXML = doc.OuterXml;
+ XmlElement root = doc.SelectSingleNode ("//Docs") as XmlElement; // Docs
+
+ TypeDefinition type = GetDefinition<T> ("mdoc.Test");
+ var method = type.Methods.First (m => m.Name == "Meth") as MethodReference;
+ var parameters = method.Parameters.ToList ();
+ TypeDefinition type2 = GetDefinition<T> ("mdoc.Test2");
+ var method2 = type2.Methods.First (m => m.Name == "Meth") as MethodReference;
+ var parameters2 = method2.Parameters.ToList ();
+
+ // updater
+ var updater = new MDocUpdater ();
+ var fx = new FrameworkIndex ("");
+ fx.Frameworks.Add (new FrameworkEntry (fx.Frameworks) { Id = "One", Name = "One", Replace="mdoc.Test2", With="mdoc.Test" });
+ fx.Frameworks.Add (new FrameworkEntry (fx.Frameworks) { Id = "Three", Name = "Three", Replace = "mdoc.Test2", With = "mdoc.Test" });
+ fx.Frameworks.Add (new FrameworkEntry (fx.Frameworks) { Id = "Two", Name = "Two", Replace = "mdoc.Test2", With = "mdoc.Test" });
+
+ var i = 0;
+ foreach (var f in fx.Frameworks)
+ {
+ if (indexCheck(i) || forceAlignment)
+ {
+ var t = f.ProcessType (type);
+ t.ProcessMember (method);
+ }
+ else {
+ var t = f.ProcessType (type2);
+ t.ProcessMember (method2);
+ }
+ i++;
+ }
+
+ updater.InitializeFrameworksCache (fx);
+
+ return new ParamContext ()
+ {
+ doc = doc,
+ beforeXML = beforeXML,
+ method = useFirst ? method : method2,
+ parameters = useFirst ? parameters : parameters2,
+ fx = fx,
+ updater = updater
+ };
+ }
+
+ TypeDefinition GetDefinition<T>(string ns)
+ {
+ Type t = typeof (T);
+ string path = t.Assembly.Location;
+ AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly (path);
+ return assembly.MainModule.Types.First (type =>
+ type.Name == t.Name && type.Namespace == ns);
+ }
+ }
+}
diff --git a/mdoc/mdoc.Test/mdoc.Test.csproj b/mdoc/mdoc.Test/mdoc.Test.csproj
index 4792d11b..5901cc46 100644
--- a/mdoc/mdoc.Test/mdoc.Test.csproj
+++ b/mdoc/mdoc.Test/mdoc.Test.csproj
@@ -58,6 +58,8 @@
<Reference Include="Windows.Foundation.UniversalApiContract">
<HintPath>..\..\external\Windows\Windows.Foundation.UniversalApiContract.winmd</HintPath>
</Reference>
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<Compile Include="BasicFormatterTests.cs" />
@@ -86,6 +88,8 @@
<Compile Include="SampleClasses\SomeStruct.cs" />
<Compile Include="SampleClasses\WebHostHiddenAttribute.cs" />
<Compile Include="VBFormatterTests.cs" />
+ <Compile Include="FrameworkAlternateTests.cs" />
+ <Compile Include="XmlUpdateTests.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
diff --git a/mdoc/mdoc.csproj b/mdoc/mdoc.csproj
index 3f97ce16..b7a43151 100644
--- a/mdoc/mdoc.csproj
+++ b/mdoc/mdoc.csproj
@@ -132,6 +132,8 @@
<Compile Include="Mono.Documentation\Updater\Frameworks\AssemblySet.cs" />
<Compile Include="Mono.Documentation\Updater\Frameworks\MDocResolver.cs" />
<Compile Include="Mono.Documentation\MDocUpdater.cs" />
+ <Compile Include="Mono.Documentation\Updater\Frameworks\FXUtils.cs" />
+ <Compile Include="GlobalSuppressions.cs" />
<Compile Include="Mono.Documentation\Updater\Frameworks\MDocMetadataResolver.cs" />
</ItemGroup>
<ItemGroup>