Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign XML-documentation collecting mechanism #1071

Closed
5 tasks done
DedSec256 opened this issue Sep 7, 2021 · 2 comments
Closed
5 tasks done

Redesign XML-documentation collecting mechanism #1071

DedSec256 opened this issue Sep 7, 2021 · 2 comments

Comments

@DedSec256
Copy link

DedSec256 commented Sep 7, 2021

Redesign XML-documentation collecting mechanism

At the moment, XML-documentation comments are sequentially collected and attached to the nearest (after comments) declaration that supports XmlDoc. This leads to errors when comments that should not be considered attached to declarations at all:

image

Also, at the moment, it is allowed to place comments up to the name of the binding/type definition, which seems redundant:

image

We propose redesigning the XML-documentation collecting mechanism to allow more predictable and C#-consistent positions for XML-docs.
The basic idea is to set a grab point for documentation after a non-comment expression is encountered. Then we can assume that the documentation comment block belongs to the declaration if its grab point matches the correct position in the declaration (for example, the beginning of the declaration).
The correct positions for setting grab points are those that comply with the rules described below:

Common

It is allowed to place documentation only at the beginning of the declarations (types, type members, bindings, etc.):

/// A1
type /// A2 - [discarded]
     internal /// A3 - [discarded]
              A
/// f1
let /// f2 - [discarded]
    rec /// f3 - [discarded]
        inline /// f4 - [discarded]
               private f x = ...
/// B1
static /// B2 - [discarded]
       member /// B3 - [discarded]
              inline /// B4 - [discarded]
                     B() = ...
///E1
exception ///E2 - [discarded]
          E of string 
/// B1
val /// B2 - [discarded]
    mutable /// B3 - [discarded]
            private /// B4 - [discarded]
                    B: int

Delimiters

Similar to C#, if another expression is encountered when collecting documentation,
then documentation before this expression cannot be attached to the declaration:

/// A1 - [discarded]
1 + 1
/// A2
type A

After documentation, it is allowed to place a group of simple comments ( //, ////, (* ... *) ):

/// X
// simple comment
//// simple comment
(* simple multiline comment *)
let x = ... 

But it is still forbidden to separate documentation blocks with simple comments:

/// X - [discarded]
// simple comment
/// Y
let x = ...

Attributes

Similar to C#, if there are attributes in front of the declaration, then documentation before the attributes are attached to the declaration:

/// A1
[<Attribute>]
/// A2 - [discarded]
type A
/// F1
[<Attribute>]
/// F2 - [discarded]
let f x = ...
/// E1
[<DllImport("")>]
/// E2 - [discarded]
extern void E()

This also means that if the declaration contains attributes after its beginning, then documentation before such attributes are discarded:

type /// A - [discarded]
     [<Attribute>] A
let /// X - [discarded]
    [<Attribute>] X
module /// M - [discarded]
       [<Attribute>] M
/// A1
[<Attribute1>]
type /// A2 - [discarded]
     [<Attribute2>] A 
/// F1
[<Attribute1>]
let /// F2 - [discarded]
    [<Attribute2>] f x = ...
/// M1
[<Attribute>]
module /// M2 - [discarded]
       [<Attribute2>] M = ...

Recursive declarations group

Since there is a real use case dotnet/fsharp#11489 (comment), it is allowed to add documentation before and keyword

type A

/// B
and B
let rec f x = g x

/// G
and g x = f x

Also, documentation is allowed to be left after and, taking into account the rule for attributes:

type A

and /// B
    B
type A

and /// B1
    [<Attribute>]
    /// B2 - [discarded]
    B
let rec f x = g x

and  /// G
     g x = f x

However, if documentation blocks before and after and are present at the same time, then the priority is given to the documentation before and:

type A

/// B1
and /// B2 - [discarded]
    B

Primary constructor

It is allowed to place documentation before the declaration of the primary constructor, taking into account the rule for attributes:

type A /// CTOR1
       [<Attribute>]
       /// CTOR2 - [discarded]
       ()

Discriminated Unions

It is allowed to place documentation for union cases, taking into account the rule for attributes:

 type A =
    ///One
    One
    ///Two
    | Two
type A =
    ///One1
    | [<Attr>]
      ///One2 - [discarded]
      One
    ///Two1
    | [<Attr>]
      ///Two2 - [discarded]
      Two

Union case/record fields

It is allowed to place documentation for fields, taking into account the rule for attributes:

type A =
    {
        ///B1
        [<Attr>]
        ///B3 - [discarded]
        B: int 
    }
type Foo =
    | Thing of
       ///a1
       a: string *
       ///b1
       bool

Function parameters

The documentation for the function parameters should be described in the documentation for the function itself (for example, in the <param> tags)
and not allowed above parameter declarations:

/// function
/// <param name='x'>...</param>
/// ...
let f x (/// x - [discarded]
         y, 
         /// y - [discarded]
         z) = ...

Property accessors

It is allowed to place documentation only for the property itself,
property documentation will also apply to accessors:

member ///A
       x.A /// GET - [discarded]
           with get () = ...
           /// SET - [discarded]
           and set (_: int) = ...

Compiler diagnostic

To detect invalid documentation blocks positions, a new compiler diagnostic will be required.
We should mark each documentation block when grabbing it and then report syntax warnings for blocks that haven't been grabbed after parsing finishes:

image

Pros and Cons

The advantages of making this adjustment to F# are:

  • Bug fixes in the current mechanism for collecting XML-documentation
  • More predictable and C#-consistent positions for XML-documentation

The disadvantages of making this adjustment to F# are:

  • Already existing projects may contain XML-documentation incompatible with the new design

Extra information

Estimated cost (XS, S, M, L, XL, XXL): S

Implementation: dotnet/fsharp#11973

Related suggestions:
#948

Affidavit (please submit!)

Please tick this by placing a cross in the box:

  • This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
  • I have searched both open and closed suggestions on this site and believe this is not a duplicate
  • This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:

  • This is not a breaking change to the F# language design
  • I or my company would be willing to help implement and/or test this

For Readers

If you would like to see this issue implemented, please click the 👍 emoji on this issue. These counts are used to generally order the suggestions by engagement.

@dsyme
Copy link
Collaborator

dsyme commented Sep 8, 2021

@dsyme
Copy link
Collaborator

dsyme commented Nov 5, 2021

THis work has been completed, thank you @DedSec256 !!!

@dsyme dsyme closed this as completed Nov 5, 2021
@dsyme dsyme added the completed label Nov 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants