diff --git a/src/Compiler/Utilities/range.fs b/src/Compiler/Utilities/range.fs
index 6bf20edfc00..0a91bb1a2c3 100755
--- a/src/Compiler/Utilities/range.fs
+++ b/src/Compiler/Utilities/range.fs
@@ -492,6 +492,20 @@ module Range =
else
m
+ let withStartEnd (startPos: Position) (endPos: Position) (r: range) = range (r.FileIndex, startPos, endPos)
+
+ let withStart (startPos: Position) (r: range) = range (r.FileIndex, startPos, r.End)
+
+ let withEnd (endPos: Position) (r: range) = range (r.FileIndex, r.Start, endPos)
+
+ let shiftStart (lineDelta: int) (columnDelta: int) (r: range) =
+ let shiftedStart = mkPos (r.Start.Line + lineDelta) (r.StartColumn + columnDelta)
+ range (r.FileIndex, shiftedStart, r.End)
+
+ let shiftEnd (lineDelta: int) (columnDelta: int) (r: range) =
+ let shiftedEnd = mkPos (r.End.Line + lineDelta) (r.EndColumn + columnDelta)
+ range (r.FileIndex, r.Start, shiftedEnd)
+
let rangeContainsRange (m1: range) (m2: range) =
m1.FileIndex = m2.FileIndex && posGeq m2.Start m1.Start && posGeq m1.End m2.End
diff --git a/src/Compiler/Utilities/range.fsi b/src/Compiler/Utilities/range.fsi
index 100c57fb67e..7b422fcd307 100755
--- a/src/Compiler/Utilities/range.fsi
+++ b/src/Compiler/Utilities/range.fsi
@@ -211,6 +211,21 @@ module Range =
/// Union two ranges, taking their first occurring start position and last occurring end position
val unionRanges: range -> range -> range
+
+ // Create a new range with the given start and end positions
+ val withStartEnd: Position -> Position -> range -> range
+
+ // Create a new range with the given start position
+ val withStart: Position -> range -> range
+
+ // Create a new range with the given end position
+ val withEnd: Position -> range -> range
+
+ // Create a new range with the start position shifted by the given deltas
+ val shiftStart: int -> int -> range -> range
+
+ // Create a new range with the end position shifted by the given deltas
+ val shiftEnd: int -> int -> range -> range
/// Test to see if one range contains another range
val rangeContainsRange: range -> range -> bool
diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy
index d22e79fd15d..18e50749469 100644
--- a/src/Compiler/pars.fsy
+++ b/src/Compiler/pars.fsy
@@ -603,7 +603,7 @@ fileModuleSpec:
| [] -> ParsedSigFileFragment.AnonModule($1, m)
| _ ->
let lastDeclRange = List.tryLast $1 |> Option.map (fun decl -> decl.Range) |> Option.defaultValue (rhs parseState 1)
- let m = mkRange lastDeclRange.FileName (lhs parseState).Start lastDeclRange.End
+ let m = withStart (lhs parseState).Start lastDeclRange
xml.MarkAsInvalid()
let trivia: SynModuleOrNamespaceSigTrivia =
match mNamespaceOpt with
@@ -1159,7 +1159,7 @@ fileModuleImpl:
| [], None -> ParsedImplFileFragment.AnonModule($1, m)
| _ ->
let lastDeclRange = List.tryLast $1 |> Option.map (fun decl -> decl.Range) |> Option.defaultValue (rhs parseState 1)
- let m = mkRange lastDeclRange.FileName (lhs parseState).Start lastDeclRange.End
+ let m = withStart (lhs parseState).Start lastDeclRange
xml.MarkAsInvalid()
let trivia: SynModuleOrNamespaceTrivia =
match mNamespaceOpt with
@@ -4927,18 +4927,18 @@ atomicExprQualification:
| GLOBAL
{ (fun e mLhs mDot ->
reportParseErrorAt (rhs parseState 3) (FSComp.SR.nrGlobalUsedOnlyAsFirstName())
- let fixedLhsm = mkRange mLhs.FileName mLhs.Start mDot.End // previous mLhs is wrong after 'recover'
+ let fixedLhsm = withEnd mDot.End mLhs // previous mLhs is wrong after 'recover'
mkSynDotMissing mDot fixedLhsm e) }
| /* empty */
{ (fun e mLhs mDot ->
reportParseErrorAt mDot (FSComp.SR.parsMissingQualificationAfterDot())
- let fixedLhsm = mkRange mLhs.FileName mLhs.Start mDot.End // previous mLhs is wrong after 'recover'
+ let fixedLhsm = withEnd mDot.End mLhs // previous mLhs is wrong after 'recover'
mkSynDotMissing mDot fixedLhsm e) }
| recover
{ (fun e mLhs mDot ->
reportParseErrorAt mDot (FSComp.SR.parsMissingQualificationAfterDot())
- let fixedLhsm = mkRange mLhs.FileName mLhs.Start mDot.End // previous mLhs is wrong after 'recover'
+ let fixedLhsm = withEnd mDot.End mLhs // previous mLhs is wrong after 'recover'
// Include 'e' in the returned expression but throw it away
mkSynDotMissing mDot fixedLhsm e) }
| LPAREN COLON_COLON rparen DOT INT32
@@ -5883,7 +5883,7 @@ appTypeConPower:
{ if $2 <> "^" && $2 <> "^-" then reportParseErrorAt (rhs parseState 2) (FSComp.SR.parsUnexpectedInfixOperator())
if $2 = "^-" then
let afterMinus = (rhs parseState 2).EndRange
- let beforeMinus = mkRange afterMinus.FileName (mkPos afterMinus.EndLine (afterMinus.EndColumn - 1)) afterMinus.End
+ let beforeMinus = shiftStart 0 -1 afterMinus
let m = unionRanges beforeMinus (rhs parseState 3) // include MINUS in Negate range
SynType.MeasurePower($1, SynRationalConst.Negate($3, m), lhs parseState)
else SynType.MeasurePower($1, $3, lhs parseState) }
@@ -6044,7 +6044,7 @@ powerType:
{ if $2 <> "^" && $2 <> "^-" then reportParseErrorAt (rhs parseState 2) (FSComp.SR.parsUnexpectedInfixOperator())
if $2 = "^-" then
let afterMinus = (rhs parseState 2).EndRange
- let beforeMinus = mkRange afterMinus.FileName (mkPos afterMinus.EndLine (afterMinus.EndColumn - 1)) afterMinus.End
+ let beforeMinus = shiftStart 0 -1 afterMinus
let m = unionRanges beforeMinus (rhs parseState 3) // include MINUS in Negate range
SynType.MeasurePower($1, SynRationalConst.Negate($3, m), lhs parseState)
else SynType.MeasurePower($1, $3, lhs parseState) }
@@ -6270,7 +6270,7 @@ measureTypePower:
if $2 = "^-" then
let mOp = rhs parseState 2
let afterMinus = mOp.EndRange
- let beforeMinus = mkRange afterMinus.FileName (mkPos afterMinus.EndLine (afterMinus.EndColumn - 1)) afterMinus.End
+ let beforeMinus = shiftStart 0 -1 afterMinus
let mNegate = unionRanges beforeMinus (rhs parseState 3) // include MINUS in Negate range
let mCaret = unionRanges mOp.StartRange mNegate.StartRange
SynMeasure.Power($1, mCaret, SynRationalConst.Negate($3, mNegate), lhs parseState)
diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
index 7f07a0f1123..6a555b4aed0 100644
--- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
+++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
@@ -10039,8 +10039,13 @@ FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range range0
FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range rangeCmdArgs
FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range rangeN(System.String, Int32)
FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range rangeStartup
+FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range shiftEnd(Int32, Int32, FSharp.Compiler.Text.Range)
+FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range shiftStart(Int32, Int32, FSharp.Compiler.Text.Range)
FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range trimRangeToLine(FSharp.Compiler.Text.Range)
FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range unionRanges(FSharp.Compiler.Text.Range, FSharp.Compiler.Text.Range)
+FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range withEnd(FSharp.Compiler.Text.Position, FSharp.Compiler.Text.Range)
+FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range withStart(FSharp.Compiler.Text.Position, FSharp.Compiler.Text.Range)
+FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range withStartEnd(FSharp.Compiler.Text.Position, FSharp.Compiler.Text.Position, FSharp.Compiler.Text.Range)
FSharp.Compiler.Text.RangeModule: System.Collections.Generic.IComparer`1[FSharp.Compiler.Text.Position] get_posOrder()
FSharp.Compiler.Text.RangeModule: System.Collections.Generic.IComparer`1[FSharp.Compiler.Text.Position] posOrder
FSharp.Compiler.Text.RangeModule: System.Collections.Generic.IComparer`1[FSharp.Compiler.Text.Range] get_rangeOrder()
diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
index 7f07a0f1123..6a555b4aed0 100644
--- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
+++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
@@ -10039,8 +10039,13 @@ FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range range0
FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range rangeCmdArgs
FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range rangeN(System.String, Int32)
FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range rangeStartup
+FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range shiftEnd(Int32, Int32, FSharp.Compiler.Text.Range)
+FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range shiftStart(Int32, Int32, FSharp.Compiler.Text.Range)
FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range trimRangeToLine(FSharp.Compiler.Text.Range)
FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range unionRanges(FSharp.Compiler.Text.Range, FSharp.Compiler.Text.Range)
+FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range withEnd(FSharp.Compiler.Text.Position, FSharp.Compiler.Text.Range)
+FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range withStart(FSharp.Compiler.Text.Position, FSharp.Compiler.Text.Range)
+FSharp.Compiler.Text.RangeModule: FSharp.Compiler.Text.Range withStartEnd(FSharp.Compiler.Text.Position, FSharp.Compiler.Text.Position, FSharp.Compiler.Text.Range)
FSharp.Compiler.Text.RangeModule: System.Collections.Generic.IComparer`1[FSharp.Compiler.Text.Position] get_posOrder()
FSharp.Compiler.Text.RangeModule: System.Collections.Generic.IComparer`1[FSharp.Compiler.Text.Position] posOrder
FSharp.Compiler.Text.RangeModule: System.Collections.Generic.IComparer`1[FSharp.Compiler.Text.Range] get_rangeOrder()
diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj
index eb9294585d9..3b83200c1d6 100644
--- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj
+++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj
@@ -97,6 +97,9 @@
PrettyNaming.fs
+
+ RangeTests.fs
+
Program.fs
diff --git a/tests/service/RangeTests.fs b/tests/service/RangeTests.fs
new file mode 100644
index 00000000000..2fd9d4c28fa
--- /dev/null
+++ b/tests/service/RangeTests.fs
@@ -0,0 +1,48 @@
+module Tests.Service.RangeTests
+
+open FSharp.Compiler.Text
+open FSharp.Compiler.Text.Position
+open FSharp.Compiler.Text.Range
+open FsUnit
+open NUnit.Framework
+
+[]
+let ``withStartEnd Test`` () =
+ let z = Range.Zero
+ let newStart = mkPos 2 4
+ let newEnd = mkPos 7 23
+ let r = withStartEnd newStart newEnd z
+ r.Start |> shouldEqual newStart
+ r.End |> shouldEqual newEnd
+
+[]
+let ``withStart Test`` () =
+ let z = Range.Zero
+ let newStart = mkPos 2 4
+ let r = withStart newStart z
+ r.Start |> shouldEqual newStart
+
+[]
+let ``withEnd Test`` () =
+ let z = Range.Zero
+ let newEnd = mkPos 2 4
+ let r = withEnd newEnd z
+ r.End |> shouldEqual newEnd
+
+[]
+let ``shiftStart Test`` () =
+ let z = Range.Zero
+ let lineDelta = 10
+ let columnDelta = 20
+ let r = shiftStart lineDelta columnDelta z
+ r.Start.Column |> shouldEqual (z.StartColumn + columnDelta)
+ r.Start.Line |> shouldEqual (z.StartLine + lineDelta)
+
+[]
+let ``shiftEnd Test`` () =
+ let z = Range.Zero
+ let lineDelta = 10
+ let columnDelta = 20
+ let r = shiftEnd lineDelta columnDelta z
+ r.End.Column |> shouldEqual (z.EndColumn + columnDelta)
+ r.End.Line |> shouldEqual (z.EndLine + lineDelta)