summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-12-20 12:58:03 -0800
committerPaul Phillips <paulp@improving.org>2012-12-20 14:47:50 -0800
commit106ca1b6767c60912b6726eeb1d435f6e22a025f (patch)
treec3c4c9a0d988720973b69f196c04e781e6e3f767 /src
parenta313fa1d2c03d49fa7bc2a5f9c1886c48e08aab6 (diff)
parent9ddb4cf41f9832e46fa1109d96fc6708c4586c53 (diff)
downloadscala-106ca1b6767c60912b6726eeb1d435f6e22a025f.tar.gz
scala-106ca1b6767c60912b6726eeb1d435f6e22a025f.tar.bz2
scala-106ca1b6767c60912b6726eeb1d435f6e22a025f.zip
Merge remote-tracking branch 'origin/2.10.x' into merge-2.10.x
* origin/2.10.x: (31 commits) Implicit vars should have non-implicit setters. Deprecate `scala.tools.nsc.Phases` because it's dead-code. scaladoc Template: remove duplicate code and several usages of Option.get. adds scala-reflect.jar to MIMA in ant Test showing the absence of a forward reference update mailmap Remove dead code from `Global`. Cleanup MemberLookup. Better explain ambiguous link targets. typedIdent no longer destroys attachments fixes incorrect handling of Annotated in lazy copier simplifies checkBounds Recurse into instantiations when stripping type vars. Extract base scaladoc functionality for the IDE. Expand pattern match position tests. SI-6288 Remedy ill-positioned extractor binding. SI-6288 Fix positioning of label jumps SI-6288 Position argument of unapply Fixes SI-6758: force LazyAnnnotationInfo for DefDef and TypeDef SI-6795 Simplify errors related to "abstract override" on type members SI-6795 Adds negative check for "abstract override" on types in traits ... Conflicts: .mailmap src/compiler/scala/tools/nsc/Global.scala src/compiler/scala/tools/nsc/ast/DocComments.scala src/compiler/scala/tools/nsc/doc/base/CommentFactoryBase.scala src/compiler/scala/tools/nsc/doc/html/page/Source.scala src/compiler/scala/tools/nsc/doc/html/page/Template.scala src/compiler/scala/tools/nsc/doc/model/LinkTo.scala src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala src/compiler/scala/tools/nsc/typechecker/Typers.scala src/reflect/scala/reflect/runtime/JavaMirrors.scala test/scaladoc/run/links.scala
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/Driver.scala6
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala75
-rw-r--r--src/compiler/scala/tools/nsc/Phases.scala1
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/DocComments.scala44
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala7
-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)94
-rwxr-xr-xsrc/compiler/scala/tools/nsc/doc/base/LinkTo.scala15
-rwxr-xr-xsrc/compiler/scala/tools/nsc/doc/base/MemberLookupBase.scala229
-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/Template.scala144
-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.scala22
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala226
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala31
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala11
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala1
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala3
-rwxr-xr-xsrc/compiler/scala/tools/nsc/interactive/Doc.scala59
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala1
-rw-r--r--src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala5
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala32
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala12
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala36
-rw-r--r--src/partest/scala/tools/partest/DirectTest.scala4
-rw-r--r--src/partest/scala/tools/partest/ScaladocModelTest.scala2
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala5
-rw-r--r--src/reflect/scala/reflect/internal/Flags.scala2
-rw-r--r--src/reflect/scala/reflect/internal/StdAttachments.scala1
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala4
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala19
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolLoaders.scala8
46 files changed, 723 insertions, 555 deletions
diff --git a/src/compiler/scala/tools/nsc/Driver.scala b/src/compiler/scala/tools/nsc/Driver.scala
index b5fd20e1cc..fc247600f6 100644
--- a/src/compiler/scala/tools/nsc/Driver.scala
+++ b/src/compiler/scala/tools/nsc/Driver.scala
@@ -54,10 +54,10 @@ abstract class Driver {
doCompile(compiler)
} catch {
case ex: Throwable =>
- compiler.logThrowable(ex)
+ compiler.reportThrowable(ex)
ex match {
- case FatalError(msg) => reporter.error(null, "fatal error: " + msg)
- case _ => throw ex
+ case FatalError(msg) => // signals that we should fail compilation.
+ case _ => throw ex // unexpected error, tell the outside world.
}
}
}
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 34d5d10cbf..75f38c7d67 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -284,7 +284,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
log(msg)
}
- def logThrowable(t: Throwable): Unit = globalError(throwableAsString(t))
+ @deprecated("Renamed to reportThrowable", "2.10.1")
+ def logThrowable(t: Throwable): Unit = reportThrowable(t)
+ def reportThrowable(t: Throwable): Unit = globalError(throwableAsString(t))
override def throwableAsString(t: Throwable) = util.stackTraceString(t)
// ------------ File interface -----------------------------------------
@@ -709,7 +711,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
/* The set of phase objects that is the basis for the compiler phase chain */
protected lazy val phasesSet = new mutable.HashSet[SubComponent]
protected lazy val phasesDescMap = new mutable.HashMap[SubComponent, String] withDefaultValue ""
- private lazy val phaseTimings = new Phases.TimingModel // tracking phase stats
protected def addToPhasesSet(sub: SubComponent, descr: String) {
phasesSet += sub
@@ -1038,37 +1039,41 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
/** Don't want to introduce new errors trying to report errors,
* so swallow exceptions.
*/
- override def supplementErrorMessage(errorMessage: String): String = try {
- val tree = analyzer.lastTreeToTyper
- val sym = tree.symbol
- val tpe = tree.tpe
- val enclosing = lastSeenContext.enclClassOrMethod.tree
-
- val info1 = formatExplain(
- "while compiling" -> currentSource.path,
- "during phase" -> ( if (globalPhase eq phase) phase else "global=%s, enteringPhase=%s".format(globalPhase, phase) ),
- "library version" -> scala.util.Properties.versionString,
- "compiler version" -> Properties.versionString,
- "reconstructed args" -> settings.recreateArgs.mkString(" ")
- )
- val info2 = formatExplain(
- "last tree to typer" -> tree.summaryString,
- "symbol" -> Option(sym).fold("null")(_.debugLocationString),
- "symbol definition" -> Option(sym).fold("null")(_.defString),
- "tpe" -> tpe,
- "symbol owners" -> ownerChainString(sym),
- "context owners" -> ownerChainString(lastSeenContext.owner)
- )
- val info3: List[String] = (
- ( List("== Enclosing template or block ==", nodePrinters.nodeToString(enclosing).trim) )
- ++ ( if (tpe eq null) Nil else List("== Expanded type of tree ==", typeDeconstruct.show(tpe)) )
- ++ ( if (!settings.debug.value) Nil else List("== Current unit body ==", nodePrinters.nodeToString(currentUnit.body)) )
- ++ ( List(errorMessage) )
- )
-
- ("\n" + info1) :: info2 :: info3 mkString "\n\n"
- }
- catch { case x: Exception => errorMessage }
+ override def supplementErrorMessage(errorMessage: String): String =
+ if (currentRun.supplementedError) errorMessage
+ else try {
+ val tree = analyzer.lastTreeToTyper
+ val sym = tree.symbol
+ val tpe = tree.tpe
+ val enclosing = lastSeenContext.enclClassOrMethod.tree
+
+ val info1 = formatExplain(
+ "while compiling" -> currentSource.path,
+ "during phase" -> ( if (globalPhase eq phase) phase else "global=%s, enteringPhase=%s".format(globalPhase, phase) ),
+ "library version" -> scala.util.Properties.versionString,
+ "compiler version" -> Properties.versionString,
+ "reconstructed args" -> settings.recreateArgs.mkString(" ")
+ )
+ val info2 = formatExplain(
+ "last tree to typer" -> tree.summaryString,
+ "symbol" -> Option(sym).fold("null")(_.debugLocationString),
+ "symbol definition" -> Option(sym).fold("null")(_.defString),
+ "tpe" -> tpe,
+ "symbol owners" -> ownerChainString(sym),
+ "context owners" -> ownerChainString(lastSeenContext.owner)
+ )
+ val info3: List[String] = (
+ ( List("== Enclosing template or block ==", nodePrinters.nodeToString(enclosing).trim) )
+ ++ ( if (tpe eq null) Nil else List("== Expanded type of tree ==", typeDeconstruct.show(tpe)) )
+ ++ ( if (!settings.debug.value) Nil else List("== Current unit body ==", nodePrinters.nodeToString(currentUnit.body)) )
+ ++ ( List(errorMessage) )
+ )
+
+ currentRun.supplementedError = true
+
+ ("\n" + info1) :: info2 :: info3 mkString "\n\n"
+ }
+ catch { case x: Exception => errorMessage }
/** The id of the currently active run
*/
@@ -1122,6 +1127,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
/** Has any macro expansion used a fallback during this run? */
var seenMacroExpansionsFallingBack = false
+ /** Have we already supplemented the error message of a compiler crash? */
+ private[nsc] final var supplementedError = false
+
private val unitbuf = new mutable.ListBuffer[CompilationUnit]
val compiledFiles = new mutable.HashSet[String]
@@ -1478,7 +1486,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
// progress update
informTime(globalPhase.description, startTime)
- phaseTimings(globalPhase) = currentTime - startTime
val shouldWriteIcode = (
(settings.writeICode.isSetByUser && (settings.writeICode containsPhase globalPhase))
|| (!settings.Xprint.doAllPhases && (settings.Xprint containsPhase globalPhase) && runIsAtOptimiz)
diff --git a/src/compiler/scala/tools/nsc/Phases.scala b/src/compiler/scala/tools/nsc/Phases.scala
index 1266622b6d..e379afce9b 100644
--- a/src/compiler/scala/tools/nsc/Phases.scala
+++ b/src/compiler/scala/tools/nsc/Phases.scala
@@ -8,6 +8,7 @@ package scala.tools.nsc
import scala.reflect.internal.util.TableDef
import scala.language.postfixOps
+@deprecated("Scheduled for removal as being a dead-code in the compiler.", "2.10.1")
object Phases {
val MaxPhases = 64
diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala
index 023f3c229c..c9bf131b79 100755
--- a/src/compiler/scala/tools/nsc/ast/DocComments.scala
+++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala
@@ -16,11 +16,22 @@ 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))
+ docComments += (sym -> DocComment(docStr, pos))
+
/** The raw doc comment of symbol `sym`, as it appears in the source text, "" if missing.
*/
def rawDocComment(sym: Symbol): String =
@@ -47,25 +58,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/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
index 34bdc1ede4..24c18e6530 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -308,7 +308,12 @@ trait BasicBlocks {
else
instrs.zipWithIndex collect {
case (oldInstr, i) if map contains oldInstr =>
- code.touched |= replaceInstruction(i, map(oldInstr))
+ // SI-6288 clone important here because `replaceInstruction` assigns
+ // a position to `newInstr`. Without this, a single instruction can
+ // be added twice, and the position last position assigned clobbers
+ // all previous positions in other usages.
+ val newInstr = map(oldInstr).clone()
+ code.touched |= replaceInstruction(i, newInstr)
}
////////////////////// Emit //////////////////////
diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala
index a091bc3e62..77e53bd90b 100644
--- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala
@@ -78,7 +78,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 c798def4cb..30f33e48c9 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 scala.collection._
import scala.util.matching.Regex
import scala.reflect.internal.util.Position
@@ -21,73 +21,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 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, Symbol }
/* Creates comments with necessary arguments */
def createComment (
@@ -251,9 +188,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] = {
@@ -379,7 +314,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 {
@@ -412,7 +347,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")),
@@ -452,20 +387,14 @@ 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 = {
@@ -752,6 +681,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member
val SchemeUri = """([a-z]+:.*)""".r
jump("[[")
val parens = 2 + repeatJump('[')
+ val start = "[" * parens
val stop = "]" * parens
//println("link with " + parens + " matching parens")
val target = readUntil { check(stop) || check(" ") }
@@ -767,7 +697,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)
}
}
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..35390adcd9
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/base/MemberLookupBase.scala
@@ -0,0 +1,229 @@
+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
+ def toString(link: LinkTo): String
+
+ 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) }
+
+ private var showExplanation = true
+ private def explanation: String =
+ if (showExplanation) {
+ showExplanation = false
+ """
+ |Quick crash course on using Scaladoc links
+ |==========================================
+ |Disambiguating terms and types: Prefix terms with '$' and types with '!' in case both names are in use:
+ | - [[scala.collection.immutable.List!.apply class List's apply method]] and
+ | - [[scala.collection.immutable.List$.apply object List's apply method]]
+ |Disambiguating overloaded members: If a term is overloaded, you can indicate the first part of its signature followed by *:
+ | - [[[scala.collection.immutable.List$.fill[A](Int)(⇒A):List[A]* Fill with a single parameter]]]
+ | - [[[scala.collection.immutable.List$.fill[A](Int,Int)(⇒A):List[List[A]]* Fill with a two parameters]]]
+ |Notes:
+ | - you can use any number of matching square brackets to avoid interference with the signature
+ | - you can use \\. to escape dots in prefixes (don't forget to use * at the end to match the signature!)
+ | - you can use \\# to escape hashes, otherwise they will be considered as delimiters, like dots.""".stripMargin
+ } else ""
+
+ 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 ""
+ toString(link) + chosenInfo + "\n"
+ }
+ if (!settings.docNoLinkWarnings.value) {
+ val allLinks = links.map(linkToString).mkString
+ reporter.warning(pos,
+ s"""The link target \"$query\" is ambiguous. Several members fit the target:
+ |$allLinks
+ |$explanation""".stripMargin)
+ }
+ chosen
+ }
+ }
+
+ private sealed trait SearchStrategy
+ private case object BothTypeAndTerm extends SearchStrategy
+ private case object OnlyType extends SearchStrategy
+ private case 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
+ strategy match {
+ case BothTypeAndTerm => termSyms ::: typeSyms
+ case OnlyType => typeSyms
+ case OnlyTerm => termSyms
+ }
+
+ //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", "")
+ }
+}
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 8848af95eb..2a07547de2 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 736727fc1a..a3d05ae50b 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._
@@ -128,5 +128,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 c898348526..829df97fc2 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.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/Template.scala b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
index 3f40e2cd0a..ff64fb4c0f 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,11 @@ package doc
package html
package page
+import base._
+import base.comment._
+
+import model._
+import model.diagram._
import scala.xml.{ NodeSeq, Text, UnprefixedAttribute }
import scala.language.postfixOps
@@ -328,12 +333,10 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
}
- def memberToShortCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq = {
- if (mbr.comment.isEmpty)
- NodeSeq.Empty
- else
- <p class="shortcomment cmt">{ memberToUseCaseCommentHtml(mbr, isSelf) }{ inlineToHtml(mbr.comment.get.short) }</p>
- }
+ def memberToShortCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq =
+ mbr.comment.fold(NodeSeq.Empty) { comment =>
+ <p class="shortcomment cmt">{ memberToUseCaseCommentHtml(mbr, isSelf) }{ inlineToHtml(comment.short) }</p>
+ }
def memberToInlineCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq =
<p class="comment cmt">{ inlineToHtml(mbr.comment.get.short) }</p>
@@ -354,37 +357,34 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
case _ => Nil
}
- def mbrCmt = mbr.comment.get
-
- def paramCommentToHtml(prs: List[ParameterEntity]): NodeSeq = prs match {
+ def paramCommentToHtml(prs: List[ParameterEntity], comment: Comment): NodeSeq = prs match {
case (tp: TypeParam) :: rest =>
val paramEntry: NodeSeq = {
- <dt class="tparam">{ tp.name }</dt><dd class="cmt">{ bodyToHtml(mbrCmt.typeParams(tp.name)) }</dd>
+ <dt class="tparam">{ tp.name }</dt><dd class="cmt">{ bodyToHtml(comment.typeParams(tp.name)) }</dd>
}
- paramEntry ++ paramCommentToHtml(rest)
+ paramEntry ++ paramCommentToHtml(rest, comment)
case (vp: ValueParam) :: rest =>
val paramEntry: NodeSeq = {
- <dt class="param">{ vp.name }</dt><dd class="cmt">{ bodyToHtml(mbrCmt.valueParams(vp.name)) }</dd>
+ <dt class="param">{ vp.name }</dt><dd class="cmt">{ bodyToHtml(comment.valueParams(vp.name)) }</dd>
}
- paramEntry ++ paramCommentToHtml(rest)
+ paramEntry ++ paramCommentToHtml(rest, comment)
case _ =>
NodeSeq.Empty
}
- if (mbr.comment.isEmpty) NodeSeq.Empty
- else {
+ mbr.comment.fold(NodeSeq.Empty) { comment =>
val cmtedPrs = prs filter {
- case tp: TypeParam => mbrCmt.typeParams isDefinedAt tp.name
- case vp: ValueParam => mbrCmt.valueParams isDefinedAt vp.name
+ case tp: TypeParam => comment.typeParams isDefinedAt tp.name
+ case vp: ValueParam => comment.valueParams isDefinedAt vp.name
}
- if (cmtedPrs.isEmpty && mbrCmt.result.isEmpty) NodeSeq.Empty
+ if (cmtedPrs.isEmpty && comment.result.isEmpty) NodeSeq.Empty
else {
<dl class="paramcmts block">{
- paramCommentToHtml(cmtedPrs) ++ (
- mbrCmt.result match {
+ paramCommentToHtml(cmtedPrs, comment) ++ (
+ comment.result match {
case None => NodeSeq.Empty
case Some(cmt) =>
<dt>returns</dt><dd class="cmt">{ bodyToHtml(cmt) }</dd>
@@ -463,7 +463,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
// --- start attributes block vals
- val attributes: Seq[scala.xml.Node] = {
+ val attributes: NodeSeq = {
val fvs: List[comment.Paragraph] = visibility(mbr).toList
if (fvs.isEmpty || isReduced) NodeSeq.Empty
else {
@@ -472,7 +472,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
}
- val definitionClasses: Seq[scala.xml.Node] = {
+ val definitionClasses: NodeSeq = {
val inDefTpls = mbr.inDefinitionTemplates
if ((inDefTpls.tail.isEmpty && (inDefTpls.head == inTpl)) || isReduced) NodeSeq.Empty
else {
@@ -481,7 +481,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
}
- val fullSignature: Seq[scala.xml.Node] = {
+ val fullSignature: NodeSeq = {
mbr match {
case nte: NonTemplateMemberEntity if nte.isUseCase =>
<div class="full-signature-block toggleContainer">
@@ -492,14 +492,14 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
}
}
- val selfType: Seq[scala.xml.Node] = mbr match {
+ val selfType: NodeSeq = mbr match {
case dtpl: DocTemplateEntity if (isSelf && !dtpl.selfType.isEmpty && !isReduced) =>
<dt>Self Type</dt>
<dd>{ typeToHtml(dtpl.selfType.get, hasLinks = true) }</dd>
case _ => NodeSeq.Empty
}
- val annotations: Seq[scala.xml.Node] = {
+ val annotations: NodeSeq = {
// A list of annotations which don't show their arguments, e. g. because they are shown separately.
val annotationsWithHiddenArguments = List("deprecated", "Deprecated", "migration")
@@ -521,7 +521,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
} else NodeSeq.Empty
}
- val sourceLink: Seq[scala.xml.Node] = mbr match {
+ val sourceLink: NodeSeq = mbr match {
case dtpl: DocTemplateEntity if (isSelf && dtpl.sourceUrl.isDefined && dtpl.inSource.isDefined && !isReduced) =>
val (absFile, _) = dtpl.inSource.get
<dt>Source</dt>
@@ -529,83 +529,87 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
case _ => NodeSeq.Empty
}
- val deprecation: Seq[scala.xml.Node] =
- if (mbr.deprecation.isEmpty || isReduced) NodeSeq.Empty
- else {
- <dt>Deprecated</dt>
- <dd class="cmt">{ bodyToHtml(mbr.deprecation.get) }</dd>
+ val deprecation: NodeSeq =
+ mbr.deprecation match {
+ case Some(deprecation) if !isReduced =>
+ <dt>Deprecated</dt>
+ <dd class="cmt">{ bodyToHtml(deprecation) }</dd>
+ case _ => NodeSeq.Empty
}
- val migration: Seq[scala.xml.Node] =
- if(mbr.migration.isEmpty || isReduced) NodeSeq.Empty
- else {
+ val migration: NodeSeq =
+ mbr.migration match {
+ case Some(migration) if !isReduced =>
<dt>Migration</dt>
- <dd class="cmt">{ bodyToHtml(mbr.migration.get) }</dd>
+ <dd class="cmt">{ bodyToHtml(migration) }</dd>
+ case _ => NodeSeq.Empty
}
- val mainComment: Seq[scala.xml.Node] = mbr.comment match {
+ val mainComment: NodeSeq = mbr.comment match {
case Some(comment) if (! isReduced) =>
+ def orEmpty[T](it: Iterable[T])(gen: =>NodeSeq): NodeSeq =
+ if (it.isEmpty) NodeSeq.Empty else gen
+
val example =
- if(!comment.example.isEmpty)
+ orEmpty(comment.example) {
<div class="block">Example{ if (comment.example.length > 1) "s" else ""}:
- <ol>{
- val exampleXml: List[scala.xml.NodeSeq] =
- for(example <- comment.example ) yield
- <li class="cmt">{ bodyToHtml(example) }</li>
- exampleXml.reduceLeft(_ ++ Text(", ") ++ _)
+ <ol>{
+ val exampleXml: List[NodeSeq] = for (ex <- comment.example) yield
+ <li class="cmt">{ bodyToHtml(ex) }</li>
+ exampleXml.reduceLeft(_ ++ Text(", ") ++ _)
}</ol>
- </div>
- else NodeSeq.Empty
+ </div>
+ }
- val version: Seq[scala.xml.Node] =
- if(!comment.version.isEmpty) {
+ val version: NodeSeq =
+ orEmpty(comment.version) {
<dt>Version</dt>
- <dd>{ for(body <- comment.version.toList) yield {bodyToHtml(body)} }</dd>
- } else NodeSeq.Empty
+ <dd>{ for(body <- comment.version.toList) yield bodyToHtml(body) }</dd>
+ }
- val sinceVersion: Seq[scala.xml.Node] =
- if(!comment.since.isEmpty) {
+ val sinceVersion: NodeSeq =
+ orEmpty(comment.since) {
<dt>Since</dt>
- <dd>{ for(body <- comment.since.toList) yield {bodyToHtml(body)} }</dd>
- } else NodeSeq.Empty
+ <dd>{ for(body <- comment.since.toList) yield bodyToHtml(body) }</dd>
+ }
- val note: Seq[scala.xml.Node] =
- if(!comment.note.isEmpty) {
+ val note: NodeSeq =
+ orEmpty(comment.note) {
<dt>Note</dt>
<dd>{
- val noteXml: List[scala.xml.NodeSeq] = (for(note <- comment.note ) yield <span class="cmt">{bodyToHtml(note)}</span> )
+ val noteXml: List[NodeSeq] = for(note <- comment.note ) yield <span class="cmt">{bodyToHtml(note)}</span>
noteXml.reduceLeft(_ ++ Text(", ") ++ _)
}</dd>
- } else NodeSeq.Empty
+ }
- val seeAlso: Seq[scala.xml.Node] =
- if(!comment.see.isEmpty) {
+ val seeAlso: NodeSeq =
+ orEmpty(comment.see) {
<dt>See also</dt>
<dd>{
- val seeXml:List[scala.xml.NodeSeq]=(for(see <- comment.see ) yield <span class="cmt">{bodyToHtml(see)}</span> )
+ val seeXml: List[NodeSeq] = for(see <- comment.see ) yield <span class="cmt">{bodyToHtml(see)}</span>
seeXml.reduceLeft(_ ++ _)
}</dd>
- } else NodeSeq.Empty
+ }
- val exceptions: Seq[scala.xml.Node] =
- if(!comment.throws.isEmpty) {
+ val exceptions: NodeSeq =
+ orEmpty(comment.throws) {
<dt>Exceptions thrown</dt>
<dd>{
- val exceptionsXml: Iterable[scala.xml.NodeSeq] =
- for(exception <- comment.throws.toList.sortBy(_._1) ) yield
- <span class="cmt">{Text(exception._1) ++ bodyToHtml(exception._2)}</span>
+ val exceptionsXml: List[NodeSeq] =
+ for((name, body) <- comment.throws.toList.sortBy(_._1) ) yield
+ <span class="cmt">{Text(name) ++ bodyToHtml(body)}</span>
exceptionsXml.reduceLeft(_ ++ Text("") ++ _)
}</dd>
- } else NodeSeq.Empty
+ }
- val todo: Seq[scala.xml.Node] =
- if(!comment.todo.isEmpty) {
+ val todo: NodeSeq =
+ orEmpty(comment.todo) {
<dt>To do</dt>
<dd>{
- val todoXml: List[scala.xml.NodeSeq] = (for(todo <- comment.todo ) yield <span class="cmt">{bodyToHtml(todo)}</span> )
+ val todoXml: List[NodeSeq] = (for(todo <- comment.todo ) yield <span class="cmt">{bodyToHtml(todo)}</span> )
todoXml.reduceLeft(_ ++ Text(", ") ++ _)
}</dd>
- } else NodeSeq.Empty
+ }
example ++ version ++ sinceVersion ++ exceptions ++ todo ++ note ++ seeAlso
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 df7c7d3dcd..512becd04d 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
@@ -70,7 +70,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 04046accc4..924f203a59 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 361837b743..0000000000
--- a/src/compiler/scala/tools/nsc/doc/model/LinkTo.scala
+++ /dev/null
@@ -1,22 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2007-2013 LAMP/EPFL
- */
-
-package scala.tools.nsc
-package doc
-package model
-
-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 4793716b9f..c7a767f992 100644
--- a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala
@@ -2,225 +2,37 @@ package scala.tools.nsc
package doc
package model
-import comment._
+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)
-
- val 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
- }
- 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"
+ 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))
}
- if (!settings.docNoLinkWarnings.value)
- reporter.warning(pos,
- "The link target \"" + query + "\" is ambiguous. Several (possibly overloaded) members fit the target:\n" +
- linkTo.map(link => linkToString(link)).mkString +
- (if (MemberLookup.showExplanation)
- "\n\n" +
- "Quick crash course on using Scaladoc links\n" +
- "==========================================\n" +
- "Disambiguating terms and types: Prefix terms with '$' and types with '!' in case both names are in use:\n" +
- " - [[scala.collection.immutable.List!.apply class List's apply method]] and\n" +
- " - [[scala.collection.immutable.List$.apply object List's apply method]]\n" +
- "Disambiguating overloaded members: If a term is overloaded, you can indicate the first part of its signature followed by *:\n" +
- " - [[[scala.collection.immutable.List$.fill[A](Int)(⇒A):List[A]* Fill with a single parameter]]]\n" +
- " - [[[scala.collection.immutable.List$.fill[A](Int,Int)(⇒A):List[List[A]]* Fill with a two parameters]]]\n" +
- "Notes: \n" +
- " - you can use any number of matching square brackets to avoid interference with the signature\n" +
- " - you can use \\. to escape dots in prefixes (don't forget to use * at the end to match the signature!)\n" +
- " - you can use \\# to escape hashes, otherwise they will be considered as delimiters, like dots.\n"
- else "")
- )
- chosen
- } else
- linkTo.head
- }
- }
-
- private abstract class SearchStrategy
- private object BothTypeAndTerm extends SearchStrategy
- private object OnlyType extends SearchStrategy
- private object OnlyTerm extends SearchStrategy
-
- private def lookupInRootPackage(pos: Position, members: List[String]) =
- lookupInTemplate(pos, members, 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
- }
+ override def chooseLink(links: List[LinkTo]): LinkTo = {
+ val mbrs = links.collect {
+ case lm@LinkToMember(mbr: MemberEntity, _) => (mbr, lm)
}
- //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
+ mbrs.min(Ordering[MemberEntity].on[(MemberEntity, LinkTo)](_._1))._2
}
- 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
+ override def toString(link: LinkTo) = link match {
+ case LinkToTpl(tpl: EntityImpl) => tpl.sym.toString
+ case LinkToMember(mbr: EntityImpl, inTpl: EntityImpl) =>
+ mbr.sym.signatureString + " in " + inTpl.sym.toString
+ case _ => link.toString
}
}
-
-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 4dac5b7d90..dc75b15f87 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._
@@ -1038,32 +1038,5 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
(bSym.isAliasType || bSym.isAbstractType) &&
{ 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)
- }
- }
- }
-
- 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 015fce294e..5d2cc51c97 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 symtab.Flags
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala
index 1876415f2a..99e9059d79 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._
@@ -17,7 +16,8 @@ trait ModelFactoryTypeSupport {
with ModelFactoryTypeSupport
with DiagramFactory
with CommentFactory
- with TreeFactory =>
+ with TreeFactory
+ with MemberLookup =>
import global._
import definitions.{ ObjectClass, NothingClass, AnyClass, AnyValClass, AnyRefClass }
@@ -82,7 +82,10 @@ trait ModelFactoryTypeSupport {
findTemplateMaybe(bSym) match {
case Some(bTpl) if owner == bSym.owner =>
// (0) the owner's class is linked AND has a template - lovely
- LinkToTpl(bTpl)
+ bTpl match {
+ case dtpl: DocTemplateEntity => new LinkToTpl(dtpl)
+ case _ => new Tooltip(bTpl.qualifiedName)
+ }
case _ =>
val oTpl = findTemplateMaybe(owner)
(oTpl, oTpl flatMap (findMember(bSym, _))) match {
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 fbf6e3386b..96bba0498c 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
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 849a2ac4b3..ebac25bbe4 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
// statistics
import html.page.diagram.DiagramStats
@@ -24,7 +23,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..ad28a28105
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interactive/Doc.scala
@@ -0,0 +1,59 @@
+/* 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
+ }
+
+ override def toString(link: LinkTo) = ask { () =>
+ link match {
+ case LinkToMember(mbr: Symbol, site: Symbol) =>
+ mbr.signatureString + " in " + site.toString
+ case LinkToTpl(sym: Symbol) => sym.toString
+ case _ => link.toString
+ }
+ }
+
+ 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 9716c75215..a34ebb2b8c 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -70,6 +70,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 b3f80168ff..11ae7c974b 100644
--- a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala
+++ b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala
@@ -7,6 +7,7 @@ import reporters.{Reporter => CompilerReporter}
/** 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
}
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 8e274f7647..9715dd3d44 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -993,6 +993,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case (overridden, env) =>
val om = specializedOverload(clazz, overridden, env)
clazz.info.decls.enter(om)
+ foreachWithIndex(om.paramss) { (params, i) =>
+ foreachWithIndex(params) { (param, j) =>
+ param.name = overriding.paramss(i)(j).name // SI-6555 Retain the parameter names from the subclass.
+ }
+ }
debuglog("specialized overload %s for %s in %s: %s".format(om, overriding.name.decode, pp(env), om.info))
if (overriding.isAbstractOverride) om.setFlag(ABSOVERRIDE)
typeEnv(om) = env
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 90ea6c94d8..b94ae99263 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -234,7 +234,10 @@ abstract class UnCurry extends InfoTransform
val applyMethodDef = {
val methSym = anonClass.newMethod(nme.apply, fun.pos, FINAL)
- methSym setInfoAndEnter MethodType(methSym newSyntheticValueParams formals, restpe)
+ val paramSyms = map2(formals, fun.vparams) {
+ (tp, param) => methSym.newSyntheticValueParam(tp, param.name)
+ }
+ methSym setInfoAndEnter MethodType(paramSyms, restpe)
fun.vparams foreach (_.symbol.owner = methSym)
fun.body changeOwner (fun.symbol -> methSym)
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index fe93a0ea76..27944b8767 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -977,7 +977,7 @@ trait ContextErrors {
object SymValidateErrors extends Enumeration {
val ImplicitConstr, ImplicitNotTermOrClass, ImplicitAtToplevel,
OverrideClass, SealedNonClass, AbstractNonClass,
- OverrideConstr, AbstractOverride, LazyAndEarlyInit,
+ OverrideConstr, AbstractOverride, AbstractOverrideOnTypeMember, LazyAndEarlyInit,
ByNameParameter, AbstractVar = Value
}
@@ -1076,6 +1076,9 @@ trait ContextErrors {
case AbstractOverride =>
"`abstract override' modifier only allowed for members of traits"
+ case AbstractOverrideOnTypeMember =>
+ "`abstract override' modifier not allowed for type members"
+
case LazyAndEarlyInit =>
"`lazy' definitions may not be initialized early"
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index bf5aa95f22..8d869b669c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -938,8 +938,8 @@ trait Implicits {
* - for alias types and abstract types, we take instead the parts
* - of their upper bounds.
* @return For those parts that refer to classes with companion objects that
- * can be accessed with unambiguous stable prefixes, the implicits infos
- * which are members of these companion objects.
+ * can be accessed with unambiguous stable prefixes that are not existentially
+ * bound, the implicits infos which are members of these companion objects.
*/
private def companionImplicitMap(tp: Type): InfoMap = {
@@ -955,7 +955,7 @@ trait Implicits {
infoMap(sym) = List() // ambiguous prefix - ignore implicit members
}
case None =>
- if (pre.isStable) {
+ if (pre.isStable && !pre.typeSymbol.isExistentiallyBound) {
val companion = companionSymbolOf(sym, context)
companion.moduleClass match {
case mc: ModuleClassSymbol =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 6cc536ad9b..a541906a99 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -1066,22 +1066,22 @@ trait Infer extends Checkable {
*/
/** error if arguments not within bounds. */
def checkBounds(tree: Tree, pre: Type, owner: Symbol,
- tparams: List[Symbol], targs: List[Type], prefix: String): Boolean = {
- //@M validate variances & bounds of targs wrt variances & bounds of tparams
- //@M TODO: better place to check this?
- //@M TODO: errors for getters & setters are reported separately
- val kindErrors = checkKindBounds(tparams, targs, pre, owner)
-
- if(!kindErrors.isEmpty) {
- if (targs contains WildcardType) true
- else { KindBoundErrors(tree, prefix, targs, tparams, kindErrors); false }
- } else if (!isWithinBounds(pre, owner, tparams, targs)) {
- if (!(targs exists (_.isErroneous)) && !(tparams exists (_.isErroneous))) {
- NotWithinBounds(tree, prefix, targs, tparams, kindErrors)
- false
- } else true
- } else true
- }
+ tparams: List[Symbol], targs: List[Type], prefix: String): Boolean =
+ if ((targs exists (_.isErroneous)) || (tparams exists (_.isErroneous))) true
+ else {
+ //@M validate variances & bounds of targs wrt variances & bounds of tparams
+ //@M TODO: better place to check this?
+ //@M TODO: errors for getters & setters are reported separately
+ val kindErrors = checkKindBounds(tparams, targs, pre, owner)
+ kindErrors match {
+ case Nil =>
+ def notWithinBounds() = NotWithinBounds(tree, prefix, targs, tparams, Nil)
+ isWithinBounds(pre, owner, tparams, targs) || {notWithinBounds(); false}
+ case errors =>
+ def kindBoundErrors() = KindBoundErrors(tree, prefix, targs, tparams, errors)
+ (targs contains WildcardType) || {kindBoundErrors(); false}
+ }
+ }
def checkKindBounds(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): List[String] = {
checkKindBounds0(tparams, targs, pre, owner, true) map {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index d524c88f43..b5160c0519 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -1462,8 +1462,12 @@ trait Namers extends MethodSynthesis {
if (sym.isConstructor && sym.isAnyOverride)
fail(OverrideConstr)
- if (sym.isAbstractOverride && !sym.owner.isTrait)
- fail(AbstractOverride)
+ if (sym.isAbstractOverride) {
+ if (!sym.owner.isTrait)
+ fail(AbstractOverride)
+ if(sym.isType)
+ fail(AbstractOverrideOnTypeMember)
+ }
if (sym.isLazy && sym.hasFlag(PRESUPER))
fail(LazyAndEarlyInit)
if (sym.info.typeSymbol == FunctionClass(0) && sym.isValueParameter && sym.owner.isCaseClass)
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index ede117f51a..dba2f25e32 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -799,8 +799,8 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
protected def spliceApply(binder: Symbol): Tree = {
object splice extends Transformer {
override def transform(t: Tree) = t match {
- case Apply(x, List(Ident(nme.SELECTOR_DUMMY))) =>
- treeCopy.Apply(t, x, List(CODE.REF(binder)))
+ case Apply(x, List(i @ Ident(nme.SELECTOR_DUMMY))) =>
+ treeCopy.Apply(t, x, List(CODE.REF(binder).setPos(i.pos)))
case _ => super.transform(t)
}
}
@@ -877,7 +877,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
override def transform(tree: Tree): Tree = {
def subst(from: List[Symbol], to: List[Tree]): Tree =
if (from.isEmpty) tree
- else if (tree.symbol == from.head) typedIfOrigTyped(to.head.shallowDuplicate, tree.tpe)
+ else if (tree.symbol == from.head) typedIfOrigTyped(to.head.shallowDuplicate.setPos(tree.pos), tree.tpe)
else subst(from.tail, to.tail)
tree match {
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 396c6acd38..12562fecf8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -1545,8 +1545,14 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
sym.name == nme.apply &&
isClassTypeAccessible(tree)
- if (doTransform)
+ if (doTransform) {
+ tree foreach {
+ case i@Ident(_) =>
+ enterReference(i.pos, i.symbol) // SI-5390 need to `enterReference` for `a` in `a.B()`
+ case _ =>
+ }
toConstructor(tree.pos, tree.tpe)
+ }
else {
ifNot
tree
diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
index 0a1d3bfa7a..20db479463 100644
--- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
@@ -19,16 +19,16 @@ trait StdAttachments {
* by `parentTypes`. This attachment coordinates `parentTypes` and `typedTemplate` and
* allows them to complete the synthesis.
*/
- case class SuperCallArgsAttachment(argss: List[List[Tree]])
+ case class SuperArgsAttachment(argss: List[List[Tree]])
- /** Convenience method for `SuperCallArgsAttachment`.
+ /** Convenience method for `SuperArgsAttachment`.
* Compared with `MacroRuntimeAttachment` this attachment has different a usage pattern,
* so it really benefits from a dedicated extractor.
*/
- def superCallArgs(tree: Tree): Option[List[List[Tree]]] =
- tree.attachments.get[SuperCallArgsAttachment] collect { case SuperCallArgsAttachment(argss) => argss }
+ def superArgs(tree: Tree): Option[List[List[Tree]]] =
+ tree.attachments.get[SuperArgsAttachment] collect { case SuperArgsAttachment(argss) => argss }
- /** Determines whether the given tree has an associated SuperCallArgsAttachment.
+ /** Determines whether the given tree has an associated SuperArgsAttachment.
*/
- def hasSuperArgs(tree: Tree): Boolean = superCallArgs(tree).nonEmpty
+ def hasSuperArgs(tree: Tree): Boolean = superArgs(tree).nonEmpty
} \ 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 f243569dc8..2b01e32497 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 {
@@ -1453,7 +1454,7 @@ trait Typers extends Modes with Adaptations with Tags {
*
* Returns a `TypeTree` representing a resolved parent type.
* If the typechecked parent reference implies non-nullary and non-empty argument list,
- * this argument list is attached to the returned value in SuperCallArgsAttachment.
+ * this argument list is attached to the returned value in SuperArgsAttachment.
* The attachment is necessary for the subsequent typecheck to fixup a super constructor call
* in the body of the primary constructor (see `typedTemplate` for details).
*
@@ -1519,7 +1520,7 @@ trait Typers extends Modes with Adaptations with Tags {
// this is the place where we tell the typer what argss should be used for the super call
// if argss are nullary or empty, then (see the docs for `typedPrimaryConstrBody`)
// the super call dummy is already good enough, so we don't need to do anything
- if (argssAreTrivial) supertpt else supertpt updateAttachment SuperCallArgsAttachment(argss)
+ if (argssAreTrivial) supertpt else supertpt updateAttachment SuperArgsAttachment(argss)
}
}
@@ -1845,8 +1846,7 @@ trait Typers extends Modes with Adaptations with Tags {
*/
def typedTemplate(templ: Template, parents1: List[Tree]): Template = {
val clazz = context.owner
- // complete lazy annotations
- clazz.annotations
+ clazz.annotations.map(_.completeInfo)
if (templ.symbol == NoSymbol)
templ setSymbol clazz.newLocalDummy(templ.pos)
val self1 = templ.self match {
@@ -1893,7 +1893,7 @@ trait Typers extends Modes with Adaptations with Tags {
val primaryCtor = treeInfo.firstConstructor(body)
val primaryCtor1 = primaryCtor match {
case DefDef(_, _, _, _, _, Block(earlyVals :+ global.pendingSuperCall, unit)) =>
- val argss = superCallArgs(parents1.head) getOrElse Nil
+ val argss = superArgs(parents1.head) getOrElse Nil
val pos = wrappingPos(parents1.head.pos, argss.flatten)
val superCall = atPos(pos)(PrimarySuperCall(argss))
deriveDefDef(primaryCtor)(block => Block(earlyVals :+ superCall, unit) setPos pos) setPos pos
@@ -1936,8 +1936,7 @@ trait Typers extends Modes with Adaptations with Tags {
val typer1 = constrTyperIf(sym.isParameter && sym.owner.isConstructor)
val typedMods = typedModifiers(vdef.mods)
- // complete lazy annotations
- sym.annotations
+ sym.annotations.map(_.completeInfo)
val tpt1 = checkNoEscaping.privates(sym, typer1.typedType(vdef.tpt))
checkNonCyclic(vdef, tpt1)
@@ -2165,8 +2164,7 @@ trait Typers extends Modes with Adaptations with Tags {
val tparams1 = ddef.tparams mapConserve typedTypeDef
val vparamss1 = ddef.vparamss mapConserve (_ mapConserve typedValDef)
- // complete lazy annotations
- meth.annotations
+ meth.annotations.map(_.completeInfo)
for (vparams1 <- vparamss1; vparam1 <- vparams1 dropRight 1)
if (isRepeatedParamType(vparam1.symbol.tpe))
@@ -2241,8 +2239,7 @@ trait Typers extends Modes with Adaptations with Tags {
reenterTypeParams(tdef.tparams)
val tparams1 = tdef.tparams mapConserve typedTypeDef
val typedMods = typedModifiers(tdef.mods)
- // complete lazy annotations
- tdef.symbol.annotations
+ tdef.symbol.annotations.map(_.completeInfo)
// @specialized should not be pickled when compiling with -no-specialize
if (settings.nospecialization.value && currentRun.compiles(tdef.symbol)) {
@@ -2707,6 +2704,7 @@ trait Typers extends Modes with Adaptations with Tags {
def typedRefinement(templ: Template) {
val stats = templ.body
namer.enterSyms(stats)
+
// need to delay rest of typedRefinement to avoid cyclic reference errors
unit.toCheck += { () =>
val stats1 = typedStats(stats, NoSymbol)
@@ -4769,7 +4767,7 @@ trait Typers extends Modes with Adaptations with Tags {
typedClassOf(tree, TypeTree(pt.typeArgs.head))
else {
val pre1 = if (sym.owner.isPackageClass) sym.owner.thisType else if (qual == EmptyTree) NoPrefix else qual.tpe
- val tree1 = if (qual == EmptyTree) tree else atPos(tree.pos)(Select(atPos(tree.pos.focusStart)(qual), name))
+ val tree1 = if (qual == EmptyTree) tree else atPos(tree.pos)(Select(atPos(tree.pos.focusStart)(qual), name) setAttachments tree.attachments)
val (tree2, pre2) = makeAccessible(tree1, sym, pre1, qual)
// SI-5967 Important to replace param type A* with Seq[A] when seen from from a reference, to avoid
// inference errors in pattern matching.
@@ -4791,14 +4789,20 @@ trait Typers extends Modes with Adaptations with Tags {
def typedCompoundTypeTree(tree: CompoundTypeTree) = {
val templ = tree.templ
val parents1 = templ.parents mapConserve (typedType(_, mode))
- if (parents1 exists (_.isErrorTyped)) tree setType ErrorType
+
+ // This is also checked later in typedStats, but that is too late for SI-5361, so
+ // we eagerly check this here.
+ for (stat <- templ.body if !treeInfo.isDeclarationOrTypeDef(stat))
+ OnlyDeclarationsError(stat)
+
+ if ((parents1 ++ templ.body) exists (_.isErrorTyped)) tree setType ErrorType
else {
val decls = newScope
//Console.println("Owner: " + context.enclClass.owner + " " + context.enclClass.owner.id)
val self = refinedType(parents1 map (_.tpe), context.enclClass.owner, decls, templ.pos)
newTyper(context.make(templ, self.typeSymbol, decls)).typedRefinement(templ)
templ updateAttachment CompoundTypeTreeOriginalAttachment(parents1, Nil) // stats are set elsewhere
- tree setType self
+ tree setType (if (templ.exists(_.isErroneous)) ErrorType else self) // Being conservative to avoid SI-5361
}
}
@@ -4861,16 +4865,14 @@ trait Typers extends Modes with Adaptations with Tags {
def typedPackageDef(pdef: PackageDef) = {
val pid1 = typedQualifier(pdef.pid).asInstanceOf[RefTree]
assert(sym.moduleClass ne NoSymbol, sym)
- // complete lazy annotations
- sym.annotations
val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls))
.typedStats(pdef.stats, NoSymbol)
treeCopy.PackageDef(tree, pid1, stats1) setType NoType
}
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/DirectTest.scala b/src/partest/scala/tools/partest/DirectTest.scala
index 8c18809ad6..483cb491a1 100644
--- a/src/partest/scala/tools/partest/DirectTest.scala
+++ b/src/partest/scala/tools/partest/DirectTest.scala
@@ -39,6 +39,10 @@ abstract class DirectTest extends App {
// new compiler
def newCompiler(args: String*): Global = {
val settings = newSettings((CommandLineParser tokenize ("-d \"" + testOutput.path + "\" " + extraSettings)) ++ args.toList)
+ newCompiler(settings)
+ }
+
+ def newCompiler(settings: Settings): Global = {
if (settings.Yrangepos.value) new Global(settings, reporter(settings)) with interactive.RangePositions
else new Global(settings, reporter(settings))
}
diff --git a/src/partest/scala/tools/partest/ScaladocModelTest.scala b/src/partest/scala/tools/partest/ScaladocModelTest.scala
index acaddff944..3db9f18484 100644
--- a/src/partest/scala/tools/partest/ScaladocModelTest.scala
+++ b/src/partest/scala/tools/partest/ScaladocModelTest.scala
@@ -10,7 +10,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/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
index da50c55fe1..cfa4bdf44c 100644
--- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -200,6 +200,8 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
override def toString = if (forced) forcedInfo.toString else "@<?>"
override def pos: Position = if (forced) forcedInfo.pos else NoPosition
+
+ override def completeInfo(): Unit = forcedInfo
}
/** Typed information about an annotation. It can be attached to either
@@ -241,6 +243,9 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
this
}
+ // Forces LazyAnnotationInfo, no op otherwise
+ def completeInfo(): Unit = ()
+
/** Annotations annotating annotations are confusing so I drew
* an example. Given the following code:
*
diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala
index 61906740a0..654dbd76e7 100644
--- a/src/reflect/scala/reflect/internal/Flags.scala
+++ b/src/reflect/scala/reflect/internal/Flags.scala
@@ -275,7 +275,7 @@ class Flags extends ModifierFlags {
* Getters of immutable values also get STABLE.
*/
final val GetterFlags = ~(PRESUPER | MUTABLE)
- final val SetterFlags = ~(PRESUPER | MUTABLE | STABLE | CASEACCESSOR)
+ final val SetterFlags = ~(PRESUPER | MUTABLE | STABLE | CASEACCESSOR | IMPLICIT)
/** When a symbol for a default getter is created, it inherits these
* flags from the method with the default. Other flags applied at creation
diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala
index 1df91a67b0..b782353ed3 100644
--- a/src/reflect/scala/reflect/internal/StdAttachments.scala
+++ b/src/reflect/scala/reflect/internal/StdAttachments.scala
@@ -10,6 +10,7 @@ trait StdAttachments {
trait Attachable {
protected var rawatt: scala.reflect.macros.Attachments { type Pos = Position } = NoPosition
def attachments = rawatt
+ def setAttachments(attachments: scala.reflect.macros.Attachments { type Pos = Position }): this.type = { rawatt = attachments; this }
def updateAttachment[T: ClassTag](attachment: T): this.type = { rawatt = rawatt.update(attachment); this }
def removeAttachment[T: ClassTag]: this.type = { rawatt = rawatt.remove[T]; this }
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index 024e1b30bf..9e737528d2 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -824,7 +824,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
def Annotated(tree: Tree, annot: Tree, arg: Tree) = tree match {
case t @ Annotated(annot0, arg0)
- if (annot0==annot) => t
+ if (annot0==annot && arg0==arg) => t
case _ => treeCopy.Annotated(tree, annot, arg)
}
def SingletonTypeTree(tree: Tree, ref: Tree) = tree match {
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 58dd7f3a03..282d7e18ac 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -6321,11 +6321,11 @@ trait Types extends api.Types { self: SymbolTable =>
case ExistentialType(qs, _) => qs
case t => List()
}
- def stripType(tp: Type) = tp match {
+ def stripType(tp: Type): Type = tp match {
case ExistentialType(_, res) =>
res
case tv@TypeVar(_, constr) =>
- if (tv.instValid) constr.inst
+ if (tv.instValid) stripType(constr.inst)
else if (tv.untouchable) tv
else abort("trying to do lub/glb of typevar "+tp)
case t => t
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index f6ce19e1d7..57cfb8b515 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -568,7 +568,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
case None =>
// class does not have a Scala signature; it's a Java class
info("translating reflection info for Java " + jclazz) //debug
- initClassModule(clazz, module, new FromJavaClassCompleter(clazz, module, jclazz))
+ initClassAndModule(clazz, module, new FromJavaClassCompleter(clazz, module, jclazz))
}
}
} catch {
@@ -670,9 +670,9 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
def enter(sym: Symbol, mods: Int) =
(if (jModifier.isStatic(mods)) module.moduleClass else clazz).info.decls enter sym
- for (jinner <- jclazz.getDeclaredClasses) {
- enter(jclassAsScala(jinner, clazz), jinner.getModifiers)
- }
+ for (jinner <- jclazz.getDeclaredClasses)
+ jclassAsScala(jinner) // inner class is entered as a side-effect
+ // no need to call enter explicitly
pendingLoadActions = { () =>
@@ -1016,14 +1016,15 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
* @param jclazz The Java class
* @return A Scala class symbol that wraps all reflection info of `jclazz`
*/
- private def jclassAsScala(jclazz: jClass[_]): Symbol = jclassAsScala(jclazz, sOwner(jclazz))
+ private def jclassAsScala(jclazz: jClass[_]): ClassSymbol =
+ toScala(classCache, jclazz)(_ jclassAsScala1 _)
- private def jclassAsScala(jclazz: jClass[_], owner: Symbol): ClassSymbol = {
+ private def jclassAsScala1(jclazz: jClass[_]): ClassSymbol = {
+ val owner = sOwner(jclazz)
val name = scalaSimpleName(jclazz)
val completer = (clazz: Symbol, module: Symbol) => new FromJavaClassCompleter(clazz, module, jclazz)
- val (clazz, _) = createClassModule(owner, name, completer)
- classCache enter (jclazz, clazz)
- clazz
+
+ initAndEnterClassAndModule(owner, name, completer)._1
}
/**
diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
index 60b22afd18..ea14e8ad43 100644
--- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
+++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
@@ -57,7 +57,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
* @param name The simple name of the newly created class
* @param completer The completer to be used to set the info of the class and the module
*/
- protected def createClassModule(owner: Symbol, name: TypeName, completer: (Symbol, Symbol) => LazyType) = {
+ protected def initAndEnterClassAndModule(owner: Symbol, name: TypeName, completer: (Symbol, Symbol) => LazyType) = {
assert(!(name.toString endsWith "[]"), name)
val clazz = owner.newClass(name)
val module = owner.newModule(name.toTermName)
@@ -67,7 +67,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
owner.info.decls enter clazz
owner.info.decls enter module
}
- initClassModule(clazz, module, completer(clazz, module))
+ initClassAndModule(clazz, module, completer(clazz, module))
(clazz, module)
}
@@ -75,7 +75,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
List(clazz, module, module.moduleClass) foreach (_ setInfo info)
}
- protected def initClassModule(clazz: Symbol, module: Symbol, completer: LazyType) =
+ protected def initClassAndModule(clazz: Symbol, module: Symbol, completer: LazyType) =
setAllInfos(clazz, module, completer)
/** The type completer for packages.
@@ -118,7 +118,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
val loadingMirror = currentMirror.mirrorDefining(cls)
val (_, module) =
if (loadingMirror eq currentMirror) {
- createClassModule(pkgClass, name.toTypeName, new TopClassCompleter(_, _))
+ initAndEnterClassAndModule(pkgClass, name.toTypeName, new TopClassCompleter(_, _))
} else {
val origOwner = loadingMirror.packageNameToScala(pkgClass.fullName)
val clazz = origOwner.info decl name.toTypeName