Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5c1cb81
Initial plan
Copilot Sep 8, 2025
1713662
Add basic XML doc comment position warning - initial implementation
Copilot Sep 8, 2025
8698eef
Add warning for XML documentation comments not positioned as first no…
Copilot Sep 8, 2025
21333cf
Fix XML doc comment position check to analyze actual line content ins…
Copilot Sep 8, 2025
7d2be7e
Address feedback by disabling hardcoded column limit approach tempora…
Copilot Sep 8, 2025
6413c55
Merge branch 'main' into copilot/fix-920e1d4e-0c13-4c25-8d7b-183dbc29…
T-Gro Sep 18, 2025
92f2c02
Address feedback: remove hardcoded column limit, disable warning temp…
Copilot Sep 19, 2025
e12e8cc
Implement XML doc comment position check in LexFilter instead of lexe…
Copilot Sep 19, 2025
fb42cf8
Merge branch 'main' into copilot/fix-920e1d4e-0c13-4c25-8d7b-183dbc29…
T-Gro Sep 22, 2025
28a6204
Fix type constraint mismatch in FSComp.SR.xmlDocNotFirstOnLine() usage
Copilot Sep 22, 2025
56607de
Fix unused variable warning in LexFilter pattern match
Copilot Sep 22, 2025
9d9a664
Merge branch 'main' into copilot/fix-920e1d4e-0c13-4c25-8d7b-183dbc29…
T-Gro Oct 17, 2025
83a3454
Update xlf localization files for xmlDocNotFirstOnLine entry
Copilot Nov 30, 2025
bd22c0e
Add lexer-level tracking for XML doc comment position warning
Copilot Dec 2, 2025
3070e3d
Fix incorrect /// comment usage in infos.fs - should be //
Copilot Dec 2, 2025
1f45f17
Disable XML doc position warning - implementation too aggressive
Copilot Dec 3, 2025
4ac9a26
Re-implement XML doc comment position warning using token position tr…
Copilot Dec 3, 2025
a560672
Add token position tracking to more token types and start updating tests
Copilot Dec 3, 2025
3f936f2
Update XmlDocTests to expect FS3879 warning for misplaced /// comments
Copilot Dec 3, 2025
df81dfb
Fix remaining test failures: update neg45.bsl baseline and type membe…
Copilot Dec 3, 2025
fc51e55
Fix code formatting in LexHelpers.fs and LexHelpers.fsi
Copilot Dec 3, 2025
4b58239
Merge branch 'main' into copilot/fix-920e1d4e-0c13-4c25-8d7b-183dbc29…
abonie Dec 5, 2025
c24643d
Update neg45.bsl baseline with all three FS3879 warnings
Copilot Dec 5, 2025
c2736dc
Fix /// comment in Trimming/Program.fs that was causing build failures
Copilot Dec 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Compiler/Checking/infos.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1516,7 +1516,7 @@ type ILFieldInfo =
match x with
| ILFieldInfo(tinfo, _) -> tinfo.TypeInstOfRawMetadata
#if !NO_TYPEPROVIDERS
| ProvidedField _ -> [] /// GENERIC TYPE PROVIDERS
| ProvidedField _ -> [] // GENERIC TYPE PROVIDERS
#endif

/// Get the name of the field
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1813,4 +1813,5 @@ featureAllowLetOrUseBangTypeAnnotationWithoutParens,"Allow let! and use! type an
3876,lexWarnDirectivesMustMatch,"There is another %s for this warning already in line %d."
3877,lexLineDirectiveMappingIsNotUnique,"The file '%s' was also pointed to in a line directive in '%s'. Proper warn directive application may not be possible."
3878,tcAttributeIsNotValidForUnionCaseWithFields,"This attribute is not valid for use on union cases with fields."
3879,xmlDocNotFirstOnLine,"XML documentation comments should be the first non-whitespace text on a line."
featureReturnFromFinal,"Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder."
13 changes: 13 additions & 0 deletions src/Compiler/SyntaxTree/LexHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ type LexArgs =
mutable indentationSyntaxStatus: IndentationAwareSyntaxStatus
mutable stringNest: LexerInterpolatedStringNesting
mutable interpolationDelimiterLength: int
/// Tracks the line number of the last non-whitespace, non-comment token
mutable lastTokenEndLine: int
/// Tracks the end column of the last non-whitespace, non-comment token
mutable lastTokenEndColumn: int
}

