diff options
author | Paul Phillips <paulp@improving.org> | 2010-02-21 21:56:56 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2010-02-21 21:56:56 +0000 |
commit | f07bdbab911a7bcef042373d45fab302753f5a1f (patch) | |
tree | 90487f84f753554b5eb2f47063be42578f6a5d42 | |
parent | 18aa7f0c8075ed543c108d99eeb10a974c3d0296 (diff) | |
download | scala-f07bdbab911a7bcef042373d45fab302753f5a1f.tar.gz scala-f07bdbab911a7bcef042373d45fab302753f5a1f.tar.bz2 scala-f07bdbab911a7bcef042373d45fab302753f5a1f.zip |
Some more code for seeing what's going on in in...
Some more code for seeing what's going on in in scalac's mind with
respect to who to load when and from where. No review.
7 files changed, 108 insertions, 21 deletions
diff --git a/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala b/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala index 50b9f12dcc..aa60231b86 100644 --- a/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala +++ b/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala @@ -14,12 +14,15 @@ package sabbus import java.io.File import java.io.FileWriter import org.apache.tools.ant.Project -import org.apache.tools.ant.taskdefs.{MatchingTask, Java} -import org.apache.tools.ant.util.{GlobPatternMapper, SourceFileScanner} +import org.apache.tools.ant.taskdefs.{ MatchingTask, Java } +import org.apache.tools.ant.util.{ GlobPatternMapper, SourceFileScanner } import scala.tools.nsc.io +import scala.tools.nsc.util.ScalaClassLoader class ScalacFork extends MatchingTask with TaskArgs { val MainClass = "scala.tools.nsc.Main" + private def originOfThis: String = + ScalaClassLoader.originOfClass(classOf[ScalacFork]) map (_.toString) getOrElse "<unknown>" def setSrcdir(input: File) { sourceDir = Some(input) @@ -59,6 +62,8 @@ class ScalacFork extends MatchingTask with TaskArgs { override def execute() { def plural(x: Int) = if (x > 1) "s" else "" + log("Executing ant task scalacfork, origin: %s".format(originOfThis), Project.MSG_VERBOSE) + val compilerPath = this.compilerPath getOrElse error("Mandatory attribute 'compilerpath' is not set.") val sourceDir = this.sourceDir getOrElse error("Mandatory attribute 'srcdir' is not set.") val destinationDir = this.destinationDir getOrElse error("Mandatory attribute 'destdir' is not set.") diff --git a/src/compiler/scala/tools/nsc/io/AbstractFile.scala b/src/compiler/scala/tools/nsc/io/AbstractFile.scala index 216579e376..1f9e6c55f0 100644 --- a/src/compiler/scala/tools/nsc/io/AbstractFile.scala +++ b/src/compiler/scala/tools/nsc/io/AbstractFile.scala @@ -102,7 +102,10 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] { /** Returns the underlying File if any and null otherwise. */ def file: JFile - def sfile = File(file) // XXX + def sfile = Option(file) map (x => File(x)) // XXX + + /** An underlying source, if known. Mostly, a zip/jar file. */ + def underlyingSource: Option[AbstractFile] = None /** Does this abstract file denote an existing file? */ def exists: Boolean = @@ -110,7 +113,7 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] { else true /** Does this abstract file represent something which can contain classfiles? */ - def isClassContainer = isDirectory || (file != null && Path.isJarOrZip(sfile)) + def isClassContainer = isDirectory || (sfile exists (Path isJarOrZip _)) /** Create a file on disk, if one does not exist already. */ def create: Unit @@ -229,7 +232,7 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] { */ def fileNamed(name: String): AbstractFile = { assert(isDirectory) - Option(lookupName(name, false)) getOrElse new PlainFile((sfile / name).createFile()) + Option(lookupName(name, false)) getOrElse new PlainFile((sfile.get / name).createFile()) } /** @@ -238,7 +241,7 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] { */ def subdirectoryNamed(name: String): AbstractFile = { assert (isDirectory) - Option(lookupName(name, true)) getOrElse new PlainFile((sfile / name).createDirectory()) + Option(lookupName(name, true)) getOrElse new PlainFile((sfile.get / name).createDirectory()) } /** Returns the path of this abstract file. */ diff --git a/src/compiler/scala/tools/nsc/io/PlainFile.scala b/src/compiler/scala/tools/nsc/io/PlainFile.scala index 5336c4d04d..df24880f32 100644 --- a/src/compiler/scala/tools/nsc/io/PlainFile.scala +++ b/src/compiler/scala/tools/nsc/io/PlainFile.scala @@ -27,6 +27,8 @@ class PlainFile(val givenPath: Path) extends AbstractFile { assert(path ne null) val file = givenPath.jfile + override def underlyingSource = Some(this) + private val fpath = try givenPath.normalize catch { case _: IOException => givenPath.toAbsolute } /** Returns the name of this abstract file. */ diff --git a/src/compiler/scala/tools/nsc/io/SourceReader.scala b/src/compiler/scala/tools/nsc/io/SourceReader.scala index bb5e662ab7..ccd946d0b6 100644 --- a/src/compiler/scala/tools/nsc/io/SourceReader.scala +++ b/src/compiler/scala/tools/nsc/io/SourceReader.scala @@ -65,7 +65,7 @@ class SourceReader(decoder: CharsetDecoder, reporter: Reporter) { case p:PlainFile => read(p.file) // bq: (!!!) case z:ZipArchive#FileEntry => - val c = Channels.newChannel(z.getArchive.getInputStream(z.entry)) + val c = Channels.newChannel(z.archive.getInputStream(z.entry)) read(c) case _ => val b = ByteBuffer.wrap(file.toByteArray) diff --git a/src/compiler/scala/tools/nsc/io/VirtualFile.scala b/src/compiler/scala/tools/nsc/io/VirtualFile.scala index edbcde1ff3..256d02c5a5 100644 --- a/src/compiler/scala/tools/nsc/io/VirtualFile.scala +++ b/src/compiler/scala/tools/nsc/io/VirtualFile.scala @@ -62,7 +62,7 @@ class VirtualFile(val name: String, _path: String) extends AbstractFile } } - def container : AbstractFile = throw new Error("not supported") + def container: AbstractFile = throw new Error("not supported") /** Is this abstract file a directory? */ def isDirectory: Boolean = false diff --git a/src/compiler/scala/tools/nsc/io/ZipArchive.scala b/src/compiler/scala/tools/nsc/io/ZipArchive.scala index 62f1491fdf..aa92b896db 100644 --- a/src/compiler/scala/tools/nsc/io/ZipArchive.scala +++ b/src/compiler/scala/tools/nsc/io/ZipArchive.scala @@ -207,9 +207,9 @@ final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file) path: String ) extends VirtualFile(name, path) { - final override def path = "%s(%s)".format(self, pathInArchive) - final def getArchive = self.archive - def pathInArchive = super.path + override def underlyingSource = Some(self) + final override def path = "%s(%s)".format(self, super.path) + final def archive = self.archive override def hashCode = super.hashCode + container.hashCode override def equals(that : Any) = @@ -234,7 +234,6 @@ final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file) val entry: ZipEntry ) extends Entry(container, name, path) with FileEntryInterface { - def archive = self.archive override def input = archive getInputStream entry } @@ -282,6 +281,7 @@ final class URLZipArchive(url: URL) extends AbstractFile with ZipContainer abstract class Entry(name: String, path: String) extends VirtualFile(name, path) { final override def path = "%s(%s)".format(URLZipArchive.this, super.path) + override def container = URLZipArchive.this } final class DirEntry(name: String, path: String) extends Entry(name, path) with DirEntryInterface { def source = input diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 0e9c4f27fa..59fc790bf1 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -47,6 +47,26 @@ object ClassPath { else List(pattern) } + /** Return duplicated classpath entries as + * (name, list of origins) + * in the order they occur on the path. + */ + def findDuplicates(cp: ClassPath[_]) = { + def toFullName(x: (String, _, cp.AnyClassRep)) = x._1 + "." + x._3.name + def toOriginString(x: ClassPath[_]) = x.origin getOrElse x.name + + /** Flatten everything into tuples, recombine grouped by name, filter down to 2+ entries. */ + val flattened = ( + for ((pkgName, pkg) <- cp.allPackagesWithNames ; clazz <- pkg.classes) yield + (pkgName, pkg, clazz) + ) + val multipleAppearingEntries = flattened groupBy toFullName filter (_._2.size > 1) + + /** Extract results. */ + for (name <- flattened map toFullName distinct ; dups <- multipleAppearingEntries get name) yield + (name, dups map { case (_, cp, _) => toOriginString(cp) }) + } + /** Split classpath using platform-dependent path separator */ def split(path: String): List[String] = (path split pathSeparator).toList filterNot (_ == "") distinct @@ -67,7 +87,7 @@ object ClassPath { /** Expand dir out to contents, a la extdir */ def expandDir(extdir: String): List[String] = { val dir = Option(AbstractFile getDirectory extdir) getOrElse (return Nil) - dir filter (_.isClassContainer) map (dir.sfile / _.name path) toList + dir filter (_.isClassContainer) map (dir.sfile.get / _.name path) toList } /** A useful name filter. */ @@ -158,7 +178,13 @@ abstract class ClassPath[T] { */ def name: String - /** An URL representing this classpath. + /** + * 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 + + /** A list of URLs representing this classpath. */ def asURLs: List[URL] @@ -168,9 +194,29 @@ abstract class ClassPath[T] { /** Lists of entities. */ - val classes: List[AnyClassRep] - val packages: List[ClassPath[T]] - val sourcepaths: List[AbstractFile] + def classes: List[AnyClassRep] + def packages: List[ClassPath[T]] + def sourcepaths: List[AbstractFile] + + /** Information which entails walking the tree. This is probably only + * necessary for tracking down problems - it's normally not used. + */ + def allPackages: List[ClassPath[T]] = packages ::: (packages flatMap (_.allPackages)) + def allPackageNames: List[String] = { + def subpackages(prefix: String, cp: ClassPath[T]): List[String] = ( + (cp.packages map (prefix + _.name)) ::: + (cp.packages flatMap (x => subpackages(prefix + x.name + ".", x))) + ) + subpackages("", this) + } + def allPackagesWithNames: List[(String, ClassPath[T])] = { + val root = packages map (p => p.name -> p) + val subs = + for ((prefix, p) <- root ; (k, v) <- p.allPackagesWithNames) yield + (prefix + "." + k, v) + + root ::: subs + } /** * Represents classes which can be loaded with a ClassfileLoader/MSILTypeLoader @@ -227,7 +273,8 @@ abstract class ClassPath[T] { */ class SourcePath[T](dir: AbstractFile, val context: ClassPathContext[T]) extends ClassPath[T] { def name = dir.name - def asURLs = List(dir.sfile.toURL) + override def origin = dir.underlyingSource map (_.path) + def asURLs = dir.sfile.toList map (_.toURL) val sourcepaths: List[AbstractFile] = List(dir) lazy val classes: List[ClassRep] = dir partialMap { @@ -247,7 +294,8 @@ class SourcePath[T](dir: AbstractFile, val context: ClassPathContext[T]) extends */ class DirectoryClassPath(val dir: AbstractFile, val context: ClassPathContext[AbstractFile]) extends ClassPath[AbstractFile] { def name = dir.name - def asURLs = List(dir.sfile.toURL) + override def origin = dir.underlyingSource map (_.path) + def asURLs = dir.sfile.toList map (_.toURL) val sourcepaths: List[AbstractFile] = Nil lazy val classes: List[ClassRep] = dir partialMap { @@ -266,11 +314,11 @@ class DirectoryClassPath(val dir: AbstractFile, val context: ClassPathContext[Ab * A classpath unifying multiple class- and sourcepath entries. */ class MergedClassPath[T]( - protected val entries: List[ClassPath[T]], + val entries: List[ClassPath[T]], val context: ClassPathContext[T]) extends ClassPath[T] { - def name = entries.head.name + override def origin = Some(entries map (x => x.origin getOrElse x.name) mkString ("Merged(", ", ", ")")) def asURLs = entries flatMap (_.asURLs) lazy val sourcepaths: List[AbstractFile] = entries flatMap (_.sourcepaths) @@ -314,6 +362,31 @@ extends ClassPath[T] { new MergedClassPath[T](newEntries, context) } + override def allPackages: List[ClassPath[T]] = entries flatMap (_.allPackages) + override def allPackageNames = entries flatMap (_.allPackageNames) + override def allPackagesWithNames = entries flatMap (_.allPackagesWithNames) + + def duplicatedClasses = { + def toFullName(x: (String, _, AnyClassRep)) = x._1 + "." + x._3.name + + /** Flatten everything into tuples, recombine grouped by name, filter down to 2+ entries. */ + val flattened = ( + for ((pkgName, pkg) <- allPackagesWithNames ; clazz <- pkg.classes) yield + (pkgName, pkg, clazz) + ) + val multipleAppearingEntries = flattened groupBy toFullName filter (_._2.size > 1) + + /** Using original name list as reference point, return duplicated entries as + * (name, list of origins) + * in the order they occur on the path. + */ + for (name <- flattened map toFullName distinct ; dups <- multipleAppearingEntries get name) yield + (name, dups map { + case (_, cp, _) if cp.origin.isDefined => cp.origin.get + case (_, cp, _) => cp.asURLs.mkString + }) + } + def asClasspathString: String = ClassPath.join(entries partialMap { case x: DirectoryClassPath => x.dir.path case x: MergedClassPath[_] => x.asClasspathString @@ -322,6 +395,10 @@ extends ClassPath[T] { println("ClassPath %s has %d entries and results in:\n".format(name, entries.size)) asClasspathString split ':' foreach (x => println(" " + x)) } + def showDuplicates = + ClassPath findDuplicates this foreach { + case (name, xs) => println(xs.mkString(name + ":\n ", "\n ", "\n")) + } override def toString() = "merged classpath "+ entries.mkString("(", "\n", ")") } |