Skip to content

Instantly share code, notes, and snippets.

@ZacharyPatten
Created June 28, 2021 22:02
Show Gist options
  • Save ZacharyPatten/cb37ae76a01b68d34efdfe7de7c041c4 to your computer and use it in GitHub Desktop.
Save ZacharyPatten/cb37ae76a01b68d34efdfe7de7c041c4 to your computer and use it in GitHub Desktop.
System.Console.WriteLine("Hello World!");
#pragma warning disable IDE0060 // Remove unused parameter
#pragma warning disable CA1822 // Mark members as static
#region Analyzer #01: not all parameters accounted for
namespace Analyzer1_Example1
{
// There is no warning that "B" is missing XML docs for "T2".
/// <summary>hello world</summary>
/// <typeparam name="T1">hello world</typeparam>
public class A<T1> { }
/// <inheritdoc cref="A{T1}" />
public class B<T1, T2> { }
}
namespace Analyzer1_Example2
{
// There is no warning that "A.Method2" is missing XML docs for "T1" and "t1".
public class A
{
/// <summary>hello world</summary>
public int Method1() => throw new System.Exception();
/// <inheritdoc cref="Method1"/>
public void Method2<T1>(T1 t1) => throw new System.Exception();
}
}
#endregion
#region Analyzer #02: no source to inherit from
namespace Analyzer2_Example1
{
// "A.Method" uses inheritdoc, but there is no source to inherit from.
public class A
{
/// <inheritdoc />
public void Method() => throw new System.Exception();
}
}
namespace Analyzer2_Example2
{
// "B.Method" uses inheritdoc, but there is no source to inherit from.
public class A
{
/// <summary>hello world</summary>
public int Method<TCompare>() => throw new System.Exception();
}
public class B : A
{
/// <inheritdoc />
public new void Method<TCompare>() => throw new System.Exception();
}
}
namespace Analyzer2_Example3
{
// "B.Method" uses inheritdoc, but it is static, and this currently doesn't work.
public class A
{
/// <summary>hello world</summary>
public static void Method() => throw new System.Exception();
}
public class B : A
{
/// <inheritdoc />
public static new void Method() => throw new System.Exception();
}
}
#endregion
#region Analyzer #03: inherit <returns> on "void" return methods or classes
namespace Analyzer3_Example1
{
// "A.Method2" inherits a "<returns>" XML node but has a "void" return type
// which currently shows up in the IDE (which IMO may need to be considered
// a bug)
public class A
{
/// <summary>hello world</summary>
/// <returns>hello world</returns>
public int Method1() => throw new System.Exception();
/// <inheritdoc cref="Method1"/>
public void Method2() => throw new System.Exception();
}
}
namespace Analyzer3_Example2
{
// "A" inherits a "<returns>" XML node but is a class
/// <inheritdoc cref="A.Method"/>
public class A
{
/// <summary>hello world</summary>
/// <returns>hello world</returns>
public int Method() => throw new System.Exception();
}
}
#endregion
#region Analyzer #04: inherit <exception> on methods that can't throw that type
namespace Analyzer4_Example1
{
// "A.Method2" inherits a "<exception>" when it doesn't throw that type of exception
public class A
{
/// <summary>hello world</summary>
/// <exception cref="System.NotImplementedException" />
public void Method1() => throw new System.NotImplementedException();
/// <inheritdoc cref="Method1"/>
public void Method2() => throw new System.Exception();
}
}
#endregion
#region Analyzer #05: explicit inheritdoc when not necessary
namespace Analyzer5_Example1
{
// the inheritdoc on "B" has an explicit "cref" when it is not necessary
/// <summary>hello world</summary>
public class A { }
/// <inheritdoc cref="A"/>
public class B : A { }
}
namespace Analyzer5_Example2
{
// the inheritdoc on "C" has an explicit "cref" when it is not necessary
/// <summary>hello world</summary>
public class A { }
/// <inheritdoc/>
public class B : A { }
/// <inheritdoc cref="A"/>
public class C : B { }
}
namespace Analyzer5_Example3
{
// the inheritdoc's on "C" has an explicit "cref" when it is not necessary
// and there only needs to be one inheritdoc
/// <summary>hello world</summary>
public class A { }
/// <inheritdoc/>
public class B : A { }
/// <inheritdoc cref="B"/>
/// <inheritdoc cref="A"/>
public class C : B { }
}
#endregion
#region Analyzer #06: incorrect order when you want to override
namespace Analyzer6_Example1
{
// "B<T1>" inheritdoc's from "A<T1>" and attempts to override the XML
// docs for "T1" but due to how the ordering of the XML docs are currently
// processed, it is not overriding. In order to override, the overrides
// must come before the inheritdoc.
/// <summary>hello world</summary>
/// <typeparam name="T1">hello world</typeparam>
public class A<T1> { }
/// <inheritdoc cref="A{T1}"/>
/// <typeparam name="T1">goodbye world</typeparam>
public class B<T1> : A<T1> { }
}
#endregion
#region Analyzer #07: valid inheritdoc but everything is overriden
namespace Analyzer7_Example1
{
// "B" has inheritdoc but nothing is inherited because every
// XML node is overriden
/// <summary>hello world</summary>
public class A { }
/// <summary>goodbye world</summary>
/// <inheritdoc />
public class B : A { }
}
#endregion
#region Analyzer #08: cyclic inheritdocs
namespace Analyzer8_Example1
{
// "A" and "B" have cyclic inheritdocs
/// <inheritdoc cref="B"/>
/// <summary>hello world</summary>
public class A { }
/// <inheritdoc cref="A"/>
/// <summary>goodbye world</summary>
public class B { }
}
namespace Analyzer8_Example2
{
// "A" and "B" have cyclic inheritdocs
/// <inheritdoc cref="B"/>
/// <summary>hello world</summary>
public class A { }
/// <inheritdoc/>
/// <summary>goodbye world</summary>
public class B : A { }
}
#endregion
#region Analyzer #09: inheriting only standard nodes that are not standard for the inheriting member
namespace Analyzer9_Example1
{
// "A", "A.Field", "A.Property", and "A.Event" only inherits
// a "params" XML node, but "params" is not not a standard node for
// classes, fields, properties, or events
/// <inheritdoc cref="Method{T1}(T1)"/>
public class A
{
/// <param name="t1">hello world</param>
public int Method<T1>(T1 t1) => throw new System.Exception();
/// <inheritdoc cref="Method{T1}(T1)"/>
public int Field;
/// <inheritdoc cref="Method{T1}(T1)"/>
public int Property => throw new System.Exception();
/// <inheritdoc cref="Method{T1}(T1)"/>
public event System.Action Event;
}
}
#endregion
#region Analyzer #10: encourage inheritdoc instead of copy-paste
// Note: I think this is a duplicate of https://github.com/DotNetAnalyzers/DocumentationAnalyzers/issues/16
namespace Analyzer10_Example1
{
// "A" and "B" contain identical XML docs and therefore "inheritdoc"
// should be prefered to duplication
/// <summary>hello world</summary>
public class A { }
/// <summary>hello world</summary>
public class B : A { }
}
namespace Analyzer10_Example2
{
// "A" and "B" contain identical "summary" XML nodes and therefore
// "inheritdoc" should be prefered to duplication.
/// <summary>hello world</summary>
public class A { }
/// <summary>hello world</summary>
/// <typeparam name="T1">hello world</typeparam>
public class B<T1> : A { }
}
#endregion
#region Analyzer #11: returns on non-returns member
namespace Analyzer11_Example1
{
// "A" has "<returns>" but it is a class
/// <returns>hello world</returns>
public class A { }
}
#endregion
#region Analyzer #12: valid inheritdoc but source doesn't have XML docs
namespace Analyzer12_Example1
{
// "B" inheritdoc's from "A", but "A" has no XML docs.
public class A { }
/// <inheritdoc cref="A"/>
public class B { }
}
#endregion
#region Analyzer #13: encourage <value> instead of <returns>
namespace Analyzer13_Example1
{
// "A.Property" has <returns> but <value> is generally prefered for properties
public class A
{
/// <returns>hello world</returns>
public int Property => throw new System.Exception();
}
}
namespace Analyzer13_Example2
{
// "A.Property" has both <value> and <returns> so there should probably only be <value>
public class A
{
/// <value>hello world</value>
/// <returns>hello world</returns>
public int Property => throw new System.Exception();
}
}
#endregion
#region Analyzer #14: encourage <typeparamref...> and <paramref...> and maybe <see...>
namespace Analyzer14_Example1
{
// "A.Method1" includes "T1", "T2", "t1", and "t2" in the summary, which might be better
// represented with <typeparamref...> and <paramref...> as done in "A.Method2"
public class A
{
/// <summary>Takes a t1 and t2 which are types T1 and T2 respectively.</summary>
public void Method1<T1, T2>(T1 t1, T2 t2) => throw new System.Exception();
/// <summary>Takes a <paramref name="t1"/> and <paramref name="t2"/> which are types <typeparamref name="T1"/> and <typeparamref name="T2"/> respectively.</summary>
public void Method2<T1, T2>(T1 t1, T2 t2) => throw new System.Exception();
}
}
#endregion
#region Analyzer #15: encourage the use of <br/> and maybe <list>
namespace Analyzer15_Example1
{
// The XML docs on "A" pretty clearly want to be a list. That can
// be achieved with either <br/> or <list> as demonstrated in "B"
// and "C"
/// <summary>
/// 1. hello world
/// 2. hello world
/// 3. hello world
/// </summary>
public class A { }
/// <summary>
/// 1. hello world<br/>
/// 2. hello world<br/>
/// 3. hello world
/// </summary>
public class B { }
/// <summary>
/// <list type="number">
/// <item>hello world</item>
/// <item>hello world</item>
/// <item>hello world</item>
/// </list>
/// </summary>
public class C { }
}
#endregion
#pragma warning restore IDE0060 // Remove unused parameter
#pragma warning restore CA1822 // Mark members as static
@sharwell
Copy link

  • Analyzer1_Example1: This is a variation of dotnet/roslyn#40325.
  • Analyzer1_Example2: The compiler doesn't generally warn about this case, but SA1611 and SA1618 are related. Before implementing support specifically for <inheritdoc/> in these scenarios, the corresponding analyzer package would need to support diagnostics for the standard case where only a <summary> element is provided. It would be reasonable to file a feature request for the general form in dotnet/roslyn-analyzers.
  • Analyzer2_Example1: This sounds like SA1648. It would be reasonable to file a feature request to add this one to dotnet/roslyn-analyzers.
  • Analyzer2_Example2: Same as Analyzer2_Example1
  • Analyzer2_Example3: Same as Analyzer2_Example1
  • Analyzer3_Example1: This sounds like SA1617. It would be reasonable to file a feature request to add this one to dotnet/roslyn-analyzers.
  • Analyzer3_Example2: I'm not sure a rule for this exists, but I'm also not sure it would ever happen. If it is filed, it should be filed for the general form (i.e. direct application of a <returns> element to a type) and handle <inheritdoc> as a side benefit.
  • Analyzer4_Example1: Members are generally allowed to document a broader set of exceptions than the implementation currently throws, so this would not be considered a warning condition. This one would be difficult to move forward without strong evidence that it would prevent application bugs that cannot be prevented in another more straightforward way.
  • Analyzer5: This one seems new and could be filed at dotnet/roslyn-analyzers.
  • Analyzer6: This is a bug in dotnet/roslyn. The order is not supposed to matter.
  • Analyzer7: This one seems new and could be filed at dotnet/roslyn-analyzers.
  • Analyzer8: This one seems new and could be filed at dotnet/roslyn-analyzers.
  • Analyzer9: For me, this is really a duplicate of Analyzer3_Example2.
  • Analyzer10: It might be possible, but we need to make sure to account for cases where projects have one or more tools in use that don't understand inheritdoc. This would be a feature request for dotnet/roslyn-analyzers.
  • Analyzer11: For me, this is a duplicate of Analyzer3_Example2.
  • Analyzer12: This would be a feature request for dotnet/roslyn-analyzers, but keep in mind this happens really often in non-error cases so it would be difficult to move forward.
  • Analyzer13: This could be an analyzer (feature request in dotnet/roslyn-analyzers), but before that we need to finish unifying the IDE features to be consistent in the use of <value> for properties. See dotnet/roslyn#8627 and all the items linked to it.
  • Analyzer14: This is the intent of DotNetAnalyzers/DocumentationAnalyzers#24, DotNetAnalyzers/DocumentationAnalyzers#15, DotNetAnalyzers/DocumentationAnalyzers#25, DotNetAnalyzers/DocumentationAnalyzers#27, DotNetAnalyzers/DocumentationAnalyzers#29, DotNetAnalyzers/DocumentationAnalyzers#28. It could be filed as a feature request to bring these over to dotnet/roslyn-analyzers.
  • Analyzer15: This seems like the scenario DOC900 targeted (see also openstacknetsdk/OpenStackNetAnalyzers#18). This could be filed as a feature request for dotnet/roslyn-analyzers, but I think the more likely eventual outcome is something like dotnet/csharplang#2394.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment