summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-12-07 17:31:49 +0000
committerMartin Odersky <odersky@gmail.com>2009-12-07 17:31:49 +0000
commit1e88594f358d08b5e9b22ba87280003a581359e4 (patch)
treee68b6d1095ff1b1345e86d8a67c1f874849a31ff /src/compiler
parentde1d172a15e20ec7e96d96d5cea5cb41162b9f75 (diff)
downloadscala-1e88594f358d08b5e9b22ba87280003a581359e4.tar.gz
scala-1e88594f358d08b5e9b22ba87280003a581359e4.tar.bz2
scala-1e88594f358d08b5e9b22ba87280003a581359e4.zip
new doc comment generation, including some new ...
new doc comment generation, including some new style doc comments in collection classes.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala35
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/DocComments.scala365
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreePrinters.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala8
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala10
-rw-r--r--src/compiler/scala/tools/nsc/doc/DocFactory.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/SourcelessComments.scala94
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala5
-rw-r--r--src/compiler/scala/tools/nsc/reporters/Reporter.scala9
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolTable.scala3
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala11
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala63
-rw-r--r--src/compiler/scala/tools/nsc/util/Position.scala5
16 files changed, 514 insertions, 109 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 6b2f3101a6..645eb1ecf6 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -115,31 +115,6 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
val treeBrowser = treeBrowsers.create()
-
-// val copy = new LazyTreeCopier()
-
- /** A map of all doc comments, indexed by symbols.
- * Only active in onlyPresentation mode
- */
- val comments =
- if (onlyPresentation) new HashMap[Symbol,String]
- else null
-
- /** A map of all doc comments source file offsets,
- * indexed by symbols.
- * Only active in onlyPresentation mode
- */
- val commentOffsets =
- if (onlyPresentation) new HashMap[Symbol,Int]
- else null
-
- /** A map of argument names for methods
- * !!! can be dropped once named method arguments are in !!!
- */
- val methodArgumentNames =
- if (onlyPresentation) new HashMap[Symbol,List[List[Symbol]]]
- else null
-
// ------------ Hooks for interactive mode-------------------------
/** Called every time an AST node is succesfully typedchecked in typerPhase.
@@ -302,8 +277,8 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
val unit0 = currentRun.currentUnit
try {
currentRun.currentUnit = unit
- reporter.setSource(unit.source)
- if (!cancelled(unit)) apply(unit)
+ if (!cancelled(unit))
+ reporter.withSource(unit.source) { apply(unit) }
currentRun.advanceUnit
} finally {
//assert(currentRun.currentUnit == unit)
@@ -889,11 +864,11 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
var localPhase = firstPhase.asInstanceOf[GlobalPhase]
while (localPhase != null && (localPhase.id < globalPhase.id || localPhase.id <= namerPhase.id)/* && !reporter.hasErrors*/) {
val oldSource = reporter.getSource
- reporter.setSource(unit.source)
- atPhase(localPhase)(localPhase.applyPhase(unit))
+ reporter.withSource(unit.source) {
+ atPhase(localPhase)(localPhase.applyPhase(unit))
+ }
val newLocalPhase = localPhase.next.asInstanceOf[GlobalPhase]
localPhase = if (localPhase == newLocalPhase) null else newLocalPhase
- reporter.setSource(oldSource)
}
refreshProgress
}
diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala
new file mode 100755
index 0000000000..d754f12dee
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala
@@ -0,0 +1,365 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2009 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id: Unapplies.scala 19206 2009-10-21 20:57:27Z extempore $
+
+package scala.tools.nsc
+package ast
+
+import symtab._
+import util.{Position, NoPosition}
+import scala.collection.mutable.{HashMap, ListBuffer, StringBuilder}
+
+/*
+ * @author Martin Odersky
+ * @version 1.0
+ */
+trait DocComments { self: SymbolTable =>
+
+ val docComments = new HashMap[Symbol, DocComment] // !!! todo: inherit from comment?
+
+ private val defs = new HashMap[Symbol, Map[String, String]] {
+ override def default(key: Symbol) = Map()
+ }
+
+ def getDocComment(sym: Symbol): Option[DocComment] = {
+ docComments get sym match {
+ case None =>
+ mapFind(sym.allOverriddenSymbols)(docComments.get)
+ case someSym =>
+ someSym
+ }
+ }
+
+ private def mapFind[A, B](xs: Iterable[A])(f: A => Option[B]): Option[B] = {
+ var res: Option[B] = None
+ val it = xs.iterator
+ while (res.isEmpty && it.hasNext) {
+ res = f(it.next())
+ }
+ res
+ }
+
+ /** The raw doc comment of symbol `sym`, as it appears in the source text, "" if missing.
+ */
+ def rawDocComment(sym: Symbol): String = getDocComment(sym) map (_.raw) getOrElse ""
+
+ /** The processed doc comment of symbol `sym`, where
+ * Wiki syntax is expanded and @usecase or @define parts are removed.
+ * No variables are expanded yet. "" if missing.
+ */
+ def templateDocComment(sym: Symbol): String = getDocComment(sym) map (_.template) getOrElse ""
+
+ /** The cooked doc comment of symbol `sym` after variable expansion, or "" if missing.
+ * @param sym The symbol for which doc comment is returned
+ * @param site The class for which doc comments are generated
+ */
+ def cookedDocComment(sym: Symbol, site: Symbol): String =
+ getDocComment(sym) map (_.expanded(site)) getOrElse ""
+
+ /** The cooked doc comment of symbol `sym` after variable expansion, or "" if missing.
+ * @param sym The symbol for which doc comment is returned (site is always the containing class)
+ */
+ def cookedDocComment(sym: Symbol): String = cookedDocComment(sym, sym.owner)
+
+ /** The position of the doc comment of symbol `sym`, or NoPosition if missing */
+ def docCommentPos(sym: Symbol): Position = getDocComment(sym) map (_.pos) getOrElse NoPosition
+
+ def useCases(sym: Symbol, site: Symbol): List[(Symbol, String)] = {
+ def getUseCases(dc: DocComment) = {
+ for (uc <- dc.useCases; defn <- uc.expandedDefs(site)) yield
+ (defn, uc.comment.expanded(site))
+ }
+ getDocComment(sym) map getUseCases getOrElse List()
+ }
+
+ def useCases(sym: Symbol): List[(Symbol, String)] = useCases(sym, sym.owner)
+
+ private val usecasePrefix = "@usecase "
+ private val definePrefix = "@define "
+
+ /** Returns index of string `str` after `in` skipping longest
+ * sequence of space and tab characters.
+ */
+ private def skipWhitespace(str: String, in: Int): Int = {
+ var idx = in
+ do {
+ idx += 1
+ } while (idx < str.length && (str charAt idx) == ' ' || (str charAt idx) == '\t')
+ idx
+ }
+
+ /** Returns index of string `str` after `in` skipping longest
+ * sequence of space and tab characters, possibly also containing
+ * a single `*' character.
+ */
+ private def skipLineLead(str: String, in: Int, end: Int): Int = {
+ val idx = skipWhitespace(str, in)
+ if (idx < end && (str charAt idx) == '*') skipWhitespace(str, idx)
+ else idx
+ }
+
+ /** Extracts variable name from a string, stripping any pair of surrounding braces */
+ private def variableName(str: String): String =
+ if (str.length >= 2 && (str charAt 0) == '{' && (str charAt (str.length - 1)) == '}')
+ str.substring(1, str.length - 1)
+ else
+ str
+
+ private def isVarPart(ch: Char) =
+ '0' <= ch && ch <= '9' || 'A' <= ch && ch <= 'Z' || 'a' <= ch && ch <= 'z'
+
+ /** Returns index following variable, or start index if no variable was recognized
+ */
+ private def skipVariable(str: String, start: Int): Int = {
+ var idx = start
+ if (idx < str.length && (str charAt idx) == '{') {
+ do idx += 1
+ while (idx < str.length && (str charAt idx) != '}')
+ if (idx < str.length) idx + 1 else start
+ } else {
+ while (idx < str.length && isVarPart(str charAt idx))
+ idx += 1
+ idx
+ }
+ }
+
+ private val wikiReplacements = List(
+ ("""(\n\s*\*?)(\s*\n)""" .r, """$1 <p>$2"""),
+ ("""\{\{\{(.*(?:\n.*)*)\}\}\}""".r, """<pre>$1</pre>"""),
+ ("""`([^`]*)`""" .r, """<code>$1</code>"""),
+ ("""__([^_]*)__""" .r, """<u>$1</u>"""),
+ ("""''([^']*)''""" .r, """<i>$1</i>"""),
+ ("""'''([^']*)'''""" .r, """<b>$1</b>"""),
+ ("""\^([^^]*)\^""" .r, """<sup>$1</sup>"""),
+ (""",,([^,]*),,""" .r, """<sub>$1</sub>"""))
+ private def expandWiki(str: String): String =
+ (str /: wikiReplacements) { (str1, regexRepl) => regexRepl._1 replaceAllIn(str1, regexRepl._2) }
+
+ /** Lookup definition of variable.
+ *
+ * @param vble The variable for which a definition is searched
+ * @param owner The current owner in which variable definitions are searched.
+ * @param site The class for which doc comments are generated
+ */
+ def lookupVariable(vble: String, site: Symbol): Option[String] =
+ if (site == NoSymbol)
+ None
+ else
+ mapFind(site.info.baseClasses)(defs(_).get(vble)) match {
+ case None => lookupVariable(vble, site.owner)
+ case someStr => someStr
+ }
+
+ private var expandCount = 0
+ private final val expandLimit = 10
+
+ /** Expand variable occurrences in string `str', until a fix point is reached or
+ * a expandLimit is exceeded.
+ *
+ * @param str The string to be expanded
+ * @param site The class for which doc comments are generated
+ * @return Expanded string
+ */
+ private def expandVariables(str: String, site: Symbol): String =
+ if (expandCount < expandLimit) {
+ try {
+ val out = new StringBuilder
+ var start = 0
+ var idx = 0
+ while (idx < str.length) {
+ if ((str charAt idx) == '$') {
+ val vstart = idx
+ idx = skipVariable(str, idx + 1)
+ val vname = variableName(str.substring(vstart + 1, idx))
+ if (vname.length > 0) {
+ lookupVariable(vname, site) match {
+ case Some(replacement) =>
+ out append str.substring(start, vstart)
+ out append replacement
+ start = idx
+ case None =>
+ println("no replacement for "+vname) // !!!
+ }
+ } else {
+ idx += 1
+ }
+ } else {
+ idx += 1
+ }
+ }
+ if (out.length == 0) str
+ else {
+ out append str.substring(start)
+ expandVariables(out.toString, site)
+ }
+ } finally {
+ expandCount -= 1
+ }
+ } else throw new ExpansionLimitExceeded(str)
+
+ case class DocComment(raw: String, pos: Position = NoPosition) {
+
+ lazy val (template, defines, useCases) = {
+ val parts = decompose(raw)
+ val (defines, usecases) = parts.tail partition (_._1 startsWith definePrefix)
+ val templ = expandWiki(parts.head._1)
+ (templ,
+ defines map (d => expandWiki(d._1)),
+ usecases map (decomposeUseCase(_, templ)))
+ }
+
+ def expanded(site: Symbol): String =
+ expandVariables(template, site)
+/*
+ expansions get site match {
+ case Some(str) => str
+ case None => val str =
+ expandVariables(template, sym, site)
+ expansions += (site -> str)
+ str
+ }
+ private var expansions: Map[Symbol, String] = Map()
+*/
+
+
+ /** Decomposes a comment string into
+ * an initial comment and a list of @define and @usecase clauses, each with starting index
+ */
+ private def decompose(str: String): List[(String, Int)] = {
+ val out = new ListBuffer[(String, Int)]
+ var segstart = 0
+ var idx = 3 // skip initial "/**"
+ val end = str.length - 2 // stop before final "*/"
+ var eolIdx = idx
+ while (idx < end) {
+ if ((str charAt idx) == '\n') {
+ eolIdx = idx
+ idx = skipLineLead(str, idx, end)
+ if ((str charAt idx) == '@' &&
+ (str.startsWith(definePrefix, idx) || str.startsWith(usecasePrefix, idx))) {
+ var segment = str.substring(segstart, eolIdx)
+ if (segstart == 0) segment += "*/"
+ out += ((segment, segstart))
+ segstart = idx
+ }
+ } else idx += 1
+ }
+ if (segstart == 0)
+ List((str, 0))
+ else {
+ out += ((str.substring(segstart, eolIdx), segstart))
+ out.toList
+ }
+ }
+
+ def subPos(start: Int, end: Int) =
+ if (pos == NoPosition) NoPosition
+ else {
+ val start1 = pos.start + start
+ val end1 = pos.end + end
+ pos withStart start1 withPoint start1 withEnd end1
+ }
+
+ def decomposeUseCase(stroff: (String, Int), mainComment: String): UseCase = {
+ val str = stroff._1
+ val offset = stroff._2
+ val start = usecasePrefix.length
+ var idx = start
+ while (idx < str.length && (str charAt idx) != '\n') idx += 1
+ val code = str.substring(start, idx)
+ val codePos = subPos(offset + usecasePrefix.length, offset + idx)
+ var firstParBreak = mainComment indexOf "<p>"
+ if (firstParBreak == -1) firstParBreak = mainComment.length - 2
+ val comment = mainComment.substring(0, firstParBreak)+"<p>"+
+ str.substring(skipLineLead(str, idx, str.length))+"*/"
+ val commentPos = subPos(offset + idx, offset + str.length)
+ UseCase(DocComment(comment, commentPos), code, codePos)
+ }
+
+ def defineVariables(sym: Symbol) {
+ for (str <- defines) {
+ val start = definePrefix.length
+ var idx = skipVariable(str, start)
+ val vble = variableName(str.substring(start, idx))
+ if (idx < str.length && (str charAt idx) == ' ') idx += 1
+ defs(sym) += vble -> str.substring(idx)
+ }
+ if (defs(sym).nonEmpty) println("vars of "+sym+" = "+defs(sym)) // !!!
+ }
+ }
+
+ case class UseCase(comment: DocComment, body: String, pos: Position) {
+ var defined: List[Symbol] = List()
+ var aliases: List[Symbol] = List()
+
+ def expandedDefs(site: Symbol): List[Symbol] = {
+
+ def select(site: Type, name: Name, orElse: => Type): Type = {
+ val member = site.nonPrivateMember(name)
+ if (member.isTerm) SingleType(site, member)
+ else if (member.isType) site.memberType(member)
+ else orElse
+ }
+
+ def getSite(name: Name): Type = {
+ if (name == nme.this_) site.thisType
+ else {
+ def findIn(sites: List[Symbol]): Type = sites match {
+ case List() => NoType
+ case site :: sites1 => select(site.thisType, name, findIn(sites1))
+ }
+ val (classes, pkgs) = site.ownerChain.span(!_.isPackageClass)
+ findIn(classes ::: List(pkgs.head, definitions.RootClass))
+ }
+ }
+
+ def getType(str: String): Type = {
+ val parts = str.split("""\.""").toList
+ val partnames = (parts.init map newTermName) ::: List(newTypeName(parts.last))
+ (getSite(partnames.head) /: partnames.tail)(select(_, _, NoType))
+ }
+
+ val aliasExpansions: List[Type] =
+ for (alias <- aliases) yield
+ lookupVariable(alias.name.toString.substring(1), site) match {
+ case Some(repl) =>
+ val tpe = getType(repl)
+ if (tpe != NoType) tpe
+ else {
+ val alias1 = alias.cloneSymbol(definitions.RootClass)
+ alias1.name = repl.toTypeName
+ TypeRef(NoPrefix, alias1, List())
+ }
+ case None =>
+ TypeRef(NoPrefix, alias, List())
+ }
+
+ def subst(sym: Symbol, from: List[Symbol], to: List[Type]): Type =
+ if (from.isEmpty) sym.tpe
+ else if (from.head == sym) to.head
+ else subst(sym, from.tail, to.tail)
+
+ val substAliases = new TypeMap {
+ def apply(tp: Type) = mapOver(tp) match {
+ case tp1 @ TypeRef(pre, sym, args) if (sym.name.length > 1 && sym.name(0) == '$') =>
+ subst(sym, aliases, aliasExpansions) match {
+ case TypeRef(pre, sym1, _) =>
+ TypeRef(pre, sym1, args)
+ case _ =>
+ tp1
+ }
+ case tp1 =>
+ tp1
+ }
+ }
+
+ for (defn <- defined) yield
+ defn.cloneSymbol(site).setInfo(
+ substAliases(defn.info).asSeenFrom(site.thisType, defn.owner))
+ }
+ }
+
+ class ExpansionLimitExceeded(str: String) extends Exception
+}
diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
index d18ecbbd37..4ba5f17a40 100644
--- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
@@ -215,7 +215,7 @@ abstract class TreePrinters {
}
case DocDef(comment, definition) =>
- print(comment); println; print(definition)
+ print(comment.raw); println; print(definition)
case Template(parents, self, body) =>
val currentOwner1 = currentOwner
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 6c6311f143..3af729d4d7 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -570,7 +570,7 @@ trait Trees {
// It's used primarily as a marker to check that the import has been typechecked.
/** Documented definition, eliminated by analyzer */
- case class DocDef(comment: String, definition: Tree)
+ case class DocDef(comment: DocComment, definition: Tree)
extends Tree {
override def symbol: Symbol = definition.symbol
override def symbol_=(sym: Symbol) { definition.symbol = sym }
@@ -1072,7 +1072,7 @@ trait Trees {
def TypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree): TypeDef
def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree): LabelDef
def Import(tree: Tree, expr: Tree, selectors: List[ImportSelector]): Import
- def DocDef(tree: Tree, comment: String, definition: Tree): DocDef
+ def DocDef(tree: Tree, comment: DocComment, definition: Tree): DocDef
def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]): Template
def Block(tree: Tree, stats: List[Tree], expr: Tree): Block
def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree): CaseDef
@@ -1127,7 +1127,7 @@ trait Trees {
new LabelDef(name, params, rhs).copyAttrs(tree)
def Import(tree: Tree, expr: Tree, selectors: List[ImportSelector]) =
new Import(expr, selectors).copyAttrs(tree)
- def DocDef(tree: Tree, comment: String, definition: Tree) =
+ def DocDef(tree: Tree, comment: DocComment, definition: Tree) =
new DocDef(comment, definition).copyAttrs(tree)
def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]) =
new Template(parents, self, body).copyAttrs(tree)
@@ -1244,7 +1244,7 @@ trait Trees {
if (expr0 == expr) && (selectors0 == selectors) => t
case _ => treeCopy.Import(tree, expr, selectors)
}
- def DocDef(tree: Tree, comment: String, definition: Tree) = tree match {
+ def DocDef(tree: Tree, comment: DocComment, definition: Tree) = tree match {
case t @ DocDef(comment0, definition0)
if (comment0 == comment) && (definition0 == definition) => t
case _ => treeCopy.DocDef(tree, comment, definition)
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index de71ba30ab..c4c26e54b3 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -420,13 +420,13 @@ self =>
*/
def joinComment(trees: => List[Tree]): List[Tree] = {
val doc = in.flushDoc
- if ((doc ne null) && doc._1.length > 0) {
+ if ((doc ne null) && doc.raw.length > 0) {
val ts = trees
val main = ts.find(_.pos.isOpaqueRange)
ts map {
t =>
- val dd = DocDef(doc._1, t)
- val pos = doc._2.withEnd(t.pos.endOrPoint)
+ val dd = DocDef(doc, t)
+ val pos = doc.pos.withEnd(t.pos.endOrPoint)
dd setPos (if (t eq main) pos else pos.makeTransparent)
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index 62c47e8606..3de13ed877 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -103,11 +103,11 @@ trait Scanners {
/** buffer for the documentation comment
*/
var docBuffer: StringBuilder = null
- var docOffset: Position = null
+ var docPos: Position = null
/** Return current docBuffer and set docBuffer to null */
- def flushDoc = {
- val ret = if (docBuffer != null) (docBuffer.toString, docOffset) else null
+ def flushDoc: DocComment = {
+ val ret = if (docBuffer != null) DocComment(docBuffer.toString, docPos) else null
docBuffer = null
ret
}
@@ -1091,8 +1091,8 @@ trait Scanners {
}
override def foundDocComment(value: String, start: Int, end: Int) {
- docOffset = new RangePosition(unit.source, start, start, end)
- unit.comment(docOffset, value)
+ docPos = new RangePosition(unit.source, start, start, end)
+ unit.comment(docPos, value)
}
}
diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala
index 240ba17d51..3c969c41f8 100644
--- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala
@@ -39,7 +39,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor
override def onlyPresentation = true
lazy val addSourceless = {
val sless = new SourcelessComments { val global = compiler }
- comments ++= sless.comments
+ docComments ++= sless.comments
}
}
diff --git a/src/compiler/scala/tools/nsc/doc/SourcelessComments.scala b/src/compiler/scala/tools/nsc/doc/SourcelessComments.scala
index 50888ba27c..9216fa6f23 100644
--- a/src/compiler/scala/tools/nsc/doc/SourcelessComments.scala
+++ b/src/compiler/scala/tools/nsc/doc/SourcelessComments.scala
@@ -21,9 +21,9 @@ abstract class SourcelessComments {
lazy val comments = {
- val comment = mutable.HashMap.empty[Symbol, String]
+ val comment = mutable.HashMap.empty[Symbol, DocComment]
- comment(NothingClass) = """
+ comment(NothingClass) = new DocComment("""
/** <p>
* Class <code>Nothing</code> is - together with class <a href="Null.html">
* <code>Null</code></a> - at the bottom of the
@@ -44,9 +44,9 @@ abstract class SourcelessComments {
* instance of <code><a href="List.html">List</a>[T]</code>, for
* any element type <code>T</code>.
* </p> */
- """
+ """)
- comment(NullClass) = """
+ comment(NullClass) = new DocComment("""
/** <p>
* Class <code>Null</code> is - together with class <a href="Nothing.html">
* <code>Nothing</code> - at the bottom of the
@@ -61,12 +61,12 @@ abstract class SourcelessComments {
* it is not possible to assign <code>null</code> to a variable of
* type <a href="Int.html"><code>Int</code></a>.
* </p> */
- """
+ """)
/*******************************************************************/
/* Documentation for Any */
- comment(AnyClass) = """
+ comment(AnyClass) = new DocComment("""
/** <p>
* Class <code>Any</code> is the root of the <a
* href="http://scala-lang.org/"
@@ -77,9 +77,9 @@ abstract class SourcelessComments {
* <a href="AnyRef.html"><code>AnyRef</code></a> and
* <a href="AnyVal.html"><code>AnyVal</code></a>.
* </p> */
- """
+ """)
- comment(Any_equals) = """
+ comment(Any_equals) = new DocComment("""
/** This method is used to compare the receiver object (<code>this</code>)
* with the argument object (<code>arg0</code>) for equivalence.
*
@@ -113,34 +113,34 @@ abstract class SourcelessComments {
* @param arg0 the object to compare against this object for equality.
* @return <code>true</code> if the receiver object is equivalent to the argument; <code>false</code> otherwise.
* </p> */
- """
+ """)
- comment(Any_==) = """
+ comment(Any_==) = new DocComment("""
/** `o == arg0` is the same as `o.equals(arg0)`.
* <p>
* @param arg0 the object to compare against this object for equality.
* @return `true` if the receiver object is equivalent to the argument; `false` otherwise.
* </p> */
- """
+ """)
- comment(Any_!=) = """
+ comment(Any_!=) = new DocComment("""
/** `o != arg0` is the same as `!(o == (arg0))`.
* <p>
* @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.
* </p> */
- """
+ """)
- comment(Any_toString) = """
+ comment(Any_toString) = new DocComment("""
/** Returns a string representation of the object.
* <p>
* The default representation is platform dependent.
*
* @return a string representation of the object.
* </p>*/
- """
+ """)
- comment(Any_asInstanceOf) = """
+ comment(Any_asInstanceOf) = new DocComment("""
/**This method is used to cast the receiver object to be of type <code>T0</code>.
*
* <p>Note that the success of a cast at runtime is modulo Scala's
@@ -156,9 +156,9 @@ abstract class SourcelessComments {
* instance of erasure of type <code>T0</code>.
* @return the receiver object.
* </p> */
- """
+ """)
- comment(Any_isInstanceOf) = """
+ comment(Any_isInstanceOf) = new DocComment("""
/** This method is used to test whether the dynamic type of the receiver object is <code>T0</code>.
*
* <p>Note that the test result of the test is modulo Scala's erasure
@@ -172,9 +172,9 @@ abstract class SourcelessComments {
*
* @return <code>true</code> if the receiver object is an
* instance of erasure of type <code>T0</code>; <code>false</code> otherwise. */
- """
+ """)
- comment(Any_hashCode) = """
+ comment(Any_hashCode) = new DocComment("""
/** Returns a hash code value for the object.
*
* <p>
@@ -195,36 +195,36 @@ abstract class SourcelessComments {
* <p>
* @return the hash code value for the object.
* </p> */
- """
+ """)
/*******************************************************************/
/* Documentation for AnyRef */
- comment(AnyRefClass) = """
+ comment(AnyRefClass) = new DocComment("""
/** <p>
* Class <code>AnyRef</code> is the root class of all
* <em>reference types</em>.
* </p> */
- """
+ """)
- comment(Object_==) = """
+ comment(Object_==) = new DocComment("""
/** <code>o == arg0</code> is the same as <code>if (o eq null) arg0 eq null else o.equals(arg0)</code>.
* <p>
* @param arg0 the object to compare against this object for equality.
* @return <code>true</code> if the receiver object is equivalent to the argument; <code>false</code> otherwise.
* </p> */
- """
+ """)
- comment(Object_ne) = """
+ comment(Object_ne) = new DocComment("""
/** <code>o.ne(arg0)</code> is the same as <code>!(o.eq(arg0))</code>.
* <p>
* @param arg0 the object to compare against this object for reference dis-equality.
* @return <code>false</code> if the argument is not a reference to the receiver object; <code>true</code> otherwise.
* </p> */
- """
+ """)
- comment(Object_finalize) = """
+ 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.
* <p>
@@ -232,9 +232,9 @@ abstract class SourcelessComments {
* invoked, as well as the interaction between <code>finalize</code>
* and non-local returns and exceptions, are all platform dependent.
* </p> */
- """
+ """)
- comment(Object_clone) = """
+ comment(Object_clone) = new DocComment("""
/** This method creates and returns a copy of the receiver object.
*
* <p>
@@ -242,9 +242,9 @@ abstract class SourcelessComments {
*
* @return a copy of the receiver object.
* </p> */
- """
+ """)
- comment(Object_getClass) = """
+ comment(Object_getClass) = new DocComment("""
/** Returns a representation that corresponds to the dynamic class of the receiver object.
*
* <p>
@@ -252,17 +252,17 @@ abstract class SourcelessComments {
*
* @return a representation that corresponds to the dynamic class of the receiver object.
* </p> */
- """
+ """)
- comment(Object_notify) = """
+ comment(Object_notify) = new DocComment("""
/** Wakes up a single thread that is waiting on the receiver object's monitor. */
- """
+ """)
- comment(Object_notifyAll) = """
+ comment(Object_notifyAll) = new DocComment("""
/** Wakes up all threads that are waiting on the receiver object's monitor. */
- """
+ """)
- comment(Object_eq) = """
+ comment(Object_eq) = new DocComment("""
/** This method is used to test whether the argument (<code>arg0</code>) is a reference to the
* receiver object (<code>this</code>).
*
@@ -304,11 +304,11 @@ abstract class SourcelessComments {
* @param arg0 the object to compare against this object for reference equality.
* @return <code>true</code> if the argument is a reference to the receiver object; <code>false</code> otherwise.
* </p> */
- """
+ """)
/*******************************************************************/
- comment(AnyValClass) = """
+ comment(AnyValClass) = new DocComment("""
/** <p>
* Class <code>AnyVal</code> is the root class of all
* <em>value types</em>.
@@ -338,25 +338,25 @@ abstract class SourcelessComments {
* <a href="Double.html"><code>Double</code></a> are called
* <em>floating point types</em>.
* </p> */
- """
+ """)
- comment(BooleanClass) = """
+ comment(BooleanClass) = new DocComment("""
/** <p>
* Class <code>Boolean</code> has only two values: <code>true</code>
* and <code>false</code>.
* </p> */
- """
+ """)
- comment(UnitClass) = """
+ comment(UnitClass) = new DocComment("""
/** <p>
* Class <code>Unit</code> has only one value: <code>()</code>.
* </p> */
- """
+ """)
List(ByteClass, CharClass, DoubleClass, LongClass, FloatClass, IntClass, ShortClass) foreach { sym =>
val maxValue = "MAX_" + sym.name.toString().toUpperCase()
val minValue = "MIN_" + sym.name.toString().toUpperCase()
- comment(sym) = """
+ comment(sym) = new DocComment("""
/** <p>
* Class <code>""" + sym.name + """</code> belongs to the value
* classes whose instances are not represented as objects by the
@@ -370,7 +370,7 @@ abstract class SourcelessComments {
* Values <code>""" + maxValue + """</code> and <code>""" + minValue + """</code>
* are in defined in object <a href="Math$object.html">scala.Math</a>.
* </p> */
- """
+ """)
}
comment
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index b8a219fb4d..35d212071e 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -512,11 +512,8 @@ self =>
*/
private def applyPhase(phase: Phase, unit: CompilationUnit) {
val oldSource = reporter.getSource
- try {
- reporter.setSource(unit.source)
+ reporter.withSource(unit.source) {
atPhase(phase) { phase.asInstanceOf[GlobalPhase] applyPhase unit }
- } finally {
- reporter setSource oldSource
}
}
}
diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala
index b00590d501..99292f2338 100644
--- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala
@@ -41,6 +41,15 @@ abstract class Reporter {
private var source: SourceFile = _
def setSource(source: SourceFile) { this.source = source }
def getSource: SourceFile = source
+ def withSource[A](src: SourceFile)(op: => A) = {
+ val oldSource = source
+ try {
+ source = src
+ op
+ } finally {
+ source = oldSource
+ }
+ }
def info(pos: Position, msg: String, force: Boolean) { info0(pos, msg, INFO, force) }
def warning(pos: Position, msg: String ) { info0(pos, msg, WARNING, false) }
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
index da0d237567..2a70c55cd6 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
@@ -6,7 +6,7 @@
package scala.tools.nsc
package symtab
-import ast.Trees
+import ast.{Trees, DocComments}
import util._
@@ -23,6 +23,7 @@ abstract class SymbolTable extends Names
with AnnotationCheckers
with Trees
with Positions
+ with DocComments
{
def settings: Settings
def rootLoader: LazyType
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
index 8d3d0bbf2a..ee0576d654 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
@@ -538,7 +538,7 @@ abstract class UnPickler {
case other => errorBadSignature("Document comment not a string (" + other + ")")
}
val definition = readTreeRef()
- DocDef(comment, definition)
+ DocDef(DocComment(comment, NoPosition), definition)
case TEMPLATEtree =>
setSym()
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 1e8b93bf5d..2132be4d50 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -758,9 +758,6 @@ trait Namers { self: Analyzer =>
tpt setPos meth.pos.focus
}
- if (onlyPresentation && methodArgumentNames != null)
- methodArgumentNames(meth) = vparamss.map(_.map(_.symbol));
-
def convertToDeBruijn(vparams: List[Symbol], level: Int): TypeMap = new TypeMap {
def debruijnFor(param: Symbol) =
DeBruijnIndex(level, vparams indexOf param)
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 682a7db991..a18fbe70d1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -151,6 +151,17 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
decls.enter(s)
}
}
+ if (settings.verbose.value && onlyPresentation && !sym.isAnonymousClass) {
+ println("========== scaladoc of "+sym+" =============================")
+ for (member <- sym.info.members) {
+ println(member+":"+sym.thisType.memberInfo(member)+"\n"+
+ cookedDocComment(member, sym))
+ for ((useCase, comment) <- useCases(member, sym)) {
+ println("usecase "+useCase+":"+useCase.info)
+ println(comment)
+ }
+ }
+ }
super.transform(tree)
case ModuleDef(_, _, _) =>
checkCompanionNameClashes(sym)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 7e4d6b7d7d..a610f85104 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -15,7 +15,7 @@ import scala.collection.mutable.{HashMap, ListBuffer}
import scala.util.control.ControlException
import scala.compat.Platform.currentTime
import scala.tools.nsc.interactive.RangePositions
-import scala.tools.nsc.util.{ Position, Set, NoPosition, SourceFile }
+import scala.tools.nsc.util.{ Position, Set, NoPosition, SourceFile, BatchSourceFile }
import symtab.Flags._
// Suggestion check whether we can do without priming scopes with symbols of outer scopes,
@@ -689,8 +689,8 @@ trait Typers { self: Analyzer =>
else qual.tpe.nonLocalMember(name)
}
- def silent(op: Typer => Tree): AnyRef /* in fact, TypeError or Tree */ = {
- val start = System.nanoTime()
+ def silent[T](op: Typer => T): Any /* in fact, TypeError or T */ = {
+// val start = System.nanoTime()
try {
if (context.reportGeneralErrors) {
val context1 = context.makeSilent(context.reportAmbiguousErrors)
@@ -709,7 +709,7 @@ trait Typers { self: Analyzer =>
} catch {
case ex: CyclicReference => throw ex
case ex: TypeError =>
- failedSilent += System.nanoTime() - start
+// failedSilent += System.nanoTime() - start
ex
}}
@@ -1709,6 +1709,45 @@ trait Typers { self: Analyzer =>
}
}
+ def typedUseCase(useCase: UseCase) {
+ def stringParser(str: String): syntaxAnalyzer.Parser = {
+ val file = new BatchSourceFile(context.unit.source.file, str) {
+ override def positionInUltimateSource(pos: Position) = {
+ pos.withSource(context.unit.source, useCase.pos.start)
+ }
+ }
+ val unit = new CompilationUnit(file)
+ new syntaxAnalyzer.UnitParser(unit)
+ }
+ val trees = stringParser(useCase.body+";").nonLocalDefOrDcl
+ val enclClass = context.enclClass.owner
+ def defineAlias(name: Name) =
+ if (context.scope.lookup(name) == NoSymbol) {
+ lookupVariable(name.toString.substring(1), enclClass) match {
+ case Some(repl) =>
+ silent(_.typedTypeConstructor(stringParser(repl).typ())) match {
+ case tpt: Tree =>
+ val alias = enclClass.newAliasType(useCase.pos, name)
+ val tparams = cloneSymbols(tpt.tpe.typeSymbol.typeParams, alias)
+ alias setInfo polyType(tparams, appliedType(tpt.tpe, tparams map (_.tpe)))
+ context.scope.enter(alias)
+ case _ =>
+ }
+ case _ =>
+ }
+ }
+ for (tree <- trees; t <- tree)
+ t match {
+ case Ident(name) if (name.length > 0 && name(0) == '$') => defineAlias(name)
+ case _ =>
+ }
+ useCase.aliases = context.scope.toList
+ namer.enterSyms(trees)
+ typedStats(trees, NoSymbol)
+ useCase.defined = context.scope.toList -- useCase.aliases
+// println("defined use cases: "+(useCase.defined map (sym => sym+":"+sym.tpe)))
+ }
+
/**
* @param ddef ...
* @return ...
@@ -3701,12 +3740,18 @@ trait Typers { self: Analyzer =>
labelTyper(ldef).typedLabelDef(ldef)
case ddef @ DocDef(comment, defn) =>
- val ret = typed(defn, mode, pt)
- if ((comments ne null) && (defn.symbol ne null) && (defn.symbol ne NoSymbol)) {
- comments(defn.symbol) = comment
- commentOffsets(defn.symbol) = ddef.pos.startOrPoint
+ if (onlyPresentation && (sym ne null) && (sym ne NoSymbol)) {
+ docComments(sym) = comment
+ comment.defineVariables(sym)
+ val typer1 = newTyper(context.makeNewScope(tree, context.owner))
+ for (useCase <- comment.useCases)
+ typer1.silent(_.typedUseCase(useCase)) match {
+ case ex: TypeError =>
+ unit.warning(useCase.pos, ex.msg)
+ case _ =>
+ }
}
- ret
+ typed(defn, mode, pt)
case Annotated(constr, arg) =>
typedAnnotated(constr, typed(arg, mode, pt))
diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala
index 999dca3927..806c885291 100644
--- a/src/compiler/scala/tools/nsc/util/Position.scala
+++ b/src/compiler/scala/tools/nsc/util/Position.scala
@@ -109,6 +109,9 @@ trait Position {
/** The same position with a different point value (if a range or offset) */
def withPoint(off: Int) = this
+ /** The same position with a different source value, and its values shifted by given offset */
+ def withSource(source: SourceFile, shift: Int) = this
+
/** If this is a range, the union with the other range, with the point of this position.
* Otherwise, this position
*/
@@ -200,6 +203,7 @@ class OffsetPosition(override val source: SourceFile, override val point: Int) e
override def isDefined = true
override def pointOrElse(default: Int): Int = point
override def withPoint(off: Int) = new OffsetPosition(source, off)
+ override def withSource(source: SourceFile, shift: Int) = new OffsetPosition(source, point + shift)
override def line: Int = source.offsetToLine(point) + 1
@@ -240,6 +244,7 @@ extends OffsetPosition(source, point) {
override def withStart(off: Int) = new RangePosition(source, off, point, end)
override def withEnd(off: Int) = new RangePosition(source, start, point, off)
override def withPoint(off: Int) = new RangePosition(source, start, off, end)
+ override def withSource(source: SourceFile, shift: Int) = new RangePosition(source, start + shift, point + shift, end + shift)
override def focusStart = new OffsetPosition(source, start)
override def focus = {
if (focusCache eq NoPosition) focusCache = new OffsetPosition(source, point)