preserve API information needed for detecting annotations on defs. fixes #232

This commit is contained in:
Mark Harrah 2011-10-19 22:23:47 -04:00
parent bec7d3fb28
commit 82ad44a701
9 changed files with 30 additions and 19 deletions

View File

@ -55,8 +55,9 @@ object APIUtil
}
def minimizeClass(c: ClassLike): ClassLike =
{
val savedAnnotations = Discovery.defAnnotations(c.structure, (_: Any) => true).toArray[String]
val struct = minimizeStructure(c.structure, c.definitionType == DefinitionType.Module)
new ClassLike(c.definitionType, lzy(emptyType), lzy(struct), c.typeParameters, c.name, c.access, c.modifiers, c.annotations)
new ClassLike(c.definitionType, lzy(emptyType), lzy(struct), savedAnnotations, c.typeParameters, c.name, c.access, c.modifiers, c.annotations)
}
def minimizeStructure(s: Structure, isModule: Boolean): Structure =

View File

@ -47,8 +47,8 @@ object ClassToAPI
val name = c.getName
val tpe = if(Modifier.isInterface(c.getModifiers)) Trait else ClassDef
lazy val (static, instance) = structure(c, enclPkg, cmap)
val cls = new api.ClassLike(tpe, strict(Empty), lzy(instance), typeParameters(c.getTypeParameters), name, acc, mods, annots)
val stat = new api.ClassLike(Module, strict(Empty), lzy(static), emptyTypeParameterArray, name, acc, mods, annots)
val cls = new api.ClassLike(tpe, strict(Empty), lzy(instance), emptyStringArray, typeParameters(c.getTypeParameters), name, acc, mods, annots)
val stat = new api.ClassLike(Module, strict(Empty), lzy(static), emptyStringArray, emptyTypeParameterArray, name, acc, mods, annots)
val defs = cls :: stat :: Nil
cmap(c.getName) = defs
defs
@ -68,6 +68,7 @@ object ClassToAPI
}
def lzy[T <: AnyRef](t: => T): xsbti.api.Lazy[T] = xsbti.SafeLazy(t)
private val emptyStringArray = new Array[String](0)
private val emptyTypeArray = new Array[xsbti.api.Type](0)
private val emptyAnnotationArray = new Array[xsbti.api.Annotation](0)
private val emptyTypeParameterArray = new Array[xsbti.api.TypeParameter](0)

View File

