diff options
3 files changed, 143 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala new file mode 100644 index 0000000000..f1bb6010a4 --- /dev/null +++ b/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2014 Contributor. All rights reserved. + */ +package scala.tools.nsc.classpath + +import scala.reflect.io.AbstractFile +import scala.tools.nsc.util.{ ClassFileLookup, ClassPath, ClassRepresentation } + +/** + * A base trait for the particular flat classpath representation implementations. + * + * We call this variant of a classpath representation flat because it's possible to + * query the whole classpath using just single instance extending this trait. + * + * This is an alternative design compared to scala.tools.nsc.util.ClassPath + */ +trait FlatClassPath extends ClassFileLookup[AbstractFile] { + /** 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): FlatClassPathEntries + + // A default implementation which should be overriden, if we can create more efficient + // solution for given type of FlatClassPath + override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = { + val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className) + + val foundClassFromClassFiles = classes(pkg) + .find(_.name == simpleClassName) + + def findClassInSources = sources(pkg) + .find(_.name == simpleClassName) + + foundClassFromClassFiles orElse findClassInSources + } + + override def asClassPathString: String = ClassPath.join(asClassPathStrings: _*) + def asClassPathStrings: Seq[String] +} + +object FlatClassPath { + val RootPackage = "" +} + +case class FlatClassPathEntries(packages: Seq[PackageEntry], classesAndSources: Seq[ClassRepClassPathEntry]) + +sealed trait ClassRepClassPathEntry extends ClassRepresentation[AbstractFile] + +trait ClassFileEntry extends ClassRepClassPathEntry { + def file: AbstractFile +} + +trait SourceFileEntry extends ClassRepClassPathEntry { + def file: AbstractFile +} + +trait PackageEntry { + def name: String +} + +private[nsc] case class ClassFileEntryImpl(file: AbstractFile) extends ClassFileEntry { + override def name = FileUtils.stripClassExtension(file.name) // class name + + override def binary: Option[AbstractFile] = Some(file) + override def source: Option[AbstractFile] = None +} + +private[nsc] case class SourceFileEntryImpl(file: AbstractFile) extends SourceFileEntry { + override def name = FileUtils.stripSourceExtension(file.name) + + override def binary: Option[AbstractFile] = None + override def source: Option[AbstractFile] = Some(file) +} + +private[nsc] case class ClassAndSourceFilesEntry(classFile: AbstractFile, srcFile: AbstractFile) extends ClassRepClassPathEntry { + override def name = FileUtils.stripClassExtension(classFile.name) + + override def binary: Option[AbstractFile] = Some(classFile) + override def source: Option[AbstractFile] = Some(srcFile) +} + +private[nsc] case class PackageEntryImpl(name: String) extends PackageEntry diff --git a/src/compiler/scala/tools/nsc/classpath/PackageNameUtils.scala b/src/compiler/scala/tools/nsc/classpath/PackageNameUtils.scala new file mode 100644 index 0000000000..c93ce6ed27 --- /dev/null +++ b/src/compiler/scala/tools/nsc/classpath/PackageNameUtils.scala @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2014 Contributor. All rights reserved. + */ +package scala.tools.nsc.classpath + +import scala.tools.nsc.classpath.FlatClassPath.RootPackage + +/** + * Common methods related to package names represented as String + */ +object PackageNameUtils { + + /** + * @param fullClassName full class name with package + * @return (package, simple class name) + */ + def separatePkgAndClassNames(fullClassName: String): (String, String) = { + val lastDotIndex = fullClassName.lastIndexOf('.') + if (lastDotIndex == -1) + (RootPackage, fullClassName) + else + (fullClassName.substring(0, lastDotIndex), fullClassName.substring(lastDotIndex + 1)) + } +} diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index f967a37fc7..3b1ce2fd5c 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -13,6 +13,7 @@ import classfile.ClassfileParser import scala.reflect.internal.MissingRequirementError import scala.reflect.internal.util.Statistics import scala.reflect.io.{ AbstractFile, NoAbstractFile } +import scala.tools.nsc.classpath.FlatClassPath /** This class ... * @@ -276,6 +277,39 @@ abstract class SymbolLoaders { } } + /** + * Loads contents of a package + */ + class PackageLoaderUsingFlatClassPath(packageName: String, classPath: FlatClassPath) extends SymbolLoader with FlagAgnosticCompleter { + protected def description = { + val shownPackageName = if (packageName == FlatClassPath.RootPackage) "<root package>" else packageName + s"package loader $shownPackageName" + } + + protected def doComplete(root: Symbol) { + assert(root.isPackageClass, root) + root.setInfo(new PackageClassInfoType(newScope, root)) + + val classPathEntries = classPath.list(packageName) + + if (!root.isRoot) + for (entry <- classPathEntries.classesAndSources) initializeFromClassPath(root, entry) + if (!root.isEmptyPackageClass) { + for (pkg <- classPathEntries.packages) { + val fullName = pkg.name + + val name = + if (packageName == FlatClassPath.RootPackage) fullName + else fullName.substring(packageName.length + 1) + val packageLoader = new PackageLoaderUsingFlatClassPath(fullName, classPath) + enterPackage(root, name, packageLoader) + } + + openPackageModule(root) + } + } + } + class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader with FlagAssigningCompleter { private object classfileParser extends { val symbolTable: SymbolLoaders.this.symbolTable.type = SymbolLoaders.this.symbolTable |