From e3b0c7abbf637dacce7bcd7b69d5655820e8e714 Mon Sep 17 00:00:00 2001 From: Simon Ochsenreither Date: Tue, 31 Jul 2012 01:02:07 +0200 Subject: SI-6162 Adds @deprecatedInheritance/@deprecatedOverriding These annotations are meant to warn from inheriting a class or from overriding a member, due to the reasons given in `msg`. The naming and placement of the methods is in line with @deprecated and @deprecatedName. --- .../scala/tools/nsc/typechecker/RefChecks.scala | 11 +++++++++++ .../scala/tools/nsc/typechecker/Typers.scala | 9 +++++++++ src/library/scala/deprecatedInheritance.scala | 20 ++++++++++++++++++++ src/library/scala/deprecatedOverriding.scala | 19 +++++++++++++++++++ src/reflect/scala/reflect/internal/Definitions.scala | 2 ++ src/reflect/scala/reflect/internal/Symbols.scala | 12 ++++++++++++ test/files/neg/t6162-inheritance.check | 4 ++++ test/files/neg/t6162-inheritance.flags | 1 + test/files/neg/t6162-inheritance.scala | 4 ++++ test/files/neg/t6162-overriding.check | 4 ++++ test/files/neg/t6162-overriding.flags | 1 + test/files/neg/t6162-overriding.scala | 8 ++++++++ 12 files changed, 95 insertions(+) create mode 100644 src/library/scala/deprecatedInheritance.scala create mode 100644 src/library/scala/deprecatedOverriding.scala create mode 100644 test/files/neg/t6162-inheritance.check create mode 100644 test/files/neg/t6162-inheritance.flags create mode 100644 test/files/neg/t6162-inheritance.scala create mode 100644 test/files/neg/t6162-overriding.check create mode 100644 test/files/neg/t6162-overriding.flags create mode 100644 test/files/neg/t6162-overriding.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 166bb2d18c..919250c562 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -430,6 +430,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R overrideError("cannot override a macro") } else { checkOverrideTypes() + checkOverrideDeprecated() if (settings.warnNullaryOverride.value) { if (other.paramss.isEmpty && !member.paramss.isEmpty) { unit.warning(member.pos, "non-nullary method overrides nullary method") @@ -508,6 +509,16 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R } } } + + def checkOverrideDeprecated() { + if (other.hasDeprecatedOverridingAnnotation) { + val msg = + member.toString + member.locationString + " overrides " + other.toString + other.locationString + + ", but overriding this member is deprecated" + + other.deprecatedOverridingMessage.map(": " + _).getOrElse(".") + unit.deprecationWarning(member.pos, msg) + } + } } val opc = new overridingPairs.Cursor(clazz) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9cf5d42e00..df97e451d1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1577,6 +1577,15 @@ trait Typers extends Modes with Adaptations with Tags { if (psym.isFinal) pending += ParentFinalInheritanceError(parent, psym) + if (psym.hasDeprecatedInheritanceAnnotation) { + val sym = selfType.typeSymbol + val msg = + sym.toString + sym.locationString + " inherits from " + psym.toString + psym.locationString + + ", but inheriting from that class is deprecated" + + psym.deprecatedInheritanceMessage.map(": " + _).getOrElse(".") + unit.deprecationWarning(sym.pos, msg) + } + if (psym.isSealed && !phase.erasedTypes) if (context.unit.source.file == psym.sourceFile) psym addChild context.owner diff --git a/src/library/scala/deprecatedInheritance.scala b/src/library/scala/deprecatedInheritance.scala new file mode 100644 index 0000000000..c461f6737c --- /dev/null +++ b/src/library/scala/deprecatedInheritance.scala @@ -0,0 +1,20 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2012, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +/** An annotation that designates that inheriting from a class is deprecated. + * + * This is usually done to warn about a non-final class being made final in a future version. + * Sub-classing such a class then generates a warning. + * + * @param message the message to print during compilation if the class was sub-classed + * @param since a string identifying the first version in which inheritance was deprecated + * @since 2.10 + */ +class deprecatedInheritance(message: String = "", since: String = "") extends annotation.StaticAnnotation \ No newline at end of file diff --git a/src/library/scala/deprecatedOverriding.scala b/src/library/scala/deprecatedOverriding.scala new file mode 100644 index 0000000000..9048d5d32d --- /dev/null +++ b/src/library/scala/deprecatedOverriding.scala @@ -0,0 +1,19 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2012, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +/** An annotation that designates that overriding a member is deprecated. + * + * Overriding such a member in a sub-class then generates a warning. + * + * @param message the message to print during compilation if the member was overridden + * @param since a string identifying the first version in which overriding was deprecated + * @since 2.10 + */ +class deprecatedOverriding(message: String = "", since: String = "") extends annotation.StaticAnnotation \ No newline at end of file diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index c21ebfe997..556fcee64f 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -940,6 +940,8 @@ trait Definitions extends api.StandardDefinitions { lazy val CloneableAttr = requiredClass[scala.annotation.cloneable] lazy val DeprecatedAttr = requiredClass[scala.deprecated] lazy val DeprecatedNameAttr = requiredClass[scala.deprecatedName] + lazy val DeprecatedInheritanceAttr = requiredClass[scala.deprecatedInheritance] + lazy val DeprecatedOverridingAttr = requiredClass[scala.deprecatedOverriding] lazy val NativeAttr = requiredClass[scala.native] lazy val RemoteAttr = requiredClass[scala.remote] lazy val ScalaInlineClass = requiredClass[scala.inline] diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 3548657c04..e75079a6ff 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -697,6 +697,18 @@ trait Symbols extends api.Symbols { self: SymbolTable => def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0) def deprecationVersion = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 1) def deprecatedParamName = getAnnotation(DeprecatedNameAttr) flatMap (_ symbolArg 0) + def hasDeprecatedInheritanceAnnotation + = hasAnnotation(DeprecatedInheritanceAttr) + def deprecatedInheritanceMessage + = getAnnotation(DeprecatedInheritanceAttr) flatMap (_ stringArg 0) + def deprecatedInheritanceVersion + = getAnnotation(DeprecatedInheritanceAttr) flatMap (_ stringArg 1) + def hasDeprecatedOverridingAnnotation + = hasAnnotation(DeprecatedOverridingAttr) + def deprecatedOverridingMessage + = getAnnotation(DeprecatedOverridingAttr) flatMap (_ stringArg 0) + def deprecatedOverridingVersion + = getAnnotation(DeprecatedOverridingAttr) flatMap (_ stringArg 1) // !!! when annotation arguments are not literal strings, but any sort of // assembly of strings, there is a fair chance they will turn up here not as diff --git a/test/files/neg/t6162-inheritance.check b/test/files/neg/t6162-inheritance.check new file mode 100644 index 0000000000..69112d7f86 --- /dev/null +++ b/test/files/neg/t6162-inheritance.check @@ -0,0 +1,4 @@ +t6162-inheritance.scala:4: error: class SubFoo inherits from class Foo, but inheriting from that class is deprecated: `Foo` will be made final in a future version. +class SubFoo extends Foo + ^ +one error found \ No newline at end of file diff --git a/test/files/neg/t6162-inheritance.flags b/test/files/neg/t6162-inheritance.flags new file mode 100644 index 0000000000..65faf53579 --- /dev/null +++ b/test/files/neg/t6162-inheritance.flags @@ -0,0 +1 @@ +-Xfatal-warnings -deprecation \ No newline at end of file diff --git a/test/files/neg/t6162-inheritance.scala b/test/files/neg/t6162-inheritance.scala new file mode 100644 index 0000000000..67bd4466c3 --- /dev/null +++ b/test/files/neg/t6162-inheritance.scala @@ -0,0 +1,4 @@ +@deprecatedInheritance("`Foo` will be made final in a future version.", "2.10.0") +class Foo + +class SubFoo extends Foo \ No newline at end of file diff --git a/test/files/neg/t6162-overriding.check b/test/files/neg/t6162-overriding.check new file mode 100644 index 0000000000..14221ddc63 --- /dev/null +++ b/test/files/neg/t6162-overriding.check @@ -0,0 +1,4 @@ +t6162-overriding.scala:7: error: method bar in class SubBar overrides method bar in class Bar, but overriding this member is deprecated: `bar` will be made private in a future version. + override def bar = 43 + ^ +one error found diff --git a/test/files/neg/t6162-overriding.flags b/test/files/neg/t6162-overriding.flags new file mode 100644 index 0000000000..65faf53579 --- /dev/null +++ b/test/files/neg/t6162-overriding.flags @@ -0,0 +1 @@ +-Xfatal-warnings -deprecation \ No newline at end of file diff --git a/test/files/neg/t6162-overriding.scala b/test/files/neg/t6162-overriding.scala new file mode 100644 index 0000000000..4907dbb075 --- /dev/null +++ b/test/files/neg/t6162-overriding.scala @@ -0,0 +1,8 @@ +class Bar { + @deprecatedOverriding("`bar` will be made private in a future version.", "2.10.0") + def bar = 42 +} + +class SubBar extends Bar { + override def bar = 43 +} \ No newline at end of file -- cgit v1.2.3