mirror of https://github.com/sbt/sbt.git
90 lines
3.3 KiB
Scala
90 lines
3.3 KiB
Scala
/* sbt -- Simple Build Tool
|
|
* Copyright 2008, 2009, 2010, 2011 Mark Harrah
|
|
*/
|
|
package xsbt
|
|
|
|
import java.io.File
|
|
import java.util.{ Arrays, Comparator }
|
|
import scala.tools.nsc.{ io, plugins, symtab, Global, Phase }
|
|
import io.{ AbstractFile, PlainFile, ZipArchive }
|
|
import plugins.{ Plugin, PluginComponent }
|
|
import symtab.Flags
|
|
import scala.collection.mutable.{ HashMap, HashSet, ListBuffer }
|
|
import xsbti.api.{ ClassLike, DefinitionType, PathComponent, SimpleType }
|
|
|
|
object API {
|
|
val name = "xsbt-api"
|
|
}
|
|
|
|
final class API(val global: CallbackGlobal) extends Compat {
|
|
import global._
|
|
|
|
@inline def debug(msg: => String) = if (settings.verbose.value) inform(msg)
|
|
|
|
def newPhase(prev: Phase) = new ApiPhase(prev)
|
|
class ApiPhase(prev: Phase) extends Phase(prev) {
|
|
override def description = "Extracts the public API from source files."
|
|
def name = API.name
|
|
def run: Unit =
|
|
{
|
|
val start = System.currentTimeMillis
|
|
currentRun.units.foreach(processUnit)
|
|
val stop = System.currentTimeMillis
|
|
debug("API phase took : " + ((stop - start) / 1000.0) + " s")
|
|
}
|
|
def processUnit(unit: CompilationUnit) = if (!unit.isJava) processScalaUnit(unit)
|
|
def processScalaUnit(unit: CompilationUnit): Unit = {
|
|
val sourceFile = unit.source.file.file
|
|
debug("Traversing " + sourceFile)
|
|
val extractApi = new ExtractAPI[global.type](global, sourceFile)
|
|
val traverser = new TopLevelHandler(extractApi)
|
|
traverser.apply(unit.body)
|
|
if (global.callback.nameHashing) {
|
|
val extractUsedNames = new ExtractUsedNames[global.type](global)
|
|
val names = extractUsedNames.extract(unit)
|
|
debug("The " + sourceFile + " contains the following used names " + names)
|
|
names foreach { (name: String) => callback.usedName(sourceFile, name) }
|
|
}
|
|
val packages = traverser.packages.toArray[String].map(p => new xsbti.api.Package(p))
|
|
val source = new xsbti.api.SourceAPI(packages, traverser.definitions.toArray[xsbti.api.Definition])
|
|
extractApi.forceStructures()
|
|
callback.api(sourceFile, source)
|
|
}
|
|
}
|
|
|
|
private final class TopLevelHandler(extractApi: ExtractAPI[global.type]) extends TopLevelTraverser {
|
|
val packages = new HashSet[String]
|
|
val definitions = new ListBuffer[xsbti.api.Definition]
|
|
def `class`(c: Symbol): Unit = {
|
|
definitions += extractApi.classLike(c.owner, c)
|
|
}
|
|
/** Record packages declared in the source file*/
|
|
def `package`(p: Symbol): Unit = {
|
|
if ((p eq null) || p == NoSymbol || p.isRoot || p.isRootPackage || p.isEmptyPackageClass || p.isEmptyPackage)
|
|
()
|
|
else {
|
|
packages += p.fullName
|
|
`package`(p.enclosingPackage)
|
|
}
|
|
}
|
|
}
|
|
|
|
private abstract class TopLevelTraverser extends Traverser {
|
|
def `class`(s: Symbol)
|
|
def `package`(s: Symbol)
|
|
override def traverse(tree: Tree): Unit = {
|
|
tree match {
|
|
case (_: ClassDef | _: ModuleDef) if isTopLevel(tree.symbol) => `class`(tree.symbol)
|
|
case p: PackageDef =>
|
|
`package`(p.symbol)
|
|
super.traverse(tree)
|
|
case _ =>
|
|
}
|
|
}
|
|
def isTopLevel(sym: Symbol): Boolean =
|
|
(sym ne null) && (sym != NoSymbol) && !sym.isImplClass && !sym.isNestedClass && sym.isStatic &&
|
|
!sym.hasFlag(Flags.SYNTHETIC) && !sym.hasFlag(Flags.JAVA)
|
|
}
|
|
|
|
}
|