Skip to content

Commit fd6eb11

Browse files
authored
Display signature xmldoc for implementation symbol when implementation xmldoc is missing. (#14711)
1 parent 2cd8fb4 commit fd6eb11

File tree

6 files changed

+94
-2
lines changed

6 files changed

+94
-2
lines changed

src/Compiler/Checking/SignatureConformance.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ type Checker(g, amap, denv, remapInfo: SignatureRepackageInfo, checkingSig) =
322322
// Propagate defn location information from implementation to signature .
323323
sigVal.SetOtherRange (implVal.Range, true)
324324
implVal.SetOtherRange (sigVal.Range, false)
325+
implVal.SetOtherXmlDoc(sigVal.XmlDoc)
325326

326327
let mk_err denv f = ValueNotContained(denv, infoReader, implModRef, implVal, sigVal, f)
327328
let err denv f = errorR(mk_err denv f); false

src/Compiler/TypedTree/TypedTree.fs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2545,7 +2545,10 @@ type ValOptionalData =
25452545

25462546
/// XML documentation attached to a value.
25472547
/// MUTABILITY: for unpickle linkage
2548-
mutable val_xmldoc: XmlDoc
2548+
mutable val_xmldoc: XmlDoc
2549+
2550+
/// the signature xml doc for an item in an implementation file.
2551+
mutable val_other_xmldoc : XmlDoc option
25492552

25502553
/// Is the value actually an instance method/property/event that augments
25512554
/// a type, and if so what name does it take in the IL?
@@ -2601,6 +2604,7 @@ type Val =
26012604
val_repr_info_for_display = None
26022605
val_access = TAccess []
26032606
val_xmldoc = XmlDoc.Empty
2607+
val_other_xmldoc = None
26042608
val_member_info = None
26052609
val_declaring_entity = ParentNone
26062610
val_xmldocsig = String.Empty
@@ -2835,7 +2839,13 @@ type Val =
28352839
/// Get the declared documentation for the value
28362840
member x.XmlDoc =
28372841
match x.val_opt_data with
2838-
| Some optData -> optData.val_xmldoc
2842+
| Some optData ->
2843+
if not optData.val_xmldoc.IsEmpty then
2844+
optData.val_xmldoc
2845+
else
2846+
match optData.val_other_xmldoc with
2847+
| Some xmlDoc -> xmlDoc
2848+
| None -> XmlDoc.Empty
28392849
| _ -> XmlDoc.Empty
28402850

28412851
///Get the signature for the value's XML documentation
@@ -3065,6 +3075,11 @@ type Val =
30653075
| Some optData -> optData.val_other_range <- Some m
30663076
| _ -> x.val_opt_data <- Some { Val.NewEmptyValOptData() with val_other_range = Some m }
30673077

3078+
member x.SetOtherXmlDoc xmlDoc =
3079+
match x.val_opt_data with
3080+
| Some optData -> optData.val_other_xmldoc <- Some xmlDoc
3081+
| _ -> x.val_opt_data <- Some { Val.NewEmptyValOptData() with val_other_xmldoc = Some xmlDoc }
3082+
30683083
member x.SetDeclaringEntity parent =
30693084
match x.val_opt_data with
30703085
| Some optData -> optData.val_declaring_entity <- parent
@@ -3119,6 +3134,7 @@ type Val =
31193134
val_repr_info = tg.val_repr_info
31203135
val_access = tg.val_access
31213136
val_xmldoc = tg.val_xmldoc
3137+
val_other_xmldoc = tg.val_other_xmldoc
31223138
val_member_info = tg.val_member_info
31233139
val_declaring_entity = tg.val_declaring_entity
31243140
val_xmldocsig = tg.val_xmldocsig

src/Compiler/TypedTree/TypedTree.fsi

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1820,6 +1820,9 @@ type ValOptionalData =
18201820
/// MUTABILITY: for unpickle linkage
18211821
mutable val_xmldoc: XmlDoc
18221822

1823+
/// the signature xml doc for an item in an implementation file.
1824+
mutable val_other_xmldoc: XmlDoc option
1825+
18231826
/// Is the value actually an instance method/property/event that augments
18241827
/// a type, type if so what name does it take in the IL?
18251828
/// MUTABILITY: for unpickle linkage
@@ -1913,6 +1916,8 @@ type Val =
19131916

19141917
member SetOtherRange: m: (range * bool) -> unit
19151918

1919+
member SetOtherXmlDoc: xmlDoc: XmlDoc -> unit
1920+
19161921
member SetType: ty: TType -> unit
19171922

19181923
member SetValDefn: val_defn: Expr -> unit

src/Compiler/TypedTree/TypedTreePickle.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2262,6 +2262,7 @@ and u_ValData st =
22622262
val_const = x14
22632263
val_access = x13
22642264
val_xmldoc = defaultArg x15 XmlDoc.Empty
2265+
val_other_xmldoc = None
22652266
val_member_info = x8
22662267
val_declaring_entity = x13b
22672268
val_xmldocsig = x12

tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@
186186
<Compile Include="..\service\PrettyNaming.fs">
187187
<Link>PrettyNaming.fs</Link>
188188
</Compile>
189+
<Compile Include="TooltipTests.fs" />
189190
<Compile Include="..\service\Program.fs">
190191
<Link>Program.fs</Link>
191192
</Compile>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
module FSharp.Compiler.Service.Tests.TooltipTests
2+
3+
#nowarn "57"
4+
5+
open FSharp.Compiler.CodeAnalysis
6+
open FSharp.Compiler.Service.Tests.Common
7+
open FSharp.Compiler.Text
8+
open FSharp.Compiler.Tokenization
9+
open FSharp.Compiler.EditorServices
10+
open FSharp.Compiler.Symbols
11+
open NUnit.Framework
12+
13+
[<Test>]
14+
let ``Display XML doc of signature file if implementation doesn't have one`` () =
15+
let files =
16+
Map.ofArray
17+
[| "A.fsi",
18+
SourceText.ofString
19+
"""
20+
module Foo
21+
22+
/// Great XML doc comment
23+
val bar: a: int -> b: int -> int
24+
"""
25+
26+
"A.fs",
27+
SourceText.ofString
28+
"""
29+
module Foo
30+
31+
// No XML doc here because the signature file has one right?
32+
let bar a b = a - b
33+
""" |]
34+
35+
let documentSource fileName = Map.tryFind fileName files
36+
37+
let projectOptions =
38+
let _, projectOptions = mkTestFileAndOptions "" Array.empty
39+
40+
{ projectOptions with
41+
SourceFiles = [| "A.fsi"; "A.fs" |] }
42+
43+
let checker =
44+
FSharpChecker.Create(documentSource = DocumentSource.Custom documentSource)
45+
46+
let checkResult =
47+
checker.ParseAndCheckFileInProject("A.fs", 0, Map.find "A.fs" files, projectOptions)
48+
|> Async.RunImmediate
49+
50+
match checkResult with
51+
| _, FSharpCheckFileAnswer.Succeeded(checkResults) ->
52+
let barSymbol = findSymbolByName "bar" checkResults
53+
54+
match barSymbol with
55+
| :? FSharpMemberOrFunctionOrValue as mfv -> Assert.True mfv.HasSignatureFile
56+
| _ -> Assert.Fail "Expected to find a symbol FSharpMemberOrFunctionOrValue that HasSignatureFile"
57+
58+
// Get the tooltip for `bar` in the implementation file
59+
let (ToolTipText tooltipElements) =
60+
checkResults.GetToolTip(4, 4, "let bar a b = a - b", [ "bar" ], FSharpTokenTag.Identifier)
61+
62+
match tooltipElements with
63+
| [ ToolTipElement.Group [ element ] ] ->
64+
match element.XmlDoc with
65+
| FSharpXmlDoc.FromXmlText xmlDoc -> Assert.True xmlDoc.NonEmpty
66+
| xmlDoc -> Assert.Fail $"Expected FSharpXmlDoc.FromXmlText, got {xmlDoc}"
67+
| elements -> Assert.Fail $"Expected a single tooltip group element, got {elements}"
68+
| _ -> Assert.Fail "Expected checking to succeed."

0 commit comments

Comments
 (0)