1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
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 s: String => s contains text
case s: Seq[_] => s exists (existsText(_, text))
case p: Product => p.productIterator exists (existsText(_, text))
case c: Comment => existsText(c.body, 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, "This is 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)
}
}
|