diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index 81c777c3685..3484ae3acfd 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -1519,7 +1519,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 diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 512e9b4dca7..16701252d0b 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -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." diff --git a/src/Compiler/SyntaxTree/LexHelpers.fs b/src/Compiler/SyntaxTree/LexHelpers.fs index a4c222720ac..f3d53faf285 100644 --- a/src/Compiler/SyntaxTree/LexHelpers.fs +++ b/src/Compiler/SyntaxTree/LexHelpers.fs @@ -63,6 +63,8 @@ type LexArgs = mutable indentationSyntaxStatus: IndentationAwareSyntaxStatus mutable stringNest: LexerInterpolatedStringNesting mutable interpolationDelimiterLength: int + /// Tracks the line number of the last non-whitespace token seen + mutable lastNonWhitespaceTokenLine: int } /// possible results of lexing a long Unicode escape sequence in a string literal, e.g. "\U0001F47D", @@ -85,6 +87,7 @@ let mkLexargs stringNest = [] pathMap = pathMap interpolationDelimiterLength = 0 + lastNonWhitespaceTokenLine = 0 } /// Register the lexbuf and call the given function @@ -445,9 +448,13 @@ module Keywords = if IsCompilerGeneratedName s then warning (Error(FSComp.SR.lexhlpIdentifiersContainingAtSymbolReserved (), lexbuf.LexemeRange)) + // Track that we've seen a non-whitespace token on this line + args.lastNonWhitespaceTokenLine <- lexbuf.StartPos.Line args.resourceManager.InternIdentifierToken s let KeywordOrIdentifierToken args (lexbuf: Lexbuf) s = + // Track that we've seen a non-whitespace token on this line + args.lastNonWhitespaceTokenLine <- lexbuf.StartPos.Line match keywordTable.TryGetValue s with | true, v -> match v with diff --git a/src/Compiler/SyntaxTree/LexHelpers.fsi b/src/Compiler/SyntaxTree/LexHelpers.fsi index 2fe067d244a..6dba76830a0 100644 --- a/src/Compiler/SyntaxTree/LexHelpers.fsi +++ b/src/Compiler/SyntaxTree/LexHelpers.fsi @@ -37,7 +37,9 @@ type LexArgs = mutable ifdefStack: LexerIfdefStack mutable indentationSyntaxStatus: IndentationAwareSyntaxStatus mutable stringNest: LexerInterpolatedStringNesting - mutable interpolationDelimiterLength: int } + mutable interpolationDelimiterLength: int + /// Tracks the line number of the last non-whitespace token seen + mutable lastNonWhitespaceTokenLine: int } type LongUnicodeLexResult = | SurrogatePair of uint16 * uint16 diff --git a/src/Compiler/lex.fsl b/src/Compiler/lex.fsl index 1f905bc049a..a49bfcbf7df 100644 --- a/src/Compiler/lex.fsl +++ b/src/Compiler/lex.fsl @@ -192,6 +192,15 @@ let tryAppendXmlDoc (buff: (range * StringBuilder) option) (s:string) = | None -> () | Some (_, sb) -> ignore(sb.Append s) +/// Check if XML doc comment is positioned after code on the same line +let checkXmlDocLinePosition (args: LexArgs) (lexbuf: UnicodeLexing.Lexbuf) = + let currentLine = lexbuf.StartPos.Line + // If a non-whitespace token was seen on this line before this /// comment, + // then the /// is incorrectly positioned + if args.lastNonWhitespaceTokenLine = currentLine then + let m = lexbuf.LexemeRange + warning (Error(FSComp.SR.xmlDocNotFirstOnLine(), m)) + // Utilities for parsing #if/#else/#endif let shouldStartLine args lexbuf (m:range) err = @@ -740,6 +749,7 @@ rule token (args: LexArgs) (skip: bool) = parse | "///" op_char* { // Match exactly 3 slash, 4+ slash caught by preceding rule let m = lexbuf.LexemeRange + checkXmlDocLinePosition args lexbuf 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)) diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 244be90e142..9ddd2fed1a2 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -2037,6 +2037,11 @@ Tento komentář XML není platný: chybí atribut name pro parametr nebo odkaz na parametr + + XML documentation comments should be the first non-whitespace text on a line. + XML documentation comments should be the first non-whitespace text on a line. + + This XML comment is invalid: unresolved cross-reference '{0}' Tento komentář XML není platný: nepřeložený křížový odkaz {0} diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index d1b1782d093..c57c10614f5 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -2037,6 +2037,11 @@ Dieser XML-Kommentar ist ungültig: Attribut "name" für Parameter oder Parameterverweis fehlt. + + XML documentation comments should be the first non-whitespace text on a line. + XML documentation comments should be the first non-whitespace text on a line. + + This XML comment is invalid: unresolved cross-reference '{0}' Dieser XML-Kommentar ist ungültig: nicht aufgelöster Querverweis "{0}". diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index cd311cc7fc5..15b9db05ec1 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -2037,6 +2037,11 @@ El comentario XML no es válido: falta el atributo "name" para el parámetro o la referencia de parámetro + + XML documentation comments should be the first non-whitespace text on a line. + XML documentation comments should be the first non-whitespace text on a line. + + This XML comment is invalid: unresolved cross-reference '{0}' El comentario XML no es válido: la referencia cruzada "{0}" no se ha resuelto diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index e05e9ecdf6c..028a942abd4 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -2037,6 +2037,11 @@ Ce commentaire XML est non valide : attribut 'name' manquant pour le paramètre ou la référence de paramètre + + XML documentation comments should be the first non-whitespace text on a line. + XML documentation comments should be the first non-whitespace text on a line. + + This XML comment is invalid: unresolved cross-reference '{0}' Ce commentaire XML est non valide : référence croisée non résolue '{0}' diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index a25fd816046..51c0e773cce 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -2037,6 +2037,11 @@ Questo commento XML non è valido: manca l'attributo 'name' per il parametro o il riferimento a parametro + + XML documentation comments should be the first non-whitespace text on a line. + XML documentation comments should be the first non-whitespace text on a line. + + This XML comment is invalid: unresolved cross-reference '{0}' Questo commento XML non è valido: il riferimento incrociato '{0}' non è stato risolto diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 87b7d40df1e..23ac619d8eb 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -2037,6 +2037,11 @@ この XML コメントは無効です: パラメーターまたはパラメーター参照に 'name' 属性がありません + + XML documentation comments should be the first non-whitespace text on a line. + XML documentation comments should be the first non-whitespace text on a line. + + This XML comment is invalid: unresolved cross-reference '{0}' この XML コメントは無効です: 相互参照 '{0}' が未解決です diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index f2fe6e20f97..2b329be44e3 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -2037,6 +2037,11 @@ 이 XML 주석이 잘못됨: 매개 변수 또는 매개 변수 참조에 'name' 특성이 없음 + + XML documentation comments should be the first non-whitespace text on a line. + XML documentation comments should be the first non-whitespace text on a line. + + This XML comment is invalid: unresolved cross-reference '{0}' 이 XML 주석이 잘못됨: 확인되지 않은 상호 참조 '{0}' diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 23a194ff258..d70411255f7 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -2037,6 +2037,11 @@ Ten komentarz XML jest nieprawidłowy: brak atrybutu „name” dla parametru lub odwołania parametru + + XML documentation comments should be the first non-whitespace text on a line. + XML documentation comments should be the first non-whitespace text on a line. + + This XML comment is invalid: unresolved cross-reference '{0}' Ten komentarz XML jest nieprawidłowy: nierozpoznany odsyłacz „{0}” diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 503fc0f073f..608b56e9d3c 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -2037,6 +2037,11 @@ Este comentário XML é inválido: atributo 'name' ausente para parâmetro ou referência de parâmetro + + XML documentation comments should be the first non-whitespace text on a line. + XML documentation comments should be the first non-whitespace text on a line. + + This XML comment is invalid: unresolved cross-reference '{0}' Este comentário XML é inválido: referência cruzada não resolvida '{0}' diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 7013fb0bc83..1e778b36445 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -2037,6 +2037,11 @@ Недопустимый XML-комментарий: отсутствует атрибут "name" для параметра или ссылки на параметр + + XML documentation comments should be the first non-whitespace text on a line. + XML documentation comments should be the first non-whitespace text on a line. + + This XML comment is invalid: unresolved cross-reference '{0}' Недопустимый XML-комментарий: неразрешенная перекрестная ссылка "{0}" diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 49d2a295b45..1caee47ce9b 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -2037,6 +2037,11 @@ Bu XML açıklaması geçersiz: Parametre veya parametre başvurusu için 'name' özniteliği eksik + + XML documentation comments should be the first non-whitespace text on a line. + XML documentation comments should be the first non-whitespace text on a line. + + This XML comment is invalid: unresolved cross-reference '{0}' Bu XML açıklaması geçersiz: '{0}' çapraz başvurusu çözümlenmemiş diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 3fc65eebc96..62e016388f7 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -2037,6 +2037,11 @@ 此 XML 注释无效: 参数或参数引用缺少 "name" 属性 + + XML documentation comments should be the first non-whitespace text on a line. + XML documentation comments should be the first non-whitespace text on a line. + + This XML comment is invalid: unresolved cross-reference '{0}' 此 XML 注释无效: 交叉引用“{0}”无法解析 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 07fea0efd23..7256c4709a6 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -2037,6 +2037,11 @@ 此 XML 註解無效: 參數或參數參考沒有 'name' 屬性 + + XML documentation comments should be the first non-whitespace text on a line. + XML documentation comments should be the first non-whitespace text on a line. + + This XML comment is invalid: unresolved cross-reference '{0}' 此 XML 註解無效: 未解析的交互參照 '{0}' diff --git a/tests/FSharp.Compiler.ComponentTests/Language/XmlDocCommentPositionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/XmlDocCommentPositionTests.fs new file mode 100644 index 00000000000..86d8df8c238 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/XmlDocCommentPositionTests.fs @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.ComponentTests.Language + +open Xunit +open FSharp.Test + +module XmlDocCommentPositionTests = + + [] + let ``XML doc comment after code should warn``() = + FSharp """ +let x = 42 /// This should trigger warning +""" + |> compile + |> shouldFail + |> withDiagnostics [ + (Warning 3879, Line 2, Col 29, Line 2, Col 62, "XML documentation comments should be the first non-whitespace text on a line.") + ] + + [] + let ``XML doc comment at start of line should not warn``() = + FSharp """ +/// This is proper documentation +let x = 42 +""" + |> compile + |> shouldSucceed + + [] + let ``XML doc comment with indentation should not warn``() = + FSharp """ +module Test = + /// This is properly indented + let x = 42 +""" + |> compile + |> shouldSucceed + + [] + let ``XML doc comment after let binding should warn``() = + FSharp """ +let value = "test" /// Bad position +""" + |> compile + |> shouldFail + |> withDiagnostics [ + (Warning 3879, Line 2, Col 29, Line 2, Col 45, "XML documentation comments should be the first non-whitespace text on a line.") + ] + + [] + let ``Regular comment after code should not warn``() = + FSharp """ +let x = 42 // This is a regular comment, not XML doc +""" + |> compile + |> shouldSucceed + + [] + let ``Regular comment with double slash after code should not warn``() = + FSharp """ +let value = "test" // Regular comment +let other = value + "more" // Another regular comment +""" + |> compile + |> shouldSucceed + + [] + let ``Multiple regular comments after code should not warn``() = + FSharp """ +module Test = + let x = 1 // comment 1 + let y = 2 // comment 2 + let z = x + y // result +""" + |> compile + |> shouldSucceed + + [] + let ``Four slash comment after code should not warn``() = + FSharp """ +let x = 42 //// This is a four-slash comment, not XML doc +""" + |> compile + |> shouldSucceed \ No newline at end of file