Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
523 changes: 266 additions & 257 deletions src/fsharp/vs/IncrementalBuild.fs

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/fsharp/vs/Reactor.fs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type Reactor() =
static let theReactor = Reactor()
let mutable pauseBeforeBackgroundWork = pauseBeforeBackgroundWorkDefault

// We need to store the culture for the VS thread that is executing now,
// We need to store the culture for the VS thread that is executing now,
// so that when the reactor picks up a thread from the threadpool we can set the culture
let culture = new CultureInfo(CultureInfo.CurrentUICulture.Name)

Expand Down Expand Up @@ -134,7 +134,7 @@ type Reactor() =
try
do! loop (None, None, false)
with e ->
Debug.Assert(false,String.Format("unexpected failure in reactor loop {0}, restarting", e))
Debug.Assert(false, String.Format("unexpected failure in reactor loop {0}, restarting", e))
}

// [Foreground Mailbox Accessors] -----------------------------------------------------------
Expand Down Expand Up @@ -172,7 +172,7 @@ type Reactor() =
async {
let! ct = Async.CancellationToken
let resultCell = AsyncUtil.AsyncResultCell<_>()
r.EnqueueOpPrim(userOpName, opName, opArg, ct,
r.EnqueueOpPrim(userOpName, opName, opArg, ct,
op=(fun ctok ->
let result =
try
Expand All @@ -181,7 +181,7 @@ type Reactor() =
| ValueOrCancelled.Cancelled e -> AsyncUtil.AsyncCanceled e
with e -> e |> AsyncUtil.AsyncException

resultCell.RegisterResult(result)),
resultCell.RegisterResult(result)),
ccont=(fun () -> resultCell.RegisterResult (AsyncUtil.AsyncCanceled(OperationCanceledException(ct))) )

)
Expand Down
37 changes: 34 additions & 3 deletions src/fsharp/vs/ServiceDeclarationLists.fs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,24 @@ module EnvMisc3 =


[<Sealed>]
/// Represents one parameter for one method (or other item) in a group.
type FSharpMethodGroupItemParameter(name: string, canonicalTypeTextForSorting: string, display: layout, isOptional: bool) =

/// The name of the parameter.
member __.ParameterName = name

/// A key that can be used for sorting the parameters, used to help sort overloads.
member __.CanonicalTypeTextForSorting = canonicalTypeTextForSorting

/// The structured representation for the parameter including its name, its type and visual indicators of other
/// information such as whether it is optional.
member __.StructuredDisplay = display

/// The text to display for the parameter including its name, its type and visual indicators of other
/// information such as whether it is optional.
member __.Display = showL display

/// Is the parameter optional
member __.IsOptional = isOptional

[<AutoOpen>]
Expand Down Expand Up @@ -688,19 +701,37 @@ type FSharpDeclarationListInfo(declarations: FSharpDeclarationListItem[], isForT



/// A single method for Intellisense completion
[<Sealed; NoEquality; NoComparison>]
/// Represents one method (or other item) in a method group. The item may represent either a method or
/// a single, non-overloaded item such as union case or a named function value.
// Note: instances of this type do not hold any references to any compiler resources.
[<Sealed; NoEquality; NoComparison>]
type FSharpMethodGroupItem(description: FSharpToolTipText<layout>, xmlDoc: FSharpXmlDoc, returnType: layout, parameters: FSharpMethodGroupItemParameter[], hasParameters: bool, hasParamArrayArg: bool, staticParameters: FSharpMethodGroupItemParameter[]) =

/// The structured description representation for the method (or other item)
member __.StructuredDescription = description

/// The formatted description text for the method (or other item)
member __.Description = Tooltips.ToFSharpToolTipText description

/// The documentation for the item
member __.XmlDoc = xmlDoc

/// The The structured description representation for the method (or other item)
member __.StructuredReturnTypeText = returnType

/// The formatted type text for the method (or other item)
member __.ReturnTypeText = showL returnType

/// The parameters of the method in the overload set
member __.Parameters = parameters

/// Does the method support an arguments list? This is always true except for static type instantiations like TP<42,"foo">.
member __.HasParameters = hasParameters

/// Does the method support a params list arg?
member __.HasParamArrayArg = hasParamArrayArg
// Does the type name or method support a static arguments list, like TP<42,"foo"> or conn.CreateCommand<42, "foo">(arg1, arg2)?

/// Does the type name or method support a static arguments list, like TP<42,"foo"> or conn.CreateCommand<42, "foo">(arg1, arg2)?
member __.StaticParameters = staticParameters


Expand Down
17 changes: 17 additions & 0 deletions src/fsharp/vs/ServiceDeclarationLists.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,37 @@ type internal FSharpDeclarationListItem =
#endif
/// Get the display name for the declaration.
member Name : string

/// Get the name for the declaration as it's presented in source code.
member NameInCode : string

/// Get the description text for the declaration. Computing this property may require using compiler
/// resources and may trigger execution of a type provider method to retrieve documentation.
///
/// May return "Loading..." if timeout occurs
member StructuredDescriptionText : FSharpStructuredToolTipText

member DescriptionText : FSharpToolTipText

/// Get the description text, asynchronously. Never returns "Loading...".
member StructuredDescriptionTextAsync : Async<FSharpStructuredToolTipText>

member DescriptionTextAsync : Async<FSharpToolTipText>

member Glyph : FSharpGlyph

member Accessibility : FSharpAccessibility option

member Kind : CompletionItemKind

member IsOwnMember : bool

member MinorPriority : int

member FullName : string

member IsResolved : bool

member NamespaceToOpen : string option


Expand All @@ -59,13 +71,18 @@ type FSharpDeclarationListInfo =
#else
type internal FSharpDeclarationListInfo =
#endif

member Items : FSharpDeclarationListItem[]

member IsForType : bool

member IsError : bool

// Implementation details used by other code in the compiler
static member internal Create : infoReader:InfoReader * m:range * denv:DisplayEnv * getAccessibility:(Item -> FSharpAccessibility option) * items:CompletionItem list * reactor:IReactorOperations * currentNamespace:string[] option * isAttributeApplicationContex:bool * checkAlive:(unit -> bool) -> FSharpDeclarationListInfo

static member internal Error : message:string -> FSharpDeclarationListInfo

static member Empty : FSharpDeclarationListInfo

/// Represents one parameter for one method (or other item) in a group.
Expand Down
72 changes: 36 additions & 36 deletions src/fsharp/vs/ServiceParamInfoLocations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ module internal NoteworthyParamInfoLocationsImpl =
let isStaticArg a =
match a with
| SynType.StaticConstant _ | SynType.StaticConstantExpr _ | SynType.StaticConstantNamed _ -> true
| SynType.LongIdent _ -> true // NOTE: this is not a static constant, but it is a prefix of incomplete code, e.g. "TP<42,Arg3" is a prefix of "TP<42,Arg3=6>" and Arg3 shows up as a LongId
| SynType.LongIdent _ -> true // NOTE: this is not a static constant, but it is a prefix of incomplete code, e.g. "TP<42, Arg3" is a prefix of "TP<42, Arg3=6>" and Arg3 shows up as a LongId
| _ -> false

/// Dig out an identifier from an expression that used in an application
let rec digOutIdentFromFuncExpr synExpr =
// we found it, dig out ident
match synExpr with
| SynExpr.Ident(id) -> Some ([id.idText], id.idRange)
| SynExpr.LongIdent(_, LongIdentWithDots(lid,_), _, lidRange)
| SynExpr.DotGet(_, _, LongIdentWithDots(lid,_), lidRange) -> Some (pathOfLid lid, lidRange)
| SynExpr.LongIdent(_, LongIdentWithDots(lid, _), _, lidRange)
| SynExpr.DotGet(_, _, LongIdentWithDots(lid, _), lidRange) -> Some (pathOfLid lid, lidRange)
| SynExpr.TypeApp(synExpr, _, _synTypeList, _commas, _, _, _range) -> digOutIdentFromFuncExpr synExpr
| _ -> None

Expand All @@ -53,30 +53,30 @@ module internal NoteworthyParamInfoLocationsImpl =

let digOutIdentFromStaticArg synType =
match synType with
| SynType.StaticConstantNamed(SynType.LongIdent(LongIdentWithDots([id],_)),_,_) -> Some id.idText
| SynType.LongIdent(LongIdentWithDots([id],_)) -> Some id.idText // NOTE: again, not a static constant, but may be a prefix of a Named in incomplete code
| SynType.StaticConstantNamed(SynType.LongIdent(LongIdentWithDots([id], _)), _, _) -> Some id.idText
| SynType.LongIdent(LongIdentWithDots([id], _)) -> Some id.idText // NOTE: again, not a static constant, but may be a prefix of a Named in incomplete code
| _ -> None

let getNamedParamName e =
match e with
// f(x=4)
| SynExpr.App(ExprAtomicFlag.NonAtomic, _,
SynExpr.App(ExprAtomicFlag.NonAtomic, true,
| SynExpr.App(ExprAtomicFlag.NonAtomic, _,
SynExpr.App(ExprAtomicFlag.NonAtomic, true,
SynExpr.Ident op,
SynExpr.Ident n,
_range),
_range),
_, _) when op.idText="op_Equality" -> Some n.idText
// f(?x=4)
| SynExpr.App(ExprAtomicFlag.NonAtomic, _,
SynExpr.App(ExprAtomicFlag.NonAtomic, true,
| SynExpr.App(ExprAtomicFlag.NonAtomic, _,
SynExpr.App(ExprAtomicFlag.NonAtomic, true,
SynExpr.Ident op,
SynExpr.LongIdent(true(*isOptional*),LongIdentWithDots([n],_),_ref,_lidrange), _range),
SynExpr.LongIdent(true(*isOptional*), LongIdentWithDots([n], _), _ref, _lidrange), _range),
_, _) when op.idText="op_Equality" -> Some n.idText
| _ -> None

let getTypeName(synType) =
match synType with
| SynType.LongIdent(LongIdentWithDots(ids,_)) -> ids |> pathOfLid
| SynType.LongIdent(LongIdentWithDots(ids, _)) -> ids |> pathOfLid
| _ -> [""] // TODO type name for other cases, see also unit test named "ParameterInfo.LocationOfParams.AfterQuicklyTyping.CallConstructorViaLongId.Bug94333"

let handleSingleArg traverseSynExpr (pos, synExpr, parenRange, rpRangeOpt : _ option) =
Expand All @@ -101,19 +101,19 @@ module internal NoteworthyParamInfoLocationsImpl =
match inner with
| None ->
if AstTraversal.rangeContainsPosEdgesExclusive parenRange pos then
let commasAndCloseParen = ((synExprList,commaRanges@[parenRange]) ||> List.map2 (fun e c -> c.End, getNamedParamName e))
let commasAndCloseParen = ((synExprList, commaRanges@[parenRange]) ||> List.map2 (fun e c -> c.End, getNamedParamName e))
let r = Found (parenRange.Start, commasAndCloseParen, rpRangeOpt.IsSome)
r, None
else
NotFound, None
| _ -> NotFound, None

| SynExprParen(SynExprParen(SynExpr.Tuple(_,_,_),_,_,_) as synExpr, _, rpRangeOpt, parenRange) -> // f((x,y)) is special, single tuple arg
handleSingleArg traverseSynExpr (pos,synExpr,parenRange,rpRangeOpt)
| SynExprParen(SynExprParen(SynExpr.Tuple(_, _, _), _, _, _) as synExpr, _, rpRangeOpt, parenRange) -> // f((x, y)) is special, single tuple arg
handleSingleArg traverseSynExpr (pos, synExpr, parenRange, rpRangeOpt)

// dig into multiple parens
| SynExprParen(SynExprParen(_,_,_,_) as synExpr, _, _, _parenRange) ->
let r,_cacheOpt = searchSynArgExpr traverseSynExpr pos synExpr
| SynExprParen(SynExprParen(_, _, _, _) as synExpr, _, _, _parenRange) ->
let r, _cacheOpt = searchSynArgExpr traverseSynExpr pos synExpr
r, None

| SynExprParen(synExpr, _lpRange, rpRangeOpt, parenRange) -> // single argument
Expand Down Expand Up @@ -146,18 +146,18 @@ module internal NoteworthyParamInfoLocationsImpl =



let traverseInput(pos,parseTree) =
let traverseInput(pos, parseTree) =

AstTraversal.Traverse(pos,parseTree, { new AstTraversal.AstVisitorBase<_>() with
AstTraversal.Traverse(pos, parseTree, { new AstTraversal.AstVisitorBase<_>() with
member this.VisitExpr(_path, traverseSynExpr, defaultTraverse, expr) =
let expr = expr // fix debug locals
match expr with

// new LID<tyarg1,....,tyargN>(...) and error recovery of these
// new LID<tyarg1, ...., tyargN>(...) and error recovery of these
| SynExpr.New(_, synType, synExpr, _range) ->
let constrArgsResult,cacheOpt = searchSynArgExpr traverseSynExpr pos synExpr
match constrArgsResult,cacheOpt with
| Found(parenLoc,args,isThereACloseParen), _ ->
let constrArgsResult, cacheOpt = searchSynArgExpr traverseSynExpr pos synExpr
match constrArgsResult, cacheOpt with
| Found(parenLoc, args, isThereACloseParen), _ ->
let typeName = getTypeName synType
Some (FSharpNoteworthyParamInfoLocations(typeName, synType.Range, parenLoc, args |> List.map fst, isThereACloseParen, args |> List.map snd))
| NotFound, Some cache ->
Expand All @@ -176,7 +176,7 @@ module internal NoteworthyParamInfoLocationsImpl =
if AstTraversal.rangeContainsPosEdgesExclusive typeArgsm pos then
// We found it, dig out ident
match digOutIdentFromFuncExpr synExpr with
| Some(lid,lidRange) -> Some (FSharpNoteworthyParamInfoLocations(lid, lidRange, op.idRange.Start, [ wholem.End ], false, []))
| Some(lid, lidRange) -> Some (FSharpNoteworthyParamInfoLocations(lid, lidRange, op.idRange.Start, [ wholem.End ], false, []))
| None -> None
else
None
Expand All @@ -189,12 +189,12 @@ module internal NoteworthyParamInfoLocationsImpl =
| Some _ -> fResult
| _ ->
// Search the argument
let xResult,cacheOpt = searchSynArgExpr traverseSynExpr pos synExpr2
match xResult,cacheOpt with
| Found(parenLoc,args,isThereACloseParen),_ ->
let xResult, cacheOpt = searchSynArgExpr traverseSynExpr pos synExpr2
match xResult, cacheOpt with
| Found(parenLoc, args, isThereACloseParen), _ ->
// We found it, dig out ident
match digOutIdentFromFuncExpr synExpr with
| Some(lid,lidRange) ->
| Some(lid, lidRange) ->
assert(isInfix = (posLt parenLoc lidRange.End))
if isInfix then
// This seems to be an infix operator, since the start of the argument is a position earlier than the end of the long-id being applied to it.
Expand All @@ -206,7 +206,7 @@ module internal NoteworthyParamInfoLocationsImpl =
| NotFound, Some cache -> cache
| _ -> traverseSynExpr synExpr2

// ID<tyarg1,....,tyargN> and error recovery of these
// ID<tyarg1, ...., tyargN> and error recovery of these
| SynExpr.TypeApp(synExpr, openm, tyArgs, commas, closemOpt, _, wholem) ->
match traverseSynExpr synExpr with
| Some _ as r -> r
Expand All @@ -221,9 +221,9 @@ module internal NoteworthyParamInfoLocationsImpl =

| _ -> defaultTraverse expr

member this.VisitTypeAbbrev(tyAbbrevRhs,_m) =
member this.VisitTypeAbbrev(tyAbbrevRhs, _m) =
match tyAbbrevRhs with
| SynType.App(SynType.LongIdent(LongIdentWithDots(lid,_) as lidwd), Some(openm), args, commas, closemOpt, _pf, wholem) ->
| SynType.App(SynType.LongIdent(LongIdentWithDots(lid, _) as lidwd), Some(openm), args, commas, closemOpt, _pf, wholem) ->
let lidm = lidwd.Range
let betweenTheBrackets = mkRange wholem.FileName openm.Start wholem.End
if AstTraversal.rangeContainsPosEdgesExclusive betweenTheBrackets pos && args |> List.forall isStaticArg then
Expand All @@ -241,9 +241,9 @@ module internal NoteworthyParamInfoLocationsImpl =
let inheritm = mkRange m.FileName m.Start m.End
if AstTraversal.rangeContainsPosEdgesExclusive inheritm pos then
// inherit ty(expr) --- treat it like an application (constructor call)
let xResult,_cacheOpt = searchSynArgExpr defaultTraverse pos expr
let xResult, _cacheOpt = searchSynArgExpr defaultTraverse pos expr
match xResult with
| Found(parenLoc,args,isThereACloseParen) ->
| Found(parenLoc, args, isThereACloseParen) ->
// we found it, dig out ident
let typeName = getTypeName ty
let r = FSharpNoteworthyParamInfoLocations(typeName, ty.Range, parenLoc, args |> List.map fst, isThereACloseParen, args |> List.map snd)
Expand All @@ -253,12 +253,12 @@ module internal NoteworthyParamInfoLocationsImpl =
})

type FSharpNoteworthyParamInfoLocations with
static member Find(pos,parseTree) =
match traverseInput(pos,parseTree) with
static member Find(pos, parseTree) =
match traverseInput(pos, parseTree) with
| Some nwpl as r ->
#if DEBUG
let ranges = nwpl.LongIdStartLocation :: nwpl.LongIdEndLocation :: nwpl.OpenParenLocation :: (nwpl.TupleEndLocations |> Array.toList)
let sorted = ranges |> List.sortWith (fun a b -> posOrder.Compare(a,b)) |> Seq.toList
let sorted = ranges |> List.sortWith (fun a b -> posOrder.Compare(a, b)) |> Seq.toList
assert(ranges = sorted)
#else
ignore nwpl
Expand Down
19 changes: 16 additions & 3 deletions src/fsharp/vs/ServiceParamInfoLocations.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,35 @@ namespace Microsoft.FSharp.Compiler.SourceCodeServices
open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.Range

/// Represents the locations relevant to activating parameter info in an IDE
[<Sealed>]
#if COMPILER_PUBLIC_API
type FSharpNoteworthyParamInfoLocations =
#else
type internal FSharpNoteworthyParamInfoLocations =
#endif

/// The text of the long identifier prior to the open-parentheses
member LongId : string list

/// The start location of long identifier prior to the open-parentheses
member LongIdStartLocation : pos

/// The end location of long identifier prior to the open-parentheses
member LongIdEndLocation : pos

/// The location of the open-parentheses
member OpenParenLocation : pos
/// locations of commas and close parenthesis (or, last char of last arg, if no final close parenthesis)

/// The locations of commas and close parenthesis (or, last char of last arg, if no final close parenthesis)
member TupleEndLocations : pos[]
/// false if either this is a call without parens "f x" or the parser recovered as in "f(x,y"

/// Is false if either this is a call without parens "f x" or the parser recovered as in "f(x,y"
member IsThereACloseParen : bool
/// empty or a name if an actual named parameter; f(0,a=4,?b=None) would be [|None; Some "a"; Some "b"|]

/// Either empty or a name if an actual named parameter; f(0,a=4,?b=None) would be [|None; Some "a"; Some "b"|]
member NamedParamNames : string option []

/// Find the information about parameter info locations at a particular source location
static member Find : pos * Ast.ParsedInput -> FSharpNoteworthyParamInfoLocations option