From 9fed30cb9c6d86ca07286febeb44bf635cb23650 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 11 Mar 2013 22:11:19 -0700 Subject: 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. --- src/compiler/scala/tools/nsc/typechecker/Macros.scala | 2 +- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 16 ++++++++++++++++ test/files/neg/forgot-interpolator.check | 9 +++++++++ test/files/neg/forgot-interpolator.flags | 1 + test/files/neg/forgot-interpolator.scala | 15 +++++++++++++++ 5 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 test/files/neg/forgot-interpolator.check create mode 100644 test/files/neg/forgot-interpolator.flags create mode 100644 test/files/neg/forgot-interpolator.scala 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 +} -- cgit v1.2.3