diff options
-rw-r--r-- | build.xml | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/ant/Scaladoc.scala | 9 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ScalaDoc.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/DocFactory.scala | 112 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/DocParser.scala | 74 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/Settings.scala | 15 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/SourcelessComments.scala | 216 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/Uncompilable.scala | 48 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/html/page/Template.scala | 12 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala | 36 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/settings/ScalaSettings.scala | 1 | ||||
-rw-r--r-- | src/library-aux/README | 3 | ||||
-rw-r--r-- | src/library-aux/scala/Any.scala | 105 | ||||
-rw-r--r-- | src/library-aux/scala/AnyRef.scala | 129 | ||||
-rw-r--r-- | src/library-aux/scala/Nothing.scala | 23 | ||||
-rw-r--r-- | src/library-aux/scala/Null.scala | 17 | ||||
-rw-r--r-- | src/scalap/scala/tools/scalap/Main.scala | 30 |
18 files changed, 525 insertions, 311 deletions
@@ -1408,6 +1408,7 @@ DOCUMENTATION doctitle="Scala Standard Library" docversion="${version.number}" docsourceurl="https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/€{FILE_PATH}.scala#L1" + docUncompilable="${src.dir}/library-aux" sourcepath="${src.dir}" classpathref="pack.classpath"> <src> diff --git a/src/compiler/scala/tools/ant/Scaladoc.scala b/src/compiler/scala/tools/ant/Scaladoc.scala index 727b8db0cc..419f60af21 100644 --- a/src/compiler/scala/tools/ant/Scaladoc.scala +++ b/src/compiler/scala/tools/ant/Scaladoc.scala @@ -112,6 +112,9 @@ class Scaladoc extends ScalaMatchingTask { /** Instruct the compiler to generate links to sources */ private var docsourceurl: Option[String] = None + /** Point scaladoc at uncompilable sources. */ + private var docUncompilable: Option[String] = None + /** Instruct the compiler to use additional parameters */ private var addParams: String = "" @@ -331,6 +334,10 @@ class Scaladoc extends ScalaMatchingTask { buildError("Unknown unchecked flag '" + input + "'") } + def setDocUncompilable(input: String) { + docUncompilable = Some(input) + } + /*============================================================================*\ ** Properties getters ** \*============================================================================*/ @@ -518,6 +525,8 @@ class Scaladoc extends ScalaMatchingTask { if (!doctitle.isEmpty) docSettings.doctitle.value = decodeEscapes(doctitle.get) if (!docversion.isEmpty) docSettings.docversion.value = decodeEscapes(docversion.get) if (!docsourceurl.isEmpty) docSettings.docsourceurl.value =decodeEscapes(docsourceurl.get) + if (!docUncompilable.isEmpty) docSettings.docUncompilable.value = decodeEscapes(docUncompilable.get) + docSettings.deprecation.value = deprecation docSettings.unchecked.value = unchecked if (!docgenerator.isEmpty) docSettings.docgenerator.value = docgenerator.get diff --git a/src/compiler/scala/tools/nsc/ScalaDoc.scala b/src/compiler/scala/tools/nsc/ScalaDoc.scala index da31ca833d..a9330b053b 100644 --- a/src/compiler/scala/tools/nsc/ScalaDoc.scala +++ b/src/compiler/scala/tools/nsc/ScalaDoc.scala @@ -27,6 +27,7 @@ class ScalaDoc { override def hasErrors = false } val command = new ScalaDoc.Command(args.toList, docSettings) + def hasFiles = command.files.nonEmpty || docSettings.uncompilableFiles.nonEmpty if (docSettings.version.value) reporter.info(null, versionMsg, true) @@ -38,7 +39,7 @@ class ScalaDoc { reporter.warning(null, "Plugins are not available when using Scaladoc") else if (docSettings.showPhases.value) reporter.warning(null, "Phases are restricted when using Scaladoc") - else if (docSettings.help.value || command.files.isEmpty) + else if (docSettings.help.value || !hasFiles) reporter.info(null, command.usageMsg, true) else try { if (docSettings.target.value == "msil") diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala index c8a6e279ff..71ee6dfcb8 100644 --- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala @@ -3,9 +3,11 @@ package scala.tools.nsc package doc +import scala.util.control.ControlThrowable import reporters.Reporter -import java.lang.ClassNotFoundException -import util.{Position, NoPosition} +import util.NoPosition +import io.{ File, Directory } +import DocParser.Parsed /** A documentation processor controls the process of generating Scala documentation, which is as follows. * @@ -25,7 +27,6 @@ import util.{Position, NoPosition} * * @author Gilles Dubochet */ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor => - /** The unique compiler instance used by this processor and constructed from its `settings`. */ object compiler extends Global(settings, reporter) with interactive.RangePositions { override protected def computeInternalPhases() { @@ -38,64 +39,89 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor phasesSet += refchecks } override def forScaladoc = true - lazy val addSourceless = { - val sless = new SourcelessComments { val global = compiler } - docComments ++= sless.comments - } } /** Creates a scaladoc site for all symbols defined in this call's `files`, as well as those defined in `files` of * previous calls to the same processor. * @param files The list of paths (relative to the compiler's source path, or absolute) of files to document. */ def makeUniverse(files: List[String]): Option[Universe] = { - (new compiler.Run()) compile files - compiler.addSourceless assert(settings.docformat.value == "html") - if (!reporter.hasErrors) { - val modelFactory = (new model.ModelFactory(compiler, settings) with model.comment.CommentFactory with model.TreeFactory) - modelFactory.makeModel match { - case Some(madeModel) => - println("model contains " + modelFactory.templatesCount + " documentable templates") - Some(madeModel) - case None => - println("no documentable class found in compilation units") - None + new compiler.Run() compile files + if (reporter.hasErrors) + return None + + val extraTemplatesToDocument: Set[compiler.Symbol] = { + if (settings.docUncompilable.isDefault) Set() + else { + val uncompilable = new { + val global: compiler.type = compiler + val settings = processor.settings + } with Uncompilable { } + + compiler.docComments ++= uncompilable.comments + docdbg("" + uncompilable) + + uncompilable.templates } } - else None + + val modelFactory = ( + new { override val global: compiler.type = compiler } + with model.ModelFactory(compiler, settings) + with model.comment.CommentFactory + with model.TreeFactory { + override def templateShouldDocument(sym: compiler.Symbol) = + extraTemplatesToDocument(sym) || super.templateShouldDocument(sym) + } + ) + + modelFactory.makeModel match { + case Some(madeModel) => + println("model contains " + modelFactory.templatesCount + " documentable templates") + Some(madeModel) + case None => + println("no documentable class found in compilation units") + None + } + + } + + object NoCompilerRunException extends ControlThrowable { } + + val documentError: PartialFunction[Throwable, Unit] = { + case NoCompilerRunException => + reporter.info(NoPosition, "No documentation generated with unsucessful compiler run", false) + case _: ClassNotFoundException => + () } /** Generate document(s) for all `files` containing scaladoc documenataion. * @param files The list of paths (relative to the compiler's source path, or absolute) of files to document. */ def document(files: List[String]): Unit = { + def generate() = { + import doclet._ + val docletClass = Class.forName(settings.docgenerator.value) // default is html.Doclet + val docletInstance = docletClass.newInstance().asInstanceOf[Generator] - class NoCompilerRunException extends Exception - - try { - val docletClass = Class.forName(settings.docgenerator.value) // default is html.Doclet - val docletInstance = docletClass.newInstance().asInstanceOf[doclet.Generator] - if (docletInstance.isInstanceOf[doclet.Universer]) { - makeUniverse(files) match { - case Some(universe) => - docletClass.getMethod("setUniverse", classOf[Universe]).invoke(docletInstance, universe) - if (docletInstance.isInstanceOf[doclet.Indexer]) { - val index = model.IndexModelFactory.makeIndex(universe) - docletClass.getMethod("setIndex", classOf[Index]).invoke(docletInstance, index) - } - case None => - throw new NoCompilerRunException() - } + docletInstance match { + case universer: Universer => + val universe = makeUniverse(files) getOrElse { throw NoCompilerRunException } + universer setUniverse universe + + docletInstance match { + case indexer: Indexer => indexer setIndex model.IndexModelFactory.makeIndex(universe) + case _ => () + } + case _ => () } docletInstance.generate } - catch { - case e: ClassNotFoundException => - case e: NoCompilerRunException => - reporter.info(NoPosition, "No documentation generated with unsucessful compiler run", false) - } - - + try generate() + catch documentError + } + private[doc] def docdbg(msg: String) { + if (settings.Ydocdebug.value) + println(msg) } - } diff --git a/src/compiler/scala/tools/nsc/doc/DocParser.scala b/src/compiler/scala/tools/nsc/doc/DocParser.scala new file mode 100644 index 0000000000..1e45079c48 --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/DocParser.scala @@ -0,0 +1,74 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools +package nsc +package doc + +import reporters._ +import util._ +import interactive.RangePositions +import DocParser.Parsed + +/** A very minimal global customized for extracting DocDefs. It stops + * right after parsing so it can read DocDefs from source code which would + * otherwise cause the compiler to go haywire. + */ +class DocParser(settings: nsc.Settings, reporter: Reporter) + extends Global(settings, reporter) + with RangePositions { + + def this(settings: Settings) = this(settings, new ConsoleReporter(settings)) + def this() = this(new Settings(Console println _)) + + // the usual global initialization + locally { new Run() } + + override def forScaladoc = true + override protected def computeInternalPhases() { + phasesSet += syntaxAnalyzer + } + + /** Returns a list of DocParser.Parseds, which hold the DocDefs found in the + * given code along with the surrounding trees. + */ + def docDefs(code: String) = { + def loop(enclosing: List[Tree], tree: Tree): List[Parsed] = tree match { + case x: PackageDef => x.stats flatMap (t => loop(enclosing :+ x, t)) + case x: DocDef => new Parsed(enclosing, x) :: loop(enclosing :+ x.definition, x.definition) + case x => x.children flatMap (t => loop(enclosing, t)) + } + loop(Nil, docUnit(code)) + } + + /** A compilation unit containing parsed source. + */ + def docUnit(code: String) = { + val unit = new CompilationUnit(new BatchSourceFile("<console>", code)) + val scanner = new syntaxAnalyzer.UnitParser(unit) + + scanner.compilationUnit() + } +} + +/** Since the DocParser's whole reason for existing involves trashing a + * global, it is designed to bottle up general Global#Tree types rather + * than path dependent ones. The recipient will have to deal. + */ +object DocParser { + type Tree = Global#Tree + type DefTree = Global#DefTree + type DocDef = Global#DocDef + type Name = Global#Name + + class Parsed(val enclosing: List[Tree], val docDef: DocDef) { + def nameChain: List[Name] = (enclosing :+ docDef.definition) collect { case x: DefTree => x.name } + def raw: String = docDef.comment.raw + + override def toString = ( + nameChain.init.map(x => if (x.isTypeName) x + "#" else x + ".").mkString + nameChain.last + ) + } +} diff --git a/src/compiler/scala/tools/nsc/doc/Settings.scala b/src/compiler/scala/tools/nsc/doc/Settings.scala index bcbdd64e62..292eca91e3 100644 --- a/src/compiler/scala/tools/nsc/doc/Settings.scala +++ b/src/compiler/scala/tools/nsc/doc/Settings.scala @@ -41,6 +41,17 @@ class Settings(error: String => Unit) extends scala.tools.nsc.Settings(error) { "" ) + val docUncompilable = StringSetting ( + "-doc-no-compile", + "path", + "A directory containing sources which should be parsed, no more (e.g. AnyRef.scala)", + "" + ) + lazy val uncompilableFiles = docUncompilable.value match { + case "" => Nil + case path => io.Directory(path).deepFiles filter (_ hasExtension "scala") toList + } + /** A setting that defines a URL to be concatenated with source locations and show a link to source files. * If needed the sourcepath option can be used to exclude undesired initial part of the link to sources */ val docsourceurl = StringSetting ( @@ -62,8 +73,6 @@ class Settings(error: String => Unit) extends scala.tools.nsc.Settings(error) { "scala.tools.nsc.doc.html.Doclet" ) - // TODO: add a new setting for whether or not to document sourceless entities (e.g., Any, Unit, etc) - // 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. @@ -71,7 +80,7 @@ class Settings(error: String => Unit) extends scala.tools.nsc.Settings(error) { // For improved help output. def scaladocSpecific = Set[Settings#Setting]( - docformat, doctitle, docversion, docsourceurl, docgenerator + docformat, doctitle, docversion, docUncompilable, docsourceurl, docgenerator ) val isScaladocSpecific: String => Boolean = scaladocSpecific map (_.name) } diff --git a/src/compiler/scala/tools/nsc/doc/SourcelessComments.scala b/src/compiler/scala/tools/nsc/doc/SourcelessComments.scala deleted file mode 100644 index 6b6886a599..0000000000 --- a/src/compiler/scala/tools/nsc/doc/SourcelessComments.scala +++ /dev/null @@ -1,216 +0,0 @@ -/* NSC -- new Scala compiler -- Copyright 2007-2011 LAMP/EPFL */ - -package scala.tools.nsc -package doc - -import scala.collection._ - -/** - * A class that provides comments for all symbols which pre-exist in Scala (Any, Nothing, ...) - * It also contains a HashSet of the given symbols - * The comments are to be added to a HashMap called comments, which resides in the Global.scala file - * @author Manohar Jonnalagedda, Stephane Micheloud, Sean McDirmid, Geoffrey Washburn - * @version 1.0 */ -abstract class SourcelessComments { - - val global: Global - - import global._ - import definitions._ - - lazy val comments = { - - val comment = mutable.HashMap.empty[Symbol, DocComment] - - comment(NothingClass) = new DocComment(""" - /** Class `Nothing` is - together with class [[scala.Null]] - at the bottom of Scala's type hierarchy. - * - * Type `Nothing` is a subtype of every other type (including [[scala.Null]]); there exist ''no instances'' of - * this type. Even though type `Nothing` is empty, it is nevertheless useful as a type parameter. For instance, - * the Scala library defines a value [[scala.collection.immutable.Nil]] of type `List[Nothing]`. Because lists - * are covariant in Scala, this makes [[scala.collection.immutable.Nil]] an instance of `List[T]`, for any - * element of type `T`. */ - """) - - comment(NullClass) = new DocComment(""" - /** Class `Null` is - together with class [[scala.Nothing]] - at the bottom of the Scala type hierarchy. - * - * Type `Null` is a subtype of all reference types; its only instance is the `null` reference. Since `Null` is - * not a subtype of value types, `null` is not a member of any such type. For instance, it is not possible to - * assign `null` to a variable of type [[scala.Int]]. */ - """) - - /*******************************************************************/ - /* Documentation for Any */ - - comment(AnyClass) = new DocComment(""" - /** Class `Any` is the root of the Scala class hierarchy. Every class in a Scala execution environment inherits - * directly or indirectly from this class. Class `Any` has two direct subclasses: [[scala.AnyRef]] and - * [[scala.AnyVal]]. */ - """) - - comment(Any_equals) = new DocComment(""" - /** This method is used to compare the receiver object (`this`) with the argument object (`arg0`) for equivalence. - * - * The default implementations of this method is an [[http://en.wikipedia.org/wiki/Equivalence_relation equivalence - * relation]]: - * - It is reflexive: for any instance `x` of type `Any`, `x.equals(x)` should return `true`. - * - It is symmetric: for any instances `x` and `y` of type `Any`, `x.equals(y)` should return `true` if and - * only if `y.equals(x)` returns `true`. - * - It is transitive: for any instances `x`, `y`, and `z` of type `AnyRef` if `x.equals(y)` returns `true` and - * `y.equals(z)` returns `true`, then `x.equals(z)` should return `true`. - * - * If you override this method, you should verify that your implementation remains an equivalence relation. - * Additionally, when overriding this method it is often necessary to override `hashCode` to ensure that objects - * that are "equal" (`o1.equals(o2)` returns `true`) hash to the same [[scala.Int]] - * (`o1.hashCode.equals(o2.hashCode)`). - * - * @param arg0 the object to compare against this object for equality. - * @return `true` if the receiver object is equivalent to the argument; `false` otherwise. */ - """) - - comment(Any_==) = new DocComment(""" - /** `o == arg0` is the same as `o.equals(arg0)`. - * - * @param arg0 the object to compare against this object for equality. - * @return `true` if the receiver object is equivalent to the argument; `false` otherwise. */ - """) - - comment(Any_!=) = new DocComment(""" - /** `o != arg0` is the same as `!(o == (arg0))`. - * - * @param arg0 the object to compare against this object for dis-equality. - * @return `false` if the receiver object is equivalent to the argument; `true` otherwise. */ - """) - - comment(Any_toString) = new DocComment(""" - /** Returns a string representation of the object. - * - * The default representation is platform dependent. - * - * @return a string representation of the object. */ - """) - - comment(Any_asInstanceOf) = new DocComment(""" - /** This method is used to cast the receiver object to be of type `T0`. - * - * Note that the success of a cast at runtime is modulo Scala's erasure semantics. Therefore the expression - * `1.asInstanceOf[String]` will throw a `ClassCastException` at runtime, while the expression - * `List(1).asInstanceOf[List[String]]` will not. In the latter example, because the type argument is erased as - * part of compilation it is not possible to check whether the contents of the list are of the requested typed. - * - * @throws ClassCastException if the receiver object is not an instance of erasure of type `T0`. - * @return the receiver object. */ - """) - - comment(Any_isInstanceOf) = new DocComment(""" - /** This method is used to test whether the dynamic type of the receiver object is `T0`. - * - * Note that the test result of the test is modulo Scala's erasure semantics. Therefore the expression - * `1.isInstanceOf[String]` will return `false`, while the expression `List(1).isInstanceOf[List[String]]` will - * return `true`. In the latter example, because the type argument is erased as part of compilation it is not - * possible to check whether the contents of the list are of the requested typed. - * - * @return `true` if the receiver object is an instance of erasure of type `T0`; `false` otherwise. */ - """) - - comment(Any_hashCode) = new DocComment(""" - /** Returns a hash code value for the object. - * - * The default hashing algorithm is platform dependent. - * - * Note that it is allowed for two objects to have identical hash codes (`o1.hashCode.equals(o2.hashCode)`) yet - * not be equal (`o1.equals(o2)` returns `false`). A degenerate implementation could always return `0`. - * However, it is required that if two objects are equal (`o1.equals(o2)` returns `true`) that they have - * identical hash codes (`o1.hashCode.equals(o2.hashCode)`). Therefore, when overriding this method, be sure - * to verify that the behavior is consistent with the `equals` method. - * - * @return the hash code value for the object. */ - """) - - /*******************************************************************/ - /* Documentation for AnyRef */ - - comment(AnyRefClass) = new DocComment(""" - /** Class `AnyRef` is the root class of all ''reference types''. */ - """) - - comment(Object_==) = new DocComment(""" - /** `o == arg0` is the same as `if (o eq null) arg0 eq null else o.equals(arg0)`. - * - * @param arg0 the object to compare against this object for equality. - * @return `true` if the receiver object is equivalent to the argument; `false` otherwise. */ - """) - - comment(Object_ne) = new DocComment(""" - /** `o.ne(arg0)` is the same as `!(o.eq(arg0))`. - * - * @param arg0 the object to compare against this object for reference dis-equality. - * @return `false` if the argument is not a reference to the receiver object; `true` otherwise. */ - """) - - - comment(Object_finalize) = new DocComment(""" - /** This method is called by the garbage collector on the receiver object when garbage collection determines that - * there are no more references to the object. - * - * The details of when and if the `finalize` method are invoked, as well as the interaction between `finalize` - * and non-local returns and exceptions, are all platform dependent. */ - """) - - comment(Object_clone) = new DocComment(""" - /** This method creates and returns a copy of the receiver object. - * - * The default implementation of the `clone` method is platform dependent. - * - * @return a copy of the receiver object. */ - """) - - comment(Object_getClass) = new DocComment(""" - /** Returns a representation that corresponds to the dynamic class of the receiver object. - * - * The nature of the representation is platform dependent. - * - * @return a representation that corresponds to the dynamic class of the receiver object. */ - """) - - comment(Object_notify) = new DocComment(""" - /** Wakes up a single thread that is waiting on the receiver object's monitor. */ - """) - - comment(Object_notifyAll) = new DocComment(""" - /** Wakes up all threads that are waiting on the receiver object's monitor. */ - """) - - comment(Object_eq) = new DocComment(""" - /** This method is used to test whether the argument (`arg0`) is a reference to the - * receiver object (`this`). - * - * The `eq` method implements an [[http://en.wikipedia.org/wiki/Equivalence_relation equivalence relation]] on - * non-null instances of `AnyRef`: - * - It is reflexive: for any non-null instance `x` of type `AnyRef`, `x.eq(x)` returns `true`. - * - It is symmetric: for any non-null instances `x` and `y` of type `AnyRef`, `x.eq(y)` returns `true` if and - * only if `y.eq(x)` returns `true`. - * - It is transitive: for any non-null instances `x`, `y`, and `z` of type `AnyRef` if `x.eq(y)` returns `true` - * and `y.eq(z)` returns `true`, then `x.eq(z)` returns `true`. - * - * Additionally, the `eq` method has three other properties. - * - It is consistent: for any non-null instances `x` and `y` of type `AnyRef`, multiple invocations of - * `x.eq(y)` consistently returns `true` or consistently returns `false`. - * - For any non-null instance `x` of type `AnyRef`, `x.eq(null)` and `null.eq(x)` returns `false`. - * - `null.eq(null)` returns `true`. - * - * When overriding the `equals` or `hashCode` methods, it is important to ensure that their behavior is - * consistent with reference equality. Therefore, if two objects are references to each other (`o1 eq o2`), they - * should be equal to each other (`o1 == o2`) and they should hash to the same value (`o1.hashCode == o2.hashCode`). - * - * @param arg0 the object to compare against this object for reference equality. - * @return `true` if the argument is a reference to the receiver object; `false` otherwise. */ - """) - - /*******************************************************************/ - - comment - } - -} diff --git a/src/compiler/scala/tools/nsc/doc/Uncompilable.scala b/src/compiler/scala/tools/nsc/doc/Uncompilable.scala new file mode 100644 index 0000000000..1f0c85361e --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/Uncompilable.scala @@ -0,0 +1,48 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.nsc +package doc + +/** Some glue between DocParser (which reads source files which can't be compiled) + * and the scaladoc model. + */ +trait Uncompilable { + val global: Global + val settings: Settings + + import global.{ reporter, inform, warning, newTypeName, newTermName, Symbol, Name, DocComment } + import global.definitions.RootClass + + private implicit def translateName(name: Global#Name) = + if (name.isTypeName) newTypeName("" + name) else newTermName("" + name) + + def docSymbol(p: DocParser.Parsed) = p.nameChain.foldLeft(RootClass: Symbol)(_.tpe member _) + def docDefs(code: String) = new DocParser(settings, reporter) docDefs code + def docPairs(code: String) = docDefs(code) map (p => (docSymbol(p), new DocComment(p.raw))) + + lazy val pairs = files flatMap { f => + val comments = docPairs(f.slurp()) + if (settings.verbose.value) + inform("Found %d doc comments in parse-only file %s: %s".format(comments.size, f, comments.map(_._1).mkString(", "))) + + comments + } + def files = settings.uncompilableFiles + def symbols = pairs map (_._1) + def templates = symbols filter (x => x.isClass || x.isTrait) toSet + def comments = { + if (settings.debug.value || settings.verbose.value) + inform("Found %d uncompilable files: %s".format(files.size, files mkString ", ")) + + if (pairs.isEmpty) + warning("no doc comments read from " + settings.docUncompilable.value) + + pairs + } + override def toString = pairs.size + " uncompilable symbols:\n" + ( + symbols map (x => " " + x.owner.fullName + " " + x.defString) mkString "\n" + ) +} diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala index 33f81fef1c..f6dc58617e 100644 --- a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala @@ -8,7 +8,6 @@ package doc package html import model._ - import java.io.{ File => JFile } import io.{ Streamable, Directory } import scala.collection._ @@ -17,7 +16,6 @@ import scala.collection._ * @author David Bernard * @author Gilles Dubochet */ class HtmlFactory(val universe: doc.Universe, index: doc.Index) { - /** The character encoding to be used for generated Scaladoc sites. This value is currently always UTF-8. */ def encoding: String = "UTF-8" 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 88d3e61263..bc35e4835a 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -390,7 +390,7 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { val linearization = mbr match { - case dtpl: DocTemplateEntity if (isSelf && !isReduced && (!dtpl.linearizationTemplates.isEmpty || !dtpl.subClasses.isEmpty)) => + case dtpl: DocTemplateEntity if isSelf && !isReduced && (dtpl.linearizationTemplates.nonEmpty || dtpl.subClasses.nonEmpty) => val linearSupertypes: Seq[scala.xml.Node] = if (dtpl.linearizationTemplates.isEmpty) NodeSeq.Empty else { @@ -523,18 +523,18 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { } }{ if (isReduced) NodeSeq.Empty else { mbr match { - case tpl: DocTemplateEntity if (!tpl.isPackage) => - tpl.parentType match { - case Some(st) => <span class="result"> extends { typeToHtml(st, hasLinks) }</span> - case None =>NodeSeq.Empty - } + case tpl: DocTemplateEntity if tpl.parentType.isDefined => + <span class="result"> extends { typeToHtml(tpl.parentType.get, 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 => val b2s = boundsToHtml(abt.hi, abt.lo, hasLinks) if (b2s != NodeSeq.Empty) <span class="result">{ b2s }</span> else NodeSeq.Empty + case alt: AliasType => <span class="result"> = { typeToHtml(alt.alias, hasLinks) }</span> case _ => NodeSeq.Empty diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 4edfa83a0d..405da29a57 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -17,7 +17,7 @@ import model.{ RootPackage => RootPackageEntity } class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory: ModelFactory with CommentFactory with TreeFactory => import global._ - import definitions.{ ObjectClass, ScalaObjectClass, RootPackage, EmptyPackage, NothingClass, AnyClass, AnyRefClass } + import definitions.{ ObjectClass, ScalaObjectClass, RootPackage, EmptyPackage, NothingClass, AnyClass, AnyValClass, AnyRefClass } private var droppedPackages = 0 def templatesCount = templatesCache.size - droppedPackages @@ -25,6 +25,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory private var modelFinished = false private var universe: Universe = null + private lazy val noSubclassCache = Set(AnyClass, AnyRefClass, ObjectClass, ScalaObjectClass) + /** */ def makeModel: Option[Universe] = { val universe = new Universe { thisUniverse => @@ -160,6 +162,9 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory * * All non-package members (including other templates, as full templates). */ abstract class DocTemplateImpl(sym: Symbol, inTpl: => DocTemplateImpl) extends MemberImpl(sym, inTpl) with TemplateImpl with HigherKindedImpl with DocTemplateEntity { //if (inTpl != null) println("mbr " + sym + " in " + (inTpl.toRoot map (_.sym)).mkString(" > ")) + if (settings.verbose.value) + inform("Creating doc template for " + sym) + templatesCache += (sym -> this) lazy val definitionName = optimize(inDefinitionTemplates.head.qualifiedName + "." + name) override def toRoot: List[DocTemplateImpl] = this :: inTpl.toRoot @@ -192,33 +197,40 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory else None } def parentType = { - if (sym.isPackage) None else { + if (sym.isPackage || sym == AnyClass) None else { val tps = (sym.tpe.parents filter (_ != ScalaObjectClass.tpe)) map { _.asSeenFrom(sym.thisType, sym) } Some(makeType(RefinedType(tps, EmptyScope), inTpl)) } } val linearization: List[(TemplateEntity, TypeEntity)] = { - val acs = sym.ancestors filter { _ != ScalaObjectClass } - val tps = acs map { cls => makeType(sym.info.baseType(cls), this) } - val tpls = acs map { makeTemplate(_) } - tpls map { - case dtpl: DocTemplateImpl => dtpl.registerSubClass(this) - case _ => + val acs = sym.ancestors filterNot (_ == ScalaObjectClass) + val tps = acs map (cls => makeType(sym.info.baseType(cls), this)) + val tpls = acs map makeTemplate + + tpls foreach { + case dtpl: DocTemplateImpl => dtpl.registerSubClass(this) + case _ => } tpls zip tps } def linearizationTemplates = linearization map { _._1 } def linearizationTypes = linearization map { _._2 } - private lazy val subClassesCache = mutable.Buffer.empty[DocTemplateEntity] + + private lazy val subClassesCache = ( + if (noSubclassCache(sym)) null + else mutable.ListBuffer[DocTemplateEntity]() + ) def registerSubClass(sc: DocTemplateEntity): Unit = { - assert(subClassesCache != null) - subClassesCache += sc + if (subClassesCache != null) + subClassesCache += sc } - def subClasses = subClassesCache.toList + def subClasses = if (subClassesCache == null) Nil else subClassesCache.toList + protected lazy val memberSyms = // Only this class's constructors are part of its members, inherited constructors are not. sym.info.members.filter(s => localShouldDocument(s) && (!s.isConstructor || s.owner == sym)) + val members = memberSyms flatMap (makeMember(_, this)) val templates = members collect { case c: DocTemplateEntity => c } val methods = members collect { case d: Def => d } diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index f0d819538e..2de5ce82ce 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -146,6 +146,7 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings { val Yrepldebug = BooleanSetting ("-Yrepl-debug", "Trace all repl activity.") . withPostSetHook(set => interpreter.isReplDebug = true) val Ycompletion = BooleanSetting ("-Ycompletion-debug", "Trace all tab completion activity.") + val Ydocdebug = BooleanSetting ("-Ydoc-debug", "Trace all scaladoc activity.") val Ypmatnaive = BooleanSetting ("-Ypmat-naive", "Desugar matches as naively as possible.") val Ynotnull = BooleanSetting ("-Ynotnull", "Enable (experimental and incomplete) scala.NotNull.") val YdepMethTpes = BooleanSetting ("-Ydependent-method-types", "Allow dependent method types.") diff --git a/src/library-aux/README b/src/library-aux/README new file mode 100644 index 0000000000..e6dcd29277 --- /dev/null +++ b/src/library-aux/README @@ -0,0 +1,3 @@ +Source files under this directory cannot be compiled by normal means. + +They exist for bootstrapping and documentation purposes.
\ No newline at end of file diff --git a/src/library-aux/scala/Any.scala b/src/library-aux/scala/Any.scala new file mode 100644 index 0000000000..a97e5f050b --- /dev/null +++ b/src/library-aux/scala/Any.scala @@ -0,0 +1,105 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +/** Class `Any` is the root of the Scala class hierarchy. Every class in a Scala + * execution environment inherits directly or indirectly from this class. + */ +abstract class Any { + /** Compares the receiver object (`this`) with the argument object (`that`) for equivalence. + * + * The default implementations of this method is an [[http://en.wikipedia.org/wiki/Equivalence_relation equivalence relation]]: + * + * - It is reflexive: for any instance `x` of type `Any`, `x.equals(x)` should return `true`. + * - It is symmetric: for any instances `x` and `y` of type `Any`, `x.equals(y)` should return `true` if and + * only if `y.equals(x)` returns `true`. + * - It is transitive: for any instances `x`, `y`, and `z` of type `AnyRef` if `x.equals(y)` returns `true` and + * `y.equals(z)` returns `true`, then `x.equals(z)` should return `true`. + * + * If you override this method, you should verify that your implementation remains an equivalence relation. + * Additionally, when overriding this method it is usually necessary to override `hashCode` to ensure that + * objects which are "equal" (`o1.equals(o2)` returns `true`) hash to the same [[scala.Int]]. + * (`o1.hashCode.equals(o2.hashCode)`). + * + * @param that the object to compare against this object for equality. + * @return `true` if the receiver object is equivalent to the argument; `false` otherwise. + */ + def equals(that: Any): Boolean + + /** Calculate a hash code value for the object. + * + * The default hashing algorithm is platform dependent. + * + * Note that it is allowed for two objects to have identical hash codes (`o1.hashCode.equals(o2.hashCode)`) yet + * not be equal (`o1.equals(o2)` returns `false`). A degenerate implementation could always return `0`. + * However, it is required that if two objects are equal (`o1.equals(o2)` returns `true`) that they have + * identical hash codes (`o1.hashCode.equals(o2.hashCode)`). Therefore, when overriding this method, be sure + * to verify that the behavior is consistent with the `equals` method. + * + * @return the hash code value for this object. + */ + def hashCode: Int + + /** Returns a string representation of the object. + * + * The default representation is platform dependent. + * + * @return a string representation of the object. + */ + def toString: String + + /** Test two objects for equality. + * + * @param that the object to compare against this object for equality. + * @return `true` if the receiver object is equivalent to the argument; `false` otherwise. + */ + final def ==(that: Any): Boolean = this equals that + + /** Test two objects for inequality. + * + * @param that the object to compare against this object for equality. + * @return `true` if !(this == that), false otherwise. + */ + final def != (that: Any): Boolean = !(this == that) + + /** Equivalent to `x.hashCode` except for boxed numeric types. + * For numerics, it returns a hash value which is consistent + * with value equality: if two value type instances compare + * as true, then ## will produce the same hash value for each + * of them. + * + * @return a hash value consistent with == + */ + final def ## : Int = sys.error("##") + + /** Test whether the dynamic type of the receiver object is `T0`. + * + * Note that the result of the test is modulo Scala's erasure semantics. + * Therefore the expression `1.isInstanceOf[String]` will return `false`, while the + * expression `List(1).isInstanceOf[List[String]]` will return `true`. + * In the latter example, because the type argument is erased as part of compilation it is + * not possible to check whether the contents of the list are of the specified type. + * + * @return `true` if the receiver object is an instance of erasure of type `T0`; `false` otherwise. + */ + def isInstanceOf[T0]: Boolean = sys.error("isInstanceOf") + + /** Cast the receiver object to be of type `T0`. + * + * Note that the success of a cast at runtime is modulo Scala's erasure semantics. + * Therefore the expression `1.asInstanceOf[String]` will throw a `ClassCastException` at + * runtime, while the expression `List(1).asInstanceOf[List[String]]` will not. + * In the latter example, because the type argument is erased as part of compilation it is + * not possible to check whether the contents of the list are of the requested type. + * + * @throws ClassCastException if the receiver object is not an instance of the erasure of type `T0`. + * @return the receiver object. + */ + def asInstanceOf[T0]: T0 = sys.error("asInstanceOf") +} diff --git a/src/library-aux/scala/AnyRef.scala b/src/library-aux/scala/AnyRef.scala new file mode 100644 index 0000000000..6792ba68b7 --- /dev/null +++ b/src/library-aux/scala/AnyRef.scala @@ -0,0 +1,129 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +/** Class `AnyRef` is the root class of all ''reference types''. + * All types except the value types descend from this class. + */ +trait AnyRef extends Any { + + /** The equality method for reference types. See equals in [[scala.Any]]. + * + * @param that the object to compare against this object for equality. + * @return `true` if the receiver object is equivalent to the argument; `false` otherwise. + */ + def equals(that: Any): Boolean = this eq that + + /** The hashCode method for reference types. See hashCode in [[scala.Any]]. + * + * @return the hash code value for this object. + */ + def hashCode: Int = sys.error("hashCode") + + /** Creates a String representation of this object. The default + * representation is platform dependent. On the java platform it + * is the concatenation of the class name, "@", and the object's + * hashcode in hexadecimal. + * + * @return a String representation of the object. + */ + def toString: String = sys.error("toString") + + /** Executes the code in `body` with an exclusive lock on `this`. + * + * @param body the code to execute + * @return the result of `body` + */ + def synchronized[T](body: => T): T + + /** Tests whether the argument (`arg0`) is a reference to the receiver object (`this`). + * + * The `eq` method implements an [[http://en.wikipedia.org/wiki/Equivalence_relation equivalence relation]] on + * non-null instances of `AnyRef`, and has three additional properties: + * + * - It is consistent: for any non-null instances `x` and `y` of type `AnyRef`, multiple invocations of + * `x.eq(y)` consistently returns `true` or consistently returns `false`. + * - For any non-null instance `x` of type `AnyRef`, `x.eq(null)` and `null.eq(x)` returns `false`. + * - `null.eq(null)` returns `true`. + * + * When overriding the `equals` or `hashCode` methods, it is important to ensure that their behavior is + * consistent with reference equality. Therefore, if two objects are references to each other (`o1 eq o2`), they + * should be equal to each other (`o1 == o2`) and they should hash to the same value (`o1.hashCode == o2.hashCode`). + * + * @param that the object to compare against this object for reference equality. + * @return `true` if the argument is a reference to the receiver object; `false` otherwise. + */ + final def eq(that: AnyRef): Boolean = sys.error("eq") + + /** Equivalent to `!(this eq that)`. + * + * @param that the object to compare against this object for reference equality. + * @return `true` if the argument is not a reference to the receiver object; `false` otherwise. + */ + final def ne(that: AnyRef): Boolean = !(this eq that) + + /** The expression `x == that` is equivalent to `if (x eq null) that eq null else x.equals(that)`. + * + * @param arg0 the object to compare against this object for equality. + * @return `true` if the receiver object is equivalent to the argument; `false` otherwise. + */ + final def ==(that: AnyRef): Boolean = + if (this eq null) that eq null + else this equals that + + /** Create a copy of the receiver object. + * + * The default implementation of the `clone` method is platform dependent. + * + * @note not specified by SLS as a member of AnyRef + * @return a copy of the receiver object. + */ + protected def clone(): AnyRef + + /** Called by the garbage collector on the receiver object when there + * are no more references to the object. + * + * The details of when and if the `finalize` method is invoked, as + * well as the interaction between `finalize` and non-local returns + * and exceptions, are all platform dependent. + * + * @note not specified by SLS as a member of AnyRef + */ + protected def finalize(): Unit + + /** A representation that corresponds to the dynamic class of the receiver object. + * + * The nature of the representation is platform dependent. + * + * @note not specified by SLS as a member of AnyRef + * @return a representation that corresponds to the dynamic class of the receiver object. + */ + def getClass(): Class[_] + + /** Wakes up a single thread that is waiting on the receiver object's monitor. + * + * @note not specified by SLS as a member of AnyRef + */ + def notify(): Unit + + /** Wakes up all threads that are waiting on the receiver object's monitor. + * + * @note not specified by SLS as a member of AnyRef + */ + def notifyAll(): Unit + + /** Causes the current Thread to wait until another Thread invokes + * the notify() or notifyAll() methods. + * + * @note not specified by SLS as a member of AnyRef + */ + def wait (): Unit + def wait (timeout: Long, nanos: Int): Unit + def wait (timeout: Long): Unit +} diff --git a/src/library-aux/scala/Nothing.scala b/src/library-aux/scala/Nothing.scala new file mode 100644 index 0000000000..eed6066039 --- /dev/null +++ b/src/library-aux/scala/Nothing.scala @@ -0,0 +1,23 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +/** `Nothing` is - together with [[scala.Null]] - at the bottom of Scala's type hierarchy. + * + * `Nothing` is a subtype of every other type (including [[scala.Null]]); there exist + * ''no instances'' of this type. Although type `Nothing` is uninhabited, it is + * nevertheless useful in several ways. For instance, the Scala library defines a value + * [[scala.collection.immutable.Nil]] of type `List[Nothing]`. Because lists are covariant in Scala, + * this makes [[scala.collection.immutable.Nil]] an instance of `List[T]`, for any element of type `T`. + * + * Another usage for Nothing is the return type for methods which never return normally. + * One example is method error in [[scala.sys]], which always throws an exception. + */ +sealed trait Nothing + diff --git a/src/library-aux/scala/Null.scala b/src/library-aux/scala/Null.scala new file mode 100644 index 0000000000..7455e78ae7 --- /dev/null +++ b/src/library-aux/scala/Null.scala @@ -0,0 +1,17 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +/** `Null` is - together with [[scala.Nothing]] - at the bottom of the Scala type hierarchy. + * + * `Null` is a subtype of all reference types; its only instance is the `null` reference. + * Since `Null` is not a subtype of value types, `null` is not a member of any such type. For instance, + * it is not possible to assign `null` to a variable of type [[scala.Int]]. + */ +sealed trait Null diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala index 7546fd99ae..9ddb521a10 100644 --- a/src/scalap/scala/tools/scalap/Main.scala +++ b/src/scalap/scala/tools/scalap/Main.scala @@ -117,34 +117,8 @@ class Main { } // if the class corresponds to the artificial class scala.Any. // (see member list in class scala.tool.nsc.symtab.Definitions) - } else if (classname == "scala.Any") { - Console.println("package scala") - Console.println("class Any {") - Console.println(" final def ==(scala.Any): scala.Boolean") - Console.println(" final def !=(scala.Any): Boolean") - Console.println(" def equals(scala.Any): scala.Boolean") - Console.println(" def hashCode(): scala.Int") - Console.println(" def toString(): java.lang.String") - Console.println(" final def isInstanceOf[a]: scala.Boolean") - Console.println(" final def asInstanceOf[a]: a") - Console.println("}") - // if the class corresponds to the artificial class scala.AnyRef. - } else if (classname == "scala.AnyRef") { - Console.println("package scala") - Console.println("class AnyRef extends Any {") - Console.println(" def equals(scala.Any): scala.Boolean") - Console.println(" def hashCode(): scala.Int") - Console.println(" def toString(): java.lang.String") - Console.println("}") - // if the class corresponds to the artificial class scala.AnyVal. - } else if (classname == "scala.Nothing") { - Console.println("package scala") - Console.println("sealed abstract class Nothing") - // if the class corresponds to the artificial class scala.Null. - } else if (classname == "scala.Null") { - Console.println("package scala") - Console.println("sealed abstract class Null") - } else + } + else Console.println("class/object " + classname + " not found.") } |