mirror of https://github.com/sbt/sbt.git
preserve API information needed for detecting annotations on defs. fixes #232
This commit is contained in:
parent
bec7d3fb28
commit
82ad44a701
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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,12 +68,13 @@ object ClassToAPI
|
|||
}
|
||||
def lzy[T <: AnyRef](t: => T): xsbti.api.Lazy[T] = xsbti.SafeLazy(t)
|
||||
|
||||
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)
|
||||
private val emptySimpleTypeArray = new Array[xsbti.api.SimpleType](0)
|
||||
private val lzyEmptyTpeArray = lzy(emptyTypeArray)
|
||||
private val lzyEmptyDefArray = lzy(new Array[xsbti.api.Definition](0))
|
||||
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)
|
||||
private val emptySimpleTypeArray = new Array[xsbti.api.SimpleType](0)
|
||||
private val lzyEmptyTpeArray = lzy(emptyTypeArray)
|
||||
private val lzyEmptyDefArray = lzy(new Array[xsbti.api.Definition](0))
|
||||
|
||||
def parents(c: Class[_]): Seq[api.Type] =
|
||||
types(c.getGenericSuperclass +: c.getGenericInterfaces)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
@ -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)) }
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ Definition
|
|||
definitionType: DefinitionType
|
||||
selfType: ~Type
|
||||
structure: ~Structure
|
||||
savedAnnotations: String*
|
||||
TypeMember
|
||||
TypeAlias
|
||||
tpe: Type
|
||||
|
|
|
|||
Loading…
Reference in New Issue