Skip to content

Commit

Permalink
Support KSDeclaration.getDocString
Browse files Browse the repository at this point in the history
A doc string is a string in the comment right in front of an declaration
and is enclosed by /** and */. Leading whitespaces and * are removed for
each line.
  • Loading branch information
ting-yuan committed May 11, 2021
1 parent fc3abf9 commit aeb290a
Show file tree
Hide file tree
Showing 14 changed files with 236 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,9 @@ interface KSDeclaration : KSModifierListOwner, KSAnnotated, KSExpectActual {
* The containing source file of this declaration, can be null if symbol does not come from a source file, i.e. from a class file.
*/
val containingFile: KSFile?

/**
* The doc string enclosed by \/\*\* and \*\/
*/
val docString: String?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2020 Google LLC
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
*
* Licensed 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 com.google.devtools.ksp.processor

import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSDeclaration
import com.google.devtools.ksp.symbol.KSNode
import com.google.devtools.ksp.visitor.KSTopDownVisitor

class DocStringProcessor : AbstractTestProcessor() {
private val result = mutableListOf<String>()

override fun toResult(): List<String> {
return result
}

private class DeclarationCollector : KSTopDownVisitor<MutableCollection<String>, Unit>() {
override fun defaultHandler(node: KSNode, data: MutableCollection<String>) = Unit

override fun visitDeclaration(declaration: KSDeclaration, data: MutableCollection<String>) {
data.add("${declaration.simpleName.asString()}: ${declaration.docString?.lines()?.joinToString("\\n")}")
}
}

override fun process(resolver: Resolver): List<KSAnnotated> {
val visitor = DeclarationCollector()
resolver.getNewFiles().forEach { it.accept(visitor, result) }
result.sort()
return emptyList()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ abstract class KSDeclarationDescriptorImpl(private val descriptor: DeclarationDe
return this.simpleName.asString()
}

override val docString = null
}

val DeclarationDescriptor.origin: Origin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections

class KSClassDeclarationJavaEnumEntryImpl private constructor(val psi: PsiEnumConstant) : KSClassDeclaration, KSDeclarationJavaImpl(),
class KSClassDeclarationJavaEnumEntryImpl private constructor(val psi: PsiEnumConstant) : KSClassDeclaration, KSDeclarationJavaImpl(psi),
KSExpectActual by KSExpectActualNoImpl() {
companion object : KSObjectCache<PsiEnumConstant, KSClassDeclarationJavaEnumEntryImpl>() {
fun getCached(psi: PsiEnumConstant) = cache.getOrPut(psi) { KSClassDeclarationJavaEnumEntryImpl(psi) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections

class KSClassDeclarationJavaImpl private constructor(val psi: PsiClass) : KSClassDeclaration, KSDeclarationJavaImpl(),
class KSClassDeclarationJavaImpl private constructor(val psi: PsiClass) : KSClassDeclaration, KSDeclarationJavaImpl(psi),
KSExpectActual by KSExpectActualNoImpl() {
companion object : KSObjectCache<PsiClass, KSClassDeclarationJavaImpl>() {
fun getCached(psi: PsiClass) = cache.getOrPut(psi) { KSClassDeclarationJavaImpl(psi) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,19 @@ package com.google.devtools.ksp.symbol.impl.java

import com.google.devtools.ksp.symbol.KSDeclaration
import com.google.devtools.ksp.symbol.KSName
import com.google.devtools.ksp.symbol.impl.getDocString
import com.intellij.psi.PsiElement

abstract class KSDeclarationJavaImpl : KSDeclaration {
abstract class KSDeclarationJavaImpl(private val psi: PsiElement) : KSDeclaration {
override val packageName: KSName by lazy {
this.containingFile!!.packageName
}

override fun toString(): String {
return this.simpleName.asString()
}
}

override val docString by lazy {
psi.getDocString()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiMethod
import com.intellij.psi.impl.source.PsiClassReferenceType

class KSFunctionDeclarationJavaImpl private constructor(val psi: PsiMethod) : KSFunctionDeclaration, KSDeclarationJavaImpl(),
class KSFunctionDeclarationJavaImpl private constructor(val psi: PsiMethod) : KSFunctionDeclaration, KSDeclarationJavaImpl(psi),
KSExpectActual by KSExpectActualNoImpl() {
companion object : KSObjectCache<PsiMethod, KSFunctionDeclarationJavaImpl>() {
fun getCached(psi: PsiMethod) = cache.getOrPut(psi) { KSFunctionDeclarationJavaImpl(psi) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import com.google.devtools.ksp.symbol.impl.*
import com.google.devtools.ksp.symbol.impl.kotlin.KSExpectActualNoImpl
import com.google.devtools.ksp.symbol.impl.kotlin.KSNameImpl

class KSPropertyDeclarationJavaImpl private constructor(val psi: PsiField) : KSPropertyDeclaration, KSDeclarationJavaImpl(),
class KSPropertyDeclarationJavaImpl private constructor(val psi: PsiField) : KSPropertyDeclaration, KSDeclarationJavaImpl(psi),
KSExpectActual by KSExpectActualNoImpl() {
companion object : KSObjectCache<PsiField, KSPropertyDeclarationJavaImpl>() {
fun getCached(psi: PsiField) = cache.getOrPut(psi) { KSPropertyDeclarationJavaImpl(psi) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import com.google.devtools.ksp.symbol.impl.kotlin.KSNameImpl
import com.google.devtools.ksp.symbol.impl.memoized
import com.google.devtools.ksp.symbol.impl.toLocation

class KSTypeParameterJavaImpl private constructor(val psi: PsiTypeParameter) : KSTypeParameter, KSDeclarationJavaImpl(),
class KSTypeParameterJavaImpl private constructor(val psi: PsiTypeParameter) : KSTypeParameter, KSDeclarationJavaImpl(psi),
KSExpectActual by KSExpectActualNoImpl() {
companion object : KSObjectCache<PsiTypeParameter, KSTypeParameterJavaImpl>() {
fun getCached(psi: PsiTypeParameter) = cache.getOrPut(psi) { KSTypeParameterJavaImpl(psi) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package com.google.devtools.ksp.symbol.impl.kotlin
import com.google.devtools.ksp.symbol.*
import com.google.devtools.ksp.symbol.impl.findParentDeclaration
import com.google.devtools.ksp.symbol.impl.memoized
import com.google.devtools.ksp.symbol.impl.getDocString
import com.google.devtools.ksp.symbol.impl.toKSModifiers
import com.google.devtools.ksp.symbol.impl.toLocation
import org.jetbrains.kotlin.psi.*
Expand Down Expand Up @@ -75,4 +76,8 @@ abstract class KSDeclarationImpl(ktDeclaration: KtDeclaration) : KSDeclaration {
internal val originalAnnotations: List<KSAnnotation> by lazy {
ktDeclaration.annotationEntries.map { KSAnnotationImpl.getCached(it) }
}

override val docString by lazy {
ktDeclaration.getDocString()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,6 @@ object KSErrorTypeClassDeclaration : KSClassDeclaration {
override fun toString(): String {
return "Error type synthetic declaration"
}

override val docString = null
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import org.jetbrains.kotlin.types.StarProjectionImpl
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.replace
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
import org.jetbrains.kotlin.psi.psiUtil.siblings
import org.jetbrains.kotlin.resolve.annotations.hasJvmStaticAnnotation
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter

Expand Down Expand Up @@ -229,6 +230,21 @@ fun PsiElement.toLocation(): Location {
return FileLocation(file.virtualFile.path, document.getLineNumber(this.textOffset) + 1)
}

private fun parseDocString(raw: String): String? {
val t1 = raw.trim()
if (!t1.startsWith("/**") || !t1.endsWith("*/"))
return null
val lineSep = t1.findAnyOf(listOf("\r\n", "\n", "\r"))?.second ?: ""
return t1.trim('/').trim('*').lines().joinToString(lineSep) {
it.trimStart().trimStart('*')
}
}

fun PsiElement.getDocString(): String? =
this.firstChild.siblings().firstOrNull { it is PsiComment }?.let {
parseDocString(it.text)
}

// TODO: handle local functions/classes correctly
fun Sequence<KtElement>.getKSDeclarations(): Sequence<KSDeclaration> =
this.mapNotNull {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ public void testDeclared() throws Exception {
runTest("testData/api/declared.kt");
}

@TestMetadata("docString.kt")
public void testDocString() throws Exception {
runTest("testData/api/docString.kt");
}

@TestMetadata("errorTypes.kt")
public void testErrorTypes() throws Exception {
runTest("testData/api/errorTypes.kt");
Expand Down
141 changes: 141 additions & 0 deletions compiler-plugin/testData/api/docString.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright 2020 Google LLC
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
*
* Licensed 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.
*/

// TEST PROCESSOR: DocStringProcessor
// EXPECTED:
// <init>: \n This is a java doc\n\n This is a second line\n\n more lines\n
// <init>: \n inner class\n
// <init>: \n nest class\n
// <init>: \n top level class\n\n doc can have multiple lines\n\n third non-empty line\n
// Inner: \n inner class\n
// JavaSrc: \n This is a java doc\n\n This is a second line\n\n more lines\n
// Nested: \n nest class\n
// TopClass: \n top level class\n\n doc can have multiple lines\n\n third non-empty line\n
// f1: \n top level function\n
// f2: \n member function\n
// foo: \n\n\n member function\n\n
// j1: \n field\n
// j2: null
// j3: null
// v1: \n\n top level property\n\n
// v2: Irregular doc comment 1
// v3: \n Irregular doc comment 2
// v4: Irregular doc comment 3 *\n
// v5: \n owned doc comment\n
// v6: null
// v7: null
// v8: \n member property\n
// END
// FILE: KotlinSrc.kt

/**
* top level function
*/
fun f1() = 0

/**
*
* top level property
*
*/
val v1 = 0


/** * Irregular doc comment 1***/
val v2 = 0

/**
* Irregular doc comment 2*/
val v3 = 0

/** Irregular doc comment 3 *
*/
val v4 = 0

/**
* unassociated doc comment
*/
/**
* owned doc comment
*/
val v5 = 0

/* Not doc comment 1 */
val v6 = 0

// Not doc comment 2
val v7 = 0

/**
* top level class
*
* doc can have multiple lines
*
* third non-empty line
*/
class TopClass {
/**
* nest class
*/
class Nested

/**
* inner class
*/
class Inner

/**
* member function
*/
fun f2() = 0

/**
* member property
*/
val v8 = 0
}

// FILE: JavaSrc.java
/**
* This is a java doc
*
* This is a second line
*
* more lines
*/
class JavaSrc {
/**
*
*
* member function
*
*/
int foo() {
return 0;
}

/**
* field
*/
int j1 = 0;

// Not a doc
int j2 = 0;

/* Not a doc */
int j3 = 0;
}

0 comments on commit aeb290a

Please sign in to comment.