"Fossies" - the Fresh Open Source Software Archive

Member "scala-js-1.3.1/linker/shared/src/test/scala/org/scalajs/linker/AnalyzerTest.scala" (14 Nov 2020, 27144 Bytes) of package /linux/www/scala-js-1.3.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Scala source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "AnalyzerTest.scala": 1.2.0_vs_1.3.0.

    1 /*
    2  * Scala.js (https://www.scala-js.org/)
    3  *
    4  * Copyright EPFL.
    5  *
    6  * Licensed under Apache License 2.0
    7  * (https://www.apache.org/licenses/LICENSE-2.0).
    8  *
    9  * See the NOTICE file distributed with this work for
   10  * additional information regarding copyright ownership.
   11  */
   12 
   13 package org.scalajs.linker
   14 
   15 import scala.concurrent._
   16 
   17 import org.junit.Test
   18 import org.junit.Assert._
   19 
   20 import org.scalajs.ir.ClassKind
   21 import org.scalajs.ir.EntryPointsInfo
   22 import org.scalajs.ir.Names._
   23 import org.scalajs.ir.Trees._
   24 import org.scalajs.ir.Types._
   25 
   26 import org.scalajs.junit.async._
   27 
   28 import org.scalajs.logging.NullLogger
   29 import org.scalajs.linker._
   30 import org.scalajs.linker.analyzer._
   31 import org.scalajs.linker.frontend.IRLoader
   32 import org.scalajs.linker.interface._
   33 import org.scalajs.linker.standard._
   34 import org.scalajs.linker.standard.ModuleSet.ModuleID
   35 
   36 import Analysis._
   37 
   38 import org.scalajs.linker.testutils._
   39 import org.scalajs.linker.testutils.TestIRBuilder._
   40 
   41 class AnalyzerTest {
   42   import scala.concurrent.ExecutionContext.Implicits.global
   43   import AnalyzerTest._
   44 
   45   @Test
   46   def trivialOK(): AsyncResult = await {
   47     val analysis = computeAnalysis(Nil)
   48     assertNoError(analysis)
   49   }
   50 
   51   @Test
   52   def missingJavaLangObject(): AsyncResult = await {
   53     val analysis = computeAnalysis(Nil, stdlib = TestIRRepo.empty)
   54     assertExactErrors(analysis, MissingJavaLangObjectClass(fromAnalyzer))
   55   }
   56 
   57   @Test
   58   def invalidJavaLangObject(): AsyncResult = await {
   59     val invalidJLObjectDefs = Seq(
   60         // j.l.Object cannot have a super class
   61         classDef(ObjectClass, superClass = Some("Parent")),
   62         // j.l.Object must have kind == ClassKind.Class
   63         classDef(ObjectClass, kind = ClassKind.ModuleClass),
   64         // j.l.Object cannot extend any interface
   65         classDef(ObjectClass, interfaces = List("Parent"))
   66     )
   67 
   68     Future.traverse(invalidJLObjectDefs) { jlObjectDef =>
   69       val analysis = computeAnalysis(Seq(jlObjectDef), stdlib = TestIRRepo.empty)
   70       assertExactErrors(analysis,
   71           InvalidJavaLangObjectClass(fromAnalyzer))
   72     }
   73   }
   74 
   75   @Test
   76   def cycleInInheritanceChainThroughParentClasses(): AsyncResult = await {
   77     val classDefs = Seq(
   78         classDef("A", superClass = Some("B")),
   79         classDef("B", superClass = Some("A"))
   80     )
   81 
   82     val analysis = computeAnalysis(classDefs, reqsFactory.classData("A"))
   83 
   84     assertContainsError("CycleInInheritanceChain(A, B)", analysis) {
   85       case CycleInInheritanceChain(List(ClsName("A"), ClsName("B")), `fromAnalyzer`) => true
   86     }
   87   }
   88 
   89   @Test
   90   def cycleInInheritanceChainThroughInterfaces(): AsyncResult = await {
   91     val classDefs = Seq(
   92         classDef("A", superClass = Some("B")),
   93         classDef("B", superClass = Some(ObjectClass), interfaces = List("A"))
   94     )
   95 
   96     val analysis = computeAnalysis(classDefs, reqsFactory.classData("A"))
   97 
   98     assertContainsError("CycleInInheritanceChain(A, B)", analysis) {
   99       case CycleInInheritanceChain(List(ClsName("A"), ClsName("B")), `fromAnalyzer`) => true
  100     }
  101   }
  102 
  103   @Test
  104   def bigCycleInInheritanceChain(): AsyncResult = await {
  105     val classDefs = Seq(
  106         classDef("A", superClass = Some("B")),
  107         classDef("B", superClass = Some("C")),
  108 
  109         // Start of cycle.
  110         classDef("C", superClass = Some("D")),
  111         classDef("D", superClass = Some("E")),
  112         classDef("E", superClass = Some("C"))
  113     )
  114 
  115     val analysis = computeAnalysis(classDefs, reqsFactory.classData("A"))
  116 
  117     assertContainsError("CycleInInheritanceChain(C, D, E)", analysis) {
  118       case CycleInInheritanceChain(List(ClsName("C"), ClsName("D"), ClsName("E")), `fromAnalyzer`) => true
  119     }
  120   }
  121 
  122   @Test
  123   def missingClassDirect(): AsyncResult = await {
  124     val analysis = computeAnalysis(Nil, reqsFactory.classData("A"))
  125 
  126     assertContainsError("MissingClass(A)", analysis) {
  127       case MissingClass(ClsInfo("A"), `fromUnitTest`) => true
  128     }
  129   }
  130 
  131   @Test
  132   def missingClassParent(): AsyncResult = await {
  133     val classDefs = Seq(
  134         classDef("A", superClass = Some("B"))
  135     )
  136 
  137     val analysis = computeAnalysis(classDefs, reqsFactory.classData("A"))
  138 
  139     assertContainsError("MissingClass(B)", analysis) {
  140       case MissingClass(ClsInfo("B"), FromClass(ClsInfo("A"))) => true
  141     }
  142   }
  143 
  144   @Test
  145   def missingSuperClass(): AsyncResult = await {
  146     val kinds = Seq(
  147         ClassKind.Class,
  148         ClassKind.ModuleClass,
  149         ClassKind.HijackedClass,
  150         ClassKind.JSClass,
  151         ClassKind.JSModuleClass,
  152         ClassKind.NativeJSClass,
  153         ClassKind.NativeJSModuleClass
  154     )
  155 
  156     Future.traverse(kinds) { kind =>
  157       val classDefs = Seq(
  158           classDef("A", kind = kind, memberDefs = List(trivialCtor("A")))
  159       )
  160 
  161       val analysis = computeAnalysis(classDefs,
  162           reqsFactory.instantiateClass("A", NoArgConstructorName))
  163 
  164       assertContainsError("MissingSuperClass(A)", analysis) {
  165         case MissingSuperClass(ClsInfo("A"), FromClass(ClsInfo("A"))) => true
  166       }
  167     }
  168   }
  169 
  170   @Test
  171   def invalidSuperClass(): AsyncResult = await {
  172     val kindsSub = Seq(
  173         ClassKind.Class,
  174         ClassKind.ModuleClass,
  175         ClassKind.HijackedClass,
  176         ClassKind.Interface,
  177         ClassKind.JSClass,
  178         ClassKind.JSModuleClass,
  179         ClassKind.NativeJSClass,
  180         ClassKind.NativeJSModuleClass,
  181         ClassKind.AbstractJSType
  182     )
  183 
  184     def kindsBaseFor(kindSub: ClassKind): Seq[ClassKind] = {
  185       import ClassKind._
  186       kindSub match {
  187         case Class | ModuleClass | HijackedClass =>
  188           Seq(Interface, ModuleClass, JSClass, NativeJSClass)
  189         case Interface =>
  190           Seq(Class, Interface)
  191         case JSClass | JSModuleClass | NativeJSClass | NativeJSModuleClass |
  192             AbstractJSType =>
  193           Seq(Class, Interface, AbstractJSType, JSModuleClass)
  194       }
  195     }
  196 
  197     Future.traverse(kindsSub) { kindSub =>
  198       Future.traverse(kindsBaseFor(kindSub)) { kindBase =>
  199 
  200         val classDefs = Seq(
  201             classDef("A", kind = kindSub, superClass = Some("B")),
  202             classDef("B", kind = kindBase,
  203                 superClass = validParentForKind(kindBase))
  204         )
  205 
  206         val analysis = computeAnalysis(classDefs,
  207             reqsFactory.instantiateClass("A", NoArgConstructorName))
  208 
  209         assertContainsError("InvalidSuperClass(B, A)", analysis) {
  210           case InvalidSuperClass(ClsInfo("B"), ClsInfo("A"),
  211               FromClass(ClsInfo("A"))) =>
  212             true
  213         }
  214       }
  215     }
  216   }
  217 
  218   @Test
  219   def invalidImplementedInterface(): AsyncResult = await {
  220     val kindsCls = Seq(
  221         ClassKind.Class,
  222         ClassKind.ModuleClass,
  223         ClassKind.HijackedClass,
  224         ClassKind.Interface,
  225         ClassKind.JSClass,
  226         ClassKind.JSModuleClass,
  227         ClassKind.NativeJSClass,
  228         ClassKind.NativeJSModuleClass,
  229         ClassKind.AbstractJSType
  230     )
  231 
  232     def kindsIntfFor(kindCls: ClassKind): Seq[ClassKind] = {
  233       import ClassKind._
  234       kindCls match {
  235         case Class | ModuleClass | HijackedClass | Interface =>
  236           Seq(Class, ModuleClass, JSClass, NativeJSClass, AbstractJSType)
  237         case JSClass | JSModuleClass | NativeJSClass | NativeJSModuleClass |
  238             AbstractJSType =>
  239           Seq(Class, ModuleClass, HijackedClass, Interface, JSClass,
  240               JSModuleClass, NativeJSClass, NativeJSModuleClass)
  241       }
  242     }
  243 
  244     Future.traverse(kindsCls) { kindCls =>
  245       Future.traverse(kindsIntfFor(kindCls)) { kindIntf =>
  246         val classDefs = Seq(
  247             classDef("A", kind = kindCls,
  248                 superClass = validParentForKind(kindCls),
  249                 interfaces = List("B")),
  250             classDef("B", kind = kindIntf,
  251                 superClass = validParentForKind(kindIntf))
  252         )
  253 
  254         val analysis = computeAnalysis(classDefs,
  255             reqsFactory.instantiateClass("A", NoArgConstructorName))
  256 
  257         assertContainsError("InvalidImplementedInterface(B, A)", analysis) {
  258           case InvalidImplementedInterface(ClsInfo("B"), ClsInfo("A"),
  259               FromClass(ClsInfo("A"))) =>
  260             true
  261         }
  262       }
  263     }
  264   }
  265 
  266   @Test
  267   def missingJSNativeLoadSpec(): AsyncResult = await {
  268     val kinds = Seq(
  269         ClassKind.NativeJSClass,
  270         ClassKind.NativeJSModuleClass
  271     )
  272 
  273     Future.traverse(kinds) { kind =>
  274       val classDefs = Seq(
  275           classDef("A", kind = kind, superClass = Some(ObjectClass))
  276       )
  277 
  278       val analysis = computeAnalysis(classDefs,
  279           reqsFactory.instantiateClass("A", NoArgConstructorName))
  280 
  281       assertContainsError("MissingJSNativeLoadSpec(A)", analysis) {
  282         case MissingJSNativeLoadSpec(ClsInfo("A"), `fromUnitTest`) => true
  283       }
  284     }
  285   }
  286 
  287   @Test
  288   def notAModule(): AsyncResult = await {
  289     val classDefs = Seq(
  290         classDef("A", superClass = Some(ObjectClass),
  291             memberDefs = List(trivialCtor("A")))
  292     )
  293 
  294     val analysis = computeAnalysis(classDefs, reqsFactory.accessModule("A"))
  295 
  296     assertContainsError("NotAModule(A)", analysis) {
  297       case NotAModule(ClsInfo("A"), `fromUnitTest`) => true
  298     }
  299   }
  300 
  301   @Test
  302   def missingMethod(): AsyncResult = await {
  303     val classDefs = Seq(
  304         classDef("A", superClass = Some(ObjectClass),
  305             memberDefs = List(trivialCtor("A")))
  306     )
  307 
  308     val analysis = computeAnalysis(classDefs,
  309         reqsFactory.instantiateClass("A", NoArgConstructorName) ++
  310         reqsFactory.callMethod("A", m("foo", Nil, V)))
  311 
  312     assertContainsError("MissingMethod(A.foo;V)", analysis) {
  313       case MissingMethod(MethInfo("A", "foo;V"), `fromUnitTest`) => true
  314     }
  315   }
  316 
  317   @Test
  318   def missingAbstractMethod(): AsyncResult = await {
  319     val fooMethodName = m("foo", Nil, IntRef)
  320 
  321     val classDefs = Seq(
  322         classDef("A", superClass = Some(ObjectClass),
  323             memberDefs = List(trivialCtor("A"))),
  324         classDef("B", superClass = Some("A"),
  325             memberDefs = List(
  326                 trivialCtor("B"),
  327                 MethodDef(EMF, fooMethodName, NON, Nil, IntType, Some(int(5)))(EOH, None)
  328             ))
  329     )
  330 
  331     val analysis = computeAnalysis(classDefs,
  332         reqsFactory.instantiateClass("B", NoArgConstructorName) ++
  333         reqsFactory.callMethod("A", fooMethodName))
  334 
  335     assertContainsError("MissingMethod(A.foo;I)", analysis) {
  336       case MissingMethod(MethInfo("A", "foo;I"), `fromUnitTest`) => true
  337     }
  338   }
  339 
  340   @Test
  341   def missingJSNativeMember(): AsyncResult = await {
  342     val mainName = m("main", Nil, V)
  343     val testName = m("test", Nil, O)
  344     val method = MethodDef(
  345         EMF.withNamespace(MemberNamespace.PublicStatic),
  346         mainName, NON, Nil, NoType,
  347         Some(SelectJSNativeMember("A", testName)))(EOH, None)
  348 
  349     val classDefs = Seq(
  350         classDef("A", memberDefs = List(method))
  351     )
  352 
  353     val analysis = computeAnalysis(classDefs,
  354         reqsFactory.callStaticMethod("A", mainName))
  355 
  356     assertContainsError("MissingJSNativeMember(A.test;O)", analysis) {
  357       case MissingJSNativeMember(ClsInfo("A"), `testName`,
  358           FromMethod(MethInfo("A", "main;V"))) => true
  359     }
  360   }
  361 
  362   @Test
  363   def conflictingDefaultMethods(): AsyncResult = await {
  364     val defaultMethodDef = MethodDef(EMF, m("foo", Nil, V), NON, Nil,
  365         NoType, Some(Skip()))(EOH, None)
  366     val classDefs = Seq(
  367         classDef("I1", kind = ClassKind.Interface,
  368             memberDefs = List(defaultMethodDef)),
  369         classDef("I2", kind = ClassKind.Interface,
  370             memberDefs = List(defaultMethodDef)),
  371         classDef("A", superClass = Some(ObjectClass),
  372             interfaces = List("I1", "I2"),
  373             memberDefs = List(trivialCtor("A")))
  374     )
  375 
  376     val analysis = computeAnalysis(classDefs,
  377         reqsFactory.instantiateClass("A", NoArgConstructorName) ++
  378         reqsFactory.callMethod("A", m("foo", Nil, V)))
  379 
  380     assertContainsError("ConflictingDefaultMethods(I1.foo;V, I2.foo;V)", analysis) {
  381       case ConflictingDefaultMethods(
  382           List(MethInfo("I1", "foo;V"), MethInfo("I2", "foo;V")),
  383           `fromAnalyzer`) =>
  384         true
  385       case ConflictingDefaultMethods(
  386           List(MethInfo("I2", "foo;V"), MethInfo("I1", "foo;V")),
  387           `fromAnalyzer`) =>
  388         true
  389     }
  390   }
  391 
  392   @Test
  393   def invalidTopLevelExportInScript(): AsyncResult = await {
  394     val classDefs = Seq(
  395         classDef(
  396             "A",
  397             kind = ClassKind.ModuleClass,
  398             superClass = Some(ObjectClass),
  399             topLevelExportDefs = List(
  400                 TopLevelMethodExportDef("main", JSMethodDef(
  401                     EMF.withNamespace(MemberNamespace.PublicStatic),
  402                     StringLiteral("default"), Nil, Undefined())(
  403                     EOH, None))
  404             )
  405         )
  406     )
  407 
  408     testScriptAndModule(classDefs) { scriptAnalysis =>
  409       assertContainsError("InvalidTopLevelExportInScript(foo, A)", scriptAnalysis) {
  410         case InvalidTopLevelExportInScript(TLEInfo(ModID("main"), "default", ClsName("A"))) =>
  411           true
  412       }
  413     } { moduleAnalysis =>
  414       assertNoError(moduleAnalysis)
  415     }
  416   }
  417 
  418   @Test
  419   def conflictingTopLevelExportsDifferentModules(): AsyncResult = await {
  420     def singleDef(name: String) = {
  421       classDef(name,
  422           kind = ClassKind.ModuleClass, superClass = Some(ObjectClass),
  423           memberDefs = List(trivialCtor(name)),
  424           topLevelExportDefs = List(TopLevelModuleExportDef(name, "foo")))
  425     }
  426 
  427     val classDefs = Seq(singleDef("A"), singleDef("B"))
  428 
  429     testScriptAndModule(classDefs) { scriptAnalysis =>
  430       assertContainsError("MultiplePublicModulesWithoutModuleSupport(A, B)", scriptAnalysis) {
  431         case MultiplePublicModulesWithoutModuleSupport(List(ModID("A"), ModID("B"))) =>
  432           true
  433         case MultiplePublicModulesWithoutModuleSupport(List(ModID("B"), ModID("A"))) =>
  434           true
  435       }
  436     } { moduleAnalysis =>
  437       assertNoError(moduleAnalysis)
  438     }
  439   }
  440 
  441   @Test
  442   def conflictingTopLevelExportsSameModule(): AsyncResult = await {
  443     def singleDef(name: String) = {
  444       classDef(name,
  445           kind = ClassKind.ModuleClass, superClass = Some(ObjectClass),
  446           memberDefs = List(trivialCtor(name)),
  447           topLevelExportDefs = List(TopLevelModuleExportDef("main", "foo")))
  448     }
  449 
  450     val classDefs = Seq(singleDef("A"), singleDef("B"))
  451 
  452     val analysis = computeAnalysis(classDefs)
  453     assertContainsError("ConflictingTopLevelExport(main, foo, A, B)", analysis) {
  454       case ConflictingTopLevelExport(ModID("main"), "foo",
  455           List(TLEInfo(_, _, ClsName("A")), TLEInfo(_, _, ClsName("B")))) =>
  456         true
  457       case ConflictingTopLevelExport(ModID("main"), "foo",
  458           List(TLEInfo(_, _, ClsName("B")), TLEInfo(_, _, ClsName("A")))) =>
  459         true
  460     }
  461   }
  462 
  463   @Test
  464   def degenerateConflictingTopLevelExports(): AsyncResult = await {
  465     val classDefs = Seq(classDef("A",
  466         kind = ClassKind.ModuleClass, superClass = Some(ObjectClass),
  467         memberDefs = List(trivialCtor("A")),
  468         topLevelExportDefs = List(
  469             TopLevelModuleExportDef("main", "foo"),
  470             TopLevelModuleExportDef("main", "foo"))))
  471 
  472     val analysis = computeAnalysis(classDefs)
  473     assertContainsError("ConflictingTopLevelExport(_, foo, <degenerate>)", analysis) {
  474       case ConflictingTopLevelExport(_, "foo", _) => true
  475     }
  476   }
  477 
  478   @Test
  479   def multipleModulesTopLevelExportAndModuleInitializer(): AsyncResult = await {
  480     val classDefs = Seq(classDef("A",
  481         kind = ClassKind.ModuleClass, superClass = Some(ObjectClass),
  482         memberDefs = List(
  483             trivialCtor("A"),
  484             mainMethodDef(Skip())
  485         ),
  486         topLevelExportDefs = List(TopLevelModuleExportDef("A", "foo"))))
  487 
  488     val moduleInitializer =
  489       ModuleInitializer.mainMethodWithArgs("A", "main").withModuleID("B")
  490 
  491     testScriptAndModule(classDefs, moduleInitializers = List(moduleInitializer)) { scriptAnalysis =>
  492       assertContainsError("MultiplePublicModulesWithoutModuleSupport(A, B)", scriptAnalysis) {
  493         case MultiplePublicModulesWithoutModuleSupport(List(ModID("A"), ModID("B"))) =>
  494           true
  495         case MultiplePublicModulesWithoutModuleSupport(List(ModID("B"), ModID("A"))) =>
  496           true
  497       }
  498     } { moduleAnalysis =>
  499       assertNoError(moduleAnalysis)
  500     }
  501   }
  502 
  503   @Test
  504   def importClassWithoutModuleSupport(): AsyncResult = await {
  505     val kinds = Seq(
  506         ClassKind.NativeJSClass,
  507         ClassKind.NativeJSModuleClass
  508     )
  509 
  510     Future.traverse(kinds) { kind =>
  511       val classDefs = Seq(
  512           classDef("A", kind = kind, superClass = Some(ObjectClass),
  513               jsNativeLoadSpec = Some(JSNativeLoadSpec.Import("my-module", List("A"))))
  514       )
  515 
  516       val analysis = computeAnalysis(classDefs,
  517           reqsFactory.instantiateClass("A", NoArgConstructorName),
  518           config = StandardConfig().withModuleKind(ModuleKind.NoModule))
  519 
  520       assertContainsError("ImportWithoutModuleSupport(my-module, A, None)", analysis) {
  521         case ImportWithoutModuleSupport("my-module", ClsInfo("A"), None, `fromUnitTest`) =>
  522           true
  523       }
  524     }
  525   }
  526 
  527   @Test
  528   def importJSNativeMemberWithoutModuleSupport(): AsyncResult = await {
  529     val mainName = m("main", Nil, V)
  530     val testName = m("test", Nil, O)
  531 
  532     val mainMethod = MethodDef(
  533         EMF.withNamespace(MemberNamespace.PublicStatic),
  534         mainName, NON, Nil, NoType,
  535         Some(SelectJSNativeMember("A", testName)))(EOH, None)
  536     val nativeMember = JSNativeMemberDef(
  537         EMF.withNamespace(MemberNamespace.PublicStatic), testName,
  538         JSNativeLoadSpec.Import("my-module", List("test")))
  539 
  540     val classDefs = Seq(
  541         classDef("A", memberDefs = List(mainMethod, nativeMember))
  542     )
  543 
  544     val analysis = computeAnalysis(classDefs,
  545         reqsFactory.callStaticMethod("A", mainName))
  546 
  547     assertContainsError("ImportWithoutModuleSupport(my-module, A, None)", analysis) {
  548       case ImportWithoutModuleSupport("my-module", ClsInfo("A"), Some(`testName`),
  549           FromMethod(MethInfo("A", "main;V"))) => true
  550     }
  551   }
  552 
  553   @Test
  554   def juPropertiesNotReachableWhenUsingGetSetClearProperty(): AsyncResult = await {
  555     val systemMod = LoadModule("java.lang.System$")
  556     val emptyStr = StringLiteral("")
  557     val StringType = ClassType(BoxedStringClass)
  558 
  559     val classDefs = Seq(
  560         classDef("A", superClass = Some(ObjectClass), memberDefs = List(
  561             trivialCtor("A"),
  562             MethodDef(EMF, m("test", Nil, V), NON, Nil, NoType, Some(Block(
  563                 Apply(EAF, systemMod, m("getProperty", List(T), T), List(emptyStr))(StringType),
  564                 Apply(EAF, systemMod, m("getProperty", List(T, T), T), List(emptyStr))(StringType),
  565                 Apply(EAF, systemMod, m("setProperty", List(T, T), T), List(emptyStr))(StringType),
  566                 Apply(EAF, systemMod, m("clearProperty", List(T), T), List(emptyStr))(StringType)
  567             )))(EOH, None)
  568         ))
  569     )
  570 
  571     for {
  572       analysis <- computeAnalysis(classDefs,
  573           reqsFactory.instantiateClass("A", NoArgConstructorName) ++
  574           reqsFactory.callMethod("A", m("test", Nil, V)),
  575           stdlib = TestIRRepo.fulllib)
  576     } yield {
  577       assertNoError(analysis)
  578 
  579       val juPropertiesClass = analysis.classInfos("java.util.Properties")
  580       assertFalse(juPropertiesClass.isAnySubclassInstantiated)
  581       assertFalse(juPropertiesClass.areInstanceTestsUsed)
  582       assertFalse(juPropertiesClass.isDataAccessed)
  583     }
  584   }
  585 
  586   @Test  // #3571
  587   def specificReflectiveProxy(): AsyncResult = await {
  588     val fooAMethodName = m("foo", Nil, ClassRef("A"))
  589     val fooBMethodName = m("foo", Nil, ClassRef("B"))
  590 
  591     val fooReflProxyName =
  592       MethodName.reflectiveProxy(SimpleMethodName("foo"), Nil)
  593 
  594     val classDefs = Seq(
  595         classDef("A", superClass = Some(ObjectClass)),
  596         classDef("B", superClass = Some("A")),
  597         classDef("X", superClass = Some(ObjectClass),
  598             memberDefs = List(
  599                 trivialCtor("X"),
  600                 MethodDef(EMF, fooAMethodName, NON, Nil, ClassType("A"),
  601                     Some(Null()))(EOH, None),
  602                 MethodDef(EMF, fooBMethodName, NON, Nil, ClassType("B"),
  603                     Some(Null()))(EOH, None)
  604             )
  605         )
  606     )
  607 
  608     for {
  609       analysis <- computeAnalysis(classDefs,
  610           reqsFactory.instantiateClass("X", NoArgConstructorName) ++
  611           reqsFactory.callMethod("X", fooReflProxyName))
  612     } yield {
  613       assertNoError(analysis)
  614 
  615       val MethodSyntheticKind.ReflectiveProxy(target) = {
  616         analysis.classInfos("X")
  617           .methodInfos(MemberNamespace.Public)(fooReflProxyName)
  618           .syntheticKind
  619       }
  620 
  621       assertEquals(fooBMethodName, target)
  622     }
  623   }
  624 
  625   @Test
  626   def isAbstractReachable(): AsyncResult = await {
  627     val fooMethodName = m("foo", Nil, IntRef)
  628     val barMethodName = m("bar", Nil, IntRef)
  629 
  630     val classDefs = Seq(
  631         classDef("I1", kind = ClassKind.Interface,
  632             memberDefs = List(
  633                 MethodDef(EMF, barMethodName, NON, Nil, IntType, None)(EOH, None)
  634             )),
  635         classDef("I2", kind = ClassKind.Interface,
  636             memberDefs = List(
  637                 MethodDef(EMF, barMethodName, NON, Nil, IntType, None)(EOH, None)
  638             )),
  639         classDef("A", superClass = Some(ObjectClass), interfaces = List("I1"),
  640             memberDefs = List(
  641                 trivialCtor("A"),
  642                 MethodDef(EMF, fooMethodName, NON, Nil, IntType, None)(EOH, None)
  643             )),
  644         classDef("B", superClass = Some("A"), interfaces = List("I2"),
  645             memberDefs = List(
  646                 trivialCtor("B"),
  647                 MethodDef(EMF, fooMethodName, NON, Nil, IntType, Some(int(5)))(EOH, None)
  648             )),
  649         classDef("C", superClass = Some("B"),
  650             memberDefs = List(
  651                 trivialCtor("C"),
  652                 MethodDef(EMF, barMethodName, NON, Nil, IntType, Some(int(5)))(EOH, None)
  653             ))
  654     )
  655 
  656     val analysisFuture = computeAnalysis(classDefs,
  657         reqsFactory.instantiateClass("C", NoArgConstructorName) ++
  658         reqsFactory.callMethod("A", fooMethodName) ++
  659         reqsFactory.callMethod("B", barMethodName))
  660 
  661     for (analysis <- analysisFuture) yield {
  662       assertNoError(analysis)
  663 
  664       val BClassInfo = analysis.classInfos("C")
  665       assertEquals(List[ClassName]("C", "B", "A", ObjectClass, "I1", "I2"),
  666           BClassInfo.ancestors.map(_.className))
  667 
  668       val AfooMethodInfo = analysis.classInfos("A")
  669         .methodInfos(MemberNamespace.Public)(fooMethodName)
  670       assertTrue(AfooMethodInfo.isAbstractReachable)
  671 
  672       val I1barMethodInfo = analysis.classInfos("I1")
  673         .methodInfos(MemberNamespace.Public)(barMethodName)
  674       assertTrue(I1barMethodInfo.isAbstractReachable)
  675 
  676       val I2barMethodInfo = analysis.classInfos("I2")
  677         .methodInfos(MemberNamespace.Public)(barMethodName)
  678       assertFalse(I2barMethodInfo.isAbstractReachable)
  679     }
  680   }
  681 }
  682 
  683 object AnalyzerTest {
  684   private val reqsFactory = SymbolRequirement.factory("unit test")
  685 
  686   private val fromAnalyzer = FromCore("analyzer")
  687   private val fromUnitTest = FromCore("unit test")
  688 
  689   private def validParentForKind(kind: ClassKind): Option[ClassName] = {
  690     import ClassKind._
  691     kind match {
  692       case Class | ModuleClass | HijackedClass | NativeJSClass |
  693           NativeJSModuleClass =>
  694         Some(ObjectClass)
  695       case JSClass | JSModuleClass =>
  696         Some(ClassName("scala.scalajs.js.Object"))
  697       case Interface | AbstractJSType =>
  698         None
  699     }
  700   }
  701 
  702   private def computeAnalysis(classDefs: Seq[ClassDef],
  703       symbolRequirements: SymbolRequirement = reqsFactory.none(),
  704       moduleInitializers: Seq[ModuleInitializer] = Nil,
  705       config: StandardConfig = StandardConfig(),
  706       stdlib: Future[Seq[IRFile]] = TestIRRepo.minilib)(
  707       implicit ec: ExecutionContext): Future[Analysis] = {
  708     for {
  709       baseFiles <- stdlib
  710       irLoader <- new IRLoader().update(classDefs.map(MemClassDefIRFile(_)) ++ baseFiles)
  711       analysis <- Analyzer.computeReachability(
  712           CommonPhaseConfig.fromStandardConfig(config), moduleInitializers,
  713           symbolRequirements, allowAddingSyntheticMethods = true,
  714           checkAbstractReachability = true, irLoader)
  715     } yield {
  716       analysis
  717     }
  718   }
  719 
  720   private def testScriptAndModule(classDefs: Seq[ClassDef],
  721       moduleInitializers: Seq[ModuleInitializer] = Nil)(
  722       scriptTest: Analysis => Unit)(
  723       moduleTest: Analysis => Unit)(
  724       implicit ec: ExecutionContext): Future[Unit] = {
  725 
  726     val scriptAnalysis = computeAnalysis(classDefs,
  727         moduleInitializers = moduleInitializers,
  728         config = StandardConfig().withModuleKind(ModuleKind.NoModule))
  729 
  730     val scriptResult = scriptAnalysis.map(scriptTest(_))
  731 
  732     val modulesResults = for {
  733       kind <- ModuleKind.All
  734       if kind != ModuleKind.NoModule
  735     } yield {
  736       val analysis = computeAnalysis(classDefs,
  737           config = StandardConfig().withModuleKind(kind))
  738       analysis.map(moduleTest(_))
  739     }
  740 
  741     Future.sequence(scriptResult :: modulesResults).map(_ => ())
  742   }
  743 
  744   private def assertNoError(analysis: Future[Analysis])(
  745       implicit ec: ExecutionContext): Future[Unit] = {
  746     assertExactErrors(analysis)
  747   }
  748 
  749   private def assertNoError(analysis: Analysis): Unit =
  750     assertExactErrors(analysis)
  751 
  752   private def assertExactErrors(analysis: Future[Analysis],
  753       expectedErrors: Error*)(implicit ec: ExecutionContext): Future[Unit] = {
  754     analysis.map(assertExactErrors(_, expectedErrors: _*))
  755   }
  756 
  757   private def assertExactErrors(analysis: Analysis,
  758       expectedErrors: Error*): Unit = {
  759     val actualErrors = analysis.errors
  760 
  761     for (expectedError <- expectedErrors) {
  762       assertTrue(s"Missing expected error: $expectedError",
  763           actualErrors.contains(expectedError))
  764     }
  765 
  766     if (actualErrors.size != expectedErrors.size) {
  767       for (actualError <- actualErrors) {
  768         assertTrue(s"Unexpected error: $actualError",
  769             expectedErrors.contains(actualError))
  770       }
  771     }
  772   }
  773 
  774   private def assertContainsError(msg: String, analysis: Future[Analysis])(
  775       pf: PartialFunction[Error, Boolean])(
  776       implicit ec: ExecutionContext): Future[Unit] = {
  777     analysis.map(assertContainsError(msg, _)(pf))
  778   }
  779 
  780   private def assertContainsError(msg: String, analysis: Analysis)(
  781       pf: PartialFunction[Error, Boolean]): Unit = {
  782     val fullMessage = s"Expected $msg, got ${analysis.errors}"
  783     assertTrue(fullMessage, analysis.errors.exists {
  784       e => pf.applyOrElse(e, (_: Error) => false)
  785     })
  786   }
  787 
  788   object ClsInfo {
  789     def unapply(classInfo: Analysis.ClassInfo): Some[String] =
  790       Some(classInfo.className.nameString)
  791   }
  792 
  793   object MethInfo {
  794     def unapply(methodInfo: Analysis.MethodInfo): Some[(String, String)] =
  795       Some((methodInfo.owner.className.nameString, methodInfo.methodName.nameString))
  796   }
  797 
  798   object TLEInfo {
  799     def unapply(tleInfo: Analysis.TopLevelExportInfo): Some[(ModuleID, String, ClassName)] =
  800       Some((tleInfo.moduleID, tleInfo.exportName, tleInfo.owningClass))
  801   }
  802 
  803   object ClsName {
  804     def unapply(className: ClassName): Some[String] =
  805       Some(className.nameString)
  806   }
  807 
  808   object ModID {
  809     def unapply(moduleID: ModuleID): Some[String] =
  810       Some(moduleID.id)
  811   }
  812 }