summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-03-11 22:11:19 -0700
committerPaul Phillips <paulp@improving.org>2013-03-12 07:35:49 -0700
commit9fed30cb9c6d86ca07286febeb44bf635cb23650 (patch)
tree951a0edf356000b0cefbf6ffa49751848e948cd7
parenta41c79bb5b2f16d8f37e253737f67171e5764bb9 (diff)
downloadscala-9fed30cb9c6d86ca07286febeb44bf635cb23650.tar.gz
scala-9fed30cb9c6d86ca07286febeb44bf635cb23650.tar.bz2
scala-9fed30cb9c6d86ca07286febeb44bf635cb23650.zip
Warn about forgotten string interpolators.
In the compiler sources this arrives with a number of false positives, because we frequently work with strings containing $foo where foo is an in-scope identifier. I think in normal source code this will be less of a problem, or none at all; but to be conservative the warning is born under -Xlint.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala16
-rw-r--r--test/files/neg/forgot-interpolator.check9
-rw-r--r--test/files/neg/forgot-interpolator.flags1
-rw-r--r--test/files/neg/forgot-interpolator.scala15
5 files changed, 42 insertions, 1 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 91ebd798e1..2dbfa1d0d3 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -189,7 +189,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
val payload = pickledPayload.map{ case Assign(k, v) => (unpickleAtom(k), unpickleAtom(v)) }.toMap
val pickleVersionFormat = payload("versionFormat").asInstanceOf[Int]
- if (versionFormat != pickleVersionFormat) throw new Error("macro impl binding format mismatch: expected $versionFormat, actual $pickleVersionFormat")
+ if (versionFormat != pickleVersionFormat) throw new Error(s"macro impl binding format mismatch: expected $versionFormat, actual $pickleVersionFormat")
val className = payload("className").asInstanceOf[String]
val methodName = payload("methodName").asInstanceOf[String]
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index eaf57cd39c..33f1ed3386 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -86,6 +86,9 @@ trait Typers extends Adaptations with Tags {
// that are turned private by typedBlock
private final val SYNTHETIC_PRIVATE = TRANS_FLAG
+ private final val InterpolatorCodeRegex = """\$\{.*?\}""".r
+ private final val InterpolatorIdentRegex = """\$\w+""".r
+
// To enable decent error messages when the typer crashes.
// TODO - this only catches trees which go through def typed,
// but there are all kinds of back ways - typedClassDef, etc. etc.
@@ -5151,6 +5154,19 @@ trait Typers extends Adaptations with Tags {
def typedLiteral(tree: Literal) = {
val value = tree.value
+ // Warn about likely interpolated strings which are missing their interpolators
+ if (settings.lint.value) value match {
+ case Constant(s: String) =>
+ def names = InterpolatorIdentRegex findAllIn s map (n => newTermName(n stripPrefix "$"))
+ val shouldWarn = (
+ (InterpolatorCodeRegex findFirstIn s).nonEmpty
+ || (names exists (n => context.lookupSymbol(n, _ => true).symbol.exists))
+ )
+ if (shouldWarn)
+ unit.warning(tree.pos, "looks like an interpolated String; did you forget the interpolator?")
+ case _ =>
+ }
+
tree setType (
if (value.tag == UnitTag) UnitClass.tpe
else ConstantType(value))
diff --git a/test/files/neg/forgot-interpolator.check b/test/files/neg/forgot-interpolator.check
new file mode 100644
index 0000000000..f6de4d7b3a
--- /dev/null
+++ b/test/files/neg/forgot-interpolator.check
@@ -0,0 +1,9 @@
+forgot-interpolator.scala:4: warning: looks like an interpolated String; did you forget the interpolator?
+ def f = "Put the $bippy in the $bippy!" // warn
+ ^
+forgot-interpolator.scala:14: warning: looks like an interpolated String; did you forget the interpolator?
+ def f = """Put the ${println("bippy")} in the bippy!""" // warn
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+two warnings found
+one error found
diff --git a/test/files/neg/forgot-interpolator.flags b/test/files/neg/forgot-interpolator.flags
new file mode 100644
index 0000000000..7949c2afa2
--- /dev/null
+++ b/test/files/neg/forgot-interpolator.flags
@@ -0,0 +1 @@
+-Xlint -Xfatal-warnings
diff --git a/test/files/neg/forgot-interpolator.scala b/test/files/neg/forgot-interpolator.scala
new file mode 100644
index 0000000000..d67db82643
--- /dev/null
+++ b/test/files/neg/forgot-interpolator.scala
@@ -0,0 +1,15 @@
+class A {
+ val bippy = 123
+
+ def f = "Put the $bippy in the $bippy!" // warn
+}
+
+class B {
+ val dingus = 123
+
+ def f = "Put the $bippy in the $bippy!" // no warn
+}
+
+class C {
+ def f = """Put the ${println("bippy")} in the bippy!""" // warn
+}