Skip to content
Open
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
28 changes: 21 additions & 7 deletions ReSharper.FSharp/src/FSharp.Psi/src/Impl/Tree/RecordExpr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,8 @@ public override FSharpSymbol GetFSharpSymbol()
if (symbolUse?.Symbol is FSharpField field)
return field.DeclaringEntity?.Value;

// todo: cover other contexts
var sequentialExpr = SequentialExprNavigator.GetByExpression(RecordExpr.IgnoreParentParens());
if (sequentialExpr != null && sequentialExpr.Expressions.Last() != RecordExpr)
return null;
var exprToGetBy = sequentialExpr ?? RecordExpr.IgnoreParentParens();

var binding = BindingNavigator.GetByExpression(exprToGetBy);
var functionExpr = GetFunctionExpression(RecordExpr);
var binding = BindingNavigator.GetByExpression(functionExpr);
if (binding == null || !(binding.HeadPattern is INamedPat namedPat))
return null;

Expand All @@ -79,6 +74,25 @@ public override FSharpSymbol GetFSharpSymbol()
return entity.IsFSharpRecord ? entity : null;
}

private static IFSharpExpression GetFunctionExpression(IFSharpExpression expression)
{
IFSharpExpression currentExpression = IfExprNavigator.GetByThenExpr(expression);
currentExpression ??= IfExprNavigator.GetByElseExpr(expression);
var matchClause = MatchClauseNavigator.GetByExpression(expression);
currentExpression = matchClause == null ? currentExpression : MatchExprNavigator.GetByClause(matchClause);
currentExpression ??= MatchLambdaExprNavigator.GetByClause(matchClause);

var sequentialExpr = SequentialExprNavigator.GetByExpression(expression);
currentExpression ??= sequentialExpr;
if (sequentialExpr != null && sequentialExpr.Expressions.Last() != expression)
return null;

if (currentExpression == null)
return expression;

return GetFunctionExpression(currentExpression);
}

public override string GetName() =>
SharedImplUtil.MISSING_DECLARATION_NAME;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type R = { A: int; B: int }

let r (shouldFail : bool) : R =
if shouldFail then
failwith ""
elif true then
{}{caret}
else
failwith ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type R = { A: int; B: int }

let r (shouldFail : bool) : R =
if shouldFail then
failwith ""
elif true then
{ A = {selstart}failwith "todo"{selend}
B = failwith "todo" }
else
failwith ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type R = { A: int; B: int }
module foo =
let r (input : int option) : (R option) =
input
|> Option.map(fun x -> {})
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
type R = { A: int; B: int }
module foo =
let r : (string option -> R) = function | Some _ -> {}{caret} | None -> {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type R = { A: int; B: int }
module foo =
let r : (string option -> R) = function | Some _ -> { A = {selstart}failwith "todo"{selend}
B = failwith "todo" } | None -> {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
type R = { A: int; B: int }

let r (shouldFail : bool) : R =
()
if shouldFail then
failwith ""
else
if true then
{}{caret}
else
failwith ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type R = { A: int; B: int }

let r (shouldFail : bool) : R =
()
if shouldFail then
failwith ""
else
if true then
{ A = {selstart}failwith "todo"{selend}
B = failwith "todo" }
else
failwith ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type R = { A: int; B: int }

let r (someOption : option int) : R =
()
match someOption with
| Some value -> {A = value; B = value}
| None -> {}{caret}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
type R = { A: int; B: int }

let r (someOption : option int) : R =
()
match someOption with
| Some value -> {A = value; B = value}
| None -> { A = {selstart}failwith "todo"{selend}
B = failwith "todo" }
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ type GenerateMissingRecordFieldsTest() =

[<Test>] member x.``Multiline 01``() = x.DoNamedTest()
[<Test>] member x.``Multiline 02``() = x.DoNamedTest()

[<Test>] member x.``Empty function``() = x.DoNamedTest()
[<Test>] member x.``Function statement``() = x.DoNamedTest()
[<Test>] member x.``If statement in function``() = x.DoNamedTest()
[<Test>] member x.``Elif statement``() = x.DoNamedTest()
[<Test>] member x.``Match statement in function``() = x.DoNamedTest()

// The quickfix should apply if the empty record is the final statement of a function binding, as that's what the
// annotated return type pertains to.
Expand Down