diff options
24 files changed, 261 insertions, 71 deletions
@@ -1916,7 +1916,8 @@ BOOTRAPING TEST AND TEST SUITE <path refid="pack.classpath"/> <fileset dir="${partest.dir}/files/lib" includes="*.jar" /> </compilationpath> - <scalachecktests dir="${partest.dir}/scaladoc/scala" includes="**/*.scala" /> + <runtests dir="${partest.dir}/scaladoc/run" includes="*.scala" /> + <scalachecktests dir="${partest.dir}/scaladoc/scalacheck" includes="*.scala" /> </partest> </target> diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 3ce8829af6..bb9549deba 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -97,7 +97,7 @@ trait Types extends api.Types { self: SymbolTable => */ private final val propagateParameterBoundsToTypeVars = sys.props contains "scalac.debug.prop-constraints" - protected val enableTypeVarExperimentals = settings.Xexperimental.value + protected val enableTypeVarExperimentals = settings.Xexperimental.value || settings.YvirtPatmat.value /** Empty immutable maps to avoid allocations. */ private val emptySymMap = immutable.Map[Symbol, Symbol]() diff --git a/src/compiler/scala/reflect/internal/settings/MutableSettings.scala b/src/compiler/scala/reflect/internal/settings/MutableSettings.scala index 0092f73fe3..b556c33aba 100644 --- a/src/compiler/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/compiler/scala/reflect/internal/settings/MutableSettings.scala @@ -43,4 +43,5 @@ abstract class MutableSettings extends AbsSettings { def Yrecursion: IntSetting def maxClassfileName: IntSetting def Xexperimental: BooleanSetting + def YvirtPatmat: BooleanSetting }
\ No newline at end of file diff --git a/src/compiler/scala/reflect/runtime/Settings.scala b/src/compiler/scala/reflect/runtime/Settings.scala index 8b475da0d3..27e90c94bd 100644 --- a/src/compiler/scala/reflect/runtime/Settings.scala +++ b/src/compiler/scala/reflect/runtime/Settings.scala @@ -34,4 +34,5 @@ class Settings extends internal.settings.MutableSettings { val maxClassfileName = new IntSetting(255) val Xexperimental = new BooleanSetting(false) val deepCloning = new BooleanSetting (false) + val YvirtPatmat = new BooleanSetting(false) } diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala index 9a025b0d14..f32564f097 100644 --- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala @@ -8,7 +8,7 @@ package doc import scala.util.control.ControlThrowable import reporters.Reporter -import util.NoPosition +import util.{ NoPosition, BatchSourceFile} import io.{ File, Directory } import DocParser.Parsed @@ -46,13 +46,19 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor override def forScaladoc = true } - /** Creates a scaladoc site for all symbols defined in this call's `files`, - * as well as those defined in `files` of previous calls to the same processor. + /** Creates a scaladoc site for all symbols defined in this call's `source`, + * as well as those defined in `sources` of previous calls to the same processor. * @param files The list of paths (relative to the compiler's source path, * or absolute) of files to document. */ - def makeUniverse(files: List[String]): Option[Universe] = { + def makeUniverse(source: Either[List[String], String]): Option[Universe] = { assert(settings.docformat.value == "html") - new compiler.Run() compile files + source match { + case Left(files) => + new compiler.Run() compile files + case Right(sourceCode) => + new compiler.Run() compileSources List(new BatchSourceFile("newSource", sourceCode)) + } + if (reporter.hasErrors) return None @@ -111,7 +117,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor docletInstance match { case universer: Universer => - val universe = makeUniverse(files) getOrElse { throw NoCompilerRunException } + val universe = makeUniverse(Left(files)) getOrElse { throw NoCompilerRunException } universer setUniverse universe docletInstance match { diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala index c8c5f1ec11..f059b5c0cb 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -35,7 +35,7 @@ class Template(universe: doc.Universe, tpl: DocTemplateEntity) extends HtmlPage </xml:group> val valueMembers = - tpl.methods.filterNot(_.isBridge) ++ tpl.values ++ tpl.templates.filter(x => x.isObject || x.isPackage) sorted + tpl.methods ++ tpl.values ++ tpl.templates.filter(x => x.isObject || x.isPackage) sorted val (absValueMembers, nonAbsValueMembers) = valueMembers partition (_.isAbstract) diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 496d004fd8..dd1c75c322 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -247,7 +247,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { protected lazy val memberSyms = // Only this class's constructors are part of its members, inherited constructors are not. - sym.info.members.filter(s => localShouldDocument(s) && (!s.isConstructor || s.owner == sym)) + sym.info.members.filter(s => localShouldDocument(s) && (!s.isConstructor || s.owner == sym) && !isPureBridge(sym) ) val members = memberSyms flatMap (makeMember(_, this)) val templates = members collect { case c: DocTemplateEntity => c } @@ -705,4 +705,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def localShouldDocument(aSym: Symbol): Boolean = { !aSym.isPrivate && (aSym.isProtected || aSym.privateWithin == NoSymbol) && !aSym.isSynthetic } + + /** Filter '@bridge' methods only if *they don't override non-bridge methods*. See SI-5373 for details */ + def isPureBridge(sym: Symbol) = sym.isBridge && sym.allOverriddenSymbols.forall(_.isBridge) } diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index e37f5784c9..764823d786 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -376,21 +376,16 @@ trait ContextErrors { setError(tree) } - def MissingParameterTypeError(fun: Tree, vparam: ValDef, pt: Type) = { - def anonMessage = ( - "\nThe argument types of an anonymous function must be fully known. (SLS 8.5)" + - "\nExpected type was: " + pt.toLongString - ) - - val suffix = - if (!vparam.mods.isSynthetic) "" - else " for expanded function" + (fun match { - case Function(_, Match(_, _)) => anonMessage - case _ => " " + fun - }) - - issueNormalTypeError(vparam, "missing parameter type" + suffix) - } + def MissingParameterTypeError(fun: Tree, vparam: ValDef, pt: Type) = + if (vparam.mods.isSynthetic) fun match { + case Function(_, Match(_, _)) => MissingParameterTypeAnonMatchError(vparam, pt) + case _ => issueNormalTypeError(vparam, "missing parameter type for expanded function " + fun) + } else issueNormalTypeError(vparam, "missing parameter type") + + def MissingParameterTypeAnonMatchError(vparam: Tree, pt: Type) = + issueNormalTypeError(vparam, "missing parameter type for expanded function\n"+ + "The argument types of an anonymous function must be fully known. (SLS 8.5)\n"+ + "Expected type was: " + pt.toLongString) def ConstructorsOrderError(tree: Tree) = { issueNormalTypeError(tree, "called constructor's definition must precede calling constructor's definition") diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index bbc36e01c9..aff8368f75 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -1649,7 +1649,7 @@ class Foo(x: Other) { x._1 } // no error in this order def catchAll = matchFailGen map { matchFailGen => val scrutRef = if(scrutSym ne NoSymbol) REF(scrutSym) else EmptyTree // for alternatives - LabelDef(nextCase, Nil, matchEnd APPLY (matchFailGen(scrutRef))) // need to jump to matchEnd with result generated by matchFailGen (could be `FALSE` for isDefinedAt) + LabelDef(nextCase, Nil, matchEnd APPLY (_asInstanceOf(matchFailGen(scrutRef), restpe))) // need to jump to matchEnd with result generated by matchFailGen (could be `FALSE` for isDefinedAt) } toList // catchAll.isEmpty iff no synthetic default case needed (the (last) user-defined case is a default) // if the last user-defined case is a default, it will never jump to the next case; it will go immediately to matchEnd diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index d98d248231..013a74da7e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1625,12 +1625,18 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R case _ => tree } + // skip refchecks in patterns.... result = result match { case CaseDef(pat, guard, body) => inPattern = true val pat1 = transform(pat) inPattern = false treeCopy.CaseDef(tree, pat1, transform(guard), transform(body)) + case LabelDef(_, _, _) if gen.hasSynthCaseSymbol(result) => + inPattern = true + val res = deriveLabelDef(result)(transform) + inPattern = false + res case _ => super.transform(result) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 95a1eafae2..06a7311f79 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2144,15 +2144,15 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case Annotated(Ident(nme.synthSwitch), selector) => (selector, false) case s => (s, true) } - val selector1 = checkDead(typed(selector, EXPRmode | BYVALmode, WildcardType)) - val selectorTp = packCaptured(selector1.tpe.widen) - val casesTyped = typedCases(cases, selectorTp, resTp) + val selector1 = checkDead(typed(selector, EXPRmode | BYVALmode, WildcardType)) + val selectorTp = packCaptured(selector1.tpe.widen) + + val casesTyped = typedCases(cases, selectorTp, resTp) val caseTypes = casesTyped map (c => packedType(c, context.owner).deconst) - val (ownType0, needAdapt) = if (isFullyDefined(resTp)) (resTp, false) else weakLub(caseTypes) - val ownType = ownType0.skolemizeExistential(context.owner, context.tree) - val casesAdapted = if (!needAdapt) casesTyped else casesTyped map (adaptCase(_, mode, ownType)) - // val (owntype0, needAdapt) = ptOrLub(casesTyped map (x => repackExistential(x.tpe))) - // val owntype = elimAnonymousClass(owntype0) + val (ownType, needAdapt) = if (isFullyDefined(resTp)) (resTp, false) else weakLub(caseTypes) + + val casesAdapted = if (!needAdapt) casesTyped else casesTyped map (adaptCase(_, mode, ownType)) + (selector1, selectorTp, casesAdapted, ownType, doTranslation) } @@ -2166,14 +2166,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { Match(selector1, casesAdapted) setType ownType // setType of the Match to avoid recursing endlessly } else { val scrutType = repeatedToSeq(elimAnonymousClass(selectorTp)) - MatchTranslator(this).translateMatch(selector1, casesAdapted, repeatedToSeq(ownType), scrutType, matchFailGen) + // we've packed the type for each case in prepareTranslateMatch so that if all cases have the same existential case, we get a clean lub + // here, we should open up the existential again + // relevant test cases: pos/existentials-harmful.scala, pos/gadt-gilles.scala, pos/t2683.scala, pos/virtpatmat_exist4.scala + MatchTranslator(this).translateMatch(selector1, casesAdapted, repeatedToSeq(ownType.skolemizeExistential(context.owner, context.tree)), scrutType, matchFailGen) } } def typedMatchAnonFun(tree: Tree, cases: List[CaseDef], mode: Int, pt0: Type, selOverride: Option[(List[ValDef], Tree)] = None) = { val pt = deskolemizeGADTSkolems(pt0) val targs = pt.normalize.typeArgs - val arity = if (isFunctionType(pt)) targs.length - 1 else 1 + val arity = if (isFunctionType(pt)) targs.length - 1 else 1 // TODO pt should always be a (Partial)Function, right? val ptRes = if (targs.isEmpty) WildcardType else targs.last // may not be fully defined val isPartial = pt.typeSymbol == PartialFunctionClass @@ -2185,6 +2188,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def mkParams(methodSym: Symbol) = { selOverride match { + case None if targs.isEmpty => MissingParameterTypeAnonMatchError(tree, pt); (Nil, EmptyTree) case None => val ps = methodSym newSyntheticValueParams targs.init // is there anything we can do if targs.isEmpty?? val ids = ps map (p => Ident(p.name)) @@ -2210,44 +2214,52 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { anonClass setInfo ClassInfoType(List(ObjectClass.tpe, pt, SerializableClass.tpe), newScope, anonClass) val methodSym = anonClass.newMethod(nme.apply, tree.pos, FINAL) val (paramSyms, selector) = mkParams(methodSym) - methodSym setInfoAndEnter MethodType(paramSyms, AnyClass.tpe) - val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - paramSyms foreach (methodBodyTyper.context.scope enter _) + if (selector eq EmptyTree) EmptyTree + else { + methodSym setInfoAndEnter MethodType(paramSyms, AnyClass.tpe) + + val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) + paramSyms foreach (methodBodyTyper.context.scope enter _) - val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes) + val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes) - val formalTypes = paramSyms map (_.tpe) - val parents = - if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, List(formalTypes.head, resTp)), SerializableClass.tpe) - else List(appliedType(AbstractFunctionClass(arity).typeConstructor, formalTypes :+ resTp), SerializableClass.tpe) + val formalTypes = paramSyms map (_.tpe) + val parents = + if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, List(formalTypes.head, resTp)), SerializableClass.tpe) + else List(appliedType(AbstractFunctionClass(arity).typeConstructor, formalTypes :+ resTp), SerializableClass.tpe) - anonClass setInfo ClassInfoType(parents, newScope, anonClass) - methodSym setInfoAndEnter MethodType(paramSyms, resTp) + anonClass setInfo ClassInfoType(parents, newScope, anonClass) + methodSym setInfoAndEnter MethodType(paramSyms, resTp) - // use apply's parameter since the scrut's type has been widened - def missingCase(scrut_ignored: Tree) = (funThis DOT nme.missingCase) (REF(paramSyms.head)) + // use apply's parameter since the scrut's type has been widened + def missingCase(scrut_ignored: Tree) = (funThis DOT nme.missingCase) (REF(paramSyms.head)) - val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, if (isPartial) Some(missingCase) else None) + val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, if (isPartial) Some(missingCase) else None) - DefDef(methodSym, body) + DefDef(methodSym, body) + } } def isDefinedAtMethod = { val methodSym = anonClass.newMethod(nme._isDefinedAt, tree.pos, FINAL) val (paramSyms, selector) = mkParams(methodSym) - val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - paramSyms foreach (methodBodyTyper.context.scope enter _) - methodSym setInfoAndEnter MethodType(paramSyms, BooleanClass.tpe) + if (selector eq EmptyTree) EmptyTree + else { + val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) + paramSyms foreach (methodBodyTyper.context.scope enter _) + methodSym setInfoAndEnter MethodType(paramSyms, BooleanClass.tpe) - val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, casesTrue, mode, BooleanClass.tpe) - val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, Some(scrutinee => FALSE_typed)) + val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, casesTrue, mode, BooleanClass.tpe) + val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, Some(scrutinee => FALSE_typed)) - DefDef(methodSym, body) + DefDef(methodSym, body) + } } val members = if (!isPartial) List(applyMethod) else List(applyMethod, isDefinedAtMethod) - typed(Block(List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, tree.pos)), New(anonClass.tpe)), mode, pt) + if (members.head eq EmptyTree) setError(tree) + else typed(Block(List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, tree.pos)), New(anonClass.tpe)), mode, pt) } /** diff --git a/src/library/scala/collection/GenTraversableOnce.scala b/src/library/scala/collection/GenTraversableOnce.scala index 019d3d0785..a7ec7618b7 100644 --- a/src/library/scala/collection/GenTraversableOnce.scala +++ b/src/library/scala/collection/GenTraversableOnce.scala @@ -156,7 +156,7 @@ trait GenTraversableOnce[+A] extends Any { * @return the result of inserting `op` between consecutive elements of this $coll, * going left to right with the start value `z` on the left: * {{{ - * op(...op(op(z, x1), x2), ..., xn) + * op(...op(op(z, x_1), x_2), ..., x_n) * }}} * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. */ @@ -191,7 +191,7 @@ trait GenTraversableOnce[+A] extends Any { * @return the result of inserting `op` between consecutive elements of this $coll, * going right to left with the start value `z` on the right: * {{{ - * op(x1, op(x2, ... op(xn, z)...)) + * op(x_1, op(x_2, ... op(x_n, z)...)) * }}} * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. */ @@ -209,7 +209,7 @@ trait GenTraversableOnce[+A] extends Any { * @return the result of inserting `op` between consecutive elements of this $coll, * going left to right with the start value `z` on the left: * {{{ - * op(...op(z, x1), x2, ..., xn) + * op(...op(z, x_1), x_2, ..., x_n) * }}} * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. */ @@ -226,7 +226,7 @@ trait GenTraversableOnce[+A] extends Any { * @return the result of inserting `op` between consecutive elements of this $coll, * going right to left with the start value `z` on the right: * {{{ - * op(x1, op(x2, ... op(xn, z)...)) + * op(x_1, op(x_2, ... op(x_n, z)...)) * }}} * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. */ @@ -271,7 +271,7 @@ trait GenTraversableOnce[+A] extends Any { * @return the result of inserting `op` between consecutive elements of this $coll, * going right to left: * {{{ - * op(x,,1,,, op(x,,2,,, ..., op(x,,n-1,,, x,,n,,)...)) + * op(x_1, op(x_2, ..., op(x_{n-1}, x_n)...)) * }}} * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. * @throws `UnsupportedOperationException` if this $coll is empty. diff --git a/src/library/scala/collection/JavaConverters.scala b/src/library/scala/collection/JavaConverters.scala index 07e8518cb0..13f1f19f81 100755 --- a/src/library/scala/collection/JavaConverters.scala +++ b/src/library/scala/collection/JavaConverters.scala @@ -16,7 +16,7 @@ import convert._ // additions. Would be nice to have in one place. -/** A collection of decorators that allow to convert between +/** A collection of decorators that allow converting between * Scala and Java collections using `asScala` and `asJava` methods. * * The following conversions are supported via `asJava`, `asScala` diff --git a/src/library/scala/collection/mutable/FlatArray.scala b/src/library/scala/collection/mutable/FlatArray.scala index a7f994bf74..3e43b66ecf 100644 --- a/src/library/scala/collection/mutable/FlatArray.scala +++ b/src/library/scala/collection/mutable/FlatArray.scala @@ -60,8 +60,15 @@ extends AbstractSeq[T] */ object FlatArray { - def empty[Boxed, Unboxed](elems: Boxed*) - (implicit boxings: BoxingConversions[Boxed, Unboxed], elemManifest: ClassManifest[Unboxed]): FlatArray[Boxed] = apply() + def ofDim[Boxed, Unboxed](size:Int) + (implicit boxings: BoxingConversions[Boxed, Unboxed], + manifest: ClassManifest[Unboxed]): FlatArray[Boxed] = { + val elems = Array.ofDim[Unboxed](size) + new FlatArray.Impl(elems, boxings, manifest) + } + + def empty[Boxed, Unboxed](implicit boxings: BoxingConversions[Boxed, Unboxed], + elemManifest: ClassManifest[Unboxed]): FlatArray[Boxed] = apply() def apply[Boxed, Unboxed](elems: Boxed*) (implicit boxings: BoxingConversions[Boxed, Unboxed], elemManifest: ClassManifest[Unboxed]): FlatArray[Boxed] = { diff --git a/src/library/scala/testing/Show.scala b/src/library/scala/testing/Show.scala index b0d094e466..7570bf705c 100644 --- a/src/library/scala/testing/Show.scala +++ b/src/library/scala/testing/Show.scala @@ -11,7 +11,7 @@ package scala.testing /** Classes inheriting trait `Show` can test their member methods using the - * notattion `meth(arg,,1,,, ..., arg,,n,,)`, where `meth` is the name of + * notation `meth(arg,,1,,, ..., arg,,n,,)`, where `meth` is the name of * the method and `arg,,1,,,...,arg,,n,,` are the arguments. * * The only difference to a normal method call is the leading quote diff --git a/src/partest/scala/tools/partest/ScaladocModelTest.scala b/src/partest/scala/tools/partest/ScaladocModelTest.scala new file mode 100644 index 0000000000..2eb026ceee --- /dev/null +++ b/src/partest/scala/tools/partest/ScaladocModelTest.scala @@ -0,0 +1,124 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Vlad Ureche + */ + +package scala.tools.partest + +import scala.tools.partest._ +import java.io._ +import scala.tools.nsc._ +import scala.tools.nsc.util.CommandLineParser +import scala.tools.nsc.doc.{Settings, DocFactory, Universe} +import scala.tools.nsc.doc.model._ +import scala.tools.nsc.reporters.ConsoleReporter + +/** A class for testing scaladoc model generation + * - you need to specify the code in the `code` method + * - you need to override the testModel method to test the model + * - you may specify extra parameters to send to scaladoc in `scaladocSettings` + * {{{ + import scala.tools.nsc.doc.model._ + import scala.tools.partest.ScaladocModelTest + + object Test extends ScaladocModelTest { + + def code = """ ... """ + def scaladocSettings = "" + def testModel(rootPackage: Package) = { + // get the quick access implicit defs in scope (_package(s), _class(es), _trait(s), object(s) _method(s), _value(s)) + import access._ + + // just need to check the member exists, access methods will throw an error if there's a problem + rootPackage._package("scala")._package("test")._class("C")._method("foo") + } + } + * }}} + */ +abstract class ScaladocModelTest extends DirectTest { + + /** Override this to give scaladoc command line parameters */ + def scaladocSettings: String + + /** Override this to test the model */ + def testModel(root: Package): Unit + + // Implementation follows: + override def extraSettings: String = "-usejavacp" + + override def show(): Unit = { + // redirect err to out, for logging + val prevErr = System.err + System.setErr(System.out) + + try { + // 1 - compile with scaladoc and get the model out + val args = scaladocSettings.split(" ") + val universe = model(args:_*).getOrElse({sys.error("Scaladoc Model Test ERROR: No universe generated!")}) + // 2 - check the model generated + testModel(universe.rootPackage) + } catch { + case e => + println(e) + e.printStackTrace + } + // set err back to the real err handler + System.setErr(prevErr) + } + + // create a new scaladoc compiler + def newDocFactory(args: String*): DocFactory = { + val settings = new Settings(_ => ()) + val command = new ScalaDoc.Command((CommandLineParser tokenize extraSettings) ++ args.toList, settings) + val docFact = new DocFactory(new ConsoleReporter(settings), settings) + docFact + } + + // compile with scaladoc and output the result + def model(args: String*): Option[Universe] = newDocFactory(args: _*).makeUniverse(Right(code)) + + // so we don't get the newSettings warning + override def isDebug = false + + + // finally, enable easy navigation inside the entities + object access { + + // Make it easy to access things + class TemplateAccess(tpl: DocTemplateEntity) { + + def _class(name: String): DocTemplateEntity = getTheFirst(_classes(name), tpl.qualifiedName + ".class(" + name + ")") + def _classes(name: String): List[DocTemplateEntity] = tpl.templates.filter(_.name == name).flatMap({ case c: Class => List(c)}) + + def _trait(name: String): DocTemplateEntity = getTheFirst(_traits(name), tpl.qualifiedName + ".trait(" + name + ")") + def _traits(name: String): List[DocTemplateEntity] = tpl.templates.filter(_.name == name).flatMap({ case t: Trait => List(t)}) + + def _object(name: String): DocTemplateEntity = getTheFirst(_objects(name), tpl.qualifiedName + ".object(" + name + ")") + def _objects(name: String): List[DocTemplateEntity] = tpl.templates.filter(_.name == name).flatMap({ case o: Object => List(o)}) + + def _method(name: String): Def = getTheFirst(_methods(name), tpl.qualifiedName + ".method(" + name + ")") + def _methods(name: String): List[Def] = tpl.methods.filter(_.name == name) + + def _value(name: String): Val = getTheFirst(_values(name), tpl.qualifiedName + ".value(" + name + ")") + def _values(name: String): List[Val] = tpl.values.filter(_.name == name) + + def getTheFirst[T](list: List[T], expl: String): T = { + if (list.length == 1) + list.head + else if (list.length == 0) + sys.error("Error getting " + expl + ": No such element. All elements in list: [" + list.mkString(", ") + "]") + else + sys.error("Error getting " + expl + ": " + list.length + " elements with this name. " + + "All elements in list: [" + list.mkString(", ") + "]") + } + } + + class PackageAccess(pack: Package) extends TemplateAccess(pack) { + def _package(name: String): Package = getTheFirst(_packages(name), pack.qualifiedName + ".package(" + name + ")") + def _packages(name: String): List[Package] = pack.packages.filter(_.name == name) + } + + implicit def templateAccess(tpl: DocTemplateEntity) = new TemplateAccess(tpl) + implicit def packageAccess(pack: Package) = new PackageAccess(pack) + } +} diff --git a/test/scaladoc/run/SI-5373.check b/test/scaladoc/run/SI-5373.check new file mode 100644 index 0000000000..c55eb001cf --- /dev/null +++ b/test/scaladoc/run/SI-5373.check @@ -0,0 +1 @@ +model contains 6 documentable templates diff --git a/test/scaladoc/run/SI-5373.scala b/test/scaladoc/run/SI-5373.scala new file mode 100644 index 0000000000..af433a1844 --- /dev/null +++ b/test/scaladoc/run/SI-5373.scala @@ -0,0 +1,34 @@ +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + + def code = """ + import scala.annotation.bridge + + package scala.test { + + trait A { + def foo = () + } + + trait B { + @bridge() + def foo = () + } + + class C extends A with B + } + """ + + // no need for special settings + def scaladocSettings = "" + + def testModel(rootPackage: Package) = { + // get the quick access implicit defs in scope (_package(s), _class(es), _trait(s), object(s) _method(s), _value(s)) + import access._ + + // just need to check the member exists, access methods will throw an error if there's a problem + rootPackage._package("scala")._package("test")._class("C")._method("foo") + } +}
\ No newline at end of file diff --git a/test/scaladoc/scala/html.flags b/test/scaladoc/scala/html.flags deleted file mode 100644 index b2264ec4f4..0000000000 --- a/test/scaladoc/scala/html.flags +++ /dev/null @@ -1 +0,0 @@ --encoding UTF-8
\ No newline at end of file diff --git a/test/scaladoc/scala/model/CommentFactoryTest.scala b/test/scaladoc/scalacheck/CommentFactoryTest.scala index 69c314a64c..69c314a64c 100644 --- a/test/scaladoc/scala/model/CommentFactoryTest.scala +++ b/test/scaladoc/scalacheck/CommentFactoryTest.scala diff --git a/test/scaladoc/scala/html/HtmlFactoryTest.flags b/test/scaladoc/scalacheck/HtmlFactoryTest.flags index b2264ec4f4..b2264ec4f4 100644 --- a/test/scaladoc/scala/html/HtmlFactoryTest.flags +++ b/test/scaladoc/scalacheck/HtmlFactoryTest.flags diff --git a/test/scaladoc/scala/html/HtmlFactoryTest.scala b/test/scaladoc/scalacheck/HtmlFactoryTest.scala index 28c7a4b94f..5b6f75426e 100644 --- a/test/scaladoc/scala/html/HtmlFactoryTest.scala +++ b/test/scaladoc/scalacheck/HtmlFactoryTest.scala @@ -50,7 +50,7 @@ object Test extends Properties("HtmlFactory") { def createTemplates(basename: String) = { val result = scala.collection.mutable.Map[String, scala.xml.NodeSeq]() - createFactory.makeUniverse(List(RESOURCES+basename)) match { + createFactory.makeUniverse(Left(List(RESOURCES+basename))) match { case Some(universe) => { val index = IndexModelFactory.makeIndex(universe) (new HtmlFactory(universe, index)).writeTemplates((page) => { @@ -64,7 +64,7 @@ object Test extends Properties("HtmlFactory") { } def createReferenceIndex(basename: String) = { - createFactory.makeUniverse(List(RESOURCES+basename)) match { + createFactory.makeUniverse(Left(List(RESOURCES+basename))) match { case Some(universe) => { val index = IndexModelFactory.makeIndex(universe) val pages = index.firstLetterIndex.map({ diff --git a/test/scaladoc/scala/IndexScriptTest.scala b/test/scaladoc/scalacheck/IndexScriptTest.scala index e0372020fd..5aef38e00a 100644 --- a/test/scaladoc/scala/IndexScriptTest.scala +++ b/test/scaladoc/scalacheck/IndexScriptTest.scala @@ -24,7 +24,7 @@ object Test extends Properties("IndexScript") { val indexModelFactory = doc.model.IndexModelFactory def createIndexScript(path: String) = - docFactory.makeUniverse(List(path)) match { + docFactory.makeUniverse(Left(List(path))) match { case Some(universe) => { val index = new IndexScript(universe, indexModelFactory.makeIndex(universe)) diff --git a/test/scaladoc/scala/IndexTest.scala b/test/scaladoc/scalacheck/IndexTest.scala index c14fd98297..29e337da2b 100644 --- a/test/scaladoc/scala/IndexTest.scala +++ b/test/scaladoc/scalacheck/IndexTest.scala @@ -37,7 +37,7 @@ object Test extends Properties("Index") { //val original = Console.out //Console.setOut(stream) - val result = docFactory.makeUniverse(List(path)) + val result = docFactory.makeUniverse(Left(List(path))) // assert(stream.toString == "model contains 2 documentable templates\n") //Console.setOut(original) |