-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Simplify classpath code #26712
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
SolalPirelli
wants to merge
4
commits into
scala:main
Choose a base branch
from
dotty-staging:solal/classpath-simplify
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Simplify classpath code #26712
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,10 +5,9 @@ package dotty.tools | |
| package dotc.classpath | ||
|
|
||
| import java.net.URL | ||
| import scala.collection.mutable.ArrayBuffer | ||
| import dotc.util | ||
|
|
||
| import dotty.tools.io.{ AbstractFile, ClassPath, ClassRepresentation } | ||
| import dotty.tools.io.AbstractFile | ||
|
|
||
| /** | ||
| * A classpath unifying multiple class- and sourcepath entries. | ||
|
|
@@ -32,7 +31,7 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath { | |
|
|
||
| override def asURLs: Seq[URL] = aggregates.flatMap(_.asURLs) | ||
|
|
||
| override def packages(inPackage: String): Iterable[PackageEntry] = | ||
| override def packages(inPackage: String): Iterable[String] = | ||
| aggregates.flatMap(_.packages(inPackage)).distinct | ||
|
|
||
| override def classes(inPackage: String): Iterable[BinaryFileEntry] = | ||
|
|
@@ -43,61 +42,7 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath { | |
|
|
||
| override def hasPackage(pkg: String): Boolean = aggregates.exists(_.hasPackage(pkg)) | ||
|
|
||
| /** Returns only one entry for each name. | ||
| * | ||
| * If there's both a source and a class entry, it | ||
| * creates an entry containing both of them. If there would be more than one class or source | ||
| * entries for the same class it always would use the first entry of each type found on a classpath. | ||
| * | ||
| * A TASTy file with no class file entry will be chosen over a class file entry. This can happen if we load | ||
| * the Scala 2 library as it has one JAR containing the class files and one JAR containing the TASTy files. | ||
| * As classpath orders are not guaranteed to be deterministic we might end up having the TASTy in a later classpath entry. | ||
| */ | ||
| private def mergeClassesAndSources(entries: scala.collection.Seq[ClassRepresentation]): Seq[ClassRepresentation] = { | ||
| // based on the implementation from MergedClassPath | ||
| var count = 0 | ||
| val indices = util.HashMap[String, Int]() | ||
| val mergedEntries = new ArrayBuffer[ClassRepresentation](entries.size) | ||
| for { | ||
| entry <- entries | ||
| } { | ||
| val name = entry.name | ||
| if (indices.contains(name)) { | ||
| val index = indices(name) | ||
| val existing = mergedEntries(index) | ||
| (entry, existing) match | ||
| case (entry: SourceFileEntry, existing: BinaryFileEntry) => | ||
| mergedEntries(index) = BinaryAndSourceFilesEntry(existing, entry) | ||
| case (entry: BinaryFileEntry, existing: SourceFileEntry) => | ||
| mergedEntries(index) = BinaryAndSourceFilesEntry(entry, existing) | ||
| case (entry: StandaloneTastyFileEntry, _: ClassFileEntry) => | ||
| // Here we do not create a TastyWithClassFileEntry because the TASTy and the classfile | ||
| // come from different classpaths. These may not have the same TASTy UUID. | ||
| mergedEntries(index) = entry | ||
| case (entry: StandaloneTastyFileEntry, BinaryAndSourceFilesEntry(_: ClassFileEntry, sourceEntry)) => | ||
| mergedEntries(index) = BinaryAndSourceFilesEntry(entry, sourceEntry) | ||
| case _ => | ||
| } | ||
| else { | ||
| indices(name) = count | ||
| mergedEntries += entry | ||
| count += 1 | ||
| } | ||
| } | ||
| if (mergedEntries.isEmpty) Nil else mergedEntries.toIndexedSeq | ||
| } | ||
|
|
||
| private def getDistinctEntries[EntryType <: ClassRepresentation](getEntries: ClassPath => Iterable[EntryType]): Iterable[EntryType] = { | ||
| private def getDistinctEntries[EntryType <: ClassRepresentation](getEntries: ClassPath => Iterable[EntryType]): Iterable[EntryType] = | ||
| val seenNames = util.HashSet[String]() | ||
| val entriesBuffer = new ArrayBuffer[EntryType](1024) | ||
| for { | ||
| cp <- aggregates | ||
| entry <- getEntries(cp) if !seenNames.contains(entry.name) | ||
| } | ||
| { | ||
| entriesBuffer += entry | ||
| seenNames += entry.name | ||
| } | ||
| entriesBuffer.toIndexedSeq | ||
| } | ||
| aggregates.flatMap(getEntries).filter(e => seenNames.add(e.name)) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this was overly convoluted |
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,40 +3,81 @@ | |
| */ | ||
| package dotty.tools.dotc.classpath | ||
|
|
||
| import dotty.tools.io.{AbstractFile, ClassRepresentation, FileExtension} | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. changes in this file:
|
||
| import dotty.tools.dotc | ||
| import dotty.tools.io.File.pathSeparator | ||
| import dotty.tools.io.{AbstractFile, Directory, File, FileExtension} | ||
|
|
||
| case class PackageEntry(name: String) | ||
| import java.net.URL | ||
| import java.util.regex.PatternSyntaxException | ||
|
|
||
| /** A TASTy file or classfile */ | ||
| sealed trait BinaryFileEntry extends ClassRepresentation { | ||
| def file: AbstractFile | ||
| final def fileName: String = file.name | ||
| final def name: String = FileUtils.stripExtension(file.name) // class name | ||
| final def source: Option[AbstractFile] = None | ||
| } | ||
| /** | ||
| * A representation of the compiler's class- or sourcepath. | ||
| */ | ||
| trait ClassPath { | ||
| def asURLs: Seq[URL] = Seq.empty | ||
| def hasPackage(pkg: String): Boolean = false | ||
| def packages(inPackage: String): Iterable[String] = Seq.empty | ||
| def classes(inPackage: String): Iterable[BinaryFileEntry] = Seq.empty | ||
| def sources(inPackage: String): Iterable[SourceFileEntry] = Seq.empty | ||
|
|
||
| object BinaryFileEntry { | ||
| def apply(file: AbstractFile): BinaryFileEntry = | ||
| if file.exists && file.ext.isTasty then | ||
| if file.resolveSiblingWithExtension(FileExtension.Class) != null then TastyWithClassFileEntry(file) | ||
| else StandaloneTastyFileEntry(file) | ||
| else | ||
| ClassFileEntry(file) | ||
| /** | ||
| * Returns *only* the classfile for an external name, e.g., "java.lang.String". This method does not | ||
| * return source files or tasty files. | ||
| * | ||
| * This method is used by the classfile parser. When parsing a Java class, its own inner classes | ||
| * are entered with a `ClassfileLoader` that parses the classfile returned by this method. | ||
| * It is also used in the backend, by the inliner, to obtain the bytecode when inlining from the | ||
| * classpath. It's also used by scalap. | ||
| */ | ||
| def findClassFile(className: String): Option[AbstractFile] = None | ||
| } | ||
|
|
||
| /** A classfile or .sig that does not have an associated TASTy file */ | ||
| private[dotty] final case class ClassFileEntry(file: AbstractFile) extends BinaryFileEntry { | ||
| def binary: Option[AbstractFile] = Some(file) | ||
| object ClassPath { | ||
| val RootPackage: String = "" | ||
|
|
||
| /** Expand single path entry */ | ||
| private def expandS(pattern: String): List[String] = { | ||
| val wildSuffix = File.separator + "*" | ||
|
|
||
| /* 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 || x.ext.isJarOrZip)).map(_.path).toList | ||
|
|
||
| if (pattern == "*") lsDir(Directory(".")) | ||
| // On Windows the JDK supports forward slash or backslash in classpath entries | ||
| else if (pattern.endsWith(wildSuffix) || pattern.endsWith("/*")) lsDir(Directory(pattern dropRight 2)) | ||
| else if (pattern.contains('*')) { | ||
| try { | ||
| val regexp = ("^" + pattern.replace("""\*""", """.*""") + "$").r | ||
| lsDir(Directory(pattern).parent, regexp.findFirstIn(_).isDefined) | ||
| } | ||
| catch { case _: PatternSyntaxException => List(pattern) } | ||
| } | ||
| else List(pattern) | ||
| } | ||
|
|
||
| /** Split classpath using platform-dependent path separator */ | ||
| def split(path: String): List[String] = path.split(pathSeparator).toList.filterNot(_ == "").distinct | ||
|
|
||
| /** Expand path and possibly expanding stars */ | ||
| def expandPath(path: String, expandStar: Boolean = true): List[String] = | ||
| if (expandStar) split(path).flatMap(expandS) | ||
| else split(path) | ||
| } | ||
|
|
||
| /** A TASTy file that has an associated class file */ | ||
| private[dotty] final case class TastyWithClassFileEntry(file: AbstractFile) extends BinaryFileEntry { | ||
| def binary: Option[AbstractFile] = Some(file) | ||
| trait ClassRepresentation { | ||
| def fileName: String | ||
| def name: String | ||
| def binary: Option[AbstractFile] | ||
| def source: Option[AbstractFile] | ||
| } | ||
|
|
||
| /** A TASTy file that does not have an associated class file */ | ||
| private[dotty] final case class StandaloneTastyFileEntry(file: AbstractFile) extends BinaryFileEntry { | ||
| /** A TASTy file or classfile */ | ||
| private[dotty] final case class BinaryFileEntry(file: AbstractFile) extends ClassRepresentation { | ||
| def fileName: String = file.name | ||
| def name: String = FileUtils.stripExtension(file.name) // class name | ||
| def binary: Option[AbstractFile] = Some(file) | ||
| def source: Option[AbstractFile] = None | ||
| } | ||
|
|
||
| private[dotty] final case class SourceFileEntry(file: AbstractFile) extends ClassRepresentation { | ||
|
|
@@ -45,10 +86,3 @@ private[dotty] final case class SourceFileEntry(file: AbstractFile) extends Clas | |
| def binary: Option[AbstractFile] = None | ||
| def source: Option[AbstractFile] = Some(file) | ||
| } | ||
|
|
||
| private[dotty] final case class BinaryAndSourceFilesEntry(binaryEntry: BinaryFileEntry, sourceEntry: SourceFileEntry) extends ClassRepresentation { | ||
| def fileName: String = binaryEntry.fileName | ||
| def name: String = binaryEntry.name | ||
| def binary: Option[AbstractFile] = binaryEntry.binary | ||
| def source: Option[AbstractFile] = sourceEntry.source | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dead