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 =
|
def minimizeClass(c: ClassLike): ClassLike =
|
||||||
{
|
{
|
||||||
|
val savedAnnotations = Discovery.defAnnotations(c.structure, (_: Any) => true).toArray[String]
|
||||||
val struct = minimizeStructure(c.structure, c.definitionType == DefinitionType.Module)
|
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 =
|
def minimizeStructure(s: Structure, isModule: Boolean): Structure =
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,8 @@ object ClassToAPI
|
||||||
val name = c.getName
|
val name = c.getName
|
||||||
val tpe = if(Modifier.isInterface(c.getModifiers)) Trait else ClassDef
|
val tpe = if(Modifier.isInterface(c.getModifiers)) Trait else ClassDef
|
||||||
lazy val (static, instance) = structure(c, enclPkg, cmap)
|
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 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), emptyTypeParameterArray, 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
|
val defs = cls :: stat :: Nil
|
||||||
cmap(c.getName) = defs
|
cmap(c.getName) = defs
|
||||||
defs
|
defs
|
||||||
|
|
@ -68,6 +68,7 @@ object ClassToAPI
|
||||||
}
|
}
|
||||||
def lzy[T <: AnyRef](t: => T): xsbti.api.Lazy[T] = xsbti.SafeLazy(t)
|
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 emptyTypeArray = new Array[xsbti.api.Type](0)
|
||||||
private val emptyAnnotationArray = new Array[xsbti.api.Annotation](0)
|
private val emptyAnnotationArray = new Array[xsbti.api.Annotation](0)
|
||||||
private val emptyTypeParameterArray = new Array[xsbti.api.TypeParameter](0)
|
private val emptyTypeParameterArray = new Array[xsbti.api.TypeParameter](0)
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,14 @@ class Discovery(baseClasses: Set[String], annotations: Set[String])
|
||||||
}
|
}
|
||||||
def discover(c: ClassLike): Discovered =
|
def discover(c: ClassLike): Discovered =
|
||||||
{
|
{
|
||||||
val onClass = findAnnotations(c.annotations)
|
val onClass = Discovery.findAnnotations(c.annotations, annotations)
|
||||||
val onDefs = defAnnotations(c.structure.declared) ++ defAnnotations(c.structure.inherited)
|
val onDefs = Discovery.defAnnotations(c.structure, annotations) ++ c.savedAnnotations.filter(annotations)
|
||||||
val module = isModule(c)
|
val module = isModule(c)
|
||||||
new Discovered( bases(c.name, c.structure.parents), onClass ++ onDefs, module && hasMainMethod(c), module )
|
new Discovered( bases(c.name, c.structure.parents), onClass ++ onDefs, module && hasMainMethod(c), module )
|
||||||
}
|
}
|
||||||
def bases(own: String, c: Seq[Type]): Set[String] =
|
def bases(own: String, c: Seq[Type]): Set[String] =
|
||||||
(own +: c.flatMap(simpleName)).filter(baseClasses).toSet
|
(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
|
object Discovery
|
||||||
{
|
{
|
||||||
|
|
@ -41,6 +38,13 @@ object Discovery
|
||||||
def applications(definitions: Seq[Definition]): Seq[(Definition, Discovered)] =
|
def applications(definitions: Seq[Definition]): Seq[(Definition, Discovered)] =
|
||||||
apply(Set.empty, Set.empty)( definitions )
|
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(a: Definition): Boolean = isConcrete(a.modifiers)
|
||||||
def isConcrete(m: Modifiers) = !m.isAbstract
|
def isConcrete(m: Modifiers) = !m.isAbstract
|
||||||
def isPublic(a: Definition): Boolean = isPublic(a.access)
|
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 classLikeCache = new HashMap[(Symbol,Symbol), xsbti.api.ClassLike]
|
||||||
private[this] val pending = new HashSet[xsbti.api.Lazy[_]]
|
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,
|
// to mitigate "temporary leaks" like that caused by NoPhase in 2.8.0,
|
||||||
// this ensures this class is not retaining objects
|
// this ensures this class is not retaining objects
|
||||||
private def clearCaches()
|
private def clearCaches()
|
||||||
|
|
@ -345,7 +347,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
|
||||||
else DefinitionType.Module
|
else DefinitionType.Module
|
||||||
}
|
}
|
||||||
else DefinitionType.ClassDef
|
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
|
private final class TopLevelHandler(sourceFile: File) extends TopLevelTraverser
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ object ApplicationsTest extends Specification
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def applications(callback: xsbti.TestCallback): Seq[(File, String)] =
|
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"));
|
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))
|
application <- applications(api))
|
||||||
yield (file, application)
|
yield (file, application)
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ object DetectAnnotations extends Specification
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def subclasses(callback: xsbti.TestCallback): Seq[(File, String, Set[String], Boolean)] =
|
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)
|
(file, definition.name, discovered.annotations, discovered.isModule)
|
||||||
|
|
||||||
def annotationNames = Set("c.A", "B", "d.C")
|
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)] =
|
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)
|
(file, definition.name, discovered.baseClasses, discovered.isModule)
|
||||||
def subclassNames = Set( "a.Super", "Super2", "x.Super3", "Super4")
|
def subclassNames = Set( "a.Super", "Super2", "x.Super3", "Super4")
|
||||||
}
|
}
|
||||||
|
|
@ -36,4 +36,6 @@ object CallbackTest
|
||||||
withTemporaryDirectory { outputDir =>
|
withTemporaryDirectory { outputDir =>
|
||||||
TestCompile(scalaVersion, sources, outputDir, Nil) { case (callback, instance, log) => f(callback, outputDir, instance, log) }
|
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
|
definitionType: DefinitionType
|
||||||
selfType: ~Type
|
selfType: ~Type
|
||||||
structure: ~Structure
|
structure: ~Structure
|
||||||
|
savedAnnotations: String*
|
||||||
TypeMember
|
TypeMember
|
||||||
TypeAlias
|
TypeAlias
|
||||||
tpe: Type
|
tpe: Type
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue