Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions plugin/src/main/scala/com/typesafe/genjavadoc/AST.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ trait AST { this: TransformCake =>

def classMembers = members.collect { case classInfo: ClassInfo => classInfo }
def methodMembers = members.collect { case methodInfo: MethodInfo => methodInfo }
def fieldMembers = members.collect { case fieldInfo: FieldInfo => fieldInfo }

override def toString =
s"ClassInfo($name, ${pattern("XXXXX", "AAAAA")}, module=$module, pckg=$pckg, ${filepattern("FFFFFF")}, interface=$interface, static=$static)" +
Expand Down Expand Up @@ -191,6 +192,55 @@ trait AST { this: TransformCake =>
}
}

// for val, var and Constructor parameters
case class FieldInfo(access: String, pattern: String => String, ret: String, name: String, comment: Seq[String], v: Option[ValDef] = None) extends Templ {
def sig: String = {
s"$addAnnotations${pattern(s"$ret $name")}"
}

private def addAnnotations: String = v match {
case Some(definition) => {
val annotations = definition.symbol.annotations
.filter(a => allowedAnnotations.contains(a.symbol.fullName('.')))
.map { a => s"@${a.symbol.fullName('.')}" }
.mkString(System.lineSeparator())
if (!annotations.isEmpty) {
annotations + System.lineSeparator()
} else {
annotations
}
}
case None => ""
}
}

object FieldInfo {
def apply(v: ValDef, interface: Boolean, comment: Seq[String], deprecation: Option[DeprecationInfo]): FieldInfo = {
val acc = fieldAccess(v.symbol, interface) + fieldFlags(v.mods, interface)

val (vt, name) =
if (v.name == nme.CONSTRUCTOR) {
("", v.symbol.enclClass.name.toString)
} else (js(v.symbol, v.tpt.tpe), v.name.toString)

val tp = v.symbol.owner.thisType.memberInfo(v.symbol) match {
case p@PolyType(params, _) => js(v.symbol, p)
case _ => ""
}

val impl = if (v.mods.isDeferred || interface) ";" else "= null;"
val pattern = (n: String) => s"$acc $tp $n $impl"

FieldInfo(acc, pattern, vt, name, comment, Some(v))
}

def apply(sym: Symbol): FieldInfo = {
val d = ValDef(sym, EmptyTree)
val f = FieldInfo(d, false, Nil, None)
f.copy(pattern = n => "static " + f.pattern(n))
}
}

private def mangleMethodName(p: ValDef): String = {
if (this.javaKeywords contains p.name.toString) s"${p.name}_" else p.name.toString
}
Expand All @@ -213,6 +263,14 @@ trait AST { this: TransformCake =>
else "public" // this is the case for interfaces
}

private def fieldAccess(sym: Symbol, interface: Boolean): String = {
if (sym.isPublic) "public"
else if (sym.isProtected && !interface) "protected"
else if (sym.isPrivate && !interface) "private"
else if (strictVisibility && sym.privateWithin != NoSymbol) ""
else "public" // this is the case for interfaces
}

