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
|
/* NSC -- new Scala compiler
* Copyright 2007-2013 LAMP/EPFL
* @author Paul Phillips
*/
package scala.tools.nsc
package doc
import scala.util.control.ControlThrowable
import reporters.Reporter
import typechecker.Analyzer
import scala.reflect.internal.util.BatchSourceFile
trait ScaladocAnalyzer extends Analyzer {
val global : Global // generally, a ScaladocGlobal
import global._
override def newTyper(context: Context): ScaladocTyper = new ScaladocTyper(context)
class ScaladocTyper(context0: Context) extends Typer(context0) {
private def unit = context.unit
override def typedDocDef(docDef: DocDef, mode: Mode, pt: Type): Tree = {
val sym = docDef.symbol
if ((sym ne null) && (sym ne NoSymbol)) {
val comment = docDef.comment
fillDocComment(sym, comment)
val typer1 = newTyper(context.makeNewScope(docDef, context.owner))
for (useCase <- comment.useCases) {
typer1.silent(_ => typer1 defineUseCases useCase) match {
case SilentTypeError(err) =>
unit.warning(useCase.pos, err.errMsg)
case _ =>
}
for (useCaseSym <- useCase.defined) {
if (sym.name != useCaseSym.name)
unit.warning(useCase.pos, "@usecase " + useCaseSym.name.decode + " does not match commented symbol: " + sym.name.decode)
}
}
}
super.typedDocDef(docDef, mode, pt)
}
def defineUseCases(useCase: UseCase): List[Symbol] = {
def stringParser(str: String): syntaxAnalyzer.Parser = {
val file = new BatchSourceFile(context.unit.source.file, str) {
override def positionInUltimateSource(pos: Position) = {
pos.withSource(context.unit.source, useCase.pos.start)
}
}
val unit = new CompilationUnit(file)
new syntaxAnalyzer.UnitParser(unit)
}
val trees = stringParser(useCase.body+";").nonLocalDefOrDcl
val enclClass = context.enclClass.owner
def defineAlias(name: Name) = (
if (context.scope.lookup(name) == NoSymbol) {
lookupVariable(name.toString.substring(1), enclClass) foreach { repl =>
silent(_.typedTypeConstructor(stringParser(repl).typ())) map { tpt =>
val alias = enclClass.newAliasType(name.toTypeName, useCase.pos)
val tparams = cloneSymbolsAtOwner(tpt.tpe.typeSymbol.typeParams, alias)
val newInfo = genPolyType(tparams, appliedType(tpt.tpe, tparams map (_.tpe)))
alias setInfo newInfo
context.scope.enter(alias)
}
}
}
)
for (tree <- trees; t <- tree)
t match {
case Ident(name) if name startsWith '$' => defineAlias(name)
case _ =>
}
useCase.aliases = context.scope.toList
namer.enterSyms(trees)
typedStats(trees, NoSymbol)
useCase.defined = context.scope.toList filterNot (useCase.aliases contains _)
if (settings.debug.value)
useCase.defined foreach (sym => println("defined use cases: %s:%s".format(sym, sym.tpe)))
useCase.defined
}
}
}
class ScaladocGlobal(settings: doc.Settings, reporter: Reporter) extends {
override val useOffsetPositions = false
} with Global(settings, reporter) {
override protected def computeInternalPhases() {
phasesSet += syntaxAnalyzer
phasesSet += analyzer.namerFactory
phasesSet += analyzer.packageObjects
phasesSet += analyzer.typerFactory
}
override def forScaladoc = true
override lazy val analyzer = new {
val global: ScaladocGlobal.this.type = ScaladocGlobal.this
} with ScaladocAnalyzer
}
|