diff options
author | Miguel Garcia <miguelalfredo.garcia@epfl.ch> | 2013-05-22 21:17:18 +0200 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2013-05-26 19:13:57 -0700 |
commit | b7add1517bc888ac55c2e2e34d456a3fd17bbe0d (patch) | |
tree | 7178f6c4219e7f318d83f28203b135b82d845f21 | |
parent | ac6504b8c43b83e43072d76d9a6fae0993f88d8e (diff) | |
download | scala-b7add1517bc888ac55c2e2e34d456a3fd17bbe0d.tar.gz scala-b7add1517bc888ac55c2e2e34d456a3fd17bbe0d.tar.bz2 scala-b7add1517bc888ac55c2e2e34d456a3fd17bbe0d.zip |
warn about uninitialized reads (in constructors), self-contained check
The check in question relies on helper maps and methods that don't
belong outside that check. This commit encapsulates those helpers into
the newly added `checkUninitializedReads()` , thus uncluttering
`transformClassTemplate()`
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Constructors.scala | 84 |
1 files changed, 47 insertions, 37 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 5079108c27..77c2d13b78 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -34,41 +34,6 @@ abstract class Constructors extends Transform with ast.TreeDSL { val stats = impl.body // the transformed template body val localTyper = typer.atOwner(impl, clazz) - // Inspect for obvious out-of-order initialization; concrete, eager vals or vars, - // declared in this class, for which a reference to the member precedes its definition. - def checkableForInit(sym: Symbol) = ( - (sym ne null) - && (sym.isVal || sym.isVar) - && !(sym hasFlag LAZY | DEFERRED | SYNTHETIC) - ) - val uninitializedVals = mutable.Set[Symbol]( - stats collect { case vd: ValDef if checkableForInit(vd.symbol) => vd.symbol.accessedOrSelf }: _* - ) - if (uninitializedVals.nonEmpty) - log("Checking constructor for init order issues among: " + uninitializedVals.map(_.name).mkString(", ")) - - for (stat <- stats) { - // Checking the qualifier symbol is necessary to prevent a selection on - // another instance of the same class from potentially appearing to be a forward - // reference on the member in the current class. - def check(tree: Tree) = { - for (t <- tree) t match { - case t: RefTree if uninitializedVals(t.symbol.accessedOrSelf) && t.qualifier.symbol == clazz => - unit.warning(t.pos, s"Reference to uninitialized ${t.symbol.accessedOrSelf}") - case _ => - } - } - stat match { - case vd: ValDef => - // doing this first allows self-referential vals, which to be a conservative - // warner we will do because it's possible though difficult for it to be useful. - uninitializedVals -= vd.symbol.accessedOrSelf - if (!vd.symbol.isLazy) - check(vd.rhs) - case _: MemberDef => // skip other member defs - case t => check(t) // constructor body statement - } - } val specializedFlag: Symbol = clazz.info.decl(nme.SPECIALIZED_INSTANCE) val shouldGuard = (specializedFlag != NoSymbol) && !clazz.hasFlag(SPECIALIZED) @@ -582,10 +547,55 @@ abstract class Constructors extends Transform with ast.TreeDSL { deriveTemplate(impl)(_ => defBuf.toList filter (stat => mustbeKept(stat.symbol))) } // transformClassTemplate + /* + * Inspect for obvious out-of-order initialization; concrete, eager vals or vars, declared in this class, + * for which a reference to the member precedes its definition. + */ + private def checkUninitializedReads(cd: ClassDef) { + val stats = cd.impl.body + val clazz = cd.symbol + + def checkableForInit(sym: Symbol) = ( + (sym ne null) + && (sym.isVal || sym.isVar) + && !(sym hasFlag LAZY | DEFERRED | SYNTHETIC) + ) + val uninitializedVals = mutable.Set[Symbol]( + stats collect { case vd: ValDef if checkableForInit(vd.symbol) => vd.symbol.accessedOrSelf }: _* + ) + if (uninitializedVals.nonEmpty) + log("Checking constructor for init order issues among: " + uninitializedVals.map(_.name).mkString(", ")) + + for (stat <- stats) { + // Checking the qualifier symbol is necessary to prevent a selection on + // another instance of the same class from potentially appearing to be a forward + // reference on the member in the current class. + def check(tree: Tree) = { + for (t <- tree) t match { + case t: RefTree if uninitializedVals(t.symbol.accessedOrSelf) && t.qualifier.symbol == clazz => + unit.warning(t.pos, s"Reference to uninitialized ${t.symbol.accessedOrSelf}") + case _ => + } + } + stat match { + case vd: ValDef => + // doing this first allows self-referential vals, which to be a conservative + // warner we will do because it's possible though difficult for it to be useful. + uninitializedVals -= vd.symbol.accessedOrSelf + if (!vd.symbol.isLazy) + check(vd.rhs) + case _: MemberDef => // skip other member defs + case t => check(t) // constructor body statement + } + } + + } // end of checkUninitializedReads() + override def transform(tree: Tree): Tree = { tree match { - case ClassDef(_,_,_,_) if !tree.symbol.isInterface && !isPrimitiveValueClass(tree.symbol) => - deriveClassDef(tree)(transformClassTemplate) + case cd : ClassDef if !cd.symbol.isInterface && !isPrimitiveValueClass(cd.symbol) => + checkUninitializedReads(cd) + deriveClassDef(cd)(transformClassTemplate) case _ => super.transform(tree) } |