diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2016-05-05 23:10:03 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2016-05-05 23:10:03 +1000 |
commit | a46af82b025e0dde3714ab8cbe5e76afafd7ab18 (patch) | |
tree | 82ac025ce1e9d9789d0950823f625176e9b50877 /src/compiler/scala/tools/nsc/util | |
parent | 2726320779356be1829aa1715888872606aa819b (diff) | |
parent | 30d6fce50aba1d73173339b0add4808bc13b1c40 (diff) | |
download | scala-a46af82b025e0dde3714ab8cbe5e76afafd7ab18.tar.gz scala-a46af82b025e0dde3714ab8cbe5e76afafd7ab18.tar.bz2 scala-a46af82b025e0dde3714ab8cbe5e76afafd7ab18.zip |
Merge pull request #5112 from lrytz/dropRecursiveClasspath
Remove legacy recursive classpath implementation
Diffstat (limited to 'src/compiler/scala/tools/nsc/util')
-rw-r--r-- | src/compiler/scala/tools/nsc/util/ClassFileLookup.scala | 78 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/ClassPath.scala | 367 |
2 files changed, 65 insertions, 380 deletions
diff --git a/src/compiler/scala/tools/nsc/util/ClassFileLookup.scala b/src/compiler/scala/tools/nsc/util/ClassFileLookup.scala deleted file mode 100644 index 5d8831a607..0000000000 --- a/src/compiler/scala/tools/nsc/util/ClassFileLookup.scala +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2014 Contributor. All rights reserved. - */ -package scala.tools.nsc.util - -import scala.tools.nsc.Settings -import scala.tools.nsc.classpath.{AggregateFlatClassPath, FlatClassPath, FlatClassPathFactory} -import scala.tools.nsc.io.AbstractFile -import java.net.URL - -/** - * Simple interface that allows us to abstract over how class file lookup is performed - * in different classpath representations. - */ -// TODO at the end, after the possible removal of the old classpath representation, this class shouldn't be generic -// T should be just changed to AbstractFile -trait ClassFileLookup[T] { - def findClassFile(name: String): Option[AbstractFile] - - /** - * It returns both classes from class file and source files (as our base ClassRepresentation). - * So note that it's not so strictly related to findClassFile. - */ - def findClass(name: String): Option[ClassRepresentation[T]] - - /** - * A sequence of URLs representing this classpath. - */ - def asURLs: Seq[URL] - - /** The whole classpath in the form of one String. - */ - def asClassPathString: String - - // for compatibility purposes - @deprecated("Use asClassPathString instead of this one", "2.11.5") - def asClasspathString: String = asClassPathString - - /** The whole sourcepath in the form of one String. - */ - def asSourcePathString: String -} - -object ClassFileLookup { - def createForFile(f: AbstractFile, current: ClassFileLookup[AbstractFile], settings: Settings): ClassFileLookup[AbstractFile] = current match { - case cp: ClassPath[_] => cp.context.newClassPath(f) - case _: FlatClassPath => FlatClassPathFactory.newClassPath(f, settings) - } - - def createAggregate(elems: Iterable[ClassFileLookup[AbstractFile]], current: ClassFileLookup[AbstractFile]): ClassFileLookup[AbstractFile] = { - assert(elems.nonEmpty) - if (elems.size == 1) elems.head - else current match { - case cp: ClassPath[_] => - new MergedClassPath(elems.asInstanceOf[Iterable[ClassPath[AbstractFile]]], cp.context) - - case _: FlatClassPath => - AggregateFlatClassPath.createAggregate(elems.asInstanceOf[Iterable[FlatClassPath]].toSeq : _*) - } - } -} - -/** - * Represents classes which can be loaded with a ClassfileLoader and/or SourcefileLoader. - */ -// TODO at the end, after the possible removal of the old classpath implementation, this class shouldn't be generic -// T should be just changed to AbstractFile -trait ClassRepresentation[T] { - def binary: Option[T] - def source: Option[AbstractFile] - - def name: String -} - -object ClassRepresentation { - def unapply[T](classRep: ClassRepresentation[T]): Option[(Option[T], Option[AbstractFile])] = - Some((classRep.binary, classRep.source)) -} diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index e5af1edadb..cef2fc4bbf 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -7,28 +7,61 @@ package scala.tools.nsc package util -import io.{ AbstractFile, Directory, File, Jar } +import io.{AbstractFile, Directory, File, Jar} import java.net.MalformedURLException import java.net.URL import java.util.regex.PatternSyntaxException -import scala.collection.{ mutable, immutable } -import scala.reflect.internal.util.StringOps.splitWhere -import scala.tools.nsc.classpath.FileUtils import File.pathSeparator -import FileUtils.endsClass -import FileUtils.endsScalaOrJava import Jar.isJarOrZip -/** <p> - * This module provides star expansion of '-classpath' option arguments, behaves the same as - * java, see [[http://docs.oracle.com/javase/6/docs/technotes/tools/windows/classpath.html]] - * </p> - * - * @author Stepan Koltsov - */ +/** + * A representation of the compiler's class- or sourcepath. + */ +trait ClassPath { + import scala.tools.nsc.classpath._ + def asURLs: Seq[URL] + + /** Empty string represents root package */ + private[nsc] def packages(inPackage: String): Seq[PackageEntry] + private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] + private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] + + /** Allows to get entries for packages and classes merged with sources possibly in one pass. */ + private[nsc] def list(inPackage: String): ClassPathEntries + + /** + * It returns both classes from class file and source files (as our base ClassRepresentation). + * So note that it's not so strictly related to findClassFile. + */ + def findClass(className: String): Option[ClassRepresentation] = { + // A default implementation which should be overridden, if we can create the more efficient + // solution for a given type of ClassPath + val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className) + + val foundClassFromClassFiles = classes(pkg).find(_.name == simpleClassName) + def findClassInSources = sources(pkg).find(_.name == simpleClassName) + + foundClassFromClassFiles orElse findClassInSources + } + def findClassFile(className: String): Option[AbstractFile] + + def asClassPathStrings: Seq[String] + + /** The whole classpath in the form of one String. + */ + def asClassPathString: String = ClassPath.join(asClassPathStrings: _*) + // for compatibility purposes + @deprecated("Use asClassPathString instead of this one", "2.11.5") + def asClasspathString: String = asClassPathString + + /** The whole sourcepath in the form of one String. + */ + def asSourcePathString: String +} + object ClassPath { - import scala.language.postfixOps + val RootPackage = "" /** Expand single path entry */ private def expandS(pattern: String): List[String] = { @@ -36,14 +69,14 @@ object ClassPath { /* Get all subdirectories, jars, zips out of a directory. */ def lsDir(dir: Directory, filt: String => Boolean = _ => true) = - dir.list filter (x => filt(x.name) && (x.isDirectory || isJarOrZip(x))) map (_.path) toList + dir.list.filter(x => filt(x.name) && (x.isDirectory || isJarOrZip(x))).map(_.path).toList if (pattern == "*") lsDir(Directory(".")) else if (pattern endsWith wildSuffix) lsDir(Directory(pattern dropRight 2)) else if (pattern contains '*') { try { val regexp = ("^" + pattern.replaceAllLiterally("""\*""", """.*""") + "$").r - lsDir(Directory(pattern).parent, regexp findFirstIn _ isDefined) + lsDir(Directory(pattern).parent, regexp.findFirstIn(_).isDefined) } catch { case _: PatternSyntaxException => List(pattern) } } @@ -51,7 +84,7 @@ object ClassPath { } /** Split classpath using platform-dependent path separator */ - def split(path: String): List[String] = (path split pathSeparator).toList filterNot (_ == "") distinct + def split(path: String): List[String] = (path split pathSeparator).toList.filterNot(_ == "").distinct /** Join classpath using platform-dependent path separator */ def join(paths: String*): String = paths filterNot (_ == "") mkString pathSeparator @@ -68,9 +101,10 @@ object ClassPath { def expandDir(extdir: String): List[String] = { AbstractFile getDirectory extdir match { case null => Nil - case dir => dir filter (_.isClassContainer) map (x => new java.io.File(dir.file, x.name) getPath) toList + case dir => dir.filter(_.isClassContainer).map(x => new java.io.File(dir.file, x.name).getPath).toList } } + /** Expand manifest jar classpath entries: these are either urls, or paths * relative to the location of the jar. */ @@ -88,301 +122,30 @@ object ClassPath { try Some(new URL(spec)) catch { case _: MalformedURLException => None } - /** A class modeling aspects of a ClassPath which should be - * propagated to any classpaths it creates. - */ - abstract class ClassPathContext[T] extends classpath.ClassPathFactory[ClassPath[T]] { - /** A filter which can be used to exclude entities from the classpath - * based on their name. - */ - def isValidName(name: String): Boolean = true - - /** Filters for assessing validity of various entities. - */ - def validClassFile(name: String) = endsClass(name) && isValidName(name) - def validPackage(name: String) = (name != "META-INF") && (name != "") && (name.charAt(0) != '.') - def validSourceFile(name: String) = endsScalaOrJava(name) - - /** From the representation to its identifier. - */ - def toBinaryName(rep: T): String - - def sourcesInPath(path: String): List[ClassPath[T]] = - for (file <- expandPath(path, expandStar = false) ; dir <- Option(AbstractFile getDirectory file)) yield - new SourcePath[T](dir, this) - } - def manifests: List[java.net.URL] = { import scala.collection.JavaConverters._ val resources = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF") resources.asScala.filter(_.getProtocol == "jar").toList } - class JavaContext extends ClassPathContext[AbstractFile] { - def toBinaryName(rep: AbstractFile) = { - val name = rep.name - assert(endsClass(name), name) - FileUtils.stripClassExtension(name) - } + @deprecated("Shim for sbt's compiler interface", since = "2.12") + sealed abstract class ClassPathContext - def newClassPath(dir: AbstractFile) = new DirectoryClassPath(dir, this) - } - - object DefaultJavaContext extends JavaContext - - /** From the source file to its identifier. - */ - def toSourceName(f: AbstractFile): String = FileUtils.stripSourceExtension(f.name) + @deprecated("Shim for sbt's compiler interface", since = "2.12") + sealed abstract class JavaContext } -import ClassPath._ - -/** - * Represents a package which contains classes and other packages - */ -abstract class ClassPath[T] extends ClassFileLookup[T] { - /** - * The short name of the package (without prefix) - */ +trait ClassRepresentation { def name: String - - /** - * A String representing the origin of this classpath element, if known. - * For example, the path of the directory or jar. - */ - def origin: Option[String] = None - - /** Info which should be propagated to any sub-classpaths. - */ - def context: ClassPathContext[T] - - /** Lists of entities. - */ - def classes: IndexedSeq[ClassRepresentation[T]] - def packages: IndexedSeq[ClassPath[T]] - def sourcepaths: IndexedSeq[AbstractFile] - - /** The entries this classpath is composed of. In class `ClassPath` it's just the singleton list containing `this`. - * Subclasses such as `MergedClassPath` typically return lists with more elements. - */ - def entries: IndexedSeq[ClassPath[T]] = IndexedSeq(this) - - /** Merge classpath of `platform` and `urls` into merged classpath */ - def mergeUrlsIntoClassPath(urls: URL*): MergedClassPath[T] = { - // Collect our new jars/directories and add them to the existing set of classpaths - val allEntries = - (entries ++ - urls.map(url => context.newClassPath(io.AbstractFile.getURL(url))) - ).distinct - - // Combine all of our classpaths (old and new) into one merged classpath - new MergedClassPath(allEntries, context) - } - - /** - * Represents classes which can be loaded with a ClassfileLoader and/or SourcefileLoader. - */ - case class ClassRep(binary: Option[T], source: Option[AbstractFile]) extends ClassRepresentation[T] { - def name: String = binary match { - case Some(x) => context.toBinaryName(x) - case _ => - assert(source.isDefined) - toSourceName(source.get) - } - } - - /** Filters for assessing validity of various entities. - */ - def validClassFile(name: String) = context.validClassFile(name) - def validPackage(name: String) = context.validPackage(name) - def validSourceFile(name: String) = context.validSourceFile(name) - - /** - * Find a ClassRep given a class name of the form "package.subpackage.ClassName". - * Does not support nested classes on .NET - */ - override def findClass(name: String): Option[ClassRepresentation[T]] = - splitWhere(name, _ == '.', doDropIndex = true) match { - case Some((pkg, rest)) => - val rep = packages find (_.name == pkg) flatMap (_ findClass rest) - rep map { - case x: ClassRepresentation[T] => x - case x => throw new FatalError("Unexpected ClassRep '%s' found searching for name '%s'".format(x, name)) - } - case _ => - classes find (_.name == name) - } - - override def findClassFile(name: String): Option[AbstractFile] = - findClass(name) match { - case Some(ClassRepresentation(Some(x: AbstractFile), _)) => Some(x) - case _ => None - } - - override def asSourcePathString: String = sourcepaths.mkString(pathSeparator) - - def sortString = join(split(asClassPathString).sorted: _*) - override def equals(that: Any) = that match { - case x: ClassPath[_] => this.sortString == x.sortString - case _ => false - } - override def hashCode = sortString.hashCode() -} - -/** - * A Classpath containing source files - */ -class SourcePath[T](dir: AbstractFile, val context: ClassPathContext[T]) extends ClassPath[T] { - import FileUtils.AbstractFileOps - - def name = dir.name - override def origin = dir.underlyingSource map (_.path) - def asURLs = dir.toURLs() - def asClassPathString = dir.path - val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq(dir) - - private def traverse() = { - val classBuf = immutable.Vector.newBuilder[ClassRep] - val packageBuf = immutable.Vector.newBuilder[SourcePath[T]] - dir foreach { f => - if (!f.isDirectory && validSourceFile(f.name)) - classBuf += ClassRep(None, Some(f)) - else if (f.isDirectory && validPackage(f.name)) - packageBuf += new SourcePath[T](f, context) - } - (packageBuf.result(), classBuf.result()) - } - - lazy val (packages, classes) = traverse() - override def toString() = "sourcepath: "+ dir.toString() + def binary: Option[AbstractFile] + def source: Option[AbstractFile] } -/** - * A directory (or a .jar file) containing classfiles and packages - */ -class DirectoryClassPath(val dir: AbstractFile, val context: ClassPathContext[AbstractFile]) extends ClassPath[AbstractFile] { - import FileUtils.AbstractFileOps - - def name = dir.name - override def origin = dir.underlyingSource map (_.path) - def asURLs = dir.toURLs(default = Seq(new URL(name))) - def asClassPathString = dir.path - val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq() - - // calculates (packages, classes) in one traversal. - private def traverse() = { - val classBuf = immutable.Vector.newBuilder[ClassRep] - val packageBuf = immutable.Vector.newBuilder[DirectoryClassPath] - dir foreach { - f => - // Optimization: We assume the file was not changed since `dir` called - // `Path.apply` and categorized existent files as `Directory` - // or `File` (avoids IO operation JFile.isDirectory()). - val isDirectory = f match { - case pf: io.PlainFile => pf.givenPath match { - case _: io.Directory => true - case _: io.File => false - case _ => f.isDirectory - } - case _ => - f.isDirectory - } - if (!isDirectory && validClassFile(f.name)) - classBuf += ClassRep(Some(f), None) - else if (isDirectory && validPackage(f.name)) - packageBuf += new DirectoryClassPath(f, context) - } - (packageBuf.result(), classBuf.result()) - } +@deprecated("Shim for sbt's compiler interface", since = "2.12") +sealed abstract class DirectoryClassPath - lazy val (packages, classes) = traverse() - override def toString() = "directory classpath: "+ origin.getOrElse("?") -} +@deprecated("Shim for sbt's compiler interface", since = "2.12") +sealed abstract class MergedClassPath -/** - * A classpath unifying multiple class- and sourcepath entries. - */ -class MergedClassPath[T]( - override val entries: IndexedSeq[ClassPath[T]], - val context: ClassPathContext[T]) -extends ClassPath[T] { - - def this(entries: TraversableOnce[ClassPath[T]], context: ClassPathContext[T]) = - this(entries.toIndexedSeq, context) - - def name = entries.head.name - def asURLs = (entries flatMap (_.asURLs)).toList - lazy val sourcepaths: IndexedSeq[AbstractFile] = entries flatMap (_.sourcepaths) - - override def origin = Some(entries map (x => x.origin getOrElse x.name) mkString ("Merged(", ", ", ")")) - override def asClassPathString: String = join(entries map (_.asClassPathString) : _*) - - lazy val classes: IndexedSeq[ClassRepresentation[T]] = { - var count = 0 - val indices = mutable.HashMap[String, Int]() - val cls = new mutable.ArrayBuffer[ClassRepresentation[T]](1024) - - for (e <- entries; c <- e.classes) { - val name = c.name - if (indices contains name) { - val idx = indices(name) - val existing = cls(idx) - - if (existing.binary.isEmpty && c.binary.isDefined) - cls(idx) = ClassRep(binary = c.binary, source = existing.source) - if (existing.source.isEmpty && c.source.isDefined) - cls(idx) = ClassRep(binary = existing.binary, source = c.source) - } - else { - indices(name) = count - cls += c - count += 1 - } - } - cls.toIndexedSeq - } - - lazy val packages: IndexedSeq[ClassPath[T]] = { - var count = 0 - val indices = mutable.HashMap[String, Int]() - val pkg = new mutable.ArrayBuffer[ClassPath[T]](256) - - for (e <- entries; p <- e.packages) { - val name = p.name - if (indices contains name) { - val idx = indices(name) - pkg(idx) = addPackage(pkg(idx), p) - } - else { - indices(name) = count - pkg += p - count += 1 - } - } - pkg.toIndexedSeq - } - - private def addPackage(to: ClassPath[T], pkg: ClassPath[T]) = { - val newEntries: IndexedSeq[ClassPath[T]] = to match { - case cp: MergedClassPath[_] => cp.entries :+ pkg - case _ => IndexedSeq(to, pkg) - } - new MergedClassPath[T](newEntries, context) - } - - def show() { - println("ClassPath %s has %d entries and results in:\n".format(name, entries.size)) - asClassPathString split ':' foreach (x => println(" " + x)) - } - - override def toString() = "merged classpath "+ entries.mkString("(", "\n", ")") -} - -/** - * The classpath when compiling with target:jvm. Binary files (classfiles) are represented - * as AbstractFile. nsc.io.ZipArchive is used to view zip/jar archives as directories. - */ -class JavaClassPath( - containers: IndexedSeq[ClassPath[AbstractFile]], - context: JavaContext) -extends MergedClassPath[AbstractFile](containers, context) { } +@deprecated("Shim for sbt's compiler interface", since = "2.12") +sealed abstract class JavaClassPath |