Skip to content

BRO1603: Documentation text should end with a period

Summary, remarks, parameter, type parameter, return value, value and exception text are sentences and end with a period. Replaces StyleCop SA1629.

Example

Before

public class Prices
{
    /// <summary>Applies a discount</summary>
    /// <param name="price">The full price</param>
    /// <returns>The discounted price, see <see cref="Prices"/></returns>
    public decimal Discount(decimal price) => price * 0.9m;
}

After

public class Prices
{
    /// <summary>Applies a discount.</summary>
    /// <param name="price">The full price.</param>
    /// <returns>The discounted price, see <see cref="Prices"/>.</returns>
    public decimal Discount(decimal price) => price * 0.9m;
}

Why

Consistent punctuation makes generated documentation and IntelliSense read as prose, and it's the convention in the .NET documentation.

How the fix works

A period is added right after the last text, or after an inline element at the end (<see cref="..."/>, <c>). A trailing space stays after the period.

This rule reads documentation as XML, which the compiler only does when the project generates documentation (<GenerateDocumentationFile>true</GenerateDocumentationFile>), like StyleCop (its SA0001 says so).

Not reported

  • Text that ends with ?, ! or :. A question, an exclamation or an introduction is a finished sentence.
  • Text that ends with , or ; (1033 => "en",, value;): a line of code or a list that goes on.
  • A period followed only by closing punctuation: (see above.), "done.", 'done.', [note.].
  • Text that ends with a block element, like a list or a code sample.
  • Empty elements.
  • Text that is only a number (<summary>0</summary> on an enum member, 0x1F): a value, not a sentence.
  • Text whose last word ends in a period and digits (Supports HTML 5.0): a period after it reads as part of the number.
  • Text that ends with an inline element whose own text ends a sentence: <paramref name="name">The name of the request.</paramref>, <see cref="X">is it done?</see>. In <c>, which holds code, only a quoted sentence counts (<c>"User logged in."</c>); Calls <c>Done.</c> gets its period.
  • Events and finalizers: StyleCop's SA1629 doesn't check their documentation, and neither does this rule.
  • Text that ends in code: its last word contains a bracket, brace, =, ;, :, a slash, |, $, #, _ or a backtick (digraph {, Example: A1:B10, Run(x), a URL). A period would read as part of the code. A closing ) without its ( in the word ends a parenthetical and still gets the period ((in ms).). A quoted literal at the end that reads as code is code too: followed by ;, with an escape, or a punctuation char (Default is ',';, Usually "\r\n", The separator ','); a quoted word (the word "done") still gets its period.
  • Elements StyleCop doesn't know are passed over, like StyleCop: the text before them counts. Text that ends with <devremarks>...</devremarks> (vs-threading) is checked where the sentence before it ends, and gets no period after the element. The period goes after an inline element: <c>, <see>, <paramref>, <typeparamref>, and HTML's <a>, <b>, <i>, <u>, <em>, <strong>, <sub>, <sup>, <span>, <tt> (StyleCop passes over those too and puts the period before them).
  • Tags named in stylebro_exclude_from_punctuation_check (see Configuration).
  • Documentation whose XML is malformed: IComparable<T> in prose opens an element T that takes the summary's end tag, and a bare < (when a < b) opens an element that never closes, so where the text ends is a guess. A bare & that starts no entity (this & that) is malformed too (the compiler reports CS1570). Write a &lt; b, &amp;, IComparable&lt;T&gt; or <see cref="IComparable{T}"/>, then the rule checks it again. The other rules that edit documentation (BRO1604-BRO1614, BRO1616-BRO1619) skip it too.

Text that ends in an XML entity (List&lt;T&gt;) gets the period after the entity. Spaces between the text and a closing tag on the same line make way for the period: evaluates to true </returns> becomes evaluates to true.</returns>, not true. </returns>.

Configuration

[*.cs]
# Tags whose text isn't checked, comma-separated (default: seealso)
stylebro_exclude_from_punctuation_check = seealso, example

StyleCop's documentationRules.excludeFromPunctuationCheck, with the same default; stylebro-migrate writes it from stylecop.json when a team changed it. An excluded tag isn't checked at the top level or nested (an excluded para inside a summary). The rule checks summary, remarks, param, typeparam, returns, value and exception anyway, so seealso is never checked, set or not.

Compared with StyleCop

Same results as StyleCop, except:

  • text ending with ?, ! or :, which StyleCop reports and turns into question?.;
  • a period followed by a closing quote or bracket ("done."), which StyleCop reports and turns into "done.". (#2860); StyleCop accepts only .);
  • text ending in an entity: StyleCop 1.2.0-beta.556 reports the entity's ; and its fix replaces it (&gt., #3802, fixed after beta.556);
  • text ending in code (digraph {, A1:B10), which StyleCop reports and turns into digraph {.;
  • text ending in a <c> element that quotes a sentence (<c>"User {User} logged in."</c>), which StyleCop reports and turns into </c>. (#2784, open);
  • text ending in an inline element with text of its own (<see cref="X">a sentence.</see>): StyleCop passes over it and checks the text before it, so it reports Ends with <see ...> and writes Ends with. <see ...>; StyleBro checks the element's own text and puts a missing period after the element;
  • text whose last word ends in a period and digits (HTML 5.0), which StyleCop turns into 5.0..

StyleCop checks every top-level tag not in excludeFromPunctuationCheck; StyleBro only the tags listed above.