diff --git a/src/fsharp/service/ServiceUntypedParse.fs b/src/fsharp/service/ServiceUntypedParse.fs index 9a9d83f059a..626898a9db2 100755 --- a/src/fsharp/service/ServiceUntypedParse.fs +++ b/src/fsharp/service/ServiceUntypedParse.fs @@ -170,14 +170,18 @@ type FSharpParseFileResults(errors: FSharpDiagnostic[], input: ParsedInput optio member _.VisitExpr(_, _, defaultTraverse, expr) = match expr with | SynExpr.App (_, _, SynExpr.App(_, true, SynExpr.Ident ident, _, _), argExpr, _) when rangeContainsPos argExpr.Range pos -> - if ident.idText = "op_PipeRight" then - Some (ident, 1) - elif ident.idText = "op_PipeRight2" then - Some (ident, 2) - elif ident.idText = "op_PipeRight3" then - Some (ident, 3) - else + match argExpr with + | SynExpr.App(_, _, _, SynExpr.Paren(expr, _, _, _), _) when rangeContainsPos expr.Range pos -> None + | _ -> + if ident.idText = "op_PipeRight" then + Some (ident, 1) + elif ident.idText = "op_PipeRight2" then + Some (ident, 2) + elif ident.idText = "op_PipeRight3" then + Some (ident, 3) + else + None | _ -> defaultTraverse expr }) | None -> None @@ -216,6 +220,10 @@ type FSharpParseFileResults(errors: FSharpDiagnostic[], input: ParsedInput optio match argExpr with | SynExpr.App (_, _, _, _, range) when rangeContainsPos range pos -> getIdentRangeForFuncExprInApp traverseSynExpr argExpr pos + + | SynExpr.Paren(SynExpr.Lambda(_, _, _args, body, _, _), _, _, _) when rangeContainsPos body.Range pos -> + getIdentRangeForFuncExprInApp traverseSynExpr body pos + | _ -> match funcExpr with | SynExpr.App (_, true, _, _, _) when rangeContainsPos argExpr.Range pos -> @@ -227,6 +235,17 @@ type FSharpParseFileResults(errors: FSharpDiagnostic[], input: ParsedInput optio // Generally, we want to dive into the func expr to get the range // of the identifier of the function we're after getIdentRangeForFuncExprInApp traverseSynExpr funcExpr pos + + | SynExpr.LetOrUse(_, _, bindings, body, range) when rangeContainsPos range pos -> + let binding = + bindings + |> List.tryFind (fun x -> rangeContainsPos x.RangeOfBindingAndRhs pos) + match binding with + | Some(SynBinding.Binding(_, _, _, _, _, _, _, _, _, expr, _, _)) -> + getIdentRangeForFuncExprInApp traverseSynExpr expr pos + | None -> + getIdentRangeForFuncExprInApp traverseSynExpr body pos + | expr -> traverseSynExpr expr |> Option.map (fun expr -> expr) diff --git a/tests/service/ServiceUntypedParseTests.fs b/tests/service/ServiceUntypedParseTests.fs index 3c87e8f7973..5d00a4f4400 100644 --- a/tests/service/ServiceUntypedParseTests.fs +++ b/tests/service/ServiceUntypedParseTests.fs @@ -835,6 +835,26 @@ async { |> tups |> shouldEqual ((4, 11), (4, 16)) + [] + let ``TryRangeOfFunctionOrMethodBeingApplied - inside lambda``() = + let source = """ +let add n1 n2 = n1 + n2 +let lst = [1; 2; 3] +let mapped = + lst |> List.map (fun n -> + let sum = add + n.ToString() + ) +""" + let parseFileResults, _ = getParseAndCheckResults source + let res = parseFileResults.TryRangeOfFunctionOrMethodBeingApplied (mkPos 6 21) + match res with + | None -> Assert.Fail("Expected 'add' but got nothing") + | Some range -> + range + |> tups + |> shouldEqual ((6, 18), (6, 21)) + module PipelinesAndArgs = [] let ``TryIdentOfPipelineContainingPosAndNumArgsApplied - No pipeline, no infix app``() = @@ -897,6 +917,21 @@ let square x = x * | None -> Assert.Fail("No pipeline found") + [] + let ``TryIdentOfPipelineContainingPosAndNumArgsApplied - none when inside lambda``() = + let source = """ +let add n1 n2 = n1 + n2 +let lst = [1; 2; 3] +let mapped = + lst |> List.map (fun n -> + let sum = add 1 + n.ToString() + ) + """ + let parseFileResults, _ = getParseAndCheckResults source + let res = parseFileResults.TryIdentOfPipelineContainingPosAndNumArgsApplied (mkPos 6 22) + Assert.IsTrue(res.IsNone, "Inside a lambda but counted the pipeline outside of that lambda.") + [] let ``TryRangeOfExprInYieldOrReturn - not contained``() = let source = """