예제 #1
0
        public XmlClassGen(XElement pkg, XElement elem)
            : base(new XmlGenBaseSupport(pkg, elem))              //FIXME: should not be xml specific
        {
            is_abstract = elem.XGetAttribute("abstract") == "true";
            is_final    = elem.XGetAttribute("final") == "true";
            base_type   = elem.XGetAttribute("extends");
            foreach (var child in elem.Elements())
            {
                switch (child.Name.LocalName)
                {
                case "implements":
                    string iname = child.XGetAttribute("name-generic-aware");
                    iname = iname.Length > 0 ? iname : child.XGetAttribute("name");
                    AddInterface(iname);
                    break;

                case "method":
                    var synthetic = child.XGetAttribute("synthetic") == "true";
                    var finalizer = child.XGetAttribute("name") == "finalize" &&
                                    child.XGetAttribute("jni-signature") == "()V";
                    if (!(synthetic || finalizer))
                    {
                        AddMethod(new XmlMethod(this, child));
                    }
                    break;

                case "constructor":
                    Ctors.Add(new XmlCtor(this, child));
                    break;

                case "field":
                    AddField(new XmlField(child));
                    break;

                case "typeParameters":
                    break;                     // handled at GenBaseSupport

                default:
                    Report.Warning(0, Report.WarningClassGen + 1, "unexpected class child {0}.", child.Name);
                    break;
                }
            }
        }
예제 #2
0
        public static ClassGen CreateClass(XElement pkg, XElement elem)
        {
            var klass = new ClassGen(CreateGenBaseSupport(pkg, elem, false))
            {
                BaseType   = elem.XGetAttribute("extends"),
                FromXml    = true,
                IsAbstract = elem.XGetAttribute("abstract") == "true",
                IsFinal    = elem.XGetAttribute("final") == "true"
            };

            foreach (var child in elem.Elements())
            {
                switch (child.Name.LocalName)
                {
                case "implements":
                    var iname = child.XGetAttribute("name-generic-aware");
                    iname = iname.Length > 0 ? iname : child.XGetAttribute("name");
                    klass.AddImplementedInterface(iname);
                    break;

                case "method":
                    klass.AddMethod(CreateMethod(klass, child));
                    break;

                case "constructor":
                    klass.Ctors.Add(CreateCtor(klass, child));
                    break;

                case "field":
                    klass.AddField(CreateField(child));
                    break;

                case "typeParameters":
                    break;                             // handled at GenBaseSupport

                default:
                    Report.Warning(0, Report.WarningClassGen + 1, "unexpected class child {0}.", child.Name);
                    break;
                }
            }

            return(klass);
        }
예제 #3
0
        public XmlCtor(GenBase declaringType, XmlElement elem) : base(declaringType, new XmlMethodBaseSupport(elem))
        {
            name = elem.XGetAttribute("name");
            int idx = name.LastIndexOf('.');

            if (idx > 0)
            {
                name = name.Substring(idx + 1);
            }
            // If 'elem' is a constructor for a non-static nested type, then
            // the type of the containing class must be inserted as the first
            // argument
            nonStaticNestedType = idx > 0 && elem.ParentNode.Attributes ["static"].Value == "false";
            if (nonStaticNestedType)
            {
                string     declName = elem.ParentNode.Attributes ["name"].Value;
                string     expectedEnclosingName = declName.Substring(0, idx);
                XmlElement enclosingType         = GetPreviousClass(elem.ParentNode.PreviousSibling, expectedEnclosingName);
                if (enclosingType == null)
                {
                    missing_enclosing_class = true;
                    Report.Warning(0, Report.WarningCtor + 0, "For {0}, could not find enclosing type '{1}'.", name, expectedEnclosingName);
                }
                else
                {
                    Parameters.AddFirst(Parameter.FromClassElement(enclosingType));
                }
            }

            foreach (XmlNode child in elem.ChildNodes)
            {
                if (child.Name == "parameter")
                {
                    Parameters.Add(Parameter.FromElement(child as XmlElement));
                }
            }

            if (elem.HasAttribute("customAttributes"))
            {
                custom_attributes = elem.GetAttribute("customAttributes");
            }
        }
예제 #4
0
        public static InterfaceGen CreateInterface(XElement pkg, XElement elem, CodeGenerationOptions options)
        {
            var iface = new InterfaceGen(CreateGenBaseSupport(pkg, elem, true))
            {
                ArgsType       = elem.XGetAttribute("argsType"),
                HasManagedName = elem.Attribute("managedName") != null,
                NoAlternatives = elem.XGetAttribute("no-alternatives") == "true",
                // Only use an explicitly set XML attribute
                Unnest = elem.XGetAttribute("unnest") == "true" ? true :
                         elem.XGetAttribute("unnest") == "false" ? false :
                         !options.SupportNestedInterfaceTypes
            };

            foreach (var child in elem.Elements())
            {
                switch (child.Name.LocalName)
                {
                case "implements":
                    string iname = child.XGetAttribute("name-generic-aware");
                    iname = iname.Length > 0 ? iname : child.XGetAttribute("name");
                    iface.AddImplementedInterface(iname);
                    break;

                case "method":
                    iface.AddMethod(CreateMethod(iface, child));
                    break;

                case "field":
                    iface.AddField(CreateField(child));
                    break;

                case "typeParameters":
                    break;                             // handled at GenBaseSupport

                default:
                    Report.Warning(0, Report.WarningInterfaceGen + 0, "unexpected interface child {0}.", child);
                    break;
                }
            }

            return(iface);
        }
예제 #5
0
        public XmlInterfaceGen(XmlElement pkg, XmlElement elem)
            : base(new InterfaceXmlGenBaseSupport(pkg, elem))
        {
            hasManagedName = elem.HasAttribute("managedName");
            args_type      = elem.XGetAttribute("argsType");
            foreach (XmlNode node in elem.ChildNodes)
            {
                XmlElement child = node as XmlElement;
                if (child == null)
                {
                    continue;
                }

                switch (node.Name)
                {
                case "implements":
                    string iname = child.XGetAttribute("name-generic-aware");
                    iname = iname.Length > 0 ? iname : child.XGetAttribute("name");
                    AddInterface(iname);
                    break;

                case "method":
                    if (child.GetAttribute("synthetic") != "true")
                    {
                        AddMethod(new XmlMethod(this, child));
                    }
                    break;

                case "field":
                    AddField(new XmlField(child));
                    break;

                case "typeParameters":
                    break;                     // handled at GenBaseSupport

                default:
                    Report.Warning(0, Report.WarningInterfaceGen + 0, "unexpected interface child {0}.", node.Name);
                    break;
                }
            }
        }
예제 #6
0
        public bool Validate(CodeGenerationOptions opt, GenericParameterDefinitionList type_params)
        {
            symbol = SymbolTable.Lookup(TypeName, type_params);

            if (symbol == null || !symbol.Validate(opt, type_params))
            {
                Report.Warning(0, Report.WarningField + 0, "unexpected field type {0} {1}.", TypeName, opt.ContextString);
                return(false);
            }

            setParameters = new ParameterList()
            {
                SetterParameter,
            };
            if (!setParameters.Validate(opt, type_params))
            {
                throw new NotSupportedException(
                          string.Format("Unable to generate setter parameter list {0}", opt.ContextString));
            }

            return(true);
        }
예제 #7
0
        public static InterfaceGen CreateInterface(XElement pkg, XElement elem)
        {
            var iface = new InterfaceGen(CreateGenBaseSupport(pkg, elem, true))
            {
                ArgsType       = elem.XGetAttribute("argsType"),
                HasManagedName = elem.Attribute("managedName") != null
            };

            foreach (var child in elem.Elements())
            {
                switch (child.Name.LocalName)
                {
                case "implements":
                    string iname = child.XGetAttribute("name-generic-aware");
                    iname = iname.Length > 0 ? iname : child.XGetAttribute("name");
                    iface.AddImplementedInterface(iname);
                    break;

                case "method":
                    iface.AddMethod(CreateMethod(iface, child));
                    break;

                case "field":
                    iface.AddField(CreateField(child));
                    break;

                case "typeParameters":
                    break;                             // handled at GenBaseSupport

                default:
                    Report.Warning(0, Report.WarningInterfaceGen + 0, "unexpected interface child {0}.", child);
                    break;
                }
            }

            return(iface);
        }
