Skip to content

Commit a2c0c22

Browse files
authored
Include settable properties in attribute completions (#14697)
* Include settable properties in attribute completions
1 parent 337d0af commit a2c0c22

File tree

11 files changed

+435
-321
lines changed

11 files changed

+435
-321
lines changed

src/Compiler/Service/FSharpCheckerResults.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1262,7 +1262,7 @@ type internal TypeCheckInfo
12621262
// No completion at '...: string'
12631263
| Some (CompletionContext.RecordField (RecordContext.Declaration true)) -> None
12641264

1265-
// Completion at ' SomeMethod( ... ) ' with named arguments
1265+
// Completion at ' SomeMethod( ... ) ' or ' [<SomeAttribute( ... )>] ' with named arguments
12661266
| Some (CompletionContext.ParameterList (endPos, fields)) ->
12671267
let results = GetNamedParametersAndSettableFields endPos
12681268

src/Compiler/Service/ServiceParseTreeWalk.fs

Lines changed: 100 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ type SyntaxVisitorBase<'T>() =
178178
ignore path
179179
defaultTraverse synType
180180

181+
abstract VisitAttributeApplication: path: SyntaxVisitorPath * attributes: SynAttributeList -> 'T option
182+
183+
default _.VisitAttributeApplication(path, attributes) =
184+
ignore (path, attributes)
185+
None
186+
181187
/// A range of utility functions to assist with traversing an AST
182188
module SyntaxTraversal =
183189

@@ -278,9 +284,10 @@ module SyntaxTraversal =
278284

279285
match m with
280286
| SynModuleDecl.ModuleAbbrev (_ident, _longIdent, _range) -> None
281-
| SynModuleDecl.NestedModule (decls = synModuleDecls) ->
287+
| SynModuleDecl.NestedModule (decls = synModuleDecls; moduleInfo = SynComponentInfo (attributes = attributes)) ->
282288
synModuleDecls
283289
|> List.map (fun x -> dive x x.Range (traverseSynModuleDecl path))
290+
|> List.append (attributeApplicationDives path attributes)
284291
|> pick decl
285292
| SynModuleDecl.Let (isRecursive, synBindingList, range) ->
286293
match visitor.VisitLetOrUse(path, isRecursive, traverseSynBinding path, synBindingList, range) with
@@ -296,7 +303,7 @@ module SyntaxTraversal =
296303
|> pick decl
297304
| SynModuleDecl.Exception (_synExceptionDefn, _range) -> None
298305
| SynModuleDecl.Open (_target, _range) -> None
299-
| SynModuleDecl.Attributes (_synAttributes, _range) -> None
306+
| SynModuleDecl.Attributes (attributes, _) -> attributeApplicationDives path attributes |> pick decl
300307
| SynModuleDecl.HashDirective (parsedHashDirective, range) -> visitor.VisitHashDirective(path, parsedHashDirective, range)
301308
| SynModuleDecl.NamespaceFragment (synModuleOrNamespace) -> traverseSynModuleOrNamespace path synModuleOrNamespace
302309

@@ -549,7 +556,7 @@ module SyntaxTraversal =
549556
| SynExpr.Lambda (args = synSimplePats; body = synExpr) ->
550557
match synSimplePats with
551558
| SynSimplePats.SimplePats (pats, _) ->
552-
match visitor.VisitSimplePats(path, pats) with
559+
match traverseSynSimplePats path pats with
553560
| None -> traverseSynExpr synExpr
554561
| x -> x
555562
| _ -> traverseSynExpr synExpr
@@ -792,7 +799,10 @@ module SyntaxTraversal =
792799
| SynPat.Ands (ps, _)
793800
| SynPat.Tuple (_, ps, _)
794801
| SynPat.ArrayOrList (_, ps, _) -> ps |> List.tryPick (traversePat path)
795-
| SynPat.Attrib (p, _, _) -> traversePat path p
802+
| SynPat.Attrib (p, attributes, m) ->
803+
match traversePat path p with
804+
| None -> attributeApplicationDives path attributes |> pick m attributes
805+
| x -> x
796806
| SynPat.LongIdent (argPats = args) ->
797807
match args with
798808
| SynArgPats.Pats ps -> ps |> List.tryPick (traversePat path)
@@ -805,6 +815,17 @@ module SyntaxTraversal =
805815

806816
visitor.VisitPat(origPath, defaultTraverse, pat)
807817

818+
and traverseSynSimplePats origPath (pats: SynSimplePat list) =
819+
match visitor.VisitSimplePats(origPath, pats) with
820+
| None ->
821+
pats
822+
|> List.tryPick (fun pat ->
823+
match pat with
824+
| SynSimplePat.Attrib (attributes = attributes; range = m) ->
825+
attributeApplicationDives origPath attributes |> pick m attributes
826+
| _ -> None)
827+
| x -> x
828+
808829
and traverseSynType origPath (StripParenTypes ty) =
809830
let defaultTraverse ty =
810831
let path = SyntaxNode.SynType ty :: origPath
@@ -854,36 +875,64 @@ module SyntaxTraversal =
854875
match visitor.VisitComponentInfo(origPath, synComponentInfo) with
855876
| Some x -> Some x
856877
| None ->
857-
[
858-
match synTypeDefnRepr with
859-
| SynTypeDefnRepr.Exception _ ->
860-
// This node is generated in CheckExpressions.fs, not in the AST.
861-
// But note exception declarations are missing from this tree walk.
862-
()
863-
| SynTypeDefnRepr.ObjectModel (synTypeDefnKind, synMemberDefns, _oRange) ->
864-
// traverse inherit function is used to capture type specific data required for processing Inherit part
865-
let traverseInherit (synType: SynType, range: range) =
866-
visitor.VisitInheritSynMemberDefn(path, synComponentInfo, synTypeDefnKind, synType, synMemberDefns, range)
878+
match synComponentInfo with
879+
| SynComponentInfo (attributes = attributes) ->
880+
[
881+
yield! attributeApplicationDives path attributes
882+
883+
match synTypeDefnRepr with
884+
| SynTypeDefnRepr.Exception _ ->
885+
// This node is generated in CheckExpressions.fs, not in the AST.
886+
// But note exception declarations are missing from this tree walk.
887+
()
888+
| SynTypeDefnRepr.ObjectModel (synTypeDefnKind, synMemberDefns, _oRange) ->
889+
// traverse inherit function is used to capture type specific data required for processing Inherit part
890+
let traverseInherit (synType: SynType, range: range) =
891+
visitor.VisitInheritSynMemberDefn(path, synComponentInfo, synTypeDefnKind, synType, synMemberDefns, range)
867892

893+
yield!
894+
synMemberDefns
895+
|> normalizeMembersToDealWithPeculiaritiesOfGettersAndSetters path traverseInherit
896+
| SynTypeDefnRepr.Simple (synTypeDefnSimpleRepr, _range) ->
897+
match synTypeDefnSimpleRepr with
898+
| SynTypeDefnSimpleRepr.Record (_synAccessOption, fields, m) ->
899+
yield dive () synTypeDefnRepr.Range (fun () -> traverseRecordDefn path fields m)
900+
| SynTypeDefnSimpleRepr.Union (_synAccessOption, cases, m) ->
901+
yield dive () synTypeDefnRepr.Range (fun () -> traverseUnionDefn path cases m)
902+
| SynTypeDefnSimpleRepr.Enum (cases, m) ->
903+
yield dive () synTypeDefnRepr.Range (fun () -> traverseEnumDefn path cases m)
904+
| SynTypeDefnSimpleRepr.TypeAbbrev (_, synType, m) ->
905+
yield dive synTypeDefnRepr synTypeDefnRepr.Range (fun _ -> visitor.VisitTypeAbbrev(path, synType, m))
906+
| _ -> ()
868907
yield!
869908
synMemberDefns
870-
|> normalizeMembersToDealWithPeculiaritiesOfGettersAndSetters path traverseInherit
871-
| SynTypeDefnRepr.Simple (synTypeDefnSimpleRepr, _range) ->
872-
match synTypeDefnSimpleRepr with
873-
| SynTypeDefnSimpleRepr.Record (_synAccessOption, fields, m) ->
874-
yield dive () synTypeDefnRepr.Range (fun () -> visitor.VisitRecordDefn(path, fields, m))
875-
| SynTypeDefnSimpleRepr.Union (_synAccessOption, cases, m) ->
876-
yield dive () synTypeDefnRepr.Range (fun () -> visitor.VisitUnionDefn(path, cases, m))
877-
| SynTypeDefnSimpleRepr.Enum (cases, m) ->
878-
yield dive () synTypeDefnRepr.Range (fun () -> visitor.VisitEnumDefn(path, cases, m))
879-
| SynTypeDefnSimpleRepr.TypeAbbrev (_, synType, m) ->
880-
yield dive synTypeDefnRepr synTypeDefnRepr.Range (fun _ -> visitor.VisitTypeAbbrev(path, synType, m))
881-
| _ -> ()
882-
yield!
883-
synMemberDefns
884-
|> normalizeMembersToDealWithPeculiaritiesOfGettersAndSetters path (fun _ -> None)
885-
]
886-
|> pick tRange tydef
909+
|> normalizeMembersToDealWithPeculiaritiesOfGettersAndSetters path (fun _ -> None)
910+
]
911+
|> pick tRange tydef
912+
913+
and traverseRecordDefn path fields m =
914+
fields
915+
|> List.tryPick (fun (SynField (attributes = attributes)) -> attributeApplicationDives path attributes |> pick m attributes)
916+
|> Option.orElseWith (fun () -> visitor.VisitRecordDefn(path, fields, m))
917+
918+
and traverseEnumDefn path cases m =
919+
cases
920+
|> List.tryPick (fun (SynEnumCase (attributes = attributes)) -> attributeApplicationDives path attributes |> pick m attributes)
921+
|> Option.orElseWith (fun () -> visitor.VisitEnumDefn(path, cases, m))
922+
923+
and traverseUnionDefn path cases m =
924+
cases
925+
|> List.tryPick (fun (SynUnionCase (attributes = attributes; caseType = caseType)) ->
926+
match attributeApplicationDives path attributes |> pick m attributes with
927+
| None ->
928+
match caseType with
929+
| SynUnionCaseKind.Fields fields ->
930+
fields
931+
|> List.tryPick (fun (SynField (attributes = attributes)) ->
932+
attributeApplicationDives path attributes |> pick m attributes)
933+
| _ -> None
934+
| x -> x)
935+
|> Option.orElseWith (fun () -> visitor.VisitUnionDefn(path, cases, m))
887936

888937
and traverseSynMemberDefn path traverseInherit (m: SynMemberDefn) =
889938
let pick (debugObj: obj) = pick m.Range debugObj
@@ -903,7 +952,7 @@ module SyntaxTraversal =
903952

904953
| SynMemberDefn.ImplicitCtor (ctorArgs = simplePats) ->
905954
match simplePats with
906-
| SynSimplePats.SimplePats (simplePats, _) -> visitor.VisitSimplePats(path, simplePats)
955+
| SynSimplePats.SimplePats (simplePats, _) -> traverseSynSimplePats path simplePats
907956
| _ -> None
908957
| SynMemberDefn.ImplicitInherit (synType, synExpr, _identOption, range) ->
909958
[
@@ -914,15 +963,21 @@ module SyntaxTraversal =
914963
dive () synExpr.Range (fun () -> visitor.VisitImplicitInherit(path, traverseSynExpr path, synType, synExpr, range))
915964
]
916965
|> pick m
917-
| SynMemberDefn.AutoProperty (synExpr = synExpr) -> traverseSynExpr path synExpr
966+
| SynMemberDefn.AutoProperty (synExpr = synExpr; attributes = attributes) ->
967+
match traverseSynExpr path synExpr with
968+
| None -> attributeApplicationDives path attributes |> pick attributes
969+
| x -> x
918970
| SynMemberDefn.LetBindings (synBindingList, isRecursive, _, range) ->
919971
match visitor.VisitLetOrUse(path, isRecursive, traverseSynBinding path, synBindingList, range) with
920972
| None ->
921973
synBindingList
922974
|> List.map (fun x -> dive x x.RangeOfBindingWithRhs (traverseSynBinding path))
923975
|> pick m
924976
| x -> x
925-
| SynMemberDefn.AbstractSlot(slotSig = SynValSig (synType = synType)) -> traverseSynType path synType
977+
| SynMemberDefn.AbstractSlot(slotSig = SynValSig (synType = synType; attributes = attributes)) ->
978+
match traverseSynType path synType with
979+
| None -> attributeApplicationDives path attributes |> pick attributes
980+
| x -> x
926981
| SynMemberDefn.Interface (interfaceType = synType; members = synMemberDefnsOption) ->
927982
match visitor.VisitInterfaceSynMemberDefnType(path, synType) with
928983
| None ->
@@ -963,13 +1018,20 @@ module SyntaxTraversal =
9631018
let path = SyntaxNode.SynBinding b :: origPath
9641019

9651020
match b with
966-
| SynBinding (headPat = synPat; expr = synExpr) ->
967-
match traversePat path synPat with
968-
| None -> traverseSynExpr path synExpr
969-
| x -> x
1021+
| SynBinding (headPat = synPat; expr = synExpr; attributes = attributes; range = m) ->
1022+
[
1023+
yield! attributeApplicationDives path attributes
1024+
dive synPat synPat.Range (traversePat path)
1025+
dive synExpr synExpr.Range (traverseSynExpr path)
1026+
]
1027+
|> pick m b
9701028

9711029
visitor.VisitBinding(origPath, defaultTraverse, b)
9721030

1031+
and attributeApplicationDives origPath attributes =
1032+
attributes
1033+
|> List.map (fun attributes -> dive () attributes.Range (fun () -> visitor.VisitAttributeApplication(origPath, attributes)))
1034+
9731035
match parseTree with
9741036
| ParsedInput.ImplFile file ->
9751037
let l = file.Contents

src/Compiler/Service/ServiceParseTreeWalk.fsi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ type SyntaxVisitorBase<'T> =
148148
abstract VisitTypeAbbrev: path: SyntaxVisitorPath * synType: SynType * range: range -> 'T option
149149
default VisitTypeAbbrev: path: SyntaxVisitorPath * synType: SynType * range: range -> 'T option
150150

151+
abstract VisitAttributeApplication: path: SyntaxVisitorPath * attributes: SynAttributeList -> 'T option
152+
default VisitAttributeApplication: path: SyntaxVisitorPath * attributes: SynAttributeList -> 'T option
153+
151154
module public SyntaxTraversal =
152155

153156
val internal rangeContainsPosLeftEdgeInclusive: m1: range -> p: pos -> bool

0 commit comments

Comments
 (0)