From b392a6217eaa79277111694bf852c38508e11b89 Mon Sep 17 00:00:00 2001 From: James Strachan Date: Thu, 23 Feb 2012 11:56:32 +0000 Subject: [PATCH] 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 --- build.xml | 30 +++- kdoc/module.kt | 9 ++ .../kotlin/org/jetbrains/kotlin/doc/KDoc.kt | 144 ++++++++++++------ .../org/jetbrains/kotlin/doc/KDocSupport.java | 78 ---------- .../kotlin/doc/templates/ClassTemplate.kt | 24 --- .../kotlin/doc/templates/KDocTemplate.kt | 3 +- .../doc/templates/PackageFrameTemplate.kt | 2 +- .../doc/templates/PackageSummaryTemplate.kt | 10 +- .../doc/templates/PackageTemplateSupport.kt | 42 ++++- .../org/jetbrains/kotlin/model/KotlinModel.kt | 78 +++++----- 10 files changed, 211 insertions(+), 209 deletions(-) create mode 100644 kdoc/module.kt delete mode 100644 kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/KDocSupport.java diff --git a/build.xml b/build.xml index 84c4c0bdae4..3eb8db32a41 100644 --- a/build.xml +++ b/build.xml @@ -61,16 +61,41 @@ - + + + + + + + + + + + + + + + + + + + + + + + @@ -180,13 +205,14 @@ - + + diff --git a/kdoc/module.kt b/kdoc/module.kt new file mode 100644 index 00000000000..1b1d078931a --- /dev/null +++ b/kdoc/module.kt @@ -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") + } +} \ No newline at end of file diff --git a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/KDoc.kt b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/KDoc.kt index 382faec2c26..89f5cd7dbf6 100644 --- a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/KDoc.kt +++ b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/KDoc.kt @@ -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?) { + $context = context + if (context != null && sources != null) { + val allNamespaces = HashSet() + 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() + 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, 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 "" } diff --git a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/KDocSupport.java b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/KDocSupport.java deleted file mode 100644 index 035cb9e52d4..00000000000 --- a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/KDocSupport.java +++ /dev/null @@ -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 sources) { - this.context = context; - Set allNamespaces = new HashSet(); - 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 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); -} diff --git a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/ClassTemplate.kt b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/ClassTemplate.kt index 9ad42bea492..eb55a3424d9 100644 --- a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/ClassTemplate.kt +++ b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/ClassTemplate.kt @@ -172,31 +172,7 @@ DETAIL: FIELD | CONSTR | METHO  """) } - println(""" - - - - - -""") - printFunctionSummary(klass.functions) - - println("""
-Method Summary
-  -

- - - - - - - - -
-Method Detail
-""") printFunctionDetail(klass.functions) println(""" diff --git a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/KDocTemplate.kt b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/KDocTemplate.kt index f5a875e97d4..9dc719bb891 100644 --- a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/KDocTemplate.kt +++ b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/KDocTemplate.kt @@ -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}" } } diff --git a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageFrameTemplate.kt b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageFrameTemplate.kt index 1e930cc2031..e2baf4a0928 100644 --- a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageFrameTemplate.kt +++ b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageFrameTemplate.kt @@ -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(""" diff --git a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageSummaryTemplate.kt b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageSummaryTemplate.kt index e400eb07a61..837271838b4 100644 --- a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageSummaryTemplate.kt +++ b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageSummaryTemplate.kt @@ -152,9 +152,11 @@ function windowTitle() """) } } + println("

") + + printFunctionDetail(pkg.packageFunctions()) println(""" -

@@ -252,10 +254,10 @@ Copyright © 2010-2012. All Rights Reserved. Functions Summary
""") - for (c in functions) { + for (f in functions) { println("""""") - println("") - println("") + println("") + println("") println("") } println("""
${c.name}${c.description}${f.name}${f.description}
diff --git a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageTemplateSupport.kt b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageTemplateSupport.kt index 3a85abdddbe..6fffec0e6d4 100644 --- a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageTemplateSupport.kt +++ b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageTemplateSupport.kt @@ -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): Unit { - for (f in functions) { - printFunctionSummary(f) + if (functions.notEmpty()) { + println(""" + + + + + +""") + + for (f in functions) { + printFunctionSummary(f) + } + println("""
+Method Summary
+  +

+""") } } fun printFunctionDetail(functions: Collection): Unit { - for (f in functions) { - printFunctionDetail(f) + if (functions.notEmpty()) { + println(""" + + + + + + + + +
+ Method Detail
+ """) + + for (f in functions) { + printFunctionDetail(f) + } } } diff --git a/kdoc/src/main/kotlin/org/jetbrains/kotlin/model/KotlinModel.kt b/kdoc/src/main/kotlin/org/jetbrains/kotlin/model/KotlinModel.kt index f90fb40da42..83389c1451c 100644 --- a/kdoc/src/main/kotlin/org/jetbrains/kotlin/model/KotlinModel.kt +++ b/kdoc/src/main/kotlin/org/jetbrains/kotlin/model/KotlinModel.kt @@ -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): SortedMap> { val map = TreeMap>() @@ -31,19 +49,15 @@ class KModel(var title: String = "Documentation", var version: String = "TODO") public val classes: Collection 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 = TreeSet(), var local: Boolean = false) : Comparable, 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 @@ -109,13 +113,6 @@ class KPackage(val model: KModel, val name: String, var external: Boolean = fals public val annotations: Collection = ArrayList() - - /* 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> { return classes.groupBy(TreeMap>()){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 = arrayList(), @@ -151,16 +151,6 @@ class KClass(val pkg: KPackage, val simpleName: String, var nestedClasses: List = arrayList(), var sourceLine: Int = 2) : Comparable, 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