summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/reflect/scala/reflect/api/Position.scala160
-rw-r--r--src/reflect/scala/reflect/api/Printers.scala10
-rw-r--r--src/reflect/scala/reflect/internal/Printers.scala4
-rw-r--r--src/reflect/scala/reflect/internal/util/Position.scala37
-rw-r--r--test/files/neg/t6931.check10
-rw-r--r--test/files/neg/t6931/Macros_1.scala15
-rw-r--r--test/files/neg/t6931/Test_2.scala4
-rw-r--r--test/files/pos/t8013/inpervolator_1.scala2
8 files changed, 145 insertions, 97 deletions
diff --git a/src/reflect/scala/reflect/api/Position.scala b/src/reflect/scala/reflect/api/Position.scala
index 891d3a43ef..9d1b7c3812 100644
--- a/src/reflect/scala/reflect/api/Position.scala
+++ b/src/reflect/scala/reflect/api/Position.scala
@@ -5,14 +5,48 @@ package api
import scala.reflect.macros.Attachments
/**
- * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
+ * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * Position tracks the origin of [[Symbols#Symbol symbols]] and [[Trees#Tree tree nodes]]. They are commonly used when
- * displaying warnings and errors, to indicate the incorrect point in the program.
+ * Position tracks the origin of [[Symbols#Symbol symbols]] and [[Trees#Tree tree nodes]]. They are commonly used when
+ * displaying warnings and errors, to indicate the incorrect point in the program.
*
- * <b>Please note that this trait may be refactored in future versions of the Scala reflection API.</b>
+ * Every non-empty position refers to a SourceFile and three character
+ * offsets within it: start, end, and point. The point is where the ^ belongs when
+ * issuing an error message, usually a Name. A range position can be designated
+ * as transparent, which excuses it from maintaining the invariants to follow. If
+ * a transparent position has opaque children, those are considered as if they were
+ * the direct children of the transparent position's parent.
*
- * For more information about `Position`s, see the [[http://docs.scala-lang.org/overviews/reflection/annotations-names-scopes.html Reflection Guide: Annotations, Names, Scopes, and More]]
+ * Note: some of these invariants actually apply to the trees which carry
+ * the positions, but they are phrased as if the positions themselves were
+ * the parent/children for conciseness.
+ *
+ * Invariant 1: in a focused/offset position, start == point == end
+ * Invariant 2: in a range position, start <= point < end
+ * Invariant 3: an offset position never has a child with a range position
+ * Invariant 4: every range position child of a range position parent is contained within its parent
+ * Invariant 5: opaque range position siblings overlap at most at a single point
+ *
+ * The following tests are useful on positions:
+ *
+ * pos.isDefined true if position is not an UndefinedPosition (those being NoPosition and FakePos)
+ * pos.isRange true if position is a range (opaque or transparent) which implies start < end
+ * pos.isOpaqueRange true if position is an opaque range
+ *
+ * The following accessor methods are provided - an exception will be thrown if
+ * point/start/end are attempted on an UndefinedPosition.
+ *
+ * pos.source The source file of the position, or NoSourceFile if unavailable
+ * pos.point The offset of the point
+ * pos.start The (inclusive) start offset, or the point of an offset position
+ * pos.end The (exclusive) end offset, or the point of an offset position
+ *
+ * The following conversion methods are often used:
+ *
+ * pos.focus Converts a range position to an offset position focused on the point
+ * pos.makeTransparent Convert an opaque range into a transparent range
+ *
+ * For more information about `Position`s, see the [[http://docs.scala-lang.org/overviews/reflection/annotations-names-scopes.html Reflection Guide: Annotations, Names, Scopes, and More]]
*
* @groupname Common Commonly used methods
* @group ReflectionAPI
@@ -22,21 +56,7 @@ trait Position extends Attachments {
/** @inheritdoc */
type Pos >: Null <: AnyRef with Position
- /** Java file corresponding to the source file of this position.
- *
- * The return type is `scala.reflect.io.AbstractFile`, which belongs to an experimental part of Scala reflection.
- * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined
- * and exposed as a part of scala.reflect.api.
- *
- * @group Common
- */
- def source: scala.reflect.internal.util.SourceFile
-
- /** Is this position neither a NoPosition nor a FakePosition?
- * If isDefined is true, offset and source are both defined.
- * @group Common
- */
- def isDefined: Boolean
+ ////////////////// POSITION FLAVORS //////////////////
/** Is this position a range position? */
def isRange: Boolean
@@ -47,119 +67,141 @@ trait Position extends Attachments {
/** Is this position a non-transparent range position? */
def isOpaqueRange: Boolean
+ /** If this is a range position, the offset position of its point.
+ * Otherwise the position itself
+ */
+ def focus: Pos
+
/** If opaque range, make this position transparent. */
def makeTransparent: Pos
+ ////////////////// POSITION ESSENTIALS //////////////////
+
/** The start of the position's range, or the point if not a range position. */
def start: Int
- /** The start of the position's range, or point if not a range position. */
- @deprecated("Use `start` instead", "2.11.0") def startOrPoint: Int
-
/** The point (where the ^ is) of the position, which is easiest to access using the [[line]] and [[column]] values.
* The [[lineContent line content]] is also available.
* @group Common
*/
def point: Int
- /** The point (where the ^ is) of the position, or else `default` if undefined.
+ /** The end of the position's range, or the point if not a range position.
+ */
+ def end: Int
+
+ /** Java file corresponding to the source file of this position.
+ *
+ * The return type is `scala.reflect.io.AbstractFile`, which belongs to an experimental part of Scala reflection.
+ * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined
+ * and exposed as a part of scala.reflect.api.
+ *
* @group Common
*/
- def pointOrElse(default: Int): Int
+ def source: scala.reflect.internal.util.SourceFile
- /** The end of the position's range, or the point if not a range position.
+ /** The position indicates a [[column `column`]] and the `line` in the source file.
+ * @group Common
*/
- def end: Int
+ def line: Int
- /** The end of the position's range, or point if not a range position.
+ /** The position indicates a `column` and the [[line `line`]] in the source file.
+ * @group Common
*/
- @deprecated("Use `end` instead", "2.11.0") def endOrPoint: Int
+ def column: Int
- /** The same position with a different start value (if a range).
+ ////////////////// POSITION FACTORIES //////////////////
+
+ /** Returns a new position with the same attributes, but a different start value (if a range).
*/
def withStart(off: Int): Pos
- /** The same position with a different end value (if a range).
+ /** Returns a new position with the same attributes, but a different end value (if a range).
*/
def withEnd(off: Int): Pos
- /** The same position with a different point value (if a range or offset).
+ /** Returns a new position with the same attributes, but a different point value (if a range or offset).
*/
def withPoint(off: Int): Pos
- /** If this is a range, the union with the other range, with the point of this position.
- * Otherwise, this position
+ ////////////////// STUFF //////////////////
+
+ /** Is this position not a NoPosition?
+ * If isDefined is true, offset and source are both defined.
+ * @group Common
*/
- def union(pos: Pos): Pos
+ @deprecated("Removed from the public API", "2.11.0") def isDefined: Boolean
- /** If this is a range position, the offset position of its point.
- * Otherwise the position itself
+ /** The point (where the ^ is) of the position, or else `default` if undefined.
+ * @group Common
*/
- def focus: Pos
+ @deprecated("Removed from the public API", "2.11.0") def pointOrElse(default: Int): Int
+
+ /** The start of the position's range, or point if not a range position. */
+ @deprecated("Removed from the public API", "2.11.0") def startOrPoint: Int
+
+ /** The end of the position's range, or point if not a range position.
+ */
+ @deprecated("Removed from the public API", "2.11.0") def endOrPoint: Int
+
+ /** If this is a range, the union with the other range, with the point of this position.
+ * Otherwise, this position
+ */
+ @deprecated("Removed from the public API", "2.11.0") def union(pos: Pos): Pos
/** If this is a range position, the offset position of its start.
* Otherwise the position itself
*/
- def focusStart: Pos
+ @deprecated("Removed from the public API", "2.11.0") def focusStart: Pos
/** If this is a range position, the offset position of its end.
* Otherwise the position itself
*/
- def focusEnd: Pos
+ @deprecated("Removed from the public API", "2.11.0") def focusEnd: Pos
/** Does this position include the given position `pos`?
* This holds if `this` is a range position and its range [start..end]
* is the same or covers the range of the given position, which may or may not be a range position.
*/
- def includes(pos: Pos): Boolean
+ @deprecated("Removed from the public API", "2.11.0") def includes(pos: Pos): Boolean
/** Does this position properly include the given position `pos` ("properly" meaning their
* ranges are not the same)?
*/
- def properlyIncludes(pos: Pos): Boolean
+ @deprecated("Removed from the public API", "2.11.0") def properlyIncludes(pos: Pos): Boolean
/** Does this position precede that position?
* This holds if both positions are defined and the end point of this position
* is not larger than the start point of the given position.
*/
- def precedes(pos: Pos): Boolean
+ @deprecated("Removed from the public API", "2.11.0") def precedes(pos: Pos): Boolean
/** Does this position properly precede the given position `pos` ("properly" meaning their ranges
* do not share a common point).
*/
- def properlyPrecedes(pos: Pos): Boolean
+ @deprecated("Removed from the public API", "2.11.0") def properlyPrecedes(pos: Pos): Boolean
/** Does this position overlap with that position?
* This holds if both positions are ranges and there is an interval of
* non-zero length that is shared by both position ranges.
*/
- def overlaps(pos: Pos): Boolean
+ @deprecated("Removed from the public API", "2.11.0") def overlaps(pos: Pos): Boolean
/** Does this position cover the same range as that position?
* Holds only if both position are ranges
*/
- def sameRange(pos: Pos): Boolean
-
- /** The position indicates a [[column `column`]] and the `line` in the source file.
- * @group Common
- */
- def line: Int
-
- /** The position indicates a `column` and the [[line `line`]] in the source file.
- * @group Common
- */
- def column: Int
+ @deprecated("Removed from the public API", "2.11.0") def sameRange(pos: Pos): Boolean
/** Convert this to a position around `point` that spans a single source line
*/
- def toSingleLine: Pos
+ @deprecated("Removed from the public API", "2.11.0") def toSingleLine: Pos
/** The content of the line this Position refers to.
* @group Common
*/
- def lineContent: String
+ @deprecated("Removed from the public API", "2.11.0") def lineContent: String
/** Show a textual representation of the position.
*/
- def show: String
+ @deprecated("Use `universe.show(position)` instead", "2.11.0") def show: String
}
diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala
index ae1ad30527..96e111f759 100644
--- a/src/reflect/scala/reflect/api/Printers.scala
+++ b/src/reflect/scala/reflect/api/Printers.scala
@@ -248,11 +248,21 @@ trait Printers { self: Universe =>
*/
def show(flags: FlagSet): String
+ /** Renders a prettified representation of a position.
+ * @group Printers
+ */
+ def show(position: Position): String
+
/** Renders internal structure of a flag set.
* @group Printers
*/
def showRaw(flags: FlagSet): String = flags.toString
+ /** Renders internal structure of a position.
+ * @group Printers
+ */
+ def showRaw(position: Position): String = position.toString
+
/** Renders a string that represents a declaration of this symbol written in Scala.
* @group Printers
*/
diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala
index b287a3884a..0a9e291abe 100644
--- a/src/reflect/scala/reflect/internal/Printers.scala
+++ b/src/reflect/scala/reflect/internal/Printers.scala
@@ -1238,6 +1238,10 @@ trait Printers extends api.Printers { self: SymbolTable =>
}
}
+ def show(position: Position): String = {
+ position.show
+ }
+
def showDeclaration(sym: Symbol): String = {
if (!isCompilerUniverse) definitions.fullyInitializeSymbol(sym)
sym.defString
diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala
index f3eedb88e7..5cec575b77 100644
--- a/src/reflect/scala/reflect/internal/util/Position.scala
+++ b/src/reflect/scala/reflect/internal/util/Position.scala
@@ -8,43 +8,6 @@ package reflect
package internal
package util
-/** The Position class and its subclasses represent positions of ASTs and symbols.
- * Every subclass of DefinedPosition refers to a SourceFile and three character
- * offsets within it: start, end, and point. The point is where the ^ belongs when
- * issuing an error message, usually a Name. A range position can be designated
- * as transparent, which excuses it from maintaining the invariants to follow. If
- * a transparent position has opaque children, those are considered as if they were
- * the direct children of the transparent position's parent.
- *
- * Note: some of these invariants actually apply to the trees which carry
- * the positions, but they are phrased as if the positions themselves were
- * the parent/children for conciseness.
- *
- * Invariant 1: in a focused/offset position, start == point == end
- * Invariant 2: in a range position, start <= point < end
- * Invariant 3: an offset position never has a child with a range position
- * Invariant 4: every range position child of a range position parent is contained within its parent
- * Invariant 5: opaque range position siblings overlap at most at a single point
- *
- * The following tests are useful on positions:
- *
- * pos.isDefined true if position is not an UndefinedPosition (those being NoPosition and FakePos)
- * pos.isRange true if position is a range (opaque or transparent) which implies start < end
- * pos.isOpaqueRange true if position is an opaque range
- *
- * The following accessor methods are provided - an exception will be thrown if
- * point/start/end are attempted on an UndefinedPosition.
- *
- * pos.source The source file of the position, or NoSourceFile if unavailable
- * pos.point The offset of the point
- * pos.start The (inclusive) start offset, or the point of an offset position
- * pos.end The (exclusive) end offset, or the point of an offset position
- *
- * The following conversion methods are often used:
- *
- * pos.focus Converts a range position to an offset position focused on the point
- * pos.makeTransparent Convert an opaque range into a transparent range
- */
class Position extends scala.reflect.api.Position with InternalPositionImpl with DeprecatedPosition {
type Pos = Position
def pos: Position = this
diff --git a/test/files/neg/t6931.check b/test/files/neg/t6931.check
new file mode 100644
index 0000000000..7cf804a936
--- /dev/null
+++ b/test/files/neg/t6931.check
@@ -0,0 +1,10 @@
+Test_2.scala:3: error: 1
+ err"123"
+ ^
+Test_2.scala:3: error: 2
+ err"123"
+ ^
+Test_2.scala:3: error: 3
+ err"123"
+ ^
+three errors found
diff --git a/test/files/neg/t6931/Macros_1.scala b/test/files/neg/t6931/Macros_1.scala
new file mode 100644
index 0000000000..56da075d1f
--- /dev/null
+++ b/test/files/neg/t6931/Macros_1.scala
@@ -0,0 +1,15 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+
+object Macros {
+ implicit class Error(ctx: StringContext) {
+ def err(args: Any*): Unit = macro impl
+ }
+
+ def impl(c: Context)(args: c.Tree*): c.Tree = {
+ import c.universe._
+ val q"Macros.Error(scala.StringContext.apply($arg)).err()" = c.macroApplication
+ for (i <- 1 to 3) c.error(arg.pos.withPoint(arg.pos.point + i - 1), i.toString)
+ q"()"
+ }
+} \ No newline at end of file
diff --git a/test/files/neg/t6931/Test_2.scala b/test/files/neg/t6931/Test_2.scala
new file mode 100644
index 0000000000..6a6f645904
--- /dev/null
+++ b/test/files/neg/t6931/Test_2.scala
@@ -0,0 +1,4 @@
+object Test extends App {
+ import Macros._
+ err"123"
+} \ No newline at end of file
diff --git a/test/files/pos/t8013/inpervolator_1.scala b/test/files/pos/t8013/inpervolator_1.scala
index 89b7c22709..612e1d727d 100644
--- a/test/files/pos/t8013/inpervolator_1.scala
+++ b/test/files/pos/t8013/inpervolator_1.scala
@@ -18,7 +18,7 @@ object Perverse {
def pImpl(c: Context)(args: c.Expr[Any]*): c.Expr[String] = {
import c.universe._
val macroPos = c.macroApplication.pos
- val text = macroPos.lineContent substring macroPos.column
+ val text = macroPos.source.lineToString(macroPos.line - 1) substring macroPos.column
val tt = Literal(Constant(text))
val tree = q"t8013.Perverse.pervert($tt)"
c.Expr[String](tree)