/// possible results of lexing a long Unicode escape sequence in a string literal, e.g. "\U0001F47D",
Expand All @@ -84,6 +88,8 @@ let mkLexargs
stringNest = []
pathMap = pathMap
interpolationDelimiterLength = 0
lastTokenEndLine = 0
lastTokenEndColumn = 0
}

/// Register the lexbuf and call the given function
Expand Down Expand Up @@ -444,9 +450,16 @@ module Keywords =
if IsCompilerGeneratedName s then
warning (Error(FSComp.SR.lexhlpIdentifiersContainingAtSymbolReserved (), lexbuf.LexemeRange))

// Track token position for XML doc comment checking
args.lastTokenEndLine <- lexbuf.EndPos.Line
args.lastTokenEndColumn <- lexbuf.EndPos.Column
args.resourceManager.InternIdentifierToken s

let KeywordOrIdentifierToken args (lexbuf: Lexbuf) s =
// Track token position for XML doc comment checking
args.lastTokenEndLine <- lexbuf.EndPos.Line
args.lastTokenEndColumn <- lexbuf.EndPos.Column

match keywordTable.TryGetValue s with
| true, v ->
match v with
Expand Down
24 changes: 15 additions & 9 deletions src/Compiler/SyntaxTree/LexHelpers.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,21 @@ type LexResourceManager =

/// The context applicable to all lexing functions (tokens, strings etc.)
type LexArgs =
{ conditionalDefines: string list
resourceManager: LexResourceManager
diagnosticsLogger: DiagnosticsLogger
applyLineDirectives: bool
pathMap: PathMap
mutable ifdefStack: LexerIfdefStack
mutable indentationSyntaxStatus: IndentationAwareSyntaxStatus
mutable stringNest: LexerInterpolatedStringNesting
mutable interpolationDelimiterLength: int }
{
conditionalDefines: string list
resourceManager: LexResourceManager
diagnosticsLogger: DiagnosticsLogger
applyLineDirectives: bool
pathMap: PathMap
mutable ifdefStack: LexerIfdefStack
mutable indentationSyntaxStatus: IndentationAwareSyntaxStatus
mutable stringNest: LexerInterpolatedStringNesting
mutable interpolationDelimiterLength: int
/// Tracks the line number of the last non-whitespace, non-comment token
mutable lastTokenEndLine: int
/// Tracks the end column of the last non-whitespace, non-comment token
mutable lastTokenEndColumn: int
}

type LongUnicodeLexResult =
| SurrogatePair of uint16 * uint16
Expand Down
30 changes: 23 additions & 7 deletions src/Compiler/lex.fsl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ let fail args (lexbuf:UnicodeLexing.Lexbuf) msg dflt =
args.diagnosticsLogger.ErrorR(Error(msg,m))
dflt

/// Update tracking of the last token position for XML doc comment position checking
let updateLastTokenPos (args: LexArgs) (lexbuf: UnicodeLexing.Lexbuf) =
let endPos = lexbuf.EndPos
args.lastTokenEndLine <- endPos.Line
args.lastTokenEndColumn <- endPos.Column

//--------------------------
// Integer parsing

