summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Context.scala3
-rw-r--r--src/compiler/scala/reflect/makro/runtime/ContextReifiers.scala26
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Mirrors.scala43
-rw-r--r--src/compiler/scala/reflect/reify/Taggers.scala32
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenSymbols.scala36
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenTypes.scala3
-rw-r--r--src/compiler/scala/reflect/reify/utils/Extractors.scala4
-rw-r--r--src/compiler/scala/tools/ant/FastScalac.scala2
-rw-r--r--src/compiler/scala/tools/ant/Scalac.scala2
-rw-r--r--src/compiler/scala/tools/ant/Scaladoc.scala28
-rw-r--r--src/compiler/scala/tools/cmd/FromString.scala2
-rw-r--r--src/compiler/scala/tools/nsc/CompileServer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/Driver.scala2
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ObjectRunner.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ScriptRunner.scala2
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/DocComments.scala87
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala7
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala6
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala83
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala9
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala12
-rw-r--r--src/compiler/scala/tools/nsc/doc/DocFactory.scala9
-rw-r--r--src/compiler/scala/tools/nsc/doc/Settings.scala61
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala9
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala43
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/Page.scala22
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/Index.scala8
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala6
-rwxr-xr-xsrc/compiler/scala/tools/nsc/doc/html/page/ReferenceIndex.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/Template.scala162
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala34
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/diagram/DotRunner.scala19
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/diagrams.css8
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js48
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/object_to_type_big.pngbin0 -> 9158 bytes
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css25
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/template.js135
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/type.pngbin0 -> 3338 bytes
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/type_big.pngbin0 -> 7691 bytes
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/type_diagram.pngbin0 -> 3895 bytes
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/type_to_object_big.pngbin0 -> 9054 bytes
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/Entity.scala119
-rwxr-xr-xsrc/compiler/scala/tools/nsc/doc/model/IndexModelFactory.scala7
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/Links.scala24
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala187
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala687
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala44
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala323
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala4
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/comment/Body.scala7
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala12
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala101
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala28
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala58
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interactive/PresentationCompilerThread.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoop.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala149
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala60
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala3
-rwxr-xr-xsrc/compiler/scala/tools/nsc/util/DocStrings.scala6
-rw-r--r--src/compiler/scala/tools/nsc/util/InterruptReq.scala5
-rw-r--r--src/compiler/scala/tools/reflect/FastTrack.scala3
-rw-r--r--src/compiler/scala/tools/reflect/MacroImplementations.scala9
-rw-r--r--src/compiler/scala/tools/reflect/StdTags.scala61
-rw-r--r--src/compiler/scala/tools/util/VerifyClass.scala3
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala2
-rw-r--r--src/library-aux/scala/AnyRef.scala1
-rw-r--r--src/library/scala/annotation/static.scala20
-rw-r--r--src/library/scala/collection/immutable/List.scala3
-rw-r--r--src/library/scala/collection/immutable/StringOps.scala2
-rw-r--r--src/library/scala/collection/mutable/ArrayOps.scala2
-rw-r--r--src/library/scala/concurrent/package.scala78
-rw-r--r--src/library/scala/reflect/base/Base.scala3
-rw-r--r--src/library/scala/reflect/base/MirrorOf.scala65
-rw-r--r--src/partest/scala/tools/partest/CompilerTest.scala2
-rw-r--r--src/partest/scala/tools/partest/DirectTest.scala5
-rw-r--r--src/partest/scala/tools/partest/ScaladocModelTest.scala67
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Mirrors.scala163
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala1
-rw-r--r--src/reflect/scala/reflect/internal/util/SourceFile.scala24
-rw-r--r--src/reflect/scala/reflect/makro/Context.scala4
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala12
-rw-r--r--src/reflect/scala/tools/nsc/io/VirtualFile.scala2
95 files changed, 2347 insertions, 1034 deletions
diff --git a/src/compiler/scala/reflect/makro/runtime/Context.scala b/src/compiler/scala/reflect/makro/runtime/Context.scala
index c7563e7b67..68964b7abb 100644
--- a/src/compiler/scala/reflect/makro/runtime/Context.scala
+++ b/src/compiler/scala/reflect/makro/runtime/Context.scala
@@ -8,7 +8,6 @@ abstract class Context extends scala.reflect.makro.Context
with CapturedVariables
with Infrastructure
with Enclosures
- with Mirrors
with Names
with Reifiers
with FrontEnds
@@ -23,7 +22,7 @@ abstract class Context extends scala.reflect.makro.Context
val universe: Global
- val mirror: MirrorOf[universe.type] = new ContextMirror
+ val mirror: MirrorOf[universe.type] = universe.rootMirror
val callsiteTyper: universe.analyzer.Typer
diff --git a/src/compiler/scala/reflect/makro/runtime/ContextReifiers.scala b/src/compiler/scala/reflect/makro/runtime/ContextReifiers.scala
deleted file mode 100644
index 564148fe6c..0000000000
--- a/src/compiler/scala/reflect/makro/runtime/ContextReifiers.scala
+++ /dev/null
@@ -1,26 +0,0 @@
-package scala.reflect.makro
-package runtime
-
-abstract class ContextReifiers { self =>
- val c: Context
-
- import c.universe._
- import definitions._
- import treeBuild._
-
- import scala.reflect.reify.Taggers
- import language.implicitConversions
- private implicit def context2taggers(c0: Context) : Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers
-
- private def forMacroContext[T](prefix: Tree)(op: (Tree, Tree) => T): T = {
- val universe = gen.mkAttributedSelect(prefix.duplicate, MacroContextUniverse) setType SingleType(prefix.tpe, MacroContextUniverse)
- val mirror = TypeApply(Select(Select(prefix.duplicate, nme.mirror), nme.asInstanceOf_), List(Select(Ident(nme.UNIVERSE_SHORT), tpnme.Mirror)))
- op(universe, mirror)
- }
-
- def materializeExprForMacroContext(prefix: Tree, expr: Tree): Tree =
- forMacroContext(prefix)((universe, mirror) => c.materializeExpr(universe, mirror, expr))
-
- def materializeTypeTagForMacroContext(prefix: Tree, tpe: Type, concrete: Boolean): Tree =
- forMacroContext(prefix)((universe, mirror) => c.materializeTypeTag(universe, mirror, tpe, concrete))
-} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/makro/runtime/Mirrors.scala b/src/compiler/scala/reflect/makro/runtime/Mirrors.scala
deleted file mode 100644
index ec970ee696..0000000000
--- a/src/compiler/scala/reflect/makro/runtime/Mirrors.scala
+++ /dev/null
@@ -1,43 +0,0 @@
-package scala.reflect.makro
-package runtime
-
-import scala.tools.nsc.util.ScalaClassLoader
-
-trait Mirrors {
- self: Context =>
-
- import universe._
- import definitions._
-
- class ContextMirror extends RootsBase(NoSymbol) {
- val universe: self.universe.type = self.universe
- def rootLoader: LazyType = rootMirror.rootLoader
-
- val RootPackage = rootMirror.RootPackage
- val RootClass = rootMirror.RootClass
- val EmptyPackage = rootMirror.EmptyPackage
- val EmptyPackageClass = rootMirror.EmptyPackageClass
-
- // [Eugene++] this still doesn't solve the problem of invoking `c.typeCheck` on the code that refers to packageless symbols
- override protected def mirrorMissingHook(owner: Symbol, name: Name): Symbol = {
- if (owner.isRoot && isJavaClass(name.toString)) EmptyPackageClass.info decl name
- else NoSymbol
- }
-
- private lazy val libraryClasspathLoader: ClassLoader = {
- val classpath = platform.classPath.asURLs
- ScalaClassLoader.fromURLs(classpath)
- }
-
- private def isJavaClass(path: String): Boolean =
- try {
- Class.forName(path, true, libraryClasspathLoader)
- true
- } catch {
- case (_: ClassNotFoundException) | (_: NoClassDefFoundError) | (_: IncompatibleClassChangeError) =>
- false
- }
-
- override def toString = "macro context mirror"
- }
-} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/Taggers.scala b/src/compiler/scala/reflect/reify/Taggers.scala
index e09f13a052..4e30d0acf8 100644
--- a/src/compiler/scala/reflect/reify/Taggers.scala
+++ b/src/compiler/scala/reflect/reify/Taggers.scala
@@ -37,23 +37,21 @@ abstract class Taggers {
}
def materializeTypeTag(universe: Tree, mirror: Tree, tpe: Type, concrete: Boolean): Tree = {
- if (universe.symbol == MacroContextUniverse && mirror == EmptyTree) {
- import scala.reflect.makro.runtime.ContextReifiers
- import language.implicitConversions
- implicit def context2contextreifiers(c0: Context) : ContextReifiers { val c: c0.type } = new { val c: c0.type = c0 } with ContextReifiers
- val Select(prefix, _) = universe
- c.materializeTypeTagForMacroContext(prefix, tpe, concrete)
- } else {
- val tagType = if (concrete) TypeTagClass else AbsTypeTagClass
- val unaffiliatedTagTpe = TypeRef(BaseUniverseClass.asTypeConstructor, tagType, List(tpe))
- val unaffiliatedTag = c.inferImplicitValue(unaffiliatedTagTpe, silent = true, withMacrosDisabled = true)
- unaffiliatedTag match {
- case success if !success.isEmpty =>
- Apply(Select(success, nme.in), List(mirror orElse mkDefaultMirrorRef(c.universe)(universe, c.callsiteTyper)))
- case _ =>
- val tagModule = if (concrete) TypeTagModule else AbsTypeTagModule
- materializeTag(universe, tpe, tagModule, c.reifyType(universe, mirror, tpe, concrete = concrete))
- }
+ val tagType = if (concrete) TypeTagClass else AbsTypeTagClass
+ // what we need here is to compose a type BaseUniverse # TypeTag[$tpe]
+ // to look for an implicit that conforms to this type
+ // that's why neither appliedType(tagType, List(tpe)) aka TypeRef(TypeTagsClass.thisType, tagType, List(tpe))
+ // nor TypeRef(BaseUniverseClass.thisType, tagType, List(tpe)) won't fit here
+ // scala> :type -v def foo: scala.reflect.base.Universe#TypeTag[Int] = ???
+ // NullaryMethodType(TypeRef(pre = TypeRef(TypeSymbol(Universe)), TypeSymbol(TypeTag), args = List($tpe))))
+ val unaffiliatedTagTpe = TypeRef(BaseUniverseClass.typeConstructor, tagType, List(tpe))
+ val unaffiliatedTag = c.inferImplicitValue(unaffiliatedTagTpe, silent = true, withMacrosDisabled = true)
+ unaffiliatedTag match {
+ case success if !success.isEmpty =>
+ Apply(Select(success, nme.in), List(mirror orElse mkDefaultMirrorRef(c.universe)(universe, c.callsiteTyper)))
+ case _ =>
+ val tagModule = if (concrete) TypeTagModule else AbsTypeTagModule
+ materializeTag(universe, tpe, tagModule, c.reifyType(universe, mirror, tpe, concrete = concrete))
}
}
diff --git a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala
index 9b0777580b..38c8fedac5 100644
--- a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala
+++ b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala
@@ -37,10 +37,40 @@ trait GenSymbols {
mirrorMirrorSelect(nme.EmptyPackageClass)
else if (sym.isModuleClass)
Select(Select(reify(sym.sourceModule), nme.asModuleSymbol), nme.moduleClass)
+ else if (sym.isPackage)
+ mirrorMirrorCall(nme.staticPackage, reify(sym.fullName))
else if (sym.isLocatable) {
- // [Eugene] am I doing this right?
-// if (sym.isStaticOwner) { // no good for us, because it returns false for packages
- if (sym.isStatic && (sym.isClass || sym.isModule)) {
+ /** This is a fancy conundrum that stems from the fact that Scala allows
+ * packageless packages and packageless objects with the same names in the same program.
+ *
+ * For more details read the docs to staticModule and staticPackage.
+ * Here I'll just provide the examples of how reify works for different kinds of symbols.
+ *
+ * // 1) packageless
+ * // packageless classes are non-ambiguous, but modules vs packages might be
+ * // that's why we have separate methods to reify those
+ * // note that staticModule will never resolve to a package if an object is missing and an homonymous package is present and vice versa
+ * // otherwise reification would be unsound
+ * class C => staticClass("C")
+ * object B => staticModule("B")
+ * package B => staticPackage("B")
+ *
+ * // 2) classes and modules enclosed in a package
+ * // staticXXX methods always look into parent packages and ignores parent modules, so for fully qualified names they are non-ambiguous
+ * // namely even if there's an object B { class C } next to package B { class C }, then staticClass("B.C") will resolve to a packageful class
+ * // this closely mirrors Scala's behavior, read up the docs to staticModule/staticPackage for more information
+ * package B { class C } => staticClass("B.C")
+ * package B { object B } => staticModule("B.B")
+ * package B { package B } => staticPackage("B.B")
+ *
+ * // 3) classes and modules enclosed in a packageless module
+ * // staticClass/staticModule won't look into EmptyPackageClass, so we reify such symbols in a roundabout way
+ * object B { class C } => selectType(staticModule("B"), "C")
+ * object B { object B } => selectType(staticModule("B"), "B")
+ * object B { package B } => impossible
+ */
+ val hasPackagelessParent = sym.ownerChain.tail.tail exists (_.isEmptyPackageClass)
+ if (sym.isStatic && (sym.isClass || sym.isModule) && !hasPackagelessParent) {
val resolver = if (sym.isType) nme.staticClass else nme.staticModule
mirrorMirrorCall(resolver, reify(sym.fullName))
} else {
diff --git a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala
index 82951a2434..c49e5b3342 100644
--- a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala
+++ b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala
@@ -41,8 +41,7 @@ trait GenTypes {
case tpe @ ThisType(empty) if empty.isEmptyPackageClass =>
mirrorBuildCall(nme.thisPrefix, mirrorMirrorSelect(nme.EmptyPackageClass))
case tpe @ ThisType(clazz) if clazz.isModuleClass && clazz.isStatic =>
- // [Eugene++ to Martin] makes sense?
- val module = mirrorMirrorCall(nme.staticModule, reify(clazz.fullName))
+ val module = reify(clazz.sourceModule)
val moduleClass = Select(Select(module, nme.asModuleSymbol), nme.moduleClass)
mirrorFactoryCall(nme.ThisType, moduleClass)
case tpe @ ThisType(_) =>
diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala
index 52e4ff08c1..86265ec77a 100644
--- a/src/compiler/scala/reflect/reify/utils/Extractors.scala
+++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala
@@ -27,7 +27,7 @@ trait Extractors {
// def applyImpl[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): U#Tree = {
// val $u: U = $m$untyped.universe;
// val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror];
- // $u.Apply($u.Select($u.Select($u.build.This($m.staticModule("scala.collection.immutable").moduleClass), $u.newTermName("List")), $u.newTermName("apply")), List($u.Literal($u.Constant(1)), $u.Literal($u.Constant(2))))
+ // $u.Apply($u.Select($u.Select($u.build.This($m.staticPackage("scala.collection.immutable").moduleClass), $u.newTermName("List")), $u.newTermName("apply")), List($u.Literal($u.Constant(1)), $u.Literal($u.Constant(2))))
// }
// };
// new $treecreator1()
@@ -40,7 +40,7 @@ trait Extractors {
// def apply[U >: Nothing <: scala.reflect.base.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): U#Type = {
// val $u: U = $m$untyped.universe;
// val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror];
- // $u.TypeRef($u.ThisType($m.staticModule("scala.collection.immutable").moduleClass), $m.staticClass("scala.collection.immutable.List"), List($m.staticClass("scala.Int").asTypeConstructor))
+ // $u.TypeRef($u.ThisType($m.staticPackage("scala.collection.immutable").moduleClass), $m.staticClass("scala.collection.immutable.List"), List($m.staticClass("scala.Int").asTypeConstructor))
// }
// };
// new $typecreator1()
diff --git a/src/compiler/scala/tools/ant/FastScalac.scala b/src/compiler/scala/tools/ant/FastScalac.scala
index c0d7441ad5..f146722087 100644
--- a/src/compiler/scala/tools/ant/FastScalac.scala
+++ b/src/compiler/scala/tools/ant/FastScalac.scala
@@ -159,7 +159,7 @@ class FastScalac extends Scalac {
val url = ScalaClassLoader.originOfClass(classOf[FastScalac]).get
File(url.getFile).jfile.getParentFile.getParentFile.getAbsolutePath
} catch {
- case _ =>
+ case _: Throwable =>
buildError("Compilation failed because of an internal compiler error;"+
" couldn't determine value for -Dscala.home=<value>")
}
diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala
index e70716885e..c6809fb48e 100644
--- a/src/compiler/scala/tools/ant/Scalac.scala
+++ b/src/compiler/scala/tools/ant/Scalac.scala
@@ -99,7 +99,7 @@ class Scalac extends ScalaMatchingTask with ScalacShared {
/** Defines valid values for the `target` property. */
object Target extends PermissibleValue {
- val values = List("jvm-1.5", "jvm-1.6", "jvm-1.7", "msil")
+ val values = List("jvm-1.5", "jvm-1.5-fjbg", "jvm-1.5-asm", "jvm-1.6", "jvm-1.7", "msil")
}
/** Defines valid values for the `deprecation` and `unchecked` properties. */
diff --git a/src/compiler/scala/tools/ant/Scaladoc.scala b/src/compiler/scala/tools/ant/Scaladoc.scala
index 2cada92c1e..b96ac6f29b 100644
--- a/src/compiler/scala/tools/ant/Scaladoc.scala
+++ b/src/compiler/scala/tools/ant/Scaladoc.scala
@@ -153,6 +153,11 @@ class Scaladoc extends ScalaMatchingTask {
/** Instruct the scaladoc to produce textual ouput from html pages, for easy diff-ing */
private var docRawOutput: Boolean = false
+ /** Instruct the scaladoc not to generate prefixes */
+ private var docNoPrefixes: Boolean = false
+
+ /** Instruct the scaladoc tool to group similar functions together */
+ private var docGroups: Boolean = false
/*============================================================================*\
** Properties setters **
@@ -427,6 +432,16 @@ class Scaladoc extends ScalaMatchingTask {
def setRawOutput(input: String) =
docRawOutput = Flag.getBooleanValue(input, "rawOutput")
+ /** Set the `noPrefixes` bit to prevent Scaladoc from generating prefixes in
+ * front of types -- may lead to confusion, but significantly speeds up the generation.
+ * @param input One of the flags `yes/no` or `on/off`. Default if no/off. */
+ def setNoPrefixes(input: String) =
+ docNoPrefixes = Flag.getBooleanValue(input, "noPrefixes")
+
+ /** Instruct the scaladoc tool to group similar functions together */
+ def setGroups(input: String) =
+ docGroups = Flag.getBooleanValue(input, "groups")
+
/*============================================================================*\
** Properties getters **
\*============================================================================*/
@@ -625,6 +640,8 @@ class Scaladoc extends ScalaMatchingTask {
docSettings.docDiagrams.value = docDiagrams
docSettings.docDiagramsDebug.value = docDiagramsDebug
docSettings.docRawOutput.value = docRawOutput
+ docSettings.docNoPrefixes.value = docNoPrefixes
+ docSettings.docGroups.value = docGroups
if(!docDiagramsDotPath.isEmpty) docSettings.docDiagramsDotPath.value = docDiagramsDotPath.get
if (!docgenerator.isEmpty) docSettings.docgenerator.value = docgenerator.get
@@ -658,15 +675,10 @@ class Scaladoc extends ScalaMatchingTask {
"; see the documenter output for details.")
reporter.printSummary()
} catch {
- case exception: Throwable if exception.getMessage ne null =>
- exception.printStackTrace()
- safeBuildError("Document failed because of an internal documenter error (" +
- exception.getMessage + "); see the error output for details.")
- case exception =>
+ case exception: Throwable =>
exception.printStackTrace()
- safeBuildError("Document failed because of an internal documenter error " +
- "(no error message provided); see the error output for details.")
+ val msg = Option(exception.getMessage) getOrElse "no error message provided"
+ safeBuildError(s"Document failed because of an internal documenter error ($msg); see the error output for details.")
}
}
-
}
diff --git a/src/compiler/scala/tools/cmd/FromString.scala b/src/compiler/scala/tools/cmd/FromString.scala
index 29f1baaa0c..415940b3fd 100644
--- a/src/compiler/scala/tools/cmd/FromString.scala
+++ b/src/compiler/scala/tools/cmd/FromString.scala
@@ -8,7 +8,7 @@ package cmd
import nsc.io.{ Path, File, Directory }
import scala.reflect.runtime.{universe => ru}
-import scala.tools.reflect.StdTags._
+import scala.tools.reflect.StdRuntimeTags._
/** A general mechanism for defining how a command line argument
* (always a String) is transformed into an arbitrary type. A few
diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala
index fd59319c14..fb278db2bf 100644
--- a/src/compiler/scala/tools/nsc/CompileServer.scala
+++ b/src/compiler/scala/tools/nsc/CompileServer.scala
@@ -154,7 +154,7 @@ class StandardCompileServer extends SocketServer {
case ex @ FatalError(msg) =>
reporter.error(null, "fatal error: " + msg)
clearCompiler()
- case ex =>
+ case ex: Throwable =>
warn("Compile server encountered fatal condition: " + ex)
shutdown = true
throw ex
diff --git a/src/compiler/scala/tools/nsc/Driver.scala b/src/compiler/scala/tools/nsc/Driver.scala
index 15e2929ff1..1775602122 100644
--- a/src/compiler/scala/tools/nsc/Driver.scala
+++ b/src/compiler/scala/tools/nsc/Driver.scala
@@ -53,7 +53,7 @@ abstract class Driver {
else
doCompile(compiler)
} catch {
- case ex =>
+ case ex: Throwable =>
compiler.logThrowable(ex)
ex match {
case FatalError(msg) => reporter.error(null, "fatal error: " + msg)
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index e378d71944..83335c4f62 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -1447,6 +1447,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
settings.userSetSettings filter (_.isDeprecated) foreach { s =>
unit.deprecationWarning(NoPosition, s.name + " is deprecated: " + s.deprecationMessage.get)
}
+ if (settings.target.value.contains("jvm-1.5"))
+ unit.deprecationWarning(NoPosition, settings.target.name + ":" + settings.target.value + " is deprecated: use target for Java 1.6 or above.")
}
/* An iterator returning all the units being compiled in this run */
diff --git a/src/compiler/scala/tools/nsc/ObjectRunner.scala b/src/compiler/scala/tools/nsc/ObjectRunner.scala
index 110de7aad5..24ae0089a2 100644
--- a/src/compiler/scala/tools/nsc/ObjectRunner.scala
+++ b/src/compiler/scala/tools/nsc/ObjectRunner.scala
@@ -33,7 +33,7 @@ trait CommonRunner {
*/
def runAndCatch(urls: List[URL], objectName: String, arguments: Seq[String]): Either[Throwable, Boolean] = {
try { run(urls, objectName, arguments) ; Right(true) }
- catch { case e => Left(unwrap(e)) }
+ catch { case e: Throwable => Left(unwrap(e)) }
}
}
diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala
index dd9bca4b7b..14c508548a 100644
--- a/src/compiler/scala/tools/nsc/ScriptRunner.scala
+++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala
@@ -199,7 +199,7 @@ class ScriptRunner extends HasCompileSocket {
scriptArgs: List[String]): Either[Throwable, Boolean] =
{
try Right(runScript(settings, scriptFile, scriptArgs))
- catch { case e => Left(unwrap(e)) }
+ catch { case e: Throwable => Left(unwrap(e)) }
}
/** Run a command
diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala
index b545140c4a..d0d0b4b5f4 100755
--- a/src/compiler/scala/tools/nsc/ast/DocComments.scala
+++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala
@@ -171,15 +171,15 @@ trait DocComments { self: Global =>
* 3. If there is no @return section in `dst` but there is one in `src`, copy it.
*/
def merge(src: String, dst: String, sym: Symbol, copyFirstPara: Boolean = false): String = {
- val srcSections = tagIndex(src)
- val dstSections = tagIndex(dst)
- val srcParams = paramDocs(src, "@param", srcSections)
- val dstParams = paramDocs(dst, "@param", dstSections)
- val srcTParams = paramDocs(src, "@tparam", srcSections)
- val dstTParams = paramDocs(dst, "@tparam", dstSections)
- val out = new StringBuilder
- var copied = 0
- var tocopy = startTag(dst, dstSections dropWhile (!isMovable(dst, _)))
+ val srcSections = tagIndex(src)
+ val dstSections = tagIndex(dst)
+ val srcParams = paramDocs(src, "@param", srcSections)
+ val dstParams = paramDocs(dst, "@param", dstSections)
+ val srcTParams = paramDocs(src, "@tparam", srcSections)
+ val dstTParams = paramDocs(dst, "@tparam", dstSections)
+ val out = new StringBuilder
+ var copied = 0
+ var tocopy = startTag(dst, dstSections dropWhile (!isMovable(dst, _)))
if (copyFirstPara) {
val eop = // end of comment body (first para), which is delimited by blank line, or tag, or end of comment
@@ -209,6 +209,7 @@ trait DocComments { self: Global =>
for (tparam <- sym.typeParams)
mergeSection(srcTParams get tparam.name.toString, dstTParams get tparam.name.toString)
mergeSection(returnDoc(src, srcSections), returnDoc(dst, dstSections))
+ mergeSection(groupDoc(src, srcSections), groupDoc(dst, dstSections))
if (out.length == 0) dst
else {
@@ -457,22 +458,16 @@ trait DocComments { self: Global =>
case List() => NoType
case site :: sites1 => select(site.thisType, name, findIn(sites1))
}
- val (classes, pkgs) = site.ownerChain.span(!_.isPackageClass)
- findIn(classes ::: List(pkgs.head, rootMirror.RootClass))
+ // Previously, searching was taking place *only* in the current package and in the root package
+ // now we're looking for it everywhere in the hierarchy, so we'll be able to link variable expansions like
+ // immutable.Seq in package immutable
+ //val (classes, pkgs) = site.ownerChain.span(!_.isPackageClass)
+ //val sites = (classes ::: List(pkgs.head, rootMirror.RootClass)))
+ //findIn(sites)
+ findIn(site.ownerChain ::: List(definitions.EmptyPackage))
}
- def getType(_str: String, variable: String): Type = {
- /*
- * work around the backticks issue suggested by Simon in
- * https://groups.google.com/forum/?hl=en&fromgroups#!topic/scala-internals/z7s1CCRCz74
- * ideally, we'd have a removeWikiSyntax method in the CommentFactory to completely eliminate the wiki markup
- */
- val str =
- if (_str.length >= 2 && _str.startsWith("`") && _str.endsWith("`"))
- _str.substring(1, _str.length - 2)
- else
- _str
-
+ def getType(str: String, variable: String): Type = {
def getParts(start: Int): List[String] = {
val end = skipIdent(str, start)
if (end == start) List()
@@ -484,7 +479,7 @@ trait DocComments { self: Global =>
val parts = getParts(0)
if (parts.isEmpty) {
reporter.error(comment.codePos, "Incorrect variable expansion for " + variable + " in use case. Does the " +
- "variable expand to wiki syntax when documenting " + site + "?")
+ "variable expand to wiki syntax when documenting " + site + "?")
return ErrorType
}
val partnames = (parts.init map newTermName) :+ newTypeName(parts.last)
@@ -498,25 +493,46 @@ trait DocComments { self: Global =>
case _ =>
(getSite(partnames.head), partnames.tail)
}
- (start /: rest)(select(_, _, NoType))
+ val result = (start /: rest)(select(_, _, NoType))
+ if (result == NoType)
+ reporter.warning(comment.codePos, "Could not find the type " + variable + " points to while expanding it " +
+ "for the usecase signature of " + sym + " in " + site + "." +
+ "In this context, " + variable + " = \"" + str + "\".")
+ result
+ }
+
+ /**
+ * work around the backticks issue suggested by Simon in
+ * https://groups.google.com/forum/?hl=en&fromgroups#!topic/scala-internals/z7s1CCRCz74
+ * ideally, we'd have a removeWikiSyntax method in the CommentFactory to completely eliminate the wiki markup
+ */
+ def cleanupVariable(str: String) = {
+ val tstr = str.trim
+ if (tstr.length >= 2 && tstr.startsWith("`") && tstr.endsWith("`"))
+ tstr.substring(1, tstr.length - 1)
+ else
+ tstr
}
- val aliasExpansions: List[Type] =
+ // the Boolean tells us whether we can normalize: if we found an actual type, then yes, we can normalize, else no,
+ // use the synthetic alias created for the variable
+ val aliasExpansions: List[(Type, Boolean)] =
for (alias <- aliases) yield
lookupVariable(alias.name.toString.substring(1), site) match {
case Some(repl) =>
- val tpe = getType(repl.trim, alias.name.toString)
- if (tpe != NoType) tpe
+ val repl2 = cleanupVariable(repl)
+ val tpe = getType(repl2, alias.name.toString)
+ if (tpe != NoType) (tpe, true)
else {
- val alias1 = alias.cloneSymbol(rootMirror.RootClass, alias.rawflags, newTypeName(repl))
- typeRef(NoPrefix, alias1, Nil)
+ val alias1 = alias.cloneSymbol(rootMirror.RootClass, alias.rawflags, newTypeName(repl2))
+ (typeRef(NoPrefix, alias1, Nil), false)
}
case None =>
- typeRef(NoPrefix, alias, Nil)
+ (typeRef(NoPrefix, alias, Nil), false)
}
- def subst(sym: Symbol, from: List[Symbol], to: List[Type]): Type =
- if (from.isEmpty) sym.tpe
+ def subst(sym: Symbol, from: List[Symbol], to: List[(Type, Boolean)]): (Type, Boolean) =
+ if (from.isEmpty) (sym.tpe, false)
else if (from.head == sym) to.head
else subst(sym, from.tail, to.tail)
@@ -524,8 +540,9 @@ trait DocComments { self: Global =>
def apply(tp: Type) = mapOver(tp) match {
case tp1 @ TypeRef(pre, sym, args) if (sym.name.length > 1 && sym.name.startChar == '$') =>
subst(sym, aliases, aliasExpansions) match {
- case TypeRef(pre1, sym1, _) =>
- typeRef(pre1, sym1, args)
+ case (TypeRef(pre1, sym1, _), canNormalize) =>
+ val tpe = typeRef(pre1, sym1, args)
+ if (canNormalize) tpe.normalize else tpe
case _ =>
tp1
}
diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
index f88e41375d..e02d605965 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
@@ -140,7 +140,7 @@ abstract class TreeBrowsers {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel")
}
catch {
- case _ => UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName())
+ case _: Throwable => UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName())
}
val frame = new JFrame("Scala AST after " + phaseName + " phase")
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index e0c9631246..cde971085d 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1169,7 +1169,12 @@ self =>
if (inPattern) dropAnyBraces(pattern())
else {
if (in.token == IDENTIFIER) atPos(in.offset)(Ident(ident()))
- else expr()
+ else if(in.token == LBRACE) expr()
+ else if(in.token == THIS) { in.nextToken(); atPos(in.offset)(This(tpnme.EMPTY)) }
+ else {
+ syntaxErrorOrIncomplete("error in interpolated string: identifier or block expected", true)
+ EmptyTree
+ }
}
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index 6ba273b8ea..7ccd6785bb 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -729,8 +729,12 @@ trait Scanners extends ScannersCommon {
next.token = IDENTIFIER
next.name = newTermName(cbuf.toString)
cbuf.clear()
+ val idx = next.name.start - kwOffset
+ if (idx >= 0 && idx < kwArray.length) {
+ next.token = kwArray(idx)
+ }
} else {
- syntaxError("invalid string interpolation")
+ syntaxError("invalid string interpolation: `$$', `$'ident or `$'BlockExpr expected")
}
} else {
val isUnclosedLiteral = !isUnicodeEscape && (ch == SU || (!multiLine && (ch == CR || ch == LF)))
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index b638745327..982267097b 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -113,26 +113,42 @@ abstract class GenICode extends SubComponent {
m.native = m.symbol.hasAnnotation(definitions.NativeAttr)
if (!m.isAbstractMethod && !m.native) {
- ctx1 = genLoad(rhs, ctx1, m.returnType);
-
- // reverse the order of the local variables, to match the source-order
- m.locals = m.locals.reverse
-
- rhs match {
- case Block(_, Return(_)) => ()
- case Return(_) => ()
- case EmptyTree =>
- globalError("Concrete method has no definition: " + tree + (
- if (settings.debug.value) "(found: " + m.symbol.owner.info.decls.toList.mkString(", ") + ")"
- else "")
- )
- case _ => if (ctx1.bb.isEmpty)
- ctx1.bb.closeWith(RETURN(m.returnType), rhs.pos)
- else
+ if (m.symbol.isAccessor && m.symbol.accessed.hasStaticAnnotation) {
+ // in companion object accessors to @static fields, we access the static field directly
+ val hostClass = m.symbol.owner.companionClass
+ val staticfield = hostClass.info.findMember(m.symbol.accessed.name, NoFlags, NoFlags, false)
+
+ if (m.symbol.isGetter) {
+ ctx1.bb.emit(LOAD_FIELD(staticfield, true) setHostClass hostClass, tree.pos)
ctx1.bb.closeWith(RETURN(m.returnType))
+ } else if (m.symbol.isSetter) {
+ ctx1.bb.emit(LOAD_LOCAL(m.locals.head), tree.pos)
+ ctx1.bb.emit(STORE_FIELD(staticfield, true), tree.pos)
+ ctx1.bb.closeWith(RETURN(m.returnType))
+ } else assert(false, "unreachable")
+ } else {
+ ctx1 = genLoad(rhs, ctx1, m.returnType);
+
+ // reverse the order of the local variables, to match the source-order
+ m.locals = m.locals.reverse
+
+ rhs match {
+ case Block(_, Return(_)) => ()
+ case Return(_) => ()
+ case EmptyTree =>
+ globalError("Concrete method has no definition: " + tree + (
+ if (settings.debug.value) "(found: " + m.symbol.owner.info.decls.toList.mkString(", ") + ")"
+ else "")
+ )
+ case _ =>
+ if (ctx1.bb.isEmpty)
+ ctx1.bb.closeWith(RETURN(m.returnType), rhs.pos)
+ else
+ ctx1.bb.closeWith(RETURN(m.returnType))
+ }
+ if (!ctx1.bb.closed) ctx1.bb.close
+ prune(ctx1.method)
}
- if (!ctx1.bb.closed) ctx1.bb.close
- prune(ctx1.method)
} else
ctx1.method.setCode(NoCode)
ctx1
@@ -854,9 +870,32 @@ abstract class GenICode extends SubComponent {
generatedType = toTypeKind(fun.symbol.tpe.resultType)
ctx1
+ case app @ Apply(fun @ Select(qual, _), args)
+ if !ctx.method.symbol.isStaticConstructor
+ && fun.symbol.isAccessor && fun.symbol.accessed.hasStaticAnnotation =>
+ // bypass the accessor to the companion object and load the static field directly
+ // the only place were this bypass is not done, is the static intializer for the static field itself
+ val sym = fun.symbol
+ generatedType = toTypeKind(sym.accessed.info)
+ val hostClass = qual.tpe.typeSymbol.orElse(sym.owner).companionClass
+ val staticfield = hostClass.info.findMember(sym.accessed.name, NoFlags, NoFlags, false)
+
+ if (sym.isGetter) {
+ ctx.bb.emit(LOAD_FIELD(staticfield, true) setHostClass hostClass, tree.pos)
+ ctx
+ } else if (sym.isSetter) {
+ val ctx1 = genLoadArguments(args, sym.info.paramTypes, ctx)
+ ctx1.bb.emit(STORE_FIELD(staticfield, true), tree.pos)
+ ctx1.bb.emit(CONSTANT(Constant(false)), tree.pos)
+ ctx1
+ } else {
+ assert(false, "supposedly unreachable")
+ ctx
+ }
+
case app @ Apply(fun, args) =>
val sym = fun.symbol
-
+
if (sym.isLabel) { // jump to a label
val label = ctx.labels.getOrElse(sym, {
// it is a forward jump, scan for labels
@@ -1623,8 +1662,12 @@ abstract class GenICode extends SubComponent {
* backend emits them as static).
* No code is needed for this module symbol.
*/
- for (f <- cls.info.decls ; if !f.isMethod && f.isTerm && !f.isModule)
+ for (
+ f <- cls.info.decls;
+ if !f.isMethod && f.isTerm && !f.isModule && !(f.owner.isModuleClass && f.hasStaticAnnotation)
+ ) {
ctx.clazz addField new IField(f)
+ }
}
/**
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index 756d90bc53..025046f19e 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -598,7 +598,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
reverseJavaName.put(internalName, trackedSym)
case Some(oldsym) =>
assert((oldsym == trackedSym) || (oldsym == RuntimeNothingClass) || (oldsym == RuntimeNullClass), // In contrast, neither NothingClass nor NullClass show up bytecode-level.
- "how can getCommonSuperclass() do its job if different class symbols get the same bytecode-level internal name.")
+ "how can getCommonSuperclass() do its job if different class symbols get the same bytecode-level internal name: " + internalName)
}
}
@@ -877,7 +877,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
def wrap(op: => Unit) = {
try { op; true }
- catch { case _ => false }
+ catch { case _: Throwable => false }
}
if (settings.Xverify.value) {
@@ -1170,7 +1170,9 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
log("No forwarder for " + m + " due to conflict with " + linkedClass.info.member(m.name))
else {
log("Adding static forwarder for '%s' from %s to '%s'".format(m, jclassName, moduleClass))
- addForwarder(isRemoteClass, jclass, moduleClass, m)
+ if (m.isAccessor && m.accessed.hasStaticAnnotation) {
+ log("@static: accessor " + m + ", accessed: " + m.accessed)
+ } else addForwarder(isRemoteClass, jclass, moduleClass, m)
}
}
}
@@ -1675,6 +1677,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
jmethod = clinitMethod
jMethodName = CLASS_CONSTRUCTOR_NAME
jmethod.visitCode()
+ computeLocalVarsIndex(m)
genCode(m, false, true)
jmethod.visitMaxs(0, 0) // just to follow protocol, dummy arguments
jmethod.visitEnd()
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 912a5b0e90..0ae2adac84 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -1021,6 +1021,8 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
method = m
jmethod = clinitMethod
+
+ computeLocalVarsIndex(m)
genCode(m)
case None =>
legacyStaticInitializer(cls, clinit)
@@ -1114,7 +1116,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
linkedClass.info.members collect { case sym if sym.name.isTermName => sym.name } toSet
}
debuglog("Potentially conflicting names for forwarders: " + conflictingNames)
-
+
for (m <- moduleClass.info.membersBasedOnFlags(ExcludedForwarderFlags, Flags.METHOD)) {
if (m.isType || m.isDeferred || (m.owner eq ObjectClass) || m.isConstructor)
debuglog("No forwarder for '%s' from %s to '%s'".format(m, className, moduleClass))
@@ -1122,7 +1124,9 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
log("No forwarder for " + m + " due to conflict with " + linkedClass.info.member(m.name))
else {
log("Adding static forwarder for '%s' from %s to '%s'".format(m, className, moduleClass))
- addForwarder(jclass, moduleClass, m)
+ if (m.isAccessor && m.accessed.hasStaticAnnotation) {
+ log("@static: accessor " + m + ", accessed: " + m.accessed)
+ } else addForwarder(jclass, moduleClass, m)
}
}
}
@@ -1304,7 +1308,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
jclass.getType())
}
}
-
+
style match {
case Static(true) => dbg("invokespecial"); jcode.emitINVOKESPECIAL(jowner, jname, jtype)
case Static(false) => dbg("invokestatic"); jcode.emitINVOKESTATIC(jowner, jname, jtype)
@@ -1885,7 +1889,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
*/
def computeLocalVarsIndex(m: IMethod) {
var idx = if (m.symbol.isStaticMember) 0 else 1;
-
+
for (l <- m.params) {
debuglog("Index value for " + l + "{" + l.## + "}: " + idx)
l.index = idx
diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala
index 3c92c3b4b6..27a03d5381 100644
--- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala
@@ -48,8 +48,8 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { 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. */
+ * @param source The list of paths (relative to the compiler's source path,
+ * or absolute) of files to document or the source code. */
def makeUniverse(source: Either[List[String], String]): Option[Universe] = {
assert(settings.docformat.value == "html")
source match {
@@ -81,9 +81,11 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor
new { override val global: compiler.type = compiler }
with model.ModelFactory(compiler, settings)
with model.ModelFactoryImplicitSupport
+ with model.ModelFactoryTypeSupport
with model.diagram.DiagramFactory
with model.comment.CommentFactory
- with model.TreeFactory {
+ with model.TreeFactory
+ with model.MemberLookup {
override def templateShouldDocument(sym: compiler.Symbol, inTpl: TemplateImpl) =
extraTemplatesToDocument(sym) || super.templateShouldDocument(sym, inTpl)
}
@@ -99,7 +101,6 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor
println("no documentable class found in compilation units")
None
}
-
}
object NoCompilerRunException extends ControlThrowable { }
diff --git a/src/compiler/scala/tools/nsc/doc/Settings.scala b/src/compiler/scala/tools/nsc/doc/Settings.scala
index 31e49131f6..ad178b8158 100644
--- a/src/compiler/scala/tools/nsc/doc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/doc/Settings.scala
@@ -147,7 +147,7 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_))
val docDiagramsDotTimeout = IntSetting(
"-diagrams-dot-timeout",
- "The timeout before the graphviz dot util is forecefully closed, in seconds (default: 10)",
+ "The timeout before the graphviz dot util is forcefully closed, in seconds (default: 10)",
10,
None,
_ => None
@@ -166,6 +166,33 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_))
"For each html file, create another .html.raw file containing only the text. (can be used for quickly diffing two scaladoc outputs)"
)
+ val docNoPrefixes = BooleanSetting (
+ "-no-prefixes",
+ "Prevents generating prefixes in types, possibly creating ambiguous references, but significantly speeding up scaladoc."
+ )
+
+ val docNoLinkWarnings = BooleanSetting (
+ "-no-link-warnings",
+ "Avoid warnings for ambiguous and incorrect links."
+ )
+
+ val docSkipPackages = StringSetting (
+ "-skip-packages",
+ "<package1>:...:<packageN>",
+ "A colon-delimited list of fully qualified package names that will be skipped from scaladoc.",
+ ""
+ )
+
+ val docExpandAllTypes = BooleanSetting (
+ "-expand-all-types",
+ "Expand all type aliases and abstract types into full template pages. (locally this can be done with the @template annotation)"
+ )
+
+ val docGroups = BooleanSetting (
+ "-groups",
+ "Group similar functions together (based on the @group annotation)"
+ )
+
// Somewhere slightly before r18708 scaladoc stopped building unless the
// self-type check was suppressed. I hijacked the slotted-for-removal-anyway
// suppress-vt-warnings option and renamed it for this purpose.
@@ -177,7 +204,9 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_))
docDiagrams, docDiagramsDebug, docDiagramsDotPath,
docDiagramsDotTimeout, docDiagramsDotRestart,
docImplicits, docImplicitsDebug, docImplicitsShowAll,
- docDiagramsMaxNormalClasses, docDiagramsMaxImplicitClasses
+ docDiagramsMaxNormalClasses, docDiagramsMaxImplicitClasses,
+ docNoPrefixes, docNoLinkWarnings, docRawOutput, docSkipPackages,
+ docExpandAllTypes, docGroups
)
val isScaladocSpecific: String => Boolean = scaladocSpecific map (_.name)
@@ -186,6 +215,15 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_))
// set by the testsuite, when checking test output
var scaladocQuietRun = false
+ lazy val skipPackageNames =
+ if (docSkipPackages.value == "")
+ Set[String]()
+ else
+ docSkipPackages.value.toLowerCase.split(':').toSet
+
+ def skipPackage(qname: String) =
+ skipPackageNames(qname.toLowerCase)
+
/**
* This is the hardcoded area of Scaladoc. This is where "undesirable" stuff gets eliminated. I know it's not pretty,
* but ultimately scaladoc has to be useful. :)
@@ -198,16 +236,15 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_))
* the function result should be a humanly-understandable description of the type class
*/
val knownTypeClasses: Map[String, String => String] = Map() +
- // TODO: Bring up to date and test these
- ("scala.package.Numeric" -> ((tparam: String) => tparam + " is a numeric class, such as Int, Long, Float or Double")) +
- ("scala.package.Integral" -> ((tparam: String) => tparam + " is an integral numeric class, such as Int or Long")) +
- ("scala.package.Fractional" -> ((tparam: String) => tparam + " is a fractional numeric class, such as Float or Double")) +
- ("scala.reflect.Manifest" -> ((tparam: String) => tparam + " is accompanied by a Manifest, which is a runtime representation of its type that survives erasure")) +
- ("scala.reflect.ClassManifest" -> ((tparam: String) => tparam + " is accompanied by a ClassManifest, which is a runtime representation of its type that survives erasure")) +
- ("scala.reflect.OptManifest" -> ((tparam: String) => tparam + " is accompanied by an OptManifest, which can be either a runtime representation of its type or the NoManifest, which means the runtime type is not available")) +
- ("scala.reflect.ClassTag" -> ((tparam: String) => tparam + " is accompanied by a ClassTag, which is a runtime representation of its type that survives erasure")) +
- ("scala.reflect.AbsTypeTag" -> ((tparam: String) => tparam + " is accompanied by an AbsTypeTag, which is a runtime representation of its type that survives erasure")) +
- ("scala.reflect.TypeTag" -> ((tparam: String) => tparam + " is accompanied by a TypeTag, which is a runtime representation of its type that survives erasure"))
+ ("scala.math.Numeric" -> ((tparam: String) => tparam + " is a numeric class, such as Int, Long, Float or Double")) +
+ ("scala.math.Integral" -> ((tparam: String) => tparam + " is an integral numeric class, such as Int or Long")) +
+ ("scala.math.Fractional" -> ((tparam: String) => tparam + " is a fractional numeric class, such as Float or Double")) +
+ ("scala.reflect.Manifest" -> ((tparam: String) => tparam + " is accompanied by a Manifest, which is a runtime representation of its type that survives erasure")) +
+ ("scala.reflect.ClassManifest" -> ((tparam: String) => tparam + " is accompanied by a ClassManifest, which is a runtime representation of its type that survives erasure")) +
+ ("scala.reflect.OptManifest" -> ((tparam: String) => tparam + " is accompanied by an OptManifest, which can be either a runtime representation of its type or the NoManifest, which means the runtime type is not available")) +
+ ("scala.reflect.ClassTag" -> ((tparam: String) => tparam + " is accompanied by a ClassTag, which is a runtime representation of its type that survives erasure")) +
+ ("scala.reflect.AbsTypeTag" -> ((tparam: String) => tparam + " is accompanied by an AbsTypeTag, which is a runtime representation of its type that survives erasure")) +
+ ("scala.reflect.base.TypeTags.TypeTag" -> ((tparam: String) => tparam + " is accompanied by a TypeTag, which is a runtime representation of its type that survives erasure"))
/**
* Set of classes to exclude from index and diagrams
diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala
index 51c5793d46..436425df83 100644
--- a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala
@@ -53,11 +53,16 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) {
"trait.png",
"trait_big.png",
"trait_diagram.png",
+ "type.png",
+ "type_big.png",
+ "type_diagram.png",
"class_to_object_big.png",
"object_to_class_big.png",
- "object_to_trait_big.png",
"trait_to_object_big.png",
+ "object_to_trait_big.png",
+ "type_to_object_big.png",
+ "object_to_type_big.png",
"arrow-down.png",
"arrow-right.png",
@@ -138,7 +143,7 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) {
if (!(written contains tpl)) {
writeForThis(new page.Template(universe, diagramGenerator, tpl))
written += tpl
- tpl.templates map writeTemplate
+ tpl.templates collect { case d: DocTemplateEntity => d } map writeTemplate
}
}
diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
index 4a1a8cf898..aa2df57967 100644
--- a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
@@ -122,17 +122,30 @@ abstract class HtmlPage extends Page { thisPage =>
case Text(text) => xml.Text(text)
case Summary(in) => inlineToHtml(in)
case HtmlTag(tag) => xml.Unparsed(tag)
- case EntityLink(target, template) => template() match {
- case Some(tpl) =>
- templateToHtml(tpl)
- case None =>
- xml.Text(target)
- }
+ case EntityLink(target, link) => linkToHtml(target, link, true)
+ }
+
+ def linkToHtml(text: Inline, link: LinkTo, hasLinks: Boolean) = link match {
+ case LinkToTpl(dtpl) =>
+ if (hasLinks)
+ <a href={ relativeLinkTo(dtpl) } class="extype" name={ dtpl.qualifiedName }>{ inlineToHtml(text) }</a>
+ else
+ <span class="extype" name={ dtpl.qualifiedName }>{ inlineToHtml(text) }</span>
+ case LinkToMember(mbr, inTpl) =>
+ if (hasLinks)
+ <a href={ relativeLinkTo(inTpl) + "#" + mbr.signature } class="extmbr" name={ mbr.qualifiedName }>{ inlineToHtml(text) }</a>
+ else
+ <span class="extmbr" name={ mbr.qualifiedName }>{ inlineToHtml(text) }</span>
+ case Tooltip(tooltip) =>
+ <span class="extype" name={ tooltip }>{ inlineToHtml(text) }</span>
+ // TODO: add case LinkToExternal here
+ case NoLink =>
+ inlineToHtml(text)
}
def typeToHtml(tpes: List[model.TypeEntity], hasLinks: Boolean): NodeSeq = tpes match {
case Nil =>
- sys.error("Internal Scaladoc error")
+ NodeSeq.Empty
case List(tpe) =>
typeToHtml(tpe, hasLinks)
case tpe :: rest =>
@@ -153,15 +166,9 @@ abstract class HtmlPage extends Page { thisPage =>
}
}
def toLinksIn(inPos: Int, starts: List[Int]): NodeSeq = {
- val (tpl, width) = tpe.refEntity(inPos)
- (tpl match {
- case dtpl:DocTemplateEntity if hasLinks =>
- <a href={ relativeLinkTo(dtpl) } class="extype" name={ dtpl.qualifiedName }>{
- string.slice(inPos, inPos + width)
- }</a>
- case tpl =>
- <span class="extype" name={ tpl.qualifiedName }>{ string.slice(inPos, inPos + width) }</span>
- }) ++ toLinksOut(inPos + width, starts.tail)
+ val (link, width) = tpe.refEntity(inPos)
+ val text = comment.Text(string.slice(inPos, inPos + width))
+ linkToHtml(text, link, hasLinks) ++ toLinksOut(inPos + width, starts.tail)
}
if (hasLinks)
toLinksOut(0, tpe.refEntity.keySet.toList)
@@ -204,10 +211,12 @@ abstract class HtmlPage extends Page { thisPage =>
else if (ety.isTrait) "trait_big.png"
else if (ety.isClass && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None) "class_to_object_big.png"
else if (ety.isClass) "class_big.png"
+ else if ((ety.isAbstractType || ety.isAliasType) && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None) "type_to_object_big.png"
+ else if ((ety.isAbstractType || ety.isAliasType)) "type_big.png"
else if (ety.isObject && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None && ety.companion.get.isClass) "object_to_class_big.png"
else if (ety.isObject && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None && ety.companion.get.isTrait) "object_to_trait_big.png"
+ else if (ety.isObject && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None && (ety.companion.get.isAbstractType || ety.companion.get.isAliasType)) "object_to_trait_big.png"
else if (ety.isObject) "object_big.png"
else if (ety.isPackage) "package_big.png"
else "class_big.png" // FIXME: an entity *should* fall into one of the above categories, but AnyRef is somehow not
-
}
diff --git a/src/compiler/scala/tools/nsc/doc/html/Page.scala b/src/compiler/scala/tools/nsc/doc/html/Page.scala
index 5e3ab87ccd..d30ca5dc08 100644
--- a/src/compiler/scala/tools/nsc/doc/html/Page.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/Page.scala
@@ -48,13 +48,21 @@ abstract class Page {
* @param generator The generator that is writing this page. */
def writeFor(site: HtmlFactory): Unit
- def docEntityKindToString(ety: DocTemplateEntity) =
- if (ety.isTrait) "trait"
- else if (ety.isCaseClass) "case class"
- else if (ety.isClass) "class"
- else if (ety.isObject) "object"
- else if (ety.isPackage) "package"
- else "class" // FIXME: an entity *should* fall into one of the above categories, but AnyRef is somehow not
+ def kindToString(mbr: MemberEntity) =
+ mbr match {
+ case c: Class => if (c.isCaseClass) "case class" else "class"
+ case _: Trait => "trait"
+ case _: Package => "package"
+ case _: Object => "object"
+ case _: AbstractType => "type"
+ case _: AliasType => "type"
+ case _: Constructor => "new"
+ case v: Def => "def"
+ case v: Val if (v.isLazyVal) => "lazy val"
+ case v: Val if (v.isVal) => "val"
+ case v: Val if (v.isVar) => "var"
+ case _ => sys.error("Cannot create kind for: " + mbr + " of class " + mbr.getClass)
+ }
def templateToPath(tpl: TemplateEntity): List[String] = {
def doName(tpl: TemplateEntity): String =
diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala
index 0e894a03bf..b15d602b57 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala
@@ -14,7 +14,7 @@ import scala.collection._
import scala.xml._
import scala.util.parsing.json.{JSONObject, JSONArray}
-class Index(universe: doc.Universe, index: doc.Index) extends HtmlPage {
+class Index(universe: doc.Universe, val index: doc.Index) extends HtmlPage {
def path = List("index.html")
@@ -61,12 +61,14 @@ class Index(universe: doc.Universe, index: doc.Index) extends HtmlPage {
}
<ol class="templates">{
val tpls: Map[String, Seq[DocTemplateEntity]] =
- (pack.templates filter (t => !t.isPackage && !universe.settings.hardcoded.isExcluded(t.qualifiedName) )) groupBy (_.name)
+ (pack.templates collect {
+ case t: DocTemplateEntity if !t.isPackage && !universe.settings.hardcoded.isExcluded(t.qualifiedName) => t
+ }) groupBy (_.name)
val placeholderSeq: NodeSeq = <div class="placeholder"></div>
def createLink(entity: DocTemplateEntity, includePlaceholder: Boolean, includeText: Boolean) = {
- val entityType = docEntityKindToString(entity)
+ val entityType = kindToString(entity)
val linkContent = (
{ if (includePlaceholder) placeholderSeq else NodeSeq.Empty }
++
diff --git a/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala b/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala
index 2b68ac2937..a37dd3fb8b 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala
@@ -27,7 +27,7 @@ class IndexScript(universe: doc.Universe, index: doc.Index) extends Page {
val ary = merged.keys.toList.sortBy(_.toLowerCase).map(key => {
val pairs = merged(key).map(
- t => docEntityKindToString(t) -> relativeLinkTo(t)
+ t => kindToString(t) -> relativeLinkTo(t)
) :+ ("name" -> key)
JSONObject(scala.collection.immutable.Map(pairs : _*))
@@ -62,7 +62,9 @@ class IndexScript(universe: doc.Universe, index: doc.Index) extends Page {
def allPackagesWithTemplates = {
Map(allPackages.map((key) => {
- key -> key.templates.filter(t => !t.isPackage && !universe.settings.hardcoded.isExcluded(t.qualifiedName))
+ key -> key.templates.collect {
+ case t: DocTemplateEntity if !t.isPackage && !universe.settings.hardcoded.isExcluded(t.qualifiedName) => t
+ }
}) : _*)
}
}
diff --git a/src/compiler/scala/tools/nsc/doc/html/page/ReferenceIndex.scala b/src/compiler/scala/tools/nsc/doc/html/page/ReferenceIndex.scala
index a76cc231b4..effaee711d 100755
--- a/src/compiler/scala/tools/nsc/doc/html/page/ReferenceIndex.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/ReferenceIndex.scala
@@ -34,7 +34,7 @@ class ReferenceIndex(letter: Char, index: doc.Index, universe: Universe) extends
} else {
html
}
- })
+ }).toList.distinct
<div class="entry">
<div class="name">{
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 0d0410c7e2..422ea5ef1c 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
@@ -64,10 +64,10 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
nonAbsValueMembers partition (_.deprecation.isDefined)
val (concValueMembers, shadowedImplicitMembers) =
- nonDeprValueMembers partition (!Template.isShadowedOrAmbiguousImplicit(_))
+ nonDeprValueMembers partition (!_.isShadowedOrAmbiguousImplicit)
val typeMembers =
- tpl.abstractTypes ++ tpl.aliasTypes ++ tpl.templates.filter(x => x.isTrait || x.isClass) sorted
+ tpl.abstractTypes ++ tpl.aliasTypes ++ tpl.templates.filter(x => x.isTrait || x.isClass) sorted (implicitly[Ordering[MemberEntity]])
val constructors = (tpl match {
case cls: Class => (cls.constructors: List[MemberEntity]).sorted
@@ -92,7 +92,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
<p id="owner">{ templatesToHtml(tpl.inTemplate.toRoot.reverse.tail, xml.Text(".")) }</p>
}
- <body class={ if (tpl.isTrait || tpl.isClass || tpl.qualifiedName == "scala.AnyRef") "type" else "value" }>
+ <body class={ if (tpl.isType) "type" else "value" }>
<div id="definition">
{
tpl.companion match {
@@ -110,10 +110,26 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
<div id="mbrsel">
<div id='textfilter'><span class='pre'/><span class='input'><input id='mbrsel-input' type='text' accesskey='/'/></span><span class='post'/></div>
- { if (tpl.linearizationTemplates.isEmpty && tpl.conversions.isEmpty) NodeSeq.Empty else
+ { if (tpl.linearizationTemplates.isEmpty && tpl.conversions.isEmpty && (!universe.settings.docGroups.value || (tpl.members.map(_.group).distinct.length == 1)))
+ NodeSeq.Empty
+ else
<div id="order">
<span class="filtertype">Ordering</span>
- <ol><li class="alpha in"><span>Alphabetic</span></li><li class="inherit out"><span>By inheritance</span></li></ol>
+ <ol>
+ {
+ if (!universe.settings.docGroups.value || (tpl.members.map(_.group).distinct.length == 1))
+ NodeSeq.Empty
+ else
+ <li class="group out"><span>Grouped</span></li>
+ }
+ <li class="alpha in"><span>Alphabetic</span></li>
+ {
+ if (tpl.linearizationTemplates.isEmpty && tpl.conversions.isEmpty)
+ NodeSeq.Empty
+ else
+ <li class="inherit out"><span>By inheritance</span></li>
+ }
+ </ol>
</div>
}
{ if (tpl.linearizationTemplates.isEmpty && tpl.conversions.isEmpty) NodeSeq.Empty else
@@ -223,6 +239,25 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
</div>
+ <div id="groupedMembers">
+ {
+ val allGroups = tpl.members.map(_.group).distinct
+ val orderedGroups = allGroups.map(group => (tpl.groupPriority(group), group)).sorted.map(_._2)
+ // linearization
+ NodeSeq fromSeq (for (group <- orderedGroups) yield
+ <div class="group" name={ group }>
+ <h3>{ tpl.groupName(group) }</h3>
+ {
+ tpl.groupDescription(group) match {
+ case Some(body) => <div class="comment cmt">{ bodyToHtml(body) }</div>
+ case _ => NodeSeq.Empty
+ }
+ }
+ </div>
+ )
+ }
+ </div>
+
</div>
<div id="tooltip" ></div>
@@ -238,44 +273,13 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
</body>
}
- def boundsToString(hi: Option[TypeEntity], lo: Option[TypeEntity]): String = {
- def bound0(bnd: Option[TypeEntity], pre: String): String = bnd match {
- case None => ""
- case Some(tpe) => pre ++ tpe.toString
- }
- bound0(hi, "<:") ++ bound0(lo, ">:")
- }
-
- def tparamsToString(tpss: List[TypeParam]): String = {
- if (tpss.isEmpty) "" else {
- def tparam0(tp: TypeParam): String =
- tp.variance + tp.name + boundsToString(tp.hi, tp.lo)
- def tparams0(tpss: List[TypeParam]): String = (tpss: @unchecked) match {
- case tp :: Nil => tparam0(tp)
- case tp :: tps => tparam0(tp) ++ ", " ++ tparams0(tps)
- }
- "[" + tparams0(tpss) + "]"
- }
- }
-
- def defParamsToString(d: MemberEntity with Def): String = {
- val paramLists: List[String] =
- if (d.valueParams.isEmpty) Nil
- else d.valueParams map (ps => ps map (_.resultType.name) mkString ("(",",",")"))
-
- tparamsToString(d.typeParams) + paramLists.mkString
- }
-
def memberToHtml(mbr: MemberEntity, inTpl: DocTemplateEntity): NodeSeq = {
- val defParamsString = mbr match {
- case d:MemberEntity with Def => defParamsToString(d)
- case _ => ""
- }
val memberComment = memberToCommentHtml(mbr, inTpl, false)
<li name={ mbr.definitionName } visbl={ if (mbr.visibility.isProtected) "prt" else "pub" }
data-isabs={ mbr.isAbstract.toString }
- fullComment={ if(memberComment.filter(_.label=="div").isEmpty) "no" else "yes" }>
- <a id={ mbr.name +defParamsString +":"+ mbr.resultType.name}/>
+ fullComment={ if(memberComment.filter(_.label=="div").isEmpty) "no" else "yes" }
+ group={ mbr.group }>
+ <a id={ mbr.signature }/>
{ signature(mbr, false) }
{ memberComment }
</li>
@@ -419,7 +423,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
{ constraintText }
</dd>
} ++ {
- if (Template.isShadowedOrAmbiguousImplicit(mbr)) {
+ if (mbr.isShadowedOrAmbiguousImplicit) {
// These are the members that are shadowing or ambiguating the current implicit
// see ImplicitMemberShadowing trait for more information
val shadowingSuggestion = {
@@ -434,10 +438,10 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
val shadowingWarning: NodeSeq =
- if (Template.isShadowedImplicit(mbr))
+ if (mbr.isShadowedImplicit)
xml.Text("This implicitly inherited member is shadowed by one or more members in this " +
"class.") ++ shadowingSuggestion
- else if (Template.isAmbiguousImplicit(mbr))
+ else if (mbr.isAmbiguousImplicit)
xml.Text("This implicitly inherited member is ambiguous. One or more implicitly " +
"inherited members have similar signatures, so calling this member may produce an ambiguous " +
"implicit conversion compiler error.") ++ shadowingSuggestion
@@ -633,13 +637,13 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
val typeHierarchy = if (s.docDiagrams.isSetByUser) mbr match {
- case dtpl: DocTemplateEntity if isSelf && !isReduced && dtpl.inheritanceDiagram.isDefined =>
+ case dtpl: DocTemplateEntity if isSelf && !isReduced =>
makeDiagramHtml(dtpl, dtpl.inheritanceDiagram, "Type Hierarchy", "inheritance-diagram")
case _ => NodeSeq.Empty
} else NodeSeq.Empty // diagrams not generated
val contentHierarchy = if (s.docDiagrams.isSetByUser) mbr match {
- case dtpl: DocTemplateEntity if isSelf && !isReduced && dtpl.contentDiagram.isDefined =>
+ case dtpl: DocTemplateEntity if isSelf && !isReduced =>
makeDiagramHtml(dtpl, dtpl.contentDiagram, "Content Hierarchy", "content-diagram")
case _ => NodeSeq.Empty
} else NodeSeq.Empty // diagrams not generated
@@ -647,19 +651,6 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
memberComment ++ paramComments ++ attributesBlock ++ linearization ++ subclasses ++ typeHierarchy ++ contentHierarchy
}
- def kindToString(mbr: MemberEntity): String = {
- mbr match {
- case tpl: DocTemplateEntity => docEntityKindToString(tpl)
- case ctor: Constructor => "new"
- case tme: MemberEntity =>
- ( if (tme.isDef) "def"
- else if (tme.isVal) "val"
- else if (tme.isLazyVal) "lazy val"
- else if (tme.isVar) "var"
- else "type")
- }
- }
-
def boundsToHtml(hi: Option[TypeEntity], lo: Option[TypeEntity], hasLinks: Boolean): NodeSeq = {
def bound0(bnd: Option[TypeEntity], pre: String): NodeSeq = bnd match {
case None => NodeSeq.Empty
@@ -677,13 +668,13 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
case PrivateInTemplate(owner) if (owner == mbr.inTemplate) =>
Some(Paragraph(CText("private")))
case PrivateInTemplate(owner) =>
- Some(Paragraph(Chain(List(CText("private["), EntityLink(owner.qualifiedName, () => Some(owner)), CText("]")))))
+ Some(Paragraph(Chain(List(CText("private["), EntityLink(comment.Text(owner.qualifiedName), LinkToTpl(owner)), CText("]")))))
case ProtectedInInstance() =>
Some(Paragraph(CText("protected[this]")))
case ProtectedInTemplate(owner) if (owner == mbr.inTemplate) =>
Some(Paragraph(CText("protected")))
case ProtectedInTemplate(owner) =>
- Some(Paragraph(Chain(List(CText("protected["), EntityLink(owner.qualifiedName, () => Some(owner)), CText("]")))))
+ Some(Paragraph(Chain(List(CText("protected["), EntityLink(comment.Text(owner.qualifiedName), LinkToTpl(owner)), CText("]")))))
case Public() =>
None
}
@@ -700,8 +691,8 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
<span class="symbol">
{
val nameClass =
- if (Template.isImplicit(mbr))
- if (Template.isShadowedOrAmbiguousImplicit(mbr))
+ if (mbr.isImplicitlyInherited)
+ if (mbr.isShadowedOrAmbiguousImplicit)
"implicit shadowed"
else
"implicit"
@@ -779,20 +770,21 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
}{ if (isReduced) NodeSeq.Empty else {
mbr match {
- case tpl: DocTemplateEntity if !tpl.parentTypes.isEmpty =>
- <span class="result"> extends { typeToHtml(tpl.parentTypes.map(_._2), hasLinks) }</span>
-
case tme: MemberEntity if (tme.isDef || tme.isVal || tme.isLazyVal || tme.isVar) =>
<span class="result">: { typeToHtml(tme.resultType, hasLinks) }</span>
- case abt: AbstractType =>
+ case abt: MemberEntity with AbstractType =>
val b2s = boundsToHtml(abt.hi, abt.lo, hasLinks)
if (b2s != NodeSeq.Empty)
<span class="result">{ b2s }</span>
else NodeSeq.Empty
- case alt: AliasType =>
+ case alt: MemberEntity with AliasType =>
<span class="result"> = { typeToHtml(alt.alias, hasLinks) }</span>
+
+ case tpl: MemberTemplateEntity if !tpl.parentTypes.isEmpty =>
+ <span class="result"> extends { typeToHtml(tpl.parentTypes.map(_._2), hasLinks) }</span>
+
case _ => NodeSeq.Empty
}
}}
@@ -800,7 +792,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
</xml:group>
mbr match {
case dte: DocTemplateEntity if !isSelf =>
- <h4 class="signature">{ inside(hasLinks = false, nameLink = relativeLinkTo(dte)) }</h4>
+ <h4 class="signature">{ inside(hasLinks = true, nameLink = relativeLinkTo(dte)) }</h4>
case _ if isSelf =>
<h4 id="signature" class="signature">{ inside(hasLinks = true) }</h4>
case _ =>
@@ -850,18 +842,13 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
val link = relativeLinkTo(mbr)
myXml ++= <span class="name"><a href={link}>{str.substring(from, to)}</a></span>
case mbr: MemberEntity =>
- val anchor = "#" + mbr.name + defParamsString(mbr) + ":" + mbr.resultType.name
+ val anchor = "#" + mbr.signature
val link = relativeLinkTo(mbr.inTemplate)
myXml ++= <span class="name"><a href={link ++ anchor}>{str.substring(from, to)}</a></span>
}
index = to
}
}
- // function used in the MemberEntity case above
- def defParamsString(mbr: Entity):String = mbr match {
- case d:MemberEntity with Def => defParamsToString(d)
- case _ => ""
- }
if (index <= length-1)
myXml ++= codeStringToXml(str.substring(index, length ))
@@ -952,16 +939,18 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
def makeDiagramHtml(tpl: DocTemplateEntity, diagram: Option[Diagram], description: String, id: String) = {
- val s = universe.settings
- val diagramSvg = generator.generate(diagram.get, tpl, this)
- if (diagramSvg != NodeSeq.Empty) {
- <div class="toggleContainer block diagram-container" id={ id + "-container"}>
- <span class="toggle diagram-link">{ description }</span>
- <a href="http://docs.scala-lang.org/overviews/scaladoc/usage.html#diagrams" target="_blank" class="diagram-help">Learn more about scaladoc diagrams</a>
- <div class="diagram" id={ id }>{
- diagramSvg
- }</div>
- </div>
+ if (diagram.isDefined) {
+ val s = universe.settings
+ val diagramSvg = generator.generate(diagram.get, tpl, this)
+ if (diagramSvg != NodeSeq.Empty) {
+ <div class="toggleContainer block diagram-container" id={ id + "-container"}>
+ <span class="toggle diagram-link">{ description }</span>
+ <a href="http://docs.scala-lang.org/overviews/scaladoc/usage.html#diagrams" target="_blank" class="diagram-help">Learn more about scaladoc diagrams</a>
+ <div class="diagram" id={ id }>{
+ diagramSvg
+ }</div>
+ </div>
+ } else NodeSeq.Empty
} else NodeSeq.Empty
}
}
@@ -970,12 +959,5 @@ object Template {
/* Vlad: Lesson learned the hard way: don't put any stateful code that references the model here,
* it won't be garbage collected and you'll end up filling the heap with garbage */
- def isImplicit(mbr: MemberEntity) = mbr.byConversion.isDefined
- def isShadowedImplicit(mbr: MemberEntity): Boolean =
- mbr.byConversion.map(_.source.implicitsShadowing.get(mbr).map(_.isShadowed).getOrElse(false)).getOrElse(false)
- def isAmbiguousImplicit(mbr: MemberEntity): Boolean =
- mbr.byConversion.map(_.source.implicitsShadowing.get(mbr).map(_.isAmbiguous).getOrElse(false)).getOrElse(false)
- def isShadowedOrAmbiguousImplicit(mbr: MemberEntity) = isShadowedImplicit(mbr) || isAmbiguousImplicit(mbr)
-
def lowerFirstLetter(s: String) = if (s.length >= 1) s.substring(0,1).toLowerCase() + s.substring(1) else s
}
diff --git a/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala b/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala
index dc6f941c30..bae61f1a3b 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala
@@ -25,7 +25,7 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator {
// maps an index to its corresponding node
private var index2Node: Map[Int, Node] = null
// true if the current diagram is a class diagram
- private var isClassDiagram = false
+ private var isInheritanceDiagram = false
// incoming implicit nodes (needed for determining the CSS class of a node)
private var incomingImplicitNodes: List[Node] = List()
// the suffix used when there are two many classes to show
@@ -66,15 +66,15 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator {
var superClasses = List[Node]()
var incomingImplicits = List[Node]()
var outgoingImplicits = List[Node]()
- isClassDiagram = false
+ isInheritanceDiagram = false
d match {
- case ClassDiagram(_thisNode, _superClasses, _subClasses, _incomingImplicits, _outgoingImplicits) =>
+ case InheritanceDiagram(_thisNode, _superClasses, _subClasses, _incomingImplicits, _outgoingImplicits) =>
def textTypeEntity(text: String) =
new TypeEntity {
val name = text
- def refEntity: SortedMap[Int, (TemplateEntity, Int)] = SortedMap()
+ def refEntity: SortedMap[Int, (LinkTo, Int)] = SortedMap()
}
// it seems dot chokes on node names over 8000 chars, so let's limit the size of the string
@@ -86,29 +86,29 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator {
// them by on node with a corresponding tooltip
superClasses = if (_superClasses.length > settings.docDiagramsMaxNormalClasses.value) {
val superClassesTooltip = Some(limitSize(_superClasses.map(_.tpe.name).mkString(", ")))
- List(NormalNode(textTypeEntity(_superClasses.length + MultiSuffix), None, superClassesTooltip))
+ List(NormalNode(textTypeEntity(_superClasses.length + MultiSuffix), None)(superClassesTooltip))
} else _superClasses
subClasses = if (_subClasses.length > settings.docDiagramsMaxNormalClasses.value) {
val subClassesTooltip = Some(limitSize(_subClasses.map(_.tpe.name).mkString(", ")))
- List(NormalNode(textTypeEntity(_subClasses.length + MultiSuffix), None, subClassesTooltip))
+ List(NormalNode(textTypeEntity(_subClasses.length + MultiSuffix), None)(subClassesTooltip))
} else _subClasses
incomingImplicits = if (_incomingImplicits.length > settings.docDiagramsMaxImplicitClasses.value) {
val incomingImplicitsTooltip = Some(limitSize(_incomingImplicits.map(_.tpe.name).mkString(", ")))
- List(ImplicitNode(textTypeEntity(_incomingImplicits.length + MultiSuffix), None, incomingImplicitsTooltip))
+ List(ImplicitNode(textTypeEntity(_incomingImplicits.length + MultiSuffix), None)(incomingImplicitsTooltip))
} else _incomingImplicits
outgoingImplicits = if (_outgoingImplicits.length > settings.docDiagramsMaxImplicitClasses.value) {
val outgoingImplicitsTooltip = Some(limitSize(_outgoingImplicits.map(_.tpe.name).mkString(", ")))
- List(ImplicitNode(textTypeEntity(_outgoingImplicits.length + MultiSuffix), None, outgoingImplicitsTooltip))
+ List(ImplicitNode(textTypeEntity(_outgoingImplicits.length + MultiSuffix), None)(outgoingImplicitsTooltip))
} else _outgoingImplicits
thisNode = _thisNode
nodes = List()
edges = (thisNode -> superClasses) :: subClasses.map(_ -> List(thisNode))
node2Index = (thisNode::subClasses:::superClasses:::incomingImplicits:::outgoingImplicits).zipWithIndex.toMap
- isClassDiagram = true
+ isInheritanceDiagram = true
incomingImplicitNodes = incomingImplicits
case _ =>
nodes = d.nodes
@@ -119,7 +119,7 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator {
index2Node = node2Index map {_.swap}
val implicitsDot = {
- if (!isClassDiagram) ""
+ if (!isInheritanceDiagram) ""
else {
// dot cluster containing thisNode
val thisCluster = "subgraph clusterThis {\n" +
@@ -242,6 +242,8 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator {
attr ++= classStyle
else if(node.isObjectNode)
attr ++= objectStyle
+ else if(node.isTypeNode)
+ attr ++= typeStyle
else
attr ++= defaultStyle
@@ -254,6 +256,8 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator {
img = "class_diagram.png"
else if(node.isObjectNode)
img = "object_diagram.png"
+ else if(node.isTypeNode)
+ img = "type_diagram.png"
if(!img.equals("")) {
img = "<TD><IMG SCALE=\"TRUE\" SRC=\"" + settings.outdir.value + "/lib/" + img + "\" /></TD>"
@@ -307,6 +311,8 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator {
space + "trait"
else if (node.isObjectNode)
space + "object"
+ else if (node.isTypeNode)
+ space + "type"
else
default
@@ -360,7 +366,7 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator {
private def transform(e:scala.xml.Node): scala.xml.Node = e match {
// add an id and class attribute to the SVG element
case Elem(prefix, "svg", attribs, scope, child @ _*) => {
- val klass = if (isClassDiagram) "class-diagram" else "package-diagram"
+ val klass = if (isInheritanceDiagram) "class-diagram" else "package-diagram"
Elem(prefix, "svg", attribs, scope, child map(x => transform(x)) : _*) %
new UnprefixedAttribute("id", "graph" + counter, Null) %
new UnprefixedAttribute("class", klass, Null)
@@ -491,6 +497,12 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator {
"fontcolor" -> "#ffffff"
)
+ private val typeStyle = Map(
+ "color" -> "#115F3B",
+ "fillcolor" -> "#0A955B",
+ "fontcolor" -> "#ffffff"
+ )
+
private def flatten(attributes: Map[String, String]) = attributes.map{ case (key, value) => key + "=\"" + value + "\"" }.mkString(", ")
private val graphAttributesStr = graphAttributes.map{ case (key, value) => key + "=\"" + value + "\";\n" }.mkString
diff --git a/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotRunner.scala b/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotRunner.scala
index 37600fa908..5cdd5c74a4 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotRunner.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotRunner.scala
@@ -28,7 +28,7 @@ class DotRunner(settings: doc.Settings) {
if (dotProcess == null) {
if (dotRestarts < settings.docDiagramsDotRestart.value) {
if (dotRestarts != 0)
- settings.printMsg("A new graphviz dot process will be created...\n")
+ settings.printMsg("Graphviz will be restarted...\n")
dotRestarts += 1
dotProcess = new DotProcess(settings)
} else
@@ -46,7 +46,7 @@ class DotRunner(settings: doc.Settings) {
if (dotRestarts == settings.docDiagramsDotRestart.value) {
settings.printMsg("\n")
settings.printMsg("**********************************************************************")
- settings.printMsg("Diagrams will be disabled for this run beucause the graphviz dot tool")
+ settings.printMsg("Diagrams will be disabled for this run because the graphviz dot tool")
settings.printMsg("has malfunctioned too many times. These scaladoc flags may help:")
settings.printMsg("")
val baseList = List(settings.docDiagramsDebug,
@@ -106,7 +106,7 @@ class DotProcess(settings: doc.Settings) {
result
} catch {
- case exc =>
+ case exc: Throwable =>
errorBuffer.append(" Main thread in " + templateName + ": " +
(if (exc.isInstanceOf[NoSuchElementException]) "Timeout" else "Exception: " + exc))
error = true
@@ -145,9 +145,10 @@ class DotProcess(settings: doc.Settings) {
settings.printMsg("**********************************************************************")
} else {
// we shouldn't just sit there for 50s not reporting anything, no?
- settings.printMsg("Graphviz dot encountered an error when generating the diagram for")
- settings.printMsg(templateName + ". Use the " + settings.docDiagramsDebug.name + " flag")
- settings.printMsg("for more information.")
+ settings.printMsg("Graphviz dot encountered an error when generating the diagram for:")
+ settings.printMsg(templateName)
+ settings.printMsg("These are usually spurious errors, but if you notice a persistant error on")
+ settings.printMsg("a diagram, please use the " + settings.docDiagramsDebug.name + " flag and report a bug with the output.")
}
}
}
@@ -173,7 +174,7 @@ class DotProcess(settings: doc.Settings) {
}
stdin.close()
} catch {
- case exc =>
+ case exc: Throwable =>
error = true
stdin.close()
errorBuffer.append(" Input thread in " + templateName + ": Exception: " + exc + "\n")
@@ -199,7 +200,7 @@ class DotProcess(settings: doc.Settings) {
outputString.put(buffer.toString)
stdOut.close()
} catch {
- case exc =>
+ case exc: Throwable =>
error = true
stdOut.close()
errorBuffer.append(" Output thread in " + templateName + ": Exception: " + exc + "\n")
@@ -218,7 +219,7 @@ class DotProcess(settings: doc.Settings) {
}
stdErr.close()
} catch {
- case exc =>
+ case exc: Throwable =>
error = true
stdErr.close()
errorBuffer.append(" Error thread in " + templateName + ": Exception: " + exc + "\n")
diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/diagrams.css b/src/compiler/scala/tools/nsc/doc/html/resource/lib/diagrams.css
index 04d29580b7..5fe33f72f5 100644
--- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/diagrams.css
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/diagrams.css
@@ -119,6 +119,14 @@ svg.class-diagram .node.this.trait.over polygon
fill: #235d7b;
}
+svg.package-diagram .node.type.over polygon,
+svg.class-diagram .node.this.type.over polygon
+{
+ fill: #098552;
+ fill: #04663e;
+}
+
+
svg.package-diagram .node.object.over polygon
{
fill: #183377;
diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js b/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js
index eb7f752440..f29438edfb 100644
--- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js
@@ -15,15 +15,15 @@ var lastHash = "";
$(document).ready(function() {
$('body').layout({ west__size: '20%' });
- $('#browser').layout({
+ $('#browser').layout({
center__paneSelector: ".ui-west-center"
//,center__initClosed:true
,north__paneSelector: ".ui-west-north"
- });
+ });
$('iframe').bind("load", function(){
var subtitle = $(this).contents().find('title').text();
$(document).attr('title', (title ? title + " - " : "") + subtitle);
-
+
setUrlFragmentFromFrameSrc();
});
@@ -81,16 +81,16 @@ function setUrlFragmentFromFrameSrc() {
var commonLength = location.pathname.lastIndexOf("/");
var frameLocation = frames["template"].location;
var relativePath = frameLocation.pathname.slice(commonLength + 1);
-
+
if(!relativePath || frameLocation.pathname.indexOf("/") < 0)
return;
-
+
// Add #, remove ".html" and replace "/" with "."
fragment = "#" + relativePath.replace(/\.html$/, "").replace(/\//g, ".");
-
+
// Add the frame's hash after an @
if(frameLocation.hash) fragment += ("@" + frameLocation.hash.slice(1));
-
+
// Use replace to not add history items
lastFragment = fragment;
location.replace(fragment);
@@ -109,7 +109,7 @@ var Index = {};
if (type == 'object') {
href = t['object'];
} else {
- href = t['class'] || t['trait'] || t['case class'];
+ href = t['class'] || t['trait'] || t['case class'] || t['type'];
}
return [
'<a class="tplshow" target="template" href="',
@@ -142,10 +142,10 @@ var Index = {};
inner += openLink(template, 'object');
}
- if (template['class'] || template['trait'] || template['case class']) {
+ if (template['class'] || template['trait'] || template['case class'] || template['type']) {
inner += (inner == '') ?
'<div class="placeholder" />' : '</a>';
- inner += openLink(template, template['trait'] ? 'trait' : 'class');
+ inner += openLink(template, template['trait'] ? 'trait' : template['type'] ? 'type' : 'class');
} else {
inner += '<div class="placeholder"/>';
}
@@ -245,6 +245,7 @@ function configureEntityList() {
function prepareEntityList() {
var classIcon = $("#library > img.class");
var traitIcon = $("#library > img.trait");
+ var typeIcon = $("#library > img.type");
var objectIcon = $("#library > img.object");
var packageIcon = $("#library > img.package");
@@ -252,6 +253,7 @@ function prepareEntityList() {
$('#tpl li.pack').each(function () {
$("span.class", this).each(function() { $(this).replaceWith(classIcon.clone()); });
$("span.trait", this).each(function() { $(this).replaceWith(traitIcon.clone()); });
+ $("span.type", this).each(function() { $(this).replaceWith(typeIcon.clone()); });
$("span.object", this).each(function() { $(this).replaceWith(objectIcon.clone()); });
$("span.package", this).each(function() { $(this).replaceWith(packageIcon.clone()); });
});
@@ -265,11 +267,11 @@ function keyboardScrolldownLeftPane() {
scheduler.add("init", function() {
$("#textfilter input").blur();
var $items = $("#tpl li");
- $items.first().addClass('selected');
+ $items.first().addClass('selected');
$(window).bind("keydown", function(e) {
var $old = $items.filter('.selected'),
- $new;
+ $new;
switch ( e.keyCode ) {
@@ -286,7 +288,7 @@ function keyboardScrolldownLeftPane() {
case 27: // escape
$old.removeClass('selected');
$(window).unbind(e);
- $("#textfilter input").focus();
+ $("#textfilter input").focus();
break;
@@ -296,7 +298,7 @@ function keyboardScrolldownLeftPane() {
if (!$new.length) {
$new = $old.parent().prev();
}
-
+
if ($new.is('ol') && $new.children(':last').is('ol')) {
$new = $new.children().children(':last');
} else if ($new.is('ol')) {
@@ -313,17 +315,17 @@ function keyboardScrolldownLeftPane() {
if ($new.is('ol')) {
$new = $new.children(':first');
}
- break;
- }
-
+ break;
+ }
+
if ($new.is('li')) {
$old.removeClass('selected');
- $new.addClass('selected');
+ $new.addClass('selected');
} else if (e.keyCode == 38) {
$(window).unbind(e);
$("#textfilter input").focus();
}
- });
+ });
});
}
@@ -342,13 +344,13 @@ function configureTextFilter() {
$("#template").contents().find("#mbrsel-input").focus();
input.attr("value", "");
return false;
- }
+ }
if (event.keyCode == 40) { // down arrow
$(window).unbind("keydown");
keyboardScrolldownLeftPane();
return false;
- }
- textFilter();
+ }
+ textFilter();
});
input.focus(function(event) { input.select(); });
});
@@ -419,7 +421,7 @@ function textFilter() {
});
configureHideFilter();
};
-
+
scheduler.add('filter', searchLoop);
}
diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/object_to_type_big.png b/src/compiler/scala/tools/nsc/doc/html/resource/lib/object_to_type_big.png
new file mode 100644
index 0000000000..7502942eb6
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/object_to_type_big.png
Binary files differ
diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css
index 1bee55313b..6fb7953724 100644
--- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css
@@ -253,6 +253,17 @@ dl.attributes > dd {
color: white;
}
+#groupedMembers > div.group > h3 {
+ background: #dadada url("typebg.gif") repeat-x bottom left; /* green */
+ height: 17px;
+ font-size: 12pt;
+}
+
+#groupedMembers > div.group > h3 * {
+ color: white;
+}
+
+
/* Member cells */
div.members > ol {
@@ -516,6 +527,20 @@ div.members > ol > li:last-child {
/* Comments structured layout */
+.group > div.comment {
+ padding-top: 5px;
+ padding-bottom: 5px;
+ padding-right: 5px;
+ padding-left: 5px;
+ border: 1px solid #ddd;
+ background-color: #eeeee;
+ margin-top:5px;
+ margin-bottom:5px;
+ margin-right:5px;
+ margin-left:5px;
+ display: block;
+}
+
p.comment {
display: block;
margin-left: 14.7em;
diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.js b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.js
index c418c3280b..afd0293fe1 100644
--- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.js
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.js
@@ -43,20 +43,20 @@ $(document).ready(function(){
case 33: //page up
input.val("");
- filter(false);
+ filter(false);
break;
case 34: //page down
input.val("");
- filter(false);
- break;
+ filter(false);
+ break;
- default:
+ default:
window.scrollTo(0, $("#mbrsel").offset().top);
- filter(true);
+ filter(true);
break;
- }
+ }
});
input.focus(function(event) {
input.select();
@@ -70,7 +70,7 @@ $(document).ready(function(){
if (event.keyCode == 9) { // tab
$("#index-input", window.parent.document).focus();
input.attr("value", "");
- return false;
+ return false;
}
});
@@ -135,18 +135,21 @@ $(document).ready(function(){
});
$("#order > ol > li.alpha").click(function() {
if ($(this).hasClass("out")) {
- $(this).removeClass("out").addClass("in");
- $("#order > ol > li.inherit").removeClass("in").addClass("out");
orderAlpha();
};
})
$("#order > ol > li.inherit").click(function() {
if ($(this).hasClass("out")) {
- $(this).removeClass("out").addClass("in");
- $("#order > ol > li.alpha").removeClass("in").addClass("out");
orderInherit();
};
});
+ $("#order > ol > li.group").click(function() {
+ if ($(this).hasClass("out")) {
+ orderGroup();
+ };
+ });
+ $("#groupedMembers").hide();
+
initInherit();
// Create tooltips
@@ -202,9 +205,14 @@ $(document).ready(function(){
// Set parent window title
windowTitle();
+
+ if ($("#order > ol > li.group").length == 1) { orderGroup(); };
});
function orderAlpha() {
+ $("#order > ol > li.alpha").removeClass("out").addClass("in");
+ $("#order > ol > li.inherit").removeClass("in").addClass("out");
+ $("#order > ol > li.group").removeClass("in").addClass("out");
$("#template > div.parent").hide();
$("#template > div.conversion").hide();
$("#mbrsel > div[id=ancestors]").show();
@@ -212,12 +220,25 @@ function orderAlpha() {
};
function orderInherit() {
+ $("#order > ol > li.inherit").removeClass("out").addClass("in");
+ $("#order > ol > li.alpha").removeClass("in").addClass("out");
+ $("#order > ol > li.group").removeClass("in").addClass("out");
$("#template > div.parent").show();
$("#template > div.conversion").show();
$("#mbrsel > div[id=ancestors]").hide();
filter();
};
+function orderGroup() {
+ $("#order > ol > li.group").removeClass("out").addClass("in");
+ $("#order > ol > li.alpha").removeClass("in").addClass("out");
+ $("#order > ol > li.inherit").removeClass("in").addClass("out");
+ $("#template > div.parent").hide();
+ $("#template > div.conversion").hide();
+ $("#mbrsel > div[id=ancestors]").show();
+ filter();
+};
+
/** Prepares the DOM for inheritance-based display. To do so it will:
* - hide all statically-generated parents headings;
* - copy all members from the value and type members lists (flat members) to corresponding lists nested below the
@@ -225,44 +246,74 @@ function orderInherit() {
* - initialises a control variable used by the filter method to control whether filtering happens on flat members
* or on inheritance-grouped members. */
function initInherit() {
- // parents is a map from fully-qualified names to the DOM node of parent headings.
- var parents = new Object();
+ // inheritParents is a map from fully-qualified names to the DOM node of parent headings.
+ var inheritParents = new Object();
+ var groupParents = new Object();
$("#inheritedMembers > div.parent").each(function(){
- parents[$(this).attr("name")] = $(this);
+ inheritParents[$(this).attr("name")] = $(this);
});
$("#inheritedMembers > div.conversion").each(function(){
- parents[$(this).attr("name")] = $(this);
+ inheritParents[$(this).attr("name")] = $(this);
+ });
+ $("#groupedMembers > div.group").each(function(){
+ groupParents[$(this).attr("name")] = $(this);
});
+
$("#types > ol > li").each(function(){
var mbr = $(this);
this.mbrText = mbr.find("> .fullcomment .cmt").text();
var qualName = mbr.attr("name");
var owner = qualName.slice(0, qualName.indexOf("#"));
var name = qualName.slice(qualName.indexOf("#") + 1);
- var parent = parents[owner];
- if (parent != undefined) {
- var types = $("> .types > ol", parent);
+ var inheritParent = inheritParents[owner];
+ if (inheritParent != undefined) {
+ var types = $("> .types > ol", inheritParent);
+ if (types.length == 0) {
+ inheritParent.append("<div class='types members'><h3>Type Members</h3><ol></ol></div>");
+ types = $("> .types > ol", inheritParent);
+ }
+ var clone = mbr.clone();
+ clone[0].mbrText = this.mbrText;
+ types.append(clone);
+ }
+ var group = mbr.attr("group")
+ var groupParent = groupParents[group];
+ if (groupParent != undefined) {
+ var types = $("> .types > ol", groupParent);
if (types.length == 0) {
- parent.append("<div class='types members'><h3>Type Members</h3><ol></ol></div>");
- types = $("> .types > ol", parent);
+ groupParent.append("<div class='types members'><ol></ol></div>");
+ types = $("> .types > ol", groupParent);
}
var clone = mbr.clone();
clone[0].mbrText = this.mbrText;
types.append(clone);
}
});
+
$("#values > ol > li").each(function(){
var mbr = $(this);
this.mbrText = mbr.find("> .fullcomment .cmt").text();
var qualName = mbr.attr("name");
var owner = qualName.slice(0, qualName.indexOf("#"));
var name = qualName.slice(qualName.indexOf("#") + 1);
- var parent = parents[owner];
- if (parent != undefined) {
- var values = $("> .values > ol", parent);
+ var inheritParent = inheritParents[owner];
+ if (inheritParent != undefined) {
+ var values = $("> .values > ol", inheritParent);
if (values.length == 0) {
- parent.append("<div class='values members'><h3>Value Members</h3><ol></ol></div>");
- values = $("> .values > ol", parent);
+ inheritParent.append("<div class='values members'><h3>Value Members</h3><ol></ol></div>");
+ values = $("> .values > ol", inheritParent);
+ }
+ var clone = mbr.clone();
+ clone[0].mbrText = this.mbrText;
+ values.append(clone);
+ }
+ var group = mbr.attr("group")
+ var groupParent = groupParents[group];
+ if (groupParent != undefined) {
+ var values = $("> .values > ol", groupParent);
+ if (values.length == 0) {
+ groupParent.append("<div class='values members'><ol></ol></div>");
+ values = $("> .values > ol", groupParent);
}
var clone = mbr.clone();
clone[0].mbrText = this.mbrText;
@@ -275,6 +326,9 @@ function initInherit() {
$("#inheritedMembers > div.conversion").each(function() {
if ($("> div.members", this).length == 0) { $(this).remove(); };
});
+ $("#groupedMembers > div.group").each(function() {
+ if ($("> div.members", this).length == 0) { $(this).remove(); };
+ });
};
/* filter used to take boolean scrollToMember */
@@ -284,26 +338,43 @@ function filter() {
var queryRegExp = new RegExp(query, "i");
var privateMembersHidden = $("#visbl > ol > li.public").hasClass("in");
var orderingAlphabetic = $("#order > ol > li.alpha").hasClass("in");
- var hiddenSuperclassElementsLinearization = orderingAlphabetic ? $("#linearization > li.out") : $("#linearization > li:gt(0)");
+ var orderingInheritance = $("#order > ol > li.inherit").hasClass("in");
+ var orderingGroups = $("#order > ol > li.group").hasClass("in");
+ var hiddenSuperclassElementsLinearization = orderingInheritance ? $("#linearization > li:gt(0)") : $("#linearization > li.out");
var hiddenSuperclassesLinearization = hiddenSuperclassElementsLinearization.map(function() {
return $(this).attr("name");
}).get();
- var hiddenSuperclassElementsImplicits = orderingAlphabetic ? $("#implicits > li.out") : $("#implicits > li");
+ var hiddenSuperclassElementsImplicits = orderingInheritance ? $("#implicits > li") : $("#implicits > li.out");
var hiddenSuperclassesImplicits = hiddenSuperclassElementsImplicits.map(function() {
return $(this).attr("name");
}).get();
var hideInheritedMembers;
- if(orderingAlphabetic) {
+ if (orderingAlphabetic) {
+ $("#allMembers").show();
$("#inheritedMembers").hide();
+ $("#groupedMembers").hide();
hideInheritedMembers = true;
$("#allMembers > .members").each(filterFunc);
- }
- else {
- $("#inheritedMembers").show();
+ } else if (orderingGroups) {
+ $("#groupedMembers").show();
+ $("#inheritedMembers").hide();
+ $("#allMembers").hide();
hideInheritedMembers = true;
- $("#allMembers > .members").each(filterFunc);
+ $("#groupedMembers > .group > .members").each(filterFunc);
+ $("#groupedMembers > div.group").each(function() {
+ $(this).show();
+ if ($("> div.members", this).not(":hidden").length == 0) {
+ $(this).hide();
+ } else {
+ $(this).show();
+ }
+ });
+ } else if (orderingInheritance) {
+ $("#inheritedMembers").show();
+ $("#groupedMembers").hide();
+ $("#allMembers").hide();
hideInheritedMembers = false;
$("#inheritedMembers > .parent > .members").each(filterFunc);
$("#inheritedMembers > .conversion > .members").each(filterFunc);
diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/type.png b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type.png
new file mode 100644
index 0000000000..366ec4e992
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type.png
Binary files differ
diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_big.png b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_big.png
new file mode 100644
index 0000000000..df0dc118bf
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_big.png
Binary files differ
diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_diagram.png b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_diagram.png
new file mode 100644
index 0000000000..d6fbb84ff2
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_diagram.png
Binary files differ
diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_to_object_big.png b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_to_object_big.png
new file mode 100644
index 0000000000..1bd2833a63
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_to_object_big.png
Binary files differ
diff --git a/src/compiler/scala/tools/nsc/doc/model/Entity.scala b/src/compiler/scala/tools/nsc/doc/model/Entity.scala
index 2901daafd6..16ade0787e 100644
--- a/src/compiler/scala/tools/nsc/doc/model/Entity.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/Entity.scala
@@ -53,6 +53,15 @@ trait Entity {
/** The kind of the entity */
def kind: String
+
+ /** Whether or not the template was defined in a package object */
+ def inPackageObject: Boolean
+
+ /** Indicates whether this entity lives in the types namespace (classes, traits, abstract/alias types) */
+ def isType: Boolean
+
+ /** Indicates whether this entity lives in the terms namespace (objects, packages, methods, values) */
+ def isTerm: Boolean
}
object Entity {
@@ -88,17 +97,14 @@ trait TemplateEntity extends Entity {
/** Whether documentation is available for this template. */
def isDocTemplate: Boolean
+ /** Whether documentation is available for this template. */
+ def isNoDocMemberTemplate: Boolean
+
/** Whether this template is a case class. */
def isCaseClass: Boolean
- /** Whether or not the template was defined in a package object */
- def inPackageObject: Boolean
-
/** The self-type of this template, if it differs from the template type. */
def selfType : Option[TypeEntity]
-
- /** The type of this entity, with type members */
- def ownType: TypeEntity
}
@@ -110,6 +116,9 @@ trait MemberEntity extends Entity {
/** The comment attached to this member, if any. */
def comment: Option[Comment]
+ /** The group this member is from */
+ def group: String
+
/** The template of which this entity is a member. */
def inTemplate: DocTemplateEntity
@@ -179,11 +188,28 @@ trait MemberEntity extends Entity {
/** If this symbol is a use case, the useCaseOf will contain the member it was derived from, containing the full
* signature and the complete parameter descriptions. */
- def useCaseOf: Option[MemberEntity] = None
+ def useCaseOf: Option[MemberEntity]
/** If this member originates from an implicit conversion, we set the implicit information to the correct origin */
def byConversion: Option[ImplicitConversion]
+
+ /** The identity of this member, used for linking */
+ def signature: String
+
+ /** Indicates whether the member is inherited by implicit conversion */
+ def isImplicitlyInherited: Boolean
+
+ /** Indicates whether there is another member with the same name in the template that will take precendence */
+ def isShadowedImplicit: Boolean
+
+ /** Indicates whether there are other implicitly inherited members that have similar signatures (and thus they all
+ * become ambiguous) */
+ def isAmbiguousImplicit: Boolean
+
+ /** Indicates whether the implicitly inherited member is shadowed or ambiguous in its template */
+ def isShadowedOrAmbiguousImplicit: Boolean
}
+
object MemberEntity {
// Oh contravariance, contravariance, wherefore art thou contravariance?
// Note: the above works for both the commonly misunderstood meaning of the line and the real one.
@@ -195,24 +221,38 @@ trait HigherKinded {
/** The type parameters of this entity. */
def typeParams: List[TypeParam]
-
}
/** A template (class, trait, object or package) which is referenced in the universe, but for which no further
* documentation is available. Only templates for which a source file is given are documented by Scaladoc. */
trait NoDocTemplate extends TemplateEntity {
- def kind = "<no doc>"
+ def kind =
+ if (isClass) "class"
+ else if (isTrait) "trait"
+ else if (isObject) "object"
+ else ""
}
-/** TODO: Document */
-trait NoDocTemplateMemberEntity extends TemplateEntity with MemberEntity {
- def kind = "<no doc, mbr>"
+/** An inherited template that was not documented in its original owner - example:
+ * in classpath: trait T { class C } -- T (and implicitly C) are not documented
+ * in the source: trait U extends T -- C appears in U as a MemberTemplateImpl
+ * -- that is, U has a member for it but C doesn't get its own page */
+trait MemberTemplateEntity extends TemplateEntity with MemberEntity with HigherKinded {
+
+ /** The value parameters of this case class, or an empty list if this class is not a case class. As case class value
+ * parameters cannot be curried, the outer list has exactly one element. */
+ def valueParams: List[List[ValueParam]]
+
+ /** The direct super-type of this template
+ e.g: {{{class A extends B[C[Int]] with D[E]}}} will have two direct parents: class B and D
+ NOTE: we are dropping the refinement here! */
+ def parentTypes: List[(TemplateEntity, TypeEntity)]
}
/** A template (class, trait, object or package) for which documentation is available. Only templates for which
* a source file is given are documented by Scaladoc. */
-trait DocTemplateEntity extends TemplateEntity with MemberEntity {
+trait DocTemplateEntity extends MemberTemplateEntity {
/** The list of templates such that each is a member of the template that follows it; the first template is always
* this template, the last the root package entity. */
@@ -226,11 +266,6 @@ trait DocTemplateEntity extends TemplateEntity with MemberEntity {
* only if the `docsourceurl` setting has been set. */
def sourceUrl: Option[java.net.URL]
- /** The direct super-type of this template
- e.g: {{{class A extends B[C[Int]] with D[E]}}} will have two direct parents: class B and D
- NOTE: we are dropping the refinement here! */
- def parentTypes: List[(TemplateEntity, TypeEntity)]
-
/** All class, trait and object templates which are part of this template's linearization, in lineratization order.
* This template's linearization contains all of its direct and indirect super-classes and super-traits. */
def linearizationTemplates: List[TemplateEntity]
@@ -253,7 +288,7 @@ trait DocTemplateEntity extends TemplateEntity with MemberEntity {
/** All templates that are members of this template. If this template is a package, only templates for which
* documentation is available in the universe (`DocTemplateEntity`) are listed. */
- def templates: List[DocTemplateEntity]
+ def templates: List[TemplateEntity with MemberEntity]
/** All methods that are members of this template. */
def methods: List[Def]
@@ -267,6 +302,12 @@ trait DocTemplateEntity extends TemplateEntity with MemberEntity {
/** All type aliases that are members of this template. */
def aliasTypes: List[AliasType]
+ /** The primary constructor of this class, if it has been defined. */
+ def primaryConstructor: Option[Constructor]
+
+ /** All constructors of this class, including the primary constructor. */
+ def constructors: List[Constructor]
+
/** The companion of this template, or none. If a class and an object are defined as a pair of the same name, the
* other entity of the pair is the companion. */
def companion: Option[DocTemplateEntity]
@@ -289,41 +330,35 @@ trait DocTemplateEntity extends TemplateEntity with MemberEntity {
/** If this template contains other templates, such as classes and traits, they will be shown in this diagram */
def contentDiagram: Option[Diagram]
-}
+ /** Returns the group description taken either from this template or its linearizationTypes */
+ def groupDescription(group: String): Option[Body]
+
+ /** Returns the group description taken either from this template or its linearizationTypes */
+ def groupPriority(group: String): Int
+
+ /** Returns the group description taken either from this template or its linearizationTypes */
+ def groupName(group: String): String
+}
/** A trait template. */
-trait Trait extends DocTemplateEntity with HigherKinded {
+trait Trait extends MemberTemplateEntity {
def kind = "trait"
}
-
/** A class template. */
-trait Class extends Trait with HigherKinded {
-
- /** The primary constructor of this class, if it has been defined. */
- def primaryConstructor: Option[Constructor]
-
- /** All constructors of this class, including the primary constructor. */
- def constructors: List[Constructor]
-
- /** The value parameters of this case class, or an empty list if this class is not a case class. As case class value
- * parameters cannot be curried, the outer list has exactly one element. */
- def valueParams: List[List[ValueParam]]
-
+trait Class extends MemberTemplateEntity {
override def kind = "class"
}
-
/** An object template. */
-trait Object extends DocTemplateEntity {
+trait Object extends MemberTemplateEntity {
def kind = "object"
}
-
/** A package template. A package is in the universe if it is declared as a package object, or if it
* contains at least one template. */
-trait Package extends Object {
+trait Package extends DocTemplateEntity {
/** The package of which this package is a member. */
def inTemplate: Package
@@ -354,7 +389,6 @@ trait NonTemplateMemberEntity extends MemberEntity {
/** Whether this member is a bridge member. A bridge member does only exist for binary compatibility reasons
* and should not appear in ScalaDoc. */
def isBridge: Boolean
-
}
@@ -391,7 +425,7 @@ trait Val extends NonTemplateMemberEntity {
/** An abstract type member of a template. */
-trait AbstractType extends NonTemplateMemberEntity with HigherKinded {
+trait AbstractType extends MemberTemplateEntity with HigherKinded {
/** The lower bound for this abstract type, if it has been defined. */
def lo: Option[TypeEntity]
@@ -404,7 +438,7 @@ trait AbstractType extends NonTemplateMemberEntity with HigherKinded {
/** An type alias of a template. */
-trait AliasType extends NonTemplateMemberEntity with HigherKinded {
+trait AliasType extends MemberTemplateEntity with HigherKinded {
/** The type aliased by this type alias. */
def alias: TypeEntity
@@ -495,6 +529,9 @@ trait ImplicitConversion {
/** The members inherited by this implicit conversion */
def members: List[MemberEntity]
+
+ /** Is this a common implicit conversion (aka conversion that affects all classes, in Predef?) */
+ def isCommonConversion: Boolean
}
/** Shadowing captures the information that the member is shadowed by some other members
diff --git a/src/compiler/scala/tools/nsc/doc/model/IndexModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/IndexModelFactory.scala
index 6392de22ff..f4c96505a7 100755
--- a/src/compiler/scala/tools/nsc/doc/model/IndexModelFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/IndexModelFactory.scala
@@ -36,7 +36,6 @@ object IndexModelFactory {
} + d
this(firstLetter) = letter + (d.name -> members)
}
-
}
//@scala.annotation.tailrec // TODO
@@ -46,11 +45,7 @@ object IndexModelFactory {
case tpl: DocTemplateEntity =>
result.addMember(tpl)
gather(tpl)
- case alias: AliasType =>
- result.addMember(alias)
- case absType: AbstractType =>
- result.addMember(absType)
- case non: NonTemplateMemberEntity if !non.isConstructor =>
+ case non: MemberEntity if !non.isConstructor =>
result.addMember(non)
case x @ _ =>
}
diff --git a/src/compiler/scala/tools/nsc/doc/model/Links.scala b/src/compiler/scala/tools/nsc/doc/model/Links.scala
new file mode 100644
index 0000000000..b76dee0f14
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/model/Links.scala
@@ -0,0 +1,24 @@
+/* NSC -- new Scala compiler
+ * Copyright 2007-2011 LAMP/EPFL
+ */
+
+package scala.tools.nsc
+package doc
+package model
+
+import scala.collection._
+
+abstract sealed class LinkTo
+case class LinkToTpl(tpl: DocTemplateEntity) extends LinkTo
+case class LinkToMember(mbr: MemberEntity, inTpl: DocTemplateEntity) extends LinkTo
+case class Tooltip(name: String) extends LinkTo { def this(tpl: TemplateEntity) = this(tpl.qualifiedName) }
+// case class LinkToExternal(name: String, url: String) extends LinkTo // for SI-191, whenever Manohar will have time
+case object NoLink extends LinkTo // you should use Tooltip if you have a name from the user, this is only in case all fails
+
+object LinkToTpl {
+ // this makes it easier to create links
+ def apply(tpl: TemplateEntity) = tpl match {
+ case dtpl: DocTemplateEntity => new LinkToTpl(dtpl)
+ case ntpl: TemplateEntity => new Tooltip(ntpl.qualifiedName)
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala
new file mode 100644
index 0000000000..ab14498a7c
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala
@@ -0,0 +1,187 @@
+package scala.tools.nsc
+package doc
+package model
+
+import comment._
+
+import scala.reflect.internal.util.FakePos //Position
+
+/** This trait extracts all required information for documentation from compilation units */
+trait MemberLookup {
+ thisFactory: ModelFactory =>
+
+ import global._
+
+ def makeEntityLink(title: Inline, pos: Position, query: String, inTplOpt: Option[DocTemplateImpl]) =
+ new EntityLink(title) { lazy val link = memberLookup(pos, query, inTplOpt) }
+
+ def memberLookup(pos: Position, query: String, inTplOpt: Option[DocTemplateImpl]): LinkTo = {
+ assert(modelFinished)
+
+ var members = breakMembers(query)
+ //println(query + " => " + members)
+
+ // (1) Lookup in the root package, as most of the links are qualified
+ var linkTo: List[LinkTo] = lookupInRootPackage(pos, members)
+
+ // (2) Recursively go into each
+ if (inTplOpt.isDefined) {
+ var currentTpl = inTplOpt.get
+ while (currentTpl != null && !currentTpl.isRootPackage && (linkTo.isEmpty)) {
+ linkTo = lookupInTemplate(pos, members, currentTpl)
+ currentTpl = currentTpl.inTemplate
+ }
+ }
+
+ // (3) Look at external links
+ if (linkTo.isEmpty) {
+ // TODO: IF THIS IS THE ROOT PACKAGE, LOOK AT EXTERNAL LINKS
+ }
+
+ // (4) if we still haven't found anything, create a tooltip, if we found too many, report
+ if (linkTo.isEmpty){
+ if (!settings.docNoLinkWarnings.value)
+ reporter.warning(pos, "Could not find any member to link for \"" + query + "\".")
+ Tooltip(query)
+ } else {
+ if (linkTo.length > 1) {
+
+ val chosen =
+ if (linkTo.exists(_.isInstanceOf[LinkToMember]))
+ linkTo.collect({case lm: LinkToMember => lm}).min(Ordering[MemberEntity].on[LinkToMember](_.mbr))
+ else
+ linkTo.head
+
+ def linkToString(link: LinkTo) = {
+ val description =
+ link match {
+ case lm@LinkToMember(mbr, inTpl) => " * " + mbr.kind + " \"" + mbr.signature + "\" in " + inTpl.kind + " " + inTpl.qualifiedName
+ case lt@LinkToTpl(tpl) => " * " + tpl.kind + " \"" + tpl.qualifiedName + "\""
+ case other => " * " + other.toString
+ }
+ val chosenInfo =
+ if (link == chosen)
+ " [chosen]"
+ else
+ ""
+ description + chosenInfo + "\n"
+ }
+ if (!settings.docNoLinkWarnings.value)
+ reporter.warning(pos,
+ "The link target \"" + query + "\" is ambiguous. Several (possibly overloaded) members fit the target:\n" +
+ linkTo.map(link => linkToString(link)).mkString +
+ (if (MemberLookup.showExplanation)
+ "\n\n" +
+ "Quick crash course on using Scaladoc links\n" +
+ "==========================================\n" +
+ "Disambiguating terms and types: Prefix terms with '$' and types with '!' in case both names are in use:\n" +
+ " - [[scala.collection.immutable.List!.apply class List's apply method]] and\n" +
+ " - [[scala.collection.immutable.List$.apply object List's apply method]]\n" +
+ "Disambiguating overloaded members: If a term is overloaded, you can indicate the first part of its signature followed by *:\n" +
+ " - [[[scala.collection.immutable.List$.fill[A](Int)(⇒A):List[A]* Fill with a single parameter]]]\n" +
+ " - [[[scala.collection.immutable.List$.fill[A](Int,Int)(⇒A):List[List[A]]* Fill with a two parameters]]]\n" +
+ "Notes: \n" +
+ " - you can use any number of matching square brackets to avoid interference with the signature\n" +
+ " - you can use \\. to escape dots in prefixes (don't forget to use * at the end to match the signature!)\n" +
+ " - you can use \\# to escape hashes, otherwise they will be considered as delimiters, like dots.\n"
+ else "")
+ )
+ chosen
+ } else
+ linkTo.head
+ }
+ }
+
+ private abstract class SearchStrategy
+ private object BothTypeAndTerm extends SearchStrategy
+ private object OnlyType extends SearchStrategy
+ private object OnlyTerm extends SearchStrategy
+
+ private def lookupInRootPackage(pos: Position, members: List[String]) = lookupInTemplate(pos, members, makeRootPackage)
+
+ private def lookupInTemplate(pos: Position, members: List[String], inTpl: DocTemplateImpl): List[LinkTo] = {
+ // Maintaining compatibility with previous links is a bit tricky here:
+ // we have a preference for term names for all terms except for the last, where we prefer a class:
+ // How to do this:
+ // - at each step we do a DFS search with the prefered strategy
+ // - if the search doesn't return any members, we backtrack on the last decision
+ // * we look for terms with the last member's name
+ // * we look for types with the same name, all the way up
+ val result = members match {
+ case Nil =>
+ Nil
+ case mbrName::Nil =>
+ var members = lookupInTemplate(pos, mbrName, inTpl, OnlyType)
+ if (members.isEmpty)
+ members = lookupInTemplate(pos, mbrName, inTpl, OnlyTerm)
+
+ members.map(_ match {
+ case tpl: DocTemplateEntity => LinkToTpl(tpl)
+ case mbr => LinkToMember(mbr, inTpl)
+ })
+
+ case tplName::rest =>
+
+ def completeSearch(mbrs: List[MemberImpl]) =
+ mbrs.collect({case d:DocTemplateImpl => d}).flatMap(tpl => lookupInTemplate(pos, rest, tpl))
+
+ var members = completeSearch(lookupInTemplate(pos, tplName, inTpl, OnlyTerm))
+ if (members.isEmpty)
+ members = completeSearch(lookupInTemplate(pos, tplName, inTpl, OnlyType))
+
+ members
+ }
+ //println("lookupInTemplate(" + members + ", " + inTpl + ") => " + result)
+ result
+ }
+
+ private def lookupInTemplate(pos: Position, member: String, inTpl: DocTemplateImpl, strategy: SearchStrategy): List[MemberImpl] = {
+ val name = member.stripSuffix("$").stripSuffix("!").stripSuffix("*")
+ val result = if (member.endsWith("$"))
+ inTpl.members.filter(mbr => (mbr.name == name) && (mbr.isTerm))
+ else if (member.endsWith("!"))
+ inTpl.members.filter(mbr => (mbr.name == name) && (mbr.isType))
+ else if (member.endsWith("*"))
+ inTpl.members.filter(mbr => (mbr.signature.startsWith(name)))
+ else {
+ if (strategy == BothTypeAndTerm)
+ inTpl.members.filter(_.name == name)
+ else if (strategy == OnlyType)
+ inTpl.members.filter(mbr => (mbr.name == name) && (mbr.isType))
+ else if (strategy == OnlyTerm)
+ inTpl.members.filter(mbr => (mbr.name == name) && (mbr.isTerm))
+ else
+ Nil
+ }
+
+ //println("lookupInTemplate(" + member + ", " + inTpl + ") => " + result)
+ result
+ }
+
+ private def breakMembers(query: String): List[String] = {
+ // Okay, how does this work? Well: you split on . but you don't want to split on \. => thus the ugly regex
+ // query.split((?<=[^\\\\])\\.).map(_.replaceAll("\\."))
+ // The same code, just faster:
+ var members = List[String]()
+ var index = 0
+ var last_index = 0
+ val length = query.length
+ while (index < length) {
+ if ((query.charAt(index) == '.' || query.charAt(index) == '#') &&
+ ((index == 0) || (query.charAt(index-1) != '\\'))) {
+
+ members ::= query.substring(last_index, index).replaceAll("\\\\([#\\.])", "$1")
+ last_index = index + 1
+ }
+ index += 1
+ }
+ if (last_index < length)
+ members ::= query.substring(last_index, length).replaceAll("\\\\\\.", ".")
+ members.reverse
+ }
+}
+
+object MemberLookup {
+ private[this] var _showExplanation = true
+ def showExplanation: Boolean = if (_showExplanation) { _showExplanation = false; true } else false
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
index 9fa6619e9f..00e6f3769e 100644
--- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
@@ -19,7 +19,13 @@ import model.{ RootPackage => RootPackageEntity }
/** This trait extracts all required information for documentation from compilation units */
class ModelFactory(val global: Global, val settings: doc.Settings) {
- thisFactory: ModelFactory with ModelFactoryImplicitSupport with DiagramFactory with CommentFactory with TreeFactory =>
+ thisFactory: ModelFactory
+ with ModelFactoryImplicitSupport
+ with ModelFactoryTypeSupport
+ with DiagramFactory
+ with CommentFactory
+ with TreeFactory
+ with MemberLookup =>
import global._
import definitions.{ ObjectClass, NothingClass, AnyClass, AnyValClass, AnyRefClass }
@@ -32,7 +38,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
private var universe: Universe = null
private def dbg(msg: String) = if (sys.props contains "scala.scaladoc.debug") println(msg)
- private def closestPackage(sym: Symbol) = {
+ protected def closestPackage(sym: Symbol) = {
if (sym.isPackage || sym.isPackageClass) sym
else sym.enclosingPackage
}
@@ -63,7 +69,10 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
private val droppedPackages = mutable.Set[PackageImpl]()
protected val docTemplatesCache = new mutable.LinkedHashMap[Symbol, DocTemplateImpl]
protected val noDocTemplatesCache = new mutable.LinkedHashMap[Symbol, NoDocTemplateImpl]
- protected var typeCache = new mutable.LinkedHashMap[Type, TypeEntity]
+ def packageDropped(tpl: DocTemplateImpl) = tpl match {
+ case p: PackageImpl => droppedPackages(p)
+ case _ => false
+ }
def optimize(str: String): String =
if (str.length < 16) str.intern else str
@@ -83,6 +92,9 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
def toRoot: List[EntityImpl] = this :: inTpl.toRoot
def qualifiedName = name
def annotations = sym.annotations.map(makeAnnotation)
+ def inPackageObject: Boolean = sym.owner.isModuleClass && sym.owner.sourceModule.isPackageObject
+ def isType = sym.name.isTypeName
+ def isTerm = sym.name.isTermName
}
trait TemplateImpl extends EntityImpl with TemplateEntity {
@@ -94,13 +106,22 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
def isObject = sym.isModule && !sym.isPackage
def isCaseClass = sym.isCaseClass
def isRootPackage = false
- def ownType = makeType(sym.tpe, this)
+ def isNoDocMemberTemplate = false
def selfType = if (sym.thisSym eq sym) None else Some(makeType(sym.thisSym.typeOfThis, this))
- def inPackageObject: Boolean = sym.owner.isModuleClass && sym.owner.sourceModule.isPackageObject
}
- abstract class MemberImpl(sym: Symbol, implConv: ImplicitConversionImpl, inTpl: DocTemplateImpl) extends EntityImpl(sym, inTpl) with MemberEntity {
- lazy val comment = if (inTpl != null) thisFactory.comment(sym, inTpl) else None
+ abstract class MemberImpl(sym: Symbol, inTpl: DocTemplateImpl) extends EntityImpl(sym, inTpl) with MemberEntity {
+ lazy val comment = {
+ // If the current tpl is a DocTemplate, we consider itself as the root for resolving link targets (instead of the
+ // package the class is in) -- so people can refer to methods directly [[foo]], instead of using [[MyClass.foo]]
+ // in the doc comment of MyClass
+ val thisTpl = this match {
+ case d: DocTemplateImpl => Some(d)
+ case _ => None
+ }
+ if (inTpl != null) thisFactory.comment(sym, thisTpl, inTpl) else None
+ }
+ def group = if (comment.isDefined) comment.get.group.getOrElse("No Group") else "No Group"
override def inTemplate = inTpl
override def toRoot: List[MemberImpl] = this :: inTpl.toRoot
def inDefinitionTemplates = this match {
@@ -138,16 +159,16 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
* }}}
* the type the method returns is TraversableOps, which has all-abstract symbols. But in reality, it couldn't have
* any abstract terms, otherwise it would fail compilation. So we reset the DEFERRED flag. */
- if (!sym.isTrait && (sym hasFlag Flags.DEFERRED) && (implConv eq null)) fgs += Paragraph(Text("abstract"))
+ if (!sym.isTrait && (sym hasFlag Flags.DEFERRED) && (!isImplicitlyInherited)) fgs += Paragraph(Text("abstract"))
if (!sym.isModule && (sym hasFlag Flags.FINAL)) fgs += Paragraph(Text("final"))
fgs.toList
}
def deprecation =
if (sym.isDeprecated)
Some((sym.deprecationMessage, sym.deprecationVersion) match {
- case (Some(msg), Some(ver)) => parseWiki("''(Since version " + ver + ")'' " + msg, NoPosition)
- case (Some(msg), None) => parseWiki(msg, NoPosition)
- case (None, Some(ver)) => parseWiki("''(Since version " + ver + ")''", NoPosition)
+ case (Some(msg), Some(ver)) => parseWiki("''(Since version " + ver + ")'' " + msg, NoPosition, Some(inTpl))
+ case (Some(msg), None) => parseWiki(msg, NoPosition, Some(inTpl))
+ case (None, Some(ver)) => parseWiki("''(Since version " + ver + ")''", NoPosition, Some(inTpl))
case (None, None) => Body(Nil)
})
else
@@ -155,9 +176,9 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
def migration =
if(sym.hasMigrationAnnotation)
Some((sym.migrationMessage, sym.migrationVersion) match {
- case (Some(msg), Some(ver)) => parseWiki("''(Changed in version " + ver + ")'' " + msg, NoPosition)
- case (Some(msg), None) => parseWiki(msg, NoPosition)
- case (None, Some(ver)) => parseWiki("''(Changed in version " + ver + ")''", NoPosition)
+ case (Some(msg), Some(ver)) => parseWiki("''(Changed in version " + ver + ")'' " + msg, NoPosition, Some(inTpl))
+ case (Some(msg), None) => parseWiki(msg, NoPosition, Some(inTpl))
+ case (None, Some(ver)) => parseWiki("''(Changed in version " + ver + ")''", NoPosition, Some(inTpl))
case (None, None) => Body(Nil)
})
else
@@ -172,7 +193,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
case NullaryMethodType(res) => resultTpe(res)
case _ => tpe
}
- val tpe = if (implConv eq null) sym.tpe else implConv.toType memberInfo sym
+ val tpe = if (!isImplicitlyInherited) sym.tpe else byConversion.get.toType memberInfo sym
makeTypeInTemplateContext(resultTpe(tpe), inTemplate, sym)
}
def isDef = false
@@ -184,11 +205,43 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
def isAliasType = false
def isAbstractType = false
def isAbstract =
- // for the explanation of implConv == null see comment on flags
- ((!sym.isTrait && ((sym hasFlag Flags.ABSTRACT) || (sym hasFlag Flags.DEFERRED)) && (implConv == null)) ||
+ // for the explanation of conversion == null see comment on flags
+ ((!sym.isTrait && ((sym hasFlag Flags.ABSTRACT) || (sym hasFlag Flags.DEFERRED)) && (!isImplicitlyInherited)) ||
sym.isAbstractClass || sym.isAbstractType) && !sym.isSynthetic
def isTemplate = false
- def byConversion = if (implConv ne null) Some(implConv) else None
+ lazy val signature = {
+
+ def defParams(mbr: Any): String = mbr match {
+ case d: MemberEntity with Def =>
+ val paramLists: List[String] =
+ if (d.valueParams.isEmpty) Nil
+ else d.valueParams map (ps => ps map (_.resultType.name) mkString ("(",",",")"))
+ paramLists.mkString
+ case _ => ""
+ }
+
+ def tParams(mbr: Any): String = mbr match {
+ case hk: HigherKinded if !hk.typeParams.isEmpty =>
+ def boundsToString(hi: Option[TypeEntity], lo: Option[TypeEntity]): String = {
+ def bound0(bnd: Option[TypeEntity], pre: String): String = bnd match {
+ case None => ""
+ case Some(tpe) => pre ++ tpe.toString
+ }
+ bound0(hi, "<:") ++ bound0(lo, ">:")
+ }
+ "[" + hk.typeParams.map(tp => tp.variance + tp.name + tParams(tp) + boundsToString(tp.hi, tp.lo)).mkString(", ") + "]"
+ case _ => ""
+ }
+
+ (name + tParams(this) + defParams(this) +":"+ resultType.name).replaceAll("\\s","") // no spaces allowed, they break links
+ }
+ // these only apply for NonTemplateMemberEntities
+ def useCaseOf: Option[MemberEntity] = None
+ def byConversion: Option[ImplicitConversionImpl] = None
+ def isImplicitlyInherited = false
+ def isShadowedImplicit = false
+ def isAmbiguousImplicit = false
+ def isShadowedOrAmbiguousImplicit = false
}
/** A template that is not documented at all. The class is instantiated during lookups, to indicate that the class
@@ -198,26 +251,53 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
assert(modelFinished)
assert(!(noDocTemplatesCache isDefinedAt sym))
noDocTemplatesCache += (sym -> this)
-
def isDocTemplate = false
}
/** An inherited template that was not documented in its original owner - example:
* in classpath: trait T { class C } -- T (and implicitly C) are not documented
- * in the source: trait U extends T -- C appears in U as a NoDocTemplateMemberImpl -- that is, U has a member for it
+ * in the source: trait U extends T -- C appears in U as a MemberTemplateImpl -- that is, U has a member for it
* but C doesn't get its own page
*/
- class NoDocTemplateMemberImpl(sym: Symbol, inTpl: DocTemplateImpl) extends MemberImpl(sym, null, inTpl) with TemplateImpl with HigherKindedImpl with NoDocTemplateMemberEntity {
- assert(modelFinished)
-
+ abstract class MemberTemplateImpl(sym: Symbol, inTpl: DocTemplateImpl) extends MemberImpl(sym, inTpl) with TemplateImpl with HigherKindedImpl with MemberTemplateEntity {
+ // no templates cache for this class, each owner gets its own instance
+ override def isTemplate = true
def isDocTemplate = false
+ override def isNoDocMemberTemplate = true
lazy val definitionName = optimize(inDefinitionTemplates.head.qualifiedName + "." + name)
+ def valueParams: List[List[ValueParam]] = Nil /** TODO, these are now only computed for DocTemplates */
+
+ // Seems unused
+ // def parentTemplates =
+ // if (sym.isPackage || sym == AnyClass)
+ // List()
+ // else
+ // sym.tpe.parents.flatMap { tpe: Type =>
+ // val tSym = tpe.typeSymbol
+ // if (tSym != NoSymbol)
+ // List(makeTemplate(tSym))
+ // else
+ // List()
+ // } filter (_.isInstanceOf[DocTemplateEntity])
+
+ def parentTypes =
+ if (sym.isPackage || sym == AnyClass) List() else {
+ val tps = (this match {
+ case a: AliasType => sym.tpe.dealias.parents
+ case a: AbstractType => sym.info.bounds match {
+ case TypeBounds(lo, hi) => List(hi)
+ case _ => Nil
+ }
+ case _ => sym.tpe.parents
+ }) map { _.asSeenFrom(sym.thisType, sym) }
+ makeParentTypes(RefinedType(tps, EmptyScope), Some(this), inTpl)
+ }
}
/** The instantiation of `TemplateImpl` triggers the creation of the following entities:
* All ancestors of the template and all non-package members.
*/
- abstract class DocTemplateImpl(sym: Symbol, inTpl: DocTemplateImpl) extends MemberImpl(sym, null, inTpl) with TemplateImpl with HigherKindedImpl with DocTemplateEntity {
+ abstract class DocTemplateImpl(sym: Symbol, inTpl: DocTemplateImpl) extends MemberTemplateImpl(sym, inTpl) with DocTemplateEntity {
assert(!modelFinished)
assert(!(docTemplatesCache isDefinedAt sym), sym)
docTemplatesCache += (sym -> this)
@@ -253,24 +333,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
else None
}
- def parentTemplates =
- if (sym.isPackage || sym == AnyClass)
- List()
- else
- sym.tpe.parents.flatMap { tpe: Type =>
- val tSym = tpe.typeSymbol
- if (tSym != NoSymbol)
- List(makeTemplate(tSym))
- else
- List()
- } filter (_.isInstanceOf[DocTemplateEntity])
-
- def parentTypes =
- if (sym.isPackage || sym == AnyClass) List() else {
- val tps = sym.tpe.parents map { _.asSeenFrom(sym.thisType, sym) }
- makeParentTypes(RefinedType(tps, EmptyScope), Some(this), inTpl)
- }
-
protected def linearizationFromSymbol(symbol: Symbol): List[(TemplateEntity, TypeEntity)] = {
symbol.ancestors map { ancestor =>
val typeEntity = makeType(symbol.info.baseType(ancestor), this)
@@ -299,14 +361,14 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
def directSubClasses = allSubClasses.filter(_.parentTypes.map(_._1).contains(this))
/* Implcitly convertible class cache */
- private var implicitlyConvertibleClassesCache: mutable.ListBuffer[(DocTemplateEntity, ImplicitConversionImpl)] = null
- def registerImplicitlyConvertibleClass(dtpl: DocTemplateEntity, conv: ImplicitConversionImpl): Unit = {
+ private var implicitlyConvertibleClassesCache: mutable.ListBuffer[(DocTemplateImpl, ImplicitConversionImpl)] = null
+ def registerImplicitlyConvertibleClass(dtpl: DocTemplateImpl, conv: ImplicitConversionImpl): Unit = {
if (implicitlyConvertibleClassesCache == null)
- implicitlyConvertibleClassesCache = mutable.ListBuffer[(DocTemplateEntity, ImplicitConversionImpl)]()
+ implicitlyConvertibleClassesCache = mutable.ListBuffer[(DocTemplateImpl, ImplicitConversionImpl)]()
implicitlyConvertibleClassesCache += ((dtpl, conv))
}
- def incomingImplicitlyConvertedClasses: List[(DocTemplateEntity, ImplicitConversionImpl)] =
+ def incomingImplicitlyConvertedClasses: List[(DocTemplateImpl, ImplicitConversionImpl)] =
if (implicitlyConvertibleClassesCache == null)
List()
else
@@ -321,16 +383,16 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
lazy val memberSyms = sym.info.members.filter(s => membersShouldDocument(s, this))
// the inherited templates (classes, traits or objects)
- var memberSymsLazy = memberSyms.filter(t => templateShouldDocument(t, this) && !inOriginalOnwer(t, this))
+ var memberSymsLazy = memberSyms.filter(t => templateShouldDocument(t, this) && !inOriginalOwner(t, this))
// the direct members (methods, values, vars, types and directly contained templates)
var memberSymsEager = memberSyms.filter(!memberSymsLazy.contains(_))
// the members generated by the symbols in memberSymsEager
- val ownMembers = (memberSyms.flatMap(makeMember(_, null, this)))
+ val ownMembers = (memberSymsEager.flatMap(makeMember(_, None, this)))
// all the members that are documentented PLUS the members inherited by implicit conversions
var members: List[MemberImpl] = ownMembers
- def templates = members collect { case c: DocTemplateEntity => c }
+ def templates = members collect { case c: TemplateEntity with MemberEntity => c }
def methods = members collect { case d: Def => d }
def values = members collect { case v: Val => v }
def abstractTypes = members collect { case t: AbstractType => t }
@@ -342,13 +404,15 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
*/
def completeModel: Unit = {
// DFS completion
- for (member <- members)
- member match {
- case d: DocTemplateImpl => d.completeModel
- case _ =>
- }
+ // since alias types and abstract types have no own members, there's no reason for them to call completeModel
+ if (!sym.isAliasType && !sym.isAbstractType)
+ for (member <- members)
+ member match {
+ case d: DocTemplateImpl => d.completeModel
+ case _ =>
+ }
- members :::= memberSymsLazy.map(modelCreation.createLazyTemplateMember(_, inTpl))
+ members :::= memberSymsLazy.map(modelCreation.createLazyTemplateMember(_, this))
// compute linearization to register subclasses
linearization
@@ -369,7 +433,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
conv.targetTypeComponents map {
case pair@(template, tpe) =>
template match {
- case d: DocTemplateImpl => d.registerImplicitlyConvertibleClass(this, conv)
+ case d: DocTemplateImpl if (d != this) => d.registerImplicitlyConvertibleClass(this, conv)
case _ => // nothing
}
(pair._1, pair._2, conv)
@@ -378,21 +442,66 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
)
override def isTemplate = true
- lazy val definitionName = optimize(inDefinitionTemplates.head.qualifiedName + "." + name)
- def isDocTemplate = true
- def companion = sym.companionSymbol match {
- case NoSymbol => None
- case comSym if !isEmptyJavaObject(comSym) && (comSym.isClass || comSym.isModule) =>
- makeTemplate(comSym) match {
- case d: DocTemplateImpl => Some(d)
- case _ => None
+ override def isDocTemplate = true
+ private[this] lazy val companionSymbol =
+ if (sym.isAliasType || sym.isAbstractType) {
+ inTpl.sym.info.member(sym.name.toTermName) match {
+ case NoSymbol => NoSymbol
+ case s =>
+ s.info match {
+ case ot: OverloadedType =>
+ NoSymbol
+ case _ =>
+ // that's to navigate from val Foo: FooExtractor to FooExtractor :)
+ s.info.resultType.typeSymbol
+ }
}
- case _ => None
+ }
+ else
+ sym.companionSymbol
+
+ def companion =
+ companionSymbol match {
+ case NoSymbol => None
+ case comSym if !isEmptyJavaObject(comSym) && (comSym.isClass || comSym.isModule) =>
+ makeTemplate(comSym) match {
+ case d: DocTemplateImpl => Some(d)
+ case _ => None
+ }
+ case _ => None
+ }
+
+ def constructors: List[MemberImpl with Constructor] = if (isClass) members collect { case d: Constructor => d } else Nil
+ def primaryConstructor: Option[MemberImpl with Constructor] = if (isClass) constructors find { _.isPrimary } else None
+ override def valueParams =
+ // we don't want params on a class (non case class) signature
+ if (isCaseClass) primaryConstructor match {
+ case Some(const) => const.sym.paramss map (_ map (makeValueParam(_, this)))
+ case None => List()
+ }
+ else List.empty
+
+ // These are generated on-demand, make sure you don't call them more than once
+ def inheritanceDiagram = makeInheritanceDiagram(this)
+ def contentDiagram = makeContentDiagram(this)
+
+ def groupSearch[T](extractor: Comment => T, default: T): T = {
+ // query this template
+ if (comment.isDefined) {
+ val entity = extractor(comment.get)
+ if (entity != default) return entity
+ }
+ // query linearization
+ for (tpl <- linearizationTemplates.collect{ case dtpl: DocTemplateImpl if dtpl!=this => dtpl}) {
+ val entity = tpl.groupSearch(extractor, default)
+ if (entity != default) return entity
+ }
+ default
}
- // We make the diagram a lazy val, since we're not sure we'll include the diagrams in the page
- lazy val inheritanceDiagram = makeInheritanceDiagram(this)
- lazy val contentDiagram = makeContentDiagram(this)
+ def groupDescription(group: String): Option[Body] = groupSearch(_.groupDesc.get(group), None)
+ def groupPriority(group: String): Int = groupSearch(_.groupPrio.get(group) match { case Some(prio) => prio; case _ => 0 }, 0)
+ def groupName(group: String): String = groupSearch(_.groupNames.get(group) match { case Some(name) => name; case _ => group }, group)
}
abstract class PackageImpl(sym: Symbol, inTpl: PackageImpl) extends DocTemplateImpl(sym, inTpl) with Package {
@@ -409,18 +518,49 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
abstract class RootPackageImpl(sym: Symbol) extends PackageImpl(sym, null) with RootPackageEntity
- abstract class NonTemplateMemberImpl(sym: Symbol, implConv: ImplicitConversionImpl, inTpl: DocTemplateImpl) extends MemberImpl(sym, implConv, inTpl) with NonTemplateMemberEntity {
+ abstract class NonTemplateMemberImpl(sym: Symbol, conversion: Option[ImplicitConversionImpl],
+ override val useCaseOf: Option[MemberEntity], inTpl: DocTemplateImpl)
+ extends MemberImpl(sym, inTpl) with NonTemplateMemberEntity {
+ override lazy val comment = {
+ val inRealTpl =
+ /* Variable precendence order for implicitly added members: Take the variable defifinitions from ...
+ * 1. the target of the implicit conversion
+ * 2. the definition template (owner)
+ * 3. the current template
+ */
+ if (conversion.isDefined) findTemplateMaybe(conversion.get.toType.typeSymbol) match {
+ case Some(d) if d != makeRootPackage => d //in case of NoSymbol, it will give us the root package
+ case _ => findTemplateMaybe(sym.owner) match {
+ case Some(d) if d != makeRootPackage => d //in case of NoSymbol, it will give us the root package
+ case _ => inTpl
+ }
+ } else inTpl
+ if (inRealTpl != null) thisFactory.comment(sym, None, inRealTpl) else None
+ }
+
override def qualifiedName = optimize(inTemplate.qualifiedName + "#" + name)
- lazy val definitionName =
- if (implConv == null) optimize(inDefinitionTemplates.head.qualifiedName + "#" + name)
- else optimize(implConv.conversionQualifiedName + "#" + name)
- def isUseCase = sym.isSynthetic
+ lazy val definitionName = {
+ // this contrived name is here just to satisfy some older tests -- if you decide to remove it, be my guest, and
+ // also remove property("package object") from test/scaladoc/scalacheck/HtmlFactoryTest.scala so you don't break
+ // the test suite...
+ val packageObject = if (inPackageObject) ".package" else ""
+ if (!conversion.isDefined) optimize(inDefinitionTemplates.head.qualifiedName + packageObject + "#" + name)
+ else optimize(conversion.get.conversionQualifiedName + packageObject + "#" + name)
+ }
def isBridge = sym.isBridge
+ def isUseCase = useCaseOf.isDefined
+ override def byConversion: Option[ImplicitConversionImpl] = conversion
+ override def isImplicitlyInherited = { assert(modelFinished); conversion.isDefined }
+ override def isShadowedImplicit = isImplicitlyInherited && inTpl.implicitsShadowing.get(this).map(_.isShadowed).getOrElse(false)
+ override def isAmbiguousImplicit = isImplicitlyInherited && inTpl.implicitsShadowing.get(this).map(_.isAmbiguous).getOrElse(false)
+ override def isShadowedOrAmbiguousImplicit = isShadowedImplicit || isAmbiguousImplicit
}
- abstract class NonTemplateParamMemberImpl(sym: Symbol, implConv: ImplicitConversionImpl, inTpl: DocTemplateImpl) extends NonTemplateMemberImpl(sym, implConv, inTpl) {
+ abstract class NonTemplateParamMemberImpl(sym: Symbol, conversion: Option[ImplicitConversionImpl],
+ useCaseOf: Option[MemberEntity], inTpl: DocTemplateImpl)
+ extends NonTemplateMemberImpl(sym, conversion, useCaseOf, inTpl) {
def valueParams = {
- val info = if (implConv eq null) sym.info else implConv.toType memberInfo sym
+ val info = if (!isImplicitlyInherited) sym.info else conversion.get.toType memberInfo sym
info.paramss map { ps => (ps.zipWithIndex) map { case (p, i) =>
if (p.nameString contains "$") makeValueParam(p, inTpl, optimize("arg" + i)) else makeValueParam(p, inTpl)
}}
@@ -431,6 +571,12 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
val name = optimize(sym.nameString)
}
+ private trait AliasImpl {
+ def sym: Symbol
+ def inTpl: TemplateImpl
+ def alias = makeTypeInTemplateContext(sym.tpe.dealias, inTpl, sym)
+ }
+
private trait TypeBoundsImpl {
def sym: Symbol
def inTpl: TemplateImpl
@@ -454,14 +600,42 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
}
/* ============== MAKER METHODS ============== */
- /** */
+ /** This method makes it easier to work with the different kinds of symbols created by scalac by stripping down the
+ * package object abstraction and placing members directly in the package.
+ *
+ * Here's the explanation of what we do. The code:
+ *
+ * package foo {
+ * object `package` {
+ * class Bar
+ * }
+ * }
+ *
+ * will yield this Symbol structure:
+ * +---------+ (2)
+ * | |
+ * +---------------+ +---------- v ------- | ---+ +--------+ (2)
+ * | package foo#1 <---(1)---- module class foo#2 | | | |
+ * +---------------+ | +------------------ | -+ | +------------------- v ---+ |
+ * | | package object foo#3 <-----(1)---- module class package#4 | |
+ * | +----------------------+ | | +---------------------+ | |
+ * +--------------------------+ | | class package$Bar#5 | | |
+ * | +----------------- | -+ | |
+ * +------------------- | ---+ |
+ * | |
+ * +--------+
+ * (1) sourceModule
+ * (2) you get out of owners with .owner
+ *
+ * and normalizeTemplate(Bar.owner) will get us the package, instead of the module class of the package object.
+ */
def normalizeTemplate(aSym: Symbol): Symbol = aSym match {
case null | rootMirror.EmptyPackage | NoSymbol =>
normalizeTemplate(RootPackage)
case ObjectClass =>
normalizeTemplate(AnyRefClass)
case _ if aSym.isPackageObject =>
- aSym
+ normalizeTemplate(aSym.owner)
case _ if aSym.isModuleClass =>
normalizeTemplate(aSym.sourceModule)
case _ =>
@@ -477,13 +651,16 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
def createRootPackage: PackageImpl = docTemplatesCache.get(RootPackage) match {
case Some(root: PackageImpl) => root
- case _ => modelCreation.createTemplate(RootPackage, null).asInstanceOf[PackageImpl]
+ case _ => modelCreation.createTemplate(RootPackage, null) match {
+ case Some(root: PackageImpl) => root
+ case _ => sys.error("Scaladoc: Unable to create root package!")
+ }
}
/**
* Create a template, either a package, class, trait or object
*/
- def createTemplate(aSym: Symbol, inTpl: DocTemplateImpl): DocTemplateImpl = {
+ def createTemplate(aSym: Symbol, inTpl: DocTemplateImpl): Option[MemberImpl] = {
// don't call this after the model finished!
assert(!modelFinished)
@@ -493,7 +670,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
import Streamable._
Path(settings.docRootContent.value) match {
case f : File => {
- val rootComment = closing(f.inputStream)(is => parse(slurp(is), "", NoPosition))
+ val rootComment = closing(f.inputStream)(is => parse(slurp(is), "", NoPosition, Option(inTpl)))
Some(rootComment)
}
case _ => None
@@ -501,27 +678,24 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
}
def createDocTemplate(bSym: Symbol, inTpl: DocTemplateImpl): DocTemplateImpl = {
- if (bSym.isModule || (bSym.isAliasType && bSym.tpe.typeSymbol.isModule))
- new DocTemplateImpl(bSym, inTpl) with Object
- else if (bSym.isTrait || (bSym.isAliasType && bSym.tpe.typeSymbol.isTrait))
- new DocTemplateImpl(bSym, inTpl) with Trait
- else if (bSym.isClass || (bSym.isAliasType && bSym.tpe.typeSymbol.isClass))
- new DocTemplateImpl(bSym, inTpl) with Class {
- def valueParams =
- // we don't want params on a class (non case class) signature
- if (isCaseClass) List(sym.constrParamAccessors map (makeValueParam(_, this)))
- else List.empty
- val constructors =
- members collect { case d: Constructor => d }
- def primaryConstructor = constructors find { _.isPrimary }
- }
+ assert(!modelFinished) // only created BEFORE the model is finished
+ if (bSym.isAliasType && bSym != AnyRefClass)
+ new DocTemplateImpl(bSym, inTpl) with AliasImpl with AliasType { override def isAliasType = true }
+ else if (bSym.isAbstractType)
+ new DocTemplateImpl(bSym, inTpl) with TypeBoundsImpl with AbstractType { override def isAbstractType = true }
+ else if (bSym.isModule)
+ new DocTemplateImpl(bSym, inTpl) with Object {}
+ else if (bSym.isTrait)
+ new DocTemplateImpl(bSym, inTpl) with Trait {}
+ else if (bSym.isClass || bSym == AnyRefClass)
+ new DocTemplateImpl(bSym, inTpl) with Class {}
else
- sys.error("'" + bSym + "' isn't a class, trait or object thus cannot be built as a documentable template")
+ sys.error("'" + bSym + "' isn't a class, trait or object thus cannot be built as a documentable template.")
}
val bSym = normalizeTemplate(aSym)
if (docTemplatesCache isDefinedAt bSym)
- return docTemplatesCache(bSym)
+ return Some(docTemplatesCache(bSym))
/* Three cases of templates:
* (1) root package -- special cased for bootstrapping
@@ -529,7 +703,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
* (3) class/object/trait
*/
if (bSym == RootPackage) // (1)
- new RootPackageImpl(bSym) {
+ Some(new RootPackageImpl(bSym) {
override lazy val comment = createRootPackageComment
override val name = "root"
override def inTemplate = this
@@ -541,31 +715,52 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
(bSym.info.members ++ EmptyPackage.info.members) filter { s =>
s != EmptyPackage && s != RootPackage
}
- }
+ })
else if (bSym.isPackage) // (2)
- inTpl match {
- case inPkg: PackageImpl =>
- val pack = new PackageImpl(bSym, inPkg) {}
- if (pack.templates.isEmpty && pack.memberSymsLazy.isEmpty)
- droppedPackages += pack
- pack
- case _ =>
- sys.error("'" + bSym + "' must be in a package")
- }
+ if (settings.skipPackage(makeQualifiedName(bSym)))
+ None
+ else
+ inTpl match {
+ case inPkg: PackageImpl =>
+ val pack = new PackageImpl(bSym, inPkg) {}
+ // Used to check package pruning works:
+ //println(pack.qualifiedName)
+ if (pack.templates.filter(_.isDocTemplate).isEmpty && pack.memberSymsLazy.isEmpty) {
+ droppedPackages += pack
+ None
+ } else
+ Some(pack)
+ case _ =>
+ sys.error("'" + bSym + "' must be in a package")
+ }
else {
// no class inheritance at this point
- assert(inOriginalOnwer(bSym, inTpl))
- createDocTemplate(bSym, inTpl)
+ assert(inOriginalOwner(bSym, inTpl) || bSym.isAbstractType || bSym.isAliasType, bSym + " in " + inTpl)
+ Some(createDocTemplate(bSym, inTpl))
}
}
/**
* After the model is completed, no more DocTemplateEntities are created.
* Therefore any symbol that still appears is:
- * - NoDocTemplateMemberEntity (created here)
+ * - MemberTemplateEntity (created here)
* - NoDocTemplateEntity (created in makeTemplate)
*/
def createLazyTemplateMember(aSym: Symbol, inTpl: DocTemplateImpl): MemberImpl = {
+
+ // Code is duplicate because the anonymous classes are created statically
+ def createNoDocMemberTemplate(bSym: Symbol, inTpl: DocTemplateImpl): MemberTemplateImpl = {
+ assert(modelFinished) // only created AFTER the model is finished
+ if (bSym.isModule || (bSym.isAliasType && bSym.tpe.typeSymbol.isModule))
+ new MemberTemplateImpl(bSym, inTpl) with Object {}
+ else if (bSym.isTrait || (bSym.isAliasType && bSym.tpe.typeSymbol.isTrait))
+ new MemberTemplateImpl(bSym, inTpl) with Trait {}
+ else if (bSym.isClass || (bSym.isAliasType && bSym.tpe.typeSymbol.isClass))
+ new MemberTemplateImpl(bSym, inTpl) with Class {}
+ else
+ sys.error("'" + bSym + "' isn't a class, trait or object thus cannot be built as a member template.")
+ }
+
assert(modelFinished)
val bSym = normalizeTemplate(aSym)
@@ -579,7 +774,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
mbrs.head
case _ =>
// move the class completely to the new location
- new NoDocTemplateMemberImpl(aSym, inTpl)
+ createNoDocMemberTemplate(bSym, inTpl)
}
}
}
@@ -588,20 +783,18 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
def makeRootPackage: PackageImpl = docTemplatesCache(RootPackage).asInstanceOf[PackageImpl]
// TODO: Should be able to override the type
- def makeMember(aSym: Symbol, implConv: ImplicitConversionImpl, inTpl: DocTemplateImpl): List[MemberImpl] = {
+ def makeMember(aSym: Symbol, conversion: Option[ImplicitConversionImpl], inTpl: DocTemplateImpl): List[MemberImpl] = {
- def makeMember0(bSym: Symbol, _useCaseOf: Option[MemberImpl]): Option[MemberImpl] = {
+ def makeMember0(bSym: Symbol, useCaseOf: Option[MemberImpl]): Option[MemberImpl] = {
if (bSym.isGetter && bSym.isLazy)
- Some(new NonTemplateMemberImpl(bSym, implConv, inTpl) with Val {
+ Some(new NonTemplateMemberImpl(bSym, conversion, useCaseOf, inTpl) with Val {
override lazy val comment = // The analyser does not duplicate the lazy val's DocDef when it introduces its accessor.
- thisFactory.comment(bSym.accessed, inTpl.asInstanceOf[DocTemplateImpl]) // This hack should be removed after analyser is fixed.
+ thisFactory.comment(bSym.accessed, None, inTpl.asInstanceOf[DocTemplateImpl]) // This hack should be removed after analyser is fixed.
override def isLazyVal = true
- override def useCaseOf = _useCaseOf
})
else if (bSym.isGetter && bSym.accessed.isMutable)
- Some(new NonTemplateMemberImpl(bSym, implConv, inTpl) with Val {
+ Some(new NonTemplateMemberImpl(bSym, conversion, useCaseOf, inTpl) with Val {
override def isVar = true
- override def useCaseOf = _useCaseOf
})
else if (bSym.isMethod && !bSym.hasAccessorFlag && !bSym.isConstructor && !bSym.isModule) {
val cSym = { // This unsightly hack closes issue #4086.
@@ -615,45 +808,32 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
}
else bSym
}
- Some(new NonTemplateParamMemberImpl(cSym, implConv, inTpl) with HigherKindedImpl with Def {
+ Some(new NonTemplateParamMemberImpl(cSym, conversion, useCaseOf, inTpl) with HigherKindedImpl with Def {
override def isDef = true
- override def useCaseOf = _useCaseOf
})
}
- else if (bSym.isConstructor && (implConv == null))
- Some(new NonTemplateParamMemberImpl(bSym, implConv, inTpl) with Constructor {
- override def isConstructor = true
- def isPrimary = sym.isPrimaryConstructor
- override def useCaseOf = _useCaseOf
- })
+ else if (bSym.isConstructor)
+ if (conversion.isDefined)
+ None // don't list constructors inherted by implicit conversion
+ else
+ Some(new NonTemplateParamMemberImpl(bSym, conversion, useCaseOf, inTpl) with Constructor {
+ override def isConstructor = true
+ def isPrimary = sym.isPrimaryConstructor
+ })
else if (bSym.isGetter) // Scala field accessor or Java field
- Some(new NonTemplateMemberImpl(bSym, implConv, inTpl) with Val {
+ Some(new NonTemplateMemberImpl(bSym, conversion, useCaseOf, inTpl) with Val {
override def isVal = true
- override def useCaseOf = _useCaseOf
})
- else if (bSym.isAbstractType)
- Some(new NonTemplateMemberImpl(bSym, implConv, inTpl) with TypeBoundsImpl with HigherKindedImpl with AbstractType {
+ else if (bSym.isAbstractType && !typeShouldDocument(bSym, inTpl))
+ Some(new MemberTemplateImpl(bSym, inTpl) with TypeBoundsImpl with AbstractType {
override def isAbstractType = true
- override def useCaseOf = _useCaseOf
})
- else if (bSym.isAliasType && bSym != AnyRefClass)
- Some(new NonTemplateMemberImpl(bSym, implConv, inTpl) with HigherKindedImpl with AliasType {
+ else if (bSym.isAliasType && !typeShouldDocument(bSym, inTpl))
+ Some(new MemberTemplateImpl(bSym, inTpl) with AliasImpl with AliasType {
override def isAliasType = true
- def alias = makeTypeInTemplateContext(sym.tpe.dealias, inTpl, sym)
- override def useCaseOf = _useCaseOf
})
- else if (bSym.isPackage && !modelFinished)
- inTpl match {
- case inPkg: PackageImpl => modelCreation.createTemplate(bSym, inTpl) match {
- case p: PackageImpl if droppedPackages contains p => None
- case p: PackageImpl => Some(p)
- case _ => sys.error("'" + bSym + "' must be a package")
- }
- case _ =>
- sys.error("'" + bSym + "' must be in a package")
- }
- else if (!modelFinished && templateShouldDocument(bSym, inTpl) && inOriginalOnwer(bSym, inTpl))
- Some(modelCreation.createTemplate(bSym, inTpl))
+ else if (!modelFinished && (bSym.isPackage || bSym.isAliasType || bSym.isAbstractType || templateShouldDocument(bSym, inTpl)))
+ modelCreation.createTemplate(bSym, inTpl)
else
None
}
@@ -680,17 +860,20 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
inTpl.members.find(_.sym == aSym)
}
+ @deprecated("2.10", "Use findLinkTarget instead!")
def findTemplate(query: String): Option[DocTemplateImpl] = {
assert(modelFinished)
- docTemplatesCache.values find { (tpl: TemplateImpl) => tpl.qualifiedName == query && !tpl.isObject }
+ docTemplatesCache.values find { (tpl: DocTemplateImpl) => tpl.qualifiedName == query && !packageDropped(tpl) && !tpl.isObject }
}
def findTemplateMaybe(aSym: Symbol): Option[DocTemplateImpl] = {
assert(modelFinished)
- docTemplatesCache.get(normalizeTemplate(aSym))
+ docTemplatesCache.get(normalizeTemplate(aSym)).filterNot(packageDropped(_))
}
- def makeTemplate(aSym: Symbol): TemplateImpl = {
+ def makeTemplate(aSym: Symbol): TemplateImpl = makeTemplate(aSym, None)
+
+ def makeTemplate(aSym: Symbol, inTpl: Option[TemplateImpl]): TemplateImpl = {
assert(modelFinished)
def makeNoDocTemplate(aSym: Symbol, inTpl: TemplateImpl): NoDocTemplateImpl = {
@@ -706,11 +889,10 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
dtpl
case None =>
val bSym = normalizeTemplate(aSym)
- makeNoDocTemplate(bSym, makeTemplate(bSym.owner))
+ makeNoDocTemplate(bSym, if (inTpl.isDefined) inTpl.get else makeTemplate(bSym.owner))
}
}
-
/** */
def makeAnnotation(annot: AnnotationInfo): Annotation = {
val aSym = annot.symbol
@@ -720,7 +902,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
val arguments = { // lazy
def noParams = annot.args map { _ => None }
val params: List[Option[ValueParam]] = annotationClass match {
- case aClass: Class =>
+ case aClass: DocTemplateEntity with Class =>
(aClass.primaryConstructor map { _.valueParams.head }) match {
case Some(vps) => vps map { Some(_) }
case None => noParams
@@ -795,17 +977,37 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
}
/** Get the types of the parents of the current class, ignoring the refinements */
- def makeParentTypes(aType: Type, tpl: Option[DocTemplateImpl], inTpl: TemplateImpl): List[(TemplateEntity, TypeEntity)] = aType match {
+ def makeParentTypes(aType: Type, tpl: Option[MemberTemplateImpl], inTpl: TemplateImpl): List[(TemplateEntity, TypeEntity)] = aType match {
case RefinedType(parents, defs) =>
- val ignoreParents = Set[Symbol](AnyRefClass, ObjectClass)
+ val ignoreParents = Set[Symbol](AnyClass, AnyRefClass, ObjectClass)
val filtParents =
// we don't want to expose too many links to AnyRef, that will just be redundant information
- if (tpl.isDefined && (!tpl.get.isObject && parents.length < 2))
+ if (tpl.isDefined && { val sym = tpl.get.sym; (!sym.isModule && parents.length < 2) || (sym == AnyValClass) || (sym == AnyRefClass) || (sym == AnyClass) })
parents
else
parents.filterNot((p: Type) => ignoreParents(p.typeSymbol))
+
+ /** Returns:
+ * - a DocTemplate if the type's symbol is documented
+ * - a NoDocTemplateMember if the type's symbol is not documented in its parent but in another template
+ * - a NoDocTemplate if the type's symbol is not documented at all */
+ def makeTemplateOrMemberTemplate(parent: Type): TemplateImpl = {
+ def noDocTemplate = makeTemplate(parent.typeSymbol)
+ findTemplateMaybe(parent.typeSymbol) match {
+ case Some(tpl) => tpl
+ case None => parent match {
+ case TypeRef(pre, sym, args) =>
+ findTemplateMaybe(pre.typeSymbol) match {
+ case Some(tpl) => findMember(parent.typeSymbol, tpl).collect({case t: TemplateImpl => t}).getOrElse(noDocTemplate)
+ case None => noDocTemplate
+ }
+ case _ => noDocTemplate
+ }
+ }
+ }
+
filtParents.map(parent => {
- val templateEntity = makeTemplate(parent.typeSymbol)
+ val templateEntity = makeTemplateOrMemberTemplate(parent)
val typeEntity = makeType(parent, inTpl)
(templateEntity, typeEntity)
})
@@ -813,160 +1015,38 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
List((makeTemplate(aType.typeSymbol), makeType(aType, inTpl)))
}
- /** */
- def makeType(aType: Type, inTpl: TemplateImpl): TypeEntity = {
- def templatePackage = closestPackage(inTpl.sym)
-
- def createTypeEntity = new TypeEntity {
- private val nameBuffer = new StringBuilder
- private var refBuffer = new immutable.TreeMap[Int, (TemplateEntity, Int)]
- private def appendTypes0(types: List[Type], sep: String): Unit = types match {
- case Nil =>
- case tp :: Nil =>
- appendType0(tp)
- case tp :: tps =>
- appendType0(tp)
- nameBuffer append sep
- appendTypes0(tps, sep)
- }
-
- private def appendType0(tpe: Type): Unit = tpe match {
- /* Type refs */
- case tp: TypeRef if definitions.isFunctionType(tp) =>
- val args = tp.normalize.typeArgs
- nameBuffer append '('
- appendTypes0(args.init, ", ")
- nameBuffer append ") ⇒ "
- appendType0(args.last)
- case tp: TypeRef if definitions.isScalaRepeatedParamType(tp) =>
- appendType0(tp.args.head)
- nameBuffer append '*'
- case tp: TypeRef if definitions.isByNameParamType(tp) =>
- nameBuffer append "⇒ "
- appendType0(tp.args.head)
- case tp: TypeRef if definitions.isTupleType(tp) =>
- val args = tp.normalize.typeArgs
- nameBuffer append '('
- appendTypes0(args, ", ")
- nameBuffer append ')'
- case TypeRef(pre, aSym, targs) =>
- val preSym = pre.widen.typeSymbol
- // There's a work in progress here trying to deal with the
- // places where undesirable prefixes are printed.
- // ...
- // If the prefix is something worthy of printing, see if the prefix type
- // is in the same package as the enclosing template. If so, print it
- // unqualified and they'll figure it out.
- //
- // val stripPrefixes = List(templatePackage.fullName + ".", "package.", "java.lang.")
- // if (!preSym.printWithoutPrefix) {
- // nameBuffer append stripPrefixes.foldLeft(pre.prefixString)(_ stripPrefix _)
- // }
- val bSym = normalizeTemplate(aSym)
- if (bSym.isNonClassType && bSym != AnyRefClass) {
- nameBuffer append bSym.decodedName
- } else {
- val tpl = makeTemplate(bSym)
- val pos0 = nameBuffer.length
- refBuffer += pos0 -> (tpl, tpl.name.length)
- nameBuffer append tpl.name
- }
- if (!targs.isEmpty) {
- nameBuffer append '['
- appendTypes0(targs, ", ")
- nameBuffer append ']'
- }
- /* Refined types */
- case RefinedType(parents, defs) =>
- val ignoreParents = Set[Symbol](AnyClass, ObjectClass)
- val filtParents = parents filterNot (x => ignoreParents(x.typeSymbol)) match {
- case Nil => parents
- case ps => ps
- }
- appendTypes0(filtParents, " with ")
- // XXX Still todo: properly printing refinements.
- // Since I didn't know how to go about displaying a multi-line type, I went with
- // printing single method refinements (which should be the most common) and printing
- // the number of members if there are more.
- defs.toList match {
- case Nil => ()
- case x :: Nil => nameBuffer append (" { " + x.defString + " }")
- case xs => nameBuffer append (" { ... /* %d definitions in type refinement */ }" format xs.size)
- }
- /* Eval-by-name types */
- case NullaryMethodType(result) =>
- nameBuffer append '⇒'
- appendType0(result)
- /* Polymorphic types */
- case PolyType(tparams, result) => assert(tparams.nonEmpty)
-// throw new Error("Polymorphic type '" + tpe + "' cannot be printed as a type")
- def typeParamsToString(tps: List[Symbol]): String = if (tps.isEmpty) "" else
- tps.map{tparam =>
- tparam.varianceString + tparam.name + typeParamsToString(tparam.typeParams)
- }.mkString("[", ", ", "]")
- nameBuffer append typeParamsToString(tparams)
- appendType0(result)
- case tpen =>
- nameBuffer append tpen.toString
+ def makeQualifiedName(sym: Symbol, relativeTo: Option[Symbol] = None): String = {
+ val stop = if (relativeTo.isDefined) relativeTo.get.ownerChain.toSet else Set[Symbol]()
+ var sym1 = sym
+ var path = new StringBuilder()
+ // var path = List[Symbol]()
+
+ while ((sym1 != NoSymbol) && (path.isEmpty || !stop(sym1))) {
+ val sym1Norm = normalizeTemplate(sym1)
+ if (!sym1.sourceModule.isPackageObject && sym1Norm != RootPackage) {
+ if (path.length != 0)
+ path.insert(0, ".")
+ path.insert(0, sym1Norm.nameString)
+ // path::= sym1Norm
}
- appendType0(aType)
- val refEntity = refBuffer
- val name = optimize(nameBuffer.toString)
+ sym1 = sym1.owner
}
- if (aType.isTrivial)
- typeCache.get(aType) match {
- case Some(typeEntity) => typeEntity
- case None =>
- val typeEntity = createTypeEntity
- typeCache += aType -> typeEntity
- typeEntity
- }
- else
- createTypeEntity
+ optimize(path.toString)
+ //path.mkString(".")
}
- def normalizeOwner(aSym: Symbol): Symbol =
- /*
- * Okay, here's the explanation of what happens. The code:
- *
- * package foo {
- * object `package` {
- * class Bar
- * }
- * }
- *
- * will yield this Symbol structure:
- *
- * +---------------+ +--------------------------+
- * | package foo#1 ----(1)---> module class foo#2 |
- * +---------------+ | +----------------------+ | +-------------------------+
- * | | package object foo#3 ------(1)---> module class package#4 |
- * | +----------------------+ | | +---------------------+ |
- * +--------------------------+ | | class package$Bar#5 | |
- * | +---------------------+ |
- * +-------------------------+
- * (1) sourceModule
- * (2) you get out of owners with .owner
- */
- normalizeTemplate(aSym) match {
- case bSym if bSym.isPackageObject =>
- normalizeOwner(bSym.owner)
- case bSym =>
- bSym
- }
-
- def inOriginalOnwer(aSym: Symbol, inTpl: TemplateImpl): Boolean =
- normalizeOwner(aSym.owner) == normalizeOwner(inTpl.sym)
+ def inOriginalOwner(aSym: Symbol, inTpl: TemplateImpl): Boolean =
+ normalizeTemplate(aSym.owner) == normalizeTemplate(inTpl.sym)
def templateShouldDocument(aSym: Symbol, inTpl: TemplateImpl): Boolean =
- (aSym.isClass || aSym.isModule || aSym == AnyRefClass) &&
+ (aSym.isTrait || aSym.isClass || aSym.isModule) &&
localShouldDocument(aSym) &&
!isEmptyJavaObject(aSym) &&
// either it's inside the original owner or we can document it later:
- (!inOriginalOnwer(aSym, inTpl) || (aSym.isPackageClass || (aSym.sourceFile != null)))
+ (!inOriginalOwner(aSym, inTpl) || (aSym.isPackageClass || (aSym.sourceFile != null)))
- def membersShouldDocument(sym: Symbol, inTpl: TemplateImpl) =
+ def membersShouldDocument(sym: Symbol, inTpl: TemplateImpl) = {
// pruning modules that shouldn't be documented
// Why Symbol.isInitialized? Well, because we need to avoid exploring all the space available to scaladoc
// from the classpath -- scaladoc is a hog, it will explore everything starting from the root package unless we
@@ -979,6 +1059,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
(!sym.isConstructor || sym.owner == inTpl.sym) &&
// If the @bridge annotation overrides a normal member, show it
!isPureBridge(sym)
+ }
def isEmptyJavaObject(aSym: Symbol): Boolean =
aSym.isModule && aSym.isJavaDefined &&
@@ -995,5 +1076,11 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
// the implicit conversions that are excluded from the pages should not appear in the diagram
def implicitExcluded(convertorMethod: String): Boolean = settings.hardcoded.commonConversionTargets.contains(convertorMethod)
+
+ // whether or not to create a page for an {abstract,alias} type
+ def typeShouldDocument(bSym: Symbol, inTpl: DocTemplateImpl) =
+ (settings.docExpandAllTypes.value && (bSym.sourceFile != null)) ||
+ { val rawComment = global.expandedDocComment(bSym, inTpl.sym)
+ rawComment.contains("@template") || rawComment.contains("@documentable") }
}
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala
index 8cbf2ac1b6..a12b67c9ed 100644
--- a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala
@@ -53,7 +53,7 @@ import model.{ RootPackage => RootPackageEntity }
* TODO: Give an overview here
*/
trait ModelFactoryImplicitSupport {
- thisFactory: ModelFactory with CommentFactory with TreeFactory =>
+ thisFactory: ModelFactory with ModelFactoryTypeSupport with CommentFactory with TreeFactory =>
import global._
import global.analyzer._
@@ -115,7 +115,7 @@ trait ModelFactoryImplicitSupport {
// Put the class-specific conversions in front
val (ownConversions, commonConversions) =
- conversions.partition(conv => !hardcoded.commonConversionTargets.contains(conv.conversionQualifiedName))
+ conversions.partition(!_.isCommonConversion)
ownConversions ::: commonConversions
}
@@ -242,7 +242,7 @@ trait ModelFactoryImplicitSupport {
available = Some(search.tree != EmptyTree)
} catch {
- case _ =>
+ case _: TypeError =>
}
}
@@ -329,11 +329,6 @@ trait ModelFactoryImplicitSupport {
}
}
- def makeQualifiedName(sym: Symbol): String = {
- val remove = Set[Symbol](RootPackage, RootClass, EmptyPackage, EmptyPackageClass)
- sym.ownerChain.filterNot(remove.contains(_)).reverse.map(_.nameString).mkString(".")
- }
-
/* ============== IMPLEMENTATION PROVIDING ENTITY TYPES ============== */
class ImplicitConversionImpl(
@@ -352,7 +347,7 @@ trait ModelFactoryImplicitSupport {
if (convSym != NoSymbol)
makeTemplate(convSym.owner)
else {
- error("Scaladoc implicits: Implicit conversion from " + sym.tpe + " to " + toType + " done by " + convSym + " = NoSymbol!")
+ error("Scaladoc implicits: " + toString + " = NoSymbol!")
makeRootPackage
}
@@ -408,29 +403,22 @@ trait ModelFactoryImplicitSupport {
debug("")
memberSyms.flatMap({ aSym =>
- makeTemplate(aSym.owner) match {
- case d: DocTemplateImpl =>
- // we can't just pick up nodes from the previous template, although that would be very convenient:
- // they need the byConversion field to be attached to themselves -- this is design decision I should
- // revisit soon
- //
- // d.ownMembers.collect({
- // // it's either a member or has a couple of usecases it's hidden behind
- // case m: MemberImpl if m.sym == aSym =>
- // m // the member itself
- // case m: MemberImpl if m.useCaseOf.isDefined && m.useCaseOf.get.asInstanceOf[MemberImpl].sym == aSym =>
- // m.useCaseOf.get.asInstanceOf[MemberImpl] // the usecase
- // })
- makeMember(aSym, this, d)
- case _ =>
- // should only happen if the code for this template is not part of the scaladoc run =>
- // members won't have any comments
- makeMember(aSym, this, inTpl)
- }
+ // we can't just pick up nodes from the original template, although that would be very convenient:
+ // they need the byConversion field to be attached to themselves and the types to be transformed by
+ // asSeenFrom
+
+ // at the same time, the member itself is in the inTpl, not in the new template -- but should pick up
+ // variables from the old template. Ugly huh? We'll always create the member inTpl, but it will change
+ // the template when expanding variables in the comment :)
+ makeMember(aSym, Some(this), inTpl)
})
}
lazy val members: List[MemberEntity] = memberImpls
+
+ def isCommonConversion = hardcoded.commonConversionTargets.contains(conversionQualifiedName)
+
+ override def toString = "Implcit conversion from " + sym.tpe + " to " + toType + " done by " + convSym
}
/* ========================= HELPER METHODS ========================== */
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala
new file mode 100644
index 0000000000..d2a26d1309
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala
@@ -0,0 +1,323 @@
+/* NSC -- new Scala compiler -- Copyright 2007-2011 LAMP/EPFL */
+
+package scala.tools.nsc
+package doc
+package model
+
+import comment._
+
+import diagram._
+
+import scala.collection._
+import scala.util.matching.Regex
+
+import symtab.Flags
+
+import io._
+
+import model.{ RootPackage => RootPackageEntity }
+
+/** This trait extracts all required information for documentation from compilation units */
+trait ModelFactoryTypeSupport {
+ thisFactory: ModelFactory
+ with ModelFactoryImplicitSupport
+ with ModelFactoryTypeSupport
+ with DiagramFactory
+ with CommentFactory
+ with TreeFactory =>
+
+ import global._
+ import definitions.{ ObjectClass, NothingClass, AnyClass, AnyValClass, AnyRefClass }
+ import rootMirror.{ RootPackage, RootClass, EmptyPackage }
+
+ protected var typeCache = new mutable.LinkedHashMap[Type, TypeEntity]
+
+ /** */
+ def makeType(aType: Type, inTpl: TemplateImpl): TypeEntity = {
+ def templatePackage = closestPackage(inTpl.sym)
+
+ def createTypeEntity = new TypeEntity {
+ private var nameBuffer = new StringBuilder
+ private var refBuffer = new immutable.TreeMap[Int, (LinkTo, Int)]
+ private def appendTypes0(types: List[Type], sep: String): Unit = types match {
+ case Nil =>
+ case tp :: Nil =>
+ appendType0(tp)
+ case tp :: tps =>
+ appendType0(tp)
+ nameBuffer append sep
+ appendTypes0(tps, sep)
+ }
+
+ private def appendType0(tpe: Type): Unit = tpe match {
+ /* Type refs */
+ case tp: TypeRef if definitions.isFunctionType(tp) =>
+ val args = tp.normalize.typeArgs
+ nameBuffer append '('
+ appendTypes0(args.init, ", ")
+ nameBuffer append ") ⇒ "
+ appendType0(args.last)
+ case tp: TypeRef if definitions.isScalaRepeatedParamType(tp) =>
+ appendType0(tp.args.head)
+ nameBuffer append '*'
+ case tp: TypeRef if definitions.isByNameParamType(tp) =>
+ nameBuffer append "⇒ "
+ appendType0(tp.args.head)
+ case tp: TypeRef if definitions.isTupleType(tp) =>
+ val args = tp.normalize.typeArgs
+ nameBuffer append '('
+ appendTypes0(args, ", ")
+ nameBuffer append ')'
+ case TypeRef(pre, aSym, targs) =>
+ val preSym = pre.widen.typeSymbol
+
+ // SI-3314/SI-4888: Classes, Traits and Types can be inherited from a template to another:
+ // class Enum { abstract class Value }
+ // class Day extends Enum { object Mon extends Value /*...*/ }
+ // ===> in such cases we have two options:
+ // (0) if there's no inheritance taking place (Enum#Value) we can link to the template directly
+ // (1) if we generate the doc template for Day, we can link to the correct member
+ // (2) if we don't generate the doc template, we should at least indicate the correct prefix in the tooltip
+ val bSym = normalizeTemplate(aSym)
+ val owner =
+ if ((preSym != NoSymbol) && /* it needs a prefix */
+ (preSym != bSym.owner) && /* prefix is different from owner */
+ (aSym == bSym)) /* normalization doesn't play tricks on us */
+ preSym
+ else
+ bSym.owner
+
+ val bTpl = findTemplateMaybe(bSym)
+ val link =
+ if (owner == bSym.owner && bTpl.isDefined)
+ // (0) the owner's class is linked AND has a template - lovely
+ LinkToTpl(bTpl.get)
+ else {
+ val oTpl = findTemplateMaybe(owner)
+ val bMbr = oTpl.map(findMember(bSym, _))
+ if (oTpl.isDefined && bMbr.isDefined && bMbr.get.isDefined)
+ // (1) the owner's class
+ LinkToMember(bMbr.get.get, oTpl.get) //ugh
+ else
+ // (2) if we still couldn't find the owner, show a tooltip with the qualified name
+ Tooltip(makeQualifiedName(bSym))
+ }
+
+ // SI-4360 Showing prefixes when necessary
+ // We check whether there's any directly accessible type with the same name in the current template OR if the
+ // type is inherited from one template to another. There may be multiple symbols with the same name in scope,
+ // but we won't show the prefix if our symbol is among them, only if *it's not* -- that's equal to showing
+ // the prefix only for ambiguous references, not for overloaded ones.
+ def needsPrefix: Boolean = {
+ if ((owner != bSym.owner || preSym.isRefinementClass) && (normalizeTemplate(owner) != inTpl.sym))
+ return true
+ // don't get tricked into prefixng method type params and existentials:
+ // I tried several tricks BUT adding the method for which I'm creating the type => that simply won't scale,
+ // as ValueParams are independent of their parent member, and I really don't want to add this information to
+ // all terms, as we're already over the allowed memory footprint
+ if (aSym.isTypeParameterOrSkolem || aSym.isExistentiallyBound /* existential or existential skolem */)
+ return false
+
+ for (tpl <- inTpl.sym.ownerChain) {
+ tpl.info.member(bSym.name) match {
+ case NoSymbol =>
+ // No syms with that name, look further inside the owner chain
+ case sym =>
+ // Symbol found -- either the correct symbol, another one OR an overloaded alternative
+ if (sym == bSym)
+ return false
+ else sym.info match {
+ case OverloadedType(owner, alternatives) =>
+ return alternatives.contains(bSym)
+ case _ =>
+ return true
+ }
+ }
+ }
+ // if it's not found in the owner chain, we can safely leave out the prefix
+ false
+ }
+
+ val prefix =
+ if (!settings.docNoPrefixes.value && needsPrefix && (bSym != AnyRefClass /* which we normalize */)) {
+ if (!owner.isRefinementClass) {
+ val qName = makeQualifiedName(owner, Some(inTpl.sym))
+ if (qName != "") qName + "." else ""
+ }
+ else {
+ nameBuffer append "("
+ appendType0(pre)
+ nameBuffer append ")#"
+ "" // we already appended the prefix
+ }
+ } else ""
+
+ //DEBUGGING:
+ //if (makeQualifiedName(bSym) == "pack1.A") println("needsPrefix(" + bSym + ", " + owner + ", " + inTpl.qualifiedName + ") => " + needsPrefix + " and prefix=" + prefix)
+
+ val name = prefix + bSym.nameString
+ val pos0 = nameBuffer.length
+ refBuffer += pos0 -> ((link, name.length))
+ nameBuffer append name
+
+ if (!targs.isEmpty) {
+ nameBuffer append '['
+ appendTypes0(targs, ", ")
+ nameBuffer append ']'
+ }
+ /* Refined types */
+ case RefinedType(parents, defs) =>
+ val ignoreParents = Set[Symbol](AnyClass, ObjectClass)
+ val filtParents = parents filterNot (x => ignoreParents(x.typeSymbol)) match {
+ case Nil => parents
+ case ps => ps
+ }
+ appendTypes0(filtParents, " with ")
+ // XXX Still todo: properly printing refinements.
+ // Since I didn't know how to go about displaying a multi-line type, I went with
+ // printing single method refinements (which should be the most common) and printing
+ // the number of members if there are more.
+ defs.toList match {
+ case Nil => ()
+ case x :: Nil => nameBuffer append (" { " + x.defString + " }")
+ case xs => nameBuffer append (" { ... /* %d definitions in type refinement */ }" format xs.size)
+ }
+ /* Eval-by-name types */
+ case NullaryMethodType(result) =>
+ nameBuffer append '⇒'
+ appendType0(result)
+
+ /* Polymorphic types */
+ case PolyType(tparams, result) => assert(tparams.nonEmpty)
+ def typeParamsToString(tps: List[Symbol]): String = if (tps.isEmpty) "" else
+ tps.map{tparam =>
+ tparam.varianceString + tparam.name + typeParamsToString(tparam.typeParams)
+ }.mkString("[", ", ", "]")
+ nameBuffer append typeParamsToString(tparams)
+ appendType0(result)
+
+ case et@ExistentialType(quantified, underlying) =>
+
+ def appendInfoStringReduced(sym: Symbol, tp: Type): Unit = {
+ if (sym.isType && !sym.isAliasType && !sym.isClass) {
+ tp match {
+ case PolyType(tparams, _) =>
+ nameBuffer append "["
+ appendTypes0(tparams.map(_.tpe), ", ")
+ nameBuffer append "]"
+ case _ =>
+ }
+ tp.resultType match {
+ case rt @ TypeBounds(_, _) =>
+ appendType0(rt)
+ case rt =>
+ nameBuffer append " <: "
+ appendType0(rt)
+ }
+ } else {
+ // fallback to the Symbol infoString
+ nameBuffer append sym.infoString(tp)
+ }
+ }
+
+ def appendClauses = {
+ nameBuffer append " forSome {"
+ var first = true
+ val qset = quantified.toSet
+ for (sym <- quantified) {
+ if (!first) { nameBuffer append ", " } else first = false
+ if (sym.isSingletonExistential) {
+ nameBuffer append "val "
+ nameBuffer append tpnme.dropSingletonName(sym.name)
+ nameBuffer append ": "
+ appendType0(dropSingletonType(sym.info.bounds.hi))
+ } else {
+ if (sym.flagString != "") nameBuffer append (sym.flagString + " ")
+ if (sym.keyString != "") nameBuffer append (sym.keyString + " ")
+ nameBuffer append sym.varianceString
+ nameBuffer append sym.nameString
+ appendInfoStringReduced(sym, sym.info)
+ }
+ }
+ nameBuffer append "}"
+ }
+
+ underlying match {
+ case TypeRef(pre, sym, args) if et.isRepresentableWithWildcards =>
+ appendType0(typeRef(pre, sym, Nil))
+ nameBuffer append "["
+ var first = true
+ val qset = quantified.toSet
+ for (arg <- args) {
+ if (!first) { nameBuffer append ", " } else first = false
+ arg match {
+ case TypeRef(_, sym, _) if (qset contains sym) =>
+ nameBuffer append "_"
+ appendInfoStringReduced(sym, sym.info)
+ case arg =>
+ appendType0(arg)
+ }
+ }
+ nameBuffer append "]"
+ case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) =>
+ nameBuffer append "("
+ appendType0(underlying)
+ nameBuffer append ")"
+ appendClauses
+ case _ =>
+ appendType0(underlying)
+ appendClauses
+ }
+
+ case tb@TypeBounds(lo, hi) =>
+ if (tb.lo != TypeBounds.empty.lo) {
+ nameBuffer append " >: "
+ appendType0(lo)
+ }
+ if (tb.hi != TypeBounds.empty.hi) {
+ nameBuffer append " <: "
+ appendType0(hi)
+ }
+ // case tpen: ThisType | SingleType | SuperType =>
+ // if (tpen.isInstanceOf[ThisType] && tpen.asInstanceOf[ThisType].sym.isEffectiveRoot) {
+ // appendType0 typeRef(NoPrefix, sym, Nil)
+ // } else {
+ // val underlying =
+ // val pre = underlying.typeSymbol.skipPackageObject
+ // if (pre.isOmittablePrefix) pre.fullName + ".type"
+ // else prefixString + "type"
+ case tpen@ThisType(sym) =>
+ appendType0(typeRef(NoPrefix, sym, Nil))
+ nameBuffer append ".this"
+ if (!tpen.underlying.typeSymbol.skipPackageObject.isOmittablePrefix) nameBuffer append ".type"
+ case tpen@SuperType(thistpe, supertpe) =>
+ nameBuffer append "super["
+ appendType0(supertpe)
+ nameBuffer append "]"
+ case tpen@SingleType(pre, sym) =>
+ appendType0(typeRef(pre, sym, Nil))
+ if (!tpen.underlying.typeSymbol.skipPackageObject.isOmittablePrefix) nameBuffer append ".type"
+ case tpen =>
+ nameBuffer append tpen.toString
+ }
+ appendType0(aType)
+ val refEntity = refBuffer
+ val name = optimize(nameBuffer.toString)
+ nameBuffer = null
+ }
+
+ // SI-4360: Entity caching depends on both the type AND the template it's in, as the prefixes might change for the
+ // same type based on the template the type is shown in.
+ if (settings.docNoPrefixes.value) {
+ val cached = typeCache.get(aType)
+ cached match {
+ case Some(typeEntity) =>
+ typeEntity
+ case None =>
+ val typeEntity = createTypeEntity
+ typeCache += aType -> typeEntity
+ typeEntity
+ }
+ } else createTypeEntity
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala b/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala
index 67e955f613..643067cca5 100644
--- a/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala
@@ -9,7 +9,6 @@ package model
import scala.collection._
-
/** A type. Note that types and templates contain the same information only for the simplest types. For example, a type
* defines how a template's type parameters are instantiated (as in `List[Cow]`), what the template's prefix is
* (as in `johnsFarm.Cow`), and supports compound or structural types. */
@@ -21,9 +20,8 @@ abstract class TypeEntity {
/** Maps which parts of this type's name reference entities. The map is indexed by the position of the first
* character that reference some entity, and contains the entity and the position of the last referenced
* character. The referenced character ranges do not to overlap or nest. The map is sorted by position. */
- def refEntity: SortedMap[Int, (TemplateEntity, Int)]
+ def refEntity: SortedMap[Int, (LinkTo, Int)]
/** The human-readable representation of this type. */
override def toString = name
-
}
diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala b/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala
index ecc3273903..3f0024cb68 100644
--- a/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala
@@ -44,7 +44,6 @@ final case class Body(blocks: Seq[Block]) {
case inlines => Some(Chain(inlines))
}
}
-
}
/** A block-level element of text, such as a paragraph or code block. */
@@ -67,10 +66,14 @@ final case class Bold(text: Inline) extends Inline
final case class Underline(text: Inline) extends Inline
final case class Superscript(text: Inline) extends Inline
final case class Subscript(text: Inline) extends Inline
-final case class EntityLink(target: String, template: () => Option[TemplateEntity]) extends Inline
final case class Link(target: String, title: Inline) extends Inline
final case class Monospace(text: Inline) extends Inline
final case class Text(text: String) extends Inline
+abstract class EntityLink(val title: Inline) extends Inline { def link: LinkTo }
+object EntityLink {
+ def apply(title: Inline, linkTo: LinkTo) = new EntityLink(title) { def link: LinkTo = linkTo }
+ def unapply(el: EntityLink): Option[(Inline, LinkTo)] = Some((el.title, el.link))
+}
final case class HtmlTag(data: String) extends Inline {
def canClose(open: HtmlTag) = {
open.data.stripPrefix("<") == data.stripPrefix("</")
diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala b/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala
index 7b70683db5..c8f4c2f285 100644
--- a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala
@@ -114,6 +114,18 @@ abstract class Comment {
/** A set of diagram directives for the content diagram */
def contentDiagram: List[String]
+ /** The group this member is part of */
+ def group: Option[String]
+
+ /** Member group descriptions */
+ def groupDesc: Map[String,Body]
+
+ /** Member group names (overriding the short tag) */
+ def groupNames: Map[String,String]
+
+ /** Member group priorities */
+ def groupPrio: Map[String,Int]
+
override def toString =
body.toString + "\n" +
(authors map ("@author " + _.toString)).mkString("\n") +
diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala
index 2099315cc6..1a11964e37 100644
--- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala
@@ -23,7 +23,7 @@ import language.postfixOps
*
* @author Manohar Jonnalagedda
* @author Gilles Dubochet */
-trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
+trait CommentFactory { thisFactory: ModelFactory with CommentFactory with MemberLookup=>
val global: Global
import global.{ reporter, definitions }
@@ -31,16 +31,16 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
protected val commentCache = mutable.HashMap.empty[(global.Symbol, TemplateImpl), Comment]
def addCommentBody(sym: global.Symbol, inTpl: TemplateImpl, docStr: String, docPos: global.Position): global.Symbol = {
- commentCache += (sym, inTpl) -> parse(docStr, docStr, docPos)
+ commentCache += (sym, inTpl) -> parse(docStr, docStr, docPos, None)
sym
}
- def comment(sym: global.Symbol, inTpl: DocTemplateImpl): Option[Comment] = {
+ def comment(sym: global.Symbol, currentTpl: Option[DocTemplateImpl], inTpl: DocTemplateImpl): Option[Comment] = {
val key = (sym, inTpl)
if (commentCache isDefinedAt key)
Some(commentCache(key))
else {
- val c = defineComment(sym, inTpl)
+ val c = defineComment(sym, currentTpl, inTpl)
if (c isDefined) commentCache += (sym, inTpl) -> c.get
c
}
@@ -50,7 +50,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
* cases we have to give some `inTpl` comments (parent class for example)
* to the comment of the symbol.
* This function manages some of those cases : Param accessor and Primary constructor */
- def defineComment(sym: global.Symbol, inTpl: DocTemplateImpl):Option[Comment] = {
+ def defineComment(sym: global.Symbol, currentTpl: Option[DocTemplateImpl], inTpl: DocTemplateImpl):Option[Comment] = {
//param accessor case
// We just need the @param argument, we put it into the body
@@ -87,7 +87,8 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
else {
val rawComment = global.expandedDocComment(sym, inTpl.sym).trim
if (rawComment != "") {
- val c = parse(rawComment, global.rawDocComment(sym), global.docCommentPos(sym))
+ val tplOpt = if (currentTpl.isDefined) currentTpl else Some(inTpl)
+ val c = parse(rawComment, global.rawDocComment(sym), global.docCommentPos(sym), tplOpt)
Some(c)
}
else None
@@ -113,7 +114,11 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
constructor0: Option[Body] = None,
source0: Option[String] = None,
inheritDiagram0: List[String] = List.empty,
- contentDiagram0: List[String] = List.empty
+ contentDiagram0: List[String] = List.empty,
+ group0: Option[Body] = None,
+ groupDesc0: Map[String,Body] = Map.empty,
+ groupNames0: Map[String,Body] = Map.empty,
+ groupPrio0: Map[String,Body] = Map.empty
) : Comment = new Comment{
val body = if(body0 isDefined) body0.get else Body(Seq.empty)
val authors = authors0
@@ -132,6 +137,35 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
val source = source0
val inheritDiagram = inheritDiagram0
val contentDiagram = contentDiagram0
+ val groupDesc = groupDesc0
+ val group =
+ group0 match {
+ case Some(Body(List(Paragraph(Chain(List(Summary(Text(groupId)))))))) => Some(groupId.toString.trim)
+ case _ => None
+ }
+ val groupPrio = groupPrio0 flatMap {
+ case (group, body) =>
+ try {
+ body match {
+ case Body(List(Paragraph(Chain(List(Summary(Text(prio))))))) => List(group -> prio.toInt)
+ case _ => List()
+ }
+ } catch {
+ case _: java.lang.NumberFormatException => List()
+ }
+ }
+ val groupNames = groupNames0 flatMap {
+ case (group, body) =>
+ try {
+ body match {
+ case Body(List(Paragraph(Chain(List(Summary(Text(name))))))) if (!name.trim.contains("\n")) => List(group -> (name.trim))
+ case _ => List()
+ }
+ } catch {
+ case _: java.lang.NumberFormatException => List()
+ }
+ }
+
}
protected val endOfText = '\u0003'
@@ -201,7 +235,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
/** A Scaladoc tag linked to a symbol. Returns the name of the tag, the name
* of the symbol, and the rest of the line. */
protected val SymbolTag =
- new Regex("""\s*@(param|tparam|throws)\s+(\S*)\s*(.*)""")
+ new Regex("""\s*@(param|tparam|throws|groupdesc|groupname|groupprio)\s+(\S*)\s*(.*)""")
/** The start of a scaladoc code block */
protected val CodeBlockStart =
@@ -225,7 +259,8 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
* @param comment The expanded comment string (including start and end markers) to be parsed.
* @param src The raw comment source string.
* @param pos The position of the comment in source. */
- protected def parse(comment: String, src: String, pos: Position): Comment = {
+ protected def parse(comment: String, src: String, pos: Position, inTplOpt: Option[DocTemplateImpl] = None): Comment = {
+ assert(!inTplOpt.isDefined || inTplOpt.get != null)
/** The cleaned raw comment as a list of lines. Cleaning removes comment
* start and end markers, line start markers and unnecessary whitespace. */
@@ -348,10 +383,11 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
case None => List.empty
}
- val tagsWithoutDiagram = tags.filterNot(pair => pair._1 == inheritDiagramTag || pair._1 == contentDiagramTag)
+ val stripTags=List(inheritDiagramTag, contentDiagramTag, SimpleTagKey("template"), SimpleTagKey("documentable"))
+ val tagsWithoutDiagram = tags.filterNot(pair => stripTags.contains(pair._1))
val bodyTags: mutable.Map[TagKey, List[Body]] =
- mutable.Map(tagsWithoutDiagram mapValues {tag => tag map (parseWiki(_, pos))} toSeq: _*)
+ mutable.Map(tagsWithoutDiagram mapValues {tag => tag map (parseWiki(_, pos, inTplOpt))} toSeq: _*)
def oneTag(key: SimpleTagKey): Option[Body] =
((bodyTags remove key): @unchecked) match {
@@ -384,7 +420,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
}
val com = createComment (
- body0 = Some(parseWiki(docBody.toString, pos)),
+ body0 = Some(parseWiki(docBody.toString, pos, inTplOpt)),
authors0 = allTags(SimpleTagKey("author")),
see0 = allTags(SimpleTagKey("see")),
result0 = oneTag(SimpleTagKey("return")),
@@ -400,7 +436,11 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
constructor0 = oneTag(SimpleTagKey("constructor")),
source0 = Some(clean(src).mkString("\n")),
inheritDiagram0 = inheritDiagramText,
- contentDiagram0 = contentDiagramText
+ contentDiagram0 = contentDiagramText,
+ group0 = oneTag(SimpleTagKey("group")),
+ groupDesc0 = allSymsOneTag(SimpleTagKey("groupdesc")),
+ groupNames0 = allSymsOneTag(SimpleTagKey("groupname")),
+ groupPrio0 = allSymsOneTag(SimpleTagKey("groupprio"))
)
for ((key, _) <- bodyTags)
@@ -420,8 +460,10 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
* - Removed start-of-line star and one whitespace afterwards (if present).
* - Removed all end-of-line whitespace.
* - Only `endOfLine` is used to mark line endings. */
- def parseWiki(string: String, pos: Position): Body = {
- new WikiParser(string, pos).document()
+ def parseWiki(string: String, pos: Position, inTplOpt: Option[DocTemplateImpl]): Body = {
+ assert(!inTplOpt.isDefined || inTplOpt.get != null)
+
+ new WikiParser(string, pos, inTplOpt).document()
}
/** TODO
@@ -429,7 +471,8 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
* @author Ingo Maier
* @author Manohar Jonnalagedda
* @author Gilles Dubochet */
- protected final class WikiParser(val buffer: String, pos: Position) extends CharReader(buffer) { wiki =>
+ protected final class WikiParser(val buffer: String, pos: Position, inTplOpt: Option[DocTemplateImpl]) extends CharReader(buffer) { wiki =>
+ assert(!inTplOpt.isDefined || inTplOpt.get != null)
var summaryParsed = false
@@ -617,7 +660,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
else if (check(",,")) subscript()
else if (check("[[")) link()
else {
- readUntil { char == safeTagMarker || check("''") || char == '`' || check("__") || char == '^' || check(",,") || check("[[") || isInlineEnd || checkParaEnded || char == endOfLine }
+ readUntil { char == safeTagMarker || check("''") || char == '`' || check("__") || char == '^' || check(",,") || check("[[") || check("{{") || isInlineEnd || checkParaEnded || char == endOfLine }
Text(getRead())
}
}
@@ -719,29 +762,27 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
def link(): Inline = {
val SchemeUri = """([^:]+:.*)""".r
jump("[[")
- readUntil { check("]]") || check(" ") }
+ var parens = 1
+ readUntil { parens += 1; !check("[") }
+ getRead // clear the buffer
+ val start = "[" * parens
+ val stop = "]" * parens
+ //println("link with " + parens + " matching parens")
+ readUntil { check(stop) || check(" ") }
val target = getRead()
val title =
- if (!check("]]")) Some({
+ if (!check(stop)) Some({
jump(" ")
- inline(check("]]"))
+ inline(check(stop))
})
else None
- jump("]]")
+ jump(stop)
(target, title) match {
case (SchemeUri(uri), optTitle) =>
Link(uri, optTitle getOrElse Text(uri))
case (qualName, optTitle) =>
- optTitle foreach (text => reportError(pos, "entity link to " + qualName + " cannot have a custom title'" + text + "'"))
- // XXX rather than warning here we should allow unqualified names
- // to refer to members of the same package. The "package exists"
- // exclusion is because [[scala]] is used in some scaladoc.
- if (!qualName.contains(".") && !definitions.packageExists(qualName))
- reportError(pos, "entity link to " + qualName + " should be a fully qualified name")
-
- // move the template resolution as late as possible
- EntityLink(qualName, () => findTemplate(qualName))
+ makeEntityLink(optTitle getOrElse Text(target), pos, target, inTplOpt)
}
}
diff --git a/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala b/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala
index 8527ca4039..c2aa1f17f3 100644
--- a/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala
@@ -13,18 +13,18 @@ import model._
abstract class Diagram {
def nodes: List[Node]
def edges: List[(Node, List[Node])]
- def isPackageDiagram = false
- def isClassDiagram = false
+ def isContentDiagram = false // Implemented by ContentDiagram
+ def isInheritanceDiagram = false // Implemented by InheritanceDiagram
def depthInfo: DepthInfo
}
-case class PackageDiagram(nodes:List[/*Class*/Node], edges:List[(Node, List[Node])]) extends Diagram {
- override def isPackageDiagram = true
- lazy val depthInfo = new PackageDiagramDepth(this)
+case class ContentDiagram(nodes:List[/*Class*/Node], edges:List[(Node, List[Node])]) extends Diagram {
+ override def isContentDiagram = true
+ lazy val depthInfo = new ContentDiagramDepth(this)
}
/** A class diagram */
-case class ClassDiagram(thisNode: ThisNode,
+case class InheritanceDiagram(thisNode: ThisNode,
superClasses: List[/*Class*/Node],
subClasses: List[/*Class*/Node],
incomingImplicits: List[ImplicitNode],
@@ -33,7 +33,7 @@ case class ClassDiagram(thisNode: ThisNode,
def edges = (thisNode -> (superClasses ::: outgoingImplicits)) ::
(subClasses ::: incomingImplicits).map(_ -> List(thisNode))
- override def isClassDiagram = true
+ override def isInheritanceDiagram = true
lazy val depthInfo = new DepthInfo {
def maxDepth = 3
def nodeDepth(node: Node) =
@@ -70,7 +70,8 @@ abstract class Node {
def isClassNode = if (tpl.isDefined) (tpl.get.isClass || tpl.get.qualifiedName == "scala.AnyRef") else false
def isTraitNode = if (tpl.isDefined) tpl.get.isTrait else false
def isObjectNode= if (tpl.isDefined) tpl.get.isObject else false
- def isOtherNode = !(isClassNode || isTraitNode || isObjectNode)
+ def isTypeNode = if (doctpl.isDefined) doctpl.get.isAbstractType || doctpl.get.isAliasType else false
+ def isOtherNode = !(isClassNode || isTraitNode || isObjectNode || isTypeNode)
def isImplicitNode = false
def isOutsideNode = false
def tooltip: Option[String]
@@ -91,6 +92,7 @@ abstract class Node {
object Node { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = Some((n.tpe, n.tpl)) }
object ClassNode { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = if (n.isClassNode) Some((n.tpe, n.tpl)) else None }
object TraitNode { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = if (n.isTraitNode) Some((n.tpe, n.tpl)) else None }
+object TypeNode { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = if (n.isTypeNode) Some((n.tpe, n.tpl)) else None }
object ObjectNode { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = if (n.isObjectNode) Some((n.tpe, n.tpl)) else None }
object OutsideNode { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = if (n.isOutsideNode) Some((n.tpe, n.tpl)) else None }
object OtherNode { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = if (n.isOtherNode) Some((n.tpe, n.tpl)) else None }
@@ -98,24 +100,24 @@ object OtherNode { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEn
/** The node for the current class */
-case class ThisNode(tpe: TypeEntity, tpl: Option[TemplateEntity], tooltip: Option[String] = None) extends Node { override def isThisNode = true }
+case class ThisNode(tpe: TypeEntity, tpl: Option[TemplateEntity])(val tooltip: Option[String] = None) extends Node { override def isThisNode = true }
/** The usual node */
-case class NormalNode(tpe: TypeEntity, tpl: Option[TemplateEntity], tooltip: Option[String] = None) extends Node { override def isNormalNode = true }
+case class NormalNode(tpe: TypeEntity, tpl: Option[TemplateEntity])(val tooltip: Option[String] = None) extends Node { override def isNormalNode = true }
/** A class or trait the thisnode can be converted to by an implicit conversion
* TODO: I think it makes more sense to use the tpe links to templates instead of the TemplateEntity for implicit nodes
* since some implicit conversions convert the class to complex types that cannot be represented as a single tmeplate
*/
-case class ImplicitNode(tpe: TypeEntity, tpl: Option[TemplateEntity], tooltip: Option[String] = None) extends Node { override def isImplicitNode = true }
+case class ImplicitNode(tpe: TypeEntity, tpl: Option[TemplateEntity])(val tooltip: Option[String] = None) extends Node { override def isImplicitNode = true }
/** An outside node is shown in packages when a class from a different package makes it to the package diagram due to
* its relation to a class in the template (see @contentDiagram hideInheritedNodes annotation) */
-case class OutsideNode(tpe: TypeEntity, tpl: Option[TemplateEntity], tooltip: Option[String] = None) extends Node { override def isOutsideNode = true }
+case class OutsideNode(tpe: TypeEntity, tpl: Option[TemplateEntity])(val tooltip: Option[String] = None) extends Node { override def isOutsideNode = true }
// Computing and offering node depth information
-class PackageDiagramDepth(pack: PackageDiagram) extends DepthInfo {
+class ContentDiagramDepth(pack: ContentDiagram) extends DepthInfo {
private[this] var _maxDepth = 0
private[this] var _nodeDepth = Map[Node, Int]()
private[this] var seedNodes = Set[Node]()
diff --git a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala
index 1a8ad193aa..2645d8fd14 100644
--- a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala
@@ -18,21 +18,14 @@ import scala.collection.immutable.SortedMap
* @author Vlad Ureche
*/
trait DiagramFactory extends DiagramDirectiveParser {
- this: ModelFactory with DiagramFactory with CommentFactory with TreeFactory =>
+ this: ModelFactory with ModelFactoryTypeSupport with DiagramFactory with CommentFactory with TreeFactory =>
import this.global.definitions._
import this.global._
// the following can used for hardcoding different relations into the diagram, for bootstrapping purposes
- lazy val AnyNode = normalNode(AnyClass)
- lazy val AnyRefNode = normalNode(AnyRefClass)
- lazy val AnyValNode = normalNode(AnyValClass)
- lazy val NullNode = normalNode(NullClass)
- lazy val NothingNode = normalNode(NothingClass)
- def normalNode(sym: Symbol) =
- NormalNode(makeTemplate(sym).ownType, Some(makeTemplate(sym)))
def aggregationNode(text: String) =
- NormalNode(new TypeEntity { val name = text; val refEntity = SortedMap[Int, (TemplateEntity, Int)]() }, None)
+ NormalNode(new TypeEntity { val name = text; val refEntity = SortedMap[Int, (LinkTo, Int)]() }, None)()
/** Create the inheritance diagram for this template */
def makeInheritanceDiagram(tpl: DocTemplateImpl): Option[Diagram] = {
@@ -52,31 +45,30 @@ trait DiagramFactory extends DiagramDirectiveParser {
None
else {
// the main node
- val thisNode = ThisNode(tpl.ownType, Some(tpl), Some(tpl.qualifiedName + " (this " + tpl.kind + ")"))
+ val thisNode = ThisNode(tpl.resultType, Some(tpl))(Some(tpl.qualifiedName + " (this " + tpl.kind + ")"))
// superclasses
var superclasses: List[Node] =
tpl.parentTypes.collect {
- case p: (TemplateEntity, TypeEntity) if !classExcluded(p._1) => NormalNode(p._2, Some(p._1))
+ case p: (TemplateEntity, TypeEntity) if !classExcluded(p._1) => NormalNode(p._2, Some(p._1))()
}.reverse
// incoming implcit conversions
lazy val incomingImplicitNodes = tpl.incomingImplicitlyConvertedClasses.map {
case (incomingTpl, conv) =>
- ImplicitNode(incomingTpl.ownType, Some(incomingTpl), implicitTooltip(from=incomingTpl, to=tpl, conv=conv))
+ ImplicitNode(makeType(incomingTpl.sym.tpe, tpl), Some(incomingTpl))(implicitTooltip(from=incomingTpl, to=tpl, conv=conv))
}
// subclasses
var subclasses: List[Node] =
- tpl.directSubClasses.flatMap {
- case d: TemplateEntity if !classExcluded(d) => List(NormalNode(d.ownType, Some(d)))
- case _ => Nil
+ tpl.directSubClasses.collect {
+ case d: TemplateImpl if !classExcluded(d) => NormalNode(makeType(d.sym.tpe, tpl), Some(d))()
}.sortBy(_.tpl.get.name)(implicitly[Ordering[String]].reverse)
// outgoing implicit coversions
lazy val outgoingImplicitNodes = tpl.outgoingImplicitlyConvertedClasses.map {
case (outgoingTpl, outgoingType, conv) =>
- ImplicitNode(outgoingType, Some(outgoingTpl), implicitTooltip(from=tpl, to=tpl, conv=conv))
+ ImplicitNode(outgoingType, Some(outgoingTpl))(implicitTooltip(from=tpl, to=tpl, conv=conv))
}
// TODO: Everyone should be able to use the @{inherit,content}Diagram annotation to change the diagrams.
@@ -93,7 +85,7 @@ trait DiagramFactory extends DiagramDirectiveParser {
val filteredImplicitOutgoingNodes = if (diagramFilter.hideOutgoingImplicits) Nil else outgoingImplicitNodes
// final diagram filter
- filterDiagram(ClassDiagram(thisNode, filteredSuperclasses.reverse, filteredSubclasses.reverse, filteredIncomingImplicits, filteredImplicitOutgoingNodes), diagramFilter)
+ filterDiagram(InheritanceDiagram(thisNode, filteredSuperclasses.reverse, filteredSubclasses.reverse, filteredIncomingImplicits, filteredImplicitOutgoingNodes), diagramFilter)
}
tModel += System.currentTimeMillis
@@ -129,12 +121,10 @@ trait DiagramFactory extends DiagramDirectiveParser {
// for each node, add its subclasses
for (node <- nodesAll if !classExcluded(node)) {
node match {
- case dnode: DocTemplateImpl =>
- var superClasses = dnode.parentTypes.map(_._1)
+ case dnode: MemberTemplateImpl =>
+ var superClasses = dnode.parentTypes.map(_._1).filter(nodesAll.contains(_))
- superClasses = superClasses.filter(nodesAll.contains(_))
-
- // TODO: Everyone should be able to use the @{inherit,content}Diagram annotation to change the diagrams.
+ // TODO: Everyone should be able to use the @{inherit,content}Diagram annotation to add nodes to diagrams.
if (pack.sym == ScalaPackage)
if (dnode.sym == NullClass)
superClasses = List(makeTemplate(AnyRefClass))
@@ -149,7 +139,12 @@ trait DiagramFactory extends DiagramDirectiveParser {
case _ =>
}
- mapNodes += node -> (if (node.inTemplate == pack) NormalNode(node.ownType, Some(node)) else OutsideNode(node.ownType, Some(node)))
+ mapNodes += node -> (
+ if (node.inTemplate == pack && (node.isDocTemplate || node.isAbstractType || node.isAliasType))
+ NormalNode(node.resultType, Some(node))()
+ else
+ OutsideNode(node.resultType, Some(node))()
+ )
}
if (nodesShown.isEmpty)
@@ -173,9 +168,12 @@ trait DiagramFactory extends DiagramDirectiveParser {
val anyRefSubtypes = Nil
val allAnyRefTypes = aggregationNode("All AnyRef subtypes")
val nullTemplate = makeTemplate(NullClass)
- PackageDiagram(allAnyRefTypes::nodes, (mapNodes(nullTemplate), allAnyRefTypes::anyRefSubtypes)::edges.filterNot(_._1.tpl == Some(nullTemplate)))
+ if (nullTemplate.isDocTemplate)
+ ContentDiagram(allAnyRefTypes::nodes, (mapNodes(nullTemplate), allAnyRefTypes::anyRefSubtypes)::edges.filterNot(_._1.tpl == Some(nullTemplate)))
+ else
+ ContentDiagram(nodes, edges)
} else
- PackageDiagram(nodes, edges)
+ ContentDiagram(nodes, edges)
filterDiagram(diagram, diagramFilter)
}
@@ -200,10 +198,10 @@ trait DiagramFactory extends DiagramDirectiveParser {
else {
// Final diagram, with the filtered nodes and edges
diagram match {
- case ClassDiagram(thisNode, _, _, _, _) if diagramFilter.hideNode(thisNode) =>
+ case InheritanceDiagram(thisNode, _, _, _, _) if diagramFilter.hideNode(thisNode) =>
None
- case ClassDiagram(thisNode, superClasses, subClasses, incomingImplicits, outgoingImplicits) =>
+ case InheritanceDiagram(thisNode, superClasses, subClasses, incomingImplicits, outgoingImplicits) =>
def hideIncoming(node: Node): Boolean =
diagramFilter.hideNode(node) || diagramFilter.hideEdge(node, thisNode)
@@ -214,13 +212,13 @@ trait DiagramFactory extends DiagramDirectiveParser {
// println(thisNode)
// println(superClasses.map(cl => "super: " + cl + " " + hideOutgoing(cl)).mkString("\n"))
// println(subClasses.map(cl => "sub: " + cl + " " + hideIncoming(cl)).mkString("\n"))
- Some(ClassDiagram(thisNode,
+ Some(InheritanceDiagram(thisNode,
superClasses.filterNot(hideOutgoing(_)),
subClasses.filterNot(hideIncoming(_)),
incomingImplicits.filterNot(hideIncoming(_)),
outgoingImplicits.filterNot(hideOutgoing(_))))
- case PackageDiagram(nodes0, edges0) =>
+ case ContentDiagram(nodes0, edges0) =>
// Filter out all edges that:
// (1) are sources of hidden classes
// (2) are manually hidden by the user
@@ -242,7 +240,7 @@ trait DiagramFactory extends DiagramDirectiveParser {
val sourceNodes = edges.map(_._1)
val sinkNodes = edges.map(_._2).flatten
val nodes = (sourceNodes ::: sinkNodes).distinct
- Some(PackageDiagram(nodes, edges))
+ Some(ContentDiagram(nodes, edges))
}
}
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index 8f287a5c7a..2a435aa6f6 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -627,7 +627,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
response raise ex
throw ex
- case ex =>
+ case ex: Throwable =>
if (debugIDE) {
println("exception thrown during response: "+ex)
ex.printStackTrace()
diff --git a/src/compiler/scala/tools/nsc/interactive/PresentationCompilerThread.scala b/src/compiler/scala/tools/nsc/interactive/PresentationCompilerThread.scala
index 098884dab1..70d8a826d0 100644
--- a/src/compiler/scala/tools/nsc/interactive/PresentationCompilerThread.scala
+++ b/src/compiler/scala/tools/nsc/interactive/PresentationCompilerThread.scala
@@ -36,7 +36,7 @@ final class PresentationCompilerThread(var compiler: Global, name: String = "")
// make sure we don't keep around stale instances
compiler = null
- case ex =>
+ case ex: Throwable =>
compiler.log.flush()
ex match {
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
index e5e7d7081d..b567293a3f 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
@@ -25,7 +25,7 @@ import ScalaClassLoader._
import scala.tools.util._
import language.{implicitConversions, existentials}
import scala.reflect.{ClassTag, classTag}
-import scala.tools.reflect.StdTags._
+import scala.tools.reflect.StdRuntimeTags._
/** The Scala interactive shell. It provides a read-eval-print loop
* around the Interpreter class.
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index b385787cce..7bdbff8627 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -28,7 +28,7 @@ import typechecker.Analyzer
import language.implicitConversions
import scala.reflect.runtime.{ universe => ru }
import scala.reflect.{ ClassTag, classTag }
-import scala.tools.reflect.StdTags._
+import scala.tools.reflect.StdRuntimeTags._
/** directory to save .class files to */
private class ReplVirtualDirectory(out: JPrintWriter) extends VirtualDirectory("(memory)", None) {
diff --git a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
index f0ee8b11f3..0991577829 100644
--- a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
@@ -40,9 +40,9 @@ trait StandardScalaSettings {
val nowarn = BooleanSetting ("-nowarn", "Generate no warnings.")
val optimise: BooleanSetting // depends on post hook which mutates other settings
val print = BooleanSetting ("-print", "Print program with Scala-specific features removed.")
- val target = ChoiceSetting ("-target", "target", "Target platform for object files.",
+ val target = ChoiceSetting ("-target", "target", "Target platform for object files. All JVM 1.5 targets are deprecated.",
List("jvm-1.5", "jvm-1.5-fjbg", "jvm-1.5-asm", "jvm-1.6", "jvm-1.7", "msil"),
- "jvm-1.5-asm")
+ "jvm-1.6")
val unchecked = BooleanSetting ("-unchecked", "Enable detailed unchecked (erasure) warnings.")
val uniqid = BooleanSetting ("-uniqid", "Uniquely tag all identifiers in debugging output.")
val usejavacp = BooleanSetting ("-usejavacp", "Utilize the java.class.path in classpath resolution.")
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index bbdf10a021..e672f1914a 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -23,9 +23,12 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
new CleanUpTransformer(unit)
class CleanUpTransformer(unit: CompilationUnit) extends Transformer {
- private val newStaticMembers = mutable.Buffer.empty[Tree]
- private val newStaticInits = mutable.Buffer.empty[Tree]
- private val symbolsStoredAsStatic = mutable.Map.empty[String, Symbol]
+ private val newStaticMembers = mutable.Buffer.empty[Tree]
+ private val newStaticInits = mutable.Buffer.empty[Tree]
+ private val symbolsStoredAsStatic = mutable.Map.empty[String, Symbol]
+ private val staticBodies = mutable.Map.empty[(Symbol, Symbol), Tree]
+ private val syntheticClasses = mutable.Map.empty[Symbol, mutable.Set[Tree]] // package and trees
+ private val classNames = mutable.Map.empty[Symbol, Set[Name]]
private def clearStatics() {
newStaticMembers.clear()
newStaticInits.clear()
@@ -45,15 +48,16 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
result
}
private def transformTemplate(tree: Tree) = {
- val Template(parents, self, body) = tree
+ val t @ Template(parents, self, body) = tree
clearStatics()
+
val newBody = transformTrees(body)
val templ = deriveTemplate(tree)(_ => transformTrees(newStaticMembers.toList) ::: newBody)
try addStaticInits(templ) // postprocess to include static ctors
finally clearStatics()
}
private def mkTerm(prefix: String): TermName = unit.freshTermName(prefix)
-
+
/** Kludge to provide a safe fix for #4560:
* If we generate a reference in an implementation class, we
* watch out for embedded This(..) nodes that point to the interface.
@@ -555,7 +559,73 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
else tree
}
-
+
+ case ValDef(mods, name, tpt, rhs) if tree.symbol.hasStaticAnnotation =>
+ log("moving @static valdef field: " + name + ", in: " + tree.symbol.owner)
+ val sym = tree.symbol
+ val owner = sym.owner
+
+ val staticBeforeLifting = atPhase(currentRun.erasurePhase) { owner.isStatic }
+ val isPrivate = atPhase(currentRun.typerPhase) { sym.getter(owner).hasFlag(PRIVATE) }
+ val isProtected = atPhase(currentRun.typerPhase) { sym.getter(owner).hasFlag(PROTECTED) }
+ val isLazy = atPhase(currentRun.typerPhase) { sym.getter(owner).hasFlag(LAZY) }
+ if (!owner.isModuleClass || !staticBeforeLifting) {
+ if (!sym.isSynthetic) {
+ reporter.error(tree.pos, "Only members of top-level objects and their nested objects can be annotated with @static.")
+ tree.symbol.removeAnnotation(StaticClass)
+ }
+ super.transform(tree)
+ } else if (isPrivate || isProtected) {
+ reporter.error(tree.pos, "The @static annotation is only allowed on public members.")
+ tree.symbol.removeAnnotation(StaticClass)
+ super.transform(tree)
+ } else if (isLazy) {
+ reporter.error(tree.pos, "The @static annotation is not allowed on lazy members.")
+ tree.symbol.removeAnnotation(StaticClass)
+ super.transform(tree)
+ } else if (owner.isModuleClass) {
+ val linkedClass = owner.companionClass match {
+ case NoSymbol =>
+ // create the companion class if it does not exist
+ val enclosing = owner.owner
+ val compclass = enclosing.newClass(newTypeName(owner.name.toString))
+ compclass setInfo ClassInfoType(List(ObjectClass.tpe), newScope, compclass)
+ enclosing.info.decls enter compclass
+
+ val compclstree = ClassDef(compclass, NoMods, List(List()), List(List()), List(), tree.pos)
+
+ syntheticClasses.getOrElseUpdate(enclosing, mutable.Set()) += compclstree
+
+ compclass
+ case comp => comp
+ }
+
+ // create a static field in the companion class for this @static field
+ val stfieldSym = linkedClass.newVariable(newTermName(name), tree.pos, STATIC | SYNTHETIC | FINAL) setInfo sym.tpe
+ stfieldSym.addAnnotation(StaticClass)
+
+ val names = classNames.getOrElseUpdate(linkedClass, linkedClass.info.decls.collect {
+ case sym if sym.name.isTermName => sym.name
+ } toSet)
+ if (names(stfieldSym.name)) {
+ reporter.error(
+ tree.pos,
+ "@static annotated field " + tree.symbol.name + " has the same name as a member of class " + linkedClass.name
+ )
+ } else {
+ linkedClass.info.decls enter stfieldSym
+
+ val initializerBody = rhs
+
+ // static field was previously initialized in the companion object itself, like this:
+ // staticBodies((linkedClass, stfieldSym)) = Select(This(owner), sym.getter(owner))
+ // instead, we move the initializer to the static ctor of the companion class
+ // we save the entire ValDef/DefDef to extract the rhs later
+ staticBodies((linkedClass, stfieldSym)) = tree
+ }
+ }
+ super.transform(tree)
+
/* MSIL requires that the stack is empty at the end of a try-block.
* Hence, we here rewrite all try blocks with a result != {Unit, All} such that they
* store their result in a local variable. The catch blocks are adjusted as well.
@@ -665,6 +735,11 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
if (newStaticInits.isEmpty)
template
else {
+ val ctorBody = newStaticInits.toList flatMap {
+ case Block(stats, expr) => stats :+ expr
+ case t => List(t)
+ }
+
val newCtor = findStaticCtor(template) match {
// in case there already were static ctors - augment existing ones
// currently, however, static ctors aren't being generated anywhere else
@@ -673,22 +748,76 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
deriveDefDef(ctor) {
case block @ Block(stats, expr) =>
// need to add inits to existing block
- treeCopy.Block(block, newStaticInits.toList ::: stats, expr)
+ treeCopy.Block(block, ctorBody ::: stats, expr)
case term: TermTree =>
// need to create a new block with inits and the old term
- treeCopy.Block(term, newStaticInits.toList, term)
+ treeCopy.Block(term, ctorBody, term)
}
case _ =>
// create new static ctor
val staticCtorSym = currentClass.newStaticConstructor(template.pos)
- val rhs = Block(newStaticInits.toList, Literal(Constant(())))
+ val rhs = Block(ctorBody, Literal(Constant(())))
localTyper.typedPos(template.pos)(DefDef(staticCtorSym, rhs))
}
deriveTemplate(template)(newCtor :: _)
}
}
-
+
+ private def addStaticDeclarations(tree: Template, clazz: Symbol) {
+ // add static field initializer statements for each static field in clazz
+ if (!clazz.isModuleClass) for {
+ staticSym <- clazz.info.decls
+ if staticSym.hasStaticAnnotation
+ } staticSym match {
+ case stfieldSym if stfieldSym.isVariable =>
+ val valdef = staticBodies((clazz, stfieldSym))
+ val ValDef(_, _, _, rhs) = valdef
+ val fixedrhs = rhs.changeOwner((valdef.symbol, clazz.info.decl(nme.CONSTRUCTOR)))
+
+ val stfieldDef = localTyper.typedPos(tree.pos)(VAL(stfieldSym) === EmptyTree)
+ val flattenedInit = fixedrhs match {
+ case Block(stats, expr) => Block(stats, safeREF(stfieldSym) === expr)
+ case rhs => safeREF(stfieldSym) === rhs
+ }
+ val stfieldInit = localTyper.typedPos(tree.pos)(flattenedInit)
+
+ // add field definition to new defs
+ newStaticMembers append stfieldDef
+ newStaticInits append stfieldInit
+ }
+ }
+
+
+
+ override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = {
+ super.transformStats(stats, exprOwner) ++ {
+ // flush pending synthetic classes created in this owner
+ val synthclassdefs = syntheticClasses.get(exprOwner).toList.flatten
+ syntheticClasses -= exprOwner
+ synthclassdefs map {
+ cdef => localTyper.typedPos(cdef.pos)(cdef)
+ }
+ } map {
+ case clsdef @ ClassDef(mods, name, tparams, t @ Template(parent, self, body)) =>
+ // process all classes in the package again to add static initializers
+ clearStatics()
+
+ addStaticDeclarations(t, clsdef.symbol)
+
+ val templ = deriveTemplate(t)(_ => transformTrees(newStaticMembers.toList) ::: body)
+ val ntempl =
+ try addStaticInits(templ)
+ finally clearStatics()
+
+ val derived = deriveClassDef(clsdef)(_ => ntempl)
+ classNames.remove(clsdef.symbol)
+ derived
+
+ case stat => stat
+ }
+ }
+
} // CleanUpTransformer
}
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index e5119eac71..70bd0bd21b 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -186,12 +186,15 @@ abstract class Constructors extends Transform with ast.TreeDSL {
// before the superclass constructor call, otherwise it goes after.
// Lazy vals don't get the assignment in the constructor.
if (!stat.symbol.tpe.isInstanceOf[ConstantType]) {
- if (rhs != EmptyTree && !stat.symbol.isLazy) {
+ if (stat.symbol.hasStaticAnnotation) {
+ debuglog("@static annotated field initialization skipped.")
+ defBuf += deriveValDef(stat)(tree => tree)
+ } else if (rhs != EmptyTree && !stat.symbol.isLazy) {
val rhs1 = intoConstructor(stat.symbol, rhs);
(if (canBeMoved(stat)) constrPrefixBuf else constrStatBuf) += mkAssign(
stat.symbol, rhs1)
+ defBuf += deriveValDef(stat)(_ => EmptyTree)
}
- defBuf += deriveValDef(stat)(_ => EmptyTree)
}
case ClassDef(_, _, _, _) =>
// classes are treated recursively, and left in the template
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index ab7bbc591b..afbe528b1f 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -46,10 +46,13 @@ abstract class ExplicitOuter extends InfoTransform
private def haveSameOuter(parent: Type, clazz: Symbol) = parent match {
case TypeRef(pre, sym, _) =>
val owner = clazz.owner
+
+ //println(s"have same outer $parent $clazz $sym ${sym.owner} $owner $pre")
sym.isClass && owner.isClass &&
- owner == sym.owner &&
+ (owner isSubClass sym.owner) &&
owner.thisType =:= pre
+
case _ => false
}
@@ -480,7 +483,7 @@ abstract class ExplicitOuter extends InfoTransform
val vparamss1 =
if (isInner(clazz)) { // (4)
val outerParam =
- sym.newValueParameter(nme.OUTER, sym.pos) setInfo outerField(clazz).info
+ sym.newValueParameter(nme.OUTER, sym.pos) setInfo clazz.outerClass.thisType
((ValDef(outerParam) setType NoType) :: vparamss.head) :: vparamss.tail
} else vparamss
super.transform(copyDefDef(tree)(vparamss = vparamss1))
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index d5bbc578fc..492273dfdc 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -397,6 +397,9 @@ abstract class TailCalls extends Transform {
case Apply(fun, arg :: Nil) if hasSynthCaseSymbol(fun) && tailLabels(fun.symbol) =>
traverse(arg)
+ case Apply(fun, args) if (fun.symbol == Boolean_or || fun.symbol == Boolean_and) =>
+ traverseTrees(args)
+
// a translated casedef
case LabelDef(_, _, body) if hasSynthCaseSymbol(tree) =>
traverse(body)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index b7043e58de..d33857371d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -1140,7 +1140,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
}
try macroExpandInternal
- catch { case ex => handleMacroExpansionException(typer, expandee, ex) }
+ catch { case ex: Throwable => handleMacroExpansionException(typer, expandee, ex) }
}
private def macroExpandWithoutRuntime(typer: Typer, expandee: Tree): MacroExpansionResult = {
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index b54f127417..43edad3576 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -54,6 +54,25 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
import debugging.patmatDebug
+ // to govern how much time we spend analyzing matches for unreachability/exhaustivity
+ object AnalysisBudget {
+ import scala.tools.cmd.FromString.IntFromString
+ val max = sys.props.get("scalac.patmat.analysisBudget").collect(IntFromString.orElse{case "off" => Integer.MAX_VALUE}).getOrElse(256)
+
+ abstract class Exception extends RuntimeException("CNF budget exceeded") {
+ val advice: String
+ def warn(pos: Position, kind: String) = currentUnit.uncheckedWarning(pos, s"Cannot check match for $kind.\n$advice")
+ }
+
+ object exceeded extends Exception {
+ val advice = s"(The analysis required more space than allowed. Please try with scalac -Dscalac.patmat.analysisBudget=${AnalysisBudget.max*2} or -Dscalac.patmat.analysisBudget=off.)"
+ }
+
+ object stackOverflow extends Exception {
+ val advice = "(There was a stack overflow. Please try increasing the stack available to the compiler using e.g., -Xss2m.)"
+ }
+ }
+
def newTransformer(unit: CompilationUnit): Transformer =
if (opt.virtPatmat) new MatchTransformer(unit)
else noopTransformer
@@ -422,7 +441,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
The pattern matches any value v such that r == v (§12.1).
The type of r must conform to the expected type of the pattern.
**/
- case Literal(Constant(_)) | Ident(_) | Select(_, _) =>
+ case Literal(Constant(_)) | Ident(_) | Select(_, _) | This(_) =>
noFurtherSubPats(EqualityTestTreeMaker(patBinder, patTree, pos))
case Alternative(alts) =>
@@ -439,7 +458,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
patmatDebug("WARNING: Bind tree with unbound symbol "+ patTree)
noFurtherSubPats() // there's no symbol -- something's wrong... don't fail here though (or should we?)
- // case Star(_) | ArrayValue | This => error("stone age pattern relics encountered!")
+ // case Star(_) | ArrayValue => error("stone age pattern relics encountered!")
case _ =>
error("unsupported pattern: "+ patTree +"(a "+ patTree.getClass +")")
@@ -1946,14 +1965,14 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
type Formula
def andFormula(a: Formula, b: Formula): Formula
- class CNFBudgetExceeded extends RuntimeException("CNF budget exceeded")
- // may throw an CNFBudgetExceeded
- def propToSolvable(p: Prop) = {
+ // may throw an AnalysisBudget.Exception
+ def propToSolvable(p: Prop): Formula = {
val (eqAxioms, pure :: Nil) = removeVarEq(List(p), modelNull = false)
eqFreePropToSolvable(And(eqAxioms, pure))
}
+ // may throw an AnalysisBudget.Exception
def eqFreePropToSolvable(p: Prop): Formula
def cnfString(f: Formula): String
@@ -1979,7 +1998,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
type Lit
def Lit(sym: Sym, pos: Boolean = true): Lit
- // throws an CNFBudgetExceeded when the prop results in a CNF that's too big
+ // throws an AnalysisBudget.Exception when the prop results in a CNF that's too big
def eqFreePropToSolvable(p: Prop): Formula = {
// TODO: for now, reusing the normalization from DPLL
def negationNormalForm(p: Prop): Prop = p match {
@@ -2001,9 +2020,9 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
def lit(s: Sym) = formula(clause(Lit(s)))
def negLit(s: Sym) = formula(clause(Lit(s, false)))
- def conjunctiveNormalForm(p: Prop, budget: Int = 256): Formula = {
+ def conjunctiveNormalForm(p: Prop, budget: Int = AnalysisBudget.max): Formula = {
def distribute(a: Formula, b: Formula, budget: Int): Formula =
- if (budget <= 0) throw new CNFBudgetExceeded
+ if (budget <= 0) throw AnalysisBudget.exceeded
else
(a, b) match {
// true \/ _ = true
@@ -2018,7 +2037,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
big flatMap (c => distribute(formula(c), small, budget - (big.size*small.size)))
}
- if (budget <= 0) throw new CNFBudgetExceeded
+ if (budget <= 0) throw AnalysisBudget.exceeded
p match {
case True => TrueF
@@ -2037,9 +2056,17 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
val start = Statistics.startTimer(patmatCNF)
- val res = conjunctiveNormalForm(negationNormalForm(p))
+ val res =
+ try {
+ conjunctiveNormalForm(negationNormalForm(p))
+ } catch { case ex : StackOverflowError =>
+ throw AnalysisBudget.stackOverflow
+ }
+
Statistics.stopTimer(patmatCNF, start)
- patmatCNFSizes(res.size).value += 1
+
+ //
+ if (Statistics.enabled) patmatCNFSizes(res.size).value += 1
// patmatDebug("cnf for\n"+ p +"\nis:\n"+cnfString(res))
res
@@ -2440,6 +2467,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// right now hackily implement this by pruning counter-examples
// unreachability would also benefit from a more faithful representation
+
// reachability (dead code)
// computes the first 0-based case index that is unreachable (if any)
@@ -2508,9 +2536,8 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
if (reachable) None else Some(caseIndex)
} catch {
- case e : CNFBudgetExceeded =>
-// debugWarn(util.Position.formatMessage(prevBinder.pos, "Cannot check match for reachability", false))
-// e.printStackTrace()
+ case ex: AnalysisBudget.Exception =>
+ ex.warn(prevBinder.pos, "unreachability")
None // CNF budget exceeded
}
}
@@ -2651,9 +2678,8 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
Statistics.stopTimer(patmatAnaExhaust, start)
pruned
} catch {
- case e : CNFBudgetExceeded =>
- patmatDebug(util.Position.formatMessage(prevBinder.pos, "Cannot check match for exhaustivity", false))
- // e.printStackTrace()
+ case ex : AnalysisBudget.Exception =>
+ ex.warn(prevBinder.pos, "exhaustivity")
Nil // CNF budget exceeded
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index b0956446a7..a378a95786 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -129,7 +129,7 @@ abstract class TreeCheckers extends Analyzer {
private def wrap[T](msg: => Any)(body: => Unit) {
try body
- catch { case x =>
+ catch { case x: Throwable =>
Console.println("Caught " + x)
Console.println(msg)
x.printStackTrace
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index f4af6a6497..dbe65c16d8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1972,7 +1972,8 @@ trait Typers extends Modes with Adaptations with Tags {
case SilentResultValue(tpt) =>
val alias = enclClass.newAliasType(name.toTypeName, useCase.pos)
val tparams = cloneSymbolsAtOwner(tpt.tpe.typeSymbol.typeParams, alias)
- alias setInfo typeFun(tparams, appliedType(tpt.tpe, tparams map (_.tpe)))
+ val newInfo = genPolyType(tparams, appliedType(tpt.tpe, tparams map (_.tpe)))
+ alias setInfo newInfo
context.scope.enter(alias)
case _ =>
}
diff --git a/src/compiler/scala/tools/nsc/util/DocStrings.scala b/src/compiler/scala/tools/nsc/util/DocStrings.scala
index f4ce6d6ef1..c88414c423 100755
--- a/src/compiler/scala/tools/nsc/util/DocStrings.scala
+++ b/src/compiler/scala/tools/nsc/util/DocStrings.scala
@@ -144,6 +144,12 @@ object DocStrings {
}
/** Optionally start and end index of return section in `str`, or `None`
+ * if `str` does not have a @group. */
+ def groupDoc(str: String, sections: List[(Int, Int)]): Option[(Int, Int)] =
+ sections find (startsWithTag(str, _, "@group"))
+
+
+ /** Optionally start and end index of return section in `str`, or `None`
* if `str` does not have a @return.
*/
def returnDoc(str: String, sections: List[(Int, Int)]): Option[(Int, Int)] =
diff --git a/src/compiler/scala/tools/nsc/util/InterruptReq.scala b/src/compiler/scala/tools/nsc/util/InterruptReq.scala
index 2857823ceb..61aaa1bdcb 100644
--- a/src/compiler/scala/tools/nsc/util/InterruptReq.scala
+++ b/src/compiler/scala/tools/nsc/util/InterruptReq.scala
@@ -19,9 +19,10 @@ abstract class InterruptReq {
try {
result = Some(Left(todo()))
} catch {
- case t => result = Some(Right(t))
+ case t: Throwable => result = Some(Right(t))
+ } finally {
+ notify()
}
- notify()
}
/** To be called from interrupting client to get result for interrupt */
diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala
index 63ecfa32b2..237ef813c7 100644
--- a/src/compiler/scala/tools/reflect/FastTrack.scala
+++ b/src/compiler/scala/tools/reflect/FastTrack.scala
@@ -1,7 +1,6 @@
package scala.tools
package reflect
-import scala.reflect.makro.runtime.ContextReifiers
import scala.reflect.reify.Taggers
import scala.tools.nsc.typechecker.{Analyzer, Macros}
@@ -16,7 +15,6 @@ trait FastTrack {
import language.implicitConversions
private implicit def context2taggers(c0: MacroContext): Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers
- private implicit def context2contextreifiers(c0: MacroContext): ContextReifiers { val c: c0.type } = new { val c: c0.type = c0 } with ContextReifiers
private implicit def context2macroimplementations(c0: MacroContext): MacroImplementations { val c: c0.type } = new { val c: c0.type = c0 } with MacroImplementations
implicit def fastTrackEntry2MacroRuntime(entry: FastTrackEntry): MacroRuntime = args => entry.run(args)
@@ -41,7 +39,6 @@ trait FastTrack {
MacroInternal_materializeAbsTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = false) }
MacroInternal_materializeTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = true) }
ApiUniverseReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, EmptyTree, expr) }
- MacroContextReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExprForMacroContext(c.prefix.tree, expr) }
ReflectRuntimeCurrentMirror bindTo { case (c, _) => scala.reflect.runtime.Macros.currentMirror(c).tree }
StringContext_f bindTo { case (c, app@Apply(Select(Apply(_, parts), _), args)) => c.macro_StringInterpolation_f(parts, args, app.pos) }
registry
diff --git a/src/compiler/scala/tools/reflect/MacroImplementations.scala b/src/compiler/scala/tools/reflect/MacroImplementations.scala
index 604bd7cd1a..e1b959cefa 100644
--- a/src/compiler/scala/tools/reflect/MacroImplementations.scala
+++ b/src/compiler/scala/tools/reflect/MacroImplementations.scala
@@ -57,6 +57,9 @@ abstract class MacroImplementations {
)
}
+ val stdContextTags = new { val tc: c.type = c } with StdContextTags
+ import stdContextTags._
+
def conversionType(ch: Char, arg: Tree): Option[Type] = {
ch match {
case 'b' | 'B' =>
@@ -68,11 +71,11 @@ abstract class MacroImplementations {
case 'c' | 'C' =>
checkType(arg, CharTpe, ByteTpe, ShortTpe, IntTpe)
case 'd' | 'o' | 'x' | 'X' =>
- checkType(arg, IntTpe, LongTpe, ByteTpe, ShortTpe, typeOf[BigInt])
+ checkType(arg, IntTpe, LongTpe, ByteTpe, ShortTpe, tagOfBigInt.tpe)
case 'e' | 'E' | 'g' | 'G' | 'f' | 'a' | 'A' =>
- checkType(arg, DoubleTpe, FloatTpe, typeOf[BigDecimal])
+ checkType(arg, DoubleTpe, FloatTpe, tagOfBigDecimal.tpe)
case 't' | 'T' =>
- checkType(arg, LongTpe, typeOf[java.util.Calendar], typeOf[java.util.Date])
+ checkType(arg, LongTpe, tagOfCalendar.tpe, tagOfDate.tpe)
case _ => None
}
}
diff --git a/src/compiler/scala/tools/reflect/StdTags.scala b/src/compiler/scala/tools/reflect/StdTags.scala
index 18cbf9c4b7..25a42a82cd 100644
--- a/src/compiler/scala/tools/reflect/StdTags.scala
+++ b/src/compiler/scala/tools/reflect/StdTags.scala
@@ -4,46 +4,55 @@ package reflect
import java.lang.{Class => jClass}
import scala.reflect.{ClassTag, classTag}
import scala.reflect.base.{MirrorOf, TypeCreator, Universe => BaseUniverse}
-import scala.reflect.runtime.{universe => ru}
// [Eugene++] Before 2.10 is released, I suggest we don't rely on automated type tag generation
// sure, it's convenient, but then refactoring reflection / reification becomes a pain
// `ClassTag` tags are fine, because they don't need a reifier to be generated
-object StdTags {
- // root mirror is fine for these guys, since scala-library.jar is guaranteed to be reachable from the root mirror
- lazy val tagOfString = ru.TypeTag[String](
- ru.rootMirror,
- new TypeCreator {
- def apply[U <: BaseUniverse with Singleton](m: MirrorOf[U]): U # Type = {
- val u = m.universe
- u.definitions.StringClass.asTypeConstructor
- }
- })
- lazy val tagOfListOfString = ru.TypeTag[List[String]](
- ru.rootMirror,
- new TypeCreator {
- def apply[U <: BaseUniverse with Singleton](m: MirrorOf[U]): U # Type = {
- val u = m.universe
- val pre = u.ThisType(m.staticModule("scala.collection.immutable").moduleClass.asInstanceOf[u.Symbol])
- u.TypeRef(pre, u.definitions.ListClass, List(u.definitions.StringClass.asTypeConstructor))
- }
- })
+trait StdTags {
+ val u: BaseUniverse with Singleton
+ val m: MirrorOf[u.type]
- // root mirror is NOT fine for these guys, hence we use the `currentMirror` trick
- private val ourClassloader = getClass.getClassLoader
- private def tagOfStaticClass[T: ClassTag] =
- ru.TypeTag[T](
- ru.runtimeMirror(ourClassloader),
+ lazy val tagOfListOfString: u.TypeTag[List[String]] =
+ u.TypeTag[List[String]](
+ m,
+ new TypeCreator {
+ def apply[U <: BaseUniverse with Singleton](m: MirrorOf[U]): U # Type = {
+ val u = m.universe
+ val pre = u.ThisType(m.staticPackage("scala.collection.immutable").moduleClass.asInstanceOf[u.Symbol])
+ u.TypeRef(pre, u.definitions.ListClass, List(u.definitions.StringClass.asTypeConstructor))
+ }
+ })
+
+ private def tagOfStaticClass[T: ClassTag]: u.TypeTag[T] =
+ u.TypeTag[T](
+ m,
new TypeCreator {
def apply[U <: BaseUniverse with Singleton](m: MirrorOf[U]): U # Type =
m.staticClass(classTag[T].runtimeClass.getName).asTypeConstructor.asInstanceOf[U # Type]
})
- lazy val tagOfInt = ru.TypeTag.Int
+ lazy val tagOfInt = u.TypeTag.Int
+ lazy val tagOfString = tagOfStaticClass[String]
lazy val tagOfFile = tagOfStaticClass[scala.tools.nsc.io.File]
lazy val tagOfDirectory = tagOfStaticClass[scala.tools.nsc.io.Directory]
lazy val tagOfStdReplVals = tagOfStaticClass[scala.tools.nsc.interpreter.StdReplVals]
lazy val tagOfIMain = tagOfStaticClass[scala.tools.nsc.interpreter.IMain]
lazy val tagOfThrowable = tagOfStaticClass[java.lang.Throwable]
lazy val tagOfClassLoader = tagOfStaticClass[java.lang.ClassLoader]
+ lazy val tagOfBigInt = tagOfStaticClass[BigInt]
+ lazy val tagOfBigDecimal = tagOfStaticClass[BigDecimal]
+ lazy val tagOfCalendar = tagOfStaticClass[java.util.Calendar]
+ lazy val tagOfDate = tagOfStaticClass[java.util.Date]
+}
+
+object StdRuntimeTags extends StdTags {
+ val u: scala.reflect.runtime.universe.type = scala.reflect.runtime.universe
+ val m = u.runtimeMirror(getClass.getClassLoader)
+ // we need getClass.getClassLoader to support the stuff from scala-compiler.jar
+}
+
+abstract class StdContextTags extends StdTags {
+ val tc: scala.reflect.makro.Context
+ val u: tc.universe.type = tc.universe
+ val m = tc.mirror
}
diff --git a/src/compiler/scala/tools/util/VerifyClass.scala b/src/compiler/scala/tools/util/VerifyClass.scala
index 5f636f63fb..e0e089d0b2 100644
--- a/src/compiler/scala/tools/util/VerifyClass.scala
+++ b/src/compiler/scala/tools/util/VerifyClass.scala
@@ -13,7 +13,8 @@ object VerifyClass {
Class.forName(name, true, cl)
(name, None)
} catch {
- case x => (name, Some(x.toString))
+ case x: Throwable => // TODO: only catch VerifyError (and related) + ExceptionInInitializationError (for static objects that bomb on classload)
+ (name, Some(x.toString))
}
}
diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala
index 3a1dc87a6a..46c644bcd6 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala
@@ -36,7 +36,7 @@ trait CPSUtils {
lazy val MarkerCPSAdaptMinus = rootMirror.getRequiredClass("scala.util.continuations.cpsMinus")
lazy val Context = rootMirror.getRequiredClass("scala.util.continuations.ControlContext")
- lazy val ModCPS = rootMirror.getRequiredModule("scala.util.continuations")
+ lazy val ModCPS = rootMirror.getRequiredPackage("scala.util.continuations")
lazy val MethShiftUnit = definitions.getMember(ModCPS, cpsNames.shiftUnit)
lazy val MethShiftUnit0 = definitions.getMember(ModCPS, cpsNames.shiftUnit0)
diff --git a/src/library-aux/scala/AnyRef.scala b/src/library-aux/scala/AnyRef.scala
index 1eefb0c806..7d8b9f9e76 100644
--- a/src/library-aux/scala/AnyRef.scala
+++ b/src/library-aux/scala/AnyRef.scala
@@ -10,6 +10,7 @@ package scala
/** Class `AnyRef` is the root class of all ''reference types''.
* All types except the value types descend from this class.
+ * @template
*/
trait AnyRef extends Any {
diff --git a/src/library/scala/annotation/static.scala b/src/library/scala/annotation/static.scala
new file mode 100644
index 0000000000..f2955c756c
--- /dev/null
+++ b/src/library/scala/annotation/static.scala
@@ -0,0 +1,20 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.annotation
+
+/**
+ * An annotation that marks a member in the companion object as static
+ * and ensures that the compiler generates static fields/methods for it.
+ * This is important for Java interoperability and performance reasons.
+ *
+ * @since 2.10
+ */
+final class static extends StaticAnnotation {
+ // TODO document exact semantics above!
+}
diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala
index 6fd8d143ee..74dc385f99 100644
--- a/src/library/scala/collection/immutable/List.scala
+++ b/src/library/scala/collection/immutable/List.scala
@@ -62,6 +62,7 @@ import java.io._
* section on `Lists` for more information.
*
* @define coll list
+ * @define Coll `List`
* @define thatinfo the class of the returned collection. In the standard library configuration,
* `That` is always `List[B]` because an implicit of type `CanBuildFrom[List, B, That]`
* is defined in object `List`.
@@ -96,7 +97,7 @@ sealed abstract class List[+A] extends AbstractSeq[A]
*
* @usecase def ::(x: A): List[A]
* @inheritdoc
- *
+ *
* Example:
* {{{1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3)}}}
*/
diff --git a/src/library/scala/collection/immutable/StringOps.scala b/src/library/scala/collection/immutable/StringOps.scala
index 633821ecea..7e60cc7195 100644
--- a/src/library/scala/collection/immutable/StringOps.scala
+++ b/src/library/scala/collection/immutable/StringOps.scala
@@ -25,7 +25,7 @@ import mutable.StringBuilder
* @param repr the actual representation of this string operations object.
*
* @since 2.8
- * @define Coll `StringOps`
+ * @define Coll `String`
* @define coll string
*/
final class StringOps(override val repr: String) extends AnyVal with StringLike[String] {
diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala
index 7a595f211d..21c2aaaec7 100644
--- a/src/library/scala/collection/mutable/ArrayOps.scala
+++ b/src/library/scala/collection/mutable/ArrayOps.scala
@@ -30,7 +30,7 @@ import parallel.mutable.ParArray
*
* @tparam T type of the elements contained in this array.
*
- * @define Coll `ArrayOps`
+ * @define Coll `Array`
* @define orderDependent
* @define orderDependentFold
* @define mayNotTerminateInf
diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala
index a6488b602f..a2ef42fac8 100644
--- a/src/library/scala/concurrent/package.scala
+++ b/src/library/scala/concurrent/package.scala
@@ -18,41 +18,6 @@ package object concurrent {
type CancellationException = java.util.concurrent.CancellationException
type TimeoutException = java.util.concurrent.TimeoutException
- @implicitNotFound("Don't call `Awaitable` methods directly, use the `Await` object.")
- sealed trait CanAwait
- private implicit object AwaitPermission extends CanAwait
-
- /**
- * `Await` is what is used to ensure proper handling of blocking for `Awaitable` instances.
- */
- object Await {
- /**
- * Invokes ready() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`.
- * ready() blocks until the awaitable has completed or the timeout expires.
- *
- * Throws a TimeoutException if the timeout expires, as that is in the contract of `Awaitable.ready`.
- * @param awaitable the `Awaitable` on which `ready` is to be called
- * @param atMost the maximum timeout for which to wait
- * @return the result of `awaitable.ready` which is defined to be the awaitable itself.
- */
- @throws(classOf[TimeoutException])
- def ready[T](awaitable: Awaitable[T], atMost: Duration): awaitable.type =
- blocking(awaitable.ready(atMost))
-
- /**
- * Invokes result() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`.
- * result() blocks until the awaitable has completed or the timeout expires.
- *
- * Throws a TimeoutException if the timeout expires, or any exception thrown by `Awaitable.result`.
- * @param awaitable the `Awaitable` on which `result` is to be called
- * @param atMost the maximum timeout for which to wait
- * @return the result of `awaitable.result`
- */
- @throws(classOf[Exception])
- def result[T](awaitable: Awaitable[T], atMost: Duration): T =
- blocking(awaitable.result(atMost))
- }
-
/** Starts an asynchronous computation and returns a `Future` object with the result of that computation.
*
* The result becomes available once the asynchronous computation is completed.
@@ -85,5 +50,46 @@ package object concurrent {
* - TimeoutException - in the case that the blockable object timed out
*/
@throws(classOf[Exception])
- def blocking[T](body: =>T): T = BlockContext.current.blockOn(body)
+ def blocking[T](body: =>T): T = BlockContext.current.blockOn(body)(scala.concurrent.AwaitPermission)
+}
+
+package concurrent {
+ @implicitNotFound("Don't call `Awaitable` methods directly, use the `Await` object.")
+ sealed trait CanAwait
+
+ /**
+ * Internal usage only, implementation detail.
+ */
+ private[concurrent] object AwaitPermission extends CanAwait
+
+ /**
+ * `Await` is what is used to ensure proper handling of blocking for `Awaitable` instances.
+ */
+ object Await {
+ /**
+ * Invokes ready() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`.
+ * ready() blocks until the awaitable has completed or the timeout expires.
+ *
+ * Throws a TimeoutException if the timeout expires, as that is in the contract of `Awaitable.ready`.
+ * @param awaitable the `Awaitable` on which `ready` is to be called
+ * @param atMost the maximum timeout for which to wait
+ * @return the result of `awaitable.ready` which is defined to be the awaitable itself.
+ */
+ @throws(classOf[TimeoutException])
+ def ready[T](awaitable: Awaitable[T], atMost: Duration): awaitable.type =
+ blocking(awaitable.ready(atMost)(AwaitPermission))
+
+ /**
+ * Invokes result() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`.
+ * result() blocks until the awaitable has completed or the timeout expires.
+ *
+ * Throws a TimeoutException if the timeout expires, or any exception thrown by `Awaitable.result`.
+ * @param awaitable the `Awaitable` on which `result` is to be called
+ * @param atMost the maximum timeout for which to wait
+ * @return the result of `awaitable.result`
+ */
+ @throws(classOf[Exception])
+ def result[T](awaitable: Awaitable[T], atMost: Duration): T =
+ blocking(awaitable.result(atMost)(AwaitPermission))
+ }
}
diff --git a/src/library/scala/reflect/base/Base.scala b/src/library/scala/reflect/base/Base.scala
index a4e6256f4d..4457a6cf14 100644
--- a/src/library/scala/reflect/base/Base.scala
+++ b/src/library/scala/reflect/base/Base.scala
@@ -357,6 +357,9 @@ class Base extends Universe { self =>
def staticModule(fullName: String): ModuleSymbol =
mkStatic[ModuleSymbol](fullName)
+ def staticPackage(fullName: String): ModuleSymbol =
+ staticModule(fullName) // this toy universe doesn't care about the distinction between packages and modules
+
private def mkStatic[S <: Symbol : ClassTag](fullName: String): S =
cached(fullName) {
val point = fullName lastIndexOf '.'
diff --git a/src/library/scala/reflect/base/MirrorOf.scala b/src/library/scala/reflect/base/MirrorOf.scala
index 03e035cd81..6dc8090eee 100644
--- a/src/library/scala/reflect/base/MirrorOf.scala
+++ b/src/library/scala/reflect/base/MirrorOf.scala
@@ -15,11 +15,76 @@ abstract class MirrorOf[U <: base.Universe with Singleton] {
/** The symbol corresponding to the globally accessible class with the
* given fully qualified name `fullName`.
+ *
+ * If the name points to a type alias, it's recursively dealiased and its target is returned.
+ * If you need a symbol that corresponds to the type alias itself, load it directly from the package class:
+ *
+ * scala> cm.staticClass("scala.List")
+ * res0: reflect.runtime.universe.ClassSymbol = class List
+ *
+ * scala> res0.fullName
+ * res1: String = scala.collection.immutable.List
+ *
+ * scala> cm.staticPackage("scala")
+ * res2: reflect.runtime.universe.ModuleSymbol = package scala
+ *
+ * scala> res2.moduleClass.typeSignature member newTypeName("List")
+ * res3: reflect.runtime.universe.Symbol = type List
+ *
+ * scala> res3.fullName
+ * res4: String = scala.List
+ *
+ * To be consistent with Scala name resolution rules, in case of ambiguity between
+ * a package and an object, the object is never been considered.
+ *
+ * For example for the following code:
+ *
+ * package foo {
+ * class B
+ * }
+ *
+ * object foo {
+ * class A
+ * class B
+ * }
+ *
+ * staticClass("foo.B") will resolve to the symbol corresponding to the class B declared in the package foo, and
+ * staticClass("foo.A") will throw a MissingRequirementException (which is exactly what scalac would do if this
+ * fully qualified class name is written inside any package in a Scala program).
+ *
+ * In the example above, to load a symbol that corresponds to the class B declared in the object foo,
+ * use staticModule("foo") to load the module symbol and then navigate typeSignature.members of its moduleClass.
*/
def staticClass(fullName: String): U#ClassSymbol
/** The symbol corresponding to the globally accessible object with the
* given fully qualified name `fullName`.
+ *
+ * To be consistent with Scala name resolution rules, in case of ambiguity between
+ * a package and an object, the object is never been considered.
+ *
+ * For example for the following code:
+ *
+ * package foo {
+ * object B
+ * }
+ *
+ * object foo {
+ * object A
+ * object B
+ * }
+ *
+ * staticModule("foo.B") will resolve to the symbol corresponding to the object B declared in the package foo, and
+ * staticModule("foo.A") will throw a MissingRequirementException (which is exactly what scalac would do if this
+ * fully qualified class name is written inside any package in a Scala program).
+ *
+ * In the example above, to load a symbol that corresponds to the object B declared in the object foo,
+ * use staticModule("foo") to load the module symbol and then navigate typeSignature.members of its moduleClass.
*/
def staticModule(fullName: String): U#ModuleSymbol
+
+ /** The symbol corresponding to a package with the
+ * given fully qualified name `fullName`.
+ */
+ def staticPackage(fullName: String): U#ModuleSymbol
}
diff --git a/src/partest/scala/tools/partest/CompilerTest.scala b/src/partest/scala/tools/partest/CompilerTest.scala
index 89c1a9c2ca..fec9893099 100644
--- a/src/partest/scala/tools/partest/CompilerTest.scala
+++ b/src/partest/scala/tools/partest/CompilerTest.scala
@@ -50,7 +50,7 @@ abstract class CompilerTest extends DirectTest {
}
class SymsInPackage(pkgName: String) {
- def pkg = rootMirror.getRequiredModule(pkgName)
+ def pkg = rootMirror.getRequiredPackage(pkgName)
def classes = allMembers(pkg) filter (_.isClass)
def modules = allMembers(pkg) filter (_.isModule)
def symbols = classes ++ terms filterNot (_ eq NoSymbol)
diff --git a/src/partest/scala/tools/partest/DirectTest.scala b/src/partest/scala/tools/partest/DirectTest.scala
index 4e7f36bdc9..5b4e1b4b25 100644
--- a/src/partest/scala/tools/partest/DirectTest.scala
+++ b/src/partest/scala/tools/partest/DirectTest.scala
@@ -38,7 +38,8 @@ abstract class DirectTest extends App {
// new compiler
def newCompiler(args: String*): Global = {
val settings = newSettings((CommandLineParser tokenize extraSettings) ++ args.toList)
- new Global(settings)
+ if (settings.Yrangepos.value) new Global(settings) with interactive.RangePositions
+ else new Global(settings)
}
def newSources(sourceCodes: String*) = sourceCodes.toList.zipWithIndex map {
case (src, idx) => new BatchSourceFile("newSource" + (idx + 1), src)
@@ -69,7 +70,7 @@ abstract class DirectTest extends App {
/** Constructor/main body **/
try show()
- catch { case t => println(t) ; t.printStackTrace ; sys.exit(1) }
+ catch { case t => println(t.getMessage) ; t.printStackTrace ; sys.exit(1) }
/** Debugger interest only below this line **/
protected def isDebug = (sys.props contains "partest.debug") || (sys.env contains "PARTEST_DEBUG")
diff --git a/src/partest/scala/tools/partest/ScaladocModelTest.scala b/src/partest/scala/tools/partest/ScaladocModelTest.scala
index de5354d4a0..ffc5e74cc0 100644
--- a/src/partest/scala/tools/partest/ScaladocModelTest.scala
+++ b/src/partest/scala/tools/partest/ScaladocModelTest.scala
@@ -11,6 +11,8 @@ 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.doc.model.diagram._
+import scala.tools.nsc.doc.model.comment._
import scala.tools.nsc.reporters.ConsoleReporter
/** A class for testing scaladoc model generation
@@ -102,13 +104,22 @@ abstract class ScaladocModelTest extends DirectTest {
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).collect({ case c: Class => c})
+ def _classes(name: String): List[DocTemplateEntity] = tpl.templates.filter(_.name == name).collect({ case c: DocTemplateEntity with Class => c})
+
+ def _classMbr(name: String): MemberTemplateEntity = getTheFirst(_classesMbr(name), tpl.qualifiedName + ".classMember(" + name + ")")
+ def _classesMbr(name: String): List[MemberTemplateEntity] = tpl.templates.filter(_.name == name).collect({ case c: MemberTemplateEntity if c.isClass => c})
def _trait(name: String): DocTemplateEntity = getTheFirst(_traits(name), tpl.qualifiedName + ".trait(" + name + ")")
- def _traits(name: String): List[DocTemplateEntity] = tpl.templates.filter(_.name == name).collect({ case t: Trait => t})
+ def _traits(name: String): List[DocTemplateEntity] = tpl.templates.filter(_.name == name).collect({ case t: DocTemplateEntity with Trait => t})
+
+ def _traitMbr(name: String): MemberTemplateEntity = getTheFirst(_traitsMbr(name), tpl.qualifiedName + ".traitMember(" + name + ")")
+ def _traitsMbr(name: String): List[MemberTemplateEntity] = tpl.templates.filter(_.name == name).collect({ case t: MemberTemplateEntity if t.isTrait => t})
def _object(name: String): DocTemplateEntity = getTheFirst(_objects(name), tpl.qualifiedName + ".object(" + name + ")")
- def _objects(name: String): List[DocTemplateEntity] = tpl.templates.filter(_.name == name).collect({ case o: Object => o})
+ def _objects(name: String): List[DocTemplateEntity] = tpl.templates.filter(_.name == name).collect({ case o: DocTemplateEntity with Object => o})
+
+ def _objectMbr(name: String): MemberTemplateEntity = getTheFirst(_objectsMbr(name), tpl.qualifiedName + ".objectMember(" + name + ")")
+ def _objectsMbr(name: String): List[MemberTemplateEntity] = tpl.templates.filter(_.name == name).collect({ case o: MemberTemplateEntity if o.isObject => o})
def _method(name: String): Def = getTheFirst(_methods(name), tpl.qualifiedName + ".method(" + name + ")")
def _methods(name: String): List[Def] = tpl.methods.filter(_.name == name)
@@ -118,6 +129,18 @@ abstract class ScaladocModelTest extends DirectTest {
def _conversion(name: String): ImplicitConversion = getTheFirst(_conversions(name), tpl.qualifiedName + ".conversion(" + name + ")")
def _conversions(name: String): List[ImplicitConversion] = tpl.conversions.filter(_.conversionQualifiedName == name)
+
+ def _absType(name: String): MemberEntity = getTheFirst(_absTypes(name), tpl.qualifiedName + ".abstractType(" + name + ")")
+ def _absTypes(name: String): List[MemberEntity] = tpl.members.filter(mbr => mbr.name == name && mbr.isAbstractType)
+
+ def _absTypeTpl(name: String): DocTemplateEntity = getTheFirst(_absTypeTpls(name), tpl.qualifiedName + ".abstractType(" + name + ")")
+ def _absTypeTpls(name: String): List[DocTemplateEntity] = tpl.members.collect({ case dtpl: DocTemplateEntity with AbstractType if dtpl.name == name => dtpl })
+
+ def _aliasType(name: String): MemberEntity = getTheFirst(_aliasTypes(name), tpl.qualifiedName + ".aliasType(" + name + ")")
+ def _aliasTypes(name: String): List[MemberEntity] = tpl.members.filter(mbr => mbr.name == name && mbr.isAliasType)
+
+ def _aliasTypeTpl(name: String): DocTemplateEntity = getTheFirst(_aliasTypeTpls(name), tpl.qualifiedName + ".aliasType(" + name + ")")
+ def _aliasTypeTpls(name: String): List[DocTemplateEntity] = tpl.members.collect({ case dtpl: DocTemplateEntity with AliasType if dtpl.name == name => dtpl })
}
class PackageAccess(pack: Package) extends TemplateAccess(pack) {
@@ -140,7 +163,43 @@ abstract class ScaladocModelTest extends DirectTest {
case 1 => list.head
case 0 => sys.error("Error getting " + expl + ": No such element.")
case _ => sys.error("Error getting " + expl + ": " + list.length + " elements with this name. " +
- "All elements in list: [" + list.mkString(", ") + "]")
+ "All elements in list: [" + list.map({
+ case ent: Entity => ent.kind + " " + ent.qualifiedName
+ case other => other.toString
+ }).mkString(", ") + "]")
+ }
+
+ def extractCommentText(c: Any) = {
+ def extractText(body: Any): String = body match {
+ case s: String => s
+ case s: Seq[_] => s.toList.map(extractText(_)).mkString
+ case p: Product => p.productIterator.toList.map(extractText(_)).mkString
+ case _ => ""
+ }
+ c match {
+ case c: Comment =>
+ extractText(c.body)
+ case b: Body =>
+ extractText(b)
+ }
+ }
+
+ def countLinks(c: Comment, p: EntityLink => Boolean) = {
+ def countLinks(body: Any): Int = body match {
+ case el: EntityLink if p(el) => 1
+ case s: Seq[_] => s.toList.map(countLinks(_)).sum
+ case p: Product => p.productIterator.toList.map(countLinks(_)).sum
+ case _ => 0
+ }
+ countLinks(c.body)
+ }
+
+ def testDiagram(doc: DocTemplateEntity, diag: Option[Diagram], nodes: Int, edges: Int) = {
+ assert(diag.isDefined, doc.qualifiedName + " diagram missing")
+ assert(diag.get.nodes.length == nodes,
+ doc.qualifiedName + "'s diagram: node count " + diag.get.nodes.length + " == " + nodes)
+ assert(diag.get.edges.map(_._2.length).sum == edges,
+ doc.qualifiedName + "'s diagram: edge count " + diag.get.edges.length + " == " + edges)
}
}
}
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index cd243b9df0..d9b63529eb 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -490,7 +490,6 @@ trait Definitions extends api.StandardDefinitions {
def MacroContextPrefixType = if (MacroContextClass != NoSymbol) getMemberType(MacroContextClass, tpnme.PrefixType) else NoSymbol
def MacroContextUniverse = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.universe) else NoSymbol
def MacroContextMirror = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.mirror) else NoSymbol
- def MacroContextReify = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.reify) else NoSymbol
lazy val MacroImplAnnotation = requiredClass[scala.reflect.makro.internal.macroImpl]
lazy val MacroInternalPackage = getPackageObject("scala.reflect.makro.internal")
def MacroInternal_materializeClassTag = getMemberMethod(MacroInternalPackage, nme.materializeClassTag)
@@ -899,6 +898,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val SwitchClass = requiredClass[scala.annotation.switch]
lazy val TailrecClass = requiredClass[scala.annotation.tailrec]
lazy val VarargsClass = requiredClass[scala.annotation.varargs]
+ lazy val StaticClass = requiredClass[scala.annotation.static]
lazy val uncheckedStableClass = requiredClass[scala.annotation.unchecked.uncheckedStable]
lazy val uncheckedVarianceClass = requiredClass[scala.annotation.unchecked.uncheckedVariance]
diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala
index 761b993539..f7561ae274 100644
--- a/src/reflect/scala/reflect/internal/Mirrors.scala
+++ b/src/reflect/scala/reflect/internal/Mirrors.scala
@@ -36,7 +36,7 @@ trait Mirrors extends api.Mirrors {
if (point > 0) getModuleOrClass(path.toTermName, point)
else RootClass
val name = path subName (point + 1, len)
- val sym = owner.info member name
+ var sym = owner.info member name
val result = if (path.isTermName) sym.suchThat(_ hasFlag MODULE) else sym
if (result != NoSymbol) result
else {
@@ -47,23 +47,39 @@ trait Mirrors extends api.Mirrors {
}
}
- protected def mirrorMissingHook(owner: Symbol, name: Name): Symbol = NoSymbol
-
- protected def symbolTableMissingHook(owner: Symbol, name: Name): Symbol = self.missingHook(owner, name)
-
- private[scala] def missingHook(owner: Symbol, name: Name): Symbol = mirrorMissingHook(owner, name) orElse symbolTableMissingHook(owner, name)
+ /** If you're looking for a class, pass a type name.
+ * If a module, a term name.
+ *
+ * Unlike `getModuleOrClass`, this function
+ * loads unqualified names from the root package.
+ */
+ private def getModuleOrClass(path: Name): Symbol =
+ getModuleOrClass(path, path.length)
/** If you're looking for a class, pass a type name.
* If a module, a term name.
+ *
+ * Unlike `getModuleOrClass`, this function
+ * loads unqualified names from the empty package.
*/
- private def getModuleOrClass(path: Name): Symbol = getModuleOrClass(path, path.length)
+ private def staticModuleOrClass(path: Name): Symbol = {
+ val isPackageless = path.pos('.') == path.length
+ if (isPackageless) EmptyPackageClass.info decl path
+ else getModuleOrClass(path)
+ }
+
+ protected def mirrorMissingHook(owner: Symbol, name: Name): Symbol = NoSymbol
+
+ protected def universeMissingHook(owner: Symbol, name: Name): Symbol = self.missingHook(owner, name)
- override def staticClass(fullName: String): ClassSymbol = getRequiredClass(fullName)
+ private[scala] def missingHook(owner: Symbol, name: Name): Symbol = mirrorMissingHook(owner, name) orElse universeMissingHook(owner, name)
- // todo: get rid of most creation methods and keep just staticClass/Module/Package
+ // todo: get rid of most the methods here and keep just staticClass/Module/Package
- def getClassByName(fullname: Name): ClassSymbol = {
- var result = getModuleOrClass(fullname.toTypeName)
+ /************************ loaders of class symbols ************************/
+
+ private def ensureClassSymbol(fullname: String, sym: Symbol): ClassSymbol = {
+ var result = sym
while (result.isAliasType) result = result.info.typeSymbol
result match {
case x: ClassSymbol => x
@@ -71,45 +87,50 @@ trait Mirrors extends api.Mirrors {
}
}
- override def staticModule(fullName: String): ModuleSymbol = getRequiredModule(fullName)
+ @deprecated("Use getClassByName", "2.10.0")
+ def getClass(fullname: Name): ClassSymbol =
+ getClassByName(fullname)
- def getModule(fullname: Name): ModuleSymbol =
- // [Eugene++] should be a ClassCastException instead?
- getModuleOrClass(fullname.toTermName) match {
- case x: ModuleSymbol => x
- case _ => MissingRequirementError.notFound("object " + fullname)
- }
+ def getClassByName(fullname: Name): ClassSymbol =
+ ensureClassSymbol(fullname.toString, getModuleOrClass(fullname.toTypeName))
- def getPackage(fullname: Name): ModuleSymbol = getModule(fullname)
+ def getRequiredClass(fullname: String): ClassSymbol =
+ getClassByName(newTypeNameCached(fullname))
- def getRequiredPackage(fullname: String): ModuleSymbol =
- getPackage(newTermNameCached(fullname))
+ def requiredClass[T: ClassTag] : ClassSymbol =
+ getRequiredClass(erasureName[T])
- @deprecated("Use getClassByName", "2.10.0")
- def getClass(fullname: Name): ClassSymbol = getClassByName(fullname)
+ def getClassIfDefined(fullname: String): Symbol =
+ getClassIfDefined(newTypeNameCached(fullname))
- def getRequiredClass(fullname: String): ClassSymbol =
- getClassByName(newTypeNameCached(fullname)) match {
- case x: ClassSymbol => x
- case _ => MissingRequirementError.notFound("class " + fullname)
- }
+ def getClassIfDefined(fullname: Name): Symbol =
+ wrapMissing(getClassByName(fullname.toTypeName))
- def getRequiredModule(fullname: String): ModuleSymbol =
- getModule(newTermNameCached(fullname))
+ /** @inheritdoc
+ *
+ * Unlike getClassByName/getRequiredClass this function can also load packageless symbols.
+ * Compiler might ignore them, but they should be loadable with macros.
+ */
+ override def staticClass(fullname: String): ClassSymbol =
+ ensureClassSymbol(fullname, staticModuleOrClass(newTypeNameCached(fullname)))
- def erasureName[T: ClassTag] : String = {
- /** We'd like the String representation to be a valid
- * scala type, so we have to decode the jvm's secret language.
- */
- def erasureString(clazz: Class[_]): String = {
- if (clazz.isArray) "Array[" + erasureString(clazz.getComponentType) + "]"
- else clazz.getName
+ /************************ loaders of module symbols ************************/
+
+ private def ensureModuleSymbol(fullname: String, sym: Symbol, allowPackages: Boolean): ModuleSymbol =
+ sym match {
+ case x: ModuleSymbol if allowPackages || !x.isPackage => x
+ case _ => MissingRequirementError.notFound("object " + fullname)
}
- erasureString(classTag[T].runtimeClass)
- }
- def requiredClass[T: ClassTag] : ClassSymbol =
- getRequiredClass(erasureName[T])
+ @deprecated("Use getModuleByName", "2.10.0")
+ def getModule(fullname: Name): ModuleSymbol =
+ getModuleByName(fullname)
+
+ def getModuleByName(fullname: Name): ModuleSymbol =
+ ensureModuleSymbol(fullname.toString, getModuleOrClass(fullname.toTermName), allowPackages = true)
+
+ def getRequiredModule(fullname: String): ModuleSymbol =
+ getModule(newTermNameCached(fullname))
// TODO: What syntax do we think should work here? Say you have an object
// like scala.Predef. You can't say requiredModule[scala.Predef] since there's
@@ -121,34 +142,60 @@ trait Mirrors extends api.Mirrors {
def requiredModule[T: ClassTag] : ModuleSymbol =
getRequiredModule(erasureName[T] stripSuffix "$")
- def getClassIfDefined(fullname: String): Symbol =
- getClassIfDefined(newTypeName(fullname))
-
- def getClassIfDefined(fullname: Name): Symbol =
- wrapMissing(getClassByName(fullname.toTypeName))
-
def getModuleIfDefined(fullname: String): Symbol =
- getModuleIfDefined(newTermName(fullname))
+ getModuleIfDefined(newTermNameCached(fullname))
def getModuleIfDefined(fullname: Name): Symbol =
wrapMissing(getModule(fullname.toTermName))
+ /** @inheritdoc
+ *
+ * Unlike getModule/getRequiredModule this function can also load packageless symbols.
+ * Compiler might ignore them, but they should be loadable with macros.
+ */
+ override def staticModule(fullname: String): ModuleSymbol =
+ ensureModuleSymbol(fullname, staticModuleOrClass(newTermNameCached(fullname)), allowPackages = false)
+
+ /************************ loaders of package symbols ************************/
+
+ private def ensurePackageSymbol(fullname: String, sym: Symbol, allowModules: Boolean): ModuleSymbol =
+ sym match {
+ case x: ModuleSymbol if allowModules || x.isPackage => x
+ case _ => MissingRequirementError.notFound("package " + fullname)
+ }
+
+ def getPackage(fullname: Name): ModuleSymbol =
+ ensurePackageSymbol(fullname.toString, getModuleOrClass(fullname), allowModules = true)
+
+ def getRequiredPackage(fullname: String): ModuleSymbol =
+ getPackage(newTermNameCached(fullname))
+
def getPackageObject(fullname: String): ModuleSymbol =
- (getModule(newTermName(fullname)).info member nme.PACKAGE) match {
+ (getPackage(newTermName(fullname)).info member nme.PACKAGE) match {
case x: ModuleSymbol => x
case _ => MissingRequirementError.notFound("package object " + fullname)
}
- def getPackageObjectIfDefined(fullname: String): Symbol = {
- val module = getModuleIfDefined(newTermName(fullname))
- if (module == NoSymbol) NoSymbol
- else {
- val packageObject = module.info member nme.PACKAGE
- packageObject match {
- case x: ModuleSymbol => x
- case _ => NoSymbol
- }
+ def getPackageObjectIfDefined(fullname: String): Symbol =
+ getPackageObjectIfDefined(newTermNameCached(fullname))
+
+ def getPackageObjectIfDefined(fullname: Name): Symbol =
+ wrapMissing(getPackageObject(fullname.toTermName))
+
+ override def staticPackage(fullname: String): ModuleSymbol =
+ ensurePackageSymbol(fullname.toString, getModuleOrClass(newTermNameCached(fullname)), allowModules = false)
+
+ /************************ helpers ************************/
+
+ def erasureName[T: ClassTag] : String = {
+ /** We'd like the String representation to be a valid
+ * scala type, so we have to decode the jvm's secret language.
+ */
+ def erasureString(clazz: Class[_]): String = {
+ if (clazz.isArray) "Array[" + erasureString(clazz.getComponentType) + "]"
+ else clazz.getName
}
+ erasureString(classTag[T].runtimeClass)
}
@inline private def wrapMissing(body: => Symbol): Symbol =
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index c8a2424118..75962ff9d0 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -246,6 +246,7 @@ trait StdNames {
final val BeanPropertyAnnot: NameType = "BeanProperty"
final val BooleanBeanPropertyAnnot: NameType = "BooleanBeanProperty"
final val bridgeAnnot: NameType = "bridge"
+ final val staticAnnot: NameType = "static"
// Classfile Attributes
final val AnnotationDefaultATTR: NameType = "AnnotationDefault"
@@ -754,6 +755,7 @@ trait StdNames {
val splice: NameType = "splice"
val staticClass : NameType = "staticClass"
val staticModule : NameType = "staticModule"
+ val staticPackage : NameType = "staticPackage"
val synchronized_ : NameType = "synchronized"
val tail: NameType = "tail"
val `then` : NameType = "then"
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index d484617767..10d02376b1 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -933,6 +933,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
|| hasAnnotation(SerializableAttr) // last part can be removed, @serializable annotation is deprecated
)
def hasBridgeAnnotation = hasAnnotation(BridgeClass)
+ def hasStaticAnnotation = hasAnnotation(StaticClass)
def isDeprecated = hasAnnotation(DeprecatedAttr)
def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0)
def deprecationVersion = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 1)
diff --git a/src/reflect/scala/reflect/internal/util/SourceFile.scala b/src/reflect/scala/reflect/internal/util/SourceFile.scala
index 7c80ddd37d..df4a3336c3 100644
--- a/src/reflect/scala/reflect/internal/util/SourceFile.scala
+++ b/src/reflect/scala/reflect/internal/util/SourceFile.scala
@@ -102,17 +102,21 @@ class ScriptSourceFile(underlying: BatchSourceFile, content: Array[Char], overri
}
/** a file whose contents do not change over time */
-class BatchSourceFile(val file : AbstractFile, val content: Array[Char]) extends SourceFile {
-
+class BatchSourceFile(val file : AbstractFile, val content0: Array[Char]) extends SourceFile {
def this(_file: AbstractFile) = this(_file, _file.toCharArray)
def this(sourceName: String, cs: Seq[Char]) = this(new VirtualFile(sourceName), cs.toArray)
def this(file: AbstractFile, cs: Seq[Char]) = this(file, cs.toArray)
- override def equals(that : Any) = that match {
- case that : BatchSourceFile => file.path == that.file.path && start == that.start
- case _ => false
- }
- override def hashCode = file.path.## + start.##
+ // If non-whitespace tokens run all the way up to EOF,
+ // positions go wrong because the correct end of the last
+ // token cannot be used as an index into the char array.
+ // The least painful way to address this was to add a
+ // newline to the array.
+ val content = (
+ if (content0.length == 0 || !content0.last.isWhitespace)
+ content0 :+ '\n'
+ else content0
+ )
val length = content.length
def start = 0
def isSelfContained = true
@@ -158,4 +162,10 @@ class BatchSourceFile(val file : AbstractFile, val content: Array[Char]) extends
lastLine = findLine(0, lines.length, lastLine)
lastLine
}
+
+ override def equals(that : Any) = that match {
+ case that : BatchSourceFile => file.path == that.file.path && start == that.start
+ case _ => false
+ }
+ override def hashCode = file.path.## + start.##
}
diff --git a/src/reflect/scala/reflect/makro/Context.scala b/src/reflect/scala/reflect/makro/Context.scala
index f9858a063c..f093016a38 100644
--- a/src/reflect/scala/reflect/makro/Context.scala
+++ b/src/reflect/scala/reflect/makro/Context.scala
@@ -33,8 +33,4 @@ trait Context extends Aliases
/** The prefix tree from which the macro is selected */
val prefix: Expr[PrefixType]
-
- /** Alias to the underlying mirror's reify */
- // implementation is magically hardwired to `scala.reflect.makro.runtime.ContextReifiers`
- def reify[T](expr: T): Expr[T] = macro ???
}
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 9f9f79058d..0878801715 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -72,6 +72,18 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
override def complete(sym: Symbol) = sym setInfo new LazyPackageType
}
+ // reflective mirrors can't know the exhaustive list of available packages
+ // (that's because compiler mirrors are based on directories and reflective mirrors are based on classloaders,
+ // and unlike directories classloaders might make up stuff on the fly)
+ // hence we need to be optimistic and create packages out of thin air
+ // the same thing is done by the `missingHook` below
+ override def staticPackage(fullname: String): ModuleSymbol =
+ try super.staticPackage(fullname)
+ catch {
+ case _: MissingRequirementError =>
+ makeScalaPackage(fullname)
+ }
+
// ----------- Caching ------------------------------------------------------------------
// [Eugene++ to Martin] not weak? why?
diff --git a/src/reflect/scala/tools/nsc/io/VirtualFile.scala b/src/reflect/scala/tools/nsc/io/VirtualFile.scala
index b9a946598c..805bc04165 100644
--- a/src/reflect/scala/tools/nsc/io/VirtualFile.scala
+++ b/src/reflect/scala/tools/nsc/io/VirtualFile.scala
@@ -55,7 +55,7 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF
}
}
- def container: AbstractFile = unsupported
+ def container: AbstractFile = NoAbstractFile
/** Is this abstract file a directory? */
def isDirectory: Boolean = false