added the generation of the kdoc to the dist goal in Ant, refactored the model a little so that it contains descriptors and removed the java code from kdoc implementation

This commit is contained in:
James Strachan
2012-02-23 11:56:32 +00:00
parent 0212f91343
commit b392a6217e
10 changed files with 211 additions and 209 deletions
+28 -2
View File
@@ -61,16 +61,41 @@
</java>
</target>
<target name="docStdlib">
<target name="compileKdoc">
<mkdir dir="${output}/classes/kdoc"/>
<java classname="org.jetbrains.jet.cli.KotlinCompiler" failonerror="true">
<classpath>
<path refid="classpath"/>
<pathelement location="${kotlin-home}/lib/kotlin-compiler.jar"/>
</classpath>
<arg value="-stdlib"/>
<arg value="${kotlin-home}/lib/kotlin-runtime.jar"/>
<arg value="-src"/>
<arg value="${basedir}/kdoc/src/main/kotlin"/>
<arg value="-output"/>
<arg value="${output}/classes/kdoc"/>
<arg value="-module"/>
<arg value="${basedir}/kdoc/module.kt"/>
</java>
</target>
<target name="docStdlib" depends="compileKdoc">
<mkdir dir="${output}/classes/stdlib"/>
<mkdir dir="${output}/apidoc/stdlib"/>
<java classname="org.jetbrains.jet.cli.KotlinCompiler" failonerror="true">
<classpath>
<path refid="classpath"/>
<pathelement location="${kotlin-home}/lib/kotlin-compiler.jar"/>
<pathelement location="${output}/classes/kdoc"/>
<!--
lets use the local Ant build rather than the mvn build
<fileset dir="${basedir}/kdoc/target">
<include name="**/*.jar"/>
</fileset>
-->
<!-- TODO Dirty Hack until kdoc jar has stdlib inside it -->
<pathelement location="${output}/classes/stdlib"/>
@@ -180,13 +205,14 @@
<delete dir="${output}"/>
</target>
<target name="dist" depends="init,jarRT,jarJDKHeaders,jar,buildToolsJar">
<target name="copyKotlinJars">
<copy todir="${kotlin-home}/lib">
<fileset dir="${idea.sdk}/core" includes="*.jar"/>
<fileset dir="${basedir}/lib" includes="*.jar"/>
</copy>
</target>
<target name="dist" depends="init,jarRT,copyKotlinJars,jarJDKHeaders,jar,buildToolsJar,docStdlib"/>
<target name="test" depends="dist,testlib" description="Creates the distribution and runs all the tests"/>
+9
View File
@@ -0,0 +1,9 @@
import kotlin.modules.*
fun project() {
module("kdoc") {
classpath += "dist/kotlinc/lib/intellij-core.jar"
classpath += "dist/kotlinc/lib/kotlin-compiler.jar"
addSourceFiles("src/main/kotlin")
}
}
@@ -1,5 +1,8 @@
package org.jetbrains.kotlin.doc
import std.*
import std.util.*
import org.jetbrains.kotlin.doc.templates.*
import org.jetbrains.kotlin.template.TextTemplate
import org.jetbrains.kotlin.model.*
@@ -11,6 +14,7 @@ import java.util.Collection
import com.intellij.psi.PsiElement
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.resolve.BindingContext.*
import org.jetbrains.jet.compiler.CompilerPlugin
import org.jetbrains.jet.lang.psi.JetFile
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor
@@ -24,61 +28,110 @@ import org.jetbrains.jet.lang.resolve.java.JavaNamespaceDescriptor
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor
import org.jetbrains.jet.lang.resolve.scopes.JetScope
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver
import org.jetbrains.jet.util.slicedmap.WritableSlice
import org.jetbrains.jet.lang.resolve.BindingContextUtils
class KDoc(val outputDir: File) : KDocSupport() {
class KDoc(val outputDir: File) : CompilerPlugin {
val model = KModel()
var context: BindingContext? = null
override fun addClass(namespace: NamespaceDescriptor?, classElement: ClassDescriptor?) {
if (namespace != null && classElement != null) {
val klass = getOrCreateClass(classElement)
if (klass != null) {
klass.pkg.local = true
override fun processFiles(context: BindingContext?, sources: List<JetFile?>?) {
$context = context
if (context != null && sources != null) {
val allNamespaces = HashSet<NamespaceDescriptor>()
for (source in sources) {
if (source != null) {
// We retrieve a descriptor by a PSI element from the context
val namespaceDescriptor = BindingContextUtils.namespaceDescriptor(context, source)
if (namespaceDescriptor != null) {
allNamespaces.add(namespaceDescriptor);
}
}
}
val allClasses = HashSet<KClass>()
for (namespace in allNamespaces) {
model.getPackage(namespace)
for (descriptor in namespace.getMemberScope().getAllDescriptors()) {
if (descriptor is ClassDescriptor) {
val klass = getOrCreateClass(descriptor)
if (klass != null) {
allClasses.add(klass)
}
} else if (descriptor is NamespaceDescriptor) {
model.getPackage(descriptor)
}
}
//addNamespace(namespace)
}
/*
for (namespace in allNamespaces) {
for (descriptor in namespace.getMemberScope().getAllDescriptors()) {
if (descriptor is CallableDescriptor) {
val pkg = getPackage(namespace)
val function = createFunction(pkg, descriptor)
if (function != null && function.extensionClass == null) {
pkg.functions.add(function)
pkg.local = true
}
}
}
//addNamespace(namespace)
}
*/
// lets add the functions...
for (klass in allClasses) {
addFunctions(klass, klass.functions, klass.descriptor.getDefaultType().getMemberScope())
}
for (pkg in model.allPackages) {
for (descriptor in pkg.descriptor.getMemberScope().getAllDescriptors()) {
if (descriptor is CallableDescriptor) {
val function = createFunction(pkg, descriptor)
if (function != null && function.extensionClass == null) {
pkg.functions.add(function)
pkg.local = true
}
}
}
}
generate();
}
}
protected fun containerName(descriptor: DeclarationDescriptor): String {
val container = descriptor.containingDeclaration
if (container == null || container is ModuleDescriptor || container is JavaNamespaceDescriptor) {
return ""
} else {
val parent = containerName(container)
val name = container.getName() ?: ""
val answer = if (parent.length() > 0) parent + "." + name else name
return if (answer.startsWith(".")) answer.substring(1) else answer
}
fun generate(): Unit {
val generator = KDocGenerator(model, outputDir)
generator.execute()
}
protected fun getOrCreateClass(classElement: ClassDescriptor): KClass? {
//val docComment = getDocCommentFor(classElement.sure()) ?: "";
val container = classElement.containingDeclaration
val namespaceName = containerName(classElement)
val pkg = model.getPackage(namespaceName)
pkg.initialise{
if (container is NamespaceDescriptor) {
addFunctions(pkg, pkg.functions, container.getMemberScope())
}
}
val name = classElement.getName()
if (name != null) {
val klass = pkg.getClass(name)
klass.initialise {
if (klass.pkg.description.length() == 0) {
klass.pkg.description = commentsFor(container)
}
klass.description = commentsFor(classElement)
val superTypes = classElement.getTypeConstructor().getSupertypes()
for (st in superTypes) {
val sc = getType(st)
if (sc != null) {
klass.baseClasses.add(sc)
}
}
addFunctions(klass, klass.functions, classElement.getDefaultType().getMemberScope())
val container = classElement.containingDeclaration
if (name != null && container is NamespaceDescriptor) {
val pkg = model.getPackage(container)
//val namespaceName = containerName(classElement)
val klass = KClass(pkg, classElement, name)
pkg.classMap.put(name, klass)
if (pkg.description.length() == 0) {
pkg.description = commentsFor(container)
}
pkg.local = true
klass.description = commentsFor(classElement)
val superTypes = classElement.getTypeConstructor().getSupertypes()
for (st in superTypes) {
val sc = getType(st)
if (sc != null) {
klass.baseClasses.add(sc)
}
}
//addFunctions(klass, klass.functions, classElement.getDefaultType().getMemberScope())
return klass
} else {
println("No package found for $container and class $name")
return null
}
return null
}
protected fun addFunctions(owner: KClassOrPackage, list: Collection<KFunction>, scope: JetScope): Unit {
@@ -137,16 +190,10 @@ class KDoc(val outputDir: File) : KDocSupport() {
return null
}
override fun generate() {
if (!model.packages.isEmpty()) {
val generator = KDocGenerator(model, outputDir)
generator.execute()
}
}
protected fun commentsFor(descriptor: DeclarationDescriptor): String {
/*
val psiElement = try {
context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor)
BindingContextUtils.descriptorToDeclaration(context.sure(), descriptor)
} catch (e: Throwable) {
// ignore exceptions on fake descriptors
null
@@ -162,6 +209,7 @@ class KDoc(val outputDir: File) : KDocSupport() {
if (node?.getElementType() != JetTokens.DOC_COMMENT) return ""
return node?.getText() ?: ""
}
*/
return ""
}
@@ -1,78 +0,0 @@
/**
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.doc;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.compiler.CompileEnvironment; // Just to show it compiles.
import org.jetbrains.jet.compiler.CompilerPlugin;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* TODO This class is written in Java for now to work around a few gremlins in Kotlin...
*/
public abstract class KDocSupport implements CompilerPlugin {
protected BindingContext context;
public void processFiles(BindingContext context, List<JetFile> sources) {
this.context = context;
Set<NamespaceDescriptor> allNamespaces = new HashSet<NamespaceDescriptor>();
for (JetFile source : sources) {
// We retrieve a descriptor by a PSI element from the context
NamespaceDescriptor namespaceDescriptor = context.get(BindingContext.NAMESPACE, source);
if (namespaceDescriptor != null) {
allNamespaces.add(namespaceDescriptor);
}
}
for (NamespaceDescriptor namespace : allNamespaces) {
// Let's take all the declarations in the namespace...
processDescriptors(namespace, namespace.getMemberScope().getAllDescriptors(), context);
}
generate();
}
protected abstract void generate();
private void processDescriptors(NamespaceDescriptor namespace, Collection<DeclarationDescriptor> allDescriptors, BindingContext context) {
for (DeclarationDescriptor descriptor : allDescriptors) {
PsiElement classElement = context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
/*
// Print the class header (verbose)
System.out.println(DescriptorRenderer.TEXT.render(descriptor));
*/
// Process members, if any
if (descriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
if (classElement != null) {
addClass(namespace, classDescriptor);
}
//processDescriptors(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors(), context);
}
}
}
protected abstract void addClass(NamespaceDescriptor namespace, ClassDescriptor classDescriptor);
}
@@ -172,31 +172,7 @@ DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHO
&nbsp;""")
}
println("""<!-- ========== METHOD SUMMARY =========== -->
<A NAME="method_summary"><!-- --></A>
<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
<B>Method Summary</B></FONT></TH>
</TR>""")
printFunctionSummary(klass.functions)
println("""</TABLE>
&nbsp;
<P>
<!-- ============ METHOD DETAIL ========== -->
<A NAME="method_detail"><!-- --></A>
<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
<B>Method Detail</B></FONT></TH>
</TR>
</TABLE>
""")
printFunctionDetail(klass.functions)
println("""<!-- ========= END OF CLASS DATA ========= -->
@@ -24,8 +24,7 @@ abstract class KDocTemplate() : TextTemplate() {
return if (f.owner is KClass) {
"${href(f.owner)}#${f.link}"
} else {
// TODO how to find the function in a package???
""
"#${f.link}"
}
}
@@ -66,7 +66,7 @@ class PackageFrameTemplate(val model: KModel, p: KPackage) : PackageTemplateSupp
}
protected fun printFunctions(): Unit {
val functions = pkg.functions.filter{ it.extensionClass == null }
val functions = pkg.packageFunctions()
if (! functions.isEmpty()) {
println("""<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
<TR>
@@ -152,9 +152,11 @@ function windowTitle()
</ul>""")
}
}
println("<P>")
printFunctionDetail(pkg.packageFunctions())
println("""
<P>
<P>
<DL>
@@ -252,10 +254,10 @@ Copyright &#169; 2010-2012. All Rights Reserved.
<B>Functions Summary</B></FONT></TH>
</TR>""")
for (c in functions) {
for (f in functions) {
println("""<TR BGCOLOR="white" CLASS="TableRowColor">""")
println("<TD WIDTH=\"15%\"><B><A HREF=\"${pkg.nameAsRelativePath}${c.name}.html\" title=\"function in ${pkg.name}\">${c.name}</A></B></TD>")
println("<TD>${c.description}</TD>")
println("<TD WIDTH=\"15%\"><B><A HREF=\"${href(f)}\" title=\"function in ${pkg.name}\">${f.name}</A></B></TD>")
println("<TD>${f.description}</TD>")
println("</TR>")
}
println("""</TABLE>
@@ -1,10 +1,10 @@
package org.jetbrains.kotlin.doc.templates
import std.*
import org.jetbrains.kotlin.template.*
import std.io.*
import std.util.*
import java.util.*
import org.jetbrains.kotlin.template.*
import org.jetbrains.kotlin.model.KModel
import org.jetbrains.kotlin.model.KPackage
import org.jetbrains.kotlin.model.KClass
@@ -16,20 +16,50 @@ abstract class PackageTemplateSupport(private val _pkg: KPackage) : KDocTemplate
// TODO this verbosity is to work around this bug: http://youtrack.jetbrains.com/issue/KT-1398
public val pkg: KPackage
get() = _pkg
get() = _pkg
protected override fun relativePrefix(): String = pkg.nameAsRelativePath
fun printFunctionSummary(functions: Collection<KFunction>): Unit {
for (f in functions) {
printFunctionSummary(f)
if (functions.notEmpty()) {
println("""<!-- ========== METHOD SUMMARY =========== -->
<A NAME="method_summary"><!-- --></A>
<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
<B>Method Summary</B></FONT></TH>
</TR>""")
for (f in functions) {
printFunctionSummary(f)
}
println("""</TABLE>
&nbsp;
<P>
""")
}
}
fun printFunctionDetail(functions: Collection<KFunction>): Unit {
for (f in functions) {
printFunctionDetail(f)
if (functions.notEmpty()) {
println("""
<!-- ============ METHOD DETAIL ========== -->
<A NAME="method_detail"><!-- --></A>
<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
<B>Method Detail</B></FONT></TH>
</TR>
</TABLE>
""")
for (f in functions) {
printFunctionDetail(f)
}
}
}
@@ -1,10 +1,28 @@
package org.jetbrains.kotlin.model
import java.lang.String
//import std.*
import std.*
import std.util.*
import java.util.*
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
import org.jetbrains.jet.lang.resolve.java.JavaNamespaceDescriptor
fun containerName(descriptor: DeclarationDescriptor): String = qualifiedName(descriptor.containingDeclaration)
fun qualifiedName(descriptor: DeclarationDescriptor?): String {
if (descriptor == null || descriptor is ModuleDescriptor || descriptor is JavaNamespaceDescriptor) {
return ""
} else {
val parent = containerName(descriptor)
val name = descriptor.getName() ?: ""
val answer = if (parent.length() > 0) parent + "." + name else name
return if (answer.startsWith(".")) answer.substring(1) else answer
}
}
fun extensionFunctions(functions: Collection<KFunction>): SortedMap<KClass, List<KFunction>> {
val map = TreeMap<KClass, List<KFunction>>()
@@ -31,19 +49,15 @@ class KModel(var title: String = "Documentation", var version: String = "TODO")
public val classes: Collection<KClass>
get() = packages.flatMap{ it.classes }
/* Returns the package for the given name, creating one if its not already been create yet */
fun getPackage(name: String): KPackage {
return packageMap.getOrPut(name){ KPackage(this, name) }
}
/* Returns the package for the given name or null if it does not exist */
fun getPackage(name: String): KPackage? = packageMap.get(name)
/* Returns the class for the given qualified name, creating one if its not already been created yet */
fun getClass(qualifiedName: String): KClass {
val idx = qualifiedName.lastIndexOf('.')
return if (idx > 0) {
getPackage(qualifiedName.substring(0, idx)).getClass(qualifiedName.substring(idx + 1))
} else {
getPackage("").getClass(qualifiedName)
}
/** Returns the package for the given descriptor, creating one if its not available */
fun getPackage(namespace: NamespaceDescriptor): KPackage {
val name = qualifiedName(namespace)
return packageMap.getOrPut(name) {
KPackage(this, namespace, name)
}
}
fun previous(pkg: KPackage): KPackage? {
@@ -57,30 +71,20 @@ class KModel(var title: String = "Documentation", var version: String = "TODO")
}
}
class KPackage(val model: KModel, val name: String, var external: Boolean = false,
class KPackage(val model: KModel, val descriptor: NamespaceDescriptor,
val name: String, var external: Boolean = false,
var description: String = "", var detailedDescription: String = "",
var functions: SortedSet<KFunction> = TreeSet<KFunction>(),
var local: Boolean = false) : Comparable<KPackage>, KClassOrPackage {
override fun compareTo(other: KPackage): Int = name.compareTo(other.name)
fun equals(other: KPackage) = name == other.name
fun toString() = "KPackage($name)"
private var _initialised = false
/** Runs the initialisation block if this class has not yet been initialised */
fun initialise(fn: () -> Unit): Unit {
if (!_initialised) {
_initialised = true
fn()
}
}
/** Returns the name as a directory using '/' instead of '.' */
public val nameAsPath: String
get() = name.replace('.', '/')
get() = if (name.length() == 0) "." else name.replace('.', '/')
/** Returns a list of all the paths in the package name */
public val namePaths: List<String>
@@ -109,13 +113,6 @@ class KPackage(val model: KModel, val name: String, var external: Boolean = fals
public val annotations: Collection<KClass> = ArrayList<KClass>()
/* Returns the class for the given name, creating one if its not already been create yet */
fun getClass(simpleName: String): KClass {
return classMap.getOrPut(simpleName) {
KClass(this, simpleName) }
}
fun qualifiedName(simpleName: String): String {
return if (name.length() > 0) {
"${name}.${simpleName}"
@@ -138,9 +135,12 @@ class KPackage(val model: KModel, val name: String, var external: Boolean = fals
fun groupClassMap(): Map<String, List<KClass>> {
return classes.groupBy(TreeMap<String, List<KClass>>()){it.group}
}
fun packageFunctions() = functions.filter{ it.extensionClass == null }
}
class KClass(val pkg: KPackage, val simpleName: String,
class KClass(val pkg: KPackage, val descriptor: ClassDescriptor,
val simpleName: String,
var kind: String = "class", var group: String = "Other",
var description: String = "", var detailedDescription: String = "",
var annotations: List<KAnnotation> = arrayList<KAnnotation>(),
@@ -151,16 +151,6 @@ class KClass(val pkg: KPackage, val simpleName: String,
var nestedClasses: List<KClass> = arrayList<KClass>(),
var sourceLine: Int = 2) : Comparable<KClass>, KClassOrPackage {
private var _initialised = false
/** Runs the initialisation block if this class has not yet been initialised */
fun initialise(fn: () -> Unit): Unit {
if (!_initialised) {
_initialised = true
fn()
}
}
override fun compareTo(other: KClass): Int = name.compareTo(other.name)
fun equals(other: KClass) = name == other.name