drop 2.7 support, fix fatal warnings support. fixes #153

This commit is contained in:
Mark Harrah 2011-08-17 21:50:46 -04:00
parent 50a3f616ca
commit ff95799af7
6 changed files with 29 additions and 112 deletions

View File

@ -14,11 +14,7 @@ import xsbti.api.{ClassLike, DefinitionType, PathComponent, SimpleType}
object API
{
val name = "xsbt-api"
// for 2.7 compatibility: this class was removed in 2.8
type ImplicitMethodType = AnyRef
}
// imports ImplicitMethodType, which will preserve source compatibility in 2.7 for defDef
import API._
final class API(val global: Global, val callback: xsbti.AnalysisCallback) extends Compat
{
@ -116,7 +112,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
if(pre == NoPrefix)
{
if(sym.isLocalClass || sym.isRoot || sym.isRootPackage) Constants.emptyType
else if(sym.isTypeParameterOrSkolem || isExistential(sym)) reference(sym)
else if(sym.isTypeParameterOrSkolem || sym.isExistentiallyBound) reference(sym)
else {
// this appears to come from an existential type in an inherited member- not sure why isExistential is false here
/*println("Warning: Unknown prefixless type: " + sym + " in " + sym.owner + " in " + sym.enclClass)
@ -145,26 +141,19 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
{
def build(t: Type, typeParams: Array[xsbti.api.TypeParameter], valueParameters: List[xsbti.api.ParameterList]): xsbti.api.Def =
{
// 2.8 compatibility
implicit def symbolsToParameters(syms: List[Symbol]): xsbti.api.ParameterList =
def parameterList(syms: List[Symbol]): xsbti.api.ParameterList =
{
val isImplicitList = syms match { case head :: _ => isImplicit(head); case _ => false }
new xsbti.api.ParameterList(syms.map(parameterS).toArray, isImplicitList)
}
// 2.7 compatibility
implicit def typesToParameters(syms: List[Type]): xsbti.api.ParameterList =
{
val isImplicitList = t.isInstanceOf[ImplicitMethodType]
new xsbti.api.ParameterList(syms.map(parameterT).toArray, isImplicitList)
}
t match
{
case PolyType(typeParams0, base) =>
assert(typeParams.isEmpty)
assert(valueParameters.isEmpty)
build(base, typeParameters(in, typeParams0), Nil)
case MethodType(params, resultType) => // in 2.7, params is of type List[Type], in 2.8 it is List[Symbol]
build(resultType, typeParams, (params: xsbti.api.ParameterList) :: valueParameters)
case MethodType(params, resultType) =>
build(resultType, typeParams, parameterList(params) :: valueParameters)
case Nullary(resultType) => // 2.9 and later
build(resultType, typeParams, valueParameters)
case returnType =>
@ -175,9 +164,6 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
def parameterS(s: Symbol): xsbti.api.MethodParameter =
makeParameter(s.nameString, s.info, s.info.typeSymbol, s)
def parameterT(t: Type): xsbti.api.MethodParameter =
makeParameter("", t, t.typeSymbol, NoSymbol)
// paramSym is only for 2.8 and is to determine if the parameter has a default
def makeParameter(name: String, tpe: Type, ts: Symbol, paramSym: Symbol): xsbti.api.MethodParameter =
{
@ -194,13 +180,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
val t = viewer(in).memberInfo(s)
build(t, Array(), Nil)
}
private def hasDefault(s: Symbol) =
{
// 2.7 compatibility
implicit def flagsWithDefault(f: AnyRef): WithDefault = new WithDefault
class WithDefault { val DEFAULTPARAM = 0x00000000 }
s != NoSymbol && s.hasFlag(Flags.DEFAULTPARAM)
}
private def hasDefault(s: Symbol) = s != NoSymbol && s.hasFlag(Flags.DEFAULTPARAM)
private def fieldDef[T](in: Symbol, s: Symbol, keepConst: Boolean, create: (xsbti.api.Type, String, xsbti.api.Access, xsbti.api.Modifiers, Array[xsbti.api.Annotation]) => T): T =
{
val t = dropNullary(viewer(in).memberType(s))
@ -266,7 +246,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
def mkVal = Some(fieldDef(in, sym, true, new xsbti.api.Val(_,_,_,_,_)))
if(sym.isClass || sym.isModule)
if(ignoreClass(sym)) None else Some(classLike(in, sym))
else if(isNonClassType(sym))
else if(sym.isNonClassType)
Some(typeDef(in, sym))
else if(sym.isVariable)
if(isSourceField(sym)) mkVar else None
@ -278,7 +258,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
None
}
private def ignoreClass(sym: Symbol): Boolean =
sym.isLocalClass || sym.isAnonymousClass || fullName(sym).endsWith(LocalChild)
sym.isLocalClass || sym.isAnonymousClass || sym.fullName.endsWith(LocalChild)
// This filters private[this] vals/vars that were not in the original source.
// The getter will be used for processing instead.
@ -305,7 +285,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
else
{
val within = c.privateWithin
val qualifier = if(within == NoSymbol) Constants.unqualified else new xsbti.api.IdQualifier(fullName(within))
val qualifier = if(within == NoSymbol) Constants.unqualified else new xsbti.api.IdQualifier(within.fullName)
if(c.hasFlag(Flags.PROTECTED)) new xsbti.api.Protected(qualifier)
else new xsbti.api.Private(qualifier)
}
@ -354,7 +334,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
private def classLike(in: Symbol, c: Symbol): ClassLike = classLikeCache.getOrElseUpdate( (in,c), mkClassLike(in, c))
private def mkClassLike(in: Symbol, c: Symbol): ClassLike =
{
val name = fullName(c)
val name = c.fullName
val isModule = c.isModuleClass || c.isModule
val struct = if(isModule) c.moduleClass else c
val defType =
@ -379,7 +359,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
()
else
{
packages += fullName(p)
packages += p.fullName
`package`(p.enclosingPackage)
}
}
@ -414,10 +394,6 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
(sym ne null) && (sym != NoSymbol) && !sym.isImplClass && !sym.isNestedClass && sym.isStatic &&
!sym.hasFlag(Flags.SYNTHETIC) && !sym.hasFlag(Flags.JAVA)
}
// In 2.8, attributes is renamed to annotations
implicit def compat(a: AnyRef): WithAnnotations = new WithAnnotations(a)
class WithAnnotations(a: AnyRef) { def attributes = a.getClass.getMethod("annotations").invoke(a).asInstanceOf[List[AnnotationInfo]] }
private def annotations(in: Symbol, s: Symbol): Array[xsbti.api.Annotation] =
atPhase(currentRun.typerPhase) {
@ -427,14 +403,13 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
// a) they are recorded as normal source methods anyway
// b) there is no way to distinguish them from user-defined methods
val associated = List(b, b.getter(b.enclClass), b.setter(b.enclClass)).filter(_ != NoSymbol)
associated.flatMap( ss => annotations(in, ss.attributes) ).removeDuplicates.toArray ;
associated.flatMap( ss => annotations(in, ss.annotations) ).distinct.toArray ;
}
private def annotatedType(in: Symbol, at: AnnotatedType): xsbti.api.Type =
{
val annots = at.attributes
val annots = at.annotations
if(annots.isEmpty) processType(in, at.underlying) else annotated(in, annots, at.underlying)
}
private def fullName(s: Symbol): String = nameString(s)
private def simpleName(s: Symbol): String =
{
val n = s.originalName

View File

@ -46,7 +46,7 @@ final class Analyzer(val global: Global, val callback: AnalysisCallback) extends
case Some((f,className)) =>
f match
{
case ze: ZipArchive#Entry => binaryDependency(new File(archive(ze).getName), className)
case ze: ZipArchive#Entry => for(zip <- ze.underlyingSource; zipFile <- Option(zip.file) ) binaryDependency(zipFile, className)
case pf: PlainFile => binaryDependency(pf.file, className)
case _ => ()
}
@ -69,7 +69,7 @@ final class Analyzer(val global: Global, val callback: AnalysisCallback) extends
}
if(sym.isModuleClass && !sym.isImplClass)
{
if(isTopLevelModule(sym) && linkedClass(sym) == NoSymbol)
if(isTopLevelModule(sym) && sym.companionClass == NoSymbol)
addGenerated(false)
addGenerated(true)
}
@ -81,14 +81,16 @@ final class Analyzer(val global: Global, val callback: AnalysisCallback) extends
}
}
private def classFile(sym: Symbol): Option[(AbstractFile, String)] =
private[this] final val classSeparator = '.'
private[this] def findClass(name: String): Option[AbstractFile] = classPath.findClass(name).flatMap(_.binary.asInstanceOf[Option[AbstractFile]])
private[this] def classFile(sym: Symbol): Option[(AbstractFile, String)] =
{
import scala.tools.nsc.symtab.Flags
val name = flatname(sym, finder.classSeparator) + moduleSuffix(sym)
finder.findClass(name).map(file => (file, name)) orElse {
val name = flatname(sym, classSeparator) + moduleSuffix(sym)
findClass(name).map(file => (file, name)) orElse {
if(isTopLevelModule(sym))
{
val linked = linkedClass(sym)
val linked = sym.companionClass
if(linked == NoSymbol)
None
else
@ -102,7 +104,7 @@ final class Analyzer(val global: Global, val callback: AnalysisCallback) extends
private def moduleSuffix(sym: Symbol) =
if (sym.hasFlag(Flags.MODULE) && !sym.isMethod && !sym.isImplClass && !sym.hasFlag(Flags.JAVA)) "$" else "";
private def flatname(s: Symbol, separator: Char) =
atPhase(currentRun.flattenPhase.next) { nameString(s, separator) }
atPhase(currentRun.flattenPhase.next) { s fullName separator }
private def isTopLevelModule(sym: Symbol): Boolean =
atPhase (currentRun.picklerPhase.next) {
@ -112,70 +114,14 @@ final class Analyzer(val global: Global, val callback: AnalysisCallback) extends
flatname(s, sep) + (if(dollarRequired) "$" else "")
private def fileForClass(outputDirectory: File, s: Symbol, separatorRequired: Boolean): File =
new File(outputDirectory, className(s, File.separatorChar, separatorRequired) + ".class")
// required because the 2.8 way to find a class is:
// classPath.findClass(name).flatMap(_.binary)
// and the 2.7 way is:
// val entry = classPath.root.find(name, false)
// if(entry eq null) None else Some(entry.classFile)
private lazy val finder = try { new LegacyFinder } catch { case _ => new NewFinder }
private trait ClassFinder
{
def classSeparator: Char
def findClass(name: String): Option[AbstractFile]
}
private class NewFinder extends ClassFinder
{
private class Compat27 { def findClass(name: String) = this; def flatMap(f: Compat27 => AnyRef) = Predef.error("Should never be called"); def binary = None }
private implicit def compat27(any: AnyRef): Compat27 = new Compat27
def classSeparator = '.' // 2.8 uses . when searching for classes
def findClass(name: String): Option[AbstractFile] =
classPath.findClass(name).flatMap(_.binary.asInstanceOf[Option[AbstractFile]])
}
private class LegacyFinder extends ClassFinder
{
private class Compat28 { def root: Compat28 = invalid; def find(n: String, b: Boolean) = this; def classFile = invalid; def invalid = Predef.error("Should never be called") }
private implicit def compat28(any: AnyRef): Compat28 = new Compat28
def classSeparator = File.separatorChar // 2.7 uses / or \ when searching for classes
private val root = classPath.root
def findClass(name: String): Option[AbstractFile] =
{
val entry = root.find(name, false)
if(entry eq null) None else Some(entry.classFile)
}
}
}
abstract class Compat
{
val global: Global
import global._
def archive(s: ZipArchive#Entry): ZipFile = s.getArchive
def nameString(s: Symbol): String = s.fullNameString
def nameString(s: Symbol, sep: Char): String = s.fullNameString(sep)
def isExistential(s: Symbol): Boolean = s.isExistential
def isNonClassType(s: Symbol): Boolean = s.isTypeMember
val LocalChild = global.tpnme.LOCAL_CHILD
val Nullary = global.NullaryMethodType
def linkedClass(s: Symbol): Symbol = s.linkedClassOfModule
/** After 2.8.0.Beta1, fullNameString was renamed fullName.
* linkedClassOfModule was renamed companionClass. */
private[this] implicit def symCompat(sym: Symbol): SymCompat = new SymCompat(sym)
private[this] final class SymCompat(s: Symbol)
{
def fullNameString = s.fullName; def fullName = sourceCompatibilityOnly
def fullNameString(sep: Char) = s.fullName(sep); def fullName(sep: Char) = sourceCompatibilityOnly
def isExistential: Boolean = s.isExistentiallyBound; def isExistentiallyBound = sourceCompatibilityOnly
def isTypeMember: Boolean = s.isNonClassType; def isNonClassType = sourceCompatibilityOnly
def linkedClassOfModule = s.companionClass; def companionClass = sourceCompatibilityOnly
// In 2.8, hasAttribute is renamed to hasAnnotation
def hasAnnotation(a: Symbol) = s.hasAttribute(a); def hasAttribute(a: Symbol) = sourceCompatibilityOnly
}
private[this] final class MiscCompat
{
// in 2.9, nme.LOCALCHILD was renamed to tpnme.LOCAL_CHILD
@ -190,14 +136,6 @@ abstract class Compat
def unapply(t: Type): Option[Type] = None
}
final def hasAnnotation(s: Symbol)(ann: Symbol) = atPhase(currentRun.typerPhase) { s.hasAnnotation(ann) }
/** After 2.8.0.Beta1, getArchive was renamed archive.*/
private[this] implicit def zipCompat(z: ZipArchive#Entry): ZipCompat = new ZipCompat(z)
private[this] final class ZipCompat(z: ZipArchive#Entry)
{
def getArchive = z.archive; def archive = sourceCompatibilityOnly
}
private[this] def sourceCompatibilityOnly: Nothing = throw new RuntimeException("For source compatibility only: should not get here.")
private[this] final implicit def miscCompat(n: AnyRef): MiscCompat = new MiscCompat

View File

@ -44,7 +44,7 @@ private final class DelegatingReporter(warnFatal: Boolean, delegate: xsbti.Repor
protected def info0(pos: Position, msg: String, rawSeverity: Severity, force: Boolean)
{
val severity = if(warnFatal && rawSeverity == WARNING) ERROR else rawSeverity
delegate.log(convert(pos), msg, convert(rawSeverity))
delegate.log(convert(pos), msg, convert(severity))
}
private[this] def convert(posIn: Position): xsbti.Position =
{

View File

@ -85,7 +85,9 @@ object Sbt extends Build
// Compiler-side interface to compiler that is compiled against the compiler being used either in advance or on the fly.
// Includes API and Analyzer phases that extract source API and relationships.
lazy val compileInterfaceSub = baseProject(compilePath / "interface", "Compiler Interface") dependsOn(interfaceSub, ioSub % "test->test", logSub % "test->test", launchSub % "test->test") settings( compileInterfaceSettings : _*)
lazy val precompiled28 = precompiled("2.8.1")
lazy val precompiled290 = precompiled("2.9.0")
lazy val precompiled281 = precompiled("2.8.1")
lazy val precompiled280 = precompiled("2.8.0")
// lazy val precompiled27 = precompiled("2.7.7")
// Implements the core functionality of detecting and propagating changes incrementally.
@ -115,7 +117,7 @@ object Sbt extends Build
// Strictly for bringing implicits and aliases from subsystems into the top-level sbt namespace through a single package object
// technically, we need a dependency on all of mainSub's dependencies, but we don't do that since this is strictly an integration project
// with the sole purpose of providing certain identifiers without qualification (with a package object)
lazy val sbtSub = baseProject(sbtPath, "Simple Build Tool") dependsOn(mainSub, compileInterfaceSub, precompiled28, scriptedSbtSub % "test->test") settings(sbtSettings : _*)
lazy val sbtSub = baseProject(sbtPath, "Simple Build Tool") dependsOn(mainSub, compileInterfaceSub, precompiled281, precompiled280, precompiled290, scriptedSbtSub % "test->test") settings(sbtSettings : _*)
/* Nested subproject paths */
def sbtPath = file("sbt")

View File

@ -1,4 +1,4 @@
name :== "test"
name := "test"
TaskKey[Unit]("check-same") <<= compile in Configurations.Compile map { analysis =>
analysis.apis.internal foreach { case (_, api) =>

View File

@ -1,3 +1,5 @@
> 'set scalacOptions += "-Xfatal-warnings"'
> compile
# have new class E extend A