diff --git a/src/Compiler/Checking/NicePrint.fs b/src/Compiler/Checking/NicePrint.fs
index 072dc76a100..db54e06faf6 100644
--- a/src/Compiler/Checking/NicePrint.fs
+++ b/src/Compiler/Checking/NicePrint.fs
@@ -1795,7 +1795,7 @@ module TastDefinitionPrinting =
let overallL = staticL ^^ WordL.keywordMember ^^ (nameL |> addColonL) ^^ typL
layoutXmlDocOfEventInfo denv infoReader einfo overallL
- let layoutPropInfo denv (infoReader: InfoReader) m (pinfo: PropInfo) =
+ let layoutPropInfo denv (infoReader: InfoReader) m (pinfo: PropInfo) : Layout list =
let amap = infoReader.amap
let isPublicGetterSetter (getter: MethInfo) (setter: MethInfo) =
@@ -1804,13 +1804,33 @@ module TastDefinitionPrinting =
| Some gRef, Some sRef -> isPublicAccess gRef.Accessibility && isPublicAccess sRef.Accessibility
| _ -> false
+ let (|MixedAccessibilityGetterAndSetter|_|) (pinfo: PropInfo) =
+ if not (pinfo.HasGetter && pinfo.HasSetter) then
+ None
+ else
+ match pinfo.GetterMethod.ArbitraryValRef, pinfo.SetterMethod.ArbitraryValRef with
+ | Some getValRef, Some setValRef ->
+ if getValRef.Accessibility = setValRef.Accessibility then
+ None
+ else
+ Some (getValRef, setValRef)
+ | _ -> None
+
match pinfo.ArbitraryValRef with
| Some vref ->
- let propL = PrintTastMemberOrVals.prettyLayoutOfValOrMemberNoInst denv infoReader vref
- if pinfo.HasGetter && pinfo.HasSetter && not pinfo.IsIndexer && isPublicGetterSetter pinfo.GetterMethod pinfo.SetterMethod then
- propL ^^ wordL (tagKeyword "with") ^^ wordL (tagText "get, set")
- else
- propL
+ match pinfo with
+ | MixedAccessibilityGetterAndSetter(getValRef, setValRef) ->
+ let getSuffix = if pinfo.IsIndexer then emptyL else wordL (tagKeyword "with") ^^ wordL (tagText "get")
+ [
+ PrintTastMemberOrVals.prettyLayoutOfValOrMemberNoInst denv infoReader getValRef ^^ getSuffix
+ PrintTastMemberOrVals.prettyLayoutOfValOrMemberNoInst denv infoReader setValRef
+ ]
+ | _ ->
+ let propL = PrintTastMemberOrVals.prettyLayoutOfValOrMemberNoInst denv infoReader vref
+ if pinfo.HasGetter && pinfo.HasSetter && not pinfo.IsIndexer && isPublicGetterSetter pinfo.GetterMethod pinfo.SetterMethod then
+ [ propL ^^ wordL (tagKeyword "with") ^^ wordL (tagText "get, set") ]
+ else
+ [ propL ]
| None ->
let modifierAndMember =
@@ -1822,7 +1842,7 @@ module TastDefinitionPrinting =
let nameL = ConvertValLogicalNameToDisplayLayout false (tagProperty >> tagNavArbValRef pinfo.ArbitraryValRef >> wordL) pinfo.PropertyName
let typL = layoutType denv (pinfo.GetPropertyType(amap, m))
let overallL = modifierAndMember ^^ (nameL |> addColonL) ^^ typL
- layoutXmlDocOfPropInfo denv infoReader pinfo overallL
+ [ layoutXmlDocOfPropInfo denv infoReader pinfo overallL ]
let layoutTyconDefn (denv: DisplayEnv) (infoReader: InfoReader) ad m simplified isFirstType (tcref: TyconRef) =
let g = denv.g
@@ -1993,7 +2013,9 @@ module TastDefinitionPrinting =
let propLs =
props
- |> List.map (fun x -> (true, x.IsStatic, x.PropertyName, 0, 0), layoutPropInfo denv infoReader m x)
+ |> List.collect (fun x ->
+ layoutPropInfo denv infoReader m x
+ |> List.map (fun layout -> (true, x.IsStatic, x.PropertyName, 0, 0), layout))
|> List.sortBy fst
|> List.map snd
diff --git a/src/Compiler/Driver/GraphChecking/DependencyResolution.fs b/src/Compiler/Driver/GraphChecking/DependencyResolution.fs
index b30d9753592..4cf689963cb 100644
--- a/src/Compiler/Driver/GraphChecking/DependencyResolution.fs
+++ b/src/Compiler/Driver/GraphChecking/DependencyResolution.fs
@@ -1,35 +1,45 @@
module internal FSharp.Compiler.GraphChecking.DependencyResolution
-open FSharp.Compiler.IO
open FSharp.Compiler.Syntax
+open Internal.Utilities.Library
-/// Find a path in the Trie.
-/// This function could be cached in future if performance is an issue.
-let queryTrie (trie: TrieNode) (path: LongIdentifier) : QueryTrieNodeResult =
+/// Find a path from a starting TrieNode and return the end node or None
+let queryTriePartial (trie: TrieNode) (path: LongIdentifier) : TrieNode option =
let rec visit (currentNode: TrieNode) (path: LongIdentifier) =
match path with
- | [] -> failwith "path should not be empty"
- | [ lastNodeFromPath ] ->
- match currentNode.Children.TryGetValue(lastNodeFromPath) with
- | false, _ -> QueryTrieNodeResult.NodeDoesNotExist
- | true, childNode ->
- if Set.isEmpty childNode.Files then
- QueryTrieNodeResult.NodeDoesNotExposeData
- else
- QueryTrieNodeResult.NodeExposesData(childNode.Files)
+ // When we get through all partial identifiers, we've reached the node the full path points to.
+ | [] -> Some currentNode
+ // More segments to get through
| currentPath :: restPath ->
match currentNode.Children.TryGetValue(currentPath) with
- | false, _ -> QueryTrieNodeResult.NodeDoesNotExist
+ | false, _ -> None
| true, childNode -> visit childNode restPath
visit trie path
-let queryTrieMemoized (trie: TrieNode) : QueryTrie =
- Internal.Utilities.Library.Tables.memoize (queryTrie trie)
+let mapNodeToQueryResult (node: TrieNode option) : QueryTrieNodeResult =
+ match node with
+ | Some finalNode ->
+ if Set.isEmpty finalNode.Files then
+ QueryTrieNodeResult.NodeDoesNotExposeData
+ else
+ QueryTrieNodeResult.NodeExposesData(finalNode.Files)
+ | None -> QueryTrieNodeResult.NodeDoesNotExist
+
+/// Find a path in the Trie.
+let queryTrie (trie: TrieNode) (path: LongIdentifier) : QueryTrieNodeResult =
+ queryTriePartial trie path |> mapNodeToQueryResult
+
+/// Same as 'queryTrie' but allows passing in a path combined from two parts, avoiding list allocation.
+let queryTrieDual (trie: TrieNode) (path1: LongIdentifier) (path2: LongIdentifier) : QueryTrieNodeResult =
+ match queryTriePartial trie path1 with
+ | Some intermediateNode -> queryTriePartial intermediateNode path2
+ | None -> None
+ |> mapNodeToQueryResult
/// Process namespace declaration.
-let processNamespaceDeclaration (queryTrie: QueryTrie) (path: LongIdentifier) (state: FileContentQueryState) : FileContentQueryState =
- let queryResult = queryTrie path
+let processNamespaceDeclaration (trie: TrieNode) (path: LongIdentifier) (state: FileContentQueryState) : FileContentQueryState =
+ let queryResult = queryTrie trie path
match queryResult with
| QueryTrieNodeResult.NodeDoesNotExist -> state
@@ -38,8 +48,8 @@ let processNamespaceDeclaration (queryTrie: QueryTrie) (path: LongIdentifier) (s
/// Process an "open" statement.
/// The statement could link to files and/or should be tracked as an open namespace.
-let processOpenPath (queryTrie: QueryTrie) (path: LongIdentifier) (state: FileContentQueryState) : FileContentQueryState =
- let queryResult = queryTrie path
+let processOpenPath (trie: TrieNode) (path: LongIdentifier) (state: FileContentQueryState) : FileContentQueryState =
+ let queryResult = queryTrie trie path
match queryResult with
| QueryTrieNodeResult.NodeDoesNotExist -> state
@@ -47,9 +57,7 @@ let processOpenPath (queryTrie: QueryTrie) (path: LongIdentifier) (state: FileCo
| QueryTrieNodeResult.NodeExposesData files -> state.AddOpenNamespace(path, files)
/// Process an identifier.
-let processIdentifier (queryTrie: QueryTrie) (path: LongIdentifier) (state: FileContentQueryState) : FileContentQueryState =
- let queryResult = queryTrie path
-
+let processIdentifier (queryResult: QueryTrieNodeResult) (state: FileContentQueryState) : FileContentQueryState =
match queryResult with
| QueryTrieNodeResult.NodeDoesNotExist -> state
| QueryTrieNodeResult.NodeDoesNotExposeData ->
@@ -59,26 +67,26 @@ let processIdentifier (queryTrie: QueryTrie) (path: LongIdentifier) (state: File
| QueryTrieNodeResult.NodeExposesData files -> state.AddDependencies files
/// Typically used to fold FileContentEntry items over a FileContentQueryState
-let rec processStateEntry (queryTrie: QueryTrie) (state: FileContentQueryState) (entry: FileContentEntry) : FileContentQueryState =
+let rec processStateEntry (trie: TrieNode) (state: FileContentQueryState) (entry: FileContentEntry) : FileContentQueryState =
match entry with
| FileContentEntry.TopLevelNamespace (topLevelPath, content) ->
let state =
match topLevelPath with
| [] -> state
- | _ -> processNamespaceDeclaration queryTrie topLevelPath state
+ | _ -> processNamespaceDeclaration trie topLevelPath state
- List.fold (processStateEntry queryTrie) state content
+ List.fold (processStateEntry trie) state content
| FileContentEntry.OpenStatement path ->
// An open statement can directly reference file or be a partial open statement
// Both cases need to be processed.
- let stateAfterFullOpenPath = processOpenPath queryTrie path state
+ let stateAfterFullOpenPath = processOpenPath trie path state
- // Any existing open statement could be extended with the current path (if that node where to exists in the trie)
+ // Any existing open statement could be extended with the current path (if that node were to exists in the trie)
// The extended path could add a new link (in case of a module or namespace with types)
- // It might also not add anything at all (in case it the extended path is still a partial one)
+ // It might also not add anything at all (in case the extended path is still a partial one)
(stateAfterFullOpenPath, state.OpenNamespaces)
- ||> Set.fold (fun acc openNS -> processOpenPath queryTrie [ yield! openNS; yield! path ] acc)
+ ||> Set.fold (fun acc openNS -> processOpenPath trie [ yield! openNS; yield! path ] acc)
| FileContentEntry.PrefixedIdentifier path ->
match path with
@@ -91,15 +99,17 @@ let rec processStateEntry (queryTrie: QueryTrie) (state: FileContentQueryState)
||> Array.fold (fun state takeParts ->
let path = List.take takeParts path
// process the name was if it were a FQN
- let stateAfterFullIdentifier = processIdentifier queryTrie path state
+ let stateAfterFullIdentifier = processIdentifier (queryTrieDual trie [] path) state
// Process the name in combination with the existing open namespaces
(stateAfterFullIdentifier, state.OpenNamespaces)
- ||> Set.fold (fun acc openNS -> processIdentifier queryTrie [ yield! openNS; yield! path ] acc))
+ ||> Set.fold (fun acc openNS ->
+ let queryResult = queryTrieDual trie openNS path
+ processIdentifier queryResult acc))
| FileContentEntry.NestedModule (nestedContent = nestedContent) ->
// We don't want our current state to be affect by any open statements in the nested module
- let nestedState = List.fold (processStateEntry queryTrie) state nestedContent
+ let nestedState = List.fold (processStateEntry trie) state nestedContent
// Afterward we are only interested in the found dependencies in the nested module
let foundDependencies =
Set.union state.FoundDependencies nestedState.FoundDependencies
@@ -123,11 +133,11 @@ let rec processStateEntry (queryTrie: QueryTrie) (state: FileContentQueryState)
/// This function returns an array with a potential extra dependencies that makes sure that any such namespaces can be resolved (if they exists).
/// For each unused namespace `open` we return at most one file that defines that namespace.
///
-let collectGhostDependencies (fileIndex: FileIndex) (trie: TrieNode) (queryTrie: QueryTrie) (result: FileContentQueryState) =
+let collectGhostDependencies (fileIndex: FileIndex) (trie: TrieNode) (result: FileContentQueryState) =
// For each opened namespace, if none of already resolved dependencies define it, return the top-most file that defines it.
Set.toArray result.OpenedNamespaces
|> Array.choose (fun path ->
- match queryTrie path with
+ match queryTrie trie path with
| QueryTrieNodeResult.NodeExposesData _
| QueryTrieNodeResult.NodeDoesNotExist -> None
| QueryTrieNodeResult.NodeDoesNotExposeData ->
@@ -170,7 +180,6 @@ let mkGraph (compilingFSharpCore: bool) (filePairs: FilePairMap) (files: FileInP
| ParsedInput.SigFile _ -> Some f)
let trie = TrieMapping.mkTrie trieInput
- let queryTrie: QueryTrie = queryTrieMemoized trie
let fileContents =
files
@@ -180,6 +189,23 @@ let mkGraph (compilingFSharpCore: bool) (filePairs: FilePairMap) (files: FileInP
else
FileContentMapping.mkFileContent file)
+ // Files in FSharp.Core have an implicit dependency on `prim-types-prelude.fsi` - add it.
+ let fsharpCoreImplicitDependency =
+ if compilingFSharpCore then
+ let filename = "prim-types-prelude.fsi"
+
+ let implicitDepIdx =
+ files
+ |> Array.tryFindIndex (fun f -> System.IO.Path.GetFileName(f.FileName) = filename)
+
+ match implicitDepIdx with
+ | Some idx -> Some idx
+ | None ->
+ exn $"Expected to find file '{filename}' during compilation of FSharp.Core, but it was not found."
+ |> raise
+ else
+ None
+
let findDependencies (file: FileInProject) : FileIndex array =
if file.Idx = 0 then
// First file cannot have any dependencies.
@@ -187,7 +213,7 @@ let mkGraph (compilingFSharpCore: bool) (filePairs: FilePairMap) (files: FileInP
else
let fileContent = fileContents[file.Idx]
- let knownFiles = [ 0 .. (file.Idx - 1) ] |> set
+ let knownFiles = [| 0 .. (file.Idx - 1) |] |> set
// File depends on all files above it that define accessible symbols at the root level (global namespace).
let filesFromRoot = trie.Files |> Set.filter (fun rootIdx -> rootIdx < file.Idx)
// Start by listing root-level dependencies.
@@ -197,10 +223,10 @@ let mkGraph (compilingFSharpCore: bool) (filePairs: FilePairMap) (files: FileInP
let depsResult =
initialDepsResult
// Seq is faster than List in this case.
- ||> Seq.fold (processStateEntry queryTrie)
+ ||> Seq.fold (processStateEntry trie)
// Add missing links for cases where an unused open namespace did not create a link.
- let ghostDependencies = collectGhostDependencies file.Idx trie queryTrie depsResult
+ let ghostDependencies = collectGhostDependencies file.Idx trie depsResult
// Add a link from implementation files to their signature files.
let signatureDependency =
@@ -208,31 +234,17 @@ let mkGraph (compilingFSharpCore: bool) (filePairs: FilePairMap) (files: FileInP
| None -> Array.empty
| Some sigIdx -> Array.singleton sigIdx
- // Files in FSharp.Core have an implicit dependency on `prim-types-prelude.fsi` - add it.
- let fsharpCoreImplicitDependencies =
- let filename = "prim-types-prelude.fsi"
-
- let implicitDepIdx =
- files
- |> Array.tryFindIndex (fun f -> FileSystemUtils.fileNameOfPath f.FileName = filename)
-
- [|
- if compilingFSharpCore then
- match implicitDepIdx with
- | Some idx ->
- if file.Idx > idx then
- yield idx
- | None ->
- exn $"Expected to find file '{filename}' during compilation of FSharp.Core, but it was not found."
- |> raise
- |]
+ let fsharpCoreImplicitDependencyForThisFile =
+ match fsharpCoreImplicitDependency with
+ | Some depIdx when file.Idx > depIdx -> [| depIdx |]
+ | _ -> [||]
let allDependencies =
[|
yield! depsResult.FoundDependencies
yield! ghostDependencies
yield! signatureDependency
- yield! fsharpCoreImplicitDependencies
+ yield! fsharpCoreImplicitDependencyForThisFile
|]
|> Array.distinct
diff --git a/src/Compiler/Driver/GraphChecking/DependencyResolution.fsi b/src/Compiler/Driver/GraphChecking/DependencyResolution.fsi
index ef0bddec478..88d92de75a1 100644
--- a/src/Compiler/Driver/GraphChecking/DependencyResolution.fsi
+++ b/src/Compiler/Driver/GraphChecking/DependencyResolution.fsi
@@ -7,8 +7,7 @@ val queryTrie: trie: TrieNode -> path: LongIdentifier -> QueryTrieNodeResult
/// Process an open path (found in the ParsedInput) with a given FileContentQueryState.
/// This code is only used directly in unit tests.
-val processOpenPath:
- queryTrie: QueryTrie -> path: LongIdentifier -> state: FileContentQueryState -> FileContentQueryState
+val processOpenPath: trie: TrieNode -> path: LongIdentifier -> state: FileContentQueryState -> FileContentQueryState
///
/// Construct an approximate* dependency graph for files within a project, based on their ASTs.
diff --git a/src/Compiler/SyntaxTree/LexFilter.fs b/src/Compiler/SyntaxTree/LexFilter.fs
index 6befda9a8eb..1c5b635498d 100644
--- a/src/Compiler/SyntaxTree/LexFilter.fs
+++ b/src/Compiler/SyntaxTree/LexFilter.fs
@@ -49,7 +49,7 @@ type Context =
| CtxtTypeDefns of Position // 'type =', not removed when we find the "="
| CtxtNamespaceHead of Position * token
- | CtxtModuleHead of Position * token * LexingModuleAttributes
+ | CtxtModuleHead of Position * token * LexingModuleAttributes * isNested: bool
| CtxtMemberHead of Position
| CtxtMemberBody of Position
// If bool is true then this is "whole file"
@@ -68,7 +68,7 @@ type Context =
member c.StartPos =
match c with
- | CtxtNamespaceHead (p, _) | CtxtModuleHead (p, _, _) | CtxtException p | CtxtModuleBody (p, _) | CtxtNamespaceBody p
+ | CtxtNamespaceHead (p, _) | CtxtModuleHead (p, _, _, _) | CtxtException p | CtxtModuleBody (p, _) | CtxtNamespaceBody p
| CtxtLetDecl (_, p) | CtxtDo p | CtxtInterfaceHead p | CtxtTypeDefns p | CtxtParen (_, p) | CtxtMemberHead p | CtxtMemberBody p
| CtxtWithAsLet p
| CtxtWithAsAugment p
@@ -748,6 +748,9 @@ type LexFilterImpl (
// ignore Vanilla because a SeqBlock is always coming
| _, CtxtVanilla _ :: rest -> undentationLimit strict rest
+ | CtxtSeqBlock(FirstInSeqBlock, _, _), (CtxtDo _ as limitCtxt) :: CtxtSeqBlock _ :: (CtxtTypeDefns _ | CtxtModuleBody _) :: _ ->
+ PositionWithColumn(limitCtxt.StartPos, limitCtxt.StartCol + 1)
+
| _, CtxtSeqBlock _ :: rest when not strict -> undentationLimit strict rest
| _, CtxtParen _ :: rest when not strict -> undentationLimit strict rest
@@ -1390,6 +1393,9 @@ type LexFilterImpl (
| CtxtSeqBlock(_, _, AddOneSidedBlockEnd) ->
Some (ORIGHT_BLOCK_END(getLastTokenEndRange ()))
+ | CtxtModuleHead(isNested = true) ->
+ Some OBLOCKSEP
+
| _ ->
None
@@ -1587,7 +1593,7 @@ type LexFilterImpl (
| _ ->
delayToken tokenTup
pushCtxt tokenTup (CtxtNamespaceBody namespaceTokenPos)
- pushCtxtSeqBlockAt false tokenTup tokenTup AddBlockEnd
+ pushCtxtSeqBlockAt false false tokenTup tokenTup AddBlockEnd
hwTokenFetch false
// Transition rule. CtxtModuleHead ~~~> push CtxtModuleBody; push CtxtSeqBlock
@@ -1595,11 +1601,11 @@ type LexFilterImpl (
// Otherwise it's a 'head' module declaration, so ignore it
// Here prevToken is either 'module', 'rec', 'global' (invalid), '.', or ident, because we skip attribute tokens and access modifier tokens
- | _, CtxtModuleHead (moduleTokenPos, prevToken, lexingModuleAttributes) :: rest ->
+ | _, CtxtModuleHead (moduleTokenPos, prevToken, lexingModuleAttributes, isNested) :: rest ->
match prevToken, token with
| _, GREATER_RBRACK when lexingModuleAttributes = LexingModuleAttributes
&& moduleTokenPos.Column < tokenStartPos.Column ->
- replaceCtxt tokenTup (CtxtModuleHead (moduleTokenPos, prevToken, NotLexingModuleAttributes))
+ replaceCtxt tokenTup (CtxtModuleHead (moduleTokenPos, prevToken, NotLexingModuleAttributes, isNested))
returnToken tokenLexbufState token
| _ when lexingModuleAttributes = LexingModuleAttributes
&& moduleTokenPos.Column < tokenStartPos.Column ->
@@ -1609,10 +1615,10 @@ type LexFilterImpl (
| MODULE, GLOBAL
| (MODULE | REC | DOT), (REC | IDENT _)
| IDENT _, DOT when moduleTokenPos.Column < tokenStartPos.Column ->
- replaceCtxt tokenTup (CtxtModuleHead (moduleTokenPos, token, NotLexingModuleAttributes))
+ replaceCtxt tokenTup (CtxtModuleHead (moduleTokenPos, token, NotLexingModuleAttributes, isNested))
returnToken tokenLexbufState token
| MODULE, LBRACK_LESS when moduleTokenPos.Column < tokenStartPos.Column ->
- replaceCtxt tokenTup (CtxtModuleHead (moduleTokenPos, prevToken, LexingModuleAttributes))
+ replaceCtxt tokenTup (CtxtModuleHead (moduleTokenPos, prevToken, LexingModuleAttributes, isNested))
returnToken tokenLexbufState token
| _, (EQUALS | COLON) ->
if debug then dprintf "CtxtModuleHead: COLON/EQUALS, pushing CtxtModuleBody and CtxtSeqBlock\n"
@@ -1640,7 +1646,7 @@ type LexFilterImpl (
// and we've encountered declarations below
if debug then dprintf "CtxtModuleHead: not start of file, popping CtxtModuleHead\n"
popCtxt()
- reprocessWithoutBlockRule()
+ insertTokenFromPrevPosToCurrentPos OBLOCKSEP
// Offside rule for SeqBlock.
// f x
@@ -1969,7 +1975,8 @@ type LexFilterImpl (
| MODULE, _ :: _ ->
insertComingSoonTokens("MODULE", MODULE_COMING_SOON, MODULE_IS_HERE)
if debug then dprintf "MODULE: entering CtxtModuleHead, awaiting EQUALS to go to CtxtSeqBlock (%a)\n" outputPos tokenStartPos
- pushCtxt tokenTup (CtxtModuleHead (tokenStartPos, token, NotLexingModuleAttributes))
+ let isNested = match offsideStack with | [ CtxtSeqBlock _ ] -> false | _ -> true
+ pushCtxt tokenTup (CtxtModuleHead (tokenStartPos, token, NotLexingModuleAttributes, isNested))
pool.Return tokenTup
hwTokenFetch useBlockRule
@@ -2162,7 +2169,7 @@ type LexFilterImpl (
| (DO | DO_BANG), _ ->
if debug then dprintf "DO: pushing CtxtSeqBlock, tokenStartPos = %a\n" outputPos tokenStartPos
pushCtxt tokenTup (CtxtDo tokenStartPos)
- pushCtxtSeqBlock tokenTup AddBlockEnd
+ tryPushCtxtSeqBlock tokenTup AddBlockEnd
returnToken tokenLexbufState (match token with DO -> ODO | DO_BANG -> ODO_BANG | _ -> failwith "unreachable")
// The r.h.s. of an infix token begins a new block.
@@ -2562,24 +2569,28 @@ type LexFilterImpl (
false
and pushCtxtSeqBlock fallbackToken addBlockEnd =
- pushCtxtSeqBlockAt strictIndentation fallbackToken (peekNextTokenTup()) addBlockEnd
+ pushCtxtSeqBlockAt strictIndentation true fallbackToken (peekNextTokenTup ()) addBlockEnd
+
+ and tryPushCtxtSeqBlock fallbackToken addBlockEnd =
+ pushCtxtSeqBlockAt strictIndentation false fallbackToken (peekNextTokenTup ()) addBlockEnd
- and pushCtxtSeqBlockAt strict (fallbackToken: TokenTup) (tokenTup: TokenTup) addBlockEnd =
+ and pushCtxtSeqBlockAt strict (useFallback: bool) (fallbackToken: TokenTup) (tokenTup: TokenTup) addBlockEnd =
let pushed = tryPushCtxt strict tokenTup (CtxtSeqBlock(FirstInSeqBlock, startPosOfTokenTup tokenTup, addBlockEnd))
- if not pushed then
+ if not pushed && useFallback then
// The upcoming token isn't sufficiently indented to start the new context.
// The parser expects proper contexts structure, so we push a new recovery context at the fallback token position.
pushCtxt fallbackToken (CtxtSeqBlock(NotFirstInSeqBlock, startPosOfTokenTup fallbackToken, addBlockEnd))
- let addBlockBegin =
- match addBlockEnd with
- | AddBlockEnd -> true
- | _ -> false
+ if pushed || useFallback then
+ let addBlockBegin =
+ match addBlockEnd with
+ | AddBlockEnd -> true
+ | _ -> false
- if addBlockBegin then
- if debug then dprintf "--> insert OBLOCKBEGIN \n"
- let ctxtToken = if pushed then tokenTup else fallbackToken
- delayToken(pool.UseLocation(ctxtToken, OBLOCKBEGIN))
+ if addBlockBegin then
+ if debug then dprintf "--> insert OBLOCKBEGIN \n"
+ let ctxtToken = if pushed then tokenTup else fallbackToken
+ delayToken(pool.UseLocation(ctxtToken, OBLOCKBEGIN))
let rec swTokenFetch() =
let tokenTup = popNextTokenTup()
diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy
index 8a472afd189..0509f867c73 100644
--- a/src/Compiler/pars.fsy
+++ b/src/Compiler/pars.fsy
@@ -521,6 +521,12 @@ moduleIntro:
let mModule = rhs parseState 1
mModule, $4, $5.LongIdent, $3, $2 }
+ | moduleKeyword opt_attributes opt_access opt_rec OBLOCKSEP
+ { if not (isNil $2) then
+ parseState.LexBuffer.CheckLanguageFeatureAndRecover LanguageFeature.AttributesToRightOfModuleKeyword (rhs parseState 4)
+ let mModule = rhs parseState 1
+ mModule, $4, [], $3, $2 }
+
/* The start of a namespace declaration */
namespaceIntro:
@@ -706,7 +712,7 @@ moduleSpfn:
SynModuleSigDecl.Exception(synExnDefn, mWhole) }
| openDecl
- { SynModuleSigDecl.Open($1, (rhs parseState 1)) }
+ { SynModuleSigDecl.Open $1 }
valSpfn:
| opt_attributes opt_access VAL opt_attributes opt_inline opt_mutable opt_access nameop opt_explicitValTyparDecls COLON topTypeWithTypeConstraints optLiteralValueSpfn
@@ -1320,15 +1326,26 @@ moduleDefn:
/* 'open' declarations */
| openDecl
- { [ SynModuleDecl.Open($1, (rhs parseState 1)) ] }
+ { [ SynModuleDecl.Open $1 ] }
openDecl:
- /* 'open' declarations */
| OPEN path
- { SynOpenDeclTarget.ModuleOrNamespace($2, (rhs parseState 2)) }
+ { let mOpen = rhs parseState 1
+ let mPath = $2.Range
+ SynOpenDeclTarget.ModuleOrNamespace($2, mPath), unionRanges mOpen mPath }
+
+ | OPEN recover
+ { let mOpen = rhs parseState 1
+ SynOpenDeclTarget.ModuleOrNamespace(SynLongIdent([], [], []), mOpen.EndRange), mOpen }
| OPEN typeKeyword appType
- { SynOpenDeclTarget.Type($3, (rhs parseState 3)) }
+ { let mOpen = rhs parseState 1
+ let mPath = $3.Range
+ SynOpenDeclTarget.Type($3, mPath), unionRanges mOpen mPath }
+
+ | OPEN typeKeyword recover
+ { let m = rhs2 parseState 1 2
+ SynOpenDeclTarget.ModuleOrNamespace(SynLongIdent([], [], []), m.EndRange), m }
/* The right-hand-side of a module abbreviation definition */
/* This occurs on the right of a module abbreviation (#light encloses the r.h.s. with OBLOCKBEGIN/OBLOCKEND) */
@@ -2787,6 +2804,12 @@ hardwhiteDoBinding:
// associated with the module, 'main' function or assembly depending on their target
BindingSetPreAttrs(mDo, false, false, (fun attrs vis -> attrs, [mkSynDoBinding (vis, mDo, $2, mAll)]), mAll), $2 }
+ | ODO ODECLEND
+ { let mDo = rhs parseState 1
+ reportParseErrorAt (rhs parseState 2) (FSComp.SR.parsExpectingExpression ())
+ let seqPt = DebugPointAtBinding.NoneAtDo
+ let expr = arbExpr ("hardwhiteDoBinding1", mDo.EndRange)
+ BindingSetPreAttrs(mDo, false, false, (fun attrs vis -> attrs, [mkSynDoBinding (vis, mDo, expr, mDo)]), mDo), expr }
/* The bindings in a class type definition */
classDefnBindings:
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
index 5e66980c1ed..76ce61f78f4 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
+++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
@@ -252,6 +252,7 @@
+
diff --git a/tests/FSharp.Compiler.ComponentTests/Signatures/MemberTests.fs b/tests/FSharp.Compiler.ComponentTests/Signatures/MemberTests.fs
new file mode 100644
index 00000000000..2452a900881
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Signatures/MemberTests.fs
@@ -0,0 +1,52 @@
+module Signatures.MemberTests
+
+open Xunit
+open FsUnit
+open FSharp.Test.Compiler
+open Signatures.TestHelpers
+
+[]
+let ``Verify that the visibility difference between the getter and setter results in two distinct member signatures`` () =
+ FSharp
+ """
+module Foo
+
+type Foo() =
+ member f.X with internal get (key1, key2) = true and public set (key1, key2) value = ()
+"""
+ |> printSignatures
+ |> should
+ equal
+ """
+module Foo
+
+type Foo =
+
+ new: unit -> Foo
+
+ member internal X: key1: obj * key2: obj -> bool with get
+
+ member X: key1: obj * key2: obj -> obj with set"""
+
+[]
+let ``Getter should have explicit with get suffix`` () =
+ FSharp
+ """
+module Foo
+
+type Foo() =
+ member f.Y with public get () = 'y' and internal set y = ignore y
+"""
+ |> printSignatures
+ |> should
+ equal
+ """
+module Foo
+
+type Foo =
+
+ new: unit -> Foo
+
+ member Y: char with get
+
+ member internal Y: char with set"""
diff --git a/tests/FSharp.Compiler.ComponentTests/Signatures/TestCasesForGenerationRoundTrip/setters.fsx b/tests/FSharp.Compiler.ComponentTests/Signatures/TestCasesForGenerationRoundTrip/setters.fsx
new file mode 100644
index 00000000000..47f7601baba
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Signatures/TestCasesForGenerationRoundTrip/setters.fsx
@@ -0,0 +1,3 @@
+type Foo() =
+ member f.X with internal get (key1, key2) = true and public set (key1, key2) value = ()
+ member f.Y with public get () = 'y' and internal set y = ignore y
diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/QueryTrieTests.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/QueryTrieTests.fs
index 0da67c406f6..1c06fe9dee2 100644
--- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/QueryTrieTests.fs
+++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/QueryTrieTests.fs
@@ -807,7 +807,7 @@ let ``ProcessOpenStatement full path match`` () =
Set.empty
let result =
- processOpenPath (queryTrie fantomasCoreTrie) [ "Fantomas"; "Core"; "AstExtensions" ] state
+ processOpenPath fantomasCoreTrie [ "Fantomas"; "Core"; "AstExtensions" ] state
let dep = Seq.exactlyOne result.FoundDependencies
Assert.AreEqual(indexOf "AstExtensions.fsi", dep)
diff --git a/tests/fsharp/typecheck/sigs/neg41.bsl b/tests/fsharp/typecheck/sigs/neg41.bsl
index 18115064cc9..122351ab76c 100644
--- a/tests/fsharp/typecheck/sigs/neg41.bsl
+++ b/tests/fsharp/typecheck/sigs/neg41.bsl
@@ -1,2 +1,2 @@
-neg41.fs(3,1,3,5): parse error FS0010: Unexpected keyword 'type' in definition. Expected '=' or other token.
+neg41.fs(2,20,3,1): parse error FS0010: Incomplete structured construct at or before this point in definition. Expected '=' or other token.
diff --git a/tests/fsharp/typecheck/sigs/neg42.bsl b/tests/fsharp/typecheck/sigs/neg42.bsl
index 3dec6d2329b..9f2bba6bf0d 100644
--- a/tests/fsharp/typecheck/sigs/neg42.bsl
+++ b/tests/fsharp/typecheck/sigs/neg42.bsl
@@ -1,2 +1,2 @@
-neg42.fsi(3,1,3,5): parse error FS0010: Unexpected keyword 'type' in signature file. Expected ':', '=' or other token.
+neg42.fsi(2,20,3,1): parse error FS0010: Incomplete structured construct at or before this point in signature file. Expected ':', '=' or other token.
diff --git a/tests/service/data/SyntaxTree/Expression/Do 03.fs.bsl b/tests/service/data/SyntaxTree/Expression/Do 03.fs.bsl
index f60cb8f91f9..99ae567f061 100644
--- a/tests/service/data/SyntaxTree/Expression/Do 03.fs.bsl
+++ b/tests/service/data/SyntaxTree/Expression/Do 03.fs.bsl
@@ -12,12 +12,12 @@ ImplFile
(None, SynValInfo ([], SynArgInfo ([], false, None)), None),
Wild (3,4--3,5), None,
Do
- (ArbitraryAfterError
- ("typedSequentialExprBlock1", (4,6--4,6)), (4,4--4,6)),
- (3,4--3,5), Yes (3,0--4,6), { LeadingKeyword = Let (3,0--3,3)
- InlineKeyword = None
- EqualsRange = Some (3,6--3,7) })],
- (3,0--4,6)); Expr (Const (Int32 1, (6,0--6,1)), (6,0--6,1))],
+ (ArbitraryAfterError ("hardwhiteDoBinding1", (4,6--4,6)),
+ (4,4--4,6)), (3,4--3,5), Yes (3,0--4,6),
+ { LeadingKeyword = Let (3,0--3,3)
+ InlineKeyword = None
+ EqualsRange = Some (3,6--3,7) })], (3,0--4,6));
+ Expr (Const (Int32 1, (6,0--6,1)), (6,0--6,1))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
diff --git a/tests/service/data/SyntaxTree/Expression/For 03.fs.bsl b/tests/service/data/SyntaxTree/Expression/For 03.fs.bsl
index 2c93eb12bb1..adaf09a1eaf 100644
--- a/tests/service/data/SyntaxTree/Expression/For 03.fs.bsl
+++ b/tests/service/data/SyntaxTree/Expression/For 03.fs.bsl
@@ -14,16 +14,16 @@ ImplFile
ForEach
(Yes (4,4--4,7), Yes (4,10--4,12), SeqExprOnly false, true,
Wild (4,8--4,9), Const (Int32 1, (4,13--4,14)),
- ArbitraryAfterError
- ("typedSequentialExprBlock1", (4,17--4,17)), (4,4--4,17)),
- (3,4--3,5), NoneAtLet, { LeadingKeyword = Let (3,0--3,3)
- InlineKeyword = None
- EqualsRange = Some (3,6--3,7) })],
- (3,0--4,17)); Expr (Const (Int32 3, (6,0--6,1)), (6,0--6,1))],
+ ArbitraryAfterError ("forLoopBody2a", (6,0--6,1)),
+ (4,4--4,17)), (3,4--3,5), NoneAtLet,
+ { LeadingKeyword = Let (3,0--3,3)
+ InlineKeyword = None
+ EqualsRange = Some (3,6--3,7) })], (3,0--4,17));
+ Expr (Const (Int32 3, (6,0--6,1)), (6,0--6,1))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))
(6,0)-(6,1) parse error Possible incorrect indentation: this token is offside of context started at position (4:5). Try indenting this token further or using standard formatting conventions.
-(6,0)-(6,1) parse error Expecting expression
+(6,0)-(6,1) parse error Incomplete structured construct at or before this point in expression
diff --git a/tests/service/data/SyntaxTree/Expression/While 03.fs.bsl b/tests/service/data/SyntaxTree/Expression/While 03.fs.bsl
index e74fa7f8486..b10e7fab890 100644
--- a/tests/service/data/SyntaxTree/Expression/While 03.fs.bsl
+++ b/tests/service/data/SyntaxTree/Expression/While 03.fs.bsl
@@ -13,8 +13,7 @@ ImplFile
Wild (3,4--3,5), None,
While
(Yes (4,4--4,11), Const (Int32 1, (4,10--4,11)),
- ArbitraryAfterError
- ("typedSequentialExprBlock1", (4,14--4,14)), (4,4--4,14)),
+ ArbitraryAfterError ("whileBody1", (6,0--6,1)), (4,4--4,14)),
(3,4--3,5), NoneAtLet, { LeadingKeyword = Let (3,0--3,3)
InlineKeyword = None
EqualsRange = Some (3,6--3,7) })],
@@ -25,4 +24,4 @@ ImplFile
CodeComments = [] }, set []))
(6,0)-(6,1) parse error Possible incorrect indentation: this token is offside of context started at position (4:5). Try indenting this token further or using standard formatting conventions.
-(6,0)-(6,1) parse error Expecting expression
+(6,0)-(6,1) parse error Incomplete structured construct at or before this point in expression
diff --git a/tests/service/data/SyntaxTree/Expression/While 04.fs.bsl b/tests/service/data/SyntaxTree/Expression/While 04.fs.bsl
index 1286e6a723a..538e8312b75 100644
--- a/tests/service/data/SyntaxTree/Expression/While 04.fs.bsl
+++ b/tests/service/data/SyntaxTree/Expression/While 04.fs.bsl
@@ -13,8 +13,7 @@ ImplFile
Wild (3,4--3,5), None,
While
(Yes (4,4--4,11), Const (Int32 1, (4,10--4,11)),
- ArbitraryAfterError
- ("typedSequentialExprBlock1", (4,14--4,14)), (4,4--4,14)),
+ ArbitraryAfterError ("whileBody1", (5,0--5,0)), (4,4--4,14)),
(3,4--3,5), NoneAtLet, { LeadingKeyword = Let (3,0--3,3)
InlineKeyword = None
EqualsRange = Some (3,6--3,7) })],
@@ -25,4 +24,4 @@ ImplFile
CodeComments = [] }, set []))
(5,0)-(5,0) parse error Possible incorrect indentation: this token is offside of context started at position (4:5). Try indenting this token further or using standard formatting conventions.
-(5,0)-(5,0) parse error Expecting expression
+(5,0)-(5,0) parse error Incomplete structured construct at or before this point in expression
diff --git a/tests/service/data/SyntaxTree/Member/Do 03.fs.bsl b/tests/service/data/SyntaxTree/Member/Do 03.fs.bsl
index 6634a59f3f2..f80e296c39b 100644
--- a/tests/service/data/SyntaxTree/Member/Do 03.fs.bsl
+++ b/tests/service/data/SyntaxTree/Member/Do 03.fs.bsl
@@ -19,7 +19,7 @@ ImplFile
SynValInfo ([], SynArgInfo ([], false, None)),
None), Const (Unit, (5,11--5,13)), None,
ArbitraryAfterError
- ("typedSequentialExprBlock1", (5,13--5,13)),
+ ("hardwhiteDoBinding1", (5,13--5,13)),
(5,11--5,13), NoneAtDo,
{ LeadingKeyword =
StaticDo ((5,4--5,10), (5,11--5,13))
diff --git a/tests/service/data/SyntaxTree/Member/Do 04.fs b/tests/service/data/SyntaxTree/Member/Do 04.fs
new file mode 100644
index 00000000000..487fb8c7e58
--- /dev/null
+++ b/tests/service/data/SyntaxTree/Member/Do 04.fs
@@ -0,0 +1,7 @@
+module Module
+
+type T =
+
+ do
+
+ do ()
diff --git a/tests/service/data/SyntaxTree/Member/Do 04.fs.bsl b/tests/service/data/SyntaxTree/Member/Do 04.fs.bsl
new file mode 100644
index 00000000000..9d6eb8b1895
--- /dev/null
+++ b/tests/service/data/SyntaxTree/Member/Do 04.fs.bsl
@@ -0,0 +1,48 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/Member/Do 04.fs", false, QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [Types
+ ([SynTypeDefn
+ (SynComponentInfo
+ ([], None, [], [T],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector),
+ false, None, (3,5--3,6)),
+ ObjectModel
+ (Unspecified,
+ [LetBindings
+ ([SynBinding
+ (None, Do, false, false, [], PreXmlDocEmpty,
+ SynValData
+ (None,
+ SynValInfo ([], SynArgInfo ([], false, None)),
+ None), Const (Unit, (5,4--5,6)), None,
+ ArbitraryAfterError
+ ("hardwhiteDoBinding1", (5,6--5,6)), (5,4--5,6),
+ NoneAtDo, { LeadingKeyword = Do (5,4--5,6)
+ InlineKeyword = None
+ EqualsRange = None })], false, false,
+ (5,4--5,6));
+ LetBindings
+ ([SynBinding
+ (None, Do, false, false, [], PreXmlDocEmpty,
+ SynValData
+ (None,
+ SynValInfo ([], SynArgInfo ([], false, None)),
+ None), Const (Unit, (7,4--7,9)), None,
+ Const (Unit, (7,7--7,9)), (7,4--7,9), NoneAtDo,
+ { LeadingKeyword = Do (7,4--7,6)
+ InlineKeyword = None
+ EqualsRange = None })], false, false, (7,4--7,9))],
+ (5,4--7,9)), [], None, (3,5--7,9),
+ { LeadingKeyword = Type (3,0--3,4)
+ EqualsRange = Some (3,7--3,8)
+ WithKeyword = None })], (3,0--7,9))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--7,9), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(7,4)-(7,6) parse error Possible incorrect indentation: this token is offside of context started at position (5:5). Try indenting this token further or using standard formatting conventions.
+(7,4)-(7,6) parse error Expecting expression
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Do 01.fs b/tests/service/data/SyntaxTree/ModuleMember/Do 01.fs
new file mode 100644
index 00000000000..7053ee15c83
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Do 01.fs
@@ -0,0 +1,5 @@
+module Module
+
+do
+
+2
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Do 01.fs.bsl b/tests/service/data/SyntaxTree/ModuleMember/Do 01.fs.bsl
new file mode 100644
index 00000000000..b3d783470bf
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Do 01.fs.bsl
@@ -0,0 +1,17 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleMember/Do 01.fs", false, QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [Expr
+ (Do
+ (ArbitraryAfterError ("hardwhiteDoBinding1", (3,2--3,2)),
+ (3,0--3,2)), (3,0--3,2));
+ Expr (Const (Int32 2, (5,0--5,1)), (5,0--5,1))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--5,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(5,0)-(5,1) parse error Possible incorrect indentation: this token is offside of context started at position (3:1). Try indenting this token further or using standard formatting conventions.
+(5,0)-(5,1) parse error Expecting expression
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Do 04.fs b/tests/service/data/SyntaxTree/ModuleMember/Do 02.fs
similarity index 100%
rename from tests/service/data/SyntaxTree/ModuleMember/Do 04.fs
rename to tests/service/data/SyntaxTree/ModuleMember/Do 02.fs
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Do 04.fs.bsl b/tests/service/data/SyntaxTree/ModuleMember/Do 02.fs.bsl
similarity index 56%
rename from tests/service/data/SyntaxTree/ModuleMember/Do 04.fs.bsl
rename to tests/service/data/SyntaxTree/ModuleMember/Do 02.fs.bsl
index 6738b7e6e95..24bb18d6dff 100644
--- a/tests/service/data/SyntaxTree/ModuleMember/Do 04.fs.bsl
+++ b/tests/service/data/SyntaxTree/ModuleMember/Do 02.fs.bsl
@@ -1,16 +1,17 @@
ImplFile
(ParsedImplFileInput
- ("/root/ModuleMember/Do 04.fs", false, QualifiedNameOfFile Module, [], [],
+ ("/root/ModuleMember/Do 02.fs", false, QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Expr
(Do
- (ArbitraryAfterError ("typedSequentialExprBlock1", (4,4--4,4)),
- (3,0--4,4)), (3,0--4,4));
+ (ArbitraryAfterError ("hardwhiteDoBinding1", (3,2--3,2)),
+ (3,0--3,2)), (3,0--3,2));
Expr (Const (Int32 2, (6,0--6,1)), (6,0--6,1))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))
+(4,0)-(4,4) parse error Possible incorrect indentation: this token is offside of context started at position (3:1). Try indenting this token further or using standard formatting conventions.
(4,0)-(4,4) parse error Expecting expression
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Do 03.fs.bsl b/tests/service/data/SyntaxTree/ModuleMember/Do 03.fs.bsl
deleted file mode 100644
index 1bc84f9a9d4..00000000000
--- a/tests/service/data/SyntaxTree/ModuleMember/Do 03.fs.bsl
+++ /dev/null
@@ -1,11 +0,0 @@
-ImplFile
- (ParsedImplFileInput
- ("/root/ModuleMember/Do 03.fs", false, QualifiedNameOfFile Module, [], [],
- [SynModuleOrNamespace
- ([Module], false, NamedModule,
- [Expr (Do (Const (Int32 1, (4,2--4,3)), (3,0--4,3)), (3,0--4,3));
- Expr (Const (Int32 2, (7,0--7,1)), (7,0--7,1))],
- PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
- (1,0--7,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
- { ConditionalDirectives = []
- CodeComments = [] }, set []))
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 01.fs b/tests/service/data/SyntaxTree/ModuleMember/Open 01.fs
new file mode 100644
index 00000000000..a6746f4ead9
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 01.fs
@@ -0,0 +1,4 @@
+module Module
+
+open
+open Ns1
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 01.fs.bsl b/tests/service/data/SyntaxTree/ModuleMember/Open 01.fs.bsl
new file mode 100644
index 00000000000..9ba9b81eb53
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 01.fs.bsl
@@ -0,0 +1,17 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleMember/Open 01.fs", false, QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [Open
+ (ModuleOrNamespace (SynLongIdent ([], [], []), (3,4--3,4)),
+ (3,0--3,4));
+ Open
+ (ModuleOrNamespace (SynLongIdent ([Ns1], [], [None]), (4,5--4,8)),
+ (4,0--4,8))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--4,8), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(3,5)-(4,0) parse error Incomplete structured construct at or before this point in open declaration. Expected identifier, 'global', 'type' or other token.
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 02.fs b/tests/service/data/SyntaxTree/ModuleMember/Open 02.fs
new file mode 100644
index 00000000000..6546212aeb2
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 02.fs
@@ -0,0 +1,4 @@
+module Module
+
+open type
+open Ns1
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 02.fs.bsl b/tests/service/data/SyntaxTree/ModuleMember/Open 02.fs.bsl
new file mode 100644
index 00000000000..2a17ef664a5
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 02.fs.bsl
@@ -0,0 +1,17 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleMember/Open 02.fs", false, QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [Open
+ (ModuleOrNamespace (SynLongIdent ([], [], []), (3,9--3,9)),
+ (3,0--3,9));
+ Open
+ (ModuleOrNamespace (SynLongIdent ([Ns1], [], [None]), (4,5--4,8)),
+ (4,0--4,8))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--4,8), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(3,10)-(4,0) parse error Incomplete structured construct at or before this point in open declaration
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 03.fs b/tests/service/data/SyntaxTree/ModuleMember/Open 03.fs
new file mode 100644
index 00000000000..15a614bc78a
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 03.fs
@@ -0,0 +1,5 @@
+module Module
+
+open type
+
+()
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 03.fs.bsl b/tests/service/data/SyntaxTree/ModuleMember/Open 03.fs.bsl
new file mode 100644
index 00000000000..549a2c50a79
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 03.fs.bsl
@@ -0,0 +1,14 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleMember/Open 03.fs", false, QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [Open
+ (ModuleOrNamespace (SynLongIdent ([], [], []), (3,9--3,9)),
+ (3,0--3,9)); Expr (Const (Unit, (5,0--5,2)), (5,0--5,2))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--5,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(3,10)-(5,0) parse error Incomplete structured construct at or before this point in open declaration
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 04.fs b/tests/service/data/SyntaxTree/ModuleMember/Open 04.fs
new file mode 100644
index 00000000000..798a6aef2ea
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 04.fs
@@ -0,0 +1,5 @@
+module Module
+
+open type
+
+ignore
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 04.fs.bsl b/tests/service/data/SyntaxTree/ModuleMember/Open 04.fs.bsl
new file mode 100644
index 00000000000..26532b885c0
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 04.fs.bsl
@@ -0,0 +1,14 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleMember/Open 04.fs", false, QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [Open
+ (ModuleOrNamespace (SynLongIdent ([], [], []), (3,9--3,9)),
+ (3,0--3,9)); Expr (Ident ignore, (5,0--5,6))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--5,6), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(3,10)-(5,0) parse error Incomplete structured construct at or before this point in open declaration
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 05.fs b/tests/service/data/SyntaxTree/ModuleMember/Open 05.fs
new file mode 100644
index 00000000000..0999fac7c74
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 05.fs
@@ -0,0 +1,5 @@
+module Module
+
+open
+
+type T = int
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 05.fs.bsl b/tests/service/data/SyntaxTree/ModuleMember/Open 05.fs.bsl
new file mode 100644
index 00000000000..d6339de665b
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 05.fs.bsl
@@ -0,0 +1,27 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleMember/Open 05.fs", false, QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [Open
+ (ModuleOrNamespace (SynLongIdent ([], [], []), (3,4--3,4)),
+ (3,0--3,4));
+ Types
+ ([SynTypeDefn
+ (SynComponentInfo
+ ([], None, [], [T],
+ PreXmlDoc ((5,0), FSharp.Compiler.Xml.XmlDocCollector),
+ false, None, (5,5--5,6)),
+ Simple
+ (TypeAbbrev
+ (Ok, LongIdent (SynLongIdent ([int], [], [None])),
+ (5,9--5,12)), (5,9--5,12)), [], None, (5,5--5,12),
+ { LeadingKeyword = Type (5,0--5,4)
+ EqualsRange = Some (5,7--5,8)
+ WithKeyword = None })], (5,0--5,12))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--5,12), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(3,5)-(5,0) parse error Incomplete structured construct at or before this point in open declaration. Expected identifier, 'global', 'type' or other token.
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 06.fs b/tests/service/data/SyntaxTree/ModuleMember/Open 06.fs
new file mode 100644
index 00000000000..77b1a3f007c
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 06.fs
@@ -0,0 +1,4 @@
+module Module
+
+open Ns1.
+open Ns2
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 06.fs.bsl b/tests/service/data/SyntaxTree/ModuleMember/Open 06.fs.bsl
new file mode 100644
index 00000000000..44453c403fa
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 06.fs.bsl
@@ -0,0 +1,18 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleMember/Open 06.fs", false, QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [Open
+ (ModuleOrNamespace
+ (SynLongIdent ([Ns1], [(3,8--3,9)], [None]), (3,5--3,9)),
+ (3,0--3,9));
+ Open
+ (ModuleOrNamespace (SynLongIdent ([Ns2], [], [None]), (4,5--4,8)),
+ (4,0--4,8))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--4,8), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(3,10)-(4,0) parse error Incomplete structured construct at or before this point in open declaration
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 07.fs b/tests/service/data/SyntaxTree/ModuleMember/Open 07.fs
new file mode 100644
index 00000000000..66d705cb2dc
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 07.fs
@@ -0,0 +1,5 @@
+module Module
+
+open Ns1.
+
+ignore
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 07.fs.bsl b/tests/service/data/SyntaxTree/ModuleMember/Open 07.fs.bsl
new file mode 100644
index 00000000000..38af89635b8
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 07.fs.bsl
@@ -0,0 +1,15 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleMember/Open 07.fs", false, QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [Open
+ (ModuleOrNamespace
+ (SynLongIdent ([Ns1], [(3,8--3,9)], [None]), (3,5--3,9)),
+ (3,0--3,9)); Expr (Ident ignore, (5,0--5,6))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--5,6), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(3,10)-(5,0) parse error Incomplete structured construct at or before this point in open declaration
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 08.fs b/tests/service/data/SyntaxTree/ModuleMember/Open 08.fs
new file mode 100644
index 00000000000..998eb9b5f96
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 08.fs
@@ -0,0 +1,4 @@
+module Module
+
+open Ns1.
+ Ns2
diff --git a/tests/service/data/SyntaxTree/ModuleMember/Open 08.fs.bsl b/tests/service/data/SyntaxTree/ModuleMember/Open 08.fs.bsl
new file mode 100644
index 00000000000..5968d7456b1
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleMember/Open 08.fs.bsl
@@ -0,0 +1,13 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleMember/Open 08.fs", false, QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [Open
+ (ModuleOrNamespace
+ (SynLongIdent ([Ns1; Ns2], [(3,8--3,9)], [None; None]),
+ (3,5--4,4)), (3,0--4,4))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--4,4), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 03.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 03.fs
new file mode 100644
index 00000000000..90d76105dbc
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 03.fs
@@ -0,0 +1,5 @@
+module Module
+
+module A
+
+()
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 03.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 03.fs.bsl
new file mode 100644
index 00000000000..44ab73f81ad
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 03.fs.bsl
@@ -0,0 +1,20 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 03.fs", false,
+ QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [A],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--3,8)), false, [], false, (3,0--3,8),
+ { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = None });
+ Expr (Const (Unit, (5,0--5,2)), (5,0--5,2))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--5,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(3,9)-(5,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 04.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 04.fs
new file mode 100644
index 00000000000..2f61714c416
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 04.fs
@@ -0,0 +1,5 @@
+module Module
+
+module
+
+()
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 04.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 04.fs.bsl
new file mode 100644
index 00000000000..4208cc94225
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 04.fs.bsl
@@ -0,0 +1,20 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 04.fs", false,
+ QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--5,0)), false, [], false, (3,0--5,0),
+ { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = None });
+ Expr (Const (Unit, (5,0--5,2)), (5,0--5,2))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--5,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(3,7)-(5,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 05.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 05.fs
new file mode 100644
index 00000000000..3d3602d9735
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 05.fs
@@ -0,0 +1,5 @@
+module Module
+
+module rec
+
+()
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 05.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 05.fs.bsl
new file mode 100644
index 00000000000..53b4a1f12df
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 05.fs.bsl
@@ -0,0 +1,20 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 05.fs", false,
+ QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--5,0)), true, [], false, (3,0--5,0),
+ { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = None });
+ Expr (Const (Unit, (5,0--5,2)), (5,0--5,2))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--5,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(3,11)-(5,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 06.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 06.fs
new file mode 100644
index 00000000000..20c697536eb
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 06.fs
@@ -0,0 +1,5 @@
+module Module
+
+module rec A
+
+()
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 06.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 06.fs.bsl
new file mode 100644
index 00000000000..d6875779d2f
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 06.fs.bsl
@@ -0,0 +1,20 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 06.fs", false,
+ QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [A],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--3,12)), true, [], false, (3,0--3,12),
+ { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = None });
+ Expr (Const (Unit, (5,0--5,2)), (5,0--5,2))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--5,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(3,13)-(5,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 07.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 07.fs
new file mode 100644
index 00000000000..c37b1641337
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 07.fs
@@ -0,0 +1,6 @@
+module Module
+
+module A =
+ module
+
+2
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 07.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 07.fs.bsl
new file mode 100644
index 00000000000..569bdfe5811
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 07.fs.bsl
@@ -0,0 +1,27 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 07.fs", false,
+ QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [A],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--3,8)), false,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [],
+ PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
+ false, None, (4,4--6,0)), false, [], false, (4,4--6,0),
+ { ModuleKeyword = Some (4,4--4,10)
+ EqualsRange = None })], false, (3,0--6,0),
+ { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = Some (3,9--3,10) });
+ Expr (Const (Int32 2, (6,0--6,1)), (6,0--6,1))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--6,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(6,0)-(6,1) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 08.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 08.fs
new file mode 100644
index 00000000000..c73c8b4320b
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 08.fs
@@ -0,0 +1,6 @@
+module Module
+
+module A =
+ module B
+
+ 2
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 08.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 08.fs.bsl
new file mode 100644
index 00000000000..1b6fcc1a41c
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 08.fs.bsl
@@ -0,0 +1,27 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 08.fs", false,
+ QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [A],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--3,8)), false,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [B],
+ PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
+ false, None, (4,4--4,12)), false, [], false, (4,4--4,12),
+ { ModuleKeyword = Some (4,4--4,10)
+ EqualsRange = None });
+ Expr (Const (Int32 2, (6,4--6,5)), (6,4--6,5))], false,
+ (3,0--6,5), { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = Some (3,9--3,10) })],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--6,5), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(4,13)-(6,4) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 09.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 09.fs
new file mode 100644
index 00000000000..e5d48898ea2
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 09.fs
@@ -0,0 +1,6 @@
+module Module
+
+module A =
+ module B =
+
+ 2
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 09.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 09.fs.bsl
new file mode 100644
index 00000000000..ce79f7aba8d
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 09.fs.bsl
@@ -0,0 +1,28 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 09.fs", false,
+ QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [A],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--3,8)), false,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [B],
+ PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
+ false, None, (4,4--4,12)), false, [], false, (4,4--4,14),
+ { ModuleKeyword = Some (4,4--4,10)
+ EqualsRange = Some (4,13--4,14) });
+ Expr (Const (Int32 2, (6,4--6,5)), (6,4--6,5))], false,
+ (3,0--6,5), { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = Some (3,9--3,10) })],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--6,5), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(6,4)-(6,5) parse error Possible incorrect indentation: this token is offside of context started at position (4:5). Try indenting this token further or using standard formatting conventions.
+(6,4)-(6,5) parse error Incomplete structured construct at or before this point in definition
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 10.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 10.fs
new file mode 100644
index 00000000000..136af483ef1
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 10.fs
@@ -0,0 +1,6 @@
+module Module
+
+module A =
+ module
+
+ 2
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 10.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 10.fs.bsl
new file mode 100644
index 00000000000..4605fc9a35d
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 10.fs.bsl
@@ -0,0 +1,27 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 10.fs", false,
+ QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [A],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--3,8)), false,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [],
+ PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
+ false, None, (4,4--6,4)), false, [], false, (4,4--6,4),
+ { ModuleKeyword = Some (4,4--4,10)
+ EqualsRange = None });
+ Expr (Const (Int32 2, (6,4--6,5)), (6,4--6,5))], false,
+ (3,0--6,5), { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = Some (3,9--3,10) })],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--6,5), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(4,11)-(6,4) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 11.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 11.fs
new file mode 100644
index 00000000000..f1284331320
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 11.fs
@@ -0,0 +1,5 @@
+module Module
+
+module
+
+A
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 11.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 11.fs.bsl
new file mode 100644
index 00000000000..181836a8b7f
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 11.fs.bsl
@@ -0,0 +1,19 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 11.fs", false,
+ QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--5,0)), false, [], false, (3,0--5,0),
+ { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = None }); Expr (Ident A, (5,0--5,1))],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--5,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(3,7)-(5,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 12.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 12.fs
new file mode 100644
index 00000000000..a2fe094f382
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 12.fs
@@ -0,0 +1,3 @@
+module Module
+
+module
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 12.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 12.fs.bsl
new file mode 100644
index 00000000000..eb79389bb5c
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 12.fs.bsl
@@ -0,0 +1,19 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 12.fs", false,
+ QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--4,0)), false, [], false, (3,0--4,0),
+ { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = None })],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--4,0), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(4,0)-(4,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 13.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 13.fs
new file mode 100644
index 00000000000..9d2084ebc72
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 13.fs
@@ -0,0 +1,3 @@
+module Module
+
+module A
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 13.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 13.fs.bsl
new file mode 100644
index 00000000000..c57a57743cb
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 13.fs.bsl
@@ -0,0 +1,19 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 13.fs", false,
+ QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [A],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--3,8)), false, [], false, (3,0--3,8),
+ { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = None })],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--3,8), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(4,0)-(4,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 14.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 14.fs
new file mode 100644
index 00000000000..97b86766455
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 14.fs
@@ -0,0 +1,3 @@
+module Module
+
+module A =
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 14.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 14.fs.bsl
new file mode 100644
index 00000000000..8417322a575
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 14.fs.bsl
@@ -0,0 +1,20 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 14.fs", false,
+ QualifiedNameOfFile Module, [], [],
+ [SynModuleOrNamespace
+ ([Module], false, NamedModule,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [A],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--3,8)), false, [], false, (3,0--3,10),
+ { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = Some (3,9--3,10) })],
+ PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
+ (1,0--3,10), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(4,0)-(4,0) parse error Possible incorrect indentation: this token is offside of context started at position (3:1). Try indenting this token further or using standard formatting conventions.
+(4,0)-(4,0) parse error Incomplete structured construct at or before this point in definition
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 15.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 15.fs
new file mode 100644
index 00000000000..e8bc9fdc187
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 15.fs
@@ -0,0 +1,3 @@
+namespace Ns
+
+module A =
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 15.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 15.fs.bsl
new file mode 100644
index 00000000000..bb23f859ec8
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 15.fs.bsl
@@ -0,0 +1,19 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 15.fs", false,
+ QualifiedNameOfFile Nested module 15, [], [],
+ [SynModuleOrNamespace
+ ([Ns], false, DeclaredNamespace,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [A],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--3,8)), false, [], false, (3,0--3,10),
+ { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = Some (3,9--3,10) })], PreXmlDocEmpty, [], None,
+ (1,0--3,10), { LeadingKeyword = Namespace (1,0--1,9) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(4,0)-(4,0) parse error Possible incorrect indentation: this token is offside of context started at position (3:1). Try indenting this token further or using standard formatting conventions.
+(4,0)-(4,0) parse error Incomplete structured construct at or before this point in definition
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 16.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 16.fs
new file mode 100644
index 00000000000..7debb3295b5
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 16.fs
@@ -0,0 +1,3 @@
+namespace Ns
+
+module A
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 16.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 16.fs.bsl
new file mode 100644
index 00000000000..2ce127eef5d
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 16.fs.bsl
@@ -0,0 +1,18 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 16.fs", false,
+ QualifiedNameOfFile Nested module 16, [], [],
+ [SynModuleOrNamespace
+ ([Ns], false, DeclaredNamespace,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [A],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--3,8)), false, [], false, (3,0--3,8),
+ { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = None })], PreXmlDocEmpty, [], None, (1,0--3,8),
+ { LeadingKeyword = Namespace (1,0--1,9) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(4,0)-(4,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 17.fs b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 17.fs
new file mode 100644
index 00000000000..4baf660a9b5
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 17.fs
@@ -0,0 +1,3 @@
+namespace Ns
+
+module
diff --git a/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 17.fs.bsl b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 17.fs.bsl
new file mode 100644
index 00000000000..4e5dd1a1914
--- /dev/null
+++ b/tests/service/data/SyntaxTree/ModuleOrNamespace/Nested module 17.fs.bsl
@@ -0,0 +1,18 @@
+ImplFile
+ (ParsedImplFileInput
+ ("/root/ModuleOrNamespace/Nested module 17.fs", false,
+ QualifiedNameOfFile Nested module 17, [], [],
+ [SynModuleOrNamespace
+ ([Ns], false, DeclaredNamespace,
+ [NestedModule
+ (SynComponentInfo
+ ([], None, [], [],
+ PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
+ None, (3,0--4,0)), false, [], false, (3,0--4,0),
+ { ModuleKeyword = Some (3,0--3,6)
+ EqualsRange = None })], PreXmlDocEmpty, [], None, (1,0--4,0),
+ { LeadingKeyword = Namespace (1,0--1,9) })], (true, true),
+ { ConditionalDirectives = []
+ CodeComments = [] }, set []))
+
+(4,0)-(4,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
diff --git a/tests/service/data/SyntaxTree/NestedModule/IncompleteNestedModuleShouldBePresent.fs b/tests/service/data/SyntaxTree/NestedModule/IncompleteNestedModuleShouldBePresent.fs
deleted file mode 100644
index 30cb557e092..00000000000
--- a/tests/service/data/SyntaxTree/NestedModule/IncompleteNestedModuleShouldBePresent.fs
+++ /dev/null
@@ -1,5 +0,0 @@
-module A.B
-
-module C
-
-let a = ()
\ No newline at end of file
diff --git a/tests/service/data/SyntaxTree/NestedModule/IncompleteNestedModuleShouldBePresent.fs.bsl b/tests/service/data/SyntaxTree/NestedModule/IncompleteNestedModuleShouldBePresent.fs.bsl
deleted file mode 100644
index 5ab8dedcebc..00000000000
--- a/tests/service/data/SyntaxTree/NestedModule/IncompleteNestedModuleShouldBePresent.fs.bsl
+++ /dev/null
@@ -1,31 +0,0 @@
-ImplFile
- (ParsedImplFileInput
- ("/root/NestedModule/IncompleteNestedModuleShouldBePresent.fs", false,
- QualifiedNameOfFile A.B, [], [],
- [SynModuleOrNamespace
- ([A; B], false, NamedModule,
- [NestedModule
- (SynComponentInfo
- ([], None, [], [C],
- PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
- None, (3,0--3,8)), false, [], false, (3,0--3,8),
- { ModuleKeyword = Some (3,0--3,6)
- EqualsRange = None });
- Let
- (false,
- [SynBinding
- (None, Normal, false, false, [],
- PreXmlDoc ((5,0), FSharp.Compiler.Xml.XmlDocCollector),
- SynValData
- (None, SynValInfo ([], SynArgInfo ([], false, None)), None),
- Named (SynIdent (a, None), false, None, (5,4--5,5)), None,
- Const (Unit, (5,8--5,10)), (5,4--5,5), Yes (5,0--5,10),
- { LeadingKeyword = Let (5,0--5,3)
- InlineKeyword = None
- EqualsRange = Some (5,6--5,7) })], (5,0--5,10))],
- PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
- (1,0--5,10), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
- { ConditionalDirectives = []
- CodeComments = [] }, set []))
-
-(5,0)-(5,3) parse error Unexpected keyword 'let' or 'use' in definition. Expected '=' or other token.
diff --git a/tests/service/data/SyntaxTree/NestedModule/IncompleteNestedModuleSigShouldBePresent.fsi.bsl b/tests/service/data/SyntaxTree/NestedModule/IncompleteNestedModuleSigShouldBePresent.fsi.bsl
index eafee5cf745..9c697d753d9 100644
--- a/tests/service/data/SyntaxTree/NestedModule/IncompleteNestedModuleSigShouldBePresent.fsi.bsl
+++ b/tests/service/data/SyntaxTree/NestedModule/IncompleteNestedModuleSigShouldBePresent.fsi.bsl
@@ -26,4 +26,4 @@ SigFile
{ ConditionalDirectives = []
CodeComments = [] }, set []))
-(5,0)-(5,3) parse error Unexpected keyword 'val' in signature file. Expected ':', '=' or other token.
+(3,9)-(5,0) parse error Incomplete structured construct at or before this point in signature file. Expected ':', '=' or other token.
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddInstanceMemberParameter.fs b/vsintegration/src/FSharp.Editor/CodeFix/AddInstanceMemberParameter.fs
deleted file mode 100644
index e98976184a0..00000000000
--- a/vsintegration/src/FSharp.Editor/CodeFix/AddInstanceMemberParameter.fs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-
-namespace Microsoft.VisualStudio.FSharp.Editor
-
-open System.Composition
-open System.Threading.Tasks
-open System.Collections.Immutable
-
-open Microsoft.CodeAnalysis.Text
-open Microsoft.CodeAnalysis.CodeFixes
-
-open CancellableTasks
-
-[]
-type internal FSharpAddInstanceMemberParameterCodeFixProvider() =
- inherit CodeFixProvider()
-
- static let title = SR.AddMissingInstanceMemberParameter()
-
- interface IFSharpCodeFix with
- member _.GetChangesAsync _ span =
- let changes = [ TextChange(TextSpan(span.Start, 0), "x.") ]
- CancellableTask.singleton (title, changes)
-
- override _.FixableDiagnosticIds = ImmutableArray.Create("FS0673")
-
- override this.RegisterCodeFixesAsync context : Task =
- cancellableTask {
- let! title, changes = (this :> IFSharpCodeFix).GetChangesAsync context.Document context.Span
- context.RegisterFsharpFix(CodeFix.AddInstanceMemberParameter, title, changes)
- }
- |> CancellableTask.startAsTask context.CancellationToken
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddMissingRecToMutuallyRecFunctions.fs b/vsintegration/src/FSharp.Editor/CodeFix/AddMissingRecToMutuallyRecFunctions.fs
deleted file mode 100644
index ec9c7dad660..00000000000
--- a/vsintegration/src/FSharp.Editor/CodeFix/AddMissingRecToMutuallyRecFunctions.fs
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-
-namespace Microsoft.VisualStudio.FSharp.Editor
-
-open System
-open System.Collections.Immutable
-open System.Composition
-open System.Threading
-
-open Microsoft.CodeAnalysis.Text
-open Microsoft.CodeAnalysis.CodeFixes
-
-open FSharp.Compiler
-open FSharp.Compiler.CodeAnalysis
-
-open Microsoft.CodeAnalysis
-open Microsoft.CodeAnalysis.CodeActions
-
-[]
-type internal FSharpAddMissingRecToMutuallyRecFunctionsCodeFixProvider [] () =
- inherit CodeFixProvider()
-
- static let titleFormat = SR.MakeOuterBindingRecursive()
-
- override _.FixableDiagnosticIds = ImmutableArray.Create("FS0576")
-
- override _.RegisterCodeFixesAsync context =
- asyncMaybe {
- let! defines, langVersion =
- context.Document.GetFSharpCompilationDefinesAndLangVersionAsync(
- nameof (FSharpAddMissingRecToMutuallyRecFunctionsCodeFixProvider)
- )
- |> liftAsync
-
- let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
-
- let funcStartPos =
- let rec loop ch pos =
- if not (Char.IsWhiteSpace(ch)) then
- pos
- else
- loop sourceText.[pos + 1] (pos + 1)
-
- loop sourceText.[context.Span.End + 1] (context.Span.End + 1)
-
- let! funcLexerSymbol =
- Tokenizer.getSymbolAtPosition (
- context.Document.Id,
- sourceText,
- funcStartPos,
- context.Document.FilePath,
- defines,
- SymbolLookupKind.Greedy,
- false,
- false,
- Some langVersion,
- context.CancellationToken
- )
-
- let! funcNameSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, funcLexerSymbol.Range)
- let funcName = sourceText.GetSubText(funcNameSpan).ToString()
-
- do
- context.RegisterFsharpFix(
- CodeFix.AddMissingRecToMutuallyRecFunctions,
- String.Format(titleFormat, funcName),
- [| TextChange(TextSpan(context.Span.End, 0), " rec") |]
- )
- }
- |> Async.Ignore
- |> RoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken)
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ChangeToUpcast.fs b/vsintegration/src/FSharp.Editor/CodeFix/ChangeToUpcast.fs
deleted file mode 100644
index 7136009a928..00000000000
--- a/vsintegration/src/FSharp.Editor/CodeFix/ChangeToUpcast.fs
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-
-namespace Microsoft.VisualStudio.FSharp.Editor
-
-open System.Composition
-open System.Threading.Tasks
-open System.Collections.Immutable
-
-open Microsoft.CodeAnalysis.Text
-open Microsoft.CodeAnalysis.CodeFixes
-
-open CancellableTasks
-
-[]
-type internal FSharpChangeToUpcastCodeFixProvider() =
- inherit CodeFixProvider()
-
- override _.FixableDiagnosticIds = ImmutableArray.Create("FS3198")
-
- interface IFSharpCodeFix with
- member _.GetChangesAsync document span =
- cancellableTask {
- let! cancellationToken = CancellableTask.getCurrentCancellationToken ()
-
- let! sourceText = document.GetTextAsync(cancellationToken)
- let text = sourceText.GetSubText(span).ToString()
-
- // Only works if it's one or the other
- let isDowncastOperator = text.Contains(":?>")
- let isDowncastKeyword = text.Contains("downcast")
-
- let changes =
- [
- if
- (isDowncastOperator || isDowncastKeyword)
- && not (isDowncastOperator && isDowncastKeyword)
- then
- let replacement =
- if isDowncastOperator then
- text.Replace(":?>", ":>")
- else
- text.Replace("downcast", "upcast")
-
- TextChange(span, replacement)
- ]
-
- let title =
- if isDowncastOperator then
- SR.UseUpcastOperator()
- else
- SR.UseUpcastKeyword()
-
- return title, changes
- }
-
- override this.RegisterCodeFixesAsync context : Task =
- cancellableTask {
- let! title, changes = (this :> IFSharpCodeFix).GetChangesAsync context.Document context.Span
- context.RegisterFsharpFix(CodeFix.ChangeToUpcast, title, changes)
- }
- |> CancellableTask.startAsTask context.CancellationToken
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/IFSharpCodeFix.fs b/vsintegration/src/FSharp.Editor/CodeFix/IFSharpCodeFix.fs
deleted file mode 100644
index e0a4fa23a6e..00000000000
--- a/vsintegration/src/FSharp.Editor/CodeFix/IFSharpCodeFix.fs
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-
-namespace Microsoft.VisualStudio.FSharp.Editor
-
-open Microsoft.CodeAnalysis
-open Microsoft.CodeAnalysis.Text
-
-open CancellableTasks
-
-type IFSharpCodeFix =
- abstract member GetChangesAsync: document: Document -> span: TextSpan -> CancellableTask
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RemoveReturnOrYield.fs b/vsintegration/src/FSharp.Editor/CodeFix/RemoveReturnOrYield.fs
deleted file mode 100644
index f69688fde13..00000000000
--- a/vsintegration/src/FSharp.Editor/CodeFix/RemoveReturnOrYield.fs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-
-namespace Microsoft.VisualStudio.FSharp.Editor
-
-open System.Composition
-open System.Collections.Immutable
-
-open Microsoft.CodeAnalysis.Text
-open Microsoft.CodeAnalysis.CodeFixes
-
-[]
-type internal FSharpRemoveReturnOrYieldCodeFixProvider [] () =
- inherit CodeFixProvider()
-
- override _.FixableDiagnosticIds = ImmutableArray.Create("FS0748", "FS0747")
-
- override _.RegisterCodeFixesAsync context =
- asyncMaybe {
- let! parseResults =
- context.Document.GetFSharpParseResultsAsync(nameof (FSharpRemoveReturnOrYieldCodeFixProvider))
- |> liftAsync
-
- let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
-
- let errorRange =
- RoslynHelpers.TextSpanToFSharpRange(context.Document.FilePath, context.Span, sourceText)
-
- let! exprRange = parseResults.TryRangeOfExprInYieldOrReturn errorRange.Start
- let! exprSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, exprRange)
-
- let title =
- let text = sourceText.GetSubText(context.Span).ToString()
-
- if text.StartsWith("return!") then SR.RemoveReturnBang()
- elif text.StartsWith("return") then SR.RemoveReturn()
- elif text.StartsWith("yield!") then SR.RemoveYieldBang()
- else SR.RemoveYield()
-
- do
- context.RegisterFsharpFix(
- CodeFix.RemoveReturnOrYield,
- title,
- [| TextChange(context.Span, sourceText.GetSubText(exprSpan).ToString()) |]
- )
- }
- |> Async.Ignore
- |> RoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken)
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/WrapExpressionInParentheses.fs b/vsintegration/src/FSharp.Editor/CodeFix/WrapExpressionInParentheses.fs
deleted file mode 100644
index 70ed64f5054..00000000000
--- a/vsintegration/src/FSharp.Editor/CodeFix/WrapExpressionInParentheses.fs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-
-namespace Microsoft.VisualStudio.FSharp.Editor
-
-open System.Composition
-open System.Threading
-open System.Threading.Tasks
-open System.Collections.Immutable
-
-open Microsoft.CodeAnalysis.Text
-open Microsoft.CodeAnalysis.CodeFixes
-open Microsoft.CodeAnalysis.CodeActions
-
-[]
-type internal FSharpWrapExpressionInParenthesesFixProvider() =
- inherit CodeFixProvider()
-
- static let title = SR.WrapExpressionInParentheses()
-
- override _.FixableDiagnosticIds = ImmutableArray.Create("FS0597")
-
- override this.RegisterCodeFixesAsync context : Task =
- backgroundTask {
- let changes =
- [
- TextChange(TextSpan(context.Span.Start, 0), "(")
- TextChange(TextSpan(context.Span.End + 1, 0), ")")
- ]
-
- context.RegisterFsharpFix(CodeFix.AddParentheses, title, changes)
- }
diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/AddInstanceMemberParameter.fs b/vsintegration/src/FSharp.Editor/CodeFixes/AddInstanceMemberParameter.fs
new file mode 100644
index 00000000000..4e757dbe617
--- /dev/null
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/AddInstanceMemberParameter.fs
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.Editor
+
+open System.Composition
+open System.Collections.Immutable
+
+open Microsoft.CodeAnalysis.Text
+open Microsoft.CodeAnalysis.CodeFixes
+
+open CancellableTasks
+
+[]
+type internal AddInstanceMemberParameterCodeFixProvider() =
+ inherit CodeFixProvider()
+
+ static let title = SR.AddMissingInstanceMemberParameter()
+
+ override _.FixableDiagnosticIds = ImmutableArray.Create("FS0673")
+
+ override this.RegisterCodeFixesAsync context = context.RegisterFsharpFix(this)
+
+ interface IFSharpCodeFixProvider with
+ member _.GetCodeFixIfAppliesAsync _ span =
+ let codeFix =
+ {
+ Name = CodeFix.AddInstanceMemberParameter
+ Message = title
+ Changes = [ TextChange(TextSpan(span.Start, 0), "x.") ]
+ }
+
+ CancellableTask.singleton (Some codeFix)
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddMissingEqualsToTypeDefinition.fs b/vsintegration/src/FSharp.Editor/CodeFixes/AddMissingEqualsToTypeDefinition.fs
similarity index 95%
rename from vsintegration/src/FSharp.Editor/CodeFix/AddMissingEqualsToTypeDefinition.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/AddMissingEqualsToTypeDefinition.fs
index 96d434ca3c4..c71d4cbcb4b 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/AddMissingEqualsToTypeDefinition.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/AddMissingEqualsToTypeDefinition.fs
@@ -11,7 +11,7 @@ open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
[]
-type internal FSharpAddMissingEqualsToTypeDefinitionCodeFixProvider() =
+type internal AddMissingEqualsToTypeDefinitionCodeFixProvider() =
inherit CodeFixProvider()
static let title = SR.AddMissingEqualsToTypeDefinition()
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddMissingFunKeyword.fs b/vsintegration/src/FSharp.Editor/CodeFixes/AddMissingFunKeyword.fs
similarity index 91%
rename from vsintegration/src/FSharp.Editor/CodeFix/AddMissingFunKeyword.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/AddMissingFunKeyword.fs
index 5c07cb6e799..65854292e79 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/AddMissingFunKeyword.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/AddMissingFunKeyword.fs
@@ -9,11 +9,8 @@ open System.Collections.Immutable
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
-open FSharp.Compiler
-open FSharp.Compiler.CodeAnalysis
-
[]
-type internal FSharpAddMissingFunKeywordCodeFixProvider [] () =
+type internal AddMissingFunKeywordCodeFixProvider [] () =
inherit CodeFixProvider()
static let title = SR.AddMissingFunKeyword()
@@ -29,7 +26,7 @@ type internal FSharpAddMissingFunKeywordCodeFixProvider []
do! Option.guard (textOfError = "->")
let! defines, langVersion =
- document.GetFSharpCompilationDefinesAndLangVersionAsync(nameof (FSharpAddMissingFunKeywordCodeFixProvider))
+ document.GetFSharpCompilationDefinesAndLangVersionAsync(nameof (AddMissingFunKeywordCodeFixProvider))
|> liftAsync
let adjustedPosition =
diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/AddMissingRecToMutuallyRecFunctions.fs b/vsintegration/src/FSharp.Editor/CodeFixes/AddMissingRecToMutuallyRecFunctions.fs
new file mode 100644
index 00000000000..5713ca8e68c
--- /dev/null
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/AddMissingRecToMutuallyRecFunctions.fs
@@ -0,0 +1,64 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.Editor
+
+open System
+open System.Collections.Immutable
+open System.Composition
+
+open Microsoft.CodeAnalysis.Text
+open Microsoft.CodeAnalysis.CodeFixes
+
+open CancellableTasks
+
+[]
+type internal AddMissingRecToMutuallyRecFunctionsCodeFixProvider [] () =
+ inherit CodeFixProvider()
+
+ static let titleFormat = SR.MakeOuterBindingRecursive()
+
+ override _.FixableDiagnosticIds = ImmutableArray.Create("FS0576")
+
+ override this.RegisterCodeFixesAsync context = context.RegisterFsharpFix(this)
+
+ interface IFSharpCodeFixProvider with
+ member _.GetCodeFixIfAppliesAsync document span =
+ cancellableTask {
+ let! cancellationToken = CancellableTask.getCurrentCancellationToken ()
+
+ let! defines, langVersion =
+ document.GetFSharpCompilationDefinesAndLangVersionAsync(nameof (AddMissingRecToMutuallyRecFunctionsCodeFixProvider))
+
+ let! sourceText = document.GetTextAsync(cancellationToken)
+
+ let funcStartPos =
+ let rec loop ch pos =
+ if not (Char.IsWhiteSpace(ch)) then
+ pos
+ else
+ loop sourceText.[pos + 1] (pos + 1)
+
+ loop sourceText.[span.End + 1] (span.End + 1)
+
+ return
+ Tokenizer.getSymbolAtPosition (
+ document.Id,
+ sourceText,
+ funcStartPos,
+ document.FilePath,
+ defines,
+ SymbolLookupKind.Greedy,
+ false,
+ false,
+ Some langVersion,
+ cancellationToken
+ )
+ |> Option.bind (fun funcLexerSymbol -> RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, funcLexerSymbol.Range))
+ |> Option.map (fun funcNameSpan -> sourceText.GetSubText(funcNameSpan).ToString())
+ |> Option.map (fun funcName ->
+ {
+ Name = CodeFix.AddMissingRecToMutuallyRecFunctions
+ Message = String.Format(titleFormat, funcName)
+ Changes = [ TextChange(TextSpan(span.End, 0), " rec") ]
+ })
+ }
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddNewKeywordToDisposableConstructorInvocation.fs b/vsintegration/src/FSharp.Editor/CodeFixes/AddNewKeywordToDisposableConstructorInvocation.fs
similarity index 93%
rename from vsintegration/src/FSharp.Editor/CodeFix/AddNewKeywordToDisposableConstructorInvocation.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/AddNewKeywordToDisposableConstructorInvocation.fs
index 8a72534a804..5dcc030fcf8 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/AddNewKeywordToDisposableConstructorInvocation.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/AddNewKeywordToDisposableConstructorInvocation.fs
@@ -10,10 +10,9 @@ open System.Collections.Immutable
open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
-open Microsoft.CodeAnalysis.CodeActions
[]
-type internal FSharpAddNewKeywordCodeFixProvider() =
+type internal AddNewKeywordCodeFixProvider() =
inherit CodeFixProvider()
static let title = SR.AddNewKeyword()
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFixes/AddOpenCodeFixProvider.fs
similarity index 95%
rename from vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/AddOpenCodeFixProvider.fs
index 38f96d81ed0..a9b71bac3fb 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/AddOpenCodeFixProvider.fs
@@ -2,24 +2,18 @@
namespace Microsoft.VisualStudio.FSharp.Editor
-open System
open System.Composition
-open System.Threading
open System.Threading.Tasks
open System.Collections.Immutable
-open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
-open Microsoft.CodeAnalysis.CodeActions
-open FSharp.Compiler
-open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.EditorServices
open FSharp.Compiler.Text
[]
-type internal FSharpAddOpenCodeFixProvider [] (assemblyContentProvider: AssemblyContentProvider) =
+type internal AddOpenCodeFixProvider [] (assemblyContentProvider: AssemblyContentProvider) =
inherit CodeFixProvider()
let fixUnderscoresInMenuText (text: string) = text.Replace("_", "__")
@@ -73,14 +67,14 @@ type internal FSharpAddOpenCodeFixProvider [] (assemblyCon
let! sourceText = document.GetTextAsync(context.CancellationToken)
let! parseResults, checkResults =
- document.GetFSharpParseAndCheckResultsAsync(nameof (FSharpAddOpenCodeFixProvider))
+ document.GetFSharpParseAndCheckResultsAsync(nameof (AddOpenCodeFixProvider))
|> liftAsync
let line = sourceText.Lines.GetLineFromPosition(context.Span.End)
let linePos = sourceText.Lines.GetLinePosition(context.Span.End)
let! defines, langVersion =
- document.GetFSharpCompilationDefinesAndLangVersionAsync(nameof (FSharpAddOpenCodeFixProvider))
+ document.GetFSharpCompilationDefinesAndLangVersionAsync(nameof (AddOpenCodeFixProvider))
|> liftAsync
let! symbol =
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddTypeAnnotationToObjectOfIndeterminateType.fs b/vsintegration/src/FSharp.Editor/CodeFixes/AddTypeAnnotationToObjectOfIndeterminateType.fs
similarity index 92%
rename from vsintegration/src/FSharp.Editor/CodeFix/AddTypeAnnotationToObjectOfIndeterminateType.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/AddTypeAnnotationToObjectOfIndeterminateType.fs
index 4e73d9bc136..5f048d4d9de 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/AddTypeAnnotationToObjectOfIndeterminateType.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/AddTypeAnnotationToObjectOfIndeterminateType.fs
@@ -4,21 +4,18 @@ namespace Microsoft.VisualStudio.FSharp.Editor
open System
open System.Composition
-open System.Threading
open System.Threading.Tasks
open System.Collections.Immutable
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
-open FSharp.Compiler
open FSharp.Compiler.EditorServices
open FSharp.Compiler.Text
open FSharp.Compiler.Symbols
-open Microsoft.CodeAnalysis.CodeActions
[]
-type internal FSharpAddTypeAnnotationToObjectOfIndeterminateTypeFixProvider [] () =
+type internal AddTypeAnnotationToObjectOfIndeterminateTypeFixProvider [] () =
inherit CodeFixProvider()
static let title = SR.AddTypeAnnotation()
@@ -42,11 +39,11 @@ type internal FSharpAddTypeAnnotationToObjectOfIndeterminateTypeFixProvider [ liftAsync
let decl =
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ChangePrefixNegationToInfixSubtraction.fs b/vsintegration/src/FSharp.Editor/CodeFixes/ChangePrefixNegationToInfixSubtraction.fs
similarity index 95%
rename from vsintegration/src/FSharp.Editor/CodeFix/ChangePrefixNegationToInfixSubtraction.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/ChangePrefixNegationToInfixSubtraction.fs
index 7f0a69ef4b9..62fda0ff519 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ChangePrefixNegationToInfixSubtraction.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/ChangePrefixNegationToInfixSubtraction.fs
@@ -11,7 +11,7 @@ open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
[]
-type internal FSharpChangePrefixNegationToInfixSubtractionodeFixProvider() =
+type internal ChangePrefixNegationToInfixSubtractionodeFixProvider() =
inherit CodeFixProvider()
static let title = SR.ChangePrefixNegationToInfixSubtraction()
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ChangeRefCellDerefToNotExpression.fs b/vsintegration/src/FSharp.Editor/CodeFixes/ChangeRefCellDerefToNotExpression.fs
similarity index 86%
rename from vsintegration/src/FSharp.Editor/CodeFix/ChangeRefCellDerefToNotExpression.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/ChangeRefCellDerefToNotExpression.fs
index e084a871a31..41e57011004 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ChangeRefCellDerefToNotExpression.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/ChangeRefCellDerefToNotExpression.fs
@@ -10,7 +10,7 @@ open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
[]
-type internal FSharpChangeRefCellDerefToNotExpressionCodeFixProvider [] () =
+type internal ChangeRefCellDerefToNotExpressionCodeFixProvider [] () =
inherit CodeFixProvider()
static let title = SR.UseNotForNegation()
@@ -22,7 +22,7 @@ type internal FSharpChangeRefCellDerefToNotExpressionCodeFixProvider [ liftAsync
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/ChangeToUpcast.fs b/vsintegration/src/FSharp.Editor/CodeFixes/ChangeToUpcast.fs
new file mode 100644
index 00000000000..4d17fba03a9
--- /dev/null
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/ChangeToUpcast.fs
@@ -0,0 +1,61 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.Editor
+
+open System.Composition
+open System.Collections.Immutable
+
+open Microsoft.CodeAnalysis.Text
+open Microsoft.CodeAnalysis.CodeFixes
+
+open CancellableTasks
+
+[]
+type internal ChangeToUpcastCodeFixProvider() =
+ inherit CodeFixProvider()
+
+ override _.FixableDiagnosticIds = ImmutableArray.Create("FS3198")
+
+ override this.RegisterCodeFixesAsync context = context.RegisterFsharpFix(this)
+
+ interface IFSharpCodeFixProvider with
+ member _.GetCodeFixIfAppliesAsync document span =
+ cancellableTask {
+ let! cancellationToken = CancellableTask.getCurrentCancellationToken ()
+
+ let! sourceText = document.GetTextAsync(cancellationToken)
+ let text = sourceText.GetSubText(span).ToString()
+
+ // Only works if it's one or the other
+ let isDowncastOperator = text.Contains(":?>")
+ let isDowncastKeyword = text.Contains("downcast")
+
+ if
+ (isDowncastOperator || isDowncastKeyword)
+ && not (isDowncastOperator && isDowncastKeyword)
+ then
+ let replacement =
+ if isDowncastOperator then
+ text.Replace(":?>", ":>")
+ else
+ text.Replace("downcast", "upcast")
+
+ let changes = [ TextChange(span, replacement) ]
+
+ let title =
+ if isDowncastOperator then
+ SR.UseUpcastOperator()
+ else
+ SR.UseUpcastKeyword()
+
+ let codeFix =
+ {
+ Name = CodeFix.ChangeToUpcast
+ Message = title
+ Changes = changes
+ }
+
+ return Some codeFix
+ else
+ return None
+ }
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/CodeFixHelpers.fs b/vsintegration/src/FSharp.Editor/CodeFixes/CodeFixHelpers.fs
similarity index 88%
rename from vsintegration/src/FSharp.Editor/CodeFix/CodeFixHelpers.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/CodeFixHelpers.fs
index 924bf6d38fb..13ce3fc3095 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/CodeFixHelpers.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/CodeFixHelpers.fs
@@ -2,9 +2,7 @@
namespace Microsoft.VisualStudio.FSharp.Editor
-open System
open System.Threading
-open System.Threading.Tasks
open System.Collections.Immutable
open System.Diagnostics
@@ -15,6 +13,8 @@ open Microsoft.CodeAnalysis.CodeFixes
open Microsoft.CodeAnalysis.CodeActions
open Microsoft.VisualStudio.FSharp.Editor.Telemetry
+open CancellableTasks
+
[]
module internal CodeFixHelpers =
let private reportCodeFixTelemetry
@@ -80,3 +80,11 @@ module internal CodeFixExtensions =
let diag = diagnostics |> Option.defaultValue ctx.Diagnostics
ctx.RegisterCodeFix(codeAction, diag)
+
+ member ctx.RegisterFsharpFix(codeFix: IFSharpCodeFixProvider) =
+ cancellableTask {
+ match! codeFix.GetCodeFixIfAppliesAsync ctx.Document ctx.Span with
+ | Some codeFix -> ctx.RegisterFsharpFix(codeFix.Name, codeFix.Message, codeFix.Changes)
+ | None -> ()
+ }
+ |> CancellableTask.startAsTask ctx.CancellationToken
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpLambdaToFSharpLambda.fs b/vsintegration/src/FSharp.Editor/CodeFixes/ConvertCSharpLambdaToFSharpLambda.fs
similarity index 92%
rename from vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpLambdaToFSharpLambda.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/ConvertCSharpLambdaToFSharpLambda.fs
index 7e8f1c71e76..978f8e328f1 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpLambdaToFSharpLambda.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/ConvertCSharpLambdaToFSharpLambda.fs
@@ -9,7 +9,7 @@ open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
[]
-type internal FSharpConvertCSharpLambdaToFSharpLambdaCodeFixProvider [] () =
+type internal ConvertCSharpLambdaToFSharpLambdaCodeFixProvider [] () =
inherit CodeFixProvider()
static let title = SR.UseFSharpLambda()
@@ -19,7 +19,7 @@ type internal FSharpConvertCSharpLambdaToFSharpLambdaCodeFixProvider [ liftAsync
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpUsingToFSharpOpen.fs b/vsintegration/src/FSharp.Editor/CodeFixes/ConvertCSharpUsingToFSharpOpen.fs
similarity index 96%
rename from vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpUsingToFSharpOpen.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/ConvertCSharpUsingToFSharpOpen.fs
index a1d45db3e4f..0619a7e021c 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpUsingToFSharpOpen.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/ConvertCSharpUsingToFSharpOpen.fs
@@ -6,12 +6,11 @@ open System
open System.Composition
open System.Collections.Immutable
-open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
[]
-type internal FSharpConvertCSharpUsingToFSharpOpen [] () =
+type internal ConvertCSharpUsingToFSharpOpenCodeFixProvider [] () =
inherit CodeFixProvider()
static let title = SR.ConvertCSharpUsingToFSharpOpen()
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ConvertToAnonymousRecord.fs b/vsintegration/src/FSharp.Editor/CodeFixes/ConvertToAnonymousRecord.fs
similarity index 57%
rename from vsintegration/src/FSharp.Editor/CodeFix/ConvertToAnonymousRecord.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/ConvertToAnonymousRecord.fs
index da39b93e9c3..098045b9295 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ConvertToAnonymousRecord.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/ConvertToAnonymousRecord.fs
@@ -3,7 +3,6 @@
namespace Microsoft.VisualStudio.FSharp.Editor
open System.Composition
-open System.Threading.Tasks
open System.Collections.Immutable
open Microsoft.CodeAnalysis.Text
@@ -12,41 +11,38 @@ open Microsoft.CodeAnalysis.CodeFixes
open CancellableTasks
[]
-type internal FSharpConvertToAnonymousRecordCodeFixProvider [] () =
+type internal ConvertToAnonymousRecordCodeFixProvider [] () =
inherit CodeFixProvider()
static let title = SR.ConvertToAnonymousRecord()
override _.FixableDiagnosticIds = ImmutableArray.Create("FS0039")
- interface IFSharpCodeFix with
- member _.GetChangesAsync document span =
+ override this.RegisterCodeFixesAsync context = context.RegisterFsharpFix(this)
+
+ interface IFSharpCodeFixProvider with
+ member _.GetCodeFixIfAppliesAsync document span =
cancellableTask {
let! cancellationToken = CancellableTask.getCurrentCancellationToken ()
- let! parseResults = document.GetFSharpParseResultsAsync(nameof (FSharpConvertToAnonymousRecordCodeFixProvider))
+ let! parseResults = document.GetFSharpParseResultsAsync(nameof (ConvertToAnonymousRecordCodeFixProvider))
let! sourceText = document.GetTextAsync(cancellationToken)
let errorRange =
RoslynHelpers.TextSpanToFSharpRange(document.FilePath, span, sourceText)
- let changes =
+ return
parseResults.TryRangeOfRecordExpressionContainingPos errorRange.Start
|> Option.bind (fun range -> RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range))
|> Option.map (fun span ->
- [
- TextChange(TextSpan(span.Start + 1, 0), "|")
- TextChange(TextSpan(span.End - 1, 0), "|")
- ])
- |> Option.defaultValue []
-
- return title, changes
+ {
+ Name = CodeFix.ConvertToAnonymousRecord
+ Message = title
+ Changes =
+ [
+ TextChange(TextSpan(span.Start + 1, 0), "|")
+ TextChange(TextSpan(span.End - 1, 0), "|")
+ ]
+ })
}
-
- override this.RegisterCodeFixesAsync context : Task =
- cancellableTask {
- let! title, changes = (this :> IFSharpCodeFix).GetChangesAsync context.Document context.Span
- return context.RegisterFsharpFix(CodeFix.ConvertToAnonymousRecord, title, changes)
- }
- |> CancellableTask.startAsTask context.CancellationToken
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ConvertToNotEqualsEqualityExpression.fs b/vsintegration/src/FSharp.Editor/CodeFixes/ConvertToNotEqualsEqualityExpression.fs
similarity index 94%
rename from vsintegration/src/FSharp.Editor/CodeFix/ConvertToNotEqualsEqualityExpression.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/ConvertToNotEqualsEqualityExpression.fs
index 41df93120ae..3a4a0dcce2e 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ConvertToNotEqualsEqualityExpression.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/ConvertToNotEqualsEqualityExpression.fs
@@ -10,7 +10,7 @@ open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
[]
-type internal FSharpConvertToNotEqualsEqualityExpressionCodeFixProvider() =
+type internal ConvertToNotEqualsEqualityExpressionCodeFixProvider() =
inherit CodeFixProvider()
static let title = SR.ConvertToNotEqualsEqualityExpression()
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ConvertToSingleEqualsEqualityExpression.fs b/vsintegration/src/FSharp.Editor/CodeFixes/ConvertToSingleEqualsEqualityExpression.fs
similarity index 94%
rename from vsintegration/src/FSharp.Editor/CodeFix/ConvertToSingleEqualsEqualityExpression.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/ConvertToSingleEqualsEqualityExpression.fs
index f38be2aed08..a243c7c63ac 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ConvertToSingleEqualsEqualityExpression.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/ConvertToSingleEqualsEqualityExpression.fs
@@ -10,7 +10,7 @@ open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
[]
-type internal FSharpConvertToSingleEqualsEqualityExpressionCodeFixProvider() =
+type internal ConvertToSingleEqualsEqualityExpressionCodeFixProvider() =
inherit CodeFixProvider()
static let title = SR.ConvertToSingleEqualsEqualityExpression()
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/FixIndexerAccess.fs b/vsintegration/src/FSharp.Editor/CodeFixes/FixIndexerAccess.fs
similarity index 98%
rename from vsintegration/src/FSharp.Editor/CodeFix/FixIndexerAccess.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/FixIndexerAccess.fs
index 71b56555091..400982edd73 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/FixIndexerAccess.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/FixIndexerAccess.fs
@@ -13,7 +13,7 @@ open Microsoft.CodeAnalysis.CodeFixes
open FSharp.Compiler.Diagnostics
[]
-type internal LegacyFsharpFixAddDotToIndexerAccess() =
+type internal LegacyFixAddDotToIndexerAccessCodeFixProvider() =
inherit CodeFixProvider()
static let title = CompilerDiagnostics.GetErrorMessage FSharpDiagnosticKind.AddIndexerDot
diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/IFSharpCodeFix.fs b/vsintegration/src/FSharp.Editor/CodeFixes/IFSharpCodeFix.fs
new file mode 100644
index 00000000000..36a4ff2db56
--- /dev/null
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/IFSharpCodeFix.fs
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.Editor
+
+open Microsoft.CodeAnalysis
+open Microsoft.CodeAnalysis.Text
+
+open CancellableTasks
+
+type FSharpCodeFix =
+ {
+ Name: string
+ Message: string
+ Changes: TextChange list
+ }
+
+type IFSharpCodeFixProvider =
+ abstract member GetCodeFixIfAppliesAsync: document: Document -> span: TextSpan -> CancellableTask
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFixes/ImplementInterfaceCodeFixProvider.fs
similarity index 98%
rename from vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/ImplementInterfaceCodeFixProvider.fs
index d0630bbba0d..ad0ca1c0f77 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/ImplementInterfaceCodeFixProvider.fs
@@ -32,7 +32,7 @@ type internal InterfaceState =
}
[]
-type internal FSharpImplementInterfaceCodeFixProvider [] () =
+type internal ImplementInterfaceCodeFixProvider [] () =
inherit CodeFixProvider()
let queryInterfaceState appendBracketAt (pos: pos) (tokens: Tokenizer.SavedTokenInfo[]) (ast: ParsedInput) =
@@ -190,7 +190,7 @@ type internal FSharpImplementInterfaceCodeFixProvider [] (
override _.RegisterCodeFixesAsync context : Task =
asyncMaybe {
let! parseResults, checkFileResults =
- context.Document.GetFSharpParseAndCheckResultsAsync(nameof (FSharpImplementInterfaceCodeFixProvider))
+ context.Document.GetFSharpParseAndCheckResultsAsync(nameof (ImplementInterfaceCodeFixProvider))
|> liftAsync
let cancellationToken = context.CancellationToken
@@ -198,7 +198,7 @@ type internal FSharpImplementInterfaceCodeFixProvider [] (
let textLine = sourceText.Lines.GetLineFromPosition context.Span.Start
let! _, _, parsingOptions, _ =
- context.Document.GetFSharpCompilationOptionsAsync(nameof (FSharpImplementInterfaceCodeFixProvider))
+ context.Document.GetFSharpCompilationOptionsAsync(nameof (ImplementInterfaceCodeFixProvider))
|> liftAsync
let defines = CompilerEnvironment.GetConditionalDefinesForEditing parsingOptions
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs b/vsintegration/src/FSharp.Editor/CodeFixes/MakeDeclarationMutable.fs
similarity index 93%
rename from vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/MakeDeclarationMutable.fs
index e230e719c9d..d3ad0ff8218 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/MakeDeclarationMutable.fs
@@ -13,7 +13,7 @@ open FSharp.Compiler.EditorServices
open FSharp.Compiler.Text
[]
-type internal FSharpMakeDeclarationMutableFixProvider [] () =
+type internal MakeDeclarationMutableFixProvider [] () =
inherit CodeFixProvider()
static let title = SR.MakeDeclarationMutable()
@@ -33,7 +33,7 @@ type internal FSharpMakeDeclarationMutableFixProvider [] (
SymbolLookupKind.Greedy,
false,
false,
- nameof (FSharpMakeDeclarationMutableFixProvider)
+ nameof (MakeDeclarationMutableFixProvider)
)
let! sourceText = document.GetTextAsync() |> liftTaskAsync
@@ -42,7 +42,7 @@ type internal FSharpMakeDeclarationMutableFixProvider [] (
let fcsTextLineNumber = Line.fromZ textLinePos.Line
let! parseFileResults, checkFileResults =
- document.GetFSharpParseAndCheckResultsAsync(nameof (FSharpMakeDeclarationMutableFixProvider))
+ document.GetFSharpParseAndCheckResultsAsync(nameof (MakeDeclarationMutableFixProvider))
|> liftAsync
let decl =
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/MakeOuterBindingRecursive.fs b/vsintegration/src/FSharp.Editor/CodeFixes/MakeOuterBindingRecursive.fs
similarity index 93%
rename from vsintegration/src/FSharp.Editor/CodeFix/MakeOuterBindingRecursive.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/MakeOuterBindingRecursive.fs
index 78fae0522f9..c0c245fe066 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/MakeOuterBindingRecursive.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/MakeOuterBindingRecursive.fs
@@ -10,7 +10,7 @@ open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
[]
-type internal FSharpMakeOuterBindingRecursiveCodeFixProvider [] () =
+type internal MakeOuterBindingRecursiveCodeFixProvider [] () =
inherit CodeFixProvider()
override _.FixableDiagnosticIds = ImmutableArray.Create("FS0039")
@@ -18,7 +18,7 @@ type internal FSharpMakeOuterBindingRecursiveCodeFixProvider [ liftAsync
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/MissingReferenceCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFixes/MissingReferenceCodeFixProvider.fs
similarity index 100%
rename from vsintegration/src/FSharp.Editor/CodeFix/MissingReferenceCodeFixProvider.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/MissingReferenceCodeFixProvider.fs
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs b/vsintegration/src/FSharp.Editor/CodeFixes/ProposeUppercaseLabel.fs
similarity index 93%
rename from vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/ProposeUppercaseLabel.fs
index d290549fa19..ceaaa8bcbc3 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ProposeUppercaseLabel.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/ProposeUppercaseLabel.fs
@@ -12,7 +12,7 @@ open Microsoft.CodeAnalysis.CodeActions
open FSharp.Compiler.Diagnostics
[]
-type internal FSharpProposeUpperCaseLabelCodeFixProvider [] () =
+type internal ProposeUpperCaseLabelCodeFixProvider [] () =
inherit CodeFixProvider()
override _.FixableDiagnosticIds = ImmutableArray.Create("FS0053")
diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/RemoveReturnOrYield.fs b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveReturnOrYield.fs
new file mode 100644
index 00000000000..728faa005ae
--- /dev/null
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveReturnOrYield.fs
@@ -0,0 +1,51 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.Editor
+
+open System.Composition
+open System.Collections.Immutable
+
+open Microsoft.CodeAnalysis.Text
+open Microsoft.CodeAnalysis.CodeFixes
+
+open CancellableTasks
+
+[]
+type internal RemoveReturnOrYieldCodeFixProvider [] () =
+ inherit CodeFixProvider()
+
+ override _.FixableDiagnosticIds = ImmutableArray.Create("FS0747", "FS0748")
+
+ override this.RegisterCodeFixesAsync context = context.RegisterFsharpFix(this)
+
+ interface IFSharpCodeFixProvider with
+ member _.GetCodeFixIfAppliesAsync document span =
+ cancellableTask {
+ let! cancellationToken = CancellableTask.getCurrentCancellationToken ()
+
+ let! parseResults = document.GetFSharpParseResultsAsync(nameof (RemoveReturnOrYieldCodeFixProvider))
+
+ let! sourceText = document.GetTextAsync(cancellationToken)
+
+ let errorRange =
+ RoslynHelpers.TextSpanToFSharpRange(document.FilePath, span, sourceText)
+
+ return
+ parseResults.TryRangeOfExprInYieldOrReturn errorRange.Start
+ |> Option.bind (fun exprRange -> RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, exprRange))
+ |> Option.map (fun exprSpan -> [ TextChange(span, sourceText.GetSubText(exprSpan).ToString()) ])
+ |> Option.map (fun changes ->
+ let title =
+ let text = sourceText.GetSubText(span).ToString()
+
+ if text.StartsWith("return!") then SR.RemoveReturnBang()
+ elif text.StartsWith("return") then SR.RemoveReturn()
+ elif text.StartsWith("yield!") then SR.RemoveYieldBang()
+ else SR.RemoveYield()
+
+ {
+ Name = CodeFix.RemoveReturnOrYield
+ Message = title
+ Changes = changes
+ })
+ }
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RemoveSuperflousCaptureForUnionCaseWithNoData.fs b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveSuperflousCaptureForUnionCaseWithNoData.fs
similarity index 95%
rename from vsintegration/src/FSharp.Editor/CodeFix/RemoveSuperflousCaptureForUnionCaseWithNoData.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/RemoveSuperflousCaptureForUnionCaseWithNoData.fs
index d2fcfa51b19..349f4f502fa 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/RemoveSuperflousCaptureForUnionCaseWithNoData.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveSuperflousCaptureForUnionCaseWithNoData.fs
@@ -8,14 +8,13 @@ open System.Threading.Tasks
open System.Collections.Immutable
open Microsoft.CodeAnalysis
-open Microsoft.CodeAnalysis.CodeActions
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
open FSharp.Compiler.EditorServices
[]
-type internal RemoveSuperflousCaptureForUnionCaseWithNoDataProvider [] () =
+type internal RemoveSuperflousCaptureForUnionCaseWithNoDataCodeFixProvider [] () =
inherit CodeFixProvider()
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedBinding.fs b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedBinding.fs
similarity index 93%
rename from vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedBinding.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedBinding.fs
index 9335eda0000..eb55bd3f0dd 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedBinding.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedBinding.fs
@@ -9,14 +9,11 @@ open System.Threading.Tasks
open System.Collections.Immutable
open Microsoft.CodeAnalysis
-open Microsoft.CodeAnalysis.CodeActions
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
-open FSharp.Compiler.EditorServices
-
[]
-type internal FSharpRemoveUnusedBindingCodeFixProvider [] () =
+type internal RemoveUnusedBindingCodeFixProvider [] () =
inherit CodeFixProvider()
@@ -27,7 +24,7 @@ type internal FSharpRemoveUnusedBindingCodeFixProvider []
backgroundTask {
let! sourceText = document.GetTextAsync(ct)
- let! parseResults = document.GetFSharpParseResultsAsync(nameof (FSharpRemoveUnusedBindingCodeFixProvider))
+ let! parseResults = document.GetFSharpParseResultsAsync(nameof (RemoveUnusedBindingCodeFixProvider))
let changes =
seq {
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedOpens.fs
similarity index 92%
rename from vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedOpens.fs
index b57f35bd61b..ac1e17bc823 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedOpens.fs
@@ -10,13 +10,10 @@ open System.Collections.Immutable
open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
-open Microsoft.CodeAnalysis.CodeActions
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics
-open FSharp.Compiler.Text
-
[]
-type internal FSharpRemoveUnusedOpensCodeFixProvider [] () =
+type internal RemoveUnusedOpensCodeFixProvider [] () =
inherit CodeFixProvider()
static let title = SR.RemoveUnusedOpens()
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs b/vsintegration/src/FSharp.Editor/CodeFixes/RenameParamToMatchSignature.fs
similarity index 95%
rename from vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/RenameParamToMatchSignature.fs
index fb916fbb849..1dfc34e62bb 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/RenameParamToMatchSignature.fs
@@ -11,14 +11,12 @@ open System.Text.RegularExpressions
open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
-open Microsoft.CodeAnalysis.CodeActions
open Microsoft.VisualStudio.FSharp.Editor.SymbolHelpers
-open FSharp.Compiler.Diagnostics
open FSharp.Compiler.Tokenization.FSharpKeywords
[]
-type internal FSharpRenameParamToMatchSignature [] () =
+type internal RenameParamToMatchSignatureCodeFixProvider [] () =
inherit CodeFixProvider()
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs b/vsintegration/src/FSharp.Editor/CodeFixes/RenameUnusedValue.fs
similarity index 96%
rename from vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/RenameUnusedValue.fs
index 63f8c0af545..b3afac2ae0f 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/RenameUnusedValue.fs
@@ -11,11 +11,7 @@ open System.Collections.Immutable
open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
-open Microsoft.CodeAnalysis.CodeActions
-open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics
-open FSharp.Compiler
-open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.Symbols
open FSharp.Compiler.Syntax
@@ -46,7 +42,7 @@ module UnusedCodeFixHelper =
async { return None }
[]
-type internal FSharpPrefixUnusedValueWithUnderscoreCodeFixProvider [] () =
+type internal PrefixUnusedValueWithUnderscoreCodeFixProvider [] () =
inherit CodeFixProvider()
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs b/vsintegration/src/FSharp.Editor/CodeFixes/ReplaceWithSuggestion.fs
similarity index 93%
rename from vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/ReplaceWithSuggestion.fs
index 7b82bcf3ed3..d3a4c3adeab 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/ReplaceWithSuggestion.fs
@@ -13,10 +13,9 @@ open FSharp.Compiler.Diagnostics
open FSharp.Compiler.EditorServices
open FSharp.Compiler.Syntax
open FSharp.Compiler.Text
-open FSharp.Compiler.Tokenization
[]
-type internal FSharpReplaceWithSuggestionCodeFixProvider [] (settings: EditorOptions) =
+type internal ReplaceWithSuggestionCodeFixProvider [] (settings: EditorOptions) =
inherit CodeFixProvider()
override _.FixableDiagnosticIds = ImmutableArray.Create("FS0039", "FS1129", "FS0495")
@@ -28,7 +27,7 @@ type internal FSharpReplaceWithSuggestionCodeFixProvider [
let document = context.Document
let! parseFileResults, checkFileResults =
- document.GetFSharpParseAndCheckResultsAsync(nameof (FSharpReplaceWithSuggestionCodeFixProvider))
+ document.GetFSharpParseAndCheckResultsAsync(nameof (ReplaceWithSuggestionCodeFixProvider))
|> liftAsync
// This is all needed to get a declaration list
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/SimplifyName.fs b/vsintegration/src/FSharp.Editor/CodeFixes/SimplifyName.fs
similarity index 93%
rename from vsintegration/src/FSharp.Editor/CodeFix/SimplifyName.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/SimplifyName.fs
index dae2e3095a5..0f31d9e68ab 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/SimplifyName.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/SimplifyName.fs
@@ -10,13 +10,10 @@ open System.Collections.Immutable
open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
-open Microsoft.CodeAnalysis.CodeActions
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics
-open FSharp.Compiler.Text
-
[]
-type internal FSharpSimplifyNameCodeFixProvider() =
+type internal SimplifyNameCodeFixProvider() =
inherit CodeFixProvider()
override _.FixableDiagnosticIds =
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/UseMutationWhenValueIsMutable.fs b/vsintegration/src/FSharp.Editor/CodeFixes/UseMutationWhenValueIsMutable.fs
similarity index 93%
rename from vsintegration/src/FSharp.Editor/CodeFix/UseMutationWhenValueIsMutable.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/UseMutationWhenValueIsMutable.fs
index 591de79e442..bf2735b043b 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/UseMutationWhenValueIsMutable.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/UseMutationWhenValueIsMutable.fs
@@ -14,7 +14,7 @@ open FSharp.Compiler.Symbols
open FSharp.Compiler.Text
[]
-type internal FSharpUseMutationWhenValueIsMutableFixProvider [] () =
+type internal UseMutationWhenValueIsMutableCodeFixProvider [] () =
inherit CodeFixProvider()
static let title = SR.UseMutationWhenValueIsMutable()
@@ -46,11 +46,11 @@ type internal FSharpUseMutationWhenValueIsMutableFixProvider [ liftAsync
let! symbolUse =
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/UseTripleQuotedInterpolation.fs b/vsintegration/src/FSharp.Editor/CodeFixes/UseTripleQuotedInterpolation.fs
similarity index 91%
rename from vsintegration/src/FSharp.Editor/CodeFix/UseTripleQuotedInterpolation.fs
rename to vsintegration/src/FSharp.Editor/CodeFixes/UseTripleQuotedInterpolation.fs
index 1f229f6e7a7..acd4de0b843 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/UseTripleQuotedInterpolation.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/UseTripleQuotedInterpolation.fs
@@ -9,7 +9,7 @@ open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
[]
-type internal FSharpUseTripleQuotedInterpolationCodeFixProvider [] () =
+type internal UseTripleQuotedInterpolationCodeFixProvider [] () =
inherit CodeFixProvider()
static let title = SR.UseTripleQuotedInterpolation()
@@ -18,7 +18,7 @@ type internal FSharpUseTripleQuotedInterpolationCodeFixProvider [ liftAsync
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/WrapExpressionInParentheses.fs b/vsintegration/src/FSharp.Editor/CodeFixes/WrapExpressionInParentheses.fs
new file mode 100644
index 00000000000..39a247263c3
--- /dev/null
+++ b/vsintegration/src/FSharp.Editor/CodeFixes/WrapExpressionInParentheses.fs
@@ -0,0 +1,36 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.FSharp.Editor
+
+open System.Composition
+open System.Collections.Immutable
+
+open Microsoft.CodeAnalysis.CodeFixes
+open Microsoft.CodeAnalysis.Text
+
+open CancellableTasks
+
+[]
+type internal WrapExpressionInParenthesesCodeFixProvider() =
+ inherit CodeFixProvider()
+
+ static let title = SR.WrapExpressionInParentheses()
+
+ override _.FixableDiagnosticIds = ImmutableArray.Create("FS0597")
+
+ override this.RegisterCodeFixesAsync context = context.RegisterFsharpFix(this)
+
+ interface IFSharpCodeFixProvider with
+ member _.GetCodeFixIfAppliesAsync _ span =
+ let codeFix =
+ {
+ Name = CodeFix.AddParentheses
+ Message = title
+ Changes =
+ [
+ TextChange(TextSpan(span.Start, 0), "(")
+ TextChange(TextSpan(span.End, 0), ")")
+ ]
+ }
+
+ CancellableTask.singleton (Some codeFix)
diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
index a2673c2d559..d50ba5d9b6a 100644
--- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
+++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
@@ -101,40 +101,40 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddInstanceMemberParameterTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddInstanceMemberParameterTests.fs
index 1fbd6b4a39d..b47462f7be6 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddInstanceMemberParameterTests.fs
+++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddInstanceMemberParameterTests.fs
@@ -7,7 +7,7 @@ open Xunit
open CodeFixTestFramework
-let private codeFix = FSharpAddInstanceMemberParameterCodeFixProvider()
+let private codeFix = AddInstanceMemberParameterCodeFixProvider()
let private diagnostic = 0673 // This instance member needs a parameter to represent the object being invoked...
[]
@@ -19,15 +19,16 @@ type UsefulTestHarness() =
"""
let expected =
- {
- Title = "Add missing instance member parameter"
- FixedCode =
- """
+ Some
+ {
+ Message = "Add missing instance member parameter"
+ FixedCode =
+ """
type UsefulTestHarness() =
member x.FortyTwo = 42
"""
- }
+ }
- let actual = codeFix |> fix code diagnostic
+ let actual = codeFix |> tryFix code diagnostic
Assert.Equal(expected, actual)
diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddMissingRecToMutuallyRecFunctionsTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddMissingRecToMutuallyRecFunctionsTests.fs
new file mode 100644
index 00000000000..a3d1bc3d526
--- /dev/null
+++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddMissingRecToMutuallyRecFunctionsTests.fs
@@ -0,0 +1,50 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+module FSharp.Editor.Tests.CodeFixes.AddMissingRecToMutuallyRecFunctionsTests
+
+open Microsoft.VisualStudio.FSharp.Editor
+open Xunit
+
+open CodeFixTestFramework
+
+let private codeFix = AddMissingRecToMutuallyRecFunctionsCodeFixProvider()
+let private diagnostic = 0576 // The declaration form 'let ... and ...' for non-recursive bindings is not used in F# code...
+
+// TODO: write some negative test cases here
+
+[]
+let ``Fixes FS0576`` () =
+ let code =
+ """
+let isEven n =
+ match n with
+ | 0 -> true
+ | _ -> isOdd (n - 1)
+
+and isOdd n =
+ match n with
+ | 0 -> false
+ | _ -> isEven (n - 1)
+"""
+
+ let expected =
+ Some
+ {
+ Message = "Make 'isEven' recursive"
+ FixedCode =
+ """
+let rec isEven n =
+ match n with
+ | 0 -> true
+ | _ -> isOdd (n - 1)
+
+and isOdd n =
+ match n with
+ | 0 -> false
+ | _ -> isEven (n - 1)
+"""
+ }
+
+ let actual = codeFix |> tryFix code diagnostic
+
+ Assert.Equal(expected, actual)
diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/ChangeToUpcastTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/ChangeToUpcastTests.fs
index 9b0ead993d7..e2a1522e84f 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/ChangeToUpcastTests.fs
+++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/ChangeToUpcastTests.fs
@@ -7,7 +7,7 @@ open Xunit
open CodeFixTestFramework
-let private codeFix = FSharpChangeToUpcastCodeFixProvider()
+let private codeFix = ChangeToUpcastCodeFixProvider()
let private diagnostic = 3198 // The conversion is an upcast, not a downcast...
// Test cases are taken from the original PR:
@@ -24,18 +24,19 @@ let Thing : IFoo = Foo() :?> IFoo
"""
let expected =
- {
- Title = "Use ':>' operator"
- FixedCode =
- """
+ Some
+ {
+ Message = "Use ':>' operator"
+ FixedCode =
+ """
type IFoo = abstract member Bar : unit -> unit
type Foo() = interface IFoo with member __.Bar () = ()
let Thing : IFoo = Foo() :> IFoo
"""
- }
+ }
- let actual = codeFix |> fix code diagnostic
+ let actual = codeFix |> tryFix code diagnostic
Assert.Equal(expected, actual)
@@ -50,17 +51,35 @@ let Thing : IFoo = downcast Foo()
"""
let expected =
- {
- Title = "Use 'upcast'"
- FixedCode =
- """
+ Some
+ {
+ Message = "Use 'upcast'"
+ FixedCode =
+ """
type IFoo = abstract member Bar : unit -> unit
type Foo() = interface IFoo with member __.Bar () = ()
let Thing : IFoo = upcast Foo()
"""
- }
+ }
- let actual = codeFix |> fix code diagnostic
+ let actual = codeFix |> tryFix code diagnostic
+
+ Assert.Equal(expected, actual)
+
+[]
+// TODO: that's a weird thing, we should rather rewrite the code of the code fix
+let ``Doesn't fix FS3198 when both`` () =
+ let code =
+ """
+type IdowncastFoo = abstract member Bar : unit -> unit
+type Foo() = interface IdowncastFoo with member __.Bar () = ()
+
+let Thing : IdowncastFoo = Foo() :?> IdowncastFoo
+"""
+
+ let expected = None
+
+ let actual = codeFix |> tryFix code diagnostic
Assert.Equal(expected, actual)
diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/CodeFixTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/CodeFixTestFramework.fs
index 04998935ea8..616bc907fe5 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/CodeFixTestFramework.fs
+++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/CodeFixTestFramework.fs
@@ -11,7 +11,7 @@ open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks
open FSharp.Editor.Tests.Helpers
-type TestCodeFix = { Title: string; FixedCode: string }
+type TestCodeFix = { Message: string; FixedCode: string }
let getRelevantDiagnostic (document: Document) errorNumber =
cancellableTask {
@@ -23,7 +23,7 @@ let getRelevantDiagnostic (document: Document) errorNumber =
|> Seq.exactlyOne
}
-let fix (code: string) diagnostic (fixProvider: IFSharpCodeFix) =
+let tryFix (code: string) diagnostic (fixProvider: IFSharpCodeFixProvider) =
cancellableTask {
let sourceText = SourceText.From code
let document = RoslynTestHelpers.GetFsDocument code
@@ -33,14 +33,15 @@ let fix (code: string) diagnostic (fixProvider: IFSharpCodeFix) =
let diagnosticSpan =
RoslynHelpers.FSharpRangeToTextSpan(sourceText, diagnostic.Range)
- let! title, changes = fixProvider.GetChangesAsync document diagnosticSpan
- let fixedSourceText = sourceText.WithChanges changes
+ let! result = fixProvider.GetCodeFixIfAppliesAsync document diagnosticSpan
return
- {
- Title = title
- FixedCode = fixedSourceText.ToString()
- }
+ (result
+ |> Option.map (fun codeFix ->
+ {
+ Message = codeFix.Message
+ FixedCode = (sourceText.WithChanges codeFix.Changes).ToString()
+ }))
}
|> CancellableTask.start CancellationToken.None
|> fun task -> task.Result
diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/ConvertToAnonymousRecordTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/ConvertToAnonymousRecordTests.fs
index 9f8008356bb..55af0a5e040 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/ConvertToAnonymousRecordTests.fs
+++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/ConvertToAnonymousRecordTests.fs
@@ -7,25 +7,39 @@ open Xunit
open CodeFixTestFramework
-let private codeFix = FSharpConvertToAnonymousRecordCodeFixProvider()
-let private diagnostic = 0039 // The record label is not defined...
+let private codeFix = ConvertToAnonymousRecordCodeFixProvider()
+let private diagnostic = 0039 // ... is not defined...
[]
-let ``Fixes FS0039`` () =
+let ``Fixes FS0039 for records`` () =
let code =
"""
let band = { Name = "The Velvet Underground" }
"""
let expected =
- {
- Title = "Convert to Anonymous Record"
- FixedCode =
- """
+ Some
+ {
+ Message = "Convert to Anonymous Record"
+ FixedCode =
+ """
let band = {| Name = "The Velvet Underground" |}
"""
- }
+ }
- let actual = codeFix |> fix code diagnostic
+ let actual = codeFix |> tryFix code diagnostic
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Doesn't fix FS0039 for random undefined identifiers`` () =
+ let code =
+ """
+let x = someUndefinedFunction 42
+"""
+
+ let expected = None
+
+ let actual = codeFix |> tryFix code diagnostic
Assert.Equal(expected, actual)
diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveReturnOrYieldTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveReturnOrYieldTests.fs
new file mode 100644
index 00000000000..a4eaf01e268
--- /dev/null
+++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveReturnOrYieldTests.fs
@@ -0,0 +1,106 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+module FSharp.Editor.Tests.CodeFixes.RemoveReturnOrYieldTests
+
+open Microsoft.VisualStudio.FSharp.Editor
+open Xunit
+
+open CodeFixTestFramework
+
+let private codeFix = RemoveReturnOrYieldCodeFixProvider()
+let private yieldDiagnostic = 0747 // This construct may only be used within list, array and sequence expressions...
+let private returnDiagnostic = 0748 // This construct may only be used with computation expressions...
+
+// TODO: write some negative tests here
+
+[]
+let ``Fixes FS0747 - yield`` () =
+ let code =
+ """
+let answer question =
+ yield 42
+"""
+
+ let expected =
+ Some
+ {
+ Message = "Remove 'yield'"
+ FixedCode =
+ """
+let answer question =
+ 42
+"""
+ }
+
+ let actual = codeFix |> tryFix code yieldDiagnostic
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Fixes FS0747 - yield!`` () =
+ let code =
+ """
+let answer question =
+ yield! 42
+"""
+
+ let expected =
+ Some
+ {
+ Message = "Remove 'yield!'"
+ FixedCode =
+ """
+let answer question =
+ 42
+"""
+ }
+
+ let actual = codeFix |> tryFix code yieldDiagnostic
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Fixes FS0748 - return`` () =
+ let code =
+ """
+let answer question =
+ return 42
+"""
+
+ let expected =
+ Some
+ {
+ Message = "Remove 'return'"
+ FixedCode =
+ """
+let answer question =
+ 42
+"""
+ }
+
+ let actual = codeFix |> tryFix code returnDiagnostic
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Fixes FS0748 - return!`` () =
+ let code =
+ """
+let answer question =
+ return! 42
+"""
+
+ let expected =
+ Some
+ {
+ Message = "Remove 'return!'"
+ FixedCode =
+ """
+let answer question =
+ 42
+"""
+ }
+
+ let actual = codeFix |> tryFix code returnDiagnostic
+
+ Assert.Equal(expected, actual)
diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/WrapExpressionInParenthesesTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/WrapExpressionInParenthesesTests.fs
new file mode 100644
index 00000000000..bd22ca56966
--- /dev/null
+++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/WrapExpressionInParenthesesTests.fs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+module FSharp.Editor.Tests.CodeFixes.FSharpWrapExpressionInParenthesesFixProviderTests
+
+open Microsoft.VisualStudio.FSharp.Editor
+open Xunit
+
+open CodeFixTestFramework
+
+let private codeFix = WrapExpressionInParenthesesCodeFixProvider()
+let private diagnostic = 0597 // ... arguments involving function or method applications should be parenthesized
+
+// Test case is taken from the original PR:
+// https://github.com/dotnet/fsharp/pull/10460
+
+[]
+let ``Fixes FS0597`` () =
+ let code =
+ """
+let rng = System.Random()
+
+printfn "Hello %d" rng.Next(5)
+"""
+
+ let expected =
+ Some
+ {
+ Message = "Wrap expression in parentheses"
+ FixedCode =
+ """
+let rng = System.Random()
+
+printfn "Hello %d" (rng.Next(5))
+"""
+ }
+
+ let actual = codeFix |> tryFix code diagnostic
+
+ Assert.Equal(expected, actual)
diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj
index 232e394455c..a943a2932cb 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj
+++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj
@@ -36,6 +36,9 @@
+
+
+
diff --git a/vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs b/vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs
index 3fed33dc983..7d92ec6715c 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs
+++ b/vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs
@@ -347,3 +347,19 @@ type RoslynTestHelpers private () =
RoslynTestHelpers.CreateSolution(code, options = options)
|> RoslynTestHelpers.GetSingleDocument
+
+ static member GetFsiAndFsDocuments (fsiCode: string) (fsCode: string) =
+ let projectId = ProjectId.CreateNewId()
+ let projFilePath = "C:\\test.fsproj"
+
+ let fsiDocInfo =
+ RoslynTestHelpers.CreateDocumentInfo projectId "C:\\test.fsi" fsiCode
+
+ let fsDocInfo = RoslynTestHelpers.CreateDocumentInfo projectId "C:\\test.fs" fsCode
+
+ let projInfo =
+ RoslynTestHelpers.CreateProjectInfo projectId projFilePath [ fsiDocInfo; fsDocInfo ]
+
+ let solution = RoslynTestHelpers.CreateSolution [ projInfo ]
+ let project = solution.Projects |> Seq.exactlyOne
+ project.Documents
diff --git a/vsintegration/tests/FSharp.Editor.Tests/Hints/HintTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Hints/HintTestFramework.fs
index d252d678d2f..1ea7b95f79f 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/Hints/HintTestFramework.fs
+++ b/vsintegration/tests/FSharp.Editor.Tests/Hints/HintTestFramework.fs
@@ -35,32 +35,6 @@ module HintTestFramework =
Tooltip = tooltip
}
- let getFsDocument code =
- // I don't know, without this lib some symbols are just not loaded
- let options =
- { RoslynTestHelpers.DefaultProjectOptions with
- OtherOptions = [| "--targetprofile:netcore" |]
- }
-
- RoslynTestHelpers.CreateSolution(code, options = options)
- |> RoslynTestHelpers.GetSingleDocument
-
- let getFsiAndFsDocuments (fsiCode: string) (fsCode: string) =
- let projectId = ProjectId.CreateNewId()
- let projFilePath = "C:\\test.fsproj"
-
- let fsiDocInfo =
- RoslynTestHelpers.CreateDocumentInfo projectId "C:\\test.fsi" fsiCode
-
- let fsDocInfo = RoslynTestHelpers.CreateDocumentInfo projectId "C:\\test.fs" fsCode
-
- let projInfo =
- RoslynTestHelpers.CreateProjectInfo projectId projFilePath [ fsiDocInfo; fsDocInfo ]
-
- let solution = RoslynTestHelpers.CreateSolution [ projInfo ]
- let project = solution.Projects |> Seq.exactlyOne
- project.Documents
-
let getHints (document: Document) hintKinds =
let task =
cancellableTask {
diff --git a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineParameterNameHintTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineParameterNameHintTests.fs
index c1cf532607a..512d16f1089 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineParameterNameHintTests.fs
+++ b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineParameterNameHintTests.fs
@@ -1,125 +1,126 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-namespace FSharp.Editor.Tests.Hints
+module FSharp.Editor.Tests.Hints.InlineParameterNameHintTests
open Xunit
-open HintTestFramework
+
+open FSharp.Editor.Tests.Helpers
open FSharp.Test
-module InlineParameterNameHintTests =
+open HintTestFramework
- []
- let ``Hint is shown for a let binding`` () =
- let code =
- """
+[]
+let ``Hint is shown for a let binding`` () =
+ let code =
+ """
let greet friend = $"hello {friend}"
let greeting = greet "darkness"
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let expected =
- [
- {
- Content = "friend = "
- Location = (2, 22)
- Tooltip = "parameter friend"
- }
- ]
+ let expected =
+ [
+ {
+ Content = "friend = "
+ Location = (2, 22)
+ Tooltip = "parameter friend"
+ }
+ ]
- let actual = getParameterNameHints document
+ let actual = getParameterNameHints document
- Assert.Equal(expected, actual)
+ Assert.Equal(expected, actual)
- []
- let ``Hints are shown for multiple function calls`` () =
- let code =
- """
+[]
+let ``Hints are shown for multiple function calls`` () =
+ let code =
+ """
let greet friend = $"hello {friend}"
let greeting1 = greet "Noel"
let greeting2 = greet "Liam"
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = "friend = "
- Location = (2, 23)
- Tooltip = "parameter friend"
- }
- {
- Content = "friend = "
- Location = (3, 23)
- Tooltip = "parameter friend"
- }
- ]
-
- let actual = getParameterNameHints document
-
- Assert.Equal(expected, actual)
-
- []
- let ``Hints are shown for multiple parameters`` () =
- let code =
- """
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = "friend = "
+ Location = (2, 23)
+ Tooltip = "parameter friend"
+ }
+ {
+ Content = "friend = "
+ Location = (3, 23)
+ Tooltip = "parameter friend"
+ }
+ ]
+
+ let actual = getParameterNameHints document
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Hints are shown for multiple parameters`` () =
+ let code =
+ """
let greet friend1 friend2 = $"hello {friend1} and {friend2}"
let greeting = greet "Liam" "Noel"
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = "friend1 = "
- Location = (2, 22)
- Tooltip = "parameter friend1"
- }
- {
- Content = "friend2 = "
- Location = (2, 29)
- Tooltip = "parameter friend2"
- }
- ]
-
- let actual = getParameterNameHints document
-
- Assert.Equal(expected, actual)
-
- []
- let ``Hints are shown for tuple items`` () =
- let code =
- """
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = "friend1 = "
+ Location = (2, 22)
+ Tooltip = "parameter friend1"
+ }
+ {
+ Content = "friend2 = "
+ Location = (2, 29)
+ Tooltip = "parameter friend2"
+ }
+ ]
+
+ let actual = getParameterNameHints document
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Hints are shown for tuple items`` () =
+ let code =
+ """
let greet (friend1, friend2) = $"hello {friend1} and {friend2}"
let greeting = greet ("Liam", "Noel")
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = "friend1 = "
- Location = (2, 23)
- Tooltip = "parameter friend1"
- }
- {
- Content = "friend2 = "
- Location = (2, 31)
- Tooltip = "parameter friend2"
- }
- ]
-
- let actual = getParameterNameHints document
-
- Assert.Equal(expected, actual)
-
- []
- let ``Hints are shown for active patterns`` () =
- let code =
- """
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = "friend1 = "
+ Location = (2, 23)
+ Tooltip = "parameter friend1"
+ }
+ {
+ Content = "friend2 = "
+ Location = (2, 31)
+ Tooltip = "parameter friend2"
+ }
+ ]
+
+ let actual = getParameterNameHints document
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Hints are shown for active patterns`` () =
+ let code =
+ """
let (|Even|Odd|) n =
if n % 2 = 0 then Even
else Odd
@@ -133,96 +134,96 @@ let even = evenOrOdd 42
let odd = evenOrOdd 41
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = "number = "
- Location = (10, 22)
- Tooltip = "parameter number"
- }
- {
- Content = "number = "
- Location = (11, 21)
- Tooltip = "parameter number"
- }
- ]
-
- let actual = getParameterNameHints document
-
- Assert.Equal(expected, actual)
-
- [] // here we don't want an empty hint before "x"
- let ``Hints are not shown for nameless parameters`` () =
- let code =
- """
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = "number = "
+ Location = (10, 22)
+ Tooltip = "parameter number"
+ }
+ {
+ Content = "number = "
+ Location = (11, 21)
+ Tooltip = "parameter number"
+ }
+ ]
+
+ let actual = getParameterNameHints document
+
+ Assert.Equal(expected, actual)
+
+[] // here we don't want an empty hint before "x"
+let ``Hints are not shown for nameless parameters`` () =
+ let code =
+ """
let exists predicate option =
match option with
| None -> false
| Some x -> predicate x
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getParameterNameHints document
+ let result = getParameterNameHints document
- Assert.Empty(result)
+ Assert.Empty(result)
- [] // here we don't want a useless (?) hint "value = "
- let ``Hints are not shown for parameters of built-in operators`` () =
- let code =
- """
+[] // here we don't want a useless (?) hint "value = "
+let ``Hints are not shown for parameters of built-in operators`` () =
+ let code =
+ """
let postTrue = not true
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getParameterNameHints document
+ let result = getParameterNameHints document
- Assert.Empty(result)
+ Assert.Empty(result)
- []
- let ``Hints are not shown for parameters of custom operators`` () =
- let code =
- """
+[]
+let ``Hints are not shown for parameters of custom operators`` () =
+ let code =
+ """
let (===) value1 value2 = value1 = value2
let c = "javascript" === "javascript"
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getParameterNameHints document
+ let result = getParameterNameHints document
- Assert.Empty(result)
+ Assert.Empty(result)
- []
- let ``Hints are shown for method parameters`` () =
- let code =
- """
+[]
+let ``Hints are shown for method parameters`` () =
+ let code =
+ """
let theAnswer = System.Console.WriteLine 42
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let expected =
- [
- {
- Content = "value = "
- Location = (1, 42)
- Tooltip = "parameter value"
- }
- ]
+ let expected =
+ [
+ {
+ Content = "value = "
+ Location = (1, 42)
+ Tooltip = "parameter value"
+ }
+ ]
- let actual = getParameterNameHints document
+ let actual = getParameterNameHints document
- Assert.Equal(expected, actual)
+ Assert.Equal(expected, actual)
- []
- let ``Hints are shown for parameters of overloaded and curried methods`` () =
- let code =
- """
+[]
+let ``Hints are shown for parameters of overloaded and curried methods`` () =
+ let code =
+ """
type C () =
member _.Normal (alone: string) = 1
member _.Normal (what: string, what2: int) = 1
@@ -235,85 +236,85 @@ let a = c.Normal ("hmm", 2)
let a = c.Normal "hmm"
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = "curr1 = "
- Location = (8, 20)
- Tooltip = "parameter curr1"
- }
- {
- Content = "curr2 = "
- Location = (8, 27)
- Tooltip = "parameter curr2"
- }
- {
- Content = "x = "
- Location = (8, 30)
- Tooltip = "parameter x"
- }
- {
- Content = "what = "
- Location = (9, 19)
- Tooltip = "parameter what"
- }
- {
- Content = "what2 = "
- Location = (9, 26)
- Tooltip = "parameter what2"
- }
- {
- Content = "alone = "
- Location = (10, 18)
- Tooltip = "parameter alone"
- }
- ]
-
- let actual = getParameterNameHints document
-
- Assert.Equal(expected, actual)
-
- []
- let ``Hints are shown for constructor parameters`` () =
- let code =
- """
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = "curr1 = "
+ Location = (8, 20)
+ Tooltip = "parameter curr1"
+ }
+ {
+ Content = "curr2 = "
+ Location = (8, 27)
+ Tooltip = "parameter curr2"
+ }
+ {
+ Content = "x = "
+ Location = (8, 30)
+ Tooltip = "parameter x"
+ }
+ {
+ Content = "what = "
+ Location = (9, 19)
+ Tooltip = "parameter what"
+ }
+ {
+ Content = "what2 = "
+ Location = (9, 26)
+ Tooltip = "parameter what2"
+ }
+ {
+ Content = "alone = "
+ Location = (10, 18)
+ Tooltip = "parameter alone"
+ }
+ ]
+
+ let actual = getParameterNameHints document
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Hints are shown for constructor parameters`` () =
+ let code =
+ """
type C (blahFirst: int) =
new (blah: int, blah2: string) = C blah
let a = C (1, "")
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = "blahFirst = "
- Location = (2, 40)
- Tooltip = "parameter blahFirst"
- }
- {
- Content = "blah = "
- Location = (4, 12)
- Tooltip = "parameter blah"
- }
- {
- Content = "blah2 = "
- Location = (4, 15)
- Tooltip = "parameter blah2"
- }
- ]
-
- let actual = getParameterNameHints document
-
- Assert.Equal(expected, actual)
-
- []
- let ``Hints are shown for discriminated union case fields with explicit names`` () =
- let code =
- """
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = "blahFirst = "
+ Location = (2, 40)
+ Tooltip = "parameter blahFirst"
+ }
+ {
+ Content = "blah = "
+ Location = (4, 12)
+ Tooltip = "parameter blah"
+ }
+ {
+ Content = "blah2 = "
+ Location = (4, 15)
+ Tooltip = "parameter blah2"
+ }
+ ]
+
+ let actual = getParameterNameHints document
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Hints are shown for discriminated union case fields with explicit names`` () =
+ let code =
+ """
type Shape =
| Square of side: int
| Rectangle of width: int * height: int
@@ -322,35 +323,35 @@ let a = Square 1
let b = Rectangle (1, 2)
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = "side = "
- Location = (5, 16)
- Tooltip = "field side"
- }
- {
- Content = "width = "
- Location = (6, 20)
- Tooltip = "field width"
- }
- {
- Content = "height = "
- Location = (6, 23)
- Tooltip = "field height"
- }
- ]
-
- let actual = getParameterNameHints document
-
- Assert.Equal(expected, actual)
-
- []
- let ``Hints are not shown for discriminated union case fields with the same names as arguements`` () =
- let code =
- """
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = "side = "
+ Location = (5, 16)
+ Tooltip = "field side"
+ }
+ {
+ Content = "width = "
+ Location = (6, 20)
+ Tooltip = "field width"
+ }
+ {
+ Content = "height = "
+ Location = (6, 23)
+ Tooltip = "field height"
+ }
+ ]
+
+ let actual = getParameterNameHints document
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Hints are not shown for discriminated union case fields with the same names as arguements`` () =
+ let code =
+ """
type Shape =
| Square of side: int
| Rectangle of width: int * height: int
@@ -360,30 +361,30 @@ let a = Square 1
let b = Rectangle (width, 2)
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = "side = "
- Location = (6, 16)
- Tooltip = "field side"
- }
- {
- Content = "height = "
- Location = (7, 27)
- Tooltip = "field height"
- }
- ]
-
- let actual = getParameterNameHints document
-
- Assert.Equal(expected, actual)
-
- []
- let ``Hints for discriminated union case fields are not shown when names are generated`` () =
- let code =
- """
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = "side = "
+ Location = (6, 16)
+ Tooltip = "field side"
+ }
+ {
+ Content = "height = "
+ Location = (7, 27)
+ Tooltip = "field height"
+ }
+ ]
+
+ let actual = getParameterNameHints document
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Hints for discriminated union case fields are not shown when names are generated`` () =
+ let code =
+ """
type Shape =
| Triangle of side1: int * int * side3: int
| Circle of int
@@ -392,30 +393,30 @@ let c = Triangle (1, 2, 3)
let d = Circle 1
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = "side1 = "
- Location = (5, 19)
- Tooltip = "field side1"
- }
- {
- Content = "side3 = "
- Location = (5, 25)
- Tooltip = "field side3"
- }
- ]
-
- let actual = getParameterNameHints document
-
- Assert.Equal(expected, actual)
-
- []
- let ``Hints for discriminated union case fields are not shown when provided arguments don't match the expected count`` () =
- let code =
- """
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = "side1 = "
+ Location = (5, 19)
+ Tooltip = "field side1"
+ }
+ {
+ Content = "side3 = "
+ Location = (5, 25)
+ Tooltip = "field side3"
+ }
+ ]
+
+ let actual = getParameterNameHints document
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Hints for discriminated union case fields are not shown when provided arguments don't match the expected count`` () =
+ let code =
+ """
type Shape =
| Triangle of side1: int * side2: int * side3: int
| Circle of int
@@ -423,57 +424,57 @@ type Shape =
let c = Triangle (1, 2)
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let actual = getParameterNameHints document
+ let actual = getParameterNameHints document
- Assert.Empty(actual)
+ Assert.Empty(actual)
- []
- let ``Hints for discriminated union case fields are not shown for Cons`` () =
- let code =
- """
+[]
+let ``Hints for discriminated union case fields are not shown for Cons`` () =
+ let code =
+ """
type X =
member _.Test() = 42 :: [42; 42]
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let actual = getParameterNameHints document
+ let actual = getParameterNameHints document
- Assert.Empty(actual)
+ Assert.Empty(actual)
- []
- let ``Hints are not shown in front of indexes`` () =
- let code =
- """
+[]
+let ``Hints are not shown in front of indexes`` () =
+ let code =
+ """
let x = "test".Split("").[0].Split("");
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = "separator = "
- Location = (1, 22)
- Tooltip = "parameter separator"
- }
- {
- Content = "separator = "
- Location = (1, 36)
- Tooltip = "parameter separator"
- }
- ]
-
- let actual = getParameterNameHints document
-
- Assert.Equal(expected, actual)
-
- []
- let ``Hints are not shown for optional parameters with specified names`` () =
- let code =
- """
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = "separator = "
+ Location = (1, 22)
+ Tooltip = "parameter separator"
+ }
+ {
+ Content = "separator = "
+ Location = (1, 36)
+ Tooltip = "parameter separator"
+ }
+ ]
+
+ let actual = getParameterNameHints document
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Hints are not shown for optional parameters with specified names`` () =
+ let code =
+ """
type MyType() =
member _.MyMethod(?beep: int, ?bap: int, ?boop: int) = ()
@@ -481,25 +482,25 @@ type MyType() =
member this.Foo = this.MyMethod(3, boop = 4)
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let expected =
- [
- {
- Content = "beep = "
- Location = (5, 37)
- Tooltip = "parameter beep"
- }
- ]
+ let expected =
+ [
+ {
+ Content = "beep = "
+ Location = (5, 37)
+ Tooltip = "parameter beep"
+ }
+ ]
- let actual = getParameterNameHints document
+ let actual = getParameterNameHints document
- Assert.Equal(expected, actual)
+ Assert.Equal(expected, actual)
- []
- let ``Hints are not shown when all optional parameters are named`` () =
- let code =
- """
+[]
+let ``Hints are not shown when all optional parameters are named`` () =
+ let code =
+ """
type MyType() =
member _.MyMethod(?beep: int, ?bap : int, ?boop : int) = ()
@@ -507,85 +508,85 @@ type MyType() =
member this.Foo = this.MyMethod(bap = 3, beep = 4)
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let actual = getParameterNameHints document
+ let actual = getParameterNameHints document
- Assert.Empty(actual)
+ Assert.Empty(actual)
- []
- let ``Hints are shown correctly for inner bindings`` () =
- let code =
- """
+[]
+let ``Hints are shown correctly for inner bindings`` () =
+ let code =
+ """
let test sequences =
sequences
|> Seq.map (fun sequence -> sequence |> Seq.map (fun sequence' -> sequence' |> Seq.map (fun item -> item)))
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = "mapping = "
- Location = (3, 16)
- Tooltip = "parameter mapping"
- }
- {
- Content = "mapping = "
- Location = (3, 53)
- Tooltip = "parameter mapping"
- }
- {
- Content = "mapping = "
- Location = (3, 92)
- Tooltip = "parameter mapping"
- }
- ]
-
- let actual = getParameterNameHints document
-
- Assert.Equal(expected, actual)
-
- []
- let ``Hints are shown correctly for custom operations`` () =
- let code =
- """
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = "mapping = "
+ Location = (3, 16)
+ Tooltip = "parameter mapping"
+ }
+ {
+ Content = "mapping = "
+ Location = (3, 53)
+ Tooltip = "parameter mapping"
+ }
+ {
+ Content = "mapping = "
+ Location = (3, 92)
+ Tooltip = "parameter mapping"
+ }
+ ]
+
+ let actual = getParameterNameHints document
+
+ Assert.Equal(expected, actual)
+
+[]
+let ``Hints are shown correctly for custom operations`` () =
+ let code =
+ """
let q = query { for x in { 1 .. 10 } do select x }
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let expected =
- [
- {
- Content = "projection = "
- Location = (1, 48)
- Tooltip = "parameter projection"
- }
- ]
+ let expected =
+ [
+ {
+ Content = "projection = "
+ Location = (1, 48)
+ Tooltip = "parameter projection"
+ }
+ ]
- let actual = getParameterNameHints document
+ let actual = getParameterNameHints document
- Assert.Equal(expected, actual)
+ Assert.Equal(expected, actual)
- []
- let ``Hints are not shown for custom operations with only 1 parameter`` () =
- let code =
- """
+[]
+let ``Hints are not shown for custom operations with only 1 parameter`` () =
+ let code =
+ """
let q = query { for _ in { 1 .. 10 } do count }
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let actual = getParameterNameHints document
+ let actual = getParameterNameHints document
- Assert.Empty(actual)
+ Assert.Empty(actual)
- []
- let ``Hints are not shown when parameter names coincide with variable names`` () =
- let code =
- """
+[]
+let ``Hints are not shown when parameter names coincide with variable names`` () =
+ let code =
+ """
let getFullName name surname = $"{name} {surname}"
let name = "Robert"
@@ -593,25 +594,25 @@ let lastName = "Smith"
let fullName = getFullName name lastName
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let expected =
- [
- {
- Content = "surname = "
- Location = (5, 33)
- Tooltip = "parameter surname"
- }
- ]
+ let expected =
+ [
+ {
+ Content = "surname = "
+ Location = (5, 33)
+ Tooltip = "parameter surname"
+ }
+ ]
- let actual = getParameterNameHints document
+ let actual = getParameterNameHints document
- Assert.Equal(expected, actual)
+ Assert.Equal(expected, actual)
- []
- let ``Hints don't break with multi-line arguments`` () =
- let code =
- """
+[]
+let ``Hints don't break with multi-line arguments`` () =
+ let code =
+ """
None
|> Option.map (fun x ->
x + 5
@@ -619,56 +620,56 @@ None
|> ignore
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let expected =
- [
- {
- Content = "mapping = "
- Location = (2, 15)
- Tooltip = "parameter mapping"
- }
- ]
+ let expected =
+ [
+ {
+ Content = "mapping = "
+ Location = (2, 15)
+ Tooltip = "parameter mapping"
+ }
+ ]
- let actual = getParameterNameHints document
+ let actual = getParameterNameHints document
- Assert.Equal(expected, actual)
+ Assert.Equal(expected, actual)
- []
- let ``Hints are shown correctly in type constructors mixed with functions`` () =
- let code =
- """
+[]
+let ``Hints are shown correctly in type constructors mixed with functions`` () =
+ let code =
+ """
type X = | X of a: int list * b: string
let x = X(List.map id [ 42 ], "")
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = "a = "
- Location = (3, 11)
- Tooltip = "field a"
- }
- {
- Content = "mapping = "
- Location = (3, 20)
- Tooltip = "parameter mapping"
- }
- {
- Content = "list = "
- Location = (3, 23)
- Tooltip = "parameter list"
- }
- {
- Content = "b = "
- Location = (3, 31)
- Tooltip = "field b"
- }
- ]
-
- let actual = getParameterNameHints document
-
- actual |> Assert.shouldBeEquivalentTo expected
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = "a = "
+ Location = (3, 11)
+ Tooltip = "field a"
+ }
+ {
+ Content = "mapping = "
+ Location = (3, 20)
+ Tooltip = "parameter mapping"
+ }
+ {
+ Content = "list = "
+ Location = (3, 23)
+ Tooltip = "parameter list"
+ }
+ {
+ Content = "b = "
+ Location = (3, 31)
+ Tooltip = "field b"
+ }
+ ]
+
+ let actual = getParameterNameHints document
+
+ actual |> Assert.shouldBeEquivalentTo expected
diff --git a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineReturnTypeHintTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineReturnTypeHintTests.fs
index 5aad963721a..9e55e484f34 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineReturnTypeHintTests.fs
+++ b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineReturnTypeHintTests.fs
@@ -3,8 +3,11 @@
module FSharp.Editor.Tests.Hints.InlineReturnTypeHintTests
open Xunit
-open HintTestFramework
+
open FSharp.Test
+open FSharp.Editor.Tests.Helpers
+
+open HintTestFramework
[]
let ``Hints are shown for let-bound function return types`` () =
@@ -15,7 +18,7 @@ let func2 x = x + 1
let setConsoleOut = System.Console.SetOut
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
let result = getReturnTypeHints document
@@ -49,7 +52,7 @@ type Answer = { Text: string }
let getAnswer() = { Text = "42" }
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
let result = getReturnTypeHints document
@@ -72,7 +75,7 @@ type Test() =
member this.Func() = 3
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
let result = getReturnTypeHints document
@@ -91,7 +94,7 @@ type Test() =
let ``Hints are shown for generic functions`` () =
let code = "let func _a = 5"
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
let result = getReturnTypeHints document
@@ -114,7 +117,7 @@ let ``Hints are shown for functions within expressions`` () =
let func () = 2
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
let result = getReturnTypeHints document
@@ -133,7 +136,7 @@ let ``Hints are shown for functions within expressions`` () =
let ``Hints are not shown for lambda bindings`` () =
let code = "let func = fun () -> 3"
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
let result = getReturnTypeHints document
@@ -145,7 +148,7 @@ let ``Hints are not shown for lambda bindings`` () =
[ = [a]")>]
let ``Hints are not shown when there's type annotation`` code =
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
let result = getReturnTypeHints document
diff --git a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs
index f669e8bb800..01c108c7461 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs
+++ b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs
@@ -1,281 +1,280 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-namespace FSharp.Editor.Tests.Hints
+module FSharp.Editor.Tests.Hints.InlineTypeHintTests
open Xunit
open HintTestFramework
open FSharp.Test
+open FSharp.Editor.Tests.Helpers
-module InlineTypeHintTests =
-
- []
- let ``Hint is shown for a let binding`` () =
- let code =
- """
+[]
+let ``Hint is shown for a let binding`` () =
+ let code =
+ """
type Song = { Artist: string; Title: string }
let s = { Artist = "Moby"; Title = "Porcelain" }
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let expected =
- [
- {
- Content = ": Song"
- Location = (3, 6)
- Tooltip = "type Song"
- }
- ]
+ let expected =
+ [
+ {
+ Content = ": Song"
+ Location = (3, 6)
+ Tooltip = "type Song"
+ }
+ ]
- let actual = getTypeHints document
+ let actual = getTypeHints document
- Assert.Equal(expected, actual)
+ Assert.Equal(expected, actual)
- []
- let ``Hints are correct for builtin types`` () =
- let code =
- """
+[]
+let ``Hints are correct for builtin types`` () =
+ let code =
+ """
let songName = "Happy House"
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getTypeHints document
+ let result = getTypeHints document
- let expected =
- [
- {
- Content = ": string"
- Location = (1, 13)
- Tooltip = "type string"
- }
- ]
+ let expected =
+ [
+ {
+ Content = ": string"
+ Location = (1, 13)
+ Tooltip = "type string"
+ }
+ ]
- Assert.Equal(expected, result)
+ Assert.Equal(expected, result)
- []
- let ``Hint is shown for a parameter`` () =
- let code =
- """
+[]
+let ``Hint is shown for a parameter`` () =
+ let code =
+ """
type Song = { Artist: string; Title: string }
let whoSings s = s.Artist
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let expected =
- [
- {
- Content = ": Song"
- Location = (3, 15)
- Tooltip = "type Song"
- }
- ]
+ let expected =
+ [
+ {
+ Content = ": Song"
+ Location = (3, 15)
+ Tooltip = "type Song"
+ }
+ ]
- let actual = getTypeHints document
+ let actual = getTypeHints document
- Assert.Equal(expected, actual)
+ Assert.Equal(expected, actual)
- []
- let ``Hints are not shown in signature files`` () =
- let fsiCode =
- """
+[]
+let ``Hints are not shown in signature files`` () =
+ let fsiCode =
+ """
module Test
val numbers: int[]
"""
- let fsCode =
- """
+ let fsCode =
+ """
module Test
let numbers = [|42|]
"""
- let fsiDocument = getFsiAndFsDocuments fsiCode fsCode |> Seq.head
+ let fsiDocument = RoslynTestHelpers.GetFsiAndFsDocuments fsiCode fsCode |> Seq.head
- let result = getTypeHints fsiDocument
+ let result = getTypeHints fsiDocument
- Assert.Empty(result)
+ Assert.Empty(result)
- []
- let ``Hints are not shown for let-bound functions yet`` () =
- let code =
- """
+[]
+let ``Hints are not shown for let-bound functions yet`` () =
+ let code =
+ """
let setConsoleOut = System.Console.SetOut
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getTypeHints document
+ let result = getTypeHints document
- Assert.Empty(result)
+ Assert.Empty(result)
- []
- let ``Hint is not shown for a let binding when the type is manually specified`` () =
- let code =
- """
+[]
+let ``Hint is not shown for a let binding when the type is manually specified`` () =
+ let code =
+ """
type Song = { Artist: string; Title: string }
let s: Song = { Artist = "Moby"; Title = "Porcelain" }
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getTypeHints document
+ let result = getTypeHints document
- Assert.Empty(result)
+ Assert.Empty(result)
- []
- let ``Hint is not shown for a parameter when the type is manually specified`` () =
- let code =
- """
+[]
+let ``Hint is not shown for a parameter when the type is manually specified`` () =
+ let code =
+ """
type Song = { Artist: string; Title: string }
let whoSings (s: Song) = s.Artist
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getTypeHints document
+ let result = getTypeHints document
- Assert.Empty(result)
+ Assert.Empty(result)
- [] // here we don't want a hint after "this"
- let ``Hint is not shown for type self-identifiers`` () =
- let code =
- """
+[] // here we don't want a hint after "this"
+let ``Hint is not shown for type self-identifiers`` () =
+ let code =
+ """
type Song() =
member this.GetName() = "Porcelain"
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getTypeHints document
+ let result = getTypeHints document
- Assert.Empty(result)
+ Assert.Empty(result)
- [] // here we don't want a hint after "x"
- let ``Hint is not shown for type aliases`` () =
- let code =
- """
+[] // here we don't want a hint after "x"
+let ``Hint is not shown for type aliases`` () =
+ let code =
+ """
type Song() as x =
member this.Name = "Porcelain"
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getTypeHints document
+ let result = getTypeHints document
- Assert.Empty(result)
+ Assert.Empty(result)
- []
- let ``Hints are shown within lambdas`` () =
- let code =
- """
+[]
+let ``Hints are shown within lambdas`` () =
+ let code =
+ """
let iamboring() =
fun x -> x
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let expected =
- [
- {
- Content = ": 'a"
- Location = (2, 10)
- Tooltip = "type 'a"
- }
- ]
+ let expected =
+ [
+ {
+ Content = ": 'a"
+ Location = (2, 10)
+ Tooltip = "type 'a"
+ }
+ ]
- let actual = getTypeHints document
+ let actual = getTypeHints document
- Assert.Equal(expected, actual)
+ Assert.Equal(expected, actual)
- []
- let ``Hints are shown within lambdas with tuples`` () =
- let code =
- """
+[]
+let ``Hints are shown within lambdas with tuples`` () =
+ let code =
+ """
let zip4 (l1: 'a list) (l2: 'b list) (l3: 'c list) (l4: 'd list) =
List.zip l1 (List.zip3 l2 l3 l4)
|> List.map (fun (x1, (x2, x3, x4)) -> (x1, x2, x3, x4))
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = ": 'a"
- Location = (3, 25)
- Tooltip = "type 'a"
- }
- {
- Content = ": 'b"
- Location = (3, 30)
- Tooltip = "type 'b"
- }
- {
- Content = ": 'c"
- Location = (3, 34)
- Tooltip = "type 'c"
- }
- {
- Content = ": 'd"
- Location = (3, 38)
- Tooltip = "type 'd"
- }
- ]
-
- let actual = getTypeHints document
-
- actual |> Assert.shouldBeEquivalentTo expected
-
- []
- let ``Hints are not shown for lambda return types`` () =
- let code =
- """
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = ": 'a"
+ Location = (3, 25)
+ Tooltip = "type 'a"
+ }
+ {
+ Content = ": 'b"
+ Location = (3, 30)
+ Tooltip = "type 'b"
+ }
+ {
+ Content = ": 'c"
+ Location = (3, 34)
+ Tooltip = "type 'c"
+ }
+ {
+ Content = ": 'd"
+ Location = (3, 38)
+ Tooltip = "type 'd"
+ }
+ ]
+
+ let actual = getTypeHints document
+
+ actual |> Assert.shouldBeEquivalentTo expected
+
+[]
+let ``Hints are not shown for lambda return types`` () =
+ let code =
+ """
let func = fun () -> 3
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getTypeHints document
+ let result = getTypeHints document
- Assert.Empty(result)
+ Assert.Empty(result)
- []
- let ``Hints are not shown for unfinished expressions`` () =
- let code =
- """
+[]
+let ``Hints are not shown for unfinished expressions`` () =
+ let code =
+ """
let x
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getTypeHints document
+ let result = getTypeHints document
- Assert.Empty(result)
+ Assert.Empty(result)
- []
- let ``Hints are not shown for unsolved types in _for_ expressions in collections`` () =
- let code =
- """
+[]
+let ``Hints are not shown for unsolved types in _for_ expressions in collections`` () =
+ let code =
+ """
let _ = [ for x ]
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getTypeHints document
+ let result = getTypeHints document
- Assert.Empty(result)
+ Assert.Empty(result)
- []
- let ``Hints are not shown for unsolved types in _for_ expressions within computational expressions`` () =
- let code =
- """
+[]
+let ``Hints are not shown for unsolved types in _for_ expressions within computational expressions`` () =
+ let code =
+ """
do task {
for x
@@ -283,16 +282,16 @@ do task {
}
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getTypeHints document
+ let result = getTypeHints document
- Assert.Empty(result)
+ Assert.Empty(result)
- []
- let ``Hints are shown for IWSAM`` () =
- let code =
- """
+[]
+let ``Hints are shown for IWSAM`` () =
+ let code =
+ """
type IAddition<'T when 'T :> IAddition<'T>> =
static abstract op_Addition: 'T * 'T -> 'T
@@ -302,30 +301,30 @@ type Number<'T when IAddition<'T>>(value: 'T) =
static member op_Addition(a, b) = Number(a.Value + b.Value)
"""
- let document = getFsDocument code
-
- let expected =
- [
- {
- Content = ": Number<'T>"
- Location = (7, 36)
- Tooltip = "type Number`1"
- }
- {
- Content = ": Number<'T>"
- Location = (7, 39)
- Tooltip = "type Number`1"
- }
- ]
-
- let actual = getTypeHints document
-
- actual |> Assert.shouldBeEquivalentTo expected
-
- []
- let ``Hints are not shown when type is specified`` () =
- let code =
- """
+ let document = RoslynTestHelpers.GetFsDocument code
+
+ let expected =
+ [
+ {
+ Content = ": Number<'T>"
+ Location = (7, 36)
+ Tooltip = "type Number`1"
+ }
+ {
+ Content = ": Number<'T>"
+ Location = (7, 39)
+ Tooltip = "type Number`1"
+ }
+ ]
+
+ let actual = getTypeHints document
+
+ actual |> Assert.shouldBeEquivalentTo expected
+
+[]
+let ``Hints are not shown when type is specified`` () =
+ let code =
+ """
type MyType() =
member _.MyMethod(?beep: int, ?bap: int, ?boop: int) = ()
@@ -333,8 +332,8 @@ type MyType() =
member this.Foo = this.MyMethod(bap = 3, boop = 4)
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let result = getTypeHints document
+ let result = getTypeHints document
- Assert.Empty(result)
+ Assert.Empty(result)
diff --git a/vsintegration/tests/FSharp.Editor.Tests/Hints/OverallHintExperienceTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Hints/OverallHintExperienceTests.fs
index 195902a7878..196ac5e8ede 100644
--- a/vsintegration/tests/FSharp.Editor.Tests/Hints/OverallHintExperienceTests.fs
+++ b/vsintegration/tests/FSharp.Editor.Tests/Hints/OverallHintExperienceTests.fs
@@ -1,18 +1,20 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-namespace FSharp.Editor.Tests.Hints
+module FSharp.Editor.Tests.Hints.OverallHintExperienceTests
open Xunit
-open HintTestFramework
+
open FSharp.Test
+open FSharp.Editor.Tests.Helpers
+
+open HintTestFramework
// just some kind of higher level testing
-module OverallHintExperienceTests =
- []
- let ``Baseline hints`` () =
- let code =
- """
+[]
+let ``Baseline hints`` () =
+ let code =
+ """
type Song = { Artist: string; Title: string }
let whoSings song = song.Artist
@@ -32,82 +34,82 @@ let a = C 1
let cc = a.Normal "hmm"
"""
- let document = getFsDocument code
+ let document = RoslynTestHelpers.GetFsDocument code
- let expected =
- [
- {
- Content = ": Song"
- Location = (2, 18)
- Tooltip = "type Song"
- }
- {
- Content = ": string "
- Location = (2, 19)
- Tooltip = "type string"
- }
- {
- Content = "song = "
- Location = (4, 23)
- Tooltip = "parameter song"
- }
- {
- Content = ": string"
- Location = (4, 11)
- Tooltip = "type string"
- }
- {
- Content = "side = "
- Location = (10, 16)
- Tooltip = "field side"
- }
- {
- Content = ": Shape"
- Location = (10, 6)
- Tooltip = "type Shape"
- }
- {
- Content = "width = "
- Location = (11, 20)
- Tooltip = "field width"
- }
- {
- Content = "height = "
- Location = (11, 23)
- Tooltip = "field height"
- }
- {
- Content = ": Shape"
- Location = (11, 6)
- Tooltip = "type Shape"
- }
- {
- Content = ": int "
- Location = (14, 36)
- Tooltip = "type int"
- }
- {
- Content = "blahFirst = "
- Location = (16, 11)
- Tooltip = "parameter blahFirst"
- }
- {
- Content = ": C"
- Location = (16, 6)
- Tooltip = "type C"
- }
- {
- Content = "what = "
- Location = (17, 19)
- Tooltip = "parameter what"
- }
- {
- Content = ": int"
- Location = (17, 7)
- Tooltip = "type int"
- }
- ]
+ let expected =
+ [
+ {
+ Content = ": Song"
+ Location = (2, 18)
+ Tooltip = "type Song"
+ }
+ {
+ Content = ": string "
+ Location = (2, 19)
+ Tooltip = "type string"
+ }
+ {
+ Content = "song = "
+ Location = (4, 23)
+ Tooltip = "parameter song"
+ }
+ {
+ Content = ": string"
+ Location = (4, 11)
+ Tooltip = "type string"
+ }
+ {
+ Content = "side = "
+ Location = (10, 16)
+ Tooltip = "field side"
+ }
+ {
+ Content = ": Shape"
+ Location = (10, 6)
+ Tooltip = "type Shape"
+ }
+ {
+ Content = "width = "
+ Location = (11, 20)
+ Tooltip = "field width"
+ }
+ {
+ Content = "height = "
+ Location = (11, 23)
+ Tooltip = "field height"
+ }
+ {
+ Content = ": Shape"
+ Location = (11, 6)
+ Tooltip = "type Shape"
+ }
+ {
+ Content = ": int "
+ Location = (14, 36)
+ Tooltip = "type int"
+ }
+ {
+ Content = "blahFirst = "
+ Location = (16, 11)
+ Tooltip = "parameter blahFirst"
+ }
+ {
+ Content = ": C"
+ Location = (16, 6)
+ Tooltip = "type C"
+ }
+ {
+ Content = "what = "
+ Location = (17, 19)
+ Tooltip = "parameter what"
+ }
+ {
+ Content = ": int"
+ Location = (17, 7)
+ Tooltip = "type int"
+ }
+ ]
- let actual = getAllHints document
+ let actual = getAllHints document
- actual |> Assert.shouldBeEquivalentTo expected
+ actual |> Assert.shouldBeEquivalentTo expected