mirror of https://github.com/sbt/sbt.git
properly handle nested class cycles in Java sources, fixes #22
This commit is contained in:
parent
b4597eb931
commit
1d36be9b00
|
|
@ -5,13 +5,14 @@ package sbt
|
||||||
import xsbti.api
|
import xsbti.api
|
||||||
import xsbti.SafeLazy
|
import xsbti.SafeLazy
|
||||||
import SafeLazy.strict
|
import SafeLazy.strict
|
||||||
|
import collection.mutable
|
||||||
|
|
||||||
object ClassToAPI
|
object ClassToAPI
|
||||||
{
|
{
|
||||||
def apply(c: Seq[Class[_]]): api.Source =
|
def apply(c: Seq[Class[_]]): api.Source =
|
||||||
{
|
{
|
||||||
val pkgs = packages(c).map(p => new api.Package(p))
|
val pkgs = packages(c).map(p => new api.Package(p))
|
||||||
val defs = c.filter(isTopLevel).flatMap(toDefinitions)
|
val defs = c.filter(isTopLevel).flatMap(toDefinitions(new mutable.HashMap))
|
||||||
new api.Source(pkgs.toArray, defs.toArray)
|
new api.Source(pkgs.toArray, defs.toArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -21,7 +22,10 @@ object ClassToAPI
|
||||||
def isTopLevel(c: Class[_]): Boolean =
|
def isTopLevel(c: Class[_]): Boolean =
|
||||||
c.getEnclosingClass eq null
|
c.getEnclosingClass eq null
|
||||||
|
|
||||||
def toDefinitions(c: Class[_]): Seq[api.ClassLike] =
|
type ClassMap = mutable.Map[String, Seq[api.ClassLike]]
|
||||||
|
def toDefinitions(cmap: ClassMap)(c: Class[_]): Seq[api.ClassLike] =
|
||||||
|
cmap.getOrElseUpdate(c.getName, toDefinitions0(c, cmap))
|
||||||
|
def toDefinitions0(c: Class[_], cmap: ClassMap): Seq[api.ClassLike] =
|
||||||
{
|
{
|
||||||
import api.DefinitionType.{ClassDef, Module, Trait}
|
import api.DefinitionType.{ClassDef, Module, Trait}
|
||||||
val enclPkg = packageName(c)
|
val enclPkg = packageName(c)
|
||||||
|
|
@ -30,24 +34,24 @@ object ClassToAPI
|
||||||
val annots = annotations(c.getAnnotations)
|
val annots = annotations(c.getAnnotations)
|
||||||
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)
|
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), typeParameters(c.getTypeParameters), name, acc, mods, annots)
|
||||||
def makeStatic(s: api.Structure) =
|
val stat = new api.ClassLike(Module, strict(Empty), lzy(static), Array(), name, acc, mods, annots)
|
||||||
new api.ClassLike(Module, strict(Empty), strict(s), Array(), name, acc, mods, annots)
|
val defs = cls :: stat :: Nil
|
||||||
cls :: static.map(makeStatic).toList
|
cmap(c.getName) = defs
|
||||||
|
defs
|
||||||
}
|
}
|
||||||
|
|
||||||
def structure(c: Class[_], enclPkg: Option[String]): (Option[api.Structure], api.Structure) =
|
def structure(c: Class[_], enclPkg: Option[String], cmap: ClassMap): (api.Structure, api.Structure) =
|
||||||
{
|
{
|
||||||
val methods = mergeMap(c, c.getMethods, c.getDeclaredMethods, methodToDef(enclPkg))
|
val methods = mergeMap(c, c.getMethods, c.getDeclaredMethods, methodToDef(enclPkg))
|
||||||
val fields = mergeMap(c, c.getFields, c.getDeclaredFields, fieldToDef(enclPkg))
|
val fields = mergeMap(c, c.getFields, c.getDeclaredFields, fieldToDef(enclPkg))
|
||||||
val constructors = mergeMap(c, c.getConstructors, c.getDeclaredConstructors, constructorToDef(enclPkg))
|
val constructors = mergeMap(c, c.getConstructors, c.getDeclaredConstructors, constructorToDef(enclPkg))
|
||||||
val classes = merge[Class[_]](c, c.getClasses, c.getDeclaredClasses, toDefinitions, (_: Seq[Class[_]]).partition(isStatic), _.getEnclosingClass != c)
|
val classes = merge[Class[_]](c, c.getClasses, c.getDeclaredClasses, toDefinitions(cmap), (_: Seq[Class[_]]).partition(isStatic), _.getEnclosingClass != c)
|
||||||
val all = (methods ++ fields ++ constructors ++ classes)
|
val all = (methods ++ fields ++ constructors ++ classes)
|
||||||
val parentTypes = parents(c)
|
val parentTypes = parents(c)
|
||||||
val instanceStructure = new api.Structure(lzy(parentTypes.toArray), lzy(all.declared.toArray), lzy(all.inherited.toArray))
|
val instanceStructure = new api.Structure(lzy(parentTypes.toArray), lzy(all.declared.toArray), lzy(all.inherited.toArray))
|
||||||
def static = new api.Structure(emptyTpeArray, lzy(all.staticDeclared.toArray), lzy(all.staticInherited.toArray))
|
val staticStructure = new api.Structure(emptyTpeArray, lzy(all.staticDeclared.toArray), lzy(all.staticInherited.toArray))
|
||||||
val staticStructure = if(all.staticDeclared.isEmpty && all.staticInherited.isEmpty) None else Some(static)
|
|
||||||
(staticStructure, instanceStructure)
|
(staticStructure, instanceStructure)
|
||||||
}
|
}
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package test;
|
||||||
|
|
||||||
|
public class O2 extends Outer {
|
||||||
|
public static class O3 extends O2 {}
|
||||||
|
public static class O4 extends Outer {}
|
||||||
|
public class O5 extends O4 {}
|
||||||
|
public class O6 extends O2 {}
|
||||||
|
public class O7 extends O5 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package test;
|
||||||
|
|
||||||
|
public class Outer {
|
||||||
|
public class Inner extends Outer {
|
||||||
|
public class Inner2 extends Inner {}
|
||||||
|
public class InnerB extends Outer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue