diff --git a/src/Compiler/Service/ServiceAnalysis.fs b/src/Compiler/Service/ServiceAnalysis.fs index 89caef4642e..f168884644c 100644 --- a/src/Compiler/Service/ServiceAnalysis.fs +++ b/src/Compiler/Service/ServiceAnalysis.fs @@ -692,6 +692,22 @@ module UnnecessaryParentheses = module SynExpr = open FSharp.Compiler.SyntaxTrivia + /// See atomicExprAfterType in pars.fsy. + [] + let (|AtomicExprAfterType|_|) expr = + match expr with + | SynExpr.Paren _ + | SynExpr.Quote _ + | SynExpr.Const _ + | SynExpr.Tuple(isStruct = true) + | SynExpr.Record _ + | SynExpr.AnonRecd _ + | SynExpr.InterpolatedString _ + | SynExpr.Null _ + | SynExpr.ArrayOrList(isArray = true) + | SynExpr.ArrayOrListComputed(isArray = true) -> ValueSome AtomicExprAfterType + | _ -> ValueNone + /// Matches if the given expression represents a high-precedence /// function application, e.g., /// @@ -1142,6 +1158,18 @@ module UnnecessaryParentheses = | SynExpr.Paren(expr = SynExpr.App _), SyntaxNode.SynExpr (SynExpr.App _) :: SyntaxNode.SynExpr (SynExpr.JoinIn _) :: _ -> ValueNone + // Parens are not required around a few anointed expressions after inherit: + // + // inherit T(3) + // inherit T(null) + // inherit T("") + // … + | SynExpr.Paren (expr = AtomicExprAfterType; range = range), SyntaxNode.SynMemberDefn (SynMemberDefn.ImplicitInherit _) :: _ -> + ValueSome range + + // Parens are otherwise required in inherit T(x), etc. + | SynExpr.Paren _, SyntaxNode.SynMemberDefn (SynMemberDefn.ImplicitInherit _) :: _ -> ValueNone + // We can't remove parens when they're required for fluent calls: // // x.M(y).N z @@ -1284,6 +1312,14 @@ module UnnecessaryParentheses = | SynExpr.AddressOf _, SynExpr.Typed _ | SynExpr.JoinIn _, SynExpr.Typed _ -> ValueNone + // new T(expr) + | SynExpr.New _, AtomicExprAfterType -> ValueSome range + | SynExpr.New _, _ -> ValueNone + + // { inherit T(expr); … } + | SynExpr.Record(baseInfo = Some (_, SynExpr.Paren(expr = Is inner), _, _, _)), AtomicExprAfterType -> ValueSome range + | SynExpr.Record(baseInfo = Some (_, SynExpr.Paren(expr = Is inner), _, _, _)), _ -> ValueNone + | _, SynExpr.Paren _ | _, SynExpr.Quote _ | _, SynExpr.Const _ diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs index d0d1dd9bf5c..551cfef9f68 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs @@ -127,6 +127,12 @@ let _ = // New "new exn(null)", "new exn null" "new exn (null)", "new exn null" + "new ResizeArray(3)", "new ResizeArray 3" + "let x = 3 in new ResizeArray(x)", "let x = 3 in new ResizeArray(x)" + "ResizeArray([3])", "ResizeArray [3]" + "new ResizeArray([3])", "new ResizeArray([3])" + "ResizeArray([|3|])", "ResizeArray [|3|]" + "new ResizeArray([|3|])", "new ResizeArray [|3|]" // ObjExpr "{ new System.IDisposable with member _.Dispose () = (ignore 3) }", @@ -1091,6 +1097,50 @@ let builder = Builder () let (+) _ _ = builder let _ = (2 + 2) { return 5 } " + + """ + type E (message : string) = + inherit exn ($"{message}") + """, + """ + type E (message : string) = + inherit exn $"{message}" + """ + + " + type E (message : string) = + inherit exn (message) + ", + " + type E (message : string) = + inherit exn (message) + " + + """ + type E = + inherit exn + val Message2 : string + new (str1, str2) = { inherit exn ($"{str1}"); Message2 = str2 } + """, + """ + type E = + inherit exn + val Message2 : string + new (str1, str2) = { inherit exn $"{str1}"; Message2 = str2 } + """ + + " + type E = + inherit exn + val Message2 : string + new (str1, str2) = { inherit exn (str1); Message2 = str2 } + ", + " + type E = + inherit exn + val Message2 : string + new (str1, str2) = { inherit exn (str1); Message2 = str2 } + " } []