diff options
23 files changed, 248 insertions, 96 deletions
diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf index 9ea78a2977..3d4e40a00d 100644 --- a/bincompat-backward.whitelist.conf +++ b/bincompat-backward.whitelist.conf @@ -22,6 +22,18 @@ filter { problemName=DirectMissingMethodProblem }, { + matchName="scala.collection.mutable.OpenHashMap.nextPositivePowerOfTwo" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.HashTable.nextPositivePowerOfTwo" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.mutable.HashTable.powerOfTwo" + problemName=DirectMissingMethodProblem + }, + { matchName="scala.reflect.runtime.JavaMirrors#JavaMirror.unpickleClass" problemName=IncompatibleMethTypeProblem }, diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index fdd0f0fa22..94b2a57b25 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -22,6 +22,10 @@ filter { problemName=DirectMissingMethodProblem }, { + matchName="scala.collection.mutable.HashTable.nextPositivePowerOfTwo" + problemName=DirectMissingMethodProblem + } + { matchName="scala.reflect.runtime.Settings.Yvirtpatmat" problemName=DirectMissingMethodProblem }, diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index c1b0733895..819887f959 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -953,10 +953,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter) definitions.isDefinitionsInitialized && rootMirror.isMirrorInitialized ) - override def isPastTyper = ( + override def isPastTyper = isPast(currentRun.typerPhase) + def isPast(phase: Phase) = ( (curRun ne null) && isGlobalInitialized // defense against init order issues - && (globalPhase.id > currentRun.typerPhase.id) + && (globalPhase.id > phase.id) ) // TODO - trim these to the absolute minimum. diff --git a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala index dfd5b07a3b..c18f220d95 100644 --- a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala +++ b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala @@ -446,9 +446,10 @@ abstract class ScalaPrimitives { inform(s"Unknown primitive method $cls.$method") else alts foreach (s => addPrimitive(s, - s.info.paramTypes match { - case tp :: _ if code == ADD && tp =:= StringTpe => CONCAT - case _ => code + if (code != ADD) code + else exitingTyper(s.info).paramTypes match { + case tp :: _ if tp =:= StringTpe => CONCAT + case _ => code } ) ) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 503f64a44f..7a3b8d2ab6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -62,7 +62,7 @@ trait Contexts { self: Analyzer => def warnUnusedImports(unit: CompilationUnit) = if (!unit.isJava) { for (imps <- allImportInfos.remove(unit)) { - for (imp <- imps.reverse.distinct) { + for (imp <- imps.distinct.reverse) { val used = allUsedSelectors(imp) imp.tree.selectors filterNot (s => isMaskImport(s) || used(s)) foreach { sel => diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index 990edcd86d..50743a922a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -112,7 +112,7 @@ abstract class TreeCheckers extends Analyzer { else if (prevTrees exists (t => (t eq tree) || (t.symbol == sym))) () else { - val s1 = (prevTrees map wholetreestr).sorted.distinct + val s1 = (prevTrees map wholetreestr).distinct.sorted val s2 = wholetreestr(tree) if (s1 contains s2) () else movedMsgs += ("\n** %s moved:\n** Previously:\n%s\n** Currently:\n%s".format(ownerstr(sym), s1 mkString ", ", s2)) diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index b66dbf21c0..36b9a65334 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -11,6 +11,7 @@ import scala.collection.mutable.ListBuffer import scala.util.control.Exception.ultimately import symtab.Flags._ import PartialFunction._ +import scala.annotation.tailrec /** An interface to enable higher configurability of diagnostic messages * regarding type errors. This is barely a beginning as error messages are @@ -274,19 +275,54 @@ trait TypeDiagnostics { if (AnyRefTpe <:< req) notAnyRefMessage(found) else "" } + def finalOwners(tpe: Type): Boolean = (tpe.prefix == NoPrefix) || recursivelyFinal(tpe) + + @tailrec + final def recursivelyFinal(tpe: Type): Boolean = { + val prefix = tpe.prefix + if (prefix != NoPrefix) { + if (prefix.typeSymbol.isFinal) { + recursivelyFinal(prefix) + } else { + false + } + } else { + true + } + } + // TODO - figure out how to avoid doing any work at all // when the message will never be seen. I though context.reportErrors // being false would do that, but if I return "<suppressed>" under // that condition, I see it. def foundReqMsg(found: Type, req: Type): String = { - def baseMessage = ( - ";\n found : " + found.toLongString + existentialContext(found) + explainAlias(found) + - "\n required: " + req + existentialContext(req) + explainAlias(req) - ) - ( withDisambiguation(Nil, found, req)(baseMessage) - + explainVariance(found, req) - + explainAnyVsAnyRef(found, req) - ) + val foundWiden = found.widen + val reqWiden = req.widen + val sameNamesDifferentPrefixes = + foundWiden.typeSymbol.name == reqWiden.typeSymbol.name && + foundWiden.prefix.typeSymbol != reqWiden.prefix.typeSymbol + val easilyMistakable = + sameNamesDifferentPrefixes && + !req.typeSymbol.isConstant && + finalOwners(foundWiden) && finalOwners(reqWiden) && + !found.typeSymbol.isTypeParameterOrSkolem && !req.typeSymbol.isTypeParameterOrSkolem + + if (easilyMistakable) { + val longestNameLength = foundWiden.nameAndArgsString.length max reqWiden.nameAndArgsString.length + val paddedFoundName = foundWiden.nameAndArgsString.padTo(longestNameLength, ' ') + val paddedReqName = reqWiden.nameAndArgsString.padTo(longestNameLength, ' ') + ";\n found : " + (paddedFoundName + s" (in ${found.prefix.typeSymbol.fullNameString}) ") + explainAlias(found) + + "\n required: " + (paddedReqName + s" (in ${req.prefix.typeSymbol.fullNameString}) ") + explainAlias(req) + } else { + def baseMessage = { + ";\n found : " + found.toLongString + existentialContext(found) + explainAlias(found) + + "\n required: " + req + existentialContext(req) + explainAlias(req) + } + (withDisambiguation(Nil, found, req)(baseMessage) + + explainVariance(found, req) + + explainAnyVsAnyRef(found, req) + ) + } } def typePatternAdvice(sym: Symbol, ptSym: Symbol) = { @@ -315,14 +351,6 @@ trait TypeDiagnostics { def restoreName() = sym.name = savedName def modifyName(f: String => String) = sym setName newTypeName(f(sym.name.toString)) - /** Prepend java.lang, scala., or Predef. if this type originated - * in one of those. - */ - def qualifyDefaultNamespaces() = { - val intersect = Set(trueOwner, aliasOwner) intersect UnqualifiedOwners - if (intersect.nonEmpty && tp.typeSymbolDirect.name == tp.typeSymbol.name) preQualify() - } - // functions to manipulate the name def preQualify() = modifyName(trueOwner.fullName + "." + _) def postQualify() = if (!(postQualifiedWith contains trueOwner)) { postQualifiedWith ::= trueOwner; modifyName(_ + "(in " + trueOwner + ")") } @@ -414,12 +442,6 @@ trait TypeDiagnostics { if (td1 string_== td2) tds foreach (_.nameQualify()) - // If they have the same simple name, and either of them is in the - // scala package or predef, qualify with scala so it is not confusing why - // e.g. java.util.Iterator and Iterator are different types. - if (td1 name_== td2) - tds foreach (_.qualifyDefaultNamespaces()) - // If they still print identically: // a) If they are type parameters with different owners, append (in <owner>) // b) Failing that, the best we can do is append "(some other)" to the latter. diff --git a/src/library/scala/collection/mutable/FlatHashTable.scala b/src/library/scala/collection/mutable/FlatHashTable.scala index 8c4115b1dd..0d8799282f 100644 --- a/src/library/scala/collection/mutable/FlatHashTable.scala +++ b/src/library/scala/collection/mutable/FlatHashTable.scala @@ -47,9 +47,7 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { @transient protected var seedvalue: Int = tableSizeSeed - import HashTable.powerOfTwo - - protected def capacity(expectedSize: Int) = if (expectedSize == 0) 1 else powerOfTwo(expectedSize) + protected def capacity(expectedSize: Int) = HashTable.nextPositivePowerOfTwo(expectedSize) /** The initial size of the hash table. */ diff --git a/src/library/scala/collection/mutable/HashTable.scala b/src/library/scala/collection/mutable/HashTable.scala index 445217ebef..01ec1defad 100644 --- a/src/library/scala/collection/mutable/HashTable.scala +++ b/src/library/scala/collection/mutable/HashTable.scala @@ -12,7 +12,7 @@ package scala package collection package mutable -import java.lang.Integer.rotateRight +import java.lang.Integer.{numberOfLeadingZeros, rotateRight} import scala.util.hashing.byteswap32 /** This class can be used to construct data structures that are based @@ -405,7 +405,7 @@ private[collection] object HashTable { private[collection] final def sizeForThreshold(_loadFactor: Int, thr: Int) = ((thr.toLong * loadFactorDenum) / _loadFactor).toInt - private[collection] final def capacity(expectedSize: Int) = if (expectedSize == 0) 1 else powerOfTwo(expectedSize) + private[collection] final def capacity(expectedSize: Int) = nextPositivePowerOfTwo(expectedSize) trait HashUtils[KeyType] { protected final def sizeMapBucketBitSize = 5 @@ -433,16 +433,7 @@ private[collection] object HashTable { /** * Returns a power of two >= `target`. */ - private[collection] def powerOfTwo(target: Int): Int = { - /* See http://bits.stephan-brumme.com/roundUpToNextPowerOfTwo.html */ - var c = target - 1 - c |= c >>> 1 - c |= c >>> 2 - c |= c >>> 4 - c |= c >>> 8 - c |= c >>> 16 - c + 1 - } + private[collection] def nextPositivePowerOfTwo(target: Int): Int = 1 << -numberOfLeadingZeros(target - 1) class Contents[A, Entry >: Null <: HashEntry[A, Entry]]( val loadFactor: Int, diff --git a/src/library/scala/collection/mutable/OpenHashMap.scala b/src/library/scala/collection/mutable/OpenHashMap.scala index ca08f475ce..b2e9ee27b9 100644 --- a/src/library/scala/collection/mutable/OpenHashMap.scala +++ b/src/library/scala/collection/mutable/OpenHashMap.scala @@ -31,8 +31,6 @@ object OpenHashMap { final private class OpenEntry[Key, Value](var key: Key, var hash: Int, var value: Option[Value]) - - private[mutable] def nextPositivePowerOfTwo(i : Int) = 1 << (32 - Integer.numberOfLeadingZeros(i - 1)) } /** A mutable hash map based on an open hashing scheme. The precise scheme is @@ -67,7 +65,7 @@ extends AbstractMap[Key, Value] override def empty: OpenHashMap[Key, Value] = OpenHashMap.empty[Key, Value] - private[this] val actualInitialSize = OpenHashMap.nextPositivePowerOfTwo(initialSize) + private[this] val actualInitialSize = HashTable.nextPositivePowerOfTwo(initialSize) private var mask = actualInitialSize - 1 diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 890a5796e9..9d71136fc5 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -809,7 +809,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isDerivedValueClass = isClass && !hasFlag(PACKAGE | TRAIT) && - info.firstParent.typeSymbol == AnyValClass && !isPrimitiveValueClass + !phase.erasedTypes && info.firstParent.typeSymbol == AnyValClass && !isPrimitiveValueClass final def isMethodWithExtension = isMethod && owner.isDerivedValueClass && !isParamAccessor && !isConstructor && !hasFlag(SUPERACCESSOR) && !isMacro && !isSpecialized diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index b46f071717..dc12ef9352 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -967,6 +967,8 @@ trait Types */ def directObjectString = safeToString + def nameAndArgsString = typeSymbol.name.toString + /** A test whether a type contains any unification type variables. * Overridden with custom logic except where trivially true. */ @@ -2321,6 +2323,8 @@ trait Types private def preString = if (needsPreString) pre.prefixString else "" private def argsString = if (args.isEmpty) "" else args.mkString("[", ",", "]") + override def nameAndArgsString = typeSymbol.name.toString + argsString + private def refinementDecls = fullyInitializeScope(decls) filter (sym => sym.isPossibleInRefinement && sym.isPublic) private def refinementString = ( if (sym.isStructuralRefinement) @@ -2728,6 +2732,19 @@ trait Types arg.toString } + override def nameAndArgsString: String = underlying match { + case TypeRef(_, sym, args) if !settings.debug && isRepresentableWithWildcards => + sym.name + wildcardArgsString(quantified.toSet, args).mkString("[", ",", "]") + case TypeRef(_, sym, args) => + sym.name + args.mkString("[", ",", "]") + existentialClauses + case _ => underlying.typeSymbol.name + existentialClauses + } + + private def existentialClauses = { + val str = quantified map (_.existentialToString) mkString (" forSome { ", "; ", " }") + if (settings.explaintypes) "(" + str + ")" else str + } + /** An existential can only be printed with wildcards if: * - the underlying type is a typeref * - every quantified variable appears at most once as a type argument and @@ -2746,7 +2763,7 @@ trait Types tpe.typeSymbol.isRefinementClass && (tpe.parents exists isQuantified) } val (wildcardArgs, otherArgs) = args partition (arg => qset contains arg.typeSymbol) - wildcardArgs.distinct == wildcardArgs && + wildcardArgs.toSet.size == wildcardArgs.size && !(otherArgs exists (arg => isQuantified(arg))) && !(wildcardArgs exists (arg => isQuantified(arg.typeSymbol.info.bounds))) && !(qset contains sym) && @@ -2756,17 +2773,13 @@ trait Types } override def safeToString: String = { - def clauses = { - val str = quantified map (_.existentialToString) mkString (" forSome { ", "; ", " }") - if (settings.explaintypes) "(" + str + ")" else str - } underlying match { case TypeRef(pre, sym, args) if !settings.debug && isRepresentableWithWildcards => "" + TypeRef(pre, sym, Nil) + wildcardArgsString(quantified.toSet, args).mkString("[", ", ", "]") case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) => - "(" + underlying + ")" + clauses + "(" + underlying + ")" + existentialClauses case _ => - "" + underlying + clauses + "" + underlying + existentialClauses } } diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index 08ccac8069..b4152c9b8c 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -377,7 +377,7 @@ abstract class UnPickler { def readThisType(): Type = { val sym = readSymbolRef() match { - case stub: StubSymbol => stub.setFlag(PACKAGE) + case stub: StubSymbol => stub.setFlag(PACKAGE | MODULE) case sym => sym } ThisType(sym) diff --git a/src/scaladoc/scala/tools/nsc/doc/html/Page.scala b/src/scaladoc/scala/tools/nsc/doc/html/Page.scala index c720c4939f..a84f77919d 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/Page.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/Page.scala @@ -7,7 +7,7 @@ package scala package tools.nsc.doc.html import scala.tools.nsc.doc.model._ -import scala.tools.nsc.doc.base.comment +import scala.tools.nsc.doc.base.comment._ import java.io.{FileOutputStream, File} import scala.reflect.NameTransformer import java.nio.channels.Channels @@ -106,16 +106,21 @@ abstract class Page { case dtpl: DocTemplateEntity => dtpl.companion.isDefined case _ => false } +} - protected def inlineToStr(inl: comment.Inline): String = inl match { - case comment.Chain(items) => items flatMap (inlineToStr(_)) mkString "" - case comment.Italic(in) => inlineToStr(in) - case comment.Bold(in) => inlineToStr(in) - case comment.Underline(in) => inlineToStr(in) - case comment.Monospace(in) => inlineToStr(in) - case comment.Text(text) => text - case comment.Summary(in) => inlineToStr(in) - case comment.EntityLink(comment.Text(text), _) => text - case _ => inl.toString +object Page { + def inlineToStr(inl: Inline): String = inl match { + case Chain(items) => items flatMap (inlineToStr(_)) mkString "" + case Italic(in) => inlineToStr(in) + case Bold(in) => inlineToStr(in) + case Underline(in) => inlineToStr(in) + case Superscript(in) => inlineToStr(in) + case Subscript(in) => inlineToStr(in) + case Link(raw, title) => inlineToStr(title) + case Monospace(in) => inlineToStr(in) + case Text(text) => text + case Summary(in) => inlineToStr(in) + case HtmlTag(tag) => "<[^>]*>".r.replaceAllIn(tag, "") + case EntityLink(in, _) => inlineToStr(in) } } diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala index 54bf42bbd5..fb2bf5049f 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala @@ -90,13 +90,13 @@ trait EntityPage extends HtmlPage { mbr match { case dtpl: DocTemplateEntity => dtpl.companion.fold(<span class="separator"></span>) { c: DocTemplateEntity => - <a class="object" href={relativeLinkTo(c)} title={c.comment.fold("")(com => inlineToStr(com.short))}></a> + <a class="object" href={relativeLinkTo(c)} title={c.comment.fold("")(com => Page.inlineToStr(com.short))}></a> } case _ => <span class="separator"></span> } } - <a class={mbr.kind} href={relativeLinkTo(mbr)} title={mbr.comment.fold("")(com => inlineToStr(com.short))}></a> - <a href={relativeLinkTo(mbr)} title={mbr.comment.fold("")(com => inlineToStr(com.short))}> + <a class={mbr.kind} href={relativeLinkTo(mbr)} title={mbr.comment.fold("")(com => Page.inlineToStr(com.short))}></a> + <a href={relativeLinkTo(mbr)} title={mbr.comment.fold("")(com => Page.inlineToStr(com.short))}> {mbr.name} </a> </li> @@ -897,7 +897,7 @@ trait EntityPage extends HtmlPage { } } if (!nameLink.isEmpty) - <a title={mbr.comment.fold("")(c => inlineToStr(c.short))} href={nameLink}> + <a title={mbr.comment.fold("")(c => Page.inlineToStr(c.short))} href={nameLink}> {nameHtml} </a> else nameHtml @@ -1065,7 +1065,7 @@ trait EntityPage extends HtmlPage { body.blocks flatMap (blockToStr(_)) mkString "" private def blockToStr(block: comment.Block): String = block match { - case comment.Paragraph(in) => inlineToStr(in) + case comment.Paragraph(in) => Page.inlineToStr(in) case _ => block.toString } diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/IndexScript.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/IndexScript.scala index 8f58a7b845..28304e76c7 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/IndexScript.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/IndexScript.scala @@ -87,7 +87,7 @@ class IndexScript(universe: doc.Universe) extends Page { /** Gets the short description i.e. the first sentence of the docstring */ def shortDesc(mbr: MemberEntity): String = mbr.comment.fold("") { c => - inlineToStr(c.short).replaceAll("\n", "") + Page.inlineToStr(c.short).replaceAll("\n", "") } /** Returns the json representation of the supplied members */ diff --git a/test/files/neg/no-predef.check b/test/files/neg/no-predef.check index a63d8c5ba5..f5c2e82fe1 100644 --- a/test/files/neg/no-predef.check +++ b/test/files/neg/no-predef.check @@ -1,11 +1,11 @@ no-predef.scala:2: error: type mismatch; - found : scala.Long(5L) - required: java.lang.Long + found : Long (in scala) + required: Long (in java.lang) def f1 = 5L: java.lang.Long ^ no-predef.scala:3: error: type mismatch; - found : java.lang.Long - required: scala.Long + found : Long (in java.lang) + required: Long (in scala) def f2 = new java.lang.Long(5) : Long ^ no-predef.scala:4: error: value map is not a member of String diff --git a/test/files/neg/t2102.check b/test/files/neg/t2102.check index b4f91a5319..6f70839d22 100644 --- a/test/files/neg/t2102.check +++ b/test/files/neg/t2102.check @@ -1,6 +1,6 @@ t2102.scala:2: error: type mismatch; - found : java.util.Iterator[Int] - required: scala.collection.Iterator[_] + found : Iterator[Int] (in java.util) + required: Iterator[_] (in scala.collection) val x: Iterator[_] = new java.util.ArrayList[Int]().iterator ^ one error found diff --git a/test/files/neg/type-diagnostics.check b/test/files/neg/type-diagnostics.check index c5e6dec3f8..fd327bcb66 100644 --- a/test/files/neg/type-diagnostics.check +++ b/test/files/neg/type-diagnostics.check @@ -1,6 +1,6 @@ type-diagnostics.scala:4: error: type mismatch; - found : scala.collection.Set[String] - required: scala.collection.immutable.Set[String] + found : Set[String] (in scala.collection) + required: Set[String] (in scala.collection.immutable) def f = Calculator("Hello", binding.keySet: collection.Set[String]) ^ type-diagnostics.scala:13: error: type mismatch; diff --git a/test/files/run/t10171/Test.scala b/test/files/run/t10171/Test.scala new file mode 100644 index 0000000000..37a2cfc67f --- /dev/null +++ b/test/files/run/t10171/Test.scala @@ -0,0 +1,59 @@ +import scala.tools.partest._ +import java.io.File + +object Test extends StoreReporterDirectTest { + def code = ??? + + def compileCode(code: String) = { + val classpath = List(sys.props("partest.lib"), testOutput.path) mkString sys.props("path.separator") + compileString(newCompiler("-cp", classpath, "-d", testOutput.path))(code) + } + + def library = """ +package a { + package b { + class C { class D } + } +} +package z { + class Base { + type S = String + def foo(s: S): a.b.C#D = null + } + class Sub extends Base { + def sub = "sub" + } +} + """ + + def client = """ + class Client { new z.Sub().sub } + """ + + def deleteClass(s: String) = { + val f = new File(testOutput.path, s + ".class") + assert(f.exists) + f.delete() + } + + def deletePackage(s: String) = { + val f = new File(testOutput.path, s) + assert(f.exists) + f.delete() + } + + def assertNoErrors(): Unit = { + assert(storeReporter.infos.isEmpty, storeReporter.infos.mkString("\n")) + storeReporter.reset() + } + def show(): Unit = { + compileCode(library) + assertNoErrors() + deleteClass("a/b/C$D") + deleteClass("a/b/C") + deletePackage("a/b") + compileCode(client) + assertNoErrors() + } +} + diff --git a/test/scaladoc/run/inlineToStr-strips-unwanted-text.check b/test/scaladoc/run/inlineToStr-strips-unwanted-text.check new file mode 100644 index 0000000000..619c56180b --- /dev/null +++ b/test/scaladoc/run/inlineToStr-strips-unwanted-text.check @@ -0,0 +1 @@ +Done. diff --git a/test/scaladoc/run/inlineToStr-strips-unwanted-text.scala b/test/scaladoc/run/inlineToStr-strips-unwanted-text.scala new file mode 100644 index 0000000000..8faaf1b93d --- /dev/null +++ b/test/scaladoc/run/inlineToStr-strips-unwanted-text.scala @@ -0,0 +1,58 @@ +import scala.tools.nsc.doc.html.Page +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + + override def code = """ + /** This comment contains ^superscript^ */ + class Foo { + /** This comment contains ,,subscript,, */ + def bar = ??? + + /** This comment contains a link [[https://scala.epfl.ch/]] */ + def baz = ??? + + /** This comment contains an <strong>html tag</strong> */ + def qux = ??? + + /** This comment contains a<br> single html tag */ + def quux = ??? + + /** This comment contains nested <strong>html<br> tags</strong> */ + def quuz = ??? + + /** This comment contains a [[corge ,,link with a subscript title,,]] */ + def corge = ??? + } + """ + def scaladocSettings = "" + + def testModel(root: Package) = { + import scala.tools.nsc.doc.base.comment._ + import access._ + + val foo = root._class("Foo") + + val fooStr = Page.inlineToStr(foo.comment.get.short) + assert(fooStr == "This comment contains superscript", fooStr) + + val barStr = Page.inlineToStr(foo._method("bar").comment.get.short) + assert(barStr == "This comment contains subscript", barStr) + + val bazStr = Page.inlineToStr(foo._method("baz").comment.get.short) + assert(bazStr == "This comment contains a link https://scala.epfl.ch/", bazStr) + + val quxStr = Page.inlineToStr(foo._method("qux").comment.get.short) + assert(quxStr == "This comment contains an html tag", quxStr) + + val quuxStr = Page.inlineToStr(foo._method("quux").comment.get.short) + assert(quuxStr == "This comment contains a single html tag", quuxStr) + + val quuzStr = Page.inlineToStr(foo._method("quuz").comment.get.short) + assert(quuzStr == "This comment contains nested html tags", quuzStr) + + val corgeStr = Page.inlineToStr(foo._method("corge").comment.get.short) + assert(corgeStr == "This comment contains a link with a subscript title", corgeStr) + } +} diff --git a/test/scaladoc/run/shortDescription-annotation.scala b/test/scaladoc/run/shortDescription-annotation.scala index 0e2950f4f9..4f9a891133 100644 --- a/test/scaladoc/run/shortDescription-annotation.scala +++ b/test/scaladoc/run/shortDescription-annotation.scala @@ -1,3 +1,4 @@ +import scala.tools.nsc.doc.html.Page import scala.tools.nsc.doc.model._ import scala.tools.partest.ScaladocModelTest @@ -26,30 +27,18 @@ object Test extends ScaladocModelTest { import scala.tools.nsc.doc.base.comment._ import access._ - def inlineToStr(inl: Inline): String = inl match { - case Chain(items) => items flatMap (inlineToStr(_)) mkString "" - case Italic(in) => inlineToStr(in) - case Bold(in) => inlineToStr(in) - case Underline(in) => inlineToStr(in) - case Monospace(in) => inlineToStr(in) - case Text(text) => text - case Summary(in) => inlineToStr(in) - case EntityLink(Text(text), _) => text - case _ => inl.toString - } - val foo = rootPackage._package("a")._class("Foo") // Assert that the class has the correct short description - val classDesc = inlineToStr(foo.comment.get.short) + val classDesc = Page.inlineToStr(foo.comment.get.short) assert(classDesc == "This one should appear", classDesc) // Assert that the `foo` method has the correct short description - val fooDesc = inlineToStr(foo._method("foo").comment.get.short) + val fooDesc = Page.inlineToStr(foo._method("foo").comment.get.short) assert(fooDesc == "This comment should appear", fooDesc) // Assert that the `goo` method has the correct short description - val gooDesc = inlineToStr(foo._method("goo").comment.get.short) + val gooDesc = Page.inlineToStr(foo._method("goo").comment.get.short) assert(gooDesc == "This comment should appear", gooDesc) } } |