예제 #8
0
        protected override bool OnValidate(CodeGenerationOptions opt, GenericParameterDefinitionList type_params)
        {
            if (validated)
            {
                return(is_valid);
            }

            validated = true;

            // Due to demand to validate in prior to validate ClassGen's BaseType, it is *not* done at
            // GenBase.
            if (TypeParameters != null && !TypeParameters.Validate(opt, type_params))
            {
                return(false);
            }

            if (!base.OnValidate(opt, type_params) || iface_validation_failed || MethodValidationFailed)
            {
                if (iface_validation_failed)
                {
                    Report.Warning(0, Report.WarningInterfaceGen + 2, "Invalidating {0} and all nested types because some of its interfaces were invalid.", FullName);
                }
                else if (MethodValidationFailed)
                {
                    Report.Warning(0, Report.WarningInterfaceGen + 3, "Invalidating {0} and all nested types because some of its methods were invalid.", FullName);
                }
                foreach (GenBase nest in NestedTypes)
                {
                    nest.Invalidate();
                }
                is_valid = false;
                return(false);
            }

            return(true);
        }
예제 #9
0
        protected virtual bool OnValidate(CodeGenerationOptions opt, GenericParameterDefinitionList type_params)
        {
            if (Name.Length > TypeNamePrefix.Length &&
                (Name [TypeNamePrefix.Length] == '.' || Char.IsDigit(Name [TypeNamePrefix.Length])))              // see bug #5111
            {
                return(false);
            }

            if (!support.ValidateNamespace())
            {
                return(false);
            }

            List <GenBase> valid_nests = new List <GenBase> ();

            foreach (GenBase gen in nested_types)
            {
                if (gen.Validate(opt, TypeParameters))
                {
                    valid_nests.Add(gen);
                }
            }
            nested_types = valid_nests;

            AdjustNestedTypeFullName(this);

            foreach (string iface_name in iface_names)
            {
                ISymbol isym = SymbolTable.Lookup(iface_name);
                if (isym != null && isym.Validate(opt, TypeParameters))
                {
                    ifaces.Add(isym);
                }
                else
                {
                    if (isym == null)
                    {
                        Report.Warning(0, Report.WarningGenBase + 0, "For type {0}, base interface {1} does not exist.", FullName, iface_name);
                    }
                    else
                    {
                        Report.Warning(0, Report.WarningGenBase + 0, "For type {0}, base interface {1} is invalid.", FullName, iface_name);
                    }
                    iface_validation_failed = true;
                }
            }

            List <Field> valid_fields = new List <Field> ();

            foreach (Field f in fields)
            {
                if (!f.Validate(opt, TypeParameters))
                {
                    continue;
                }
                valid_fields.Add(f);
            }
            fields = valid_fields;

            int method_cnt = methods.Count;

            methods = methods.Where(m => ValidateMethod(opt, m)).ToList();
            method_validation_failed = method_cnt != methods.Count;
            foreach (Method m in methods)
            {
                if (m.IsVirtual)
                {
                    has_virtual_methods = true;
                }
                if (m.Name == "HashCode" && m.Parameters.Count == 0)
                {
                    m.IsOverride = true;
                    m.Name       = "GetHashCode";
                }
                jni_sig_hash [m.JavaName + m.JniSignature] = m;
                if ((m.Name == "ToString" && m.Parameters.Count == 0) || (BaseSymbol != null && BaseSymbol.ContainsMethod(m, true)))
                {
                    m.IsOverride = true;
                }
            }
            return(true);
        }
