Skip to content

Commit 17df646

Browse files
exoegoexoego
exoego
authored andcommitted
Use the same logic how scala.js compiler identify default parameter
1 parent 87f7052 commit 17df646

File tree

1 file changed

+79
-4
lines changed
  • scalac-scoverage-plugin/src/main/scala/scoverage

1 file changed

+79
-4
lines changed

scalac-scoverage-plugin/src/main/scala/scoverage/plugin.scala

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,85 @@ class ScoverageInstrumentationComponent(val global: Global, extraAfterPhase: Opt
237237
}
238238
}
239239

240-
def isUndefinedParameterInScalaJs(symbol: Symbol): Boolean = {
241-
isScalaJsEnabled && symbol != null && symbol.isSynthetic && symbol.isMethod &&
242-
symbol.nameString.contains("$default$") &&
243-
symbol.tpe.resultType.annotations.exists(_.symbol.nameString == "uncheckedVariance")
240+
// Copied from
241+
// https://github.com/scala-js/scala-js/blob/4619d906baef7feb5d0b6d555d5b33044669434e/compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala#L2696-L2721
242+
private def isJSDefaultParam(sym: Symbol): Boolean = {
243+
if (isCtorDefaultParam(sym)) {
244+
isJSCtorDefaultParam(sym)
245+
} else {
246+
sym.hasFlag(reflect.internal.Flags.DEFAULTPARAM) &&
247+
isJSType(sym.owner) && {
248+
/* If this is a default parameter accessor on a
249+
* non-native JS class, we need to know if the method for which we
250+
* are the default parameter is exposed or not.
251+
* We do this by removing the $default suffix from the method name,
252+
* and looking up a member with that name in the owner.
253+
* Note that this does not work for local methods. But local methods
254+
* are never exposed.
255+
* Further note that overloads are easy, because either all or none
256+
* of them are exposed.
257+
*/
258+
def isAttachedMethodExposed = {
259+
val methodName = nme.defaultGetterToMethod(sym.name)
260+
val ownerMethod = sym.owner.info.decl(methodName)
261+
ownerMethod.filter(isExposed).exists
262+
}
263+
264+
!isNonNativeJSClass(sym.owner) || isAttachedMethodExposed
265+
}
266+
}
267+
}
268+
269+
private lazy val JSTypeAnnot = rootMirror.getRequiredClass("scala.scalajs.js.annotation.internal.JSType")
270+
private lazy val ExposedJSMemberAnnot = rootMirror.getRequiredClass("scala.scalajs.js.annotation.internal.ExposedJSMember")
271+
private lazy val JSNativeAnnotation = rootMirror.getRequiredClass("scala.scalajs.js.native")
272+
273+
private def isJSType(sym: Symbol): Boolean =
274+
sym.hasAnnotation(JSTypeAnnot)
275+
276+
def isNonNativeJSClass(sym: Symbol): Boolean =
277+
!sym.isTrait && isJSType(sym) && !sym.hasAnnotation(JSNativeAnnotation)
278+
279+
private def isExposed(sym: Symbol): Boolean = {
280+
!sym.isBridge && {
281+
if (sym.isLazy)
282+
sym.isAccessor && sym.accessed.hasAnnotation(ExposedJSMemberAnnot)
283+
else
284+
sym.hasAnnotation(ExposedJSMemberAnnot)
285+
}
286+
}
287+
288+
private def isJSCtorDefaultParam(sym: Symbol) = {
289+
isCtorDefaultParam(sym) &&
290+
isJSType(patchedLinkedClassOfClass(sym.owner))
291+
}
292+
293+
private def patchedLinkedClassOfClass(sym: Symbol): Symbol = {
294+
/* Work around a bug of scalac with linkedClassOfClass where package
295+
* objects are involved (the companion class would somehow exist twice
296+
* in the scope, making an assertion fail in Symbol.suchThat).
297+
* Basically this inlines linkedClassOfClass up to companionClass,
298+
* then replaces the `suchThat` by a `filter` and `head`.
299+
*/
300+
val flatOwnerInfo = {
301+
// inline Symbol.flatOwnerInfo because it is protected
302+
if (sym.needsFlatClasses)
303+
sym.info
304+
sym.owner.rawInfo
305+
}
306+
val result = flatOwnerInfo.decl(sym.name).filter(_ isCoDefinedWith sym)
307+
if (!result.isOverloaded) result
308+
else result.alternatives.head
309+
}
310+
311+
private def isCtorDefaultParam(sym: Symbol) = {
312+
sym.hasFlag(reflect.internal.Flags.DEFAULTPARAM) &&
313+
sym.owner.isModuleClass &&
314+
nme.defaultGetterToMethod(sym.name) == nme.CONSTRUCTOR
315+
}
316+
317+
def isUndefinedParameterInScalaJs(sym: Symbol): Boolean = {
318+
isScalaJsEnabled && sym != null && isJSDefaultParam(sym)
244319
}
245320
def isClassIncluded(symbol: Symbol): Boolean = coverageFilter.isClassIncluded(symbol.fullNameString)
246321
def isFileIncluded(source: SourceFile): Boolean = coverageFilter.isFileIncluded(source)

0 commit comments

Comments
 (0)