@@ -14,14 +14,16 @@ package scala.tools.nsc.classpath
14
14
15
15
import java .io .{Closeable , File }
16
16
import java .net .{URI , URL }
17
+ import java .nio .file ._
17
18
18
- import scala .reflect .io .{AbstractFile , PlainFile , PlainNioFile }
19
- import scala .tools .nsc .util .{ClassPath , ClassRepresentation , EfficientClassPath }
20
- import FileUtils ._
21
19
import scala .jdk .CollectionConverters ._
22
20
import scala .reflect .internal .JDK9Reflectors
21
+ import scala .reflect .io .{AbstractFile , PlainFile , PlainNioFile }
23
22
import scala .tools .nsc .CloseableRegistry
24
23
import scala .tools .nsc .classpath .PackageNameUtils .{packageContains , separatePkgAndClassNames }
24
+ import scala .tools .nsc .util .{ClassPath , ClassRepresentation , EfficientClassPath }
25
+ import scala .util .Properties .{isJavaAtLeast , javaHome }
26
+ import FileUtils ._
25
27
26
28
/**
27
29
* A trait allowing to look for classpath entries in directories. It provides common logic for
@@ -129,12 +131,10 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends Directo
129
131
}
130
132
131
133
object JrtClassPath {
132
- import java .nio .file ._ , java .net .URI
133
134
private val jrtClassPathCache = new FileBasedCache [Unit , JrtClassPath ]()
134
135
private val ctSymClassPathCache = new FileBasedCache [String , CtSymClassPath ]()
135
- def apply (release : Option [String ], closeableRegistry : CloseableRegistry ): Option [ClassPath ] = {
136
- import scala .util .Properties ._
137
- if (! isJavaAtLeast(" 9" )) None
136
+ def apply (release : Option [String ], unsafe : Option [List [String ]], closeableRegistry : CloseableRegistry ): List [ClassPath ] =
137
+ if (! isJavaAtLeast(" 9" )) Nil
138
138
else {
139
139
// TODO escalate errors once we're sure they are fatal
140
140
// I'm hesitant to do this immediately, because -release will still work for multi-release JARs
@@ -145,28 +145,52 @@ object JrtClassPath {
145
145
146
146
val currentMajorVersion : Int = JDK9Reflectors .runtimeVersionMajor(JDK9Reflectors .runtimeVersion()).intValue()
147
147
release match {
148
- case Some (v) if v.toInt < currentMajorVersion =>
149
- try {
150
- val ctSym = Paths .get(javaHome).resolve(" lib" ).resolve(" ct.sym" )
151
- if (Files .notExists(ctSym)) None
152
- else {
153
- val classPath = ctSymClassPathCache.getOrCreate(v, ctSym :: Nil , () => new CtSymClassPath (ctSym, v.toInt), closeableRegistry, true )
154
- Some (classPath)
155
- }
156
- } catch {
157
- case _ : Throwable => None
148
+ case Some (version) if version.toInt < currentMajorVersion =>
149
+ val ct = createCt(version, closeableRegistry)
150
+ unsafe match {
151
+ case Some (pkgs) if pkgs.nonEmpty =>
152
+ createJrt(closeableRegistry) match {
153
+ case Nil => ct
154
+ case jrts => ct.appended(new FilteringJrtClassPath (jrts.head, pkgs : _* ))
155
+ }
156
+ case _ => ct
158
157
}
159
158
case _ =>
160
- try {
161
- val fs = FileSystems .getFileSystem(URI .create(" jrt:/" ))
162
- val classPath = jrtClassPathCache.getOrCreate((), Nil , () => new JrtClassPath (fs), closeableRegistry, false )
163
- Some (classPath)
164
- } catch {
165
- case _ : ProviderNotFoundException | _ : FileSystemNotFoundException => None
166
- }
159
+ createJrt(closeableRegistry)
167
160
}
168
161
}
169
- }
162
+ private def createCt (v : String , closeableRegistry : CloseableRegistry ): List [ClassPath ] =
163
+ try {
164
+ val ctSym = Paths .get(javaHome).resolve(" lib" ).resolve(" ct.sym" )
165
+ if (Files .notExists(ctSym)) Nil
166
+ else {
167
+ val classPath = ctSymClassPathCache.getOrCreate(v, ctSym :: Nil , () => new CtSymClassPath (ctSym, v.toInt), closeableRegistry, checkStamps= true )
168
+ List (classPath)
169
+ }
170
+ } catch {
171
+ case _ : Throwable => Nil
172
+ }
173
+ private def createJrt (closeableRegistry : CloseableRegistry ): List [JrtClassPath ] =
174
+ try {
175
+ val fs = FileSystems .getFileSystem(URI .create(" jrt:/" ))
176
+ val classPath = jrtClassPathCache.getOrCreate((), Nil , () => new JrtClassPath (fs), closeableRegistry, checkStamps= false )
177
+ List (classPath)
178
+ } catch {
179
+ case _ : ProviderNotFoundException | _ : FileSystemNotFoundException => Nil
180
+ }
181
+ }
182
+
183
+ final class FilteringJrtClassPath (delegate : JrtClassPath , allowed : String * ) extends ClassPath with NoSourcePaths {
184
+ private val allowedPackages = allowed
185
+ private def packagePrefix (p : String , q : String ) = p.startsWith(q) && (p.length == q.length || p.charAt(q.length) == '.' )
186
+ private def ok (pkg : PackageName ) = pkg.dottedString.isEmpty || allowedPackages.exists(packagePrefix(_, pkg.dottedString))
187
+ def asClassPathStrings : Seq [String ] = delegate.asClassPathStrings
188
+ def asURLs : Seq [java.net.URL ] = delegate.asURLs
189
+ private [nsc] def classes (inPackage : PackageName ) = if (ok(inPackage)) delegate.classes(inPackage) else Nil
190
+ def findClassFile (className : String ) = if (ok(PackageName (separatePkgAndClassNames(className)._1))) delegate.findClassFile(className) else None
191
+ private [nsc] def hasPackage (pkg : PackageName ) = ok(pkg) && delegate.hasPackage(pkg)
192
+ private [nsc] def list (inPackage : PackageName ) = if (ok(inPackage)) delegate.list(inPackage) else ClassPathEntries (Nil , Nil )
193
+ private [nsc] def packages (inPackage : PackageName ) = if (ok(inPackage)) delegate.packages(inPackage) else Nil
170
194
}
171
195
172
196
/**
@@ -177,8 +201,7 @@ object JrtClassPath {
177
201
*
178
202
* The implementation assumes that no classes exist in the empty package.
179
203
*/
180
- final class JrtClassPath (fs : java.nio.file.FileSystem ) extends ClassPath with NoSourcePaths {
181
- import java .nio .file .Path , java .nio .file ._
204
+ final class JrtClassPath (fs : FileSystem ) extends ClassPath with NoSourcePaths {
182
205
type F = Path
183
206
private val dir : Path = fs.getPath(" /packages" )
184
207
@@ -246,7 +269,7 @@ final class CtSymClassPath(ctSym: java.nio.file.Path, release: Int) extends Clas
246
269
// e.g. "java.lang" -> Seq(/876/java/lang, /87/java/lang, /8/java/lang))
247
270
private val packageIndex : scala.collection.Map [String , scala.collection.Seq [Path ]] = {
248
271
val index = collection.mutable.AnyRefMap [String , collection.mutable.ListBuffer [Path ]]()
249
- val isJava12OrHigher = scala.util. Properties . isJavaAtLeast(" 12" )
272
+ val isJava12OrHigher = isJavaAtLeast(" 12" )
250
273
rootsForRelease.foreach(root => Files .walk(root).iterator().asScala.filter(Files .isDirectory(_)).foreach { p =>
251
274
val moduleNamePathElementCount = if (isJava12OrHigher) 1 else 0
252
275
if (p.getNameCount > root.getNameCount + moduleNamePathElementCount) {
0 commit comments