Skip to content

Commit a12e07a

Browse files
authored
Implement completions for overrides (#15731)
* Implement completions for overrides * Fix override matching * Refactor, add tests
1 parent 8f75697 commit a12e07a

File tree

6 files changed

+11723
-11529
lines changed

6 files changed

+11723
-11529
lines changed

src/Compiler/Service/FSharpCheckerResults.fs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,47 @@ type internal TypeCheckInfo
10081008
|> List.prependIfSome (CreateCompletionItemForSuggestedPatternName caseIdPos fieldName))
10091009
|> Option.defaultValue completions
10101010

1011+
/// Gets all methods that a type can override, but has not yet done so.
1012+
let GetOverridableMethods pos typeNameRange =
1013+
let isMethodOverridable alreadyOverridden (candidate: MethInfo) =
1014+
not candidate.IsFinal
1015+
&& not (
1016+
alreadyOverridden
1017+
|> List.exists (MethInfosEquivByNameAndSig EraseNone true g amap range0 candidate)
1018+
)
1019+
1020+
let (nenv, ad), m = GetBestEnvForPos pos
1021+
1022+
sResolutions.CapturedNameResolutions
1023+
|> ResizeArray.tryPick (fun r ->
1024+
match r.Item with
1025+
| Item.Types (_, ty :: _) when equals r.Range typeNameRange && isAppTy g ty ->
1026+
let superTy =
1027+
(tcrefOfAppTy g ty).TypeContents.tcaug_super |> Option.defaultValue g.obj_ty
1028+
1029+
let overriddenMethods =
1030+
GetImmediateIntrinsicMethInfosOfType (None, ad) g amap typeNameRange ty
1031+
|> List.filter (fun x -> x.IsDefiniteFSharpOverride)
1032+
1033+
let overridableMethods =
1034+
GetIntrinsicMethInfosOfType
1035+
infoReader
1036+
None
1037+
ad
1038+
TypeHierarchy.AllowMultiIntfInstantiations.No
1039+
FindMemberFlag.PreferOverrides
1040+
range0
1041+
superTy
1042+
|> List.filter (isMethodOverridable overriddenMethods)
1043+
|> List.groupBy (fun x -> x.DisplayName)
1044+
|> List.map (fun (name, overloads) ->
1045+
Item.MethodGroup(name, overloads, None)
1046+
|> ItemWithNoInst
1047+
|> CompletionItem ValueNone ValueNone)
1048+
1049+
Some(overridableMethods, nenv.DisplayEnv, m)
1050+
| _ -> None)
1051+
10111052
let getItem (x: ItemWithInst) = x.Item
10121053

10131054
let GetDeclaredItems
@@ -1559,6 +1600,8 @@ type internal TypeCheckInfo
15591600
| _ -> None)
15601601
|> Option.orElse declaredItems
15611602

1603+
| Some (CompletionContext.MethodOverride enclosingTypeNameRange) -> GetOverridableMethods pos enclosingTypeNameRange
1604+
15621605
// Other completions
15631606
| cc ->
15641607
match residueOpt |> Option.bind Seq.tryHead with
@@ -1664,7 +1707,10 @@ type internal TypeCheckInfo
16641707
|> Option.map (fun parsedInput ->
16651708
ParsedInput.GetFullNameOfSmallestModuleOrNamespaceAtPoint(mkPos line 0, parsedInput))
16661709

1667-
let isAttributeApplication = ctx = Some CompletionContext.AttributeApplication
1710+
let isAttributeApplication =
1711+
match ctx with
1712+
| Some CompletionContext.AttributeApplication -> true
1713+
| _ -> false
16681714

16691715
DeclarationListInfo.Create(
16701716
infoReader,

src/Compiler/Service/ServiceParsedInputOps.fs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ open System.Text.RegularExpressions
99
open Internal.Utilities.Library
1010
open FSharp.Compiler.Diagnostics
1111
open FSharp.Compiler.Syntax
12+
open FSharp.Compiler.SyntaxTrivia
1213
open FSharp.Compiler.Syntax.PrettyNaming
1314
open FSharp.Compiler.SyntaxTreeOps
1415
open FSharp.Compiler.Text
@@ -97,6 +98,9 @@ type CompletionContext =
9798
/// Completing a pattern in a match clause, member/let binding or lambda
9899
| Pattern of context: PatternContext
99100

101+
/// Completing a method override (e.g. override this.ToStr|)
102+
| MethodOverride of enclosingTypeNameRange: range
103+
100104
type ShortIdent = string
101105

102106
type ShortIdents = ShortIdent[]
@@ -1414,9 +1418,36 @@ module ParsedInput =
14141418

14151419
| _ -> None
14161420

1417-
member _.VisitBinding(_, defaultTraverse, (SynBinding (headPat = headPat) as synBinding)) =
1421+
member _.VisitBinding(path, defaultTraverse, (SynBinding (headPat = headPat; trivia = trivia) as synBinding)) =
1422+
1423+
let isOverride leadingKeyword =
1424+
match leadingKeyword with
1425+
| SynLeadingKeyword.Override _ -> true
1426+
| _ -> false
1427+
1428+
let overrideContext path =
1429+
match path with
1430+
| _ :: SyntaxNode.SynTypeDefn (SynTypeDefn(typeInfo = SynComponentInfo(longId = [ enclosingType ]))) :: _ ->
1431+
Some(CompletionContext.MethodOverride enclosingType.idRange)
1432+
| _ -> Some CompletionContext.Invalid
14181433

14191434
match headPat with
1435+
1436+
// override _.|
1437+
| SynPat.FromParseError _ when isOverride trivia.LeadingKeyword -> overrideContext path
1438+
1439+
// override this.|
1440+
| SynPat.Named(ident = SynIdent (ident = selfId)) when
1441+
isOverride trivia.LeadingKeyword && selfId.idRange.End.IsAdjacentTo pos
1442+
->
1443+
overrideContext path
1444+
1445+
// override this.ToStr|
1446+
| SynPat.LongIdent(longDotId = SynLongIdent(id = [ _; methodId ])) when
1447+
isOverride trivia.LeadingKeyword && rangeContainsPos methodId.idRange pos
1448+
->
1449+
overrideContext path
1450+
14201451
| SynPat.LongIdent (longDotId = lidwd; argPats = SynArgPats.Pats pats; range = m) when rangeContainsPos m pos ->
14211452
if rangeContainsPos lidwd.Range pos then
14221453
// let fo|o x = ()
@@ -1425,10 +1456,12 @@ module ParsedInput =
14251456
pats
14261457
|> List.tryPick (fun pat -> TryGetCompletionContextInPattern true pat None pos)
14271458
|> Option.orElseWith (fun () -> defaultTraverse synBinding)
1459+
14281460
| SynPat.Named (range = range)
14291461
| SynPat.As (_, SynPat.Named (range = range), _) when rangeContainsPos range pos ->
14301462
// let fo|o = 1
14311463
Some CompletionContext.Invalid
1464+
14321465
| _ -> defaultTraverse synBinding
14331466

14341467
member _.VisitHashDirective(_, _directive, range) =

src/Compiler/Service/ServiceParsedInputOps.fsi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ type public CompletionContext =
7070
/// Completing a pattern in a match clause, member/let binding or lambda
7171
| Pattern of context: PatternContext
7272

73+
/// Completing a method override (e.g. override this.ToStr|)
74+
| MethodOverride of enclosingTypeNameRange: range
75+
7376
type public ModuleKind =
7477
{ IsAutoOpen: bool
7578
HasModuleSuffix: bool }

0 commit comments

Comments
 (0)