protected void RenderAttributes(XElement source, XElement target, ApiChanges changes) { var srcObsolete = source.GetObsoleteMessage(); var tgtObsolete = target.GetObsoleteMessage(); if (srcObsolete == tgtObsolete) { return; // nothing changed } if (srcObsolete == null) { if (tgtObsolete == null) { return; // neither is obsolete } var change = new ApiChange(GetDescription(source), State); change.Header = "Obsoleted " + GroupName; Formatter.RenderObsoleteMessage(change.Member, this, GetDescription(target), tgtObsolete); change.AnyChange = true; changes.Add(source, target, change); } else if (tgtObsolete == null) { // Made non-obsolete. Do we care to report this? } else { // Obsolete message changed. Do we care to report this? } }
public override bool Equals(XElement source, XElement target, ApiChanges changes) { if (base.Equals(source, target, changes)) { return(true); } var change = new ApiChange(GetDescription(source), State); change.Header = "Modified " + GroupName; change.Append("public event "); var srcEventType = source.GetTypeName("eventtype", State); var tgtEventType = target.GetTypeName("eventtype", State); if (srcEventType != tgtEventType) { change.AppendModified(srcEventType, tgtEventType, true); } else { change.Append(srcEventType); } change.Append(" "); change.Append(source.GetAttribute("name")).Append(";"); return(false); }
public override void Diff(TextWriter output, ApiChange apichange) { output.Write("<div {0}>", apichange.Breaking ? "data-is-breaking" : "data-is-non-breaking"); foreach (var line in apichange.Member.ToString().Split(new[] { Environment.NewLine }, 0)) { output.Write('\t'); output.WriteLine(line); } output.Write("</div>"); }
public override void Modified(XElement source, XElement target, ApiChanges diff) { // hack - there could be changes that we're not monitoring (e.g. attributes properties) var output = Output; State.Output = new StringWriter(); var sb = source.GetAttribute("base"); var tb = target.GetAttribute("base"); var rm = $"{State.Namespace}.{State.Type}: Modified base type: '{sb}' to '{tb}'"; State.LogDebugMessage($"Possible -r value: {rm}"); if (sb != tb && !State.IgnoreRemoved.Any(re => re.IsMatch(rm)) && !(State.IgnoreNonbreaking && IsBaseChangeCompatible(sb, tb))) { Formatter.BeginMemberModification(Output, "Modified base type"); var apichange = new ApiChange($"{State.Namespace}.{State.Type}", State).AppendModified(sb, tb, true); Formatter.Diff(Output, apichange); Formatter.EndMemberModification(Output); } ccomparer.Compare(source, target); icomparer.Compare(source, target); fcomparer.Compare(source, target); pcomparer.Compare(source, target); ecomparer.Compare(source, target); mcomparer.Compare(source, target); var si = source.Element("classes"); if (si != null) { var ti = target.Element("classes"); kcomparer = new NestedClassComparer(State); State.Parent = State.Type; kcomparer.Compare(si.Elements("class"), ti == null ? null : ti.Elements("class")); State.Type = State.Parent; } var s = (Output as StringWriter).ToString(); State.Output = output; if (s.Length > 0) { SetContext(target); Formatter.BeginTypeModification(Output); Output.WriteLine(s); Formatter.EndTypeModification(Output); } }
public override void Diff(TextWriter output, ApiChange apichange) { foreach (var line in apichange.Member.ToString().Split('\n')) { if (line.Contains("+++")) { output.WriteLine("-{0}", Clean(line, "+++", "---")); output.WriteLine("+{0}", Clean(line, "---", "+++")); } else { output.WriteLine(" {0}", line); } } }
void RenderPropertyType(XElement source, XElement target, ApiChange change) { var srcType = source.GetTypeName("ptype", State); var tgtType = target.GetTypeName("ptype", State); if (srcType == tgtType) { change.Append(tgtType); } else { change.AppendModified(srcType, tgtType, true); } change.Append(" "); }
protected void RenderName(XElement source, XElement target, ApiChange change) { var name = target.GetAttribute("name"); // show the constructor as it would be defined in C# name = name.Replace(".ctor", State.Type); var p = name.IndexOf('('); if (p >= 0) { name = name.Substring(0, p); } change.Append(name); }
void RenderReturnType(XElement source, XElement target, ApiChange change) { var srcType = source.GetTypeName("returntype", State); var tgtType = target.GetTypeName("returntype", State); if (srcType != tgtType) { change.AppendModified(srcType, tgtType, true); change.Append(" "); } else if (srcType != null) { // ctor don't have a return type change.Append(srcType); change.Append(" "); } }
protected void RenderStatic(MethodAttributes src, MethodAttributes tgt, ApiChange diff) { var srcStatic = (src & MethodAttributes.Static) == MethodAttributes.Static; var tgtStatic = (tgt & MethodAttributes.Static) == MethodAttributes.Static; if (srcStatic != tgtStatic) { if (srcStatic) { diff.AppendRemoved("static", true).Append(" "); } else { diff.AppendAdded("static", true).Append(" "); } } }
protected void RenderGenericParameters(XElement source, XElement target, ApiChange change) { var src = source.DescendantList("generic-parameters", "generic-parameter"); var tgt = target.DescendantList("generic-parameters", "generic-parameter"); var srcCount = src == null ? 0 : src.Count; var tgtCount = tgt == null ? 0 : tgt.Count; if (srcCount == 0 && tgtCount == 0) { return; } change.Append(Formatter.LesserThan); for (int i = 0; i < System.Math.Max(srcCount, tgtCount); i++) { if (i > 0) { change.Append(", "); } if (i >= srcCount) { change.AppendAdded(RenderGenericParameter(tgt [i]), true); } else if (i >= tgtCount) { change.AppendRemoved(RenderGenericParameter(src [i]), true); } else { var srcName = RenderGenericParameter(src [i]); var tgtName = RenderGenericParameter(tgt [i]); if (srcName != tgtName) { change.AppendModified(srcName, tgtName, true); } else { change.Append(srcName); } } } change.Append(Formatter.GreaterThan); }
public override bool Equals(XElement source, XElement target, ApiChanges changes) { if (base.Equals(source, target, changes)) { return(true); } XElement srcGetter, srcSetter; XElement tgtGetter, tgtSetter; GetAccessors(source, out srcGetter, out srcSetter); GetAccessors(target, out tgtGetter, out tgtSetter); List <XElement> srcIndexers = null; List <XElement> tgtIndexers = null; bool isIndexer = false; if (srcGetter != null) { srcIndexers = srcGetter.DescendantList("parameters", "parameter"); tgtIndexers = tgtGetter.DescendantList("parameters", "parameter"); isIndexer = srcIndexers != null && srcIndexers.Count > 0; } var change = new ApiChange(GetDescription(source), State); change.Header = "Modified " + GroupName; RenderMethodAttributes(GetMethodAttributes(srcGetter, srcSetter), GetMethodAttributes(tgtGetter, tgtSetter), change); RenderPropertyType(source, target, change); if (isIndexer) { RenderIndexers(srcIndexers, tgtIndexers, change); } else { RenderName(source, target, change); } RenderGenericParameters(source, target, change); RenderAccessors(srcGetter, tgtGetter, srcSetter, tgtSetter, change); changes.Add(source, target, change); return(false); }
public override bool Equals(XElement source, XElement target, ApiChanges changes) { if (base.Equals(source, target, changes)) { return(true); } var change = new ApiChange(GetDescription(source), State); change.Header = "Modified " + GroupName; RenderMethodAttributes(source, target, change); RenderReturnType(source, target, change); RenderName(source, target, change); RenderGenericParameters(source, target, change); RenderParameters(source, target, change); changes.Add(source, target, change); return(false); }
public abstract void Diff(TextWriter output, ApiChange apichange);
protected void RenderMethodAttributes(XElement source, XElement target, ApiChange diff) { RenderMethodAttributes(source.GetMethodAttributes(), target.GetMethodAttributes(), diff); }
protected void RenderMethodAttributes(MethodAttributes src, MethodAttributes tgt, ApiChange diff) { RenderStatic(src, tgt, diff); RenderVisibility(src & MethodAttributes.MemberAccessMask, tgt & MethodAttributes.MemberAccessMask, diff); RenderVTable(src, tgt, diff); }
protected void RenderVisibility(MethodAttributes source, MethodAttributes target, ApiChange diff) { source = source & MethodAttributes.MemberAccessMask; target = target & MethodAttributes.MemberAccessMask; if (source == target) { diff.Append(GetVisibility(target)); } else { var breaking = false; switch (source) { case MethodAttributes.Private: case MethodAttributes.Assembly: case MethodAttributes.FamANDAssem: break; // these are not publicly visible, thus not breaking case MethodAttributes.FamORAssem: case MethodAttributes.Family: switch (target) { case MethodAttributes.Public: // to public is not a breaking change break; case MethodAttributes.Family: case MethodAttributes.FamORAssem: // not a breaking change, but should still show up in diff break; default: // anything else is a breaking change breaking = true; break; } break; case MethodAttributes.Public: default: // any change from public is breaking. breaking = true; break; } diff.AppendModified(GetVisibility(source), GetVisibility(target), breaking); } diff.Append(" "); }
void RenderVTable(MethodAttributes source, MethodAttributes target, ApiChange change) { var srcAbstract = (source & MethodAttributes.Abstract) == MethodAttributes.Abstract; var tgtAbstract = (target & MethodAttributes.Abstract) == MethodAttributes.Abstract; var srcFinal = (source & MethodAttributes.Final) == MethodAttributes.Final; var tgtFinal = (target & MethodAttributes.Final) == MethodAttributes.Final; var srcVirtual = (source & MethodAttributes.Virtual) == MethodAttributes.Virtual; var tgtVirtual = (target & MethodAttributes.Virtual) == MethodAttributes.Virtual; var srcOverride = (source & MethodAttributes.VtableLayoutMask) != MethodAttributes.NewSlot; var tgtOverride = (target & MethodAttributes.VtableLayoutMask) != MethodAttributes.NewSlot; var srcWord = srcVirtual ? (srcOverride ? "override" : "virtual") : string.Empty; var tgtWord = tgtVirtual ? (tgtOverride ? "override" : "virtual") : string.Empty; var breaking = srcWord.Length > 0 && tgtWord.Length == 0; if (srcAbstract) { if (tgtAbstract) { change.Append("abstract "); } else if (tgtVirtual) { change.AppendModified("abstract", tgtWord, false).Append(" "); } else { change.AppendRemoved("abstract").Append(" "); } } else { if (tgtAbstract) { change.AppendAdded("abstract", true).Append(" "); } else if (srcWord != tgtWord) { if (!tgtFinal) { if (State.IgnoreVirtualChanges) { change.HasIgnoredChanges = true; } else { change.AppendModified(srcWord, tgtWord, breaking).Append(" "); } } } else if (tgtWord.Length > 0) { change.Append(tgtWord).Append(" "); } else if (srcWord.Length > 0) { change.AppendRemoved(srcWord, breaking).Append(" "); } } if (srcFinal) { if (tgtFinal) { change.Append("final "); } else { if (srcVirtual && !tgtVirtual && State.IgnoreVirtualChanges) { change.HasIgnoredChanges = true; } else { change.AppendRemoved("final", false).Append(" "); // removing 'final' is not a breaking change. } } } else { if (tgtFinal && srcVirtual) { change.AppendModified("virtual", "final", true).Append(" "); // adding 'final' is a breaking change if the member was virtual } } if (!srcVirtual && !srcFinal && tgtVirtual && tgtFinal) { // existing member implements a member from a new interface // this would show up as 'virtual final', which is redundant, so show nothing at all. change.HasIgnoredChanges = true; } // Ignore non-breaking virtual changes. if (State.IgnoreVirtualChanges && !change.Breaking) { change.AnyChange = false; change.HasIgnoredChanges = true; } var tgtSecurity = (source & MethodAttributes.HasSecurity) == MethodAttributes.HasSecurity; var srcSecurity = (target & MethodAttributes.HasSecurity) == MethodAttributes.HasSecurity; if (tgtSecurity != srcSecurity) { change.HasIgnoredChanges = true; } var srcPInvoke = (source & MethodAttributes.PinvokeImpl) == MethodAttributes.PinvokeImpl; var tgtPInvoke = (target & MethodAttributes.PinvokeImpl) == MethodAttributes.PinvokeImpl; if (srcPInvoke != tgtPInvoke) { change.HasIgnoredChanges = true; } }
protected void RenderParameters(XElement source, XElement target, ApiChange change) { var src = source.DescendantList("parameters", "parameter"); var tgt = target.DescendantList("parameters", "parameter"); var srcCount = src == null ? 0 : src.Count; var tgtCount = tgt == null ? 0 : tgt.Count; change.Append(" ("); for (int i = 0; i < System.Math.Max(srcCount, tgtCount); i++) { if (i > 0) { change.Append(", "); } string mods_tgt = tgt [i].GetAttribute("direction") ?? ""; string mods_src = src [i].GetAttribute("direction") ?? ""; if (mods_tgt.Length > 0) { mods_tgt = mods_tgt + " "; } if (mods_src.Length > 0) { mods_src = mods_src + " "; } if (i >= srcCount) { change.AppendAdded(mods_tgt + tgt [i].GetTypeName("type", State) + " " + tgt [i].GetAttribute("name"), true); } else if (i >= tgtCount) { change.AppendRemoved(mods_src + src [i].GetTypeName("type", State) + " " + src [i].GetAttribute("name"), true); } else { var paramSourceType = src [i].GetTypeName("type", State); var paramTargetType = tgt [i].GetTypeName("type", State); var paramSourceName = src [i].GetAttribute("name"); var paramTargetName = tgt [i].GetAttribute("name"); if (mods_src != mods_tgt) { change.AppendModified(mods_src, mods_tgt, true); } else { change.Append(mods_src); } if (paramSourceType != paramTargetType) { change.AppendModified(paramSourceType, paramTargetType, true); } else { change.Append(paramSourceType); } change.Append(" "); if (!State.IgnoreParameterNameChanges && paramSourceName != paramTargetName) { change.AppendModified(paramSourceName, paramTargetName, true); } else { change.Append(paramSourceName); } var optSource = src [i].Attribute("optional"); var optTarget = tgt [i].Attribute("optional"); var srcValue = FormatValue(paramSourceType, src [i].GetAttribute("defaultValue")); var tgtValue = FormatValue(paramTargetType, tgt [i].GetAttribute("defaultValue")); if (optSource != null) { if (optTarget != null) { change.Append(" = "); if (srcValue != tgtValue) { change.AppendModified(srcValue, tgtValue, false); } else { change.Append(tgtValue); } } else { change.AppendRemoved(" = " + srcValue); } } else { if (optTarget != null) { change.AppendAdded(" = " + tgtValue); } } } } change.Append(")"); }
void RenderAccessors(XElement srcGetter, XElement tgtGetter, XElement srcSetter, XElement tgtSetter, ApiChange change) { // FIXME: this doesn't render changes in the accessor visibility (a protected setter can become public for instance). change.Append(" {"); if (tgtGetter != null) { if (srcGetter != null) { change.Append(" ").Append("get;"); } else { change.Append(" ").AppendAdded("get;"); } } else if (srcGetter != null) { change.Append(" ").AppendRemoved("get;"); } if (tgtSetter != null) { if (srcSetter != null) { change.Append(" ").Append("set;"); } else { change.Append(" ").AppendAdded("set;"); } } else if (srcSetter != null) { change.Append(" ").AppendRemoved("set;"); } change.Append(" }"); // Ignore added property setters if asked to if (srcSetter == null && tgtSetter != null && State.IgnoreAddedPropertySetters && !change.Breaking) { change.AnyChange = false; change.HasIgnoredChanges = true; } }
void RenderIndexers(List <XElement> srcIndexers, List <XElement> tgtIndexers, ApiChange change) { change.Append("this ["); for (int i = 0; i < srcIndexers.Count; i++) { var source = srcIndexers [i]; var target = tgtIndexers [i]; if (i > 0) { change.Append(", "); } var srcType = source.GetTypeName("type", State); var tgtType = target.GetTypeName("type", State); if (srcType == tgtType) { change.Append(tgtType); } else { change.AppendModified(srcType, tgtType, true); } change.Append(" "); var srcName = source.GetAttribute("name"); var tgtName = target.GetAttribute("name"); if (srcName == tgtName) { change.Append(tgtName); } else { change.AppendModified(srcName, tgtName, true); } } change.Append("]"); }
void RenderFieldAttributes(FieldAttributes source, FieldAttributes target, ApiChange change) { if (!State.IgnoreNonbreaking) { var srcNotSerialized = (source & FieldAttributes.NotSerialized) == FieldAttributes.NotSerialized; var tgtNotSerialized = (target & FieldAttributes.NotSerialized) == FieldAttributes.NotSerialized; if (srcNotSerialized != tgtNotSerialized) { // this is not a breaking change, so only render it if it changed. if (srcNotSerialized) { change.AppendRemoved($"[NonSerialized]{Environment.NewLine}"); } else { change.AppendAdded($"[NonSerialized]{Environment.NewLine}"); } } } // the visibility values are the same for MethodAttributes and FieldAttributes, so just use the same method. RenderVisibility((MethodAttributes)source, (MethodAttributes)target, change); // same for the static flag RenderStatic((MethodAttributes)source, (MethodAttributes)target, change); var srcLiteral = (source & FieldAttributes.Literal) != 0; var tgtLiteral = (target & FieldAttributes.Literal) != 0; if (srcLiteral) { if (tgtLiteral) { change.Append("const "); } else { change.AppendRemoved("const", true).Append(" "); } } else if (tgtLiteral) { change.AppendAdded("const", true).Append(" "); } var srcInitOnly = (source & FieldAttributes.InitOnly) != 0; var tgtInitOnly = (target & FieldAttributes.InitOnly) != 0; if (srcInitOnly) { if (tgtInitOnly) { change.Append("readonly "); } else { change.AppendRemoved("readonly", false).Append(" "); } } else if (tgtInitOnly) { change.AppendAdded("readonly", true).Append(" "); } }
public override bool Equals(XElement source, XElement target, ApiChanges changes) { if (base.Equals(source, target, changes)) { return(true); } var name = source.GetAttribute("name"); var srcValue = source.GetAttribute("value"); var tgtValue = target.GetAttribute("value"); var change = new ApiChange(GetDescription(source), State); change.Header = "Modified " + GroupName; if (State.BaseType == "System.Enum") { change.Append(name).Append(" = "); if (srcValue != tgtValue) { change.AppendModified(srcValue, tgtValue, true); } else { change.Append(srcValue); } } else { RenderFieldAttributes(source.GetFieldAttributes(), target.GetFieldAttributes(), change); var srcType = source.GetTypeName("fieldtype", State); var tgtType = target.GetTypeName("fieldtype", State); if (srcType != tgtType) { change.AppendModified(srcType, tgtType, true); } else { change.Append(srcType); } change.Append(" "); change.Append(name); if (srcType == "string" && srcValue != null) { srcValue = "\"" + srcValue + "\""; } if (tgtType == "string" && tgtValue != null) { tgtValue = "\"" + tgtValue + "\""; } if (srcValue != tgtValue) { change.Append(" = "); if (srcValue == null) { srcValue = "null"; } if (tgtValue == null) { tgtValue = "null"; } change.AppendModified(srcValue, tgtValue, true); } else if (srcValue != null) { change.Append(" = "); change.Append(srcValue); } change.Append(";"); } changes.Add(source, target, change); return(false); }