diff --git a/compile/api/src/main/scala/sbt/ClassToAPI.scala b/compile/api/src/main/scala/sbt/ClassToAPI.scala index 37e8a5919..8511d3599 100644 --- a/compile/api/src/main/scala/sbt/ClassToAPI.scala +++ b/compile/api/src/main/scala/sbt/ClassToAPI.scala @@ -160,7 +160,7 @@ object ClassToAPI { } catch { case e: Throwable => throw new IllegalStateException( - s"Failed to parse class $c: this may mean your classfiles are corrupted. Please clean and try again.", + s"Failed to parse $c: this may mean your classfiles are corrupted. Please clean and try again.", e ) } diff --git a/util/io/src/main/scala/sbt/IO.scala b/util/io/src/main/scala/sbt/IO.scala index 348fd0ab3..0fd5f52ad 100644 --- a/util/io/src/main/scala/sbt/IO.scala +++ b/util/io/src/main/scala/sbt/IO.scala @@ -38,14 +38,23 @@ object IO { /** * Returns a URL for the directory or jar containing the the class file `cl`. * If the location cannot be determined, an error is generated. - * Note that Java standard library classes typically do not have a location associated with them. */ - def classLocation(cl: Class[_]): URL = - { - val codeSource = cl.getProtectionDomain.getCodeSource - if (codeSource == null) sys.error("No class location for " + cl) - else codeSource.getLocation + def classLocation(cl: Class[_]): URL = { + val codeSource = cl.getProtectionDomain.getCodeSource + if (codeSource ne null) { + codeSource.getLocation + } else { + // NB: This assumes that classes without code sources are System classes, and thus located in + // jars. It assumes that `urlAsFile` will truncate to the containing jar file. + val clsfile = s"${cl.getName.replace('.', '/')}.class" + Option(ClassLoader.getSystemClassLoader.getResource(clsfile)) + .flatMap { + urlAsFile + }.getOrElse { + sys.error("No class location for " + cl) + }.toURI.toURL } + } /** * Returns the directory or jar file containing the the class file `cl`. diff --git a/util/io/src/test/scala/CopySpec.scala b/util/io/src/test/scala/sbt/CopySpec.scala similarity index 100% rename from util/io/src/test/scala/CopySpec.scala rename to util/io/src/test/scala/sbt/CopySpec.scala diff --git a/util/io/src/test/scala/FileUtilitiesSpecification.scala b/util/io/src/test/scala/sbt/FileUtilitiesSpecification.scala similarity index 100% rename from util/io/src/test/scala/FileUtilitiesSpecification.scala rename to util/io/src/test/scala/sbt/FileUtilitiesSpecification.scala diff --git a/util/io/src/test/scala/sbt/IOSpecification.scala b/util/io/src/test/scala/sbt/IOSpecification.scala new file mode 100644 index 000000000..882f147c5 --- /dev/null +++ b/util/io/src/test/scala/sbt/IOSpecification.scala @@ -0,0 +1,25 @@ +package sbt + +import util.Try + +import org.scalacheck._ +import Prop._ + +object IOSpecification extends Properties("IO") { + property("classLocation able to determine containing directories") = + Prop.forAll(classes) { (c: Class[_]) => + Try(IO.classLocationFile(c)).toOption.exists { + case jar if jar.getName.endsWith(".jar") => jar.isFile + case dir => dir.isDirectory + } + } + + implicit def classes: Gen[Class[_]] = + Gen.oneOf( + this.getClass, + classOf[java.lang.Integer], + classOf[String], + classOf[Thread], + classOf[Properties] + ) +} diff --git a/util/io/src/test/scala/NameFilterSpecification.scala b/util/io/src/test/scala/sbt/NameFilterSpecification.scala similarity index 100% rename from util/io/src/test/scala/NameFilterSpecification.scala rename to util/io/src/test/scala/sbt/NameFilterSpecification.scala diff --git a/util/io/src/test/scala/RichURISpecification.scala b/util/io/src/test/scala/sbt/RichURISpecification.scala similarity index 100% rename from util/io/src/test/scala/RichURISpecification.scala rename to util/io/src/test/scala/sbt/RichURISpecification.scala diff --git a/util/io/src/test/scala/StashSpec.scala b/util/io/src/test/scala/sbt/StashSpec.scala similarity index 100% rename from util/io/src/test/scala/StashSpec.scala rename to util/io/src/test/scala/sbt/StashSpec.scala diff --git a/util/io/src/test/scala/WithFiles.scala b/util/io/src/test/scala/sbt/WithFiles.scala similarity index 100% rename from util/io/src/test/scala/WithFiles.scala rename to util/io/src/test/scala/sbt/WithFiles.scala