Skip to content

Commit d063dd3

Browse files
author
Vlad Ureche
committed
Merge pull request scala#4464 from gourlaysama/wip/scaladoc-deprecated
SI-4476 add an index of deprecated members to scaladoc
2 parents 906584d + a3e93d9 commit d063dd3

File tree

8 files changed

+140
-4
lines changed

8 files changed

+140
-4
lines changed

src/scaladoc/scala/tools/nsc/doc/Index.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ trait Index {
1111
type SymbolMap = SortedMap[String, SortedSet[model.MemberEntity]]
1212

1313
def firstLetterIndex: Map[Char, SymbolMap]
14+
15+
def hasDeprecatedMembers: Boolean
1416
}

src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) {
123123

124124
new page.Index(universe, index) writeFor this
125125
new page.IndexScript(universe, index) writeFor this
126+
if (index.hasDeprecatedMembers)
127+
new page.DeprecatedIndex(universe, index) writeFor this
126128
try {
127129
writeTemplates(_ writeFor this)
128130
for (letter <- index.firstLetterIndex) {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/* NSC -- new Scala compiler
2+
* Copyright 2007-2013 LAMP/EPFL
3+
*/
4+
5+
package scala
6+
package tools
7+
package nsc
8+
package doc
9+
package html
10+
package page
11+
12+
import doc.model._
13+
14+
class DeprecatedIndex(universe: Universe, index: doc.Index) extends HtmlPage {
15+
16+
def path = List("deprecated-list.html")
17+
18+
def title = {
19+
val s = universe.settings
20+
( if (!s.doctitle.isDefault) s.doctitle.value else "" ) +
21+
( if (!s.docversion.isDefault) (" " + s.docversion.value) else "" )
22+
}
23+
24+
def headers =
25+
<xml:group>
26+
<link href={ relativeLinkTo(List("ref-index.css", "lib")) } media="screen" type="text/css" rel="stylesheet"/>
27+
<script type="text/javascript" src={ relativeLinkTo{List("jquery.js", "lib")} }></script>
28+
</xml:group>
29+
30+
31+
private def entry(name: String, methods: Iterable[MemberEntity]) = {
32+
val occurrences = methods.filter(_.deprecation.isDefined).map(method =>
33+
templateToHtml(method.inDefinitionTemplates.head)
34+
).toList.distinct
35+
36+
<div class="entry">
37+
<div class="name">{ name }</div>
38+
<div class="occurrences">{
39+
for (owner <- occurrences) yield owner ++ scala.xml.Text(" ")
40+
}</div>
41+
</div>
42+
}
43+
44+
def deprecatedEntries = {
45+
val available = ('_' +: ('a' to 'z')).flatMap(index.firstLetterIndex.get)
46+
47+
for (group <- available;
48+
value <- group if value._2.find(_.deprecation.isDefined).isDefined)
49+
yield value
50+
}
51+
52+
def body =
53+
<body>{
54+
for(value <- deprecatedEntries) yield
55+
entry(value._1, value._2.view)
56+
}</body>
57+
58+
}

src/scaladoc/scala/tools/nsc/doc/html/page/Index.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,17 @@ class Index(universe: doc.Universe, val index: doc.Index) extends HtmlPage {
6161
}
6262
}
6363

64+
def deprecated: NodeSeq = if (index.hasDeprecatedMembers)
65+
<a target="template" href="deprecated-list.html">deprecated</a>
66+
else
67+
<span>deprecated</span>
68+
6469
def browser =
6570
<div id="browser" class="ui-layout-west">
6671
<div class="ui-west-center">
6772
<div id="filter">
6873
<div id="textfilter"></div>
69-
<div id="letters">{ letters }</div>
74+
<div id="letters">{ letters } &#8211; { deprecated }</div>
7075
</div>
7176
<div class="pack" id="tpl">{
7277
def packageElem(pack: model.Package): NodeSeq = {

src/scaladoc/scala/tools/nsc/doc/model/IndexModelFactory.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ object IndexModelFactory {
1414

1515
def makeIndex(universe: Universe): Index = new Index {
1616

17-
lazy val firstLetterIndex: Map[Char, SymbolMap] = {
17+
lazy val (firstLetterIndex, hasDeprecatedMembers): (Map[Char, SymbolMap], Boolean) = {
1818

1919
object result extends mutable.HashMap[Char,SymbolMap] {
2020

21+
var deprecated = false
22+
2123
/* symbol name ordering */
2224
implicit def orderingMap = math.Ordering.String
2325

@@ -32,6 +34,8 @@ object IndexModelFactory {
3234
val members = letter.get(d.name).getOrElse {
3335
SortedSet.empty[MemberEntity](Ordering.by { _.toString })
3436
} + d
37+
if (!deprecated && members.find(_.deprecation.isDefined).isDefined)
38+
deprecated = true
3539
this(firstLetter) = letter + (d.name -> members)
3640
}
3741
}
@@ -50,7 +54,7 @@ object IndexModelFactory {
5054

5155
gather(universe.rootPackage)
5256

53-
result.toMap
57+
(result.toMap, result.deprecated)
5458
}
5559
}
5660
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package foo
2+
3+
@deprecated("","")
4+
class A
5+
6+
class B {
7+
@deprecated("","")
8+
def bar = 1
9+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import org.scalacheck._
2+
import org.scalacheck.Prop._
3+
4+
import scala.tools.nsc.doc
5+
import scala.tools.nsc.doc.html.page.DeprecatedIndex
6+
import java.net.{URLClassLoader, URLDecoder}
7+
8+
object Test extends Properties("IndexScript") {
9+
10+
def getClasspath = {
11+
// these things can be tricky
12+
// this test previously relied on the assumption that the current thread's classloader is an url classloader and contains all the classpaths
13+
// does partest actually guarantee this? to quote Leonard Nimoy: The answer, of course, is no.
14+
// this test _will_ fail again some time in the future.
15+
// Footnote: java.lang.ClassCastException: org.apache.tools.ant.loader.AntClassLoader5 cannot be cast to java.net.URLClassLoader
16+
val loader = Thread.currentThread.getContextClassLoader.asInstanceOf[URLClassLoader]
17+
val paths = loader.getURLs.map(u => URLDecoder.decode(u.getPath))
18+
paths mkString java.io.File.pathSeparator
19+
}
20+
21+
val docFactory = {
22+
val settings = new doc.Settings({Console.err.println(_)})
23+
settings.scaladocQuietRun = true
24+
settings.nowarn.value = true
25+
settings.classpath.value = getClasspath
26+
val reporter = new scala.tools.nsc.reporters.ConsoleReporter(settings)
27+
new doc.DocFactory(reporter, settings)
28+
}
29+
30+
val indexModelFactory = doc.model.IndexModelFactory
31+
32+
def createDeprecatedScript(path: String) =
33+
docFactory.makeUniverse(Left(List(path))) match {
34+
case Some(universe) => {
35+
val index = new DeprecatedIndex(universe, indexModelFactory.makeIndex(universe))
36+
Some(index)
37+
}
38+
case _ =>
39+
None
40+
}
41+
42+
property("deprecated-list page lists deprecated members") = {
43+
createDeprecatedScript("test/scaladoc/resources/SI-4476.scala") match {
44+
case Some(p) =>
45+
p.deprecatedEntries.find(_._1 == "A").isDefined &&
46+
p.deprecatedEntries.find(_._1 == "bar").isDefined
47+
case None => false
48+
}
49+
}
50+
}

test/scaladoc/scalacheck/IndexTest.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ object Test extends Properties("Index") {
7171
case None => false
7272
}
7373
}
74-
property("browser contants a script element") = {
74+
property("browser contains a script element") = {
7575
createIndex("src/scaladoc/scala/tools/nsc/doc/html/page/Index.scala") match {
7676
case Some(index) =>
7777
(index.browser \ "script").size == 1
@@ -86,4 +86,10 @@ object Test extends Properties("Index") {
8686
case None => false
8787
}
8888
}
89+
property("index should report if there are deprecated members") = {
90+
createIndex("test/scaladoc/resources/SI-4476.scala") match {
91+
case Some(indexPage) => indexPage.index.hasDeprecatedMembers
92+
case None => false
93+
}
94+
}
8995
}

0 commit comments

Comments
 (0)