예제 #10
0
        void Process(XDocument meta_doc, string apiLevelString, int productVersion)
        {
            int apiLevel = 0;

            int.TryParse(apiLevelString, out apiLevel);

            var      metadataChildren = meta_doc.XPathSelectElements("/metadata/*");
            string   prev_path        = null;
            XElement attr_last_cache  = null;

            foreach (var metaitem in metadataChildren)
            {
                if (ShouldSkip(metaitem, apiLevel, productVersion))
                {
                    continue;
                }
                if (!ShouldApply(metaitem))
                {
                    continue;
                }
                string path = metaitem.XGetAttribute("path");
                if (path != prev_path)
                {
                    attr_last_cache = null;
                }
                prev_path = path;

                switch (metaitem.Name.LocalName)
                {
                case "remove-node":
                    try {
                        var nodes = api_doc.XPathSelectElements(path).ToArray();
                        if (nodes.Any())
                        {
                            foreach (var node in nodes)
                            {
                                node.Remove();
                            }
                        }
                        else
                        {
                            // BG8A00
                            Report.Warning(0, Report.WarningApiFixup + 0, null, metaitem, "<remove-node path=\"{0}\"/> matched no nodes.", path);
                        }
                    } catch (XPathException e) {
                        // BG4A01
                        Report.Error(Report.ErrorApiFixup + 1, e, metaitem, "Invalid XPath specification: {0}", path);
                    }
                    break;

                case "add-node":
                    try {
                        var  nodes   = api_doc.XPathSelectElements(path);
                        bool matched = false;
                        if (!nodes.Any())
                        {
                            // BG8A01
                            Report.Warning(0, Report.WarningApiFixup + 1, null, metaitem, "<add-node path=\"{0}\"/> matched no nodes.", path);
                        }
                        else
                        {
                            foreach (var node in nodes)
                            {
                                node.Add(metaitem.Nodes());
                            }
                            matched = true;
                        }
                    } catch (XPathException e) {
                        // BG4A02
                        Report.Error(Report.ErrorApiFixup + 2, e, metaitem, "Invalid XPath specification: {0}", path);
                    }
                    break;

                case "change-node":
                    try {
                        var  nodes   = api_doc.XPathSelectElements(path);
                        bool matched = false;
                        foreach (var node in nodes)
                        {
                            var newChild = new XElement(metaitem.Value);
                            newChild.Add(node.Attributes());
                            newChild.Add(node.Nodes());
                            node.ReplaceWith(newChild);
                            matched = true;
                        }

                        if (!matched)
                        {
                            // BG8A03
                            Report.Warning(0, Report.WarningApiFixup + 3, null, metaitem, "<change-node-type path=\"{0}\"/> matched no nodes.", path);
                        }
                    } catch (XPathException e) {
                        // BG4A03
                        Report.Error(Report.ErrorApiFixup + 3, e, metaitem, "Invalid XPath specification: {0}", path);
                    }
                    break;

                case "attr":
                    try {
                        string attr_name = metaitem.XGetAttribute("name");
                        if (string.IsNullOrEmpty(attr_name))
                        {
                            // BG4A07
                            Report.Error(Report.ErrorApiFixup + 7, null, metaitem, "Target attribute name is not specified for path: {0}", path);
                        }
                        var nodes        = attr_last_cache != null ? new XElement [] { attr_last_cache } : api_doc.XPathSelectElements(path);
                        int attr_matched = 0;
                        foreach (var n in nodes)
                        {
                            n.SetAttributeValue(attr_name, metaitem.Value);
                            attr_matched++;
                        }
                        if (attr_matched == 0)
                        {
                            // BG8A04
                            Report.Warning(0, Report.WarningApiFixup + 4, null, metaitem, "<attr path=\"{0}\"/> matched no nodes.", path);
                        }
                        if (attr_matched != 1)
                        {
                            attr_last_cache = null;
                        }
                    } catch (XPathException e) {
                        // BG4A04
                        Report.Error(Report.ErrorApiFixup + 4, e, metaitem, "Invalid XPath specification: {0}", path);
                    }
                    break;

                case "move-node":
                    try {
                        string parent  = metaitem.Value;
                        var    parents = api_doc.XPathSelectElements(parent);
                        bool   matched = false;
                        foreach (var parent_node in parents)
                        {
                            var nodes = parent_node.XPathSelectElements(path).ToArray();
                            foreach (var node in nodes)
                            {
                                node.Remove();
                            }
                            parent_node.Add(nodes);
                            matched = true;
                        }
                        if (!matched)
                        {
                            // BG8A05
                            Report.Warning(0, Report.WarningApiFixup + 5, null, metaitem, "<move-node path=\"{0}\"/> matched no nodes.", path);
                        }
                    } catch (XPathException e) {
                        // BG4A05
                        Report.Error(Report.ErrorApiFixup + 5, e, metaitem, "Invalid XPath specification: {0}", path);
                    }
                    break;

                case "remove-attr":
                    try {
                        string name    = metaitem.XGetAttribute("name");
                        var    nodes   = api_doc.XPathSelectElements(path);
                        bool   matched = false;

                        foreach (var node in nodes)
                        {
                            node.RemoveAttributes();
                            matched = true;
                        }

                        if (!matched)
                        {
                            // BG8A06
                            Report.Warning(0, Report.WarningApiFixup + 6, null, metaitem, "<remove-attr path=\"{0}\"/> matched no nodes.", path);
                        }
                    } catch (XPathException e) {
                        // BG4A06
                        Report.Error(Report.ErrorApiFixup + 6, e, metaitem, "Invalid XPath specification: {0}", path);
                    }
                    break;
                }
            }
        }
