summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2012-12-12 15:05:47 -0800
committerAdriaan Moors <adriaan.moors@typesafe.com>2012-12-12 15:05:47 -0800
commita6f10cf7f4245f2dfcf2fef5fab5255b6fca119f (patch)
treecbad4b40dc2e471234dad0fec55a643f9bbdae93
parent59c2649ae074364a9a2d171d58d47612c92bf1c1 (diff)
parente5e6d673cf669e3c9a7643aedd02213e4f7bbddf (diff)
downloadscala-a6f10cf7f4245f2dfcf2fef5fab5255b6fca119f.tar.gz
scala-a6f10cf7f4245f2dfcf2fef5fab5255b6fca119f.tar.bz2
scala-a6f10cf7f4245f2dfcf2fef5fab5255b6fca119f.zip
Merge pull request #1722 from vigdorchik/ide.api
Extract base scaladoc functionality for the IDE.
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/DocComments.scala39
-rw-r--r--src/compiler/scala/tools/nsc/doc/DocFactory.scala2
-rwxr-xr-x[-rw-r--r--]src/compiler/scala/tools/nsc/doc/base/CommentFactoryBase.scala (renamed from src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala)232
-rwxr-xr-xsrc/compiler/scala/tools/nsc/doc/base/LinkTo.scala15
-rwxr-xr-xsrc/compiler/scala/tools/nsc/doc/base/MemberLookupBase.scala230
-rwxr-xr-x[-rw-r--r--]src/compiler/scala/tools/nsc/doc/base/comment/Body.scala (renamed from src/compiler/scala/tools/nsc/doc/model/comment/Body.scala)2
-rw-r--r--src/compiler/scala/tools/nsc/doc/base/comment/Comment.scala (renamed from src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala)3
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala9
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/Source.scala1
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/Template.scala3
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/CommentFactory.scala114
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/Entity.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/LinkTo.scala24
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala225
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala33
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala4
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala6
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala3
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala3
-rwxr-xr-xsrc/compiler/scala/tools/nsc/interactive/Doc.scala50
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala1
-rw-r--r--src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala3
-rw-r--r--src/partest/scala/tools/partest/ScaladocModelTest.scala2
-rwxr-xr-xtest/files/presentation/doc.check48
-rwxr-xr-xtest/files/presentation/doc.scala71
-rwxr-xr-xtest/files/presentation/doc/src/Test.scala1
-rw-r--r--test/files/presentation/memory-leaks/MemoryLeaksTest.scala5
-rwxr-xr-xtest/scaladoc/run/SI-191-deprecated.scala3
-rwxr-xr-xtest/scaladoc/run/SI-191.scala3
-rw-r--r--test/scaladoc/run/SI-3314.scala3
-rw-r--r--test/scaladoc/run/SI-5235.scala3
-rw-r--r--test/scaladoc/run/links.scala7
-rw-r--r--test/scaladoc/scalacheck/CommentFactoryTest.scala3
36 files changed, 664 insertions, 496 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala
index 5a4be5125d..e635c5e87d 100755
--- a/src/compiler/scala/tools/nsc/ast/DocComments.scala
+++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala
@@ -19,11 +19,17 @@ import scala.collection.mutable
*/
trait DocComments { self: Global =>
- var cookedDocComments = Map[Symbol, String]()
+ val cookedDocComments = mutable.HashMap[Symbol, String]()
/** The raw doc comment map */
val docComments = mutable.HashMap[Symbol, DocComment]()
+ def clearDocComments() {
+ cookedDocComments.clear()
+ docComments.clear()
+ defs.clear()
+ }
+
/** Associate comment with symbol `sym` at position `pos`. */
def docComment(sym: Symbol, docStr: String, pos: Position = NoPosition) =
if ((sym ne null) && (sym ne NoSymbol))
@@ -55,25 +61,20 @@ trait DocComments { self: Global =>
* If a symbol does not have a doc comment but some overridden version of it does,
* the doc comment of the overridden version is copied instead.
*/
- def cookedDocComment(sym: Symbol, docStr: String = ""): String = cookedDocComments.get(sym) match {
- case Some(comment) =>
- comment
- case None =>
- val ownComment = if (docStr.length == 0) docComments get sym map (_.template) getOrElse ""
+ def cookedDocComment(sym: Symbol, docStr: String = ""): String = cookedDocComments.getOrElseUpdate(sym, {
+ val ownComment = if (docStr.length == 0) docComments get sym map (_.template) getOrElse ""
else DocComment(docStr).template
- val comment = superComment(sym) match {
- case None =>
- if (ownComment.indexOf("@inheritdoc") != -1)
- reporter.warning(sym.pos, "The comment for " + sym +
- " contains @inheritdoc, but no parent comment is available to inherit from.")
- ownComment.replaceAllLiterally("@inheritdoc", "<invalid inheritdoc annotation>")
- case Some(sc) =>
- if (ownComment == "") sc
- else expandInheritdoc(sc, merge(sc, ownComment, sym), sym)
- }
- cookedDocComments += (sym -> comment)
- comment
- }
+ superComment(sym) match {
+ case None =>
+ if (ownComment.indexOf("@inheritdoc") != -1)
+ reporter.warning(sym.pos, "The comment for " + sym +
+ " contains @inheritdoc, but no parent comment is available to inherit from.")
+ ownComment.replaceAllLiterally("@inheritdoc", "<invalid inheritdoc annotation>")
+ case Some(sc) =>
+ if (ownComment == "") sc
+ else expandInheritdoc(sc, merge(sc, ownComment, sym), sym)
+ }
+ })
/** The cooked doc comment of symbol `sym` after variable expansion, or "" if missing.
*
diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala
index 642e330a57..a091b04993 100644
--- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala
@@ -80,7 +80,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor
with model.ModelFactoryImplicitSupport
with model.ModelFactoryTypeSupport
with model.diagram.DiagramFactory
- with model.comment.CommentFactory
+ with model.CommentFactory
with model.TreeFactory
with model.MemberLookup {
override def templateShouldDocument(sym: compiler.Symbol, inTpl: DocTemplateImpl) =
diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/base/CommentFactoryBase.scala
index 40057bbb52..f60d56d9bb 100644..100755
--- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/base/CommentFactoryBase.scala
@@ -1,13 +1,13 @@
/* NSC -- new Scala compiler
- * Copyright 2007-2013 LAMP/EPFL
+ * Copyright 2007-2012 LAMP/EPFL
* @author Manohar Jonnalagedda
*/
package scala.tools.nsc
package doc
-package model
-package comment
+package base
+import base.comment._
import reporters.Reporter
import scala.collection._
import scala.util.matching.Regex
@@ -23,78 +23,10 @@ import scala.language.postfixOps
*
* @author Manohar Jonnalagedda
* @author Gilles Dubochet */
-trait CommentFactory { thisFactory: ModelFactory with CommentFactory with MemberLookup=>
+trait CommentFactoryBase { this: MemberLookupBase =>
val global: Global
- import global.{ reporter, definitions }
-
- 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, None)
- sym
- }
-
- 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, currentTpl, inTpl)
- if (c isDefined) commentCache += (sym, inTpl) -> c.get
- c
- }
- }
-
- /** A comment is usualy created by the parser, however for some special
- * 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, currentTpl: Option[DocTemplateImpl], inTpl: DocTemplateImpl):Option[Comment] = {
-
- //param accessor case
- // We just need the @param argument, we put it into the body
- if( sym.isParamAccessor &&
- inTpl.comment.isDefined &&
- inTpl.comment.get.valueParams.isDefinedAt(sym.encodedName)) {
- val comContent = Some(inTpl.comment.get.valueParams(sym.encodedName))
- Some(createComment(body0 = comContent))
- }
-
- // Primary constructor case
- // We need some content of the class definition : @constructor for the body,
- // @param and @deprecated, we can add some more if necessary
- else if (sym.isPrimaryConstructor && inTpl.comment.isDefined ) {
- val tplComment = inTpl.comment.get
- // If there is nothing to put into the comment there is no need to create it
- if(tplComment.constructor.isDefined ||
- tplComment.throws != Map.empty ||
- tplComment.valueParams != Map.empty ||
- tplComment.typeParams != Map.empty ||
- tplComment.deprecated.isDefined
- )
- Some(createComment( body0 = tplComment.constructor,
- throws0 = tplComment.throws,
- valueParams0 = tplComment.valueParams,
- typeParams0 = tplComment.typeParams,
- deprecated0 = tplComment.deprecated
- ))
- else None
- }
-
- //other comment cases
- // parse function will make the comment
- else {
- val rawComment = global.expandedDocComment(sym, inTpl.sym).trim
- if (rawComment != "") {
- val tplOpt = if (currentTpl.isDefined) currentTpl else Some(inTpl)
- val c = parse(rawComment, global.rawDocComment(sym), global.docCommentPos(sym), tplOpt)
- Some(c)
- }
- else None
- }
-
- }
+ import global.{ reporter, definitions, Symbol }
/* Creates comments with necessary arguments */
def createComment (
@@ -259,9 +191,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
* @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, inTplOpt: Option[DocTemplateImpl] = None): Comment = {
- assert(!inTplOpt.isDefined || inTplOpt.get != null)
-
+ protected def parseAtSymbol(comment: String, src: String, pos: Position, siteOpt: Option[Symbol] = None): Comment = {
/** The cleaned raw comment as a list of lines. Cleaning removes comment
* start and end markers, line start markers and unnecessary whitespace. */
def clean(comment: String): List[String] = {
@@ -387,7 +317,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
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, inTplOpt))} toSeq: _*)
+ mutable.Map(tagsWithoutDiagram mapValues {tag => tag map (parseWikiAtSymbol(_, pos, siteOpt))} toSeq: _*)
def oneTag(key: SimpleTagKey): Option[Body] =
((bodyTags remove key): @unchecked) match {
@@ -420,7 +350,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
}
val com = createComment (
- body0 = Some(parseWiki(docBody.toString, pos, inTplOpt)),
+ body0 = Some(parseWikiAtSymbol(docBody.toString, pos, siteOpt)),
authors0 = allTags(SimpleTagKey("author")),
see0 = allTags(SimpleTagKey("see")),
result0 = oneTag(SimpleTagKey("return")),
@@ -460,24 +390,17 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
* - 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, inTplOpt: Option[DocTemplateImpl]): Body = {
- assert(!inTplOpt.isDefined || inTplOpt.get != null)
-
- new WikiParser(string, pos, inTplOpt).document()
- }
+ def parseWikiAtSymbol(string: String, pos: Position, siteOpt: Option[Symbol]): Body = new WikiParser(string, pos, siteOpt).document()
/** TODO
*
* @author Ingo Maier
* @author Manohar Jonnalagedda
* @author Gilles Dubochet */
- protected final class WikiParser(val buffer: String, pos: Position, inTplOpt: Option[DocTemplateImpl]) extends CharReader(buffer) { wiki =>
- assert(!inTplOpt.isDefined || inTplOpt.get != null)
-
+ protected final class WikiParser(val buffer: String, pos: Position, siteOpt: Option[Symbol]) extends CharReader(buffer) { wiki =>
var summaryParsed = false
def document(): Body = {
- nextChar()
val blocks = new mutable.ListBuffer[Block]
while (char != endOfText)
blocks += block()
@@ -559,21 +482,21 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
def code(): Block = {
jumpWhitespace()
jump("{{{")
- readUntil("}}}")
+ val str = readUntil("}}}")
if (char == endOfText)
reportError(pos, "unclosed code block")
else
jump("}}}")
blockEnded("code block")
- Code(normalizeIndentation(getRead))
+ Code(normalizeIndentation(str))
}
/** {{{ title ::= ('=' inline '=' | "==" inline "==" | ...) '\n' }}} */
def title(): Block = {
jumpWhitespace()
- val inLevel = repeatJump("=")
+ val inLevel = repeatJump('=')
val text = inline(check("=" * inLevel))
- val outLevel = repeatJump("=", inLevel)
+ val outLevel = repeatJump('=', inLevel)
if (inLevel != outLevel)
reportError(pos, "unbalanced or unclosed heading")
blockEnded("heading")
@@ -583,7 +506,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
/** {{{ hrule ::= "----" { '-' } '\n' }}} */
def hrule(): Block = {
jumpWhitespace()
- repeatJump("-")
+ repeatJump('-')
blockEnded("horizontal rule")
HorizontalRule()
}
@@ -621,8 +544,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
}
do {
- readUntil { char == safeTagMarker || char == endOfText }
- val str = getRead()
+ val str = readUntil { char == safeTagMarker || char == endOfText }
nextChar()
list += str
@@ -660,8 +582,8 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
else if (check(",,")) subscript()
else if (check("[[")) link()
else {
- readUntil { char == safeTagMarker || check("''") || char == '`' || check("__") || char == '^' || check(",,") || check("[[") || isInlineEnd || checkParaEnded || char == endOfLine }
- Text(getRead())
+ val str = readUntil { char == safeTagMarker || check("''") || char == '`' || check("__") || char == '^' || check(",,") || check("[[") || isInlineEnd || checkParaEnded || char == endOfLine }
+ Text(str)
}
}
@@ -698,9 +620,8 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
def htmlTag(): HtmlTag = {
jump(safeTagMarker)
- readUntil(safeTagMarker)
+ val read = readUntil(safeTagMarker)
if (char != endOfText) jump(safeTagMarker)
- var read = getRead
HtmlTag(read)
}
@@ -762,14 +683,11 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
def link(): Inline = {
val SchemeUri = """([a-z]+:.*)""".r
jump("[[")
- var parens = 1
- readUntil { parens += 1; !check("[") }
- getRead // clear the buffer
+ var parens = 2 + repeatJump('[')
val start = "[" * parens
val stop = "]" * parens
//println("link with " + parens + " matching parens")
- readUntil { check(stop) || check(" ") }
- val target = getRead()
+ val target = readUntil { check(stop) || check(" ") }
val title =
if (!check(stop)) Some({
jump(" ")
@@ -782,7 +700,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
case (SchemeUri(uri), optTitle) =>
Link(uri, optTitle getOrElse Text(uri))
case (qualName, optTitle) =>
- makeEntityLink(optTitle getOrElse Text(target), pos, target, inTplOpt)
+ makeEntityLink(optTitle getOrElse Text(target), pos, target, siteOpt)
}
}
@@ -860,7 +778,6 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
(char == endOfText) ||
((char == endOfLine) && {
val poff = offset
- val pc = char
nextChar() // read EOL
val ok = {
checkSkipInitWhitespace(endOfLine) ||
@@ -870,7 +787,6 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
checkSkipInitWhitespace('\u003D')
}
offset = poff
- char = pc
ok
})
}
@@ -882,40 +798,31 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
protected sealed class CharReader(buffer: String) { reader =>
- var char: Char = _
var offset: Int = 0
+ def char: Char =
+ if (offset >= buffer.length) endOfText else buffer charAt offset
final def nextChar() {
- if (offset >= buffer.length)
- char = endOfText
- else {
- char = buffer charAt offset
- offset += 1
- }
+ offset += 1
}
final def check(chars: String): Boolean = {
val poff = offset
- val pc = char
val ok = jump(chars)
offset = poff
- char = pc
ok
}
def checkSkipInitWhitespace(c: Char): Boolean = {
val poff = offset
- val pc = char
jumpWhitespace()
val ok = jump(c)
offset = poff
- char = pc
ok
}
def checkSkipInitWhitespace(chars: String): Boolean = {
val poff = offset
- val pc = char
jumpWhitespace()
val (ok0, chars0) =
if (chars.charAt(0) == ' ')
@@ -924,20 +831,17 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
(true, chars)
val ok = ok0 && jump(chars0)
offset = poff
- char = pc
ok
}
def countWhitespace: Int = {
var count = 0
val poff = offset
- val pc = char
while (isWhitespace(char) && char != endOfText) {
nextChar()
count += 1
}
offset = poff
- char = pc
count
}
@@ -964,38 +868,10 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
index == chars.length
}
- final def checkedJump(chars: String): Boolean = {
- val poff = offset
- val pc = char
- val ok = jump(chars)
- if (!ok) {
- offset = poff
- char = pc
- }
- ok
- }
-
- final def repeatJump(chars: String, max: Int): Int = {
- var count = 0
- var more = true
- while (more && count < max) {
- if (!checkedJump(chars))
- more = false
- else
- count += 1
- }
- count
- }
-
- final def repeatJump(chars: String): Int = {
+ final def repeatJump(c: Char, max: Int = Int.MaxValue): Int = {
var count = 0
- var more = true
- while (more) {
- if (!checkedJump(chars))
- more = false
- else
- count += 1
- }
+ while (jump(c) && count < max)
+ count += 1
count
}
@@ -1035,47 +911,41 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
/* READERS */
- private val readBuilder = new mutable.StringBuilder
-
- final def getRead(): String = {
- val bld = readBuilder.toString
- readBuilder.clear()
- if (bld.length < 6) bld.intern else bld
- }
-
- final def readUntil(ch: Char): Int = {
- var count = 0
- while (char != ch && char != endOfText) {
- readBuilder += char
- nextChar()
+ final def readUntil(c: Char): String = {
+ withRead {
+ while (char != c && char != endOfText) {
+ nextChar()
+ }
}
- count
}
- final def readUntil(chars: String): Int = {
+ final def readUntil(chars: String): String = {
assert(chars.length > 0)
- var count = 0
- val c = chars.charAt(0)
- while (!check(chars) && char != endOfText) {
- readBuilder += char
- nextChar()
- while (char != c && char != endOfText) {
- readBuilder += char
+ withRead {
+ val c = chars.charAt(0)
+ while (!check(chars) && char != endOfText) {
nextChar()
+ while (char != c && char != endOfText)
+ nextChar()
}
}
- count
}
- final def readUntil(pred: => Boolean): Int = {
- var count = 0
- while (!pred && char != endOfText) {
- readBuilder += char
- nextChar()
+ final def readUntil(pred: => Boolean): String = {
+ withRead {
+ while (char != endOfText && !pred) {
+ nextChar()
+ }
}
- count
}
+ private def withRead(read: => Unit): String = {
+ val start = offset
+ read
+ buffer.substring(start, offset)
+ }
+
+
/* CHARS CLASSES */
def isWhitespace(c: Char) = c == ' ' || c == '\t'
diff --git a/src/compiler/scala/tools/nsc/doc/base/LinkTo.scala b/src/compiler/scala/tools/nsc/doc/base/LinkTo.scala
new file mode 100755
index 0000000000..c11179800c
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/base/LinkTo.scala
@@ -0,0 +1,15 @@
+/* NSC -- new Scala compiler
+ * Copyright 2007-2013 LAMP/EPFL
+ */
+
+package scala.tools.nsc
+package doc
+package base
+
+import scala.collection._
+
+sealed trait LinkTo
+final case class LinkToMember[Mbr, Tpl](mbr: Mbr, tpl: Tpl) extends LinkTo
+final case class LinkToTpl[Tpl](tpl: Tpl) extends LinkTo
+final case class LinkToExternal(name: String, url: String) extends LinkTo
+final case class Tooltip(name: String) extends LinkTo
diff --git a/src/compiler/scala/tools/nsc/doc/base/MemberLookupBase.scala b/src/compiler/scala/tools/nsc/doc/base/MemberLookupBase.scala
new file mode 100755
index 0000000000..f3a5660dc4
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/base/MemberLookupBase.scala
@@ -0,0 +1,230 @@
+package scala.tools.nsc
+package doc
+package base
+
+import comment._
+
+/** This trait extracts all required information for documentation from compilation units.
+ * The base trait has been extracted to allow getting light-weight documentation
+ * for a particular symbol in the IDE.*/
+trait MemberLookupBase {
+
+ val global: Global
+ val settings: doc.Settings
+
+ import global._
+ def internalLink(sym: Symbol, site: Symbol): Option[LinkTo]
+ def chooseLink(links: List[LinkTo]): LinkTo
+
+ import global._
+ import definitions.{ NothingClass, AnyClass, AnyValClass, AnyRefClass, ListClass }
+ import rootMirror.{RootPackage, EmptyPackage}
+
+ private def isRoot(s: Symbol) = s.isRootSymbol || s.isEmptyPackage || s.isEmptyPackageClass
+
+ def makeEntityLink(title: Inline, pos: Position, query: String, siteOpt: Option[Symbol]) =
+ new EntityLink(title) { lazy val link = memberLookup(pos, query, siteOpt) }
+
+ def memberLookup(pos: Position, query: String, siteOpt: Option[Symbol]): LinkTo = {
+ var members = breakMembers(query)
+
+ // (1) First look in the root package, as most of the links are qualified
+ val fromRoot = lookupInRootPackage(pos, members)
+
+ // (2) Or recursively go into each containing template.
+ val fromParents = siteOpt.fold(Stream.empty[Symbol]) { s =>
+ Stream.iterate(s)(_.owner)
+ }.takeWhile (!isRoot(_)).map {
+ lookupInTemplate(pos, members, _)
+ }
+
+ val syms = (fromRoot +: fromParents) find (!_.isEmpty) getOrElse Nil
+
+ val links = syms flatMap { case (sym, site) => internalLink(sym, site) } match {
+ case Nil =>
+ // (3) Look at external links
+ syms.flatMap { case (sym, owner) =>
+ // reconstruct the original link
+ def linkName(sym: Symbol) = {
+ def nameString(s: Symbol) = s.nameString + (if ((s.isModule || s.isModuleClass) && !s.isPackage) "$" else "")
+ val packageSuffix = if (sym.isPackage) ".package" else ""
+
+ sym.ownerChain.reverse.filterNot(isRoot(_)).map(nameString(_)).mkString(".") + packageSuffix
+ }
+
+ if (sym.isClass || sym.isModule || sym.isTrait || sym.isPackage)
+ findExternalLink(sym, linkName(sym))
+ else if (owner.isClass || owner.isModule || owner.isTrait || owner.isPackage)
+ findExternalLink(sym, linkName(owner) + "@" + externalSignature(sym))
+ else
+ None
+ }
+ case links => links
+ }
+ links match {
+ case Nil =>
+ if (!settings.docNoLinkWarnings.value)
+ reporter.warning(pos, "Could not find any member to link for \"" + query + "\".")
+ // (4) if we still haven't found anything, create a tooltip
+ Tooltip(query)
+ case List(l) => l
+ case links =>
+ val chosen = chooseLink(links)
+ def linkToString(link: LinkTo) = {
+ val chosenInfo =
+ if (link == chosen) " [chosen]" else ""
+ link.toString + chosenInfo + "\n"
+ }
+ if (!settings.docNoLinkWarnings.value)
+ reporter.warning(pos,
+ "The link target \"" + query + "\" is ambiguous. Several (possibly overloaded) members fit the target:\n" +
+ links.map(linkToString).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
+ }
+ }
+
+ 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, EmptyPackage) ::: lookupInTemplate(pos, members, RootPackage)
+
+ private def lookupInTemplate(pos: Position, members: List[String], container: Symbol): List[(Symbol, Symbol)] = {
+ // 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 syms = lookupInTemplate(pos, mbrName, container, OnlyType) map ((_, container))
+ if (syms.isEmpty)
+ syms = lookupInTemplate(pos, mbrName, container, OnlyTerm) map ((_, container))
+ syms
+
+ case tplName::rest =>
+ def completeSearch(syms: List[Symbol]) =
+ syms flatMap (lookupInTemplate(pos, rest, _))
+
+ completeSearch(lookupInTemplate(pos, tplName, container, OnlyTerm)) match {
+ case Nil => completeSearch(lookupInTemplate(pos, tplName, container, OnlyType))
+ case syms => syms
+ }
+ }
+ //println("lookupInTemplate(" + members + ", " + container + ") => " + result)
+ result
+ }
+
+ private def lookupInTemplate(pos: Position, member: String, container: Symbol, strategy: SearchStrategy): List[Symbol] = {
+ val name = member.stripSuffix("$").stripSuffix("!").stripSuffix("*")
+ def signatureMatch(sym: Symbol): Boolean = externalSignature(sym).startsWith(name)
+
+ // We need to cleanup the bogus classes created by the .class file parser. For example, [[scala.Predef]] resolves
+ // to (bogus) class scala.Predef loaded by the class loader -- which we need to eliminate by looking at the info
+ // and removing NoType classes
+ def cleanupBogusClasses(syms: List[Symbol]) = { syms.filter(_.info != NoType) }
+
+ def syms(name: Name) = container.info.nonPrivateMember(name.encodedName).alternatives
+ def termSyms = cleanupBogusClasses(syms(newTermName(name)))
+ def typeSyms = cleanupBogusClasses(syms(newTypeName(name)))
+
+ val result = if (member.endsWith("$"))
+ termSyms
+ else if (member.endsWith("!"))
+ typeSyms
+ else if (member.endsWith("*"))
+ cleanupBogusClasses(container.info.nonPrivateDecls) filter signatureMatch
+ else
+ if (strategy == BothTypeAndTerm)
+ termSyms ::: typeSyms
+ else if (strategy == OnlyType)
+ typeSyms
+ else if (strategy == OnlyTerm)
+ termSyms
+ else
+ Nil
+
+ //println("lookupInTemplate(" + member + ", " + container + ") => " + 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) != '\\'))) {
+
+ val member = query.substring(last_index, index).replaceAll("\\\\([#\\.])", "$1")
+ // we want to allow javadoc-style links [[#member]] -- which requires us to remove empty members from the first
+ // elemnt in the list
+ if ((member != "") || (!members.isEmpty))
+ members ::= member
+ last_index = index + 1
+ }
+ index += 1
+ }
+ if (last_index < length)
+ members ::= query.substring(last_index, length).replaceAll("\\\\\\.", ".")
+ members.reverse
+ }
+
+
+ def findExternalLink(sym: Symbol, name: String): Option[LinkToExternal] = {
+ val sym1 =
+ if (sym == AnyClass || sym == AnyRefClass || sym == AnyValClass || sym == NothingClass) ListClass
+ else if (sym.isPackage)
+ /* Get package object which has associatedFile ne null */
+ sym.info.member(newTermName("package"))
+ else sym
+ Option(sym1.associatedFile) flatMap (_.underlyingSource) flatMap { src =>
+ val path = src.path
+ settings.extUrlMapping get path map { url =>
+ LinkToExternal(name, url + "#" + name)
+ }
+ } orElse {
+ // Deprecated option.
+ settings.extUrlPackageMapping find {
+ case (pkg, _) => name startsWith pkg
+ } map {
+ case (_, url) => LinkToExternal(name, url + "#" + name)
+ }
+ }
+ }
+
+ def externalSignature(sym: Symbol) = {
+ sym.info // force it, otherwise we see lazy types
+ (sym.nameString + sym.signatureString).replaceAll("\\s", "")
+ }
+}
+
+object MemberLookup {
+ private[this] var _showExplanation = true
+ def showExplanation: Boolean = if (_showExplanation) { _showExplanation = false; true } else false
+}
diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala b/src/compiler/scala/tools/nsc/doc/base/comment/Body.scala
index 3e5e634e18..02e662da85 100644..100755
--- a/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala
+++ b/src/compiler/scala/tools/nsc/doc/base/comment/Body.scala
@@ -5,7 +5,7 @@
package scala.tools.nsc
package doc
-package model
+package base
package comment
import scala.collection._
diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala b/src/compiler/scala/tools/nsc/doc/base/comment/Comment.scala
index 3e172544dd..2b28164ca4 100644
--- a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala
+++ b/src/compiler/scala/tools/nsc/doc/base/comment/Comment.scala
@@ -5,7 +5,7 @@
package scala.tools.nsc
package doc
-package model
+package base
package comment
import scala.collection._
@@ -131,5 +131,4 @@ abstract class Comment {
(authors map ("@author " + _.toString)).mkString("\n") +
(result map ("@return " + _.toString)).mkString("\n") +
(version map ("@version " + _.toString)).mkString
-
}
diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
index e8131e242b..69da322418 100644
--- a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
@@ -7,8 +7,9 @@ package scala.tools.nsc
package doc
package html
+import base._
+import base.comment._
import model._
-import comment._
import scala.xml.{XML, NodeSeq}
import scala.xml.dtd.{DocType, PublicID}
@@ -126,12 +127,12 @@ abstract class HtmlPage extends Page { thisPage =>
}
def linkToHtml(text: Inline, link: LinkTo, hasLinks: Boolean) = link match {
- case LinkToTpl(dtpl) =>
+ case LinkToTpl(dtpl: TemplateEntity) =>
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) =>
+ case LinkToMember(mbr: MemberEntity, inTpl: TemplateEntity) =>
if (hasLinks)
<a href={ relativeLinkTo(inTpl) + "#" + mbr.signature } class="extmbr" name={ mbr.qualifiedName }>{ inlineToHtml(text) }</a>
else
@@ -140,7 +141,7 @@ abstract class HtmlPage extends Page { thisPage =>
<span class="extype" name={ tooltip }>{ inlineToHtml(text) }</span>
case LinkToExternal(name, url) =>
<a href={ url } class="extype" target="_top">{ inlineToHtml(text) }</a>
- case NoLink =>
+ case _ =>
inlineToHtml(text)
}
diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Source.scala b/src/compiler/scala/tools/nsc/doc/html/page/Source.scala
index 807a1bc11a..68289b7474 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/Source.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/Source.scala
@@ -9,7 +9,6 @@ package html
package page
import model._
-import comment._
import scala.xml.{NodeSeq, Unparsed}
import java.io.File
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 008999e09f..e885e9c56e 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
@@ -8,6 +8,9 @@ package doc
package html
package page
+import base._
+import base.comment._
+
import model._
import model.diagram._
import diagram._
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 304c534bdc..847367838c 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
@@ -74,7 +74,7 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator {
def textTypeEntity(text: String) =
new TypeEntity {
val name = text
- def refEntity: SortedMap[Int, (LinkTo, Int)] = SortedMap()
+ def refEntity: SortedMap[Int, (base.LinkTo, Int)] = SortedMap()
}
// it seems dot chokes on node names over 8000 chars, so let's limit the size of the string
diff --git a/src/compiler/scala/tools/nsc/doc/model/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/CommentFactory.scala
new file mode 100644
index 0000000000..9ba89146c0
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/model/CommentFactory.scala
@@ -0,0 +1,114 @@
+/* NSC -- new Scala compiler
+ * Copyright 2007-2013 LAMP/EPFL
+ * @author Manohar Jonnalagedda
+ */
+
+package scala.tools.nsc
+package doc
+package model
+
+import base.comment._
+
+import reporters.Reporter
+import scala.collection._
+import scala.reflect.internal.util.{NoPosition, Position}
+import scala.language.postfixOps
+
+/** The comment parser transforms raw comment strings into `Comment` objects.
+ * Call `parse` to run the parser. Note that the parser is stateless and
+ * should only be built once for a given Scaladoc run.
+ *
+ * @param reporter The reporter on which user messages (error, warnings) should be printed.
+ *
+ * @author Manohar Jonnalagedda
+ * @author Gilles Dubochet */
+trait CommentFactory extends base.CommentFactoryBase {
+ thisFactory: ModelFactory with CommentFactory with MemberLookup =>
+
+ val global: Global
+ import global.{ reporter, definitions, Symbol }
+
+ protected val commentCache = mutable.HashMap.empty[(Symbol, TemplateImpl), Comment]
+
+ def addCommentBody(sym: Symbol, inTpl: TemplateImpl, docStr: String, docPos: global.Position): Symbol = {
+ commentCache += (sym, inTpl) -> parse(docStr, docStr, docPos, None)
+ sym
+ }
+
+ def comment(sym: Symbol, currentTpl: Option[DocTemplateImpl], inTpl: DocTemplateImpl): Option[Comment] = {
+ val key = (sym, inTpl)
+ if (commentCache isDefinedAt key)
+ Some(commentCache(key))
+ else {
+ val c = defineComment(sym, currentTpl, inTpl)
+ if (c isDefined) commentCache += (sym, inTpl) -> c.get
+ c
+ }
+ }
+
+ /** A comment is usualy created by the parser, however for some special
+ * 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: Symbol, currentTpl: Option[DocTemplateImpl], inTpl: DocTemplateImpl):Option[Comment] = {
+
+ //param accessor case
+ // We just need the @param argument, we put it into the body
+ if( sym.isParamAccessor &&
+ inTpl.comment.isDefined &&
+ inTpl.comment.get.valueParams.isDefinedAt(sym.encodedName)) {
+ val comContent = Some(inTpl.comment.get.valueParams(sym.encodedName))
+ Some(createComment(body0 = comContent))
+ }
+
+ // Primary constructor case
+ // We need some content of the class definition : @constructor for the body,
+ // @param and @deprecated, we can add some more if necessary
+ else if (sym.isPrimaryConstructor && inTpl.comment.isDefined ) {
+ val tplComment = inTpl.comment.get
+ // If there is nothing to put into the comment there is no need to create it
+ if(tplComment.constructor.isDefined ||
+ tplComment.throws != Map.empty ||
+ tplComment.valueParams != Map.empty ||
+ tplComment.typeParams != Map.empty ||
+ tplComment.deprecated.isDefined
+ )
+ Some(createComment( body0 = tplComment.constructor,
+ throws0 = tplComment.throws,
+ valueParams0 = tplComment.valueParams,
+ typeParams0 = tplComment.typeParams,
+ deprecated0 = tplComment.deprecated
+ ))
+ else None
+ }
+
+ //other comment cases
+ // parse function will make the comment
+ else {
+ val rawComment = global.expandedDocComment(sym, inTpl.sym).trim
+ if (rawComment != "") {
+ val tplOpt = if (currentTpl.isDefined) currentTpl else Some(inTpl)
+ val c = parse(rawComment, global.rawDocComment(sym), global.docCommentPos(sym), tplOpt)
+ Some(c)
+ }
+ else None
+ }
+
+ }
+
+ protected def parse(comment: String, src: String, pos: Position, inTplOpt: Option[DocTemplateImpl] = None): Comment = {
+ assert(!inTplOpt.isDefined || inTplOpt.get != null)
+ parseAtSymbol(comment, src, pos, inTplOpt map (_.sym))
+ }
+
+ /** Parses a string containing wiki syntax into a `Comment` object.
+ * Note that the string is assumed to be clean:
+ * - Removed Scaladoc start and end markers.
+ * - 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, inTplOpt: Option[DocTemplateImpl]): Body = {
+ assert(!inTplOpt.isDefined || inTplOpt.get != null)
+ parseWikiAtSymbol(string,pos, inTplOpt map (_.sym))
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/doc/model/Entity.scala b/src/compiler/scala/tools/nsc/doc/model/Entity.scala
index c3f9101f17..cbc1a23d44 100644
--- a/src/compiler/scala/tools/nsc/doc/model/Entity.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/Entity.scala
@@ -9,7 +9,7 @@ package doc
package model
import scala.collection._
-import comment._
+import base.comment._
import diagram._
/** An entity in a Scaladoc universe. Entities are declarations in the program and correspond to symbols in the
diff --git a/src/compiler/scala/tools/nsc/doc/model/LinkTo.scala b/src/compiler/scala/tools/nsc/doc/model/LinkTo.scala
deleted file mode 100644
index 6c13d5a6d3..0000000000
--- a/src/compiler/scala/tools/nsc/doc/model/LinkTo.scala
+++ /dev/null
@@ -1,24 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2007-2013 LAMP/EPFL
- */
-
-package scala.tools.nsc
-package doc
-package model
-
-import scala.collection._
-
-abstract sealed class LinkTo
-final case class LinkToTpl(tpl: DocTemplateEntity) extends LinkTo
-final case class LinkToMember(mbr: MemberEntity, inTpl: DocTemplateEntity) extends LinkTo
-final case class Tooltip(name: String) extends LinkTo { def this(tpl: TemplateEntity) = this(tpl.qualifiedName) }
-final case class LinkToExternal(name: String, url: String) extends LinkTo
-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
index 5257db1610..b1105196b7 100644
--- a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala
@@ -2,227 +2,30 @@ package scala.tools.nsc
package doc
package model
-import comment._
-
-import scala.reflect.internal.util.FakePos //Position
+import base._
/** This trait extracts all required information for documentation from compilation units */
-trait MemberLookup {
+trait MemberLookup extends base.MemberLookupBase {
thisFactory: ModelFactory =>
import global._
- import rootMirror.RootPackage, rootMirror.EmptyPackage
-
- 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) First look in the root package, as most of the links are qualified
- val fromRoot = lookupInRootPackage(pos, members)
-
- // (2) Or recursively go into each containing template.
- val fromParents = inTplOpt.fold(Stream.empty[DocTemplateImpl]) { tpl =>
- Stream.iterate(tpl)(_.inTemplate)
- }.takeWhile (tpl => tpl != null && !tpl.isRootPackage).map { tpl =>
- lookupInTemplate(pos, members, tpl.asInstanceOf[EntityImpl].sym)
- }
-
- val syms = (fromRoot +: fromParents) find (!_.isEmpty) getOrElse Nil
- val linkTo = createLinks(syms) match {
- case Nil if !syms.isEmpty =>
- // (3) Look at external links
- syms.flatMap { case (sym, owner) =>
-
- // reconstruct the original link
- def linkName(sym: Symbol) = {
- def isRoot(s: Symbol) = s.isRootSymbol || s.isEmptyPackage || s.isEmptyPackageClass
- def nameString(s: Symbol) = s.nameString + (if ((s.isModule || s.isModuleClass) && !s.isPackage) "$" else "")
- val packageSuffix = if (sym.isPackage) ".package" else ""
- sym.ownerChain.reverse.filterNot(isRoot(_)).map(nameString(_)).mkString(".") + packageSuffix
- }
-
- if (sym.isClass || sym.isModule || sym.isTrait || sym.isPackage)
- findExternalLink(sym, linkName(sym))
- else if (owner.isClass || owner.isModule || owner.isTrait || owner.isPackage)
- findExternalLink(sym, linkName(owner) + "@" + externalSignature(sym))
- else
- None
+ override def internalLink(sym: Symbol, site: Symbol): Option[LinkTo] =
+ findTemplateMaybe(sym) match {
+ case Some(tpl) => Some(LinkToTpl(tpl))
+ case None =>
+ findTemplateMaybe(site) flatMap { inTpl =>
+ inTpl.members find (_.asInstanceOf[EntityImpl].sym == sym) map (LinkToMember(_, inTpl))
}
- case links => links
}
- //println(createLinks(syms))
- //println(linkTo)
-
- // (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
+ override def chooseLink(links: List[LinkTo]): LinkTo = {
+ val mbrs = links.collect {
+ case lm@LinkToMember(mbr: MemberEntity, _) => (mbr, lm)
}
- }
-
- 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, EmptyPackage) ::: lookupInTemplate(pos, members, RootPackage)
-
- private def createLinks(syms: List[(Symbol, Symbol)]): List[LinkTo] =
- syms.flatMap { case (sym, owner) =>
- findTemplateMaybe(sym) match {
- case Some(tpl) => LinkToTpl(tpl) :: Nil
- case None =>
- findTemplateMaybe(owner) flatMap { inTpl =>
- inTpl.members find (_.asInstanceOf[EntityImpl].sym == sym) map (LinkToMember(_, inTpl))
- }
- }
- }
-
- private def lookupInTemplate(pos: Position, members: List[String], container: Symbol): List[(Symbol, Symbol)] = {
- // 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 syms = lookupInTemplate(pos, mbrName, container, OnlyType) map ((_, container))
- if (syms.isEmpty)
- syms = lookupInTemplate(pos, mbrName, container, OnlyTerm) map ((_, container))
- syms
-
- case tplName::rest =>
- def completeSearch(syms: List[Symbol]) =
- syms flatMap (lookupInTemplate(pos, rest, _))
-
- completeSearch(lookupInTemplate(pos, tplName, container, OnlyTerm)) match {
- case Nil => completeSearch(lookupInTemplate(pos, tplName, container, OnlyType))
- case syms => syms
- }
- }
- //println("lookupInTemplate(" + members + ", " + container + ") => " + result)
- result
- }
-
- private def lookupInTemplate(pos: Position, member: String, container: Symbol, strategy: SearchStrategy): List[Symbol] = {
- val name = member.stripSuffix("$").stripSuffix("!").stripSuffix("*")
- def signatureMatch(sym: Symbol): Boolean = externalSignature(sym).startsWith(name)
-
- // We need to cleanup the bogus classes created by the .class file parser. For example, [[scala.Predef]] resolves
- // to (bogus) class scala.Predef loaded by the class loader -- which we need to eliminate by looking at the info
- // and removing NoType classes
- def cleanupBogusClasses(syms: List[Symbol]) = { syms.filter(_.info != NoType) }
-
- def syms(name: Name) = container.info.nonPrivateMember(name.encodedName).alternatives
- def termSyms = cleanupBogusClasses(syms(newTermName(name)))
- def typeSyms = cleanupBogusClasses(syms(newTypeName(name)))
-
- val result = if (member.endsWith("$"))
- termSyms
- else if (member.endsWith("!"))
- typeSyms
- else if (member.endsWith("*"))
- cleanupBogusClasses(container.info.nonPrivateDecls) filter signatureMatch
+ if (mbrs.isEmpty)
+ links.head
else
- if (strategy == BothTypeAndTerm)
- termSyms ::: typeSyms
- else if (strategy == OnlyType)
- typeSyms
- else if (strategy == OnlyTerm)
- termSyms
- else
- Nil
-
- //println("lookupInTemplate(" + member + ", " + container + ") => " + 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) != '\\'))) {
-
- val member = query.substring(last_index, index).replaceAll("\\\\([#\\.])", "$1")
- // we want to allow javadoc-style links [[#member]] -- which requires us to remove empty members from the first
- // elemnt in the list
- if ((member != "") || (!members.isEmpty))
- members ::= member
- last_index = index + 1
- }
- index += 1
- }
- if (last_index < length)
- members ::= query.substring(last_index, length).replaceAll("\\\\\\.", ".")
- members.reverse
+ mbrs.min(Ordering[MemberEntity].on[(MemberEntity, LinkTo)](_._1))._2
}
}
-
-object MemberLookup {
- private[this] var _showExplanation = true
- def showExplanation: Boolean = if (_showExplanation) { _showExplanation = false; true } else false
-}
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
index 8ced574676..ea074873e8 100644
--- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
@@ -4,8 +4,8 @@ package scala.tools.nsc
package doc
package model
-import comment._
-
+import base._
+import base.comment._
import diagram._
import scala.collection._
@@ -1094,31 +1094,12 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
{ val rawComment = global.expandedDocComment(bSym, inTpl.sym)
rawComment.contains("@template") || rawComment.contains("@documentable") }
- def findExternalLink(sym: Symbol, name: String): Option[LinkTo] = {
- val sym1 =
- if (sym == AnyClass || sym == AnyRefClass || sym == AnyValClass || sym == NothingClass) ListClass
- else if (sym.isPackage)
- /* Get package object which has associatedFile ne null */
- sym.info.member(newTermName("package"))
- else sym
- Option(sym1.associatedFile) flatMap (_.underlyingSource) flatMap { src =>
- val path = src.path
- settings.extUrlMapping get path map { url =>
- LinkToExternal(name, url + "#" + name)
- }
- } orElse {
- // Deprecated option.
- settings.extUrlPackageMapping find {
- case (pkg, _) => name startsWith pkg
- } map {
- case (_, url) => LinkToExternal(name, url + "#" + name)
- }
+ object LinkToTpl {
+ // this makes it easier to create links
+ def apply(tpl: TemplateEntity): LinkTo = tpl match {
+ case dtpl: DocTemplateEntity => new LinkToTpl(dtpl)
+ case _ => new Tooltip(tpl.qualifiedName)
}
}
-
- def externalSignature(sym: Symbol) = {
- sym.info // force it, otherwise we see lazy types
- (sym.nameString + sym.signatureString).replaceAll("\\s", "")
- }
}
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala
index 5334de3797..f88251b22e 100644
--- a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala
@@ -10,8 +10,6 @@ package scala.tools.nsc
package doc
package model
-import comment._
-
import scala.collection._
import scala.util.matching.Regex
@@ -608,4 +606,4 @@ trait ModelFactoryImplicitSupport {
false
} else true // the member structure is different foo(3, 5) vs foo(3)(5)
}
-} \ No newline at end of file
+}
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala
index 942ccaf1ba..87dc615c8e 100644
--- a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala
@@ -4,8 +4,7 @@ package scala.tools.nsc
package doc
package model
-import comment._
-
+import base._
import diagram._
import scala.collection._
@@ -24,7 +23,8 @@ trait ModelFactoryTypeSupport {
with ModelFactoryTypeSupport
with DiagramFactory
with CommentFactory
- with TreeFactory =>
+ with TreeFactory
+ with MemberLookup =>
import global._
import definitions.{ ObjectClass, NothingClass, AnyClass, AnyValClass, AnyRefClass }
diff --git a/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala b/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala
index e4a053e115..cf5c1fb3fb 100644
--- a/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala
@@ -20,7 +20,7 @@ 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, (LinkTo, Int)]
+ def refEntity: SortedMap[Int, (base.LinkTo, Int)]
/** The human-readable representation of this type. */
override def toString = name
diff --git a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala
index 49cfaffc2e..cd60865ce7 100644
--- a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala
@@ -3,7 +3,6 @@ package model
package diagram
import model._
-import comment.CommentFactory
import java.util.regex.{Pattern, Matcher}
import scala.util.matching.Regex
@@ -259,4 +258,4 @@ trait DiagramDirectiveParser {
result
}
-} \ No newline at end of file
+}
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 db2d0c0175..175b4a6472 100644
--- a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala
@@ -3,7 +3,6 @@ package model
package diagram
import model._
-import comment.CommentFactory
import scala.collection.mutable
// statistics
@@ -25,7 +24,7 @@ trait DiagramFactory extends DiagramDirectiveParser {
// the following can used for hardcoding different relations into the diagram, for bootstrapping purposes
def aggregationNode(text: String) =
- NormalNode(new TypeEntity { val name = text; val refEntity = SortedMap[Int, (LinkTo, Int)]() }, None)()
+ NormalNode(new TypeEntity { val name = text; val refEntity = SortedMap[Int, (base.LinkTo, Int)]() }, None)()
/** Create the inheritance diagram for this template */
def makeInheritanceDiagram(tpl: DocTemplateImpl): Option[Diagram] = {
diff --git a/src/compiler/scala/tools/nsc/interactive/Doc.scala b/src/compiler/scala/tools/nsc/interactive/Doc.scala
new file mode 100755
index 0000000000..4d02de6198
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interactive/Doc.scala
@@ -0,0 +1,50 @@
+/* NSC -- new Scala compiler
+ * Copyright 2007-2012 LAMP/EPFL
+ * @author Eugene Vigdorchik
+ */
+
+package scala.tools.nsc
+package interactive
+
+import doc.base._
+import comment._
+import scala.xml.NodeSeq
+
+sealed trait DocResult
+final case class UrlResult(url: String) extends DocResult
+final case class HtmlResult(comment: Comment) extends DocResult
+
+abstract class Doc(val settings: doc.Settings) extends MemberLookupBase with CommentFactoryBase {
+
+ override val global: interactive.Global
+ import global._
+
+ def chooseLink(links: List[LinkTo]): LinkTo
+
+ override def internalLink(sym: Symbol, site: Symbol): Option[LinkTo] =
+ ask { () =>
+ if (sym.isClass || sym.isModule)
+ Some(LinkToTpl(sym))
+ else
+ if ((site.isClass || site.isModule) && site.info.members.toList.contains(sym))
+ Some(LinkToMember(sym, site))
+ else
+ None
+ }
+
+ def retrieve(sym: Symbol, site: Symbol): Option[DocResult] = {
+ val sig = ask { () => externalSignature(sym) }
+ findExternalLink(sym, sig) map { link => UrlResult(link.url) } orElse {
+ val resp = new Response[Tree]
+ // Ensure docComment tree is type-checked.
+ val pos = ask { () => docCommentPos(sym) }
+ askTypeAt(pos, resp)
+ resp.get.left.toOption flatMap { _ =>
+ ask { () =>
+ val comment = parseAtSymbol(expandedDocComment(sym), rawDocComment(sym), pos, Some(site))
+ Some(HtmlResult(comment))
+ }
+ }
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index 2ab389445f..0fc4fcaaf7 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -74,6 +74,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
if (verboseIDE) println("[%s][%s]".format(projectName, msg))
override def forInteractive = true
+ override def forScaladoc = settings.isScaladoc
/** A map of all loaded files to the rich compilation units that correspond to them.
*/
diff --git a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala
index 5c1837b3bf..ea2333a65b 100644
--- a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala
+++ b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala
@@ -8,6 +8,7 @@ import scala.reflect.internal.util.Position
/** Trait encapsulating the creation of a presentation compiler's instance.*/
private[tests] trait PresentationCompilerInstance extends TestSettings {
protected val settings = new Settings
+ protected def docSettings: doc.Settings = new doc.Settings(_ => ())
protected val compilerReporter: CompilerReporter = new InteractiveReporter {
override def compiler = PresentationCompilerInstance.this.compiler
}
@@ -28,4 +29,4 @@ private[tests] trait PresentationCompilerInstance extends TestSettings {
reporter.println("\tbootClassPath: %s".format(settings.bootclasspath.value))
reporter.println("\tverbose: %b".format(settings.verbose.value))
}
-} \ No newline at end of file
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 83ded04c39..76fd07f63a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -48,6 +48,7 @@ trait Typers extends Modes with Adaptations with Tags {
resetContexts()
resetImplicits()
transformed.clear()
+ clearDocComments()
}
object UnTyper extends Traverser {
@@ -5261,8 +5262,8 @@ trait Typers extends Modes with Adaptations with Tags {
}
def typedDocDef(docdef: DocDef) = {
- val comment = docdef.comment
if (forScaladoc && (sym ne null) && (sym ne NoSymbol)) {
+ val comment = docdef.comment
docComments(sym) = comment
comment.defineVariables(sym)
val typer1 = newTyper(context.makeNewScope(tree, context.owner))
diff --git a/src/partest/scala/tools/partest/ScaladocModelTest.scala b/src/partest/scala/tools/partest/ScaladocModelTest.scala
index e7134d0271..b9abff69d8 100644
--- a/src/partest/scala/tools/partest/ScaladocModelTest.scala
+++ b/src/partest/scala/tools/partest/ScaladocModelTest.scala
@@ -12,7 +12,7 @@ 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.doc.base.comment._
import scala.tools.nsc.reporters.ConsoleReporter
/** A class for testing scaladoc model generation
diff --git a/test/files/presentation/doc.check b/test/files/presentation/doc.check
new file mode 100755
index 0000000000..62b3bfc2e3
--- /dev/null
+++ b/test/files/presentation/doc.check
@@ -0,0 +1,48 @@
+body:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This is a test comment), Text(.)))), Text(
+))))))
+@example:Body(List(Paragraph(Chain(List(Summary(Monospace(Text("abb".permutations = Iterator(abb, bab, bba)))))))))
+@version:
+@since:
+@todo:
+@note:
+@see:
+body:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This is a test comment), Text(.)))), Text(
+))))))
+@example:Body(List(Paragraph(Chain(List(Summary(Monospace(Text("abb".permutations = Iterator(abb, bab, bba)))))))))
+@version:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(1), Text(.)))), Text(0, 09/07/2012))))))
+@since:
+@todo:
+@note:
+@see:
+body:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This is a test comment), Text(.)))), Text(
+))))))
+@example:Body(List(Paragraph(Chain(List(Summary(Monospace(Text("abb".permutations = Iterator(abb, bab, bba)))))))))
+@version:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(1), Text(.)))), Text(0, 09/07/2012))))))
+@since:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(2), Text(.)))), Text(10))))))
+@todo:
+@note:
+@see:
+body:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This is a test comment), Text(.)))), Text(
+))))))
+@example:Body(List(Paragraph(Chain(List(Summary(Monospace(Text("abb".permutations = Iterator(abb, bab, bba)))))))))
+@version:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(1), Text(.)))), Text(0, 09/07/2012))))))
+@since:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(2), Text(.)))), Text(10))))))
+@todo:Body(List(Paragraph(Chain(List(Summary(Text(this method is unsafe)))))))
+@note:
+@see:
+body:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This is a test comment), Text(.)))), Text(
+))))))
+@example:Body(List(Paragraph(Chain(List(Summary(Monospace(Text("abb".permutations = Iterator(abb, bab, bba)))))))))
+@version:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(1), Text(.)))), Text(0, 09/07/2012))))))
+@since:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(2), Text(.)))), Text(10))))))
+@todo:Body(List(Paragraph(Chain(List(Summary(Text(this method is unsafe)))))))
+@note:Body(List(Paragraph(Chain(List(Summary(Text(Don't inherit!)))))))
+@see:
+body:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This is a test comment), Text(.)))), Text(
+))))))
+@example:Body(List(Paragraph(Chain(List(Summary(Monospace(Text("abb".permutations = Iterator(abb, bab, bba)))))))))
+@version:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(1), Text(.)))), Text(0, 09/07/2012))))))
+@since:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(2), Text(.)))), Text(10))))))
+@todo:Body(List(Paragraph(Chain(List(Summary(Text(this method is unsafe)))))))
+@note:Body(List(Paragraph(Chain(List(Summary(Text(Don't inherit!)))))))
+@see:Body(List(Paragraph(Chain(List(Summary(Text(some other method)))))))
diff --git a/test/files/presentation/doc.scala b/test/files/presentation/doc.scala
new file mode 100755
index 0000000000..4b0d6baa1f
--- /dev/null
+++ b/test/files/presentation/doc.scala
@@ -0,0 +1,71 @@
+import scala.tools.nsc.doc
+import scala.tools.nsc.doc.base.LinkTo
+import scala.tools.nsc.doc.base.comment._
+import scala.tools.nsc.interactive._
+import scala.tools.nsc.interactive.tests._
+import scala.tools.nsc.util._
+import scala.tools.nsc.io._
+
+object Test extends InteractiveTest {
+ override val settings: doc.Settings = docSettings
+
+ val tags = Seq(
+ "@example `\"abb\".permutations = Iterator(abb, bab, bba)`",
+ "@version 1.0, 09/07/2012",
+ "@since 2.10",
+ "@todo this method is unsafe",
+ "@note Don't inherit!",
+ "@see some other method"
+ )
+
+ val comment = "This is a test comment."
+ val caret = "<caret>"
+
+ def text(nTags: Int) =
+ """|/** %s
+ |
+ | * %s */
+ |trait Commented {}
+ |class User(c: %sCommented)""".stripMargin.format(comment, tags take nTags mkString "\n", caret)
+
+ override def main(args: Array[String]) {
+ val documenter = new Doc(settings) {
+ val global: compiler.type = compiler
+
+ def chooseLink(links: List[LinkTo]): LinkTo = links.head
+ }
+ for (i <- 1 to tags.length) {
+ val markedText = text(i)
+ val idx = markedText.indexOf(caret)
+ val fileText = markedText.substring(0, idx) + markedText.substring(idx + caret.length)
+ val source = sourceFiles(0)
+ val batch = new BatchSourceFile(source.file, fileText.toCharArray)
+ val reloadResponse = new Response[Unit]
+ compiler.askReload(List(batch), reloadResponse)
+ reloadResponse.get.left.toOption match {
+ case None =>
+ reporter.println("Couldn't reload")
+ case Some(_) =>
+ val treeResponse = new compiler.Response[compiler.Tree]
+ val pos = compiler.rangePos(batch, idx, idx, idx)
+ compiler.askTypeAt(pos, treeResponse)
+ treeResponse.get.left.toOption match {
+ case Some(tree) =>
+ val sym = tree.tpe.typeSymbol
+ documenter.retrieve(sym, sym.owner) match {
+ case Some(HtmlResult(comment)) =>
+ import comment._
+ val tags: List[(String, Iterable[Body])] =
+ List(("@example", example), ("@version", version), ("@since", since.toList), ("@todo", todo), ("@note", note), ("@see", see))
+ val str = ("body:" + body + "\n") +
+ tags.map{ case (name, bodies) => name + ":" + bodies.mkString("\n") }.mkString("\n")
+ reporter.println(str)
+ case Some(_) => reporter.println("Got unexpected result")
+ case None => reporter.println("Got no result")
+ }
+ case None => reporter.println("Couldn't find a typedTree")
+ }
+ }
+ }
+ }
+}
diff --git a/test/files/presentation/doc/src/Test.scala b/test/files/presentation/doc/src/Test.scala
new file mode 100755
index 0000000000..fcc1554994
--- /dev/null
+++ b/test/files/presentation/doc/src/Test.scala
@@ -0,0 +1 @@
+object Test \ No newline at end of file
diff --git a/test/files/presentation/memory-leaks/MemoryLeaksTest.scala b/test/files/presentation/memory-leaks/MemoryLeaksTest.scala
index a5533a623a..159097cc10 100644
--- a/test/files/presentation/memory-leaks/MemoryLeaksTest.scala
+++ b/test/files/presentation/memory-leaks/MemoryLeaksTest.scala
@@ -5,6 +5,7 @@ import java.util.Calendar
import scala.tools.nsc.interactive.tests._
import scala.tools.nsc.util._
import scala.tools.nsc.io._
+import scala.tools.nsc.doc
/** This test runs the presentation compiler on the Scala compiler project itself and records memory consumption.
*
@@ -24,6 +25,8 @@ import scala.tools.nsc.io._
object Test extends InteractiveTest {
final val mega = 1024 * 1024
+ override val settings: doc.Settings = docSettings
+
override def execute(): Unit = memoryConsumptionTest()
def batchSource(name: String) =
@@ -120,4 +123,4 @@ object Test extends InteractiveTest {
r.totalMemory() - r.freeMemory()
}
-} \ No newline at end of file
+}
diff --git a/test/scaladoc/run/SI-191-deprecated.scala b/test/scaladoc/run/SI-191-deprecated.scala
index 746aa9c598..4ed24ff8d1 100755
--- a/test/scaladoc/run/SI-191-deprecated.scala
+++ b/test/scaladoc/run/SI-191-deprecated.scala
@@ -1,5 +1,6 @@
import scala.tools.nsc.doc.model._
-import scala.tools.nsc.doc.model.comment._
+import scala.tools.nsc.doc.base._
+import scala.tools.nsc.doc.base.comment._
import scala.tools.partest.ScaladocModelTest
import java.net.{URI, URL}
import java.io.File
diff --git a/test/scaladoc/run/SI-191.scala b/test/scaladoc/run/SI-191.scala
index 0fb28145c3..6fb5339d66 100755
--- a/test/scaladoc/run/SI-191.scala
+++ b/test/scaladoc/run/SI-191.scala
@@ -1,5 +1,6 @@
import scala.tools.nsc.doc.model._
-import scala.tools.nsc.doc.model.comment._
+import scala.tools.nsc.doc.base._
+import scala.tools.nsc.doc.base.comment._
import scala.tools.partest.ScaladocModelTest
import java.net.{URI, URL}
import java.io.File
diff --git a/test/scaladoc/run/SI-3314.scala b/test/scaladoc/run/SI-3314.scala
index fe220b08af..c856fe46a8 100644
--- a/test/scaladoc/run/SI-3314.scala
+++ b/test/scaladoc/run/SI-3314.scala
@@ -1,3 +1,4 @@
+import scala.tools.nsc.doc.base._
import scala.tools.nsc.doc.model._
import scala.tools.partest.ScaladocModelTest
@@ -88,4 +89,4 @@ object Test extends ScaladocModelTest {
assert(bar.valueParams(0)(0).resultType.name == "(AnyRef { type Lambda[X] <: Either[A,X] })#Lambda[String]",
bar.valueParams(0)(0).resultType.name + " == (AnyRef { type Lambda[X] <: Either[A,X] })#Lambda[String]")
}
-} \ No newline at end of file
+}
diff --git a/test/scaladoc/run/SI-5235.scala b/test/scaladoc/run/SI-5235.scala
index 6295fc7786..c6b7922bb8 100644
--- a/test/scaladoc/run/SI-5235.scala
+++ b/test/scaladoc/run/SI-5235.scala
@@ -1,3 +1,4 @@
+import scala.tools.nsc.doc.base._
import scala.tools.nsc.doc.model._
import scala.tools.nsc.doc.model.diagram._
import scala.tools.partest.ScaladocModelTest
@@ -84,4 +85,4 @@ object Test extends ScaladocModelTest {
assert(mcReverseType.refEntity(0)._1 == LinkToTpl(MyCollection),
mcReverse.qualifiedName + "'s return type has a link to " + MyCollection.qualifiedName)
}
-} \ No newline at end of file
+}
diff --git a/test/scaladoc/run/links.scala b/test/scaladoc/run/links.scala
index 0c67857e1c..fde24edb2a 100644
--- a/test/scaladoc/run/links.scala
+++ b/test/scaladoc/run/links.scala
@@ -1,3 +1,4 @@
+import scala.tools.nsc.doc.base._
import scala.tools.nsc.doc.model._
import scala.tools.partest.ScaladocModelTest
@@ -23,9 +24,9 @@ object Test extends ScaladocModelTest {
val base = rootPackage._package("scala")._package("test")._package("scaladoc")._package("links")
val TEST = base._object("TEST")
- val memberLinks = countLinks(TEST.comment.get, _.link.isInstanceOf[LinkToMember])
- val templateLinks = countLinks(TEST.comment.get, _.link.isInstanceOf[LinkToTpl])
+ val memberLinks = countLinks(TEST.comment.get, _.link.isInstanceOf[LinkToMember[_, _]])
+ val templateLinks = countLinks(TEST.comment.get, _.link.isInstanceOf[LinkToTpl[_]])
assert(memberLinks == 17, memberLinks + " == 17 (the member links in object TEST)")
assert(templateLinks == 6, templateLinks + " == 6 (the template links in object TEST)")
}
-} \ No newline at end of file
+}
diff --git a/test/scaladoc/scalacheck/CommentFactoryTest.scala b/test/scaladoc/scalacheck/CommentFactoryTest.scala
index 5e3141bdc0..96174d29d1 100644
--- a/test/scaladoc/scalacheck/CommentFactoryTest.scala
+++ b/test/scaladoc/scalacheck/CommentFactoryTest.scala
@@ -3,8 +3,7 @@ import org.scalacheck.Prop._
import scala.tools.nsc.Global
import scala.tools.nsc.doc
-import scala.tools.nsc.doc.model._
-import scala.tools.nsc.doc.model.comment._
+import scala.tools.nsc.doc.base.comment._
import scala.tools.nsc.doc.model._
import scala.tools.nsc.doc.model.diagram._