summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/ant/sabbus/ScalacFork.scala9
-rw-r--r--src/compiler/scala/tools/nsc/io/AbstractFile.scala11
-rw-r--r--src/compiler/scala/tools/nsc/io/PlainFile.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/SourceReader.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/VirtualFile.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/ZipArchive.scala8
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassPath.scala95
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", ")")
}