예제 #11
0
        public void GenerateEventsOrPropertiesForListener(StreamWriter sw, string indent, CodeGenerationOptions opt, ClassGen target)
        {
            var methods      = target.Methods.Concat(target.Properties.Where(p => p.Setter != null).Select(p => p.Setter));
            var props        = new HashSet <string> ();
            var refs         = new HashSet <string> ();
            var eventMethods = methods.Where(m => m.IsListenerConnector && m.EventName != String.Empty && m.ListenerType == this).Distinct();

            foreach (var method in eventMethods)
            {
                string name = method.CalculateEventName(target.ContainsName);
                if (String.IsNullOrEmpty(name))
                {
                    Report.Warning(0, Report.WarningInterfaceGen + 1, "empty event name in {0}.{1}.", FullName, method.Name);
                    continue;
                }
                if (opt.GetSafeIdentifier(name) != name)
                {
                    Report.Warning(0, Report.WarningInterfaceGen + 4, "event name for {0}.{1} is invalid. `eventName' or `argsType` can be used to assign a valid member name.", FullName, method.Name);
                    continue;
                }
                var prop = target.Properties.FirstOrDefault(p => p.Setter == method);
                if (prop != null)
                {
                    string setter = "__Set" + prop.Name;
                    props.Add(prop.Name);
                    refs.Add(setter);
                    GenerateEventOrProperty(sw, indent, target, opt, name, setter,
                                            string.Format("__v => {0} = __v", prop.Name),
                                            string.Format("__v => {0} = null", prop.Name));
                }
                else
                {
                    refs.Add(method.Name);
                    string rm = null;
                    string remove;
                    if (method.Name.StartsWith("Set"))
                    {
                        remove = string.Format("__v => {0} (null)", method.Name);
                    }
                    else if (method.Name.StartsWith("Add") &&
                             (rm = "Remove" + method.Name.Substring("Add".Length)) != null &&
                             methods.Where(m => m.Name == rm).Any())
                    {
                        remove = string.Format("__v => {0} (__v)", rm);
                    }
                    else
                    {
                        remove = string.Format("__v => {{throw new NotSupportedException (\"Cannot unregister from {0}.{1}\");}}",
                                               FullName, method.Name);
                    }
                    GenerateEventOrProperty(sw, indent, target, opt, name, method.Name,
                                            method.Name,
                                            remove);
                }
            }

            foreach (var r in refs)
            {
                sw.WriteLine("{0}WeakReference weak_implementor_{1};", indent, r);
            }
            sw.WriteLine();
            sw.WriteLine("{0}{1}Implementor __Create{2}Implementor ()", indent, opt.GetOutputName(FullName), Name);
            sw.WriteLine("{0}{{", indent);
            sw.WriteLine("{0}\treturn new {1}Implementor ({2});", indent, opt.GetOutputName(FullName),
                         NeedsSender ? "this" : "");
            sw.WriteLine("{0}}}", indent);
        }
