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
|
/* NSC -- new Scala compiler
* Copyright 2005-2012 LAMP/EPFL
* @author Martin Odersky
*/
package scala.tools.nsc
package symtab
import scala.reflect.internal.util.BatchSourceFile
import scala.tools.nsc.io.AbstractFile
/** A subclass of SymbolLoaders that implements browsing behavior.
* This class should be used whenever file dependencies and recompile sets
* are managed automatically.
*/
abstract class BrowsingLoaders extends SymbolLoaders {
import global._
import syntaxAnalyzer.{OutlineParser, MalformedInput}
/** In browse mode, it can happen that an encountered symbol is already
* present. For instance, if the source file has a name different from
* the classes and objects it contains, the symbol loader will always
* reparse the source file. The symbols it encounters might already be loaded
* as class files. In this case we return the one which has a sourcefile
* (and the other has not), and issue an error if both have sourcefiles.
*/
override protected def enterIfNew(owner: Symbol, member: Symbol, completer: SymbolLoader): Symbol = {
completer.sourcefile match {
case Some(src) =>
(if (member.isModule) member.moduleClass else member).sourceFile = src
case _ =>
}
val decls = owner.info.decls
val existing = decls.lookup(member.name)
if (existing == NoSymbol) {
decls enter member
member
} else if (existing.sourceFile == null) {
decls unlink existing
decls enter member
member
} else {
if (member.sourceFile != null) {
if (existing.sourceFile != member.sourceFile)
error(member+"is defined twice,"+
"\n in "+existing.sourceFile+
"\n and also in "+member.sourceFile)
}
existing
}
}
/** Browse the top-level of given abstract file `src` and enter
* eny encountered top-level classes and modules in `root`
*/
def browseTopLevel(root: Symbol, src: AbstractFile) {
class BrowserTraverser extends Traverser {
var packagePrefix = ""
var entered = 0
def addPackagePrefix(pkg: Tree): Unit = pkg match {
case Select(pre, name) =>
addPackagePrefix(pre)
packagePrefix += ("." + name)
case Ident(name) =>
if (packagePrefix.length != 0) packagePrefix += "."
packagePrefix += name
case _ =>
throw new MalformedInput(pkg.pos.point, "illegal tree node in package prefix: "+pkg)
}
private def inPackagePrefix(pkg: Tree)(op: => Unit): Unit = {
val oldPrefix = packagePrefix
addPackagePrefix(pkg)
op
packagePrefix = oldPrefix
}
override def traverse(tree: Tree): Unit = tree match {
case PackageDef(pkg, body) =>
inPackagePrefix(pkg) { body foreach traverse }
case ClassDef(_, name, _, _) =>
if (packagePrefix == root.fullName) {
enterClass(root, name.toString, new SourcefileLoader(src))
entered += 1
} else println("prefixes differ: "+packagePrefix+","+root.fullName)
case ModuleDef(_, name, _) =>
if (packagePrefix == root.fullName) {
val module = enterModule(root, name.toString, new SourcefileLoader(src))
entered += 1
if (name == nme.PACKAGEkw) {
println("open package module: "+module)
openPackageModule(module, root)
}
} else println("prefixes differ: "+packagePrefix+","+root.fullName)
case _ =>
}
}
// System.out.println("Browsing "+src)
val source = getSourceFile(src) // this uses the current encoding
val body = new OutlineParser(source).parse()
// System.out.println(body)
val browser = new BrowserTraverser
browser.traverse(body)
if (browser.entered == 0)
warning("No classes or objects found in "+source+" that go in "+root)
}
/** Enter top-level symbols from a source file
*/
override def enterToplevelsFromSource(root: Symbol, name: String, src: AbstractFile) {
try {
if (root.isEffectiveRoot || !src.name.endsWith(".scala")) // RootClass or EmptyPackageClass
super.enterToplevelsFromSource(root, name, src)
else
browseTopLevel(root, src)
} catch {
case ex: syntaxAnalyzer.MalformedInput =>
println("[%s] caught malformed input exception at offset %d: %s".format(src, ex.offset, ex.msg))
super.enterToplevelsFromSource(root, name, src)
}
}
}
|