diff options
author | Joel Martinez <joelmartinez@gmail.com> | 2018-03-19 23:50:15 +0300 |
---|---|---|
committer | Joel Martinez <joelmartinez@gmail.com> | 2018-03-20 00:17:53 +0300 |
commit | 5e2012309f32b9ab42825c24e6641fe33c73ab55 (patch) | |
tree | 340bacfa935e186ba8ad12a5e1dba06cffd0a2d3 | |
parent | 9a8af0960234d808c9e682ad26601a5979b2b062 (diff) |
mdoc: parameters and member signatures now use FrameworkAlternate when different
Resolves #116
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>
|