private def flags(m: Modifiers): String = {
var f: List[String] = Nil
if (m.isFinal) f ::= "final"
Expand All @@ -227,4 +285,10 @@ trait AST { this: TransformCake =>
(if (f.nonEmpty) " " else "") + f.mkString(" ")
}

private def fieldFlags(m: Modifiers, interface: Boolean): String = {
var f: List[String] = Nil
if (m.isFinal && !interface) f ::= "final"
(if (f.nonEmpty) " " else "") + f.mkString(" ")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ trait BasicTransform { this: TransformCake =>
private def advancePos(p: Position) =
if (p.isDefined && p > templateMaxPos) templateMaxPos = p

def createField: Boolean
def borrowConstructorArgsComment: Boolean

def newTransform(tree: Tree): Tree = {
def commentText(tp: Position, endPos: Option[Position]) = {
val ret = if (tp.isDefined) {
Expand Down Expand Up @@ -110,7 +113,13 @@ trait BasicTransform { this: TransformCake =>
addMethod(d, text)
}
tree
case _: ValDef => { track(tree) }
case v: ValDef => {
if (createField) {
// addField(v, comments) // not working
addField(v.copy(), commentText(v.pos, endPos(v.rhs)))
} else track(tree)
tree
}
case _: PackageDef => { track(tree); superTransform(tree) }
case _: Template => { track(tree); superTransform(tree) }
case _: TypeTree => { track(tree) }
Expand Down Expand Up @@ -155,6 +164,37 @@ trait BasicTransform { this: TransformCake =>
clazz = clazz map (c => c.addMember(MethodInfo(d, c.interface, comment, hasVararg = true, deprecation = deprecationInfo(d))))
}

private def addField(v: ValDef, comments: Seq[String]): Unit = {
clazz = clazz map (c => {
def mergeComments(comments: Seq[String]): Seq[String] = {
val r = "[ ]?[*] @param[ ]+([a-zA-Z_$][a-zA-Z_$0-9]+)[ ]+.*".r
c.comment.collect { case co: String if co.contains("* @param ") =>
try {
val r(pName) = co
if (!pName.isEmpty && pName == v.name.toString.trim) {
co.replace("@param ", "")
} else ""
} catch {
case ex: Throwable => ""
}
}.collect { case str: String if str != "" => str } match {
case Nil => comments
case fromCon => comments match {
case Nil => (Seq("/**") ++ fromCon) :+ " */"
case only if only.size == 1 && !only.exists(p => p.contains("/**") && p.contains("*/")) =>
(only :+ "/**") ++ fromCon :+ " */"
case only if only.size == 1 && only.exists(p => p.contains("/**") && p.contains("*/")) =>
Seq("/**") ++ fromCon :+ only.head.replace("/**", " * ")
case some => (Seq("/**") ++ fromCon :+ some.head.replace("/**", " *")) ++ some.tail
}
}
}
val fieldInfo = FieldInfo(v, c.interface, if (borrowConstructorArgsComment) mergeComments(comments) else comments, deprecation = deprecationInfo(v))
c.addMember(fieldInfo)
})
}

private def deprecationInfo(v: ValDef): Option[DeprecationInfo] = deprecationInfo(v.symbol)
private def deprecationInfo(d: DefDef): Option[DeprecationInfo] = deprecationInfo(d.symbol)
private def deprecationInfo(d: ImplDef): Option[DeprecationInfo] = deprecationInfo(d.symbol)
private def deprecationInfo(symbol: Symbol): Option[DeprecationInfo] =
Expand Down
25 changes: 18 additions & 7 deletions plugin/src/main/scala/com/typesafe/genjavadoc/Output.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ trait Output { this: TransformCake =>
m match {
case clazz: ClassInfo => write(out, clazz)
case method: MethodInfo => write(out, method)
case field: FieldInfo => write(out, field)
}
out.outdent()
out("}")
Expand All @@ -34,6 +35,10 @@ trait Output { this: TransformCake =>
m.comment foreach (out(_))
out(m.sig)
}
def write(out: Out, f: FieldInfo): Unit = {
f.comment foreach (out(_))
out(f.sig)
}

trait Out {
var ind = 0
Expand Down Expand Up @@ -87,7 +92,7 @@ trait Output { this: TransformCake =>
} match {
case Some(nestedClass: ClassInfo) =>
Seq(
c.copy(members = c.classMembers.filterNot(_ == nestedClass).flatMap(liftInnerClassesWithSameName) ++ c.methodMembers),
c.copy(members = c.classMembers.filterNot(_ == nestedClass).flatMap(liftInnerClassesWithSameName) ++ c.methodMembers ++ c.fieldMembers),
nestedClass.copy(
name = s"${nestedClass.name}$$${nestedClass.name}",
static = false,
Expand All @@ -100,7 +105,7 @@ trait Output { this: TransformCake =>
)
)
case _ =>
Seq(c.copy(members = c.classMembers.flatMap(liftInnerClassesWithSameName) ++ c.methodMembers))
Seq(c.copy(members = c.classMembers.flatMap(liftInnerClassesWithSameName) ++ c.methodMembers ++ c.fieldMembers))
}
}

Expand All @@ -124,7 +129,7 @@ trait Output { this: TransformCake =>
case (Some(o), Some(c)) => merge(o, c, forwarders, staticScope)
case (Some(o), None) if forwarders => merge(o, fabricateCompanion(o), forwarders, staticScope)
case (Some(o), None) => Vector(mangleModule(o, addMODULE = forwarders, pruneClasses = false))
case (None, Some(c)) => Vector(c.copy(members = flattenObjects(c.classMembers) ++ c.methodMembers.sortBy(_.name)))
case (None, Some(c)) => Vector(c.copy(members = flattenObjects(c.classMembers) ++ c.methodMembers.sortBy(_.name) ++ c.fieldMembers.sortBy(_.name)))
case (None, None) => ???
}
}
Expand Down Expand Up @@ -155,8 +160,8 @@ trait Output { this: TransformCake =>
else None

val members = moduleInstance ++: (
if (pruneClasses) obj.methodMembers
else flattenObjects(obj.classMembers) ++ obj.methodMembers
if (pruneClasses) obj.methodMembers ++ obj.fieldMembers
else flattenObjects(obj.classMembers) ++ obj.methodMembers ++ obj.fieldMembers
)

val (com: Seq[String], moduleMembers: Vector[Templ]) = members.foldLeft((obj.comment, Vector.empty[Templ]))((p, mem) => mem match {
Expand All @@ -174,6 +179,12 @@ trait Output { this: TransformCake =>
m.copy(comment = Seq("/**", " * Accessor for nested Scala object", " * @return (undocumented)", " */"))
else m
}
val fields = cls.members collect {
case f: FieldInfo =>
if (f.ret.endsWith("$") && classes.exists(_.name == f.name))
f.copy(comment = Seq("/**", " * Accessor for nested Scala object", " * @return (undocumented)", " */"))
else f
}
val staticClasses = obj.members collect {
case c: ClassInfo =>
c.copy(
Expand All @@ -194,11 +205,11 @@ trait Output { this: TransformCake =>
val nestedClasses = flattenObjects(classes, forwarders = false, staticScope = false)
val nestedStaticClasses = flattenObjects(staticClasses, forwarders = false, staticScope = staticScope)
if (forwarders) {
val base = cls.copy(members = nestedClasses ++ nestedStaticClasses ++ staticMethods ++ methods)
val base = cls.copy(members = nestedClasses ++ nestedStaticClasses ++ staticMethods ++ methods ++ fields)
val mod = mangleModule(obj, addMODULE = forwarders, pruneClasses = true)
Vector(base, mod)
} else {
val base = cls.copy(members = nestedClasses ++ staticMethods ++ methods)
val base = cls.copy(members = nestedClasses ++ staticMethods ++ methods ++ fields)
val mod = mangleModule(obj, addMODULE = forwarders, pruneClasses = true)
Vector(base, mod.copy(members = nestedStaticClasses ++ mod.members))
}
Expand Down
4 changes: 4 additions & 0 deletions plugin/src/main/scala/com/typesafe/genjavadoc/Plugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class GenJavadocPlugin(val global: Global) extends Plugin {
lazy val fabricateParams = java.lang.Boolean.parseBoolean(myOptions.getProperty("fabricateParams", "true"))
lazy val strictVisibility = java.lang.Boolean.parseBoolean(myOptions.getProperty("strictVisibility", "false"))
lazy val allowedAnnotations: Set[String] = stringToFilter(myOptions.getProperty("annotations", ""))
lazy val createfield = java.lang.Boolean.parseBoolean(myOptions.getProperty("createfields", "false"))
lazy val borrowConstructorArgsComment = java.lang.Boolean.parseBoolean(myOptions.getProperty("borrowConstructorArgsComment", "false"))

private object MyComponent extends PluginComponent with Transform {

Expand All @@ -73,6 +75,8 @@ class GenJavadocPlugin(val global: Global) extends Plugin {
override val suppressSynthetic: Boolean = GenJavadocPlugin.this.suppressSynthetic
override val fabricateParams: Boolean = GenJavadocPlugin.this.fabricateParams
override val strictVisibility: Boolean = GenJavadocPlugin.this.strictVisibility
override val createField: Boolean = GenJavadocPlugin.this.createfield
override val borrowConstructorArgsComment: Boolean = GenJavadocPlugin.this.createfield && GenJavadocPlugin.this.borrowConstructorArgsComment

override def superTransformUnit(unit: CompilationUnit) = super.transformUnit(unit)
override def superTransform(tree: Tree) = super.transform(tree)
Expand Down