From 2352814d4be064d67794899cf5494d3324a131ec Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 6 Mar 2013 09:35:04 -0800 Subject: Eliminated all forInteractive/forScaladoc uses. This is the commit which brings it all together. The booleans forInteractive and forScaladoc are now deprecated and are not inspected for any purpose. All behavioral changes formerly accomplished via tests of those flags are embodied in the globals built specifically for those tasks. --- src/compiler/scala/tools/nsc/Global.scala | 2 - .../tools/nsc/typechecker/ContextErrors.scala | 18 +-- .../scala/tools/nsc/typechecker/Namers.scala | 45 +----- .../scala/tools/nsc/typechecker/Typers.scala | 24 ++-- .../scala/tools/nsc/interactive/Global.scala | 14 +- .../tests/core/PresentationCompilerInstance.scala | 11 +- src/reflect/scala/reflect/internal/Required.scala | 7 +- src/reflect/scala/reflect/internal/Symbols.scala | 25 ++-- .../scala/reflect/runtime/JavaUniverse.scala | 2 - .../scala/tools/nsc/doc/ScaladocAnalyzer.scala | 5 + test/files/neg/macro-basic-mamdmi.check | 3 +- test/files/neg/t5753.check | 3 +- test/files/presentation/doc.check | 1 + test/files/presentation/doc/doc.scala | 151 +++++++++++++++++++++ test/files/presentation/doc/src/Class.scala | 1 + test/files/presentation/doc/src/p/Base.scala | 11 ++ test/files/presentation/doc/src/p/Derived.scala | 9 ++ test/pending/presentation/doc.check | 1 - test/pending/presentation/doc/doc.scala | 145 -------------------- test/pending/presentation/doc/src/Class.scala | 1 - test/pending/presentation/doc/src/p/Base.scala | 11 -- test/pending/presentation/doc/src/p/Derived.scala | 9 -- 22 files changed, 237 insertions(+), 262 deletions(-) create mode 100644 test/files/presentation/doc.check create mode 100755 test/files/presentation/doc/doc.scala create mode 100755 test/files/presentation/doc/src/Class.scala create mode 100755 test/files/presentation/doc/src/p/Base.scala create mode 100755 test/files/presentation/doc/src/p/Derived.scala delete mode 100644 test/pending/presentation/doc.check delete mode 100755 test/pending/presentation/doc/doc.scala delete mode 100755 test/pending/presentation/doc/src/Class.scala delete mode 100755 test/pending/presentation/doc/src/p/Base.scala delete mode 100755 test/pending/presentation/doc/src/p/Derived.scala diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index bc18b06e2a..c0f611daa7 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1696,8 +1696,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } }) } - def forInteractive = false - def forScaladoc = false def createJavadoc = false } diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 580f024b40..0af75a2aad 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -683,7 +683,7 @@ trait ContextErrors { // same reason as for MacroBodyTypecheckException case object MacroExpansionException extends Exception with scala.util.control.ControlThrowable - private def macroExpansionError(expandee: Tree, msg: String, pos: Position = NoPosition) = { + protected def macroExpansionError(expandee: Tree, msg: String, pos: Position = NoPosition) = { def msgForLog = if (msg != null && (msg contains "exception during macro expansion")) msg.split(EOL).drop(1).headOption.getOrElse("?") else msg macroLogLite("macro expansion has failed: %s".format(msgForLog)) if (msg != null) context.error(pos, msg) // issueTypeError(PosAndMsgTypeError(..)) won't work => swallows positions @@ -772,15 +772,15 @@ trait ContextErrors { )) } - def MacroImplementationNotFoundError(expandee: Tree) = { - val message = - "macro implementation not found: " + expandee.symbol.name + " " + - "(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)" + - (if (forScaladoc) ". When generating scaladocs for multiple projects at once, consider using -Ymacro-no-expand to disable macro expansions altogether." - else "") - macroExpansionError(expandee, message) - } + def MacroImplementationNotFoundError(expandee: Tree) = + macroExpansionError(expandee, macroImplementationNotFoundMessage(expandee.symbol.name)) } + + /** This file will be the death of me. */ + protected def macroImplementationNotFoundMessage(name: Name): String = ( + s"""|macro implementation not found: $name + |(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)""".stripMargin + ) } trait InferencerContextErrors { diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 777e96da82..007c7c6a83 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -50,19 +50,8 @@ trait Namers extends MethodSynthesis { def newNamerFor(context: Context, tree: Tree): Namer = newNamer(context.makeNewScope(tree, tree.symbol)) abstract class Namer(val context: Context) extends MethodSynth with NamerContextErrors { thisNamer => - - def saveDefaultGetter(meth: Symbol, default: Symbol) { - if (forInteractive) { - // save the default getters as attachments in the method symbol. if compiling the - // same local block several times (which can happen in interactive mode) we might - // otherwise not find the default symbol, because the second time it the method - // symbol will be re-entered in the scope but the default parameter will not. - meth.attachments.get[DefaultsOfLocalMethodAttachment] match { - case Some(att) => att.defaultGetters += default - case None => meth.updateAttachment(new DefaultsOfLocalMethodAttachment(default)) - } - } - } + // overridden by the presentation compiler + def saveDefaultGetter(meth: Symbol, default: Symbol) { } import NamerErrorGen._ val typer = newTyper(context) @@ -606,17 +595,6 @@ trait Namers extends MethodSynthesis { } } - def enterIfNotThere(sym: Symbol) { - val scope = context.scope - @tailrec def search(e: ScopeEntry) { - if ((e eq null) || (e.owner ne scope)) - scope enter sym - else if (e.sym ne sym) // otherwise, aborts since we found sym - search(e.tail) - } - search(scope lookupEntry sym.name) - } - def enterValDef(tree: ValDef) { if (noEnterGetterSetter(tree)) assignAndEnterFinishedSymbol(tree) @@ -709,22 +687,9 @@ trait Namers extends MethodSynthesis { validateCompanionDefs(tree) } - // this logic is needed in case typer was interrupted half - // way through and then comes back to do the tree again. In - // that case the definitions that were already attributed as - // well as any default parameters of such methods need to be - // re-entered in the current scope. - protected def enterExistingSym(sym: Symbol): Context = { - if (forInteractive && sym != null && sym.owner.isTerm) { - enterIfNotThere(sym) - if (sym.isLazy) - sym.lazyAccessor andAlso enterIfNotThere - - for (defAtt <- sym.attachments.get[DefaultsOfLocalMethodAttachment]) - defAtt.defaultGetters foreach enterIfNotThere - } - this.context - } + // Hooks which are overridden in the presentation compiler + def enterExistingSym(sym: Symbol): Context = this.context + def enterIfNotThere(sym: Symbol) { } def enterSyntheticSym(tree: Tree): Symbol = { enterSym(tree) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 1a3c20c4b9..eaf57cd39c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -96,16 +96,16 @@ trait Typers extends Adaptations with Tags { // - we may virtualize matches (if -Xexperimental and there's a suitable __match in scope) // - we synthesize PartialFunction implementations for `x => x match {...}` and `match {...}` when the expected type is PartialFunction // this is disabled by: interactive compilation (we run it for scaladoc due to SI-5933) - protected def newPatternMatching = !forInteractive //&& !forScaladoc && (phase.id < currentRun.uncurryPhase.id) + protected def newPatternMatching = true // presently overridden in the presentation compiler abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with Tag with TyperContextErrors { import context0.unit import typeDebug.{ ptTree, ptBlock, ptLine } import TyperErrorGen._ - /** (Will be) overridden to false in scaladoc and/or interactive. */ - def canAdaptConstantTypeToLiteral = !forScaladoc && !forInteractive - def canTranslateEmptyListToNil = !forInteractive + /** Overridden to false in scaladoc and/or interactive. */ + def canAdaptConstantTypeToLiteral = true + def canTranslateEmptyListToNil = true def missingSelectErrorTree(tree: Tree, qual: Tree, name: Name): Tree = tree def typedDocDef(docDef: DocDef, mode: Mode, pt: Type): Tree = @@ -1041,7 +1041,7 @@ trait Typers extends Adaptations with Tags { tree.tpe match { case atp @ AnnotatedType(_, _, _) if canAdaptAnnotations(tree, this, mode, pt) => // (-1) adaptAnnotations(tree, this, mode, pt) - case ct @ ConstantType(value) if mode.inNone(TYPEmode | FUNmode) && (ct <:< pt) && !forScaladoc && !forInteractive => // (0) + case ct @ ConstantType(value) if mode.inNone(TYPEmode | FUNmode) && (ct <:< pt) && canAdaptConstantTypeToLiteral => // (0) val sym = tree.symbol if (sym != null && sym.isDeprecated) { val msg = sym.toString + sym.locationString + " is deprecated: " + sym.deprecationMessage.getOrElse("") @@ -2436,11 +2436,9 @@ trait Typers extends Adaptations with Tags { if (pat1.tpe.paramSectionCount > 0) pat1 setType pat1.tpe.finalResultType - if (forInteractive) { - for (bind @ Bind(name, _) <- cdef.pat) - if (name.toTermName != nme.WILDCARD && bind.symbol != null && bind.symbol != NoSymbol) - namer.enterIfNotThere(bind.symbol) - } + for (bind @ Bind(name, _) <- cdef.pat) + if (name.toTermName != nme.WILDCARD && bind.symbol != null && bind.symbol != NoSymbol) + namer.enterIfNotThere(bind.symbol) val guard1: Tree = if (cdef.guard == EmptyTree) EmptyTree else typed(cdef.guard, BooleanClass.tpe) @@ -4691,11 +4689,7 @@ trait Typers extends Adaptations with Tags { if (!reallyExists(sym)) { def handleMissing: Tree = { - def errorTree = tree match { - case _ if !forInteractive => tree - case Select(_, _) => treeCopy.Select(tree, qual, name) - case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name) - } + def errorTree = missingSelectErrorTree(tree, qual, name) def asTypeSelection = ( if (context.owner.enclosingTopLevelClass.isJavaDefined && name.isTypeName) { atPos(tree.pos)(gen.convertToSelectFromType(qual, name)) match { diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala index 6abbd1b3ba..099a882f10 100644 --- a/src/interactive/scala/tools/nsc/interactive/Global.scala +++ b/src/interactive/scala/tools/nsc/interactive/Global.scala @@ -14,11 +14,20 @@ import scala.tools.nsc.util.MultiHashMap import scala.reflect.internal.util.{ SourceFile, BatchSourceFile, Position, NoPosition } import scala.tools.nsc.reporters._ import scala.tools.nsc.symtab._ +import scala.tools.nsc.doc.ScaladocAnalyzer import scala.tools.nsc.typechecker.{ Analyzer, DivergentImplicit } import symtab.Flags.{ACCESSOR, PARAMACCESSOR} import scala.annotation.{ elidable, tailrec } import scala.language.implicitConversions +trait InteractiveScaladocAnalyzer extends InteractiveAnalyzer with ScaladocAnalyzer { + val global : Global + import global._ + override def newTyper(context: Context) = new Typer(context) with InteractiveTyper with ScaladocTyper { + override def canAdaptConstantTypeToLiteral = false + } +} + trait InteractiveAnalyzer extends Analyzer { val global : Global import global._ @@ -127,9 +136,10 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") if (verboseIDE) println("[%s][%s]".format(projectName, msg)) // don't keep the original owner in presentation compiler runs - // (the map will grow indefinitely, and the only use case is the - // backend). + // (the map will grow indefinitely, and the only use case is the backend) override protected def saveOriginalOwner(sym: Symbol) { } + override protected def originalEnclosingMethod(sym: Symbol) = + abort("originalOwner is not kept in presentation compiler runs.") override def forInteractive = true diff --git a/src/interactive/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala b/src/interactive/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala index 5cda0e53fb..9a2abd5139 100644 --- a/src/interactive/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala +++ b/src/interactive/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala @@ -13,11 +13,16 @@ private[tests] trait PresentationCompilerInstance extends TestSettings { override def compiler = PresentationCompilerInstance.this.compiler } + private class ScaladocEnabledGlobal extends Global(settings, compilerReporter) { + override lazy val analyzer = new { + val global: ScaladocEnabledGlobal.this.type = ScaladocEnabledGlobal.this + } with InteractiveScaladocAnalyzer + } + protected lazy val compiler: Global = { prepareSettings(settings) - new Global(settings, compilerReporter) { - override def forScaladoc = withDocComments - } + if (withDocComments) new ScaladocEnabledGlobal + else new Global(settings, compilerReporter) } /** diff --git a/src/reflect/scala/reflect/internal/Required.scala b/src/reflect/scala/reflect/internal/Required.scala index 842491d56d..93383f5376 100644 --- a/src/reflect/scala/reflect/internal/Required.scala +++ b/src/reflect/scala/reflect/internal/Required.scala @@ -4,12 +4,9 @@ package internal import settings.MutableSettings trait Required { self: SymbolTable => - def picklerPhase: Phase - def settings: MutableSettings - def forInteractive: Boolean - - def forScaladoc: Boolean + @deprecated("Interactive is implemented with a custom Global; this flag is ignored", "2.11.0") def forInteractive = false + @deprecated("Scaladoc is implemented with a custom Global; this flag is ignored", "2.11.0") def forScaladoc = false } diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index f7a87d2700..6837f37445 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -74,12 +74,15 @@ trait Symbols extends api.Symbols { self: SymbolTable => // e.g. after flatten all classes are owned by package classes, there are lots and // lots of these to be declared (or more realistically, discovered.) protected def saveOriginalOwner(sym: Symbol) { - // don't keep the original owner in presentation compiler runs - // (the map will grow indefinitely, and the only use case is the - // backend). - if (!forInteractive) { - if (originalOwner contains sym) () - else originalOwner(sym) = sym.rawowner + if (originalOwner contains sym) () + else originalOwner(sym) = sym.rawowner + } + protected def originalEnclosingMethod(sym: Symbol): Symbol = { + if (sym.isMethod || sym == NoSymbol) sym + else { + val owner = originalOwner.getOrElse(sym, sym.rawowner) + if (sym.isLocalDummy) owner.enclClass.primaryConstructor + else originalEnclosingMethod(owner) } } @@ -1920,15 +1923,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * originalOwner map is not populated for memory considerations (the symbol * may hang on to lazy types and in turn to whole (outdated) compilation units. */ - def originalEnclosingMethod: Symbol = { - assert(!forInteractive, "originalOwner is not kept in presentation compiler runs.") - if (isMethod) this - else { - val owner = originalOwner.getOrElse(this, rawowner) - if (isLocalDummy) owner.enclClass.primaryConstructor - else owner.originalEnclosingMethod - } - } + def originalEnclosingMethod: Symbol = Symbols.this.originalEnclosingMethod(this) /** The method or class which logically encloses the current symbol. * If the symbol is defined in the initialization part of a template diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index 5467d70cea..a130013398 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -11,8 +11,6 @@ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.S def inform(msg: String): Unit = log(msg) def picklerPhase = internal.SomePhase - def forInteractive = false - def forScaladoc = false lazy val settings = new Settings private val isLogging = sys.props contains "scala.debug.reflect" diff --git a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala index 37d95a9d95..5ad50445a8 100644 --- a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala +++ b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala @@ -24,6 +24,11 @@ trait ScaladocAnalyzer extends Analyzer { override def canAdaptConstantTypeToLiteral = false + override protected def macroImplementationNotFoundMessage(name: Name): String = ( + super.macroImplementationNotFoundMessage(name) + + "\nWhen generating scaladocs for multiple projects at once, consider using -Ymacro-no-expand to disable macro expansions altogether." + ) + override def typedDocDef(docDef: DocDef, mode: Mode, pt: Type): Tree = { val sym = docDef.symbol diff --git a/test/files/neg/macro-basic-mamdmi.check b/test/files/neg/macro-basic-mamdmi.check index c7b58d70d2..621d318ceb 100644 --- a/test/files/neg/macro-basic-mamdmi.check +++ b/test/files/neg/macro-basic-mamdmi.check @@ -1,4 +1,5 @@ -Impls_Macros_Test_1.scala:36: error: macro implementation not found: foo (the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them) +Impls_Macros_Test_1.scala:36: error: macro implementation not found: foo +(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them) println(foo(2) + Macros.bar(2) * new Macros().quux(4)) ^ one error found diff --git a/test/files/neg/t5753.check b/test/files/neg/t5753.check index 76602de17d..379416c179 100644 --- a/test/files/neg/t5753.check +++ b/test/files/neg/t5753.check @@ -1,4 +1,5 @@ -Test_2.scala:9: error: macro implementation not found: foo (the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them) +Test_2.scala:9: error: macro implementation not found: foo +(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them) println(foo(42)) ^ one error found diff --git a/test/files/presentation/doc.check b/test/files/presentation/doc.check new file mode 100644 index 0000000000..5a3ff13151 --- /dev/null +++ b/test/files/presentation/doc.check @@ -0,0 +1 @@ +reload: Base.scala, Class.scala, Derived.scala diff --git a/test/files/presentation/doc/doc.scala b/test/files/presentation/doc/doc.scala new file mode 100755 index 0000000000..7a2eb9a588 --- /dev/null +++ b/test/files/presentation/doc/doc.scala @@ -0,0 +1,151 @@ +import scala.tools.nsc.doc +import scala.tools.nsc.doc.base._ +import scala.tools.nsc.doc.base.comment._ +import scala.tools.nsc.interactive._ +import scala.tools.nsc.interactive.tests._ +import scala.tools.nsc.util._ + +object Test extends InteractiveTest { + val tags = Seq( + "@example `\"abb\".permutations = Iterator(abb, bab, bba)`", + "@version 1.0, 09/07/2012", + "@since 2.10", + "@todo this is unsafe!", + "@note Don't inherit!", + "@see something else" + ) + + val names = Seq("Class", "Def", "Val", "Var", "AbstracType", "TypeAlias", "Trait", "InnerClass") + val bareText = + """abstract class %s { + | def %s = "" + | val %s = "" + | var %s: String = _ + | type %s + | type %s = String + | class %s + |} + |trait %s""".stripMargin.format(names: _*) + + def docComment(nTags: Int) = "/**\n%s*/".format(tags.take(nTags).mkString("\n")) + + def text(name: String, nTags: Int) = { + val nameIndex = bareText.indexOf(name) + val (pre, post) = bareText.splitAt(nameIndex) + val crIndex = pre.lastIndexOf("\n") + val (prepre, prepost) = pre.splitAt(crIndex) + prepre + docComment(nTags) + prepost + post + } + + override lazy val compiler = { + prepareSettings(settings) + new Global(settings, compilerReporter) with MemberLookupBase with CommentFactoryBase with doc.ScaladocGlobalTrait { + outer => + + val global: this.type = this + + override lazy val analyzer = new { + val global: outer.type = outer + } with doc.ScaladocAnalyzer with InteractiveAnalyzer { + override def newTyper(context: Context): InteractiveTyper with ScaladocTyper = + new Typer(context) with InteractiveTyper with ScaladocTyper + } + + override lazy val loaders = new scala.tools.nsc.symtab.SymbolLoaders { + val global: outer.type = outer + } + + def chooseLink(links: List[LinkTo]): LinkTo = links.head + def internalLink(sym: Symbol, site: Symbol) = None + def toString(link: LinkTo) = link.toString + def warnNoLink = false + def findExternalLink(sym: Symbol, name: String) = None + + override def forScaladoc = true + + def getComment(sym: Symbol, source: SourceFile, fragments: List[(Symbol,SourceFile)]): Option[Comment] = { + val docResponse = new Response[(String, String, Position)] + askDocComment(sym, source, sym.owner, fragments, docResponse) + docResponse.get.left.toOption flatMap { + case (expanded, raw, pos) => + if (expanded.isEmpty) + None + else + Some(ask { () => parseAtSymbol(expanded, raw, pos, Some(sym.owner)) }) + } + } + } + } + + override def runDefaultTests() { + import compiler._ + def findSource(name: String) = sourceFiles.find(_.file.name == name).get + + val className = names.head + for (name <- names; + i <- 1 to tags.length) { + val newText = text(name, i) + val source = findSource("Class.scala") + val batch = new BatchSourceFile(source.file, newText.toCharArray) + val reloadResponse = new Response[Unit] + compiler.askReload(List(batch), reloadResponse) + reloadResponse.get.left.toOption match { + case None => + println("Couldn't reload") + case Some(_) => + val parseResponse = new Response[Tree] + askParsedEntered(batch, true, parseResponse) + parseResponse.get.left.toOption match { + case None => + println("Couldn't parse") + case Some(_) => + val sym = compiler.ask { () => + val toplevel = definitions.EmptyPackage.info.decl(newTypeName(name)) + if (toplevel eq NoSymbol) { + val clazz = definitions.EmptyPackage.info.decl(newTypeName(className)) + + val term = clazz.info.decl(newTermName(name)) + if (term eq NoSymbol) clazz.info.decl(newTypeName(name)) else + if (term.isAccessor) term.accessed else term + } else toplevel + } + + getComment(sym, batch, (sym,batch)::Nil) match { + case None => println(s"Got no doc comment for $name") + case Some(comment) => + import comment._ + def cnt(bodies: Iterable[Body]) = bodies.size + val actual = cnt(example) + cnt(version) + cnt(since) + cnt(todo) + cnt(note) + cnt(see) + if (actual != i) + println(s"Got docComment with $actual tags instead of $i, file text:\n$newText") + } + } + } + } + + // Check inter-classes documentation one-time retrieved ok. + val baseSource = findSource("Base.scala") + val derivedSource = findSource("Derived.scala") + def existsText(where: Any, text: String): Boolean = where match { + case `text` => true + case s: Seq[_] => s exists (existsText(_, text)) + case p: Product => p.productIterator exists (existsText(_, text)) + } + val (derived, base) = compiler.ask { () => + val derived = definitions.RootPackage.info.decl(newTermName("p")).info.decl(newTypeName("Derived")) + (derived, derived.ancestors(0)) + } + val cmt1 = getComment(derived, derivedSource, (base, baseSource)::(derived, derivedSource)::Nil) + if (!existsText(cmt1, "Derived comment.")) + println("Unexpected Derived class comment:"+cmt1) + + val (fooDerived, fooBase) = compiler.ask { () => + val decl = derived.tpe.decl(newTermName("foo")) + (decl, decl.allOverriddenSymbols(0)) + } + + val cmt2 = getComment(fooDerived, derivedSource, (fooBase, baseSource)::(fooDerived, derivedSource)::Nil) + if (!existsText(cmt2, "Base method has documentation.")) + println("Unexpected foo method comment:"+cmt2) + } +} diff --git a/test/files/presentation/doc/src/Class.scala b/test/files/presentation/doc/src/Class.scala new file mode 100755 index 0000000000..a974bd6f5c --- /dev/null +++ b/test/files/presentation/doc/src/Class.scala @@ -0,0 +1 @@ +object Class \ No newline at end of file diff --git a/test/files/presentation/doc/src/p/Base.scala b/test/files/presentation/doc/src/p/Base.scala new file mode 100755 index 0000000000..9031de3e3e --- /dev/null +++ b/test/files/presentation/doc/src/p/Base.scala @@ -0,0 +1,11 @@ +package p + +/** + * @define BaseComment $BaseVar comment. + */ +trait Base { + /** + * Base method has documentation. + */ + def foo: String +} diff --git a/test/files/presentation/doc/src/p/Derived.scala b/test/files/presentation/doc/src/p/Derived.scala new file mode 100755 index 0000000000..1a9c9a26d1 --- /dev/null +++ b/test/files/presentation/doc/src/p/Derived.scala @@ -0,0 +1,9 @@ +package p + +/** + * $BaseComment + * @define BaseVar Derived + */ +class Derived extends Base { + def foo = "" +} diff --git a/test/pending/presentation/doc.check b/test/pending/presentation/doc.check deleted file mode 100644 index 5a3ff13151..0000000000 --- a/test/pending/presentation/doc.check +++ /dev/null @@ -1 +0,0 @@ -reload: Base.scala, Class.scala, Derived.scala diff --git a/test/pending/presentation/doc/doc.scala b/test/pending/presentation/doc/doc.scala deleted file mode 100755 index d198f4c324..0000000000 --- a/test/pending/presentation/doc/doc.scala +++ /dev/null @@ -1,145 +0,0 @@ -import scala.tools.nsc.doc -import scala.tools.nsc.doc.base._ -import scala.tools.nsc.doc.base.comment._ -import scala.tools.nsc.interactive._ -import scala.tools.nsc.interactive.tests._ -import scala.tools.nsc.util._ - -object Test extends InteractiveTest { - val tags = Seq( - "@example `\"abb\".permutations = Iterator(abb, bab, bba)`", - "@version 1.0, 09/07/2012", - "@since 2.10", - "@todo this is unsafe!", - "@note Don't inherit!", - "@see something else" - ) - - val names = Seq("Class", "Def", "Val", "Var", "AbstracType", "TypeAlias", "Trait", "InnerClass") - val bareText = - """abstract class %s { - | def %s = "" - | val %s = "" - | var %s: String = _ - | type %s - | type %s = String - | class %s - |} - |trait %s""".stripMargin.format(names: _*) - - def docComment(nTags: Int) = "/**\n%s*/".format(tags.take(nTags).mkString("\n")) - - def text(name: String, nTags: Int) = { - val nameIndex = bareText.indexOf(name) - val (pre, post) = bareText.splitAt(nameIndex) - val crIndex = pre.lastIndexOf("\n") - val (prepre, prepost) = pre.splitAt(crIndex) - prepre + docComment(nTags) + prepost + post - } - - - - override lazy val compiler = { - prepareSettings(settings) - new Global(settings, compilerReporter) with MemberLookupBase with CommentFactoryBase { - outer => - val global: this.type = this - - override lazy val analyzer = new { - val global: outer.type = outer - } with doc.ScaladocAnalyzer - - def chooseLink(links: List[LinkTo]): LinkTo = links.head - def internalLink(sym: Symbol, site: Symbol) = None - def toString(link: LinkTo) = link.toString - def warnNoLink = false - def findExternalLink(sym: Symbol, name: String) = None - - override def forScaladoc = true - - def getComment(sym: Symbol, source: SourceFile, fragments: List[(Symbol,SourceFile)]): Option[Comment] = { - val docResponse = new Response[(String, String, Position)] - askDocComment(sym, source, sym.owner, fragments, docResponse) - docResponse.get.left.toOption flatMap { - case (expanded, raw, pos) => - if (expanded.isEmpty) - None - else - Some(ask { () => parseAtSymbol(expanded, raw, pos, Some(sym.owner)) }) - } - } - } - } - - override def runDefaultTests() { - import compiler._ - def findSource(name: String) = sourceFiles.find(_.file.name == name).get - - val className = names.head - for (name <- names; - i <- 1 to tags.length) { - val newText = text(name, i) - val source = findSource("Class.scala") - val batch = new BatchSourceFile(source.file, newText.toCharArray) - val reloadResponse = new Response[Unit] - compiler.askReload(List(batch), reloadResponse) - reloadResponse.get.left.toOption match { - case None => - println("Couldn't reload") - case Some(_) => - val parseResponse = new Response[Tree] - askParsedEntered(batch, true, parseResponse) - parseResponse.get.left.toOption match { - case None => - println("Couldn't parse") - case Some(_) => - val sym = compiler.ask { () => - val toplevel = definitions.EmptyPackage.info.decl(newTypeName(name)) - if (toplevel eq NoSymbol) { - val clazz = definitions.EmptyPackage.info.decl(newTypeName(className)) - - val term = clazz.info.decl(newTermName(name)) - if (term eq NoSymbol) clazz.info.decl(newTypeName(name)) else - if (term.isAccessor) term.accessed else term - } else toplevel - } - - getComment(sym, batch, (sym,batch)::Nil) match { - case None => println(s"Got no doc comment for $name") - case Some(comment) => - import comment._ - def cnt(bodies: Iterable[Body]) = bodies.size - val actual = cnt(example) + cnt(version) + cnt(since) + cnt(todo) + cnt(note) + cnt(see) - if (actual != i) - println(s"Got docComment with $actual tags instead of $i, file text:\n$newText") - } - } - } - } - - // Check inter-classes documentation one-time retrieved ok. - val baseSource = findSource("Base.scala") - val derivedSource = findSource("Derived.scala") - def existsText(where: Any, text: String): Boolean = where match { - case `text` => true - case s: Seq[_] => s exists (existsText(_, text)) - case p: Product => p.productIterator exists (existsText(_, text)) - } - val (derived, base) = compiler.ask { () => - val derived = definitions.RootPackage.info.decl(newTermName("p")).info.decl(newTypeName("Derived")) - (derived, derived.ancestors(0)) - } - val cmt1 = getComment(derived, derivedSource, (base, baseSource)::(derived, derivedSource)::Nil) - if (!existsText(cmt1, "Derived comment.")) - println("Unexpected Derived class comment:"+cmt1) - - val (fooDerived, fooBase) = compiler.ask { () => - val decl = derived.tpe.decl(newTermName("foo")) - (decl, decl.allOverriddenSymbols(0)) - } - - val cmt2 = getComment(fooDerived, derivedSource, (fooBase, baseSource)::(fooDerived, derivedSource)::Nil) - if (!existsText(cmt2, "Base method has documentation.")) - println("Unexpected foo method comment:"+cmt2) - } -} diff --git a/test/pending/presentation/doc/src/Class.scala b/test/pending/presentation/doc/src/Class.scala deleted file mode 100755 index a974bd6f5c..0000000000 --- a/test/pending/presentation/doc/src/Class.scala +++ /dev/null @@ -1 +0,0 @@ -object Class \ No newline at end of file diff --git a/test/pending/presentation/doc/src/p/Base.scala b/test/pending/presentation/doc/src/p/Base.scala deleted file mode 100755 index 9031de3e3e..0000000000 --- a/test/pending/presentation/doc/src/p/Base.scala +++ /dev/null @@ -1,11 +0,0 @@ -package p - -/** - * @define BaseComment $BaseVar comment. - */ -trait Base { - /** - * Base method has documentation. - */ - def foo: String -} diff --git a/test/pending/presentation/doc/src/p/Derived.scala b/test/pending/presentation/doc/src/p/Derived.scala deleted file mode 100755 index 1a9c9a26d1..0000000000 --- a/test/pending/presentation/doc/src/p/Derived.scala +++ /dev/null @@ -1,9 +0,0 @@ -package p - -/** - * $BaseComment - * @define BaseVar Derived - */ -class Derived extends Base { - def foo = "" -} -- cgit v1.2.3