@@ -53,61 +53,85 @@ class InteractiveDriver(val settings: List[String]) extends Driver {
53
53
def openedTrees : Map [URI , List [SourceTree ]] = myOpenedTrees
54
54
def compilationUnits : Map [URI , CompilationUnit ] = myCompilationUnits
55
55
56
+ /**
57
+ * The trees for all the source files in this project.
58
+ *
59
+ * This includes the trees for the buffers that are presently open in the IDE, and the trees
60
+ * from the target directory.
61
+ */
62
+ def sourceTrees (implicit ctx : Context ): List [SourceTree ] = sourceTreesContaining(" " )
63
+
64
+ /**
65
+ * The trees for all the source files in this project that contain `id`.
66
+ *
67
+ * This includes the trees for the buffers that are presently open in the IDE, and the trees
68
+ * from the target directory.
69
+ */
70
+ def sourceTreesContaining (id : String )(implicit ctx : Context ): List [SourceTree ] = {
71
+ val fromBuffers = openedTrees.values.flatten.toList
72
+ val fromCompilationOutput = {
73
+ val classNames = new mutable.ListBuffer [String ]
74
+ val output = ctx.settings.outputDir.value
75
+ if (output.isDirectory) {
76
+ classesFromDir(output.jpath, classNames)
77
+ } else {
78
+ val zipFile = new ZipFile (output.file)
79
+ classesFromZip(zipFile, classNames)
80
+ }
81
+ classNames.flatMap { cls =>
82
+ val className = cls.toTypeName
83
+ treesFromClassName(className, id = " " )
84
+ }
85
+ }
86
+ (fromBuffers ++ fromCompilationOutput).distinct
87
+ }
88
+
89
+ /**
90
+ * All the trees for this project.
91
+ *
92
+ * This includes the trees of the sources of this project, along with the trees that are found
93
+ * on this project's classpath.
94
+ */
56
95
def allTrees (implicit ctx : Context ): List [SourceTree ] = allTreesContaining(" " )
57
96
97
+ /**
98
+ * All the trees for this project that contain `id`.
99
+ *
100
+ * This includes the trees of the sources of this project, along with the trees that are found
101
+ * on this project's classpath.
102
+ */
58
103
def allTreesContaining (id : String )(implicit ctx : Context ): List [SourceTree ] = {
59
104
val fromSource = openedTrees.values.flatten.toList
60
105
val fromClassPath = (dirClassPathClasses ++ zipClassPathClasses).flatMap { cls =>
61
106
val className = cls.toTypeName
62
- List (tree( className, id), tree(className.moduleClassName, id)).flatten
107
+ treesFromClassName( className, id)
63
108
}
64
109
(fromSource ++ fromClassPath).distinct
65
110
}
66
111
67
- private def tree (className : TypeName , id : String )(implicit ctx : Context ): Option [SourceTree ] = {
68
- val clsd = ctx.base.staticRef(className)
69
- clsd match {
70
- case clsd : ClassDenotation =>
71
- clsd.ensureCompleted()
72
- SourceTree .fromSymbol(clsd.symbol.asClass, id)
73
- case _ =>
74
- None
112
+ /**
113
+ * The `SourceTree`s that define the class `className` and/or module `className`.
114
+ *
115
+ * @see SourceTree.fromSymbol
116
+ */
117
+ private def treesFromClassName (className : TypeName , id : String )(implicit ctx : Context ): List [SourceTree ] = {
118
+ def tree (className : TypeName , id : String ): Option [SourceTree ] = {
119
+ val clsd = ctx.base.staticRef(className)
120
+ clsd match {
121
+ case clsd : ClassDenotation =>
122
+ clsd.ensureCompleted()
123
+ SourceTree .fromSymbol(clsd.symbol.asClass, id)
124
+ case _ =>
125
+ None
126
+ }
75
127
}
128
+ List (tree(className, id), tree(className.moduleClassName, id)).flatten
76
129
}
77
130
78
131
// Presence of a file with one of these suffixes indicates that the
79
132
// corresponding class has been pickled with TASTY.
80
133
private val tastySuffixes = List (" .hasTasty" , " .tasty" )
81
134
82
- private def classNames (cp : ClassPath , packageName : String ): List [String ] = {
83
- def className (classSegments : List [String ]) =
84
- classSegments.mkString(" ." ).stripSuffix(" .class" )
85
-
86
- val ClassPathEntries (pkgs, classReps) = cp.list(packageName)
87
-
88
- classReps
89
- .filter((classRep : ClassRepresentation ) => classRep.binary match {
90
- case None =>
91
- true
92
- case Some (binFile) =>
93
- val prefix =
94
- if (binFile.name.endsWith(" .class" ))
95
- binFile.name.stripSuffix(" .class" )
96
- else
97
- null
98
- prefix != null && {
99
- binFile match {
100
- case pf : PlainFile =>
101
- tastySuffixes.map(suffix => pf.givenPath.parent / (prefix + suffix)).exists(_.exists)
102
- case _ =>
103
- sys.error(s " Unhandled file type: $binFile [getClass = ${binFile.getClass}] " )
104
- }
105
- }
106
- })
107
- .map(classRep => (packageName ++ (if (packageName != " " ) " ." else " " ) ++ classRep.name)).toList ++
108
- pkgs.flatMap(pkg => classNames(cp, pkg.name))
109
- }
110
-
111
135
// FIXME: All the code doing classpath handling is very fragile and ugly,
112
136
// improving this requires changing the dotty classpath APIs to handle our usecases.
113
137
// We also need something like sbt server-mode to be informed of changes on
@@ -128,17 +152,13 @@ class InteractiveDriver(val settings: List[String]) extends Driver {
128
152
}
129
153
130
154
// Like in `ZipArchiveFileLookup` we assume that zips are immutable
131
- private val zipClassPathClasses : Seq [String ] = zipClassPaths.flatMap { zipCp =>
132
- val zipFile = new ZipFile (zipCp.zipFile)
133
-
134
- try {
135
- for {
136
- entry <- zipFile.stream.toArray((size : Int ) => new Array [ZipEntry ](size))
137
- name = entry.getName
138
- tastySuffix <- tastySuffixes.find(name.endsWith)
139
- } yield name.replace(" /" , " ." ).stripSuffix(tastySuffix)
155
+ private val zipClassPathClasses : Seq [String ] = {
156
+ val names = new mutable.ListBuffer [String ]
157
+ zipClassPaths.foreach { zipCp =>
158
+ val zipFile = new ZipFile (zipCp.zipFile)
159
+ classesFromZip(zipFile, names)
140
160
}
141
- finally zipFile.close()
161
+ names
142
162
}
143
163
144
164
// FIXME: classfiles in directories may change at any point, so we retraverse
@@ -148,26 +168,43 @@ class InteractiveDriver(val settings: List[String]) extends Driver {
148
168
val names = new mutable.ListBuffer [String ]
149
169
dirClassPaths.foreach { dirCp =>
150
170
val root = dirCp.dir.toPath
151
- try
152
- Files .walkFileTree(root, new SimpleFileVisitor [Path ] {
153
- override def visitFile (path : Path , attrs : BasicFileAttributes ) = {
154
- if (! attrs.isDirectory) {
155
- val name = path.getFileName.toString
156
- for {
157
- tastySuffix <- tastySuffixes
158
- if name.endsWith(tastySuffix)
159
- } {
160
- names += root.relativize(path).toString.replace(" /" , " ." ).stripSuffix(tastySuffix)
161
- }
171
+ classesFromDir(root, names)
172
+ }
173
+ names.toList
174
+ }
175
+
176
+ /** Adds the names of the classes that are defined in `zipFile` to `buffer`. */
177
+ private def classesFromZip (zipFile : ZipFile , buffer : mutable.ListBuffer [String ]): Unit = {
178
+ try {
179
+ for {
180
+ entry <- zipFile.stream.toArray((size : Int ) => new Array [ZipEntry ](size))
181
+ name = entry.getName
182
+ tastySuffix <- tastySuffixes.find(name.endsWith)
183
+ } buffer += name.replace(" /" , " ." ).stripSuffix(tastySuffix)
184
+ }
185
+ finally zipFile.close()
186
+ }
187
+
188
+ /** Adds the names of the classes that are defined in `dir` to `buffer`. */
189
+ private def classesFromDir (dir : Path , buffer : mutable.ListBuffer [String ]): Unit = {
190
+ try
191
+ Files .walkFileTree(dir, new SimpleFileVisitor [Path ] {
192
+ override def visitFile (path : Path , attrs : BasicFileAttributes ) = {
193
+ if (! attrs.isDirectory) {
194
+ val name = path.getFileName.toString
195
+ for {
196
+ tastySuffix <- tastySuffixes
197
+ if name.endsWith(tastySuffix)
198
+ } {
199
+ buffer += dir.relativize(path).toString.replace(" /" , " ." ).stripSuffix(tastySuffix)
162
200
}
163
- FileVisitResult .CONTINUE
164
201
}
165
- })
166
- catch {
167
- case _ : NoSuchFileException =>
168
- }
202
+ FileVisitResult .CONTINUE
203
+ }
204
+ })
205
+ catch {
206
+ case _ : NoSuchFileException =>
169
207
}
170
- names.toList
171
208
}
172
209
173
210
private def topLevelClassTrees (topTree : Tree , source : SourceFile ): List [SourceTree ] = {
0 commit comments