95fdb59ea6
Former-commit-id: b39a328747c2f3414dc52e009fb6f0aa80ca2492
270 lines
12 KiB
C#
270 lines
12 KiB
C#
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 (Consts.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 (Consts.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 (Consts.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 (Consts.FrameworkAlternate);
|
||
}
|
||
else
|
||
{
|
||
a.Element.SetAttribute (Consts.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
|
||
*/
|
||
}
|
||
|
||
|
||
|
||
|
||
}
|
||
}
|