From 9d9abffc94b28785e54bc2179b495d81f29b1e7f Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 14 Sep 2016 13:02:11 -0700 Subject: SI-8040 Improve unused warnings Add symbol names, don't warn for both getters and setters or for synthetics (except default arg getters). Tweak messages for readability. --- .../tools/nsc/typechecker/TypeDiagnostics.scala | 33 +++++++++--- test/files/neg/warn-unused-privates.check | 60 ++++++++++++++-------- test/files/neg/warn-unused-privates.scala | 36 +++++++++++++ 3 files changed, 101 insertions(+), 28 deletions(-) diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 36b9a65334..3cc896f3bd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -464,7 +464,9 @@ trait TypeDiagnostics { context.warning(pos, "imported `%s' is permanently hidden by definition of %s".format(hidden, defn.fullLocationString)) object checkUnused { - val ignoreNames: Set[TermName] = Set(TermName("readResolve"), TermName("readObject"), TermName("writeObject"), TermName("writeReplace")) + val ignoreNames: Set[TermName] = Set( + "readResolve", "readObject", "writeObject", "writeReplace" + ).map(TermName(_)) class UnusedPrivates extends Traverser { val defnTrees = ListBuffer[MemberDef]() @@ -523,8 +525,12 @@ trait TypeDiagnostics { && (m.isPrivate || m.isLocalToBlock) && !(treeTypes.exists(tp => tp exists (t => t.typeSymbolDirect == m))) ) + def isSyntheticWarnable(sym: Symbol) = ( + sym.isDefaultGetter + ) def isUnusedTerm(m: Symbol): Boolean = ( (m.isTerm) + && (!m.isSynthetic || isSyntheticWarnable(m)) && (m.isPrivate || m.isLocalToBlock) && !targets(m) && !(m.name == nme.WILDCARD) // e.g. val _ = foo @@ -533,7 +539,13 @@ trait TypeDiagnostics { && !treeTypes.exists(_ contains m) // e.g. val a = new Foo ; new a.Bar ) def unusedTypes = defnTrees.toList filter (t => isUnusedType(t.symbol)) - def unusedTerms = defnTrees.toList filter (v => isUnusedTerm(v.symbol)) + def unusedTerms = { + val all = defnTrees.toList.filter(v => isUnusedTerm(v.symbol)) + // filter out setters if already warning for getter, indicated by position + if (all.exists(_.symbol.isSetter)) + all.filterNot(v => v.symbol.isSetter && all.exists(g => g.symbol.isGetter && g.symbol.pos.point == v.symbol.pos.point)) + else all + } // local vars which are never set, except those already returned in unused def unsetVars = localVars filter (v => !setVars(v) && !isUnusedTerm(v)) } @@ -556,11 +568,18 @@ trait TypeDiagnostics { val what = ( if (sym.isDefaultGetter) "default argument" else if (sym.isConstructor) "constructor" - else if (sym.isVar || sym.isGetter && (sym.accessed.isVar || (sym.owner.isTrait && !sym.hasFlag(STABLE)))) "var" - else if (sym.isVal || sym.isGetter && (sym.accessed.isVal || (sym.owner.isTrait && sym.hasFlag(STABLE))) || sym.isLazy) "val" - else if (sym.isSetter) "setter" - else if (sym.isMethod) "method" - else if (sym.isModule) "object" + else if ( + sym.isVar + || sym.isGetter && (sym.accessed.isVar || (sym.owner.isTrait && !sym.hasFlag(STABLE))) + ) s"var ${sym.name.getterName.decoded}" + else if ( + sym.isVal + || sym.isGetter && (sym.accessed.isVal || (sym.owner.isTrait && sym.hasFlag(STABLE))) + || sym.isLazy + ) s"val ${sym.name.decoded}" + else if (sym.isSetter) s"setter of ${sym.name.getterName.decoded}" + else if (sym.isMethod) s"method ${sym.name.decoded}" + else if (sym.isModule) s"object ${sym.name.decoded}" else "term" ) reporter.warning(pos, s"$why $what in ${sym.owner} is never used") diff --git a/test/files/neg/warn-unused-privates.check b/test/files/neg/warn-unused-privates.check index 2e93f338bb..6e1511d0e5 100644 --- a/test/files/neg/warn-unused-privates.check +++ b/test/files/neg/warn-unused-privates.check @@ -1,66 +1,84 @@ warn-unused-privates.scala:2: warning: private constructor in class Bippy is never used private def this(c: Int) = this(c, c) // warn ^ -warn-unused-privates.scala:4: warning: private method in class Bippy is never used +warn-unused-privates.scala:4: warning: private method boop in class Bippy is never used private def boop(x: Int) = x+a+b // warn ^ -warn-unused-privates.scala:6: warning: private val in class Bippy is never used +warn-unused-privates.scala:6: warning: private val MILLIS2 in class Bippy is never used final private val MILLIS2: Int = 1000 // warn ^ -warn-unused-privates.scala:13: warning: private val in object Bippy is never used +warn-unused-privates.scala:13: warning: private val HEY_INSTANCE in object Bippy is never used private val HEY_INSTANCE: Int = 1000 // warn ^ -warn-unused-privates.scala:14: warning: private val in object Bippy is never used +warn-unused-privates.scala:14: warning: private val BOOL in object Bippy is never used private lazy val BOOL: Boolean = true // warn ^ -warn-unused-privates.scala:36: warning: private val in class Boppy is never used +warn-unused-privates.scala:36: warning: private val hummer in class Boppy is never used private val hummer = "def" // warn ^ -warn-unused-privates.scala:43: warning: private var in trait Accessors is never used +warn-unused-privates.scala:43: warning: private var v1 in trait Accessors is never used private var v1: Int = 0 // warn ^ -warn-unused-privates.scala:44: warning: private var in trait Accessors is never used +warn-unused-privates.scala:44: warning: private var v2 in trait Accessors is never used private var v2: Int = 0 // warn, never set ^ -warn-unused-privates.scala:45: warning: private var in trait Accessors is never used +warn-unused-privates.scala:45: warning: private var v3 in trait Accessors is never used private var v3: Int = 0 // warn, never got ^ -warn-unused-privates.scala:57: warning: private default argument in trait DefaultArgs is never used +warn-unused-privates.scala:56: warning: private var s1 in class StableAccessors is never used + private var s1: Int = 0 // warn + ^ +warn-unused-privates.scala:57: warning: private setter of s2 in class StableAccessors is never used + private var s2: Int = 0 // warn, never set + ^ +warn-unused-privates.scala:58: warning: private var s3 in class StableAccessors is never used + private var s3: Int = 0 // warn, never got + ^ +warn-unused-privates.scala:70: warning: private default argument in trait DefaultArgs is never used private def bippy(x1: Int, x2: Int = 10, x3: Int = 15): Int = x1 + x2 + x3 ^ -warn-unused-privates.scala:57: warning: private default argument in trait DefaultArgs is never used +warn-unused-privates.scala:70: warning: private default argument in trait DefaultArgs is never used private def bippy(x1: Int, x2: Int = 10, x3: Int = 15): Int = x1 + x2 + x3 ^ -warn-unused-privates.scala:68: warning: local var in method f0 is never used +warn-unused-privates.scala:86: warning: local var x in method f0 is never used var x = 1 // warn ^ -warn-unused-privates.scala:75: warning: local val in method f1 is never used +warn-unused-privates.scala:93: warning: local val b in method f1 is never used val b = new Outer // warn ^ -warn-unused-privates.scala:85: warning: private object in object Types is never used +warn-unused-privates.scala:103: warning: private object Dongo in object Types is never used private object Dongo { def f = this } // warn ^ -warn-unused-privates.scala:95: warning: local object in method l1 is never used +warn-unused-privates.scala:113: warning: local object HiObject in method l1 is never used object HiObject { def f = this } // warn ^ -warn-unused-privates.scala:79: warning: local var x in method f2 is never set - it could be a val +warn-unused-privates.scala:136: warning: private method x_= in class OtherNames is never used + private def x_=(i: Int): Unit = ??? + ^ +warn-unused-privates.scala:137: warning: private method x in class OtherNames is never used + private def x: Int = 42 + ^ +warn-unused-privates.scala:138: warning: private method y_= in class OtherNames is never used + private def y_=(i: Int): Unit = ??? + ^ +warn-unused-privates.scala:97: warning: local var x in method f2 is never set - it could be a val var x = 100 // warn about it being a var ^ -warn-unused-privates.scala:86: warning: private class Bar1 in object Types is never used +warn-unused-privates.scala:104: warning: private class Bar1 in object Types is never used private class Bar1 // warn ^ -warn-unused-privates.scala:88: warning: private type Alias1 in object Types is never used +warn-unused-privates.scala:106: warning: private type Alias1 in object Types is never used private type Alias1 = String // warn ^ -warn-unused-privates.scala:96: warning: local class Hi is never used +warn-unused-privates.scala:114: warning: local class Hi is never used class Hi { // warn ^ -warn-unused-privates.scala:100: warning: local class DingDongDoobie is never used +warn-unused-privates.scala:118: warning: local class DingDongDoobie is never used class DingDongDoobie // warn ^ -warn-unused-privates.scala:103: warning: local type OtherThing is never used +warn-unused-privates.scala:121: warning: local type OtherThing is never used type OtherThing = String // warn ^ error: No warnings can be incurred under -Xfatal-warnings. -21 warnings found +27 warnings found one error found diff --git a/test/files/neg/warn-unused-privates.scala b/test/files/neg/warn-unused-privates.scala index 2eda280d40..2f67882632 100644 --- a/test/files/neg/warn-unused-privates.scala +++ b/test/files/neg/warn-unused-privates.scala @@ -52,6 +52,19 @@ trait Accessors { } } +class StableAccessors { + private var s1: Int = 0 // warn + private var s2: Int = 0 // warn, never set + private var s3: Int = 0 // warn, never got + private var s4: Int = 0 // no warn + + def bippy(): Int = { + s3 = 5 + s4 = 6 + s2 + s4 + } +} + trait DefaultArgs { // warn about default getters for x2 and x3 private def bippy(x1: Int, x2: Int = 10, x3: Int = 15): Int = x1 + x2 + x3 @@ -59,6 +72,11 @@ trait DefaultArgs { def boppy() = bippy(5, 100, 200) } +/* SI-7707 Both usages warn default arg because using PrivateRyan.apply, not new. +case class PrivateRyan private (ryan: Int = 42) { def f = PrivateRyan() } +object PrivateRyan { def f = PrivateRyan() } +*/ + class Outer { class Inner } @@ -104,3 +122,21 @@ object Types { (new Bippy): Something } } + +trait Underwarn { + def f(): Seq[Int] + + def g() = { + val Seq(_, _) = f() // no warn + true + } +} + +class OtherNames { + private def x_=(i: Int): Unit = ??? + private def x: Int = 42 + private def y_=(i: Int): Unit = ??? + private def y: Int = 42 + + def f = y +} -- cgit v1.2.3