Expand Down Expand Up @@ -412,6 +418,7 @@ rule token (args: LexArgs) (skip: bool) = parse
| int
{ let s = removeUnderscores (lexeme lexbuf)
// Allow <max_int+1> to parse as min_int. Allowed only because we parse '-' as an operator.
updateLastTokenPos args lexbuf
if Ranges.isInt32BadMax s then INT32(Int32.MinValue, true (* 'true' = 'bad'*) ) else
let n =
try int32 s with _ -> fail args lexbuf (FSComp.SR.lexOutsideThirtyTwoBitSigned()) 0
Expand All @@ -422,6 +429,7 @@ rule token (args: LexArgs) (skip: bool) = parse
| int32
{ let s = removeUnderscores (lexemeTrimRight lexbuf 1)
// Allow <max_int+1> to parse as min_int. Allowed only because we parse '-' as an operator.
updateLastTokenPos args lexbuf
if Ranges.isInt32BadMax s then INT32(Int32.MinValue, true (* 'true' = 'bad'*) ) else
let n =
try int32 s with _ -> fail args lexbuf (FSComp.SR.lexOutsideThirtyTwoBitSigned()) 0
Expand Down Expand Up @@ -484,10 +492,12 @@ rule token (args: LexArgs) (skip: bool) = parse
}

| ieee64
{ IEEE64 (try float(lexeme lexbuf) with _ -> fail args lexbuf (FSComp.SR.lexInvalidFloat()) 0.0) }
{ updateLastTokenPos args lexbuf
IEEE64 (try float(lexeme lexbuf) with _ -> fail args lexbuf (FSComp.SR.lexInvalidFloat()) 0.0) }

| decimal
{ try
{ updateLastTokenPos args lexbuf
try
let s = removeUnderscores (lexemeTrimRight lexbuf 1)
// This implements a range check for decimal literals
let d = System.Decimal.Parse(s,System.Globalization.NumberStyles.AllowExponent ||| System.Globalization.NumberStyles.Number,System.Globalization.CultureInfo.InvariantCulture)
Expand Down Expand Up @@ -740,6 +750,10 @@ rule token (args: LexArgs) (skip: bool) = parse
| "///" op_char*
{ // Match exactly 3 slash, 4+ slash caught by preceding rule
let m = lexbuf.LexemeRange
// Check if there was a token on this line before this /// comment
// If lastTokenEndLine matches the current line, there's code before the comment
if args.lastTokenEndLine = m.StartLine then
warning (Error(FSComp.SR.xmlDocNotFirstOnLine(), m))
let doc = lexemeTrimLeft lexbuf 3
let sb = (new StringBuilder(100)).Append(doc)
if not skip then LINE_COMMENT (LexCont.SingleLineComment(args.ifdefStack, args.stringNest, 1, m))
Expand Down Expand Up @@ -852,7 +866,7 @@ rule token (args: LexArgs) (skip: bool) = parse

| '(' { LPAREN }

| ')' { RPAREN }
| ')' { updateLastTokenPos args lexbuf; RPAREN }

| '*' { STAR }

Expand Down Expand Up @@ -910,13 +924,13 @@ rule token (args: LexArgs) (skip: bool) = parse

| "[<" { LBRACK_LESS }

| "]" { RBRACK }
| "]" { updateLastTokenPos args lexbuf; RBRACK }

| "|]" { BAR_RBRACK }
| "|]" { updateLastTokenPos args lexbuf; BAR_RBRACK }

| "|}" { BAR_RBRACE }
| "|}" { updateLastTokenPos args lexbuf; BAR_RBRACE }

| ">]" { GREATER_RBRACK }
| ">]" { updateLastTokenPos args lexbuf; GREATER_RBRACK }

| "{"
{
Expand Down Expand Up @@ -966,10 +980,12 @@ rule token (args: LexArgs) (skip: bool) = parse
// will be reported w.r.t. the first '{'
args.stringNest <- (counter - 1, style, d, altR, m) :: rest
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
updateLastTokenPos args lexbuf
RBRACE cont

| _ ->
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
updateLastTokenPos args lexbuf
RBRACE cont
}

Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.tr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.zh-Hans.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.zh-Hant.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion tests/AheadOfTime/Trimming/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8262,7 +8262,7 @@ let func7000()=
test "test7935" (lazy(sprintf "%+0G" -10.0M)) "-10"
test "test7936" (lazy(sprintf "%+05G" -10.0M)) "-0010"// "00-10"
test "test7937" (lazy(sprintf "%+01G" -10.0M)) "-10"
test "test7938" (lazy(sprintf "%+0*G" 7 -10.0M)) "-000010"/// "0000-10"
test "test7938" (lazy(sprintf "%+0*G" 7 -10.0M)) "-000010"// "0000-10"
test "test7939" (lazy(sprintf "%+0.5G" -10.0M)) "-10"
test "test7940" (lazy(sprintf "%+0.*G" 4 -10.0M)) "-10"
test "test7941" (lazy(sprintf "%+0*.*G" 5 4 -10.0M)) "-0010"// "00-10"
Expand Down
Loading
Loading