From 886f0277a74fd5a938a0f5aebe0a9ac07cb667e9 Mon Sep 17 00:00:00 2001 From: kerams Date: Sun, 5 Feb 2023 19:58:36 +0100 Subject: [PATCH 1/5] Include settable properties in attribute completions --- src/Compiler/Service/FSharpCheckerResults.fs | 2 + src/Compiler/Service/ServiceParseTreeWalk.fs | 142 ++++-- src/Compiler/Service/ServiceParseTreeWalk.fsi | 3 + src/Compiler/Service/ServiceParsedInputOps.fs | 463 +++++++++--------- .../Service/ServiceParsedInputOps.fsi | 4 + .../CompletionProviderTests.fs | 44 ++ 6 files changed, 391 insertions(+), 267 deletions(-) diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index c66bb3e5142..2efc160d426 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -1262,6 +1262,8 @@ type internal TypeCheckInfo // No completion at '...: string' | Some (CompletionContext.RecordField (RecordContext.Declaration true)) -> None + // Completion at ' [] ' with named arguments + | Some (CompletionContext.AttributeApplicationParameterList (endPos, fields)) // Completion at ' SomeMethod( ... ) ' with named arguments | Some (CompletionContext.ParameterList (endPos, fields)) -> let results = GetNamedParametersAndSettableFields endPos diff --git a/src/Compiler/Service/ServiceParseTreeWalk.fs b/src/Compiler/Service/ServiceParseTreeWalk.fs index 7e932bdb83f..760d1bc0ed0 100644 --- a/src/Compiler/Service/ServiceParseTreeWalk.fs +++ b/src/Compiler/Service/ServiceParseTreeWalk.fs @@ -178,6 +178,12 @@ type SyntaxVisitorBase<'T>() = ignore path defaultTraverse synType + abstract VisitAttributeApplication: path: SyntaxVisitorPath * attributes: SynAttributeList -> 'T option + + default _.VisitAttributeApplication(path, attributes) = + ignore (path, attributes) + None + /// A range of utility functions to assist with traversing an AST module SyntaxTraversal = @@ -278,9 +284,10 @@ module SyntaxTraversal = match m with | SynModuleDecl.ModuleAbbrev (_ident, _longIdent, _range) -> None - | SynModuleDecl.NestedModule (decls = synModuleDecls) -> + | SynModuleDecl.NestedModule (decls = synModuleDecls; moduleInfo = SynComponentInfo (attributes = attributes)) -> synModuleDecls |> List.map (fun x -> dive x x.Range (traverseSynModuleDecl path)) + |> List.append (traverseAttributeApplication path attributes) |> pick decl | SynModuleDecl.Let (isRecursive, synBindingList, range) -> match visitor.VisitLetOrUse(path, isRecursive, traverseSynBinding path, synBindingList, range) with @@ -296,7 +303,7 @@ module SyntaxTraversal = |> pick decl | SynModuleDecl.Exception (_synExceptionDefn, _range) -> None | SynModuleDecl.Open (_target, _range) -> None - | SynModuleDecl.Attributes (_synAttributes, _range) -> None + | SynModuleDecl.Attributes (attributes, _) -> traverseAttributeApplication path attributes |> pick decl | SynModuleDecl.HashDirective (parsedHashDirective, range) -> visitor.VisitHashDirective(path, parsedHashDirective, range) | SynModuleDecl.NamespaceFragment (synModuleOrNamespace) -> traverseSynModuleOrNamespace path synModuleOrNamespace @@ -549,7 +556,7 @@ module SyntaxTraversal = | SynExpr.Lambda (args = synSimplePats; body = synExpr) -> match synSimplePats with | SynSimplePats.SimplePats (pats, _) -> - match visitor.VisitSimplePats(path, pats) with + match traverseSynSimplePats path pats with | None -> traverseSynExpr synExpr | x -> x | _ -> traverseSynExpr synExpr @@ -792,7 +799,10 @@ module SyntaxTraversal = | SynPat.Ands (ps, _) | SynPat.Tuple (_, ps, _) | SynPat.ArrayOrList (_, ps, _) -> ps |> List.tryPick (traversePat path) - | SynPat.Attrib (p, _, _) -> traversePat path p + | SynPat.Attrib (p, attributes, m) -> + match traversePat path p with + | None -> traverseAttributeApplication path attributes |> pick m attributes + | x -> x | SynPat.LongIdent (argPats = args) -> match args with | SynArgPats.Pats ps -> ps |> List.tryPick (traversePat path) @@ -805,6 +815,17 @@ module SyntaxTraversal = visitor.VisitPat(origPath, defaultTraverse, pat) + and traverseSynSimplePats origPath (pats: SynSimplePat list) = + match visitor.VisitSimplePats(origPath, pats) with + | None -> + pats + |> List.tryPick (fun pat -> + match pat with + | SynSimplePat.Attrib (attributes = attributes; range = m) -> + traverseAttributeApplication origPath attributes |> pick m attributes + | _ -> None) + | x -> x + and traverseSynType origPath (StripParenTypes ty) = let defaultTraverse ty = let path = SyntaxNode.SynType ty :: origPath @@ -854,36 +875,65 @@ module SyntaxTraversal = match visitor.VisitComponentInfo(origPath, synComponentInfo) with | Some x -> Some x | None -> - [ - match synTypeDefnRepr with - | SynTypeDefnRepr.Exception _ -> - // This node is generated in CheckExpressions.fs, not in the AST. - // But note exception declarations are missing from this tree walk. - () - | SynTypeDefnRepr.ObjectModel (synTypeDefnKind, synMemberDefns, _oRange) -> - // traverse inherit function is used to capture type specific data required for processing Inherit part - let traverseInherit (synType: SynType, range: range) = - visitor.VisitInheritSynMemberDefn(path, synComponentInfo, synTypeDefnKind, synType, synMemberDefns, range) + match synComponentInfo with + | SynComponentInfo (attributes = attributes) -> + [ + yield! traverseAttributeApplication path attributes + + match synTypeDefnRepr with + | SynTypeDefnRepr.Exception _ -> + // This node is generated in CheckExpressions.fs, not in the AST. + // But note exception declarations are missing from this tree walk. + () + | SynTypeDefnRepr.ObjectModel (synTypeDefnKind, synMemberDefns, _oRange) -> + // traverse inherit function is used to capture type specific data required for processing Inherit part + let traverseInherit (synType: SynType, range: range) = + visitor.VisitInheritSynMemberDefn(path, synComponentInfo, synTypeDefnKind, synType, synMemberDefns, range) + yield! + synMemberDefns + |> normalizeMembersToDealWithPeculiaritiesOfGettersAndSetters path traverseInherit + | SynTypeDefnRepr.Simple (synTypeDefnSimpleRepr, _range) -> + match synTypeDefnSimpleRepr with + | SynTypeDefnSimpleRepr.Record (_synAccessOption, fields, m) -> + yield dive () synTypeDefnRepr.Range (fun () -> traverseRecordDefn path fields m) + | SynTypeDefnSimpleRepr.Union (_synAccessOption, cases, m) -> + yield dive () synTypeDefnRepr.Range (fun () -> traverseUnionDefn path cases m) + | SynTypeDefnSimpleRepr.Enum (cases, m) -> + yield dive () synTypeDefnRepr.Range (fun () -> traverseEnumDefn path cases m) + | SynTypeDefnSimpleRepr.TypeAbbrev (_, synType, m) -> + yield dive synTypeDefnRepr synTypeDefnRepr.Range (fun _ -> visitor.VisitTypeAbbrev(path, synType, m)) + | _ -> () yield! synMemberDefns - |> normalizeMembersToDealWithPeculiaritiesOfGettersAndSetters path traverseInherit - | SynTypeDefnRepr.Simple (synTypeDefnSimpleRepr, _range) -> - match synTypeDefnSimpleRepr with - | SynTypeDefnSimpleRepr.Record (_synAccessOption, fields, m) -> - yield dive () synTypeDefnRepr.Range (fun () -> visitor.VisitRecordDefn(path, fields, m)) - | SynTypeDefnSimpleRepr.Union (_synAccessOption, cases, m) -> - yield dive () synTypeDefnRepr.Range (fun () -> visitor.VisitUnionDefn(path, cases, m)) - | SynTypeDefnSimpleRepr.Enum (cases, m) -> - yield dive () synTypeDefnRepr.Range (fun () -> visitor.VisitEnumDefn(path, cases, m)) - | SynTypeDefnSimpleRepr.TypeAbbrev (_, synType, m) -> - yield dive synTypeDefnRepr synTypeDefnRepr.Range (fun _ -> visitor.VisitTypeAbbrev(path, synType, m)) - | _ -> () - yield! - synMemberDefns - |> normalizeMembersToDealWithPeculiaritiesOfGettersAndSetters path (fun _ -> None) - ] - |> pick tRange tydef + |> normalizeMembersToDealWithPeculiaritiesOfGettersAndSetters path (fun _ -> None) + ] + |> pick tRange tydef + + and traverseRecordDefn path fields m = + fields + |> List.tryPick (fun (SynField (attributes = attributes)) -> traverseAttributeApplication path attributes |> pick m attributes) + |> Option.orElseWith (fun () -> visitor.VisitRecordDefn(path, fields, m)) + + and traverseEnumDefn path cases m = + cases + |> List.tryPick (fun (SynEnumCase (attributes = attributes)) -> + traverseAttributeApplication path attributes |> pick m attributes) + |> Option.orElseWith (fun () -> visitor.VisitEnumDefn(path, cases, m)) + + and traverseUnionDefn path cases m = + cases + |> List.tryPick (fun (SynUnionCase (attributes = attributes; caseType = caseType)) -> + match traverseAttributeApplication path attributes |> pick m attributes with + | None -> + match caseType with + | SynUnionCaseKind.Fields fields -> + fields + |> List.tryPick (fun (SynField (attributes = attributes)) -> + traverseAttributeApplication path attributes |> pick m attributes) + | _ -> None + | x -> x) + |> Option.orElseWith (fun () -> visitor.VisitUnionDefn(path, cases, m)) and traverseSynMemberDefn path traverseInherit (m: SynMemberDefn) = let pick (debugObj: obj) = pick m.Range debugObj @@ -903,7 +953,7 @@ module SyntaxTraversal = | SynMemberDefn.ImplicitCtor (ctorArgs = simplePats) -> match simplePats with - | SynSimplePats.SimplePats (simplePats, _) -> visitor.VisitSimplePats(path, simplePats) + | SynSimplePats.SimplePats (simplePats, _) -> traverseSynSimplePats path simplePats | _ -> None | SynMemberDefn.ImplicitInherit (synType, synExpr, _identOption, range) -> [ @@ -914,7 +964,10 @@ module SyntaxTraversal = dive () synExpr.Range (fun () -> visitor.VisitImplicitInherit(path, traverseSynExpr path, synType, synExpr, range)) ] |> pick m - | SynMemberDefn.AutoProperty (synExpr = synExpr) -> traverseSynExpr path synExpr + | SynMemberDefn.AutoProperty (synExpr = synExpr; attributes = attributes) -> + match traverseSynExpr path synExpr with + | None -> traverseAttributeApplication path attributes |> pick attributes + | x -> x | SynMemberDefn.LetBindings (synBindingList, isRecursive, _, range) -> match visitor.VisitLetOrUse(path, isRecursive, traverseSynBinding path, synBindingList, range) with | None -> @@ -922,7 +975,10 @@ module SyntaxTraversal = |> List.map (fun x -> dive x x.RangeOfBindingWithRhs (traverseSynBinding path)) |> pick m | x -> x - | SynMemberDefn.AbstractSlot(slotSig = SynValSig (synType = synType)) -> traverseSynType path synType + | SynMemberDefn.AbstractSlot(slotSig = SynValSig (synType = synType; attributes = attributes)) -> + match traverseSynType path synType with + | None -> traverseAttributeApplication path attributes |> pick attributes + | x -> x | SynMemberDefn.Interface (interfaceType = synType; members = synMemberDefnsOption) -> match visitor.VisitInterfaceSynMemberDefnType(path, synType) with | None -> @@ -963,13 +1019,23 @@ module SyntaxTraversal = let path = SyntaxNode.SynBinding b :: origPath match b with - | SynBinding (headPat = synPat; expr = synExpr) -> - match traversePat path synPat with - | None -> traverseSynExpr path synExpr - | x -> x + | SynBinding (headPat = synPat; expr = synExpr; attributes = attributes; range = m) -> + [ + yield! traverseAttributeApplication path attributes + dive synPat synPat.Range (traversePat path) + dive synExpr synExpr.Range (traverseSynExpr path) + ] + |> pick m b visitor.VisitBinding(origPath, defaultTraverse, b) + and traverseAttributeApplication origPath attributes = + match attributes with + | [] -> [] + | _ -> + attributes + |> List.map (fun attributes -> dive () attributes.Range (fun () -> visitor.VisitAttributeApplication(origPath, attributes))) + match parseTree with | ParsedInput.ImplFile file -> let l = file.Contents diff --git a/src/Compiler/Service/ServiceParseTreeWalk.fsi b/src/Compiler/Service/ServiceParseTreeWalk.fsi index 2b9819def4e..d073ca1e73c 100644 --- a/src/Compiler/Service/ServiceParseTreeWalk.fsi +++ b/src/Compiler/Service/ServiceParseTreeWalk.fsi @@ -148,6 +148,9 @@ type SyntaxVisitorBase<'T> = abstract VisitTypeAbbrev: path: SyntaxVisitorPath * synType: SynType * range: range -> 'T option default VisitTypeAbbrev: path: SyntaxVisitorPath * synType: SynType * range: range -> 'T option + abstract VisitAttributeApplication: path: SyntaxVisitorPath * attributes: SynAttributeList -> 'T option + default VisitAttributeApplication: path: SyntaxVisitorPath * attributes: SynAttributeList -> 'T option + module public SyntaxTraversal = val internal rangeContainsPosLeftEdgeInclusive: m1: range -> p: pos -> bool diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index b4739fe73e2..fd9daf79363 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -68,6 +68,10 @@ type CompletionContext = | AttributeApplication + /// The same as as 'ParameterList', except within the context of attribute application, + /// which is more restrictive + | AttributeApplicationParameterList of pos * HashSet + | OpenDeclaration of isOpenType: bool /// Completing pattern type (e.g. foo (x: |)) @@ -1267,278 +1271,279 @@ module ParsedInput = /// Try to determine completion context for the given pair (row, columns) let TryGetCompletionContext (pos, parsedInput: ParsedInput, lineStr: string) : CompletionContext option = - match GetEntityKind(pos, parsedInput) with - | Some EntityKind.Attribute -> Some CompletionContext.AttributeApplication - | _ -> + let visitor = + { new SyntaxVisitorBase<_>() with + member _.VisitExpr(path, _, defaultTraverse, expr) = - let visitor = - { new SyntaxVisitorBase<_>() with - member _.VisitExpr(path, _, defaultTraverse, expr) = + if isAtRangeOp path then + match defaultTraverse expr with + | None -> Some CompletionContext.RangeOperator // nothing was found - report that we were in the context of range operator + | x -> x // ok, we found something - return it + else + match expr with + // new A($) + | SynExpr.Const (SynConst.Unit, m) when rangeContainsPos m pos -> + match path with + | SyntaxNode.SynExpr (NewObjectOrMethodCall args) :: _ -> Some(CompletionContext.ParameterList args) + | _ -> defaultTraverse expr - if isAtRangeOp path then - match defaultTraverse expr with - | None -> Some CompletionContext.RangeOperator // nothing was found - report that we were in the context of range operator - | x -> x // ok, we found something - return it - else - match expr with - // new A($) - | SynExpr.Const (SynConst.Unit, m) when rangeContainsPos m pos -> - match path with - | SyntaxNode.SynExpr (NewObjectOrMethodCall args) :: _ -> Some(CompletionContext.ParameterList args) - | _ -> defaultTraverse expr - - // new (... A$) - | SynExpr.Ident id - | SynExpr.LongIdent(longDotId = SynLongIdent ([ id ], [], [ Some _ ])) when id.idRange.End = pos -> - match path with - | PartOfParameterList pos None args -> Some(CompletionContext.ParameterList args) - | _ -> defaultTraverse expr - - // new (A$ = 1) - // new (A = 1, $) - | Setter id when id.idRange.End = pos || rangeBeforePos expr.Range pos -> - let precedingArgument = if id.idRange.End = pos then None else Some expr - - match path with - | PartOfParameterList pos precedingArgument args -> Some(CompletionContext.ParameterList args) - | _ -> defaultTraverse expr - - | SynExpr.Record (None, None, [], _) -> Some(CompletionContext.RecordField RecordContext.Empty) - - // Unchecked.defaultof - | SynExpr.TypeApp (typeArgsRange = range) when rangeContainsPos range pos -> Some CompletionContext.PatternType + // new (... A$) + | SynExpr.Ident id + | SynExpr.LongIdent(longDotId = SynLongIdent ([ id ], [], [ Some _ ])) when id.idRange.End = pos -> + match path with + | PartOfParameterList pos None args -> Some(CompletionContext.ParameterList args) | _ -> defaultTraverse expr - member _.VisitRecordField(path, copyOpt, field) = - let contextFromTreePath completionPath = - // detect records usage in constructor + // new (A$ = 1) + // new (A = 1, $) + | Setter id when id.idRange.End = pos || rangeBeforePos expr.Range pos -> + let precedingArgument = if id.idRange.End = pos then None else Some expr + match path with - | SyntaxNode.SynExpr _ :: SyntaxNode.SynBinding _ :: SyntaxNode.SynMemberDefn _ :: SyntaxNode.SynTypeDefn (SynTypeDefn(typeInfo = SynComponentInfo(longId = [ id ]))) :: _ -> - RecordContext.Constructor(id.idText) + | PartOfParameterList pos precedingArgument args -> Some(CompletionContext.ParameterList args) + | _ -> defaultTraverse expr + + | SynExpr.Record (None, None, [], _) -> Some(CompletionContext.RecordField RecordContext.Empty) - | SyntaxNode.SynExpr (SynExpr.Record (None, _, fields, _)) :: _ -> - let isFirstField = - match field, fields with - | Some contextLid, SynExprRecordField(fieldName = lid, _) :: _ -> contextLid.Range = lid.Range - | _ -> false + // Unchecked.defaultof + | SynExpr.TypeApp (typeArgsRange = range) when rangeContainsPos range pos -> Some CompletionContext.PatternType + | _ -> defaultTraverse expr - RecordContext.New(completionPath, isFirstField) + member _.VisitRecordField(path, copyOpt, field) = + let contextFromTreePath completionPath = + // detect records usage in constructor + match path with + | SyntaxNode.SynExpr _ :: SyntaxNode.SynBinding _ :: SyntaxNode.SynMemberDefn _ :: SyntaxNode.SynTypeDefn (SynTypeDefn(typeInfo = SynComponentInfo(longId = [ id ]))) :: _ -> + RecordContext.Constructor(id.idText) - // Unfinished `{ xxx }` expression considered a record field by the tree visitor. - | SyntaxNode.SynExpr (SynExpr.ComputationExpr _) :: _ -> RecordContext.New(completionPath, true) + | SyntaxNode.SynExpr (SynExpr.Record (None, _, fields, _)) :: _ -> + let isFirstField = + match field, fields with + | Some contextLid, SynExprRecordField(fieldName = lid, _) :: _ -> contextLid.Range = lid.Range + | _ -> false - | _ -> RecordContext.New(completionPath, false) + RecordContext.New(completionPath, isFirstField) - match field with - | Some field -> - match parseLid pos field with - | Some completionPath -> - let recordContext = - match copyOpt with - | Some (s: SynExpr) -> RecordContext.CopyOnUpdate(s.Range, completionPath) - | None -> contextFromTreePath completionPath + // Unfinished `{ xxx }` expression considered a record field by the tree visitor. + | SyntaxNode.SynExpr (SynExpr.ComputationExpr _) :: _ -> RecordContext.New(completionPath, true) - Some(CompletionContext.RecordField recordContext) - | None -> None - | None -> + | _ -> RecordContext.New(completionPath, false) + + match field with + | Some field -> + match parseLid pos field with + | Some completionPath -> let recordContext = match copyOpt with - | Some s -> RecordContext.CopyOnUpdate(s.Range, ([], None)) - | None -> contextFromTreePath ([], None) + | Some (s: SynExpr) -> RecordContext.CopyOnUpdate(s.Range, completionPath) + | None -> contextFromTreePath completionPath Some(CompletionContext.RecordField recordContext) + | None -> None + | None -> + let recordContext = + match copyOpt with + | Some s -> RecordContext.CopyOnUpdate(s.Range, ([], None)) + | None -> contextFromTreePath ([], None) - member _.VisitInheritSynMemberDefn(_, componentInfo, typeDefnKind, synType, _, _) = - match synType with - | SynType.LongIdent lidwd -> - match parseLid pos lidwd with - | Some completionPath -> GetCompletionContextForInheritSynMember(componentInfo, typeDefnKind, completionPath) - | None -> Some CompletionContext.Invalid // A $ .B -> no completion list + Some(CompletionContext.RecordField recordContext) - | _ -> None + member _.VisitInheritSynMemberDefn(_, componentInfo, typeDefnKind, synType, _, _) = + match synType with + | SynType.LongIdent lidwd -> + match parseLid pos lidwd with + | Some completionPath -> GetCompletionContextForInheritSynMember(componentInfo, typeDefnKind, completionPath) + | None -> Some CompletionContext.Invalid // A $ .B -> no completion list - member _.VisitBinding(_, defaultTraverse, (SynBinding (headPat = headPat) as synBinding)) = + | _ -> None - let visitParam (SkipFromParseErrorPat pat) = - match pat with - | SynPat.Named (range = range) - | SynPat.As (_, SynPat.Named (range = range), _) when rangeContainsPos range pos -> - // parameter without type hint, no completion - Some CompletionContext.Invalid - | SynPat.Typed (SynPat.Named (_, _, _, range), _, _) when rangeContainsPos range pos -> - // parameter with type hint, but we are on its name, no completion - Some CompletionContext.Invalid - | _ -> defaultTraverse synBinding + member _.VisitBinding(_, defaultTraverse, (SynBinding (headPat = headPat) as synBinding)) = - match headPat with - | SynPat.LongIdent (longDotId = lidwd) when rangeContainsPos lidwd.Range pos -> - // let fo|o x = () - Some CompletionContext.Invalid - | SynPat.LongIdent (argPats = ctorArgs) -> - match ctorArgs with - | SynArgPats.Pats pats -> - pats - |> List.tryPick (fun (SkipFromParseErrorPat pat) -> - match pat with - | SynPat.Paren (pat, _) -> - match pat with - | SynPat.Tuple (_, pats, _) -> pats |> List.tryPick visitParam - | _ -> visitParam pat - | SynPat.Wild range - | SynPat.FromParseError (SynPat.Named _, range) when rangeContainsPos range pos -> - // let foo (x| - Some CompletionContext.Invalid - | _ -> visitParam pat) - | _ -> defaultTraverse synBinding + let visitParam (SkipFromParseErrorPat pat) = + match pat with | SynPat.Named (range = range) | SynPat.As (_, SynPat.Named (range = range), _) when rangeContainsPos range pos -> - // let fo|o = 1 + // parameter without type hint, no completion Some CompletionContext.Invalid + | SynPat.Typed (SynPat.Named (_, _, _, range), _, _) when rangeContainsPos range pos -> + // parameter with type hint, but we are on its name, no completion + Some CompletionContext.Invalid + | _ -> defaultTraverse synBinding + + match headPat with + | SynPat.LongIdent (longDotId = lidwd) when rangeContainsPos lidwd.Range pos -> + // let fo|o x = () + Some CompletionContext.Invalid + | SynPat.LongIdent (argPats = ctorArgs; range = range) when rangeContainsPos range pos -> + match ctorArgs with + | SynArgPats.Pats pats -> + pats + |> List.tryPick (fun (SkipFromParseErrorPat pat) -> + match pat with + | SynPat.Paren (pat, _) -> + match pat with + | SynPat.Tuple (_, pats, _) -> pats |> List.tryPick visitParam + | _ -> visitParam pat + | SynPat.Wild range + | SynPat.FromParseError (SynPat.Named _, range) when rangeContainsPos range pos -> + // let foo (x| + Some CompletionContext.Invalid + | _ -> visitParam pat) | _ -> defaultTraverse synBinding + | SynPat.Named (range = range) + | SynPat.As (_, SynPat.Named (range = range), _) when rangeContainsPos range pos -> + // let fo|o = 1 + Some CompletionContext.Invalid + | _ -> defaultTraverse synBinding + + member _.VisitHashDirective(_, _directive, range) = + // No completions in a directive + if rangeContainsPos range pos then + Some CompletionContext.Invalid + else + None + + member _.VisitModuleOrNamespace(_, SynModuleOrNamespace (longId = idents)) = + match List.tryLast idents with + | Some lastIdent when + pos.Line = lastIdent.idRange.EndLine + && lastIdent.idRange.EndColumn >= 0 + && pos.Column <= lineStr.Length + -> + let stringBetweenModuleNameAndPos = + lineStr[lastIdent.idRange.EndColumn .. pos.Column - 1] - member _.VisitHashDirective(_, _directive, range) = - // No completions in a directive - if rangeContainsPos range pos then + if stringBetweenModuleNameAndPos |> Seq.forall (fun x -> x = ' ' || x = '.') then + // No completions in a top level a module or namespace identifier Some CompletionContext.Invalid else None + | _ -> None - member _.VisitModuleOrNamespace(_, SynModuleOrNamespace (longId = idents)) = - match List.tryLast idents with - | Some lastIdent when - pos.Line = lastIdent.idRange.EndLine - && lastIdent.idRange.EndColumn >= 0 - && pos.Column <= lineStr.Length - -> - let stringBetweenModuleNameAndPos = - lineStr[lastIdent.idRange.EndColumn .. pos.Column - 1] + member _.VisitComponentInfo(_, SynComponentInfo (range = range)) = + // No completions in component info (unless it's within an attribute) + // /// XmlDo| + // type R = class end + if rangeContainsPos range pos then + Some CompletionContext.Invalid + else + None + + member _.VisitLetOrUse(_, _, _, bindings, range) = + match bindings with + | [] when range.StartLine = pos.Line -> Some CompletionContext.Invalid + | _ -> None - if stringBetweenModuleNameAndPos |> Seq.forall (fun x -> x = ' ' || x = '.') then - // No completions in a top level a module or namespace identifier + member _.VisitSimplePats(_, pats) = + pats + |> List.tryPick (fun pat -> + // No completions in an identifier in a pattern + match pat with + // fun x| -> + | SynSimplePat.Id (range = range) when rangeContainsPos range pos -> Some CompletionContext.Invalid + | SynSimplePat.Typed (SynSimplePat.Id (range = idRange), synType, _) -> + // fun (x|: int) -> + if rangeContainsPos idRange pos then Some CompletionContext.Invalid + // fun (x: int|) -> + elif rangeContainsPos synType.Range pos then + Some CompletionContext.PatternType else None - | _ -> None - - member _.VisitComponentInfo(_, SynComponentInfo (range = range)) = - // No completions in component info (unless it's within an attribute) - // /// XmlDo| - // type R = class end - if rangeContainsPos range pos then - Some CompletionContext.Invalid + | _ -> None) + + member _.VisitPat(_, defaultTraverse, pat) = + match pat with + | SynPat.IsInst (_, range) when rangeContainsPos range pos -> Some CompletionContext.PatternType + | _ -> defaultTraverse pat + + member _.VisitModuleDecl(_, defaultTraverse, decl) = + match decl with + | SynModuleDecl.Open (target, m) -> + // in theory, this means we're "in an open" + // in practice, because the parse tree/visitors do not handle attributes well yet, need extra check below to ensure not e.g. $here$ + // open System + // [ true + | SynOpenDeclTarget.ModuleOrNamespace _ -> false + + Some(CompletionContext.OpenDeclaration isOpenType) else None + | _ -> defaultTraverse decl - member _.VisitLetOrUse(_, _, _, bindings, range) = - match bindings with - | [] when range.StartLine = pos.Line -> Some CompletionContext.Invalid - | _ -> None - - member _.VisitSimplePats(_, pats) = - pats - |> List.tryPick (fun pat -> - // No completions in an identifier in a pattern - match pat with - // fun x| -> - | SynSimplePat.Id (range = range) when rangeContainsPos range pos -> Some CompletionContext.Invalid - | SynSimplePat.Typed (SynSimplePat.Id (range = idRange), synType, _) -> - // fun (x|: int) -> - if rangeContainsPos idRange pos then - Some CompletionContext.Invalid - // fun (x: int|) -> - elif rangeContainsPos synType.Range pos then - Some CompletionContext.PatternType - else - None - | _ -> None) + member _.VisitType(_, defaultTraverse, ty) = + match ty with + | SynType.LongIdent _ when rangeContainsPos ty.Range pos -> Some CompletionContext.PatternType + | _ -> defaultTraverse ty - member _.VisitPat(_, defaultTraverse, pat) = - match pat with - | SynPat.IsInst (_, range) when rangeContainsPos range pos -> Some CompletionContext.PatternType - | _ -> defaultTraverse pat - - member _.VisitModuleDecl(_, defaultTraverse, decl) = - match decl with - | SynModuleDecl.Open (target, m) -> - // in theory, this means we're "in an open" - // in practice, because the parse tree/visitors do not handle attributes well yet, need extra check below to ensure not e.g. $here$ - // open System - // [ true - | SynOpenDeclTarget.ModuleOrNamespace _ -> false - - Some(CompletionContext.OpenDeclaration isOpenType) - else - None - | _ -> defaultTraverse decl - - member _.VisitType(_, defaultTraverse, ty) = - match ty with - | SynType.LongIdent _ when rangeContainsPos ty.Range pos -> Some CompletionContext.PatternType - | _ -> defaultTraverse ty - - member _.VisitRecordDefn(_, fields, range) = - fields - |> List.tryPick (fun (SynField (idOpt = idOpt; range = fieldRange)) -> - match idOpt with - | Some id when rangeContainsPos id.idRange pos -> - Some(CompletionContext.RecordField(RecordContext.Declaration true)) - | _ when rangeContainsPos fieldRange pos -> Some(CompletionContext.RecordField(RecordContext.Declaration false)) - | _ -> None) - // No completions in a record outside of all fields - |> Option.orElseWith (fun () -> - if rangeContainsPos range pos then - Some CompletionContext.Invalid - else - None) - - member _.VisitUnionDefn(_, cases, _) = - cases - |> List.tryPick (fun (SynUnionCase (ident = SynIdent (id, _); caseType = caseType)) -> - if rangeContainsPos id.idRange pos then - // No completions in a union case identifier - Some CompletionContext.Invalid - else - match caseType with - | SynUnionCaseKind.Fields fieldCases -> - fieldCases - |> List.tryPick (fun (SynField (idOpt = fieldIdOpt; range = fieldRange)) -> - match fieldIdOpt with - // No completions in a union case field identifier - | Some id when rangeContainsPos id.idRange pos -> Some CompletionContext.Invalid - | _ -> - if rangeContainsPos fieldRange pos then - Some CompletionContext.UnionCaseFieldsDeclaration - else - None) - | _ -> None) - - member _.VisitEnumDefn(_, _, range) = - // No completions anywhere in an enum - if rangeContainsPos range pos then + member _.VisitRecordDefn(_, fields, _) = + fields + |> List.tryPick (fun (SynField (idOpt = idOpt; range = fieldRange)) -> + match idOpt with + | Some id when rangeContainsPos id.idRange pos -> + Some(CompletionContext.RecordField(RecordContext.Declaration true)) + | _ when rangeContainsPos fieldRange pos -> Some(CompletionContext.RecordField(RecordContext.Declaration false)) + | _ -> None) + // No completions in a record outside of all fields, except in attributes, which is established earlier in VisitAttributeApplication + |> Option.orElse (Some CompletionContext.Invalid) + + member _.VisitUnionDefn(_, cases, _) = + cases + |> List.tryPick (fun (SynUnionCase (ident = SynIdent (id, _); caseType = caseType)) -> + if rangeContainsPos id.idRange pos then + // No completions in a union case identifier Some CompletionContext.Invalid else - None + match caseType with + | SynUnionCaseKind.Fields fieldCases -> + fieldCases + |> List.tryPick (fun (SynField (idOpt = fieldIdOpt; range = fieldRange)) -> + match fieldIdOpt with + // No completions in a union case field identifier + | Some id when rangeContainsPos id.idRange pos -> Some CompletionContext.Invalid + | _ -> + if rangeContainsPos fieldRange pos then + Some CompletionContext.UnionCaseFieldsDeclaration + else + None) + | _ -> None) + + member _.VisitEnumDefn(_, _, _) = + // No completions anywhere in an enum, except in attributes, which is established earlier in VisitAttributeApplication + Some CompletionContext.Invalid - member _.VisitTypeAbbrev(_, _, range) = - if rangeContainsPos range pos then - Some CompletionContext.TypeAbbreviationOrSingleCaseUnion + member _.VisitTypeAbbrev(_, _, range) = + if rangeContainsPos range pos then + Some CompletionContext.TypeAbbreviationOrSingleCaseUnion + else + None + + member _.VisitAttributeApplication(_, attributes) = + attributes.Attributes + |> List.tryPick (fun att -> + // [] + if rangeContainsPos att.TypeName.Range pos then + Some CompletionContext.AttributeApplication + // [] + elif rangeContainsPos att.ArgExpr.Range pos then + Some(CompletionContext.AttributeApplicationParameterList(att.TypeName.Range.End, findSetters att.ArgExpr)) else - None - } + None) + } - let ctxt = SyntaxTraversal.Traverse(pos, parsedInput, visitor) + let ctxt = SyntaxTraversal.Traverse(pos, parsedInput, visitor) - match ctxt with - | Some _ -> ctxt - | _ -> TryGetCompletionContextOfAttributes(pos, lineStr) + match ctxt with + | Some _ -> ctxt + | _ -> TryGetCompletionContextOfAttributes(pos, lineStr) //-------------------------------------------------------------------------------------------- // TryGetInsertionContext diff --git a/src/Compiler/Service/ServiceParsedInputOps.fsi b/src/Compiler/Service/ServiceParsedInputOps.fsi index f0542957759..bb027e55215 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fsi +++ b/src/Compiler/Service/ServiceParsedInputOps.fsi @@ -41,6 +41,10 @@ type public CompletionContext = | AttributeApplication + /// The same as as 'ParameterList', except within the context of attribute application, + /// which is more restrictive + | AttributeApplicationParameterList of pos * HashSet + | OpenDeclaration of isOpenType: bool /// Completing pattern type (e.g. foo (x: |)) diff --git a/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs index 2be760394f9..b5b6685138c 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs @@ -1266,3 +1266,47 @@ let inline f_StaticProperty_SRTP<'T when 'T : (static member StaticProperty: 'T) """ VerifyCompletionListWithOptions(fileContents, "'T.", [ "StaticProperty" ], [], [| "/langversion:preview" |]) + + [] + let ``Completion list for attribute application contains settable members and ctor parameters`` () = + let fileContents = + """ +type LangAttribute (langParam: int) = + inherit System.Attribute () + + member val LangMember1 = 0 with get, set + member val LangMember2 = 0 with get, set + +[] +module X = + [< Lang(2, LangMember1 = 2)>] + let a = () + +[< Lang(3, LangMember1 = 3, L)>] +type B () = + [< Lang(la)>] + member _.M = "" + +type G = { [] f: string } + +type A = + | [] A = 1 +""" + + // Attribute on module, completing attribute name - settable properties omitted + VerifyCompletionList(fileContents, "[ Date: Sun, 5 Feb 2023 20:58:36 +0100 Subject: [PATCH 2/5] Update surface area --- ...ompiler.Service.SurfaceArea.netstandard20.debug.bsl | 10 ++++++++++ ...piler.Service.SurfaceArea.netstandard20.release.bsl | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index 1bce6c61d8d..814f59c159d 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -2482,6 +2482,10 @@ FSharp.Compiler.EditorServices.AssemblySymbol: System.String get_FullName() FSharp.Compiler.EditorServices.AssemblySymbol: System.String[] CleanedIdents FSharp.Compiler.EditorServices.AssemblySymbol: System.String[] get_CleanedIdents() FSharp.Compiler.EditorServices.AssemblySymbol: Void .ctor(System.String, System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpFunc`2[FSharp.Compiler.EditorServices.LookupType,FSharp.Compiler.EditorServices.EntityKind], FSharp.Compiler.EditorServices.UnresolvedSymbol) +FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: FSharp.Compiler.Text.Position Item1 +FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: FSharp.Compiler.Text.Position get_Item1() +FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: System.Collections.Generic.HashSet`1[System.String] Item2 +FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: System.Collections.Generic.HashSet`1[System.String] get_Item2() FSharp.Compiler.EditorServices.CompletionContext+Inherit: FSharp.Compiler.EditorServices.InheritanceContext context FSharp.Compiler.EditorServices.CompletionContext+Inherit: FSharp.Compiler.EditorServices.InheritanceContext get_context() FSharp.Compiler.EditorServices.CompletionContext+Inherit: System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.String],Microsoft.FSharp.Core.FSharpOption`1[System.String]] get_path() @@ -2495,6 +2499,7 @@ FSharp.Compiler.EditorServices.CompletionContext+ParameterList: System.Collectio FSharp.Compiler.EditorServices.CompletionContext+RecordField: FSharp.Compiler.EditorServices.RecordContext context FSharp.Compiler.EditorServices.CompletionContext+RecordField: FSharp.Compiler.EditorServices.RecordContext get_context() FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 AttributeApplication +FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 AttributeApplicationParameterList FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 Inherit FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 Invalid FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 OpenDeclaration @@ -2508,6 +2513,7 @@ FSharp.Compiler.EditorServices.CompletionContext: Boolean Equals(FSharp.Compiler FSharp.Compiler.EditorServices.CompletionContext: Boolean Equals(System.Object) FSharp.Compiler.EditorServices.CompletionContext: Boolean Equals(System.Object, System.Collections.IEqualityComparer) FSharp.Compiler.EditorServices.CompletionContext: Boolean IsAttributeApplication +FSharp.Compiler.EditorServices.CompletionContext: Boolean IsAttributeApplicationParameterList FSharp.Compiler.EditorServices.CompletionContext: Boolean IsInherit FSharp.Compiler.EditorServices.CompletionContext: Boolean IsInvalid FSharp.Compiler.EditorServices.CompletionContext: Boolean IsOpenDeclaration @@ -2518,6 +2524,7 @@ FSharp.Compiler.EditorServices.CompletionContext: Boolean IsRecordField FSharp.Compiler.EditorServices.CompletionContext: Boolean IsTypeAbbreviationOrSingleCaseUnion FSharp.Compiler.EditorServices.CompletionContext: Boolean IsUnionCaseFieldsDeclaration FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsAttributeApplication() +FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsAttributeApplicationParameterList() FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsInherit() FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsInvalid() FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsOpenDeclaration() @@ -2529,6 +2536,7 @@ FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsTypeAbbreviation FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsUnionCaseFieldsDeclaration() FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext AttributeApplication FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext Invalid +FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewAttributeApplicationParameterList(FSharp.Compiler.Text.Position, System.Collections.Generic.HashSet`1[System.String]) FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewInherit(FSharp.Compiler.EditorServices.InheritanceContext, System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.String],Microsoft.FSharp.Core.FSharpOption`1[System.String]]) FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewOpenDeclaration(Boolean) FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewParameterList(FSharp.Compiler.Text.Position, System.Collections.Generic.HashSet`1[System.String]) @@ -2543,6 +2551,7 @@ FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext get_RangeOperator() FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext get_TypeAbbreviationOrSingleCaseUnion() FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext get_UnionCaseFieldsDeclaration() +FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+Inherit FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+OpenDeclaration FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+ParameterList @@ -9102,6 +9111,7 @@ FSharp.Compiler.Syntax.SyntaxNode: Int32 Tag FSharp.Compiler.Syntax.SyntaxNode: Int32 get_Tag() FSharp.Compiler.Syntax.SyntaxNode: System.String ToString() FSharp.Compiler.Syntax.SyntaxTraversal: Microsoft.FSharp.Core.FSharpOption`1[T] Traverse[T](FSharp.Compiler.Text.Position, FSharp.Compiler.Syntax.ParsedInput, FSharp.Compiler.Syntax.SyntaxVisitorBase`1[T]) +FSharp.Compiler.Syntax.SyntaxVisitorBase`1[T]: Microsoft.FSharp.Core.FSharpOption`1[T] VisitAttributeApplication(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SyntaxNode], FSharp.Compiler.Syntax.SynAttributeList) FSharp.Compiler.Syntax.SyntaxVisitorBase`1[T]: Microsoft.FSharp.Core.FSharpOption`1[T] VisitBinding(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SyntaxNode], Microsoft.FSharp.Core.FSharpFunc`2[FSharp.Compiler.Syntax.SynBinding,Microsoft.FSharp.Core.FSharpOption`1[T]], FSharp.Compiler.Syntax.SynBinding) FSharp.Compiler.Syntax.SyntaxVisitorBase`1[T]: Microsoft.FSharp.Core.FSharpOption`1[T] VisitComponentInfo(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SyntaxNode], FSharp.Compiler.Syntax.SynComponentInfo) FSharp.Compiler.Syntax.SyntaxVisitorBase`1[T]: Microsoft.FSharp.Core.FSharpOption`1[T] VisitEnumDefn(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SyntaxNode], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynEnumCase], FSharp.Compiler.Text.Range) diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index 1bce6c61d8d..814f59c159d 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -2482,6 +2482,10 @@ FSharp.Compiler.EditorServices.AssemblySymbol: System.String get_FullName() FSharp.Compiler.EditorServices.AssemblySymbol: System.String[] CleanedIdents FSharp.Compiler.EditorServices.AssemblySymbol: System.String[] get_CleanedIdents() FSharp.Compiler.EditorServices.AssemblySymbol: Void .ctor(System.String, System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpFunc`2[FSharp.Compiler.EditorServices.LookupType,FSharp.Compiler.EditorServices.EntityKind], FSharp.Compiler.EditorServices.UnresolvedSymbol) +FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: FSharp.Compiler.Text.Position Item1 +FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: FSharp.Compiler.Text.Position get_Item1() +FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: System.Collections.Generic.HashSet`1[System.String] Item2 +FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: System.Collections.Generic.HashSet`1[System.String] get_Item2() FSharp.Compiler.EditorServices.CompletionContext+Inherit: FSharp.Compiler.EditorServices.InheritanceContext context FSharp.Compiler.EditorServices.CompletionContext+Inherit: FSharp.Compiler.EditorServices.InheritanceContext get_context() FSharp.Compiler.EditorServices.CompletionContext+Inherit: System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.String],Microsoft.FSharp.Core.FSharpOption`1[System.String]] get_path() @@ -2495,6 +2499,7 @@ FSharp.Compiler.EditorServices.CompletionContext+ParameterList: System.Collectio FSharp.Compiler.EditorServices.CompletionContext+RecordField: FSharp.Compiler.EditorServices.RecordContext context FSharp.Compiler.EditorServices.CompletionContext+RecordField: FSharp.Compiler.EditorServices.RecordContext get_context() FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 AttributeApplication +FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 AttributeApplicationParameterList FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 Inherit FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 Invalid FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 OpenDeclaration @@ -2508,6 +2513,7 @@ FSharp.Compiler.EditorServices.CompletionContext: Boolean Equals(FSharp.Compiler FSharp.Compiler.EditorServices.CompletionContext: Boolean Equals(System.Object) FSharp.Compiler.EditorServices.CompletionContext: Boolean Equals(System.Object, System.Collections.IEqualityComparer) FSharp.Compiler.EditorServices.CompletionContext: Boolean IsAttributeApplication +FSharp.Compiler.EditorServices.CompletionContext: Boolean IsAttributeApplicationParameterList FSharp.Compiler.EditorServices.CompletionContext: Boolean IsInherit FSharp.Compiler.EditorServices.CompletionContext: Boolean IsInvalid FSharp.Compiler.EditorServices.CompletionContext: Boolean IsOpenDeclaration @@ -2518,6 +2524,7 @@ FSharp.Compiler.EditorServices.CompletionContext: Boolean IsRecordField FSharp.Compiler.EditorServices.CompletionContext: Boolean IsTypeAbbreviationOrSingleCaseUnion FSharp.Compiler.EditorServices.CompletionContext: Boolean IsUnionCaseFieldsDeclaration FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsAttributeApplication() +FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsAttributeApplicationParameterList() FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsInherit() FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsInvalid() FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsOpenDeclaration() @@ -2529,6 +2536,7 @@ FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsTypeAbbreviation FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsUnionCaseFieldsDeclaration() FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext AttributeApplication FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext Invalid +FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewAttributeApplicationParameterList(FSharp.Compiler.Text.Position, System.Collections.Generic.HashSet`1[System.String]) FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewInherit(FSharp.Compiler.EditorServices.InheritanceContext, System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.String],Microsoft.FSharp.Core.FSharpOption`1[System.String]]) FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewOpenDeclaration(Boolean) FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewParameterList(FSharp.Compiler.Text.Position, System.Collections.Generic.HashSet`1[System.String]) @@ -2543,6 +2551,7 @@ FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext get_RangeOperator() FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext get_TypeAbbreviationOrSingleCaseUnion() FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext get_UnionCaseFieldsDeclaration() +FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+Inherit FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+OpenDeclaration FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+ParameterList @@ -9102,6 +9111,7 @@ FSharp.Compiler.Syntax.SyntaxNode: Int32 Tag FSharp.Compiler.Syntax.SyntaxNode: Int32 get_Tag() FSharp.Compiler.Syntax.SyntaxNode: System.String ToString() FSharp.Compiler.Syntax.SyntaxTraversal: Microsoft.FSharp.Core.FSharpOption`1[T] Traverse[T](FSharp.Compiler.Text.Position, FSharp.Compiler.Syntax.ParsedInput, FSharp.Compiler.Syntax.SyntaxVisitorBase`1[T]) +FSharp.Compiler.Syntax.SyntaxVisitorBase`1[T]: Microsoft.FSharp.Core.FSharpOption`1[T] VisitAttributeApplication(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SyntaxNode], FSharp.Compiler.Syntax.SynAttributeList) FSharp.Compiler.Syntax.SyntaxVisitorBase`1[T]: Microsoft.FSharp.Core.FSharpOption`1[T] VisitBinding(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SyntaxNode], Microsoft.FSharp.Core.FSharpFunc`2[FSharp.Compiler.Syntax.SynBinding,Microsoft.FSharp.Core.FSharpOption`1[T]], FSharp.Compiler.Syntax.SynBinding) FSharp.Compiler.Syntax.SyntaxVisitorBase`1[T]: Microsoft.FSharp.Core.FSharpOption`1[T] VisitComponentInfo(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SyntaxNode], FSharp.Compiler.Syntax.SynComponentInfo) FSharp.Compiler.Syntax.SyntaxVisitorBase`1[T]: Microsoft.FSharp.Core.FSharpOption`1[T] VisitEnumDefn(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SyntaxNode], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynEnumCase], FSharp.Compiler.Text.Range) From 29d36b98a008e0494c13270eefa3a43ab4ae67e0 Mon Sep 17 00:00:00 2001 From: kerams Date: Mon, 6 Feb 2023 08:55:03 +0100 Subject: [PATCH 3/5] Fix some tests, remove CompletionContext.AttributeApplicationParameterList --- src/Compiler/Service/FSharpCheckerResults.fs | 4 +- src/Compiler/Service/ServiceParsedInputOps.fs | 9 +-- .../Service/ServiceParsedInputOps.fsi | 7 +- ...ervice.SurfaceArea.netstandard20.debug.bsl | 9 --- ...vice.SurfaceArea.netstandard20.release.bsl | 9 --- tests/service/ServiceUntypedParseTests.fs | 66 ++++++++++++------- 6 files changed, 47 insertions(+), 57 deletions(-) diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index 2efc160d426..4ace2384ffc 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -1262,9 +1262,7 @@ type internal TypeCheckInfo // No completion at '...: string' | Some (CompletionContext.RecordField (RecordContext.Declaration true)) -> None - // Completion at ' [] ' with named arguments - | Some (CompletionContext.AttributeApplicationParameterList (endPos, fields)) - // Completion at ' SomeMethod( ... ) ' with named arguments + // Completion at ' SomeMethod( ... ) ' or ' [] ' with named arguments | Some (CompletionContext.ParameterList (endPos, fields)) -> let results = GetNamedParametersAndSettableFields endPos diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index fd9daf79363..292686fe6c9 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -62,16 +62,13 @@ type CompletionContext = | RangeOperator - /// Completing named parameters\setters in parameter list of constructor\method calls + /// Completing named parameters\setters in parameter list of attributes\constructor\method calls /// end of name ast node * list of properties\parameters that were already set | ParameterList of pos * HashSet + /// Completing an attribute name, outside of the constructor | AttributeApplication - /// The same as as 'ParameterList', except within the context of attribute application, - /// which is more restrictive - | AttributeApplicationParameterList of pos * HashSet - | OpenDeclaration of isOpenType: bool /// Completing pattern type (e.g. foo (x: |)) @@ -1534,7 +1531,7 @@ module ParsedInput = Some CompletionContext.AttributeApplication // [] elif rangeContainsPos att.ArgExpr.Range pos then - Some(CompletionContext.AttributeApplicationParameterList(att.TypeName.Range.End, findSetters att.ArgExpr)) + Some(CompletionContext.ParameterList(att.TypeName.Range.End, findSetters att.ArgExpr)) else None) } diff --git a/src/Compiler/Service/ServiceParsedInputOps.fsi b/src/Compiler/Service/ServiceParsedInputOps.fsi index bb027e55215..5fb5e85d8cd 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fsi +++ b/src/Compiler/Service/ServiceParsedInputOps.fsi @@ -35,16 +35,13 @@ type public CompletionContext = | RangeOperator - /// Completing named parameters\setters in parameter list of constructor\method calls + /// Completing named parameters\setters in parameter list of attributes\constructor\method calls /// end of name ast node * list of properties\parameters that were already set | ParameterList of pos * HashSet + /// Completing an attribute name, outside of the constructor | AttributeApplication - /// The same as as 'ParameterList', except within the context of attribute application, - /// which is more restrictive - | AttributeApplicationParameterList of pos * HashSet - | OpenDeclaration of isOpenType: bool /// Completing pattern type (e.g. foo (x: |)) diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index 814f59c159d..c80440dc2ac 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -2482,10 +2482,6 @@ FSharp.Compiler.EditorServices.AssemblySymbol: System.String get_FullName() FSharp.Compiler.EditorServices.AssemblySymbol: System.String[] CleanedIdents FSharp.Compiler.EditorServices.AssemblySymbol: System.String[] get_CleanedIdents() FSharp.Compiler.EditorServices.AssemblySymbol: Void .ctor(System.String, System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpFunc`2[FSharp.Compiler.EditorServices.LookupType,FSharp.Compiler.EditorServices.EntityKind], FSharp.Compiler.EditorServices.UnresolvedSymbol) -FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: FSharp.Compiler.Text.Position Item1 -FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: FSharp.Compiler.Text.Position get_Item1() -FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: System.Collections.Generic.HashSet`1[System.String] Item2 -FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: System.Collections.Generic.HashSet`1[System.String] get_Item2() FSharp.Compiler.EditorServices.CompletionContext+Inherit: FSharp.Compiler.EditorServices.InheritanceContext context FSharp.Compiler.EditorServices.CompletionContext+Inherit: FSharp.Compiler.EditorServices.InheritanceContext get_context() FSharp.Compiler.EditorServices.CompletionContext+Inherit: System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.String],Microsoft.FSharp.Core.FSharpOption`1[System.String]] get_path() @@ -2499,7 +2495,6 @@ FSharp.Compiler.EditorServices.CompletionContext+ParameterList: System.Collectio FSharp.Compiler.EditorServices.CompletionContext+RecordField: FSharp.Compiler.EditorServices.RecordContext context FSharp.Compiler.EditorServices.CompletionContext+RecordField: FSharp.Compiler.EditorServices.RecordContext get_context() FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 AttributeApplication -FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 AttributeApplicationParameterList FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 Inherit FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 Invalid FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 OpenDeclaration @@ -2513,7 +2508,6 @@ FSharp.Compiler.EditorServices.CompletionContext: Boolean Equals(FSharp.Compiler FSharp.Compiler.EditorServices.CompletionContext: Boolean Equals(System.Object) FSharp.Compiler.EditorServices.CompletionContext: Boolean Equals(System.Object, System.Collections.IEqualityComparer) FSharp.Compiler.EditorServices.CompletionContext: Boolean IsAttributeApplication -FSharp.Compiler.EditorServices.CompletionContext: Boolean IsAttributeApplicationParameterList FSharp.Compiler.EditorServices.CompletionContext: Boolean IsInherit FSharp.Compiler.EditorServices.CompletionContext: Boolean IsInvalid FSharp.Compiler.EditorServices.CompletionContext: Boolean IsOpenDeclaration @@ -2524,7 +2518,6 @@ FSharp.Compiler.EditorServices.CompletionContext: Boolean IsRecordField FSharp.Compiler.EditorServices.CompletionContext: Boolean IsTypeAbbreviationOrSingleCaseUnion FSharp.Compiler.EditorServices.CompletionContext: Boolean IsUnionCaseFieldsDeclaration FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsAttributeApplication() -FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsAttributeApplicationParameterList() FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsInherit() FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsInvalid() FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsOpenDeclaration() @@ -2536,7 +2529,6 @@ FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsTypeAbbreviation FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsUnionCaseFieldsDeclaration() FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext AttributeApplication FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext Invalid -FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewAttributeApplicationParameterList(FSharp.Compiler.Text.Position, System.Collections.Generic.HashSet`1[System.String]) FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewInherit(FSharp.Compiler.EditorServices.InheritanceContext, System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.String],Microsoft.FSharp.Core.FSharpOption`1[System.String]]) FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewOpenDeclaration(Boolean) FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewParameterList(FSharp.Compiler.Text.Position, System.Collections.Generic.HashSet`1[System.String]) @@ -2551,7 +2543,6 @@ FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext get_RangeOperator() FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext get_TypeAbbreviationOrSingleCaseUnion() FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext get_UnionCaseFieldsDeclaration() -FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+Inherit FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+OpenDeclaration FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+ParameterList diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index 814f59c159d..c80440dc2ac 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -2482,10 +2482,6 @@ FSharp.Compiler.EditorServices.AssemblySymbol: System.String get_FullName() FSharp.Compiler.EditorServices.AssemblySymbol: System.String[] CleanedIdents FSharp.Compiler.EditorServices.AssemblySymbol: System.String[] get_CleanedIdents() FSharp.Compiler.EditorServices.AssemblySymbol: Void .ctor(System.String, System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpFunc`2[FSharp.Compiler.EditorServices.LookupType,FSharp.Compiler.EditorServices.EntityKind], FSharp.Compiler.EditorServices.UnresolvedSymbol) -FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: FSharp.Compiler.Text.Position Item1 -FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: FSharp.Compiler.Text.Position get_Item1() -FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: System.Collections.Generic.HashSet`1[System.String] Item2 -FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList: System.Collections.Generic.HashSet`1[System.String] get_Item2() FSharp.Compiler.EditorServices.CompletionContext+Inherit: FSharp.Compiler.EditorServices.InheritanceContext context FSharp.Compiler.EditorServices.CompletionContext+Inherit: FSharp.Compiler.EditorServices.InheritanceContext get_context() FSharp.Compiler.EditorServices.CompletionContext+Inherit: System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.String],Microsoft.FSharp.Core.FSharpOption`1[System.String]] get_path() @@ -2499,7 +2495,6 @@ FSharp.Compiler.EditorServices.CompletionContext+ParameterList: System.Collectio FSharp.Compiler.EditorServices.CompletionContext+RecordField: FSharp.Compiler.EditorServices.RecordContext context FSharp.Compiler.EditorServices.CompletionContext+RecordField: FSharp.Compiler.EditorServices.RecordContext get_context() FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 AttributeApplication -FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 AttributeApplicationParameterList FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 Inherit FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 Invalid FSharp.Compiler.EditorServices.CompletionContext+Tags: Int32 OpenDeclaration @@ -2513,7 +2508,6 @@ FSharp.Compiler.EditorServices.CompletionContext: Boolean Equals(FSharp.Compiler FSharp.Compiler.EditorServices.CompletionContext: Boolean Equals(System.Object) FSharp.Compiler.EditorServices.CompletionContext: Boolean Equals(System.Object, System.Collections.IEqualityComparer) FSharp.Compiler.EditorServices.CompletionContext: Boolean IsAttributeApplication -FSharp.Compiler.EditorServices.CompletionContext: Boolean IsAttributeApplicationParameterList FSharp.Compiler.EditorServices.CompletionContext: Boolean IsInherit FSharp.Compiler.EditorServices.CompletionContext: Boolean IsInvalid FSharp.Compiler.EditorServices.CompletionContext: Boolean IsOpenDeclaration @@ -2524,7 +2518,6 @@ FSharp.Compiler.EditorServices.CompletionContext: Boolean IsRecordField FSharp.Compiler.EditorServices.CompletionContext: Boolean IsTypeAbbreviationOrSingleCaseUnion FSharp.Compiler.EditorServices.CompletionContext: Boolean IsUnionCaseFieldsDeclaration FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsAttributeApplication() -FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsAttributeApplicationParameterList() FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsInherit() FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsInvalid() FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsOpenDeclaration() @@ -2536,7 +2529,6 @@ FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsTypeAbbreviation FSharp.Compiler.EditorServices.CompletionContext: Boolean get_IsUnionCaseFieldsDeclaration() FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext AttributeApplication FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext Invalid -FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewAttributeApplicationParameterList(FSharp.Compiler.Text.Position, System.Collections.Generic.HashSet`1[System.String]) FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewInherit(FSharp.Compiler.EditorServices.InheritanceContext, System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.String],Microsoft.FSharp.Core.FSharpOption`1[System.String]]) FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewOpenDeclaration(Boolean) FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext NewParameterList(FSharp.Compiler.Text.Position, System.Collections.Generic.HashSet`1[System.String]) @@ -2551,7 +2543,6 @@ FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext get_RangeOperator() FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext get_TypeAbbreviationOrSingleCaseUnion() FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext get_UnionCaseFieldsDeclaration() -FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+AttributeApplicationParameterList FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+Inherit FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+OpenDeclaration FSharp.Compiler.EditorServices.CompletionContext: FSharp.Compiler.EditorServices.CompletionContext+ParameterList diff --git a/tests/service/ServiceUntypedParseTests.fs b/tests/service/ServiceUntypedParseTests.fs index 86b3bd83d2a..ea2591b8bf9 100644 --- a/tests/service/ServiceUntypedParseTests.fs +++ b/tests/service/ServiceUntypedParseTests.fs @@ -19,7 +19,7 @@ open NUnit.Framework let [] private Marker = "(* marker *)" -let private (=>) (source: string) (expected: CompletionContext option) = +let private assertCompletionContext (checker: CompletionContext option -> bool) (source: string) = let lines = use reader = new StringReader(source) @@ -43,10 +43,10 @@ let private (=>) (source: string) (expected: CompletionContext option) = | Some markerPos -> let parseTree = parseSourceCode("C:\\test.fs", source) let actual = ParsedInput.TryGetCompletionContext(markerPos, parseTree, lines[Line.toZ markerPos.Line]) - try Assert.AreEqual(expected, actual) - with e -> + + if not (checker actual) then printfn "ParseTree: %A" parseTree - reraise() + failwithf "Completion context '%A' was not expected" actual module AttributeCompletion = [] @@ -54,7 +54,7 @@ module AttributeCompletion = """ [<(* marker *) """ - => Some CompletionContext.AttributeApplication + |> assertCompletionContext (fun x -> x = Some CompletionContext.AttributeApplication) [] [] @@ -65,17 +65,13 @@ module AttributeCompletion = [] [][<(* marker *)", true)>] [][< (* marker *)", true)>] - [] - [] - [] - [][] - [] let ``incomplete``(lineStr: string, expectAttributeApplicationContext: bool) = - (sprintf """ -%s + let code = $""" +{lineStr} type T = - { F: int } -""" lineStr) => (if expectAttributeApplicationContext then Some CompletionContext.AttributeApplication else None) + {{ F: int }} +""" + code |> assertCompletionContext (fun x -> x = (if expectAttributeApplicationContext then Some CompletionContext.AttributeApplication else None)) []", true)>] []", true)>] @@ -87,20 +83,40 @@ type T = []", true)>] []", true)>] [][]", true)>] - []", false)>] []", false)>] - [][]", false)>] - []", false)>] - []", false)>] - [][]", false)>] let ``complete``(lineStr: string, expectAttributeApplicationContext: bool) = - (sprintf """ -%s + let code = $""" +{lineStr} type T = - { F: int } -""" lineStr) => (if expectAttributeApplicationContext then Some CompletionContext.AttributeApplication else None) - - + {{ F: int }} +""" + code |> assertCompletionContext (fun x -> x = (if expectAttributeApplicationContext then Some CompletionContext.AttributeApplication else None)) + +module AttributeConstructorCompletion = + [] + [] + [][] + [] + let ``incomplete``(lineStr: string) = + let code = $""" +{lineStr} +type T = + {{ F: int }} +""" + code |> assertCompletionContext (fun x -> match x with Some (CompletionContext.ParameterList _) -> true | _ -> false) + + []")>] + [][]")>] + []")>] + []")>] + [][]")>] + let ``complete``(lineStr: string) = + let code = $""" +{lineStr} +type T = + {{ F: int }} +""" + code |> assertCompletionContext (fun x -> match x with Some (CompletionContext.ParameterList _) -> true | _ -> false) [] let ``Attribute lists`` () = From 5a784737544a319043852e957c4b6209d4b6de82 Mon Sep 17 00:00:00 2001 From: kerams Date: Mon, 6 Feb 2023 10:15:46 +0100 Subject: [PATCH 4/5] Move fishy test --- src/Compiler/Service/ServiceParseTreeWalk.fs | 32 ++++++++----------- .../CompletionTests.fs | 11 ++++++- .../Tests.LanguageService.Completion.fs | 25 --------------- 3 files changed, 24 insertions(+), 44 deletions(-) diff --git a/src/Compiler/Service/ServiceParseTreeWalk.fs b/src/Compiler/Service/ServiceParseTreeWalk.fs index 760d1bc0ed0..db84b8d9e71 100644 --- a/src/Compiler/Service/ServiceParseTreeWalk.fs +++ b/src/Compiler/Service/ServiceParseTreeWalk.fs @@ -287,7 +287,7 @@ module SyntaxTraversal = | SynModuleDecl.NestedModule (decls = synModuleDecls; moduleInfo = SynComponentInfo (attributes = attributes)) -> synModuleDecls |> List.map (fun x -> dive x x.Range (traverseSynModuleDecl path)) - |> List.append (traverseAttributeApplication path attributes) + |> List.append (attributeApplicationDives path attributes) |> pick decl | SynModuleDecl.Let (isRecursive, synBindingList, range) -> match visitor.VisitLetOrUse(path, isRecursive, traverseSynBinding path, synBindingList, range) with @@ -303,7 +303,7 @@ module SyntaxTraversal = |> pick decl | SynModuleDecl.Exception (_synExceptionDefn, _range) -> None | SynModuleDecl.Open (_target, _range) -> None - | SynModuleDecl.Attributes (attributes, _) -> traverseAttributeApplication path attributes |> pick decl + | SynModuleDecl.Attributes (attributes, _) -> attributeApplicationDives path attributes |> pick decl | SynModuleDecl.HashDirective (parsedHashDirective, range) -> visitor.VisitHashDirective(path, parsedHashDirective, range) | SynModuleDecl.NamespaceFragment (synModuleOrNamespace) -> traverseSynModuleOrNamespace path synModuleOrNamespace @@ -801,7 +801,7 @@ module SyntaxTraversal = | SynPat.ArrayOrList (_, ps, _) -> ps |> List.tryPick (traversePat path) | SynPat.Attrib (p, attributes, m) -> match traversePat path p with - | None -> traverseAttributeApplication path attributes |> pick m attributes + | None -> attributeApplicationDives path attributes |> pick m attributes | x -> x | SynPat.LongIdent (argPats = args) -> match args with @@ -822,7 +822,7 @@ module SyntaxTraversal = |> List.tryPick (fun pat -> match pat with | SynSimplePat.Attrib (attributes = attributes; range = m) -> - traverseAttributeApplication origPath attributes |> pick m attributes + attributeApplicationDives origPath attributes |> pick m attributes | _ -> None) | x -> x @@ -878,7 +878,7 @@ module SyntaxTraversal = match synComponentInfo with | SynComponentInfo (attributes = attributes) -> [ - yield! traverseAttributeApplication path attributes + yield! attributeApplicationDives path attributes match synTypeDefnRepr with | SynTypeDefnRepr.Exception _ -> @@ -912,25 +912,25 @@ module SyntaxTraversal = and traverseRecordDefn path fields m = fields - |> List.tryPick (fun (SynField (attributes = attributes)) -> traverseAttributeApplication path attributes |> pick m attributes) + |> List.tryPick (fun (SynField (attributes = attributes)) -> attributeApplicationDives path attributes |> pick m attributes) |> Option.orElseWith (fun () -> visitor.VisitRecordDefn(path, fields, m)) and traverseEnumDefn path cases m = cases |> List.tryPick (fun (SynEnumCase (attributes = attributes)) -> - traverseAttributeApplication path attributes |> pick m attributes) + attributeApplicationDives path attributes |> pick m attributes) |> Option.orElseWith (fun () -> visitor.VisitEnumDefn(path, cases, m)) and traverseUnionDefn path cases m = cases |> List.tryPick (fun (SynUnionCase (attributes = attributes; caseType = caseType)) -> - match traverseAttributeApplication path attributes |> pick m attributes with + match attributeApplicationDives path attributes |> pick m attributes with | None -> match caseType with | SynUnionCaseKind.Fields fields -> fields |> List.tryPick (fun (SynField (attributes = attributes)) -> - traverseAttributeApplication path attributes |> pick m attributes) + attributeApplicationDives path attributes |> pick m attributes) | _ -> None | x -> x) |> Option.orElseWith (fun () -> visitor.VisitUnionDefn(path, cases, m)) @@ -966,7 +966,7 @@ module SyntaxTraversal = |> pick m | SynMemberDefn.AutoProperty (synExpr = synExpr; attributes = attributes) -> match traverseSynExpr path synExpr with - | None -> traverseAttributeApplication path attributes |> pick attributes + | None -> attributeApplicationDives path attributes |> pick attributes | x -> x | SynMemberDefn.LetBindings (synBindingList, isRecursive, _, range) -> match visitor.VisitLetOrUse(path, isRecursive, traverseSynBinding path, synBindingList, range) with @@ -977,7 +977,7 @@ module SyntaxTraversal = | x -> x | SynMemberDefn.AbstractSlot(slotSig = SynValSig (synType = synType; attributes = attributes)) -> match traverseSynType path synType with - | None -> traverseAttributeApplication path attributes |> pick attributes + | None -> attributeApplicationDives path attributes |> pick attributes | x -> x | SynMemberDefn.Interface (interfaceType = synType; members = synMemberDefnsOption) -> match visitor.VisitInterfaceSynMemberDefnType(path, synType) with @@ -1021,7 +1021,7 @@ module SyntaxTraversal = match b with | SynBinding (headPat = synPat; expr = synExpr; attributes = attributes; range = m) -> [ - yield! traverseAttributeApplication path attributes + yield! attributeApplicationDives path attributes dive synPat synPat.Range (traversePat path) dive synExpr synExpr.Range (traverseSynExpr path) ] @@ -1029,12 +1029,8 @@ module SyntaxTraversal = visitor.VisitBinding(origPath, defaultTraverse, b) - and traverseAttributeApplication origPath attributes = - match attributes with - | [] -> [] - | _ -> - attributes - |> List.map (fun attributes -> dive () attributes.Range (fun () -> visitor.VisitAttributeApplication(origPath, attributes))) + and attributeApplicationDives origPath attributes = + attributes |> List.map (fun attributes -> dive () attributes.Range (fun () -> visitor.VisitAttributeApplication(origPath, attributes))) match parseTree with | ParsedInput.ImplFile file -> diff --git a/tests/FSharp.Compiler.Private.Scripting.UnitTests/CompletionTests.fs b/tests/FSharp.Compiler.Private.Scripting.UnitTests/CompletionTests.fs index 8bc7fa581a1..01dd539eab7 100644 --- a/tests/FSharp.Compiler.Private.Scripting.UnitTests/CompletionTests.fs +++ b/tests/FSharp.Compiler.Private.Scripting.UnitTests/CompletionTests.fs @@ -157,4 +157,13 @@ type CompletionTests() = Assert.Equal(1, matchingCompletions.Length) Assert.Equal("A", matchingCompletions.[0].NameInCode) - + [] + member _.``Completions for record field with backticks`` () = + use script = new FSharpScript() + let lines = [ "type MyRec = { ``field.field`` : string }" + "let a = {``field.field`` = \"\"}" + "a." ] + let completions = script.GetCompletionItems(String.Join("\n", lines), 3, 2) |> Async.RunSynchronously + let matchingCompletions = completions |> Array.filter (fun d -> d.NameInList = "field.field") + Assert.Equal(1, matchingCompletions.Length) + Assert.Equal("``field.field``", matchingCompletions.[0].NameInCode) \ No newline at end of file diff --git a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs index 368df57ad3f..a6202350d0d 100644 --- a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs +++ b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs @@ -315,31 +315,6 @@ type UsingMSBuild() as this = test "DU_3." "DU_3." ["ExtensionPropObj"; "ExtensionMethodObj"; "Equals"] ["GetHashCode"] // no gethashcode, has equals defined in DU3 type test "DU_4." "DU_4." ["ExtensionPropObj"; "ExtensionMethodObj"; "GetHashCode"] ["Equals"] // no equals, has gethashcode defined in DU4 type - [] - member this.``AutoCompletion.escaped with backticks`` () = - let code = """ -type MyRec = { - ``field.field`` : string -} - -let a = {``field.field`` = ""} -a. - """ - this.AssertCtrlSpaceCompletion( - [code] - , "a." - , (fun completions -> - completions - |> Seq.tryFind (fun (CompletionItem(_,name,nameInCode,_,_)) -> - name = "field.field" - && nameInCode = "``field.field``" - ) - |> function - | Some _ -> () - | None -> Assert.Fail "expected ``field.field`` to be present" - - )) - [] member this.``AutoCompletion.BeforeThis``() = let code = From 439321bb8eae22e781f603b6c127c6745260ceda Mon Sep 17 00:00:00 2001 From: kerams Date: Mon, 6 Feb 2023 10:21:55 +0100 Subject: [PATCH 5/5] Fix formatting --- src/Compiler/Service/ServiceParseTreeWalk.fs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Compiler/Service/ServiceParseTreeWalk.fs b/src/Compiler/Service/ServiceParseTreeWalk.fs index db84b8d9e71..b938c8a2254 100644 --- a/src/Compiler/Service/ServiceParseTreeWalk.fs +++ b/src/Compiler/Service/ServiceParseTreeWalk.fs @@ -917,8 +917,7 @@ module SyntaxTraversal = and traverseEnumDefn path cases m = cases - |> List.tryPick (fun (SynEnumCase (attributes = attributes)) -> - attributeApplicationDives path attributes |> pick m attributes) + |> List.tryPick (fun (SynEnumCase (attributes = attributes)) -> attributeApplicationDives path attributes |> pick m attributes) |> Option.orElseWith (fun () -> visitor.VisitEnumDefn(path, cases, m)) and traverseUnionDefn path cases m = @@ -1030,7 +1029,8 @@ module SyntaxTraversal = visitor.VisitBinding(origPath, defaultTraverse, b) and attributeApplicationDives origPath attributes = - attributes |> List.map (fun attributes -> dive () attributes.Range (fun () -> visitor.VisitAttributeApplication(origPath, attributes))) + attributes + |> List.map (fun attributes -> dive () attributes.Range (fun () -> visitor.VisitAttributeApplication(origPath, attributes))) match parseTree with | ParsedInput.ImplFile file ->