@@ -3,6 +3,7 @@ package dotc
3
3
package transform
4
4
5
5
import core .*
6
+ import Annotations .Annotation
6
7
import Symbols .* , Types .* , Contexts .* , Flags .* , Decorators .* , reporting .*
7
8
import util .SrcPos
8
9
import config .{ScalaVersion , NoScalaVersion , Feature , ScalaRelease }
@@ -161,29 +162,42 @@ object CrossVersionChecks:
161
162
162
163
/** If @deprecated is present, and the point of reference is not enclosed
163
164
* in either a deprecated member or a scala bridge method, issue a warning.
165
+ *
166
+ * Also check for deprecation of the companion class for synthetic methods in the companion module.
164
167
*/
165
168
private [CrossVersionChecks ] def checkDeprecatedRef (sym : Symbol , pos : SrcPos )(using Context ): Unit =
166
-
167
- // Also check for deprecation of the companion class for synthetic methods
168
- val toCheck = sym :: (if sym.isAllOf(SyntheticMethod ) then sym.owner.companionClass :: Nil else Nil )
169
- for sym <- toCheck; annot <- sym.getAnnotation(defn.DeprecatedAnnot ) do
170
- if ! skipWarning(sym) then
171
- val msg = annot.argumentConstant(0 ).map(" : " + _.stringValue).getOrElse(" " )
172
- val since = annot.argumentConstant(1 ).map(" since " + _.stringValue).getOrElse(" " )
173
- report.deprecationWarning(em " ${sym.showLocated} is deprecated ${since}${msg}" , pos)
174
-
175
- /** Skip warnings for synthetic members of case classes during declaration and
176
- * scan the chain of outer declaring scopes from the current context
177
- * a deprecation warning will be skipped if one the following holds
178
- * for a given declaring scope:
179
- * - the symbol associated with the scope is also deprecated.
180
- * - if and only if `sym` is an enum case, the scope is either
181
- * a module that declares `sym`, or the companion class of the
182
- * module that declares `sym`.
169
+ def maybeWarn (annotee : Symbol , annot : Annotation ) = if ! skipWarning(sym) then
170
+ val message = annot.argumentConstantString(0 ).filter(! _.isEmpty).map(" : " + _).getOrElse(" " )
171
+ val since = annot.argumentConstantString(1 ).filter(! _.isEmpty).map(" since " + _).getOrElse(" " )
172
+ report.deprecationWarning(em " ${annotee.showLocated} is deprecated ${since}${message}" , pos)
173
+ sym.getAnnotation(defn.DeprecatedAnnot ) match
174
+ case Some (annot) => maybeWarn(sym, annot)
175
+ case _ =>
176
+ if sym.isAllOf(SyntheticMethod ) then
177
+ val companion = sym.owner.companionClass
178
+ if companion.is(CaseClass ) then companion.getAnnotation(defn.DeprecatedAnnot ).foreach(maybeWarn(companion, _))
179
+
180
+ /** Decide whether the deprecation of `sym` should be ignored in this context.
181
+ *
182
+ * The warning is skipped if any symbol in the context owner chain is deprecated,
183
+ * that is, an enclosing scope is associated with a deprecated symbol.
184
+ *
185
+ * Further exclusions are needed for enums and case classes,
186
+ * since they typically need to refer to deprecated members
187
+ * even if the enclosing enum or case class is not deprecated.
188
+ *
189
+ * If and only if `sym` is an enum case, the warning is skipped
190
+ * if an enclosing scope is either a module that declares `sym`,
191
+ * or the companion class of the module that declares `sym`.
192
+ *
193
+ * For a deprecated case class or case class element,
194
+ * the warning is skipped for synthetic sites where the enclosing
195
+ * class (or its companion) is either the deprecated case class
196
+ * or the case class of the deprecated element.
183
197
*/
184
198
private def skipWarning (sym : Symbol )(using Context ): Boolean =
185
199
186
- /** is the owner an enum or its companion and also the owner of sym */
200
+ // is the owner an enum or its companion and also the owner of sym
187
201
def isEnumOwner (owner : Symbol )(using Context ) =
188
202
// pre: sym is an enumcase
189
203
if owner.isEnumClass then owner.companionClass eq sym.owner
@@ -194,6 +208,19 @@ object CrossVersionChecks:
194
208
// pre: sym is an enumcase
195
209
owner.isDeprecated || isEnumOwner(owner)
196
210
197
- (ctx.owner.is(Synthetic ) && sym.is(CaseClass ))
198
- || ctx.owner.ownersIterator.exists(if sym.isEnumCase then isDeprecatedOrEnum else _.isDeprecated)
211
+ def siteIsEnclosedByDeprecatedElement =
212
+ ctx.owner.ownersIterator.exists:
213
+ if sym.isEnumCase then isDeprecatedOrEnum else _.isDeprecated
214
+
215
+ def siteIsSyntheticCaseClassMember =
216
+ val owner = ctx.owner
217
+ def symIsCaseOrMember =
218
+ val enclosing = owner.enclosingClass
219
+ val companion = enclosing.companionClass
220
+ // deprecated sym is either enclosing case class or a sibling member
221
+ def checkSym (k : Symbol ) = sym == k || sym.owner == k
222
+ (enclosing.is(CaseClass ) || companion.is(CaseClass )) && (checkSym(enclosing) || checkSym(companion))
223
+ owner.is(Synthetic ) && symIsCaseOrMember
224
+
225
+ siteIsSyntheticCaseClassMember || siteIsEnclosedByDeprecatedElement
199
226
end skipWarning
0 commit comments