@ -19,17 +19,14 @@ class Discovery(baseClasses: Set[String], annotations: Set[String])
}
def discover(c: ClassLike): Discovered =
{
val onClass = findAnnotations(c.annotations)
val onDefs = defAnnotations(c.structure.declared) ++ defAnnotations(c.structure.inherited)
val onClass = Discovery.findAnnotations(c.annotations, annotations)
val onDefs = Discovery.defAnnotations(c.structure, annotations) ++ c.savedAnnotations.filter(annotations)
val module = isModule(c)
new Discovered( bases(c.name, c.structure.parents), onClass ++ onDefs, module && hasMainMethod(c), module )
}
def bases(own: String, c: Seq[Type]): Set[String] =
(own +: c.flatMap(simpleName)).filter(baseClasses).toSet
def findAnnotations(as: Seq[Annotation]): Set[String] =
as.flatMap { a => simpleName(a.base).filter(annotations) }.toSet
def defAnnotations(defs: Seq[Definition]): Set[String] =
findAnnotations( defs.flatMap { case d: Def if isPublic(d) => d.annotations.toSeq; case _ => Nil } )
}
object Discovery
{
@ -41,6 +38,13 @@ object Discovery
def applications(definitions: Seq[Definition]): Seq[(Definition, Discovered)] =
apply(Set.empty, Set.empty)( definitions )
def findAnnotations(as: Seq[Annotation], pred: String => Boolean): Set[String] =
as.flatMap { a => simpleName(a.base).filter(pred) }.toSet
def defAnnotations(s: Structure, pred: String => Boolean): Set[String] =
defAnnotations(s.declared, pred) ++ defAnnotations(s.inherited, pred)
def defAnnotations(defs: Seq[Definition], pred: String => Boolean): Set[String] =
findAnnotations( defs.flatMap { case d: Def if isPublic(d) => d.annotations.toSeq; case _ => Nil }, pred )
def isConcrete(a: Definition): Boolean = isConcrete(a.modifiers)
def isConcrete(m: Modifiers) = !m.isAbstract
def isPublic(a: Definition): Boolean = isPublic(a.access)

View File

@ -58,6 +58,8 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
private[this] val classLikeCache = new HashMap[(Symbol,Symbol), xsbti.api.ClassLike]
private[this] val pending = new HashSet[xsbti.api.Lazy[_]]
private[this] val emptyStringArray = new Array[String](0)
// to mitigate "temporary leaks" like that caused by NoPhase in 2.8.0,
// this ensures this class is not retaining objects
private def clearCaches()
@ -345,7 +347,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
else DefinitionType.Module
}
else DefinitionType.ClassDef
new xsbti.api.ClassLike(defType, lzy(selfType(in, c)), lzy(structure(in, struct)), typeParameters(in, c), name, getAccess(c), getModifiers(c), annotations(in, c))
new xsbti.api.ClassLike(defType, lzy(selfType(in, c)), lzy(structure(in, struct)), emptyStringArray, typeParameters(in, c), name, getAccess(c), getModifiers(c), annotations(in, c))
}
private final class TopLevelHandler(sourceFile: File) extends TopLevelTraverser
{

View File

@ -127,7 +127,7 @@ object ApplicationsTest extends Specification
}
}
def applications(callback: xsbti.TestCallback): Seq[(File, String)] =
for( (file, api) <- callback.apis.toSeq;
for( (file, api) <- CallbackTest.apis(callback);
x = println("\n" + file + ":\n" + (api.definitions.flatMap { case c: xsbti.api.ClassLike => c.structure.inherited.filter(_.name == "main"); case _ => Nil }).map(xsbt.api.DefaultShowAPI.apply).mkString("\n"));
application <- applications(api))
yield (file, application)

View File

@ -54,7 +54,7 @@ object DetectAnnotations extends Specification
}
}
def subclasses(callback: xsbti.TestCallback): Seq[(File, String, Set[String], Boolean)] =
for( (file, src) <- callback.apis.toSeq; (definition, discovered) <- Discovery(Set.empty, annotationNames)(src.definitions) if !discovered.isEmpty ) yield
for( (file, src) <- CallbackTest.apis(callback); (definition, discovered) <- Discovery(Set.empty, annotationNames)(src.definitions) if !discovered.isEmpty ) yield
(file, definition.name, discovered.annotations, discovered.isModule)
def annotationNames = Set("c.A", "B", "d.C")

View File

@ -37,7 +37,7 @@ object DetectSubclasses extends Specification
}
}
def subclasses(callback: xsbti.TestCallback): Seq[(File, String, Set[String], Boolean)] =
for( (file, src) <- callback.apis.toSeq; (definition, discovered) <- Discovery(subclassNames, Set.empty)(src.definitions) if !discovered.isEmpty ) yield
for( (file, src) <- CallbackTest.apis(callback); (definition, discovered) <- Discovery(subclassNames, Set.empty)(src.definitions) if !discovered.isEmpty ) yield
(file, definition.name, discovered.baseClasses, discovered.isModule)
def subclassNames = Set( "a.Super", "Super2", "x.Super3", "Super4")
}

View File

@ -36,4 +36,6 @@ object CallbackTest
withTemporaryDirectory { outputDir =>
TestCompile(scalaVersion, sources, outputDir, Nil) { case (callback, instance, log) => f(callback, outputDir, instance, log) }
}
def apis(callback: xsbti.TestCallback) =
callback.apis.toSeq map { case (src, api) => (src, xsbt.api.APIUtil.minimize(api)) }
}

View File

@ -16,6 +16,7 @@ Definition
definitionType: DefinitionType
selfType: ~Type
structure: ~Structure
savedAnnotations: String*
TypeMember
TypeAlias
tpe: Type