예제 #12
0
        List <GenBase> ParsePackage(XElement ns, Predicate <XElement> p)
        {
            List <GenBase> result = new List <GenBase> ();
            Dictionary <string, GenBase> nested  = new Dictionary <string, GenBase> ();
            Dictionary <string, GenBase> by_name = new Dictionary <string, GenBase> ();

            foreach (var elem in ns.Elements())
            {
                string  name = elem.XGetAttribute("name");
                GenBase gen  = null;
                switch (elem.Name.LocalName)
                {
                case "class":
                    if (elem.XGetAttribute("obfuscated") == "true")
                    {
                        continue;
                    }
                    gen = XmlApiImporter.CreateClass(ns, elem, opt);
                    break;

                case "interface":
                    if (elem.XGetAttribute("obfuscated") == "true")
                    {
                        continue;
                    }
                    gen = XmlApiImporter.CreateInterface(ns, elem, opt);
                    break;

                default:
                    Report.Warning(0, Report.WarningParser + 3, "Unexpected node in package element: {0}.", elem.Name);
                    break;
                }

                if (gen == null)
                {
                    continue;
                }
                int idx = name.IndexOf('<');
                if (idx > 0)
                {
                    name = name.Substring(0, idx);
                }
                by_name [name] = gen;
                if (name.IndexOf('.') > 0)
                {
                    nested [name] = gen;
                }
                else
                {
                    result.Add(gen);
                }
            }

            foreach (string name in nested.Keys)
            {
                string top_ancestor = name.Substring(0, name.IndexOf('.'));
                if (by_name.ContainsKey(top_ancestor))
                {
                    by_name [top_ancestor].AddNestedType(nested [name]);
                }
                else
                {
                    Report.Warning(0, Report.WarningParser + 4, "top ancestor {0} not found for nested type {1}.", top_ancestor, nested [name].FullName);
                    nested [name].Invalidate();
                }
            }
            return(result);
        }
예제 #13
0
        void Process(XmlDocument meta_doc, string apiLevelString, int productVersion)
        {
            XPathNavigator api_nav  = api_doc.CreateNavigator();
            XPathNavigator meta_nav = meta_doc.CreateNavigator();
            int            apiLevel = 0;

            int.TryParse(apiLevelString, out apiLevel);

            XPathNodeIterator metadata        = meta_nav.Select("/metadata/*");
            string            prev_path       = null;
            XPathNavigator    attr_last_cache = null;

            while (metadata.MoveNext())
            {
                var metanav = metadata.Current;
                if (ShouldSkip(metanav, apiLevel, productVersion))
                {
                    continue;
                }
                if (!ShouldApply(metanav))
                {
                    continue;
                }
                string path = metanav.XGetAttribute("path", "");
                if (path != prev_path)
                {
                    attr_last_cache = null;
                }
                prev_path = path;

                switch (metanav.LocalName)
                {
                case "remove-node":
                    try {
                        XPathNodeIterator api_iter = api_nav.Select(path);
                        List <XmlElement> matches  = new List <XmlElement> ();
                        while (api_iter.MoveNext())
                        {
                            matches.Add(((IHasXmlNode)api_iter.Current).GetNode() as XmlElement);
                        }
                        foreach (XmlElement api_node in matches)
                        {
                            api_node.ParentNode.RemoveChild(api_node);
                        }
                        if (matches.Count == 0)
                        {
                            // BG8A00
                            Report.Warning(0, Report.WarningApiFixup + 0, "<remove-node path=\"{0}\"/> matched no nodes.", path);
                        }
                    } catch (XPathException e) {
                        // BG4A01
                        Report.Error(Report.ErrorApiFixup + 1, e, "Invalid XPath specification: {0}", path);
                    }
                    break;

                case "add-node":
                    try {
                        XPathNodeIterator api_iter = api_nav.Select(path);
                        bool matched = false;
                        while (api_iter.MoveNext())
                        {
                            XmlElement api_node = ((IHasXmlNode)api_iter.Current).GetNode() as XmlElement;
                            foreach (XmlNode child in ((IHasXmlNode)metanav).GetNode().ChildNodes)
                            {
                                api_node.AppendChild(api_doc.ImportNode(child, true));
                            }
                            matched = true;
                        }
                        if (!matched)
                        {
                            // BG8A01
                            Report.Warning(0, Report.WarningApiFixup + 1, "<add-node path=\"{0}\"/> matched no nodes.", path);
                        }
                    } catch (XPathException e) {
                        // BG4A02
                        Report.Error(Report.ErrorApiFixup + 2, e, "Invalid XPath specification: {0}", path);
                    }
                    break;

                case "change-node":
                    try {
                        XPathNodeIterator api_iter = api_nav.Select(path);
                        bool matched = false;
                        while (api_iter.MoveNext())
                        {
                            XmlElement node     = ((IHasXmlNode)api_iter.Current).GetNode() as XmlElement;
                            XmlElement parent   = node.ParentNode as XmlElement;
                            XmlElement new_node = api_doc.CreateElement(metanav.Value);

                            foreach (XmlNode child in node.ChildNodes)
                            {
                                new_node.AppendChild(child.Clone());
                            }
                            foreach (XmlAttribute attribute in node.Attributes)
                            {
                                new_node.Attributes.Append((XmlAttribute)attribute.Clone());
                            }

                            parent.ReplaceChild(new_node, node);
                            matched = true;
                        }

                        if (!matched)
                        {
                            // BG8A03
                            Report.Warning(0, Report.WarningApiFixup + 3, "<change-node-type path=\"{0}\"/> matched no nodes.", path);
                        }
                    } catch (XPathException e) {
                        // BG4A03
                        Report.Error(Report.ErrorApiFixup + 3, e, "Invalid XPath specification: {0}", path);
                    }
                    break;

                case "attr":
                    try {
                        string attr_name = metanav.XGetAttribute("name", "");
                        if (string.IsNullOrEmpty(attr_name))
                        {
                            // BG4A07
                            Report.Error(Report.ErrorApiFixup + 7, "Target attribute name is not specified for path: {0}", path);
                        }
                        var nodes = attr_last_cache != null ?
                                    (IEnumerable <XPathNavigator>) new XPathNavigator [] { attr_last_cache } :
                        api_nav.Select(path).OfType <XPathNavigator> ();
                        int attr_matched = 0;
                        foreach (var n in nodes)
                        {
                            XmlElement node = ((IHasXmlNode)n).GetNode() as XmlElement;
                            node.SetAttribute(attr_name, metanav.Value);
                            //attr_last_cache = n;
                            attr_matched++;
                        }
                        if (attr_matched == 0)
                        {
                            // BG8A04
                            Report.Warning(0, Report.WarningApiFixup + 4, "<attr path=\"{0}\"/> matched no nodes.", path);
                        }
                        if (attr_matched != 1)
                        {
                            attr_last_cache = null;
                        }
                    } catch (XPathException e) {
                        // BG4A04
                        Report.Error(Report.ErrorApiFixup + 4, e, "Invalid XPath specification: {0}", path);
                    }
                    break;

                case "move-node":
                    try {
                        XPathExpression   expr        = api_nav.Compile(path);
                        string            parent      = metanav.Value;
                        XPathNodeIterator parent_iter = api_nav.Select(parent);
                        bool matched = false;
                        while (parent_iter.MoveNext())
                        {
                            XmlNode           parent_node = ((IHasXmlNode)parent_iter.Current).GetNode();
                            XPathNodeIterator path_iter   = parent_iter.Current.Clone().Select(expr);
                            while (path_iter.MoveNext())
                            {
                                XmlNode node = ((IHasXmlNode)path_iter.Current).GetNode();
                                parent_node.AppendChild(node.Clone());
                                node.ParentNode.RemoveChild(node);
                            }
                            matched = true;
                        }
                        if (!matched)
                        {
                            // BG8A05
                            Report.Warning(0, Report.WarningApiFixup + 5, "<move-node path=\"{0}\"/> matched no nodes.", path);
                        }
                    } catch (XPathException e) {
                        // BG4A05
                        Report.Error(Report.ErrorApiFixup + 5, e, "Invalid XPath specification: {0}", path);
                    }
                    break;

                case "remove-attr":
                    try {
                        string            name     = metanav.XGetAttribute("name", "");
                        XPathNodeIterator api_iter = api_nav.Select(path);
                        bool matched = false;

                        while (api_iter.MoveNext())
                        {
                            XmlElement node = ((IHasXmlNode)api_iter.Current).GetNode() as XmlElement;

                            node.RemoveAttribute(name);
                            matched = true;
                        }

                        if (!matched)
                        {
                            // BG8A06
                            Report.Warning(0, Report.WarningApiFixup + 6, "<remove-attr path=\"{0}\"/> matched no nodes.", path);
                        }
                    } catch (XPathException e) {
                        // BG4A06
                        Report.Error(Report.ErrorApiFixup + 6, e, "Invalid XPath specification: {0}", path);
                    }
                    break;
                }
            }
        }