Skip to content

Commit f007405

Browse files
authored
More improve completion after method/property override (#18341)
1 parent 27aa9be commit f007405

31 files changed

+429
-164
lines changed

docs/release-notes/.FSharp.Compiler.Service/9.0.300.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
* Nullness warnings are issued for signature<>implementation conformance ([PR #18186](https://github.com/dotnet/fsharp/pull/18186))
2727
* Symbols: Add FSharpAssembly.IsFSharp ([PR #18290](https://github.com/dotnet/fsharp/pull/18290))
2828
* Type parameter constraint `null` in generic code will now automatically imply `not struct` ([Issue #18320](https://github.com/dotnet/fsharp/issues/18320), [PR #18323](https://github.com/dotnet/fsharp/pull/18323))
29+
* Add a switch to determine whether to generate a default implementation body for overridden method when completing. [PR #18341](https://github.com/dotnet/fsharp/pull/18341)
30+
2931

3032
### Changed
3133

@@ -35,6 +37,7 @@
3537
* Added nullability annotations to `.Using` builder method for `async`, `task` and compiler-internal builders ([PR #18292](https://github.com/dotnet/fsharp/pull/18292))
3638
* Warn when `unit` is passed to an `obj`-typed argument ([PR #18330](https://github.com/dotnet/fsharp/pull/18330))
3739
* Warning for "useless null handling" works with piped syntax constructs now ([PR #18331](https://github.com/dotnet/fsharp/pull/18331))
40+
* Make indent in generated overridden member code depend on the context, not fix to 4. ([PR #18341](https://github.com/dotnet/fsharp/pull/18341))
3841
* Adjust caller info attribute error message range ([PR #18388](https://github.com/dotnet/fsharp/pull/18388))
3942

4043
### Breaking Changes
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
### Fixed
2+
3+
### Added
4+
* Add a switch to determine whether to generate a default implementation body for overridden method when completing. [PR #18341](https://github.com/dotnet/fsharp/pull/18341)
5+
6+
### Changed
7+
* Make indent in generated overridden member code depend on the context, not fix to 4. ([PR #18341](https://github.com/dotnet/fsharp/pull/18341))
8+
9+
### Breaking Changes

src/Compiler/Service/FSharpCheckerResults.fs

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,7 +1063,7 @@ type internal TypeCheckInfo
10631063
|> Option.defaultValue completions
10641064

10651065
/// Gets all methods that a type can override, but has not yet done so.
1066-
let GetOverridableMethods pos ctx (typeNameRange: range) spacesBeforeOverrideKeyword hasThis isStatic =
1066+
let GetOverridableMethods pos ctx (typeNameRange: range) newlineIndentCount hasThis isStatic genBodyForOverriddenMeth =
10671067
let checkImplementedSlotDeclareType ty slots =
10681068
slots
10691069
|> Option.map (List.exists (fun (TSlotSig(declaringType = ty2)) -> typeEquiv g ty ty2))
@@ -1111,17 +1111,20 @@ type internal TypeCheckInfo
11111111
let (nenv, ad), m = GetBestEnvForPos pos
11121112
let denv = nenv.DisplayEnv
11131113

1114+
/// Check if the method is abstract, return "raise (NotImplementedException())" if it is abstract, otherwise return the given body
11141115
let checkMethAbstractAndGetImplementBody (meth: MethInfo) implementBody =
1115-
if meth.IsAbstract then
1116+
if not genBodyForOverriddenMeth then
1117+
String.Empty
1118+
elif meth.IsAbstract then
11161119
if nenv.DisplayEnv.openTopPathsSorted.Force() |> List.contains [ "System" ] then
11171120
"raise (NotImplementedException())"
11181121
else
11191122
"raise (System.NotImplementedException())"
11201123
else
11211124
implementBody
11221125

1123-
let newlineIndent =
1124-
Environment.NewLine + String.make (spacesBeforeOverrideKeyword + 4) ' '
1126+
let newlineIndentCount = max 1 newlineIndentCount
1127+
let newlineIndent = Environment.NewLine + String.make newlineIndentCount ' '
11251128

11261129
let getOverridableMethods superTy (overriddenMethods: MethInfo list) overriddenProperties =
11271130
// Do not check a method with same name twice
@@ -1197,12 +1200,6 @@ type internal TypeCheckInfo
11971200

11981201
let this = if hasThis || prop.IsStatic then String.Empty else "this."
11991202

1200-
let getterWithBody =
1201-
if String.IsNullOrWhiteSpace getterWithBody then
1202-
String.Empty
1203-
else
1204-
getterWithBody + newlineIndent
1205-
12061203
let name = $"{prop.DisplayName} with {getter}{keywordAnd}{setter}"
12071204

12081205
let textInCode =
@@ -1211,6 +1208,10 @@ type internal TypeCheckInfo
12111208
+ newlineIndent
12121209
+ "with "
12131210
+ getterWithBody
1211+
+ (if String.IsNullOrEmpty keywordAnd then
1212+
String.Empty
1213+
else
1214+
newlineIndent)
12141215
+ keywordAnd
12151216
+ setterWithBody
12161217

@@ -1721,7 +1722,8 @@ type internal TypeCheckInfo
17211722
filterCtors,
17221723
resolveOverloads,
17231724
completionContextAtPos: (pos * CompletionContext option) option,
1724-
getAllSymbols: unit -> AssemblySymbol list
1725+
getAllSymbols: unit -> AssemblySymbol list,
1726+
genBodyForOverriddenMeth
17251727
) : (CompletionItem list * DisplayEnv * CompletionContext option * range) option =
17261728

17271729
let loc =
@@ -1957,8 +1959,22 @@ type internal TypeCheckInfo
19571959
getDeclaredItemsNotInRangeOpWithAllSymbols ()
19581960
|> Option.bind (FilterRelevantItemsBy getItem2 None IsPatternCandidate)
19591961

1960-
| Some(CompletionContext.MethodOverride(ctx, enclosingTypeNameRange, spacesBeforeOverrideKeyword, hasThis, isStatic)) ->
1961-
GetOverridableMethods pos ctx enclosingTypeNameRange spacesBeforeOverrideKeyword hasThis isStatic
1962+
| Some(CompletionContext.MethodOverride(ctx,
1963+
enclosingTypeNameRange,
1964+
spacesBeforeOverrideKeyword,
1965+
hasThis,
1966+
isStatic,
1967+
spacesBeforeEnclosingDefinition)) ->
1968+
let indent = max 1 (spacesBeforeOverrideKeyword - spacesBeforeEnclosingDefinition)
1969+
1970+
GetOverridableMethods
1971+
pos
1972+
ctx
1973+
enclosingTypeNameRange
1974+
(spacesBeforeOverrideKeyword + indent)
1975+
hasThis
1976+
isStatic
1977+
genBodyForOverriddenMeth
19621978

19631979
// Other completions
19641980
| cc ->
@@ -2025,7 +2041,16 @@ type internal TypeCheckInfo
20252041
scope.IsRelativeNameResolvable(cursorPos, plid, symbol.Item)
20262042

20272043
/// Get the auto-complete items at a location
2028-
member _.GetDeclarations(parseResultsOpt, line, lineStr, partialName, completionContextAtPos, getAllEntities) =
2044+
member _.GetDeclarations
2045+
(
2046+
parseResultsOpt,
2047+
line,
2048+
lineStr,
2049+
partialName,
2050+
completionContextAtPos,
2051+
getAllEntities,
2052+
genBodyForOverriddenMeth
2053+
) =
20292054
let isSigFile = SourceFileImpl.IsSignatureFile mainInputFileName
20302055

20312056
DiagnosticsScope.Protect
@@ -2044,7 +2069,8 @@ type internal TypeCheckInfo
20442069
ResolveTypeNamesToCtors,
20452070
ResolveOverloads.Yes,
20462071
completionContextAtPos,
2047-
getAllEntities
2072+
getAllEntities,
2073+
genBodyForOverriddenMeth
20482074
)
20492075

20502076
match declItemsOpt with
@@ -2085,7 +2111,7 @@ type internal TypeCheckInfo
20852111
DeclarationListInfo.Error msg)
20862112

20872113
/// Get the symbols for auto-complete items at a location
2088-
member _.GetDeclarationListSymbols(parseResultsOpt, line, lineStr, partialName, getAllEntities) =
2114+
member _.GetDeclarationListSymbols(parseResultsOpt, line, lineStr, partialName, getAllEntities, genBodyForOverriddenMeth) =
20892115
let isSigFile = SourceFileImpl.IsSignatureFile mainInputFileName
20902116

20912117
DiagnosticsScope.Protect
@@ -2104,7 +2130,8 @@ type internal TypeCheckInfo
21042130
ResolveTypeNamesToCtors,
21052131
ResolveOverloads.Yes,
21062132
None,
2107-
getAllEntities
2133+
getAllEntities,
2134+
genBodyForOverriddenMeth
21082135
)
21092136

21102137
match declItemsOpt with
@@ -2285,7 +2312,8 @@ type internal TypeCheckInfo
22852312
ResolveTypeNamesToCtors,
22862313
ResolveOverloads.Yes,
22872314
None,
2288-
(fun () -> [])
2315+
(fun () -> []),
2316+
false
22892317
)
22902318

22912319
match declItemsOpt with
@@ -2347,7 +2375,8 @@ type internal TypeCheckInfo
23472375
ResolveTypeNamesToCtors,
23482376
ResolveOverloads.No,
23492377
None,
2350-
(fun () -> [])
2378+
(fun () -> []),
2379+
false
23512380
)
23522381

23532382
match declItemsOpt with
@@ -2393,7 +2422,8 @@ type internal TypeCheckInfo
23932422
ResolveTypeNamesToCtors,
23942423
ResolveOverloads.No,
23952424
None,
2396-
(fun () -> [])
2425+
(fun () -> []),
2426+
false
23972427
)
23982428

23992429
match declItemsOpt with
@@ -2434,7 +2464,8 @@ type internal TypeCheckInfo
24342464
ResolveTypeNamesToCtors,
24352465
ResolveOverloads.No,
24362466
None,
2437-
(fun () -> [])
2467+
(fun () -> []),
2468+
false
24382469
)
24392470

24402471
match declItemsOpt with
@@ -2470,7 +2501,8 @@ type internal TypeCheckInfo
24702501
ResolveTypeNamesToCtors,
24712502
ResolveOverloads.Yes,
24722503
None,
2473-
(fun () -> [])
2504+
(fun () -> []),
2505+
false
24742506
)
24752507

24762508
match declItemsOpt with
@@ -2618,7 +2650,8 @@ type internal TypeCheckInfo
26182650
ResolveTypeNamesToCtors,
26192651
ResolveOverloads.Yes,
26202652
None,
2621-
(fun () -> [])
2653+
(fun () -> []),
2654+
false
26222655
)
26232656

26242657
match declItemsOpt with
@@ -2647,7 +2680,8 @@ type internal TypeCheckInfo
26472680
ResolveTypeNamesToCtors,
26482681
ResolveOverloads.Yes,
26492682
None,
2650-
(fun () -> [])
2683+
(fun () -> []),
2684+
false
26512685
)
26522686

26532687
match declItemsOpt with
@@ -3348,20 +3382,40 @@ type FSharpCheckFileResults
33483382
| Some(scope, _builderOpt) -> Some scope.TcImports
33493383

33503384
/// Intellisense autocompletions
3351-
member _.GetDeclarationListInfo(parsedFileResults, line, lineText, partialName, ?getAllEntities, ?completionContextAtPos) =
3385+
member _.GetDeclarationListInfo
3386+
(
3387+
parsedFileResults,
3388+
line,
3389+
lineText,
3390+
partialName,
3391+
?getAllEntities,
3392+
?completionContextAtPos,
3393+
?genBodyForOverriddenMeth
3394+
) =
33523395
let getAllEntities = defaultArg getAllEntities (fun () -> [])
3396+
let genBodyForOverriddenMeth = defaultArg genBodyForOverriddenMeth true
33533397

33543398
match details with
33553399
| None -> DeclarationListInfo.Empty
33563400
| Some(scope, _builderOpt) ->
3357-
scope.GetDeclarations(parsedFileResults, line, lineText, partialName, completionContextAtPos, getAllEntities)
3401+
scope.GetDeclarations(
3402+
parsedFileResults,
3403+
line,
3404+
lineText,
3405+
partialName,
3406+
completionContextAtPos,
3407+
getAllEntities,
3408+
genBodyForOverriddenMeth
3409+
)
33583410

3359-
member _.GetDeclarationListSymbols(parsedFileResults, line, lineText, partialName, ?getAllEntities) =
3411+
member _.GetDeclarationListSymbols(parsedFileResults, line, lineText, partialName, ?getAllEntities, ?genBodyForOverriddenMeth) =
33603412
let getAllEntities = defaultArg getAllEntities (fun () -> [])
3413+
let genBodyForOverriddenMeth = defaultArg genBodyForOverriddenMeth true
33613414

33623415
match details with
33633416
| None -> []
3364-
| Some(scope, _builderOpt) -> scope.GetDeclarationListSymbols(parsedFileResults, line, lineText, partialName, getAllEntities)
3417+
| Some(scope, _builderOpt) ->
3418+
scope.GetDeclarationListSymbols(parsedFileResults, line, lineText, partialName, getAllEntities, genBodyForOverriddenMeth)
33653419

33663420
member _.GetKeywordTooltip(names: string list) =
33673421
ToolTipText.ToolTipText

src/Compiler/Service/FSharpCheckerResults.fsi

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,13 +290,17 @@ type public FSharpCheckFileResults =
290290
/// <param name="completionContextAtPos">
291291
/// Completion context for a particular position computed in advance.
292292
/// </param>
293+
/// <param name="genBodyForOverriddenMeth">
294+
/// A switch to determine whether to generate a default implementation body for overridden method when completing.
295+
/// </param>
293296
member GetDeclarationListInfo:
294297
parsedFileResults: FSharpParseFileResults option *
295298
line: int *
296299
lineText: string *
297300
partialName: PartialLongName *
298301
?getAllEntities: (unit -> AssemblySymbol list) *
299-
?completionContextAtPos: (pos * CompletionContext option) ->
302+
?completionContextAtPos: (pos * CompletionContext option) *
303+
?genBodyForOverriddenMeth: bool ->
300304
DeclarationListInfo
301305

302306
/// <summary>Get the items for a declaration list in FSharpSymbol format</summary>
@@ -317,12 +321,16 @@ type public FSharpCheckFileResults =
317321
/// <param name="getAllEntities">
318322
/// Function that returns all entities from current and referenced assemblies.
319323
/// </param>
324+
/// <param name="genBodyForOverriddenMeth">
325+
/// A switch to determine whether to generate a default implementation body for overridden method when completing.
326+
/// </param>
320327
member GetDeclarationListSymbols:
321328
parsedFileResults: FSharpParseFileResults option *
322329
line: int *
323330
lineText: string *
324331
partialName: PartialLongName *
325-
?getAllEntities: (unit -> AssemblySymbol list) ->
332+
?getAllEntities: (unit -> AssemblySymbol list) *
333+
?genBodyForOverriddenMeth: bool ->
326334
FSharpSymbolUse list list
327335

328336
/// <summary>Compute a formatted tooltip for the given keywords</summary>

src/Compiler/Service/ServiceParsedInputOps.fs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ type CompletionContext =
118118
enclosingTypeNameRange: range *
119119
spacesBeforeOverrideKeyword: int *
120120
hasThis: bool *
121-
isStatic: bool
121+
isStatic: bool *
122+
spacesBeforeEnclosingDefinition: int
122123

123124
type ShortIdent = string
124125

@@ -1543,7 +1544,8 @@ module ParsedInput =
15431544

15441545
let overrideContext path (mOverride: range) hasThis isStatic isMember =
15451546
match path with
1546-
| _ :: SyntaxNode.SynTypeDefn(SynTypeDefn(typeInfo = SynComponentInfo(longId = [ enclosingType ]))) :: _ when
1547+
| _ :: SyntaxNode.SynTypeDefn(SynTypeDefn(
1548+
typeInfo = SynComponentInfo(longId = [ enclosingType ]); trivia = { LeadingKeyword = keyword })) :: _ when
15471549
not isMember
15481550
->
15491551
Some(
@@ -1552,12 +1554,13 @@ module ParsedInput =
15521554
enclosingType.idRange,
15531555
mOverride.StartColumn,
15541556
hasThis,
1555-
isStatic
1557+
isStatic,
1558+
keyword.Range.StartColumn
15561559
)
15571560
)
1558-
| SyntaxNode.SynMemberDefn(SynMemberDefn.Interface(interfaceType = ty)) :: SyntaxNode.SynTypeDefn(SynTypeDefn(
1561+
| SyntaxNode.SynMemberDefn(SynMemberDefn.Interface(interfaceType = ty) as enclosingDefn) :: SyntaxNode.SynTypeDefn(SynTypeDefn(
15591562
typeInfo = SynComponentInfo(longId = [ enclosingType ]))) :: _
1560-
| _ :: SyntaxNode.SynMemberDefn(SynMemberDefn.Interface(interfaceType = ty)) :: SyntaxNode.SynTypeDefn(SynTypeDefn(
1563+
| _ :: SyntaxNode.SynMemberDefn(SynMemberDefn.Interface(interfaceType = ty) as enclosingDefn) :: SyntaxNode.SynTypeDefn(SynTypeDefn(
15611564
typeInfo = SynComponentInfo(longId = [ enclosingType ]))) :: _ ->
15621565
let ty =
15631566
match ty with
@@ -1570,11 +1573,12 @@ module ParsedInput =
15701573
enclosingType.idRange,
15711574
mOverride.StartColumn,
15721575
hasThis,
1573-
isStatic
1576+
isStatic,
1577+
enclosingDefn.Range.StartColumn
15741578
)
15751579
)
1576-
| SyntaxNode.SynMemberDefn(SynMemberDefn.Interface(interfaceType = ty)) :: (SyntaxNode.SynExpr(SynExpr.ObjExpr _) as expr) :: _
1577-
| _ :: SyntaxNode.SynMemberDefn(SynMemberDefn.Interface(interfaceType = ty)) :: (SyntaxNode.SynExpr(SynExpr.ObjExpr _) as expr) :: _ ->
1580+
| SyntaxNode.SynMemberDefn(SynMemberDefn.Interface(interfaceType = ty) as enclosingDefn) :: (SyntaxNode.SynExpr(SynExpr.ObjExpr _) as expr) :: _
1581+
| _ :: SyntaxNode.SynMemberDefn(SynMemberDefn.Interface(interfaceType = ty) as enclosingDefn) :: (SyntaxNode.SynExpr(SynExpr.ObjExpr _) as expr) :: _ ->
15781582
let ty =
15791583
match ty with
15801584
| SynType.App(typeName = ty) -> ty
@@ -1586,10 +1590,11 @@ module ParsedInput =
15861590
ty.Range,
15871591
mOverride.StartColumn,
15881592
hasThis,
1589-
isStatic
1593+
isStatic,
1594+
enclosingDefn.Range.StartColumn
15901595
)
15911596
)
1592-
| SyntaxNode.SynExpr(SynExpr.ObjExpr(objType = ty)) as expr :: _ ->
1597+
| SyntaxNode.SynExpr(SynExpr.ObjExpr(objType = ty; newExprRange = newExprRange)) as expr :: _ ->
15931598
let ty =
15941599
match ty with
15951600
| SynType.App(typeName = ty) -> ty
@@ -1601,7 +1606,8 @@ module ParsedInput =
16011606
ty.Range,
16021607
mOverride.StartColumn,
16031608
hasThis,
1604-
isStatic
1609+
isStatic,
1610+
newExprRange.StartColumn
16051611
)
16061612
)
16071613
| _ -> Some CompletionContext.Invalid

0 commit comments

Comments
 (0)