diff --git a/compiler/psi/src/org/jetbrains/kotlin/kdoc/psi/api/KDoc.kt b/compiler/psi/src/org/jetbrains/kotlin/kdoc/psi/api/KDoc.kt index 18e12875d1e..0209d6f0720 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/kdoc/psi/api/KDoc.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/kdoc/psi/api/KDoc.kt @@ -1,30 +1,20 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * 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. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.kdoc.psi.api -import com.intellij.psi.PsiComment +import com.intellij.psi.PsiDocCommentBase import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag -// Don't implement JetElement (or it will be treated as statement) -interface KDoc : PsiComment, KDocElement { - fun getOwner(): KtDeclaration? +// Don't implement KtElement (or it will be treated as statement) +interface KDoc : PsiDocCommentBase, KDocElement { + override fun getOwner(): KtDeclaration? fun getDefaultSection(): KDocSection + fun getAllSections(): List fun findSectionByName(name: String): KDocSection? fun findSectionByTag(tag: KDocKnownTag): KDocSection? fun findSectionByTag(tag: KDocKnownTag, subjectName: String): KDocSection? diff --git a/compiler/psi/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocImpl.kt b/compiler/psi/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocImpl.kt index dec8cf0d53a..43c5480fe8c 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocImpl.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocImpl.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * 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. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.kdoc.psi.impl @@ -37,9 +26,12 @@ class KDocImpl(buffer: CharSequence?) : LazyParseablePsiElement(KDocTokens.KDOC, override fun getTokenType(): IElementType = KtTokens.DOC_COMMENT - override fun getOwner(): KtDeclaration? = getParentOfType(true) + override fun getOwner(): KtDeclaration? = getParentOfType(true) - override fun getDefaultSection(): KDocSection = getChildOfType()!! + override fun getDefaultSection(): KDocSection = getChildOfType()!! + + override fun getAllSections(): List = + getChildrenOfType().toList() override fun findSectionByName(name: String): KDocSection? = getChildrenOfType().firstOrNull { it.name == name } diff --git a/compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt b/compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt index b7823868e2c..331d58f19ae 100644 --- a/compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt @@ -62,7 +62,8 @@ class CodeConformanceTest : TestCase() { "compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt", "compiler/util/src/org/jetbrains/kotlin/config/MavenComparableVersion.java", "dependencies/protobuf/protobuf-relocated/build", - "compiler/fir/lightTree/testData" + "compiler/fir/lightTree/testData", + "idea/testData/codeInsight/renderingKDoc" ).map(::File) private val COPYRIGHT_EXCLUDED_FILES_AND_DIRS = listOf( diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 91ef3e6c614..cc7afcbd42e 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -476,6 +476,10 @@ fun main(args: Array) { model("codeInsight/expressionType") } + testClass { + model("codeInsight/renderingKDoc") + } + testClass { model("editor/backspaceHandler") } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/kdoc/KDocElementFactory.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/kdoc/KDocElementFactory.kt index 48049637f50..98e2a35e57e 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/kdoc/KDocElementFactory.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/kdoc/KDocElementFactory.kt @@ -37,6 +37,6 @@ class KDocElementFactory(val project: Project) { val section = kdoc.getDefaultSection() val tag = section.findTagByName("param") val link = tag?.getSubjectLink() ?: throw IllegalArgumentException("Cannot find subject link in doc comment '$kdocText'") - return link.getChildOfType()!! + return link.getChildOfType()!! } } diff --git a/idea/resources/messages/KotlinBundle.properties b/idea/resources/messages/KotlinBundle.properties index 6faf6ac8893..ae50f1ca041 100644 --- a/idea/resources/messages/KotlinBundle.properties +++ b/idea/resources/messages/KotlinBundle.properties @@ -373,7 +373,10 @@ kdoc.section.title.parameters=Params kdoc.section.title.returns=Returns kdoc.section.title.throws=Throws kdoc.section.title.author=Author +kdoc.section.title.properties=Properties +kdoc.section.title.constructor=Constructor kdoc.section.title.since=Since +kdoc.section.title.suppress=Suppress kdoc.section.title.samples=Samples kdoc.section.title.see.also=See Also kdoc.comment.unresolved=Unresolved diff --git a/idea/src/org/jetbrains/kotlin/idea/KotlinQuickDocumentationProvider.kt b/idea/src/org/jetbrains/kotlin/idea/KotlinQuickDocumentationProvider.kt index a26ab242919..62a621c792a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/KotlinQuickDocumentationProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/KotlinQuickDocumentationProvider.kt @@ -13,12 +13,7 @@ import com.intellij.lang.documentation.DocumentationMarkup.* import com.intellij.lang.java.JavaDocumentationProvider import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.editor.Editor -import com.intellij.openapi.project.DumbService -import com.intellij.openapi.project.IndexNotReadyException -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFile -import com.intellij.psi.PsiManager -import com.intellij.psi.PsiWhiteSpace +import com.intellij.psi.* import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration import org.jetbrains.kotlin.descriptors.* @@ -30,7 +25,7 @@ import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject import org.jetbrains.kotlin.idea.decompiler.navigation.SourceNavigationHelper import org.jetbrains.kotlin.idea.kdoc.* import org.jetbrains.kotlin.idea.kdoc.KDocRenderer.appendKDocContent -import org.jetbrains.kotlin.idea.kdoc.KDocRenderer.appendKDocSection +import org.jetbrains.kotlin.idea.kdoc.KDocRenderer.appendKDocSections import org.jetbrains.kotlin.idea.kdoc.KDocTemplate.DescriptionBodyTemplate import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.resolve.frontendService @@ -38,6 +33,7 @@ import org.jetbrains.kotlin.idea.util.isRunningInCidrIde import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.kdoc.psi.api.KDoc import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection +import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* @@ -120,11 +116,9 @@ class WrapValueParameterHandler(val base: DescriptorRenderer.ValueParametersHand } base.appendAfterValueParameters(parameterCount, builder) } - } - -class KotlinQuickDocumentationProvider : AbstractDocumentationProvider() { +open class KotlinQuickDocumentationProviderCompatBase : AbstractDocumentationProvider() { override fun getCustomDocumentationElement(editor: Editor, fil: PsiFile, contextElement: PsiElement?): PsiElement? { return if (contextElement.isModifier()) contextElement else null @@ -173,6 +167,17 @@ class KotlinQuickDocumentationProvider : AbstractDocumentationProvider() { boldOnlyForNamesInHtml = true } + fun StringBuilder.renderKDoc(contentTag: KDocTag, sections: List) { + insert(DescriptionBodyTemplate.Kotlin()) { + content { + appendKDocContent(contentTag) + } + sections { + appendKDocSections(sections) + } + } + } + private fun renderEnumSpecialFunction(element: KtClass, functionDescriptor: FunctionDescriptor, quickNavigation: Boolean): String { val kdoc = run { val declarationDescriptor = element.resolveToDescriptorIfAny() @@ -188,23 +193,14 @@ class KotlinQuickDocumentationProvider : AbstractDocumentationProvider() { } } - val section = kdoc?.getDefaultSection() - return buildString { insert(KDocTemplate()) { definition { renderDefinition(functionDescriptor, DESCRIPTOR_RENDERER) } - if (!quickNavigation && section != null) { + if (!quickNavigation && kdoc != null) { description { - insert(DescriptionBodyTemplate.Kotlin()) { - content { - appendKDocContent(section) - } - sections { - appendKDocSection(section) - } - } + renderKDoc(kdoc.getDefaultSection(), listOf(kdoc.getDefaultSection())) } } } @@ -255,7 +251,7 @@ class KotlinQuickDocumentationProvider : AbstractDocumentationProvider() { // element is not an KtReferenceExpression, but KtClass of enum return renderEnum(element, originalElement, quickNavigation) } else if (element is KtEnumEntry && !quickNavigation) { - val ordinal = element.containingClassOrObject?.getBody()?.run { getChildrenOfType().indexOf(element) } + val ordinal = element.containingClassOrObject?.body?.run { getChildrenOfType().indexOf(element) } return buildString { insert(buildKotlinDeclaration(element, quickNavigation)) { @@ -360,14 +356,8 @@ class KotlinQuickDocumentationProvider : AbstractDocumentationProvider() { description { val comment = declarationDescriptor.findKDoc { DescriptorToSourceUtilsIde.getAnyDeclaration(ktElement.project, it) } if (comment != null) { - insert(DescriptionBodyTemplate.Kotlin()) { - content { - appendKDocContent(comment) - } - sections { - if (comment is KDocSection) appendKDocSection(comment) - } - } + val sectionList = if (comment is KDocSection) listOf(comment) else emptyList() + renderKDoc(comment, sectionList) } else if (declarationDescriptor is CallableDescriptor) { // If we couldn't find KDoc, try to find javadoc in one of super's insert(DescriptionBodyTemplate.FromJava()) { body = extractJavaDescription(declarationDescriptor) diff --git a/idea/src/org/jetbrains/kotlin/idea/KotlinQuickDocumentationProviderCompat.kt b/idea/src/org/jetbrains/kotlin/idea/KotlinQuickDocumentationProviderCompat.kt new file mode 100644 index 00000000000..5bb7400991c --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/KotlinQuickDocumentationProviderCompat.kt @@ -0,0 +1,9 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea + +// BUNCH 201 +class KotlinQuickDocumentationProvider : KotlinQuickDocumentationProviderCompatBase() \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/KotlinQuickDocumentationProviderCompat.kt.201 b/idea/src/org/jetbrains/kotlin/idea/KotlinQuickDocumentationProviderCompat.kt.201 new file mode 100644 index 00000000000..0967fd9ca97 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/KotlinQuickDocumentationProviderCompat.kt.201 @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea + +import com.intellij.codeInsight.javadoc.JavaDocExternalFilter +import com.intellij.psi.PsiDocCommentBase +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtFile +import java.util.function.Consumer + +// BUNCH 201 +class KotlinQuickDocumentationProvider : KotlinQuickDocumentationProviderCompatBase() { + + override fun collectDocComments(file: PsiFile, sink: Consumer) { + if (file !is KtFile) return + + PsiTreeUtil.processElements(file) { + val comment = (it as? KtDeclaration)?.docComment + if (comment != null) sink.accept(comment) + true + } + } + + override fun generateRenderedDoc(element: PsiElement): String? { + val docComment = (element as? KtDeclaration)?.docComment ?: return null + + val result = StringBuilder().also { + it.renderKDoc(docComment.getDefaultSection(), docComment.getAllSections()) + } + + return JavaDocExternalFilter.filterInternalDocInfo(result.toString()) + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocRenderer.kt b/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocRenderer.kt index c16c4385516..ceb64ae13a4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocRenderer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocRenderer.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * 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. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.idea.kdoc @@ -37,44 +26,43 @@ import org.jetbrains.kotlin.psi.KtDeclarationWithBody import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType object KDocRenderer { - fun renderKDoc(docComment: KDocTag): String { - return if (docComment is KDocSection) { - renderKDocContent(docComment) + renderKDocSection(docComment) - } else { - renderKDocContent(docComment) - } - } - fun renderKDocContent(docComment: KDocTag): String { - return markdownToHtml(docComment.getContent(), allowSingleParagraph = true) - } + private fun renderKDocContent(docComment: KDocTag) = + markdownToHtml(docComment.getContent(), allowSingleParagraph = true) - fun StringBuilder.appendKDocContent(docComment: KDocTag) { + fun StringBuilder.appendKDocContent(docComment: KDocTag): StringBuilder = append(renderKDocContent(docComment)) - } + fun StringBuilder.appendKDocSections(sections: List) { + fun findTagsByName(name: String) = + sequence { sections.forEach { yieldAll(it.findTagsByName(name)) } } + .filterNotNull() - fun renderKDocSection(section: KDocSection): String = buildString { - appendKDocSection(section) - } + fun findTagByName(name: String) = findTagsByName(name).firstOrNull() - fun StringBuilder.appendKDocSection(section: KDocSection) { - renderTag(section.findTagByName("receiver"), KotlinBundle.message("kdoc.section.title.receiver"), this) - val paramTags = section.findTagsByName("param").filter { it.getSubjectName() != null } + renderTag(findTagByName("receiver"), KotlinBundle.message("kdoc.section.title.receiver"), this) + + val paramTags = findTagsByName("param").filter { it.getSubjectName() != null } renderTagList(paramTags, KotlinBundle.message("kdoc.section.title.parameters"), this) - renderTag(section.findTagByName("return"), KotlinBundle.message("kdoc.section.title.returns"), this) + val propertyTags = findTagsByName("property").filter { it.getSubjectName() != null } + renderTagList(propertyTags, KotlinBundle.message("kdoc.section.title.properties"), this) - val throwsTags = (section.findTagsByName("exception").union(section.findTagsByName("throws"))) - .filter { it.getSubjectName() != null } - renderTagList(throwsTags, KotlinBundle.message("kdoc.section.title.throws"), this) + renderTag(findTagByName("constructor"), KotlinBundle.message("kdoc.section.title.constructor"), this) - renderTag(section.findTagByName("author"), KotlinBundle.message("kdoc.section.title.author"), this) - renderTag(section.findTagByName("since"), KotlinBundle.message("kdoc.section.title.since"), this) + renderTag(findTagByName("return"), KotlinBundle.message("kdoc.section.title.returns"), this) - renderSeeAlso(section, this) + val throwTags = findTagsByName("throws").filter { it.getSubjectName() != null } + val exceptionTags = findTagsByName("exception").filter { it.getSubjectName() != null } + renderThrows(throwTags, exceptionTags, this) - val sampleTags = section.findTagsByName("sample").filter { it.getSubjectLink() != null } + renderTag(findTagByName("author"), KotlinBundle.message("kdoc.section.title.author"), this) + renderTag(findTagByName("since"), KotlinBundle.message("kdoc.section.title.since"), this) + renderTag(findTagByName("suppress"), KotlinBundle.message("kdoc.section.title.suppress"), this) + + renderSeeAlso(findTagsByName("see"), this) + + val sampleTags = findTagsByName("sample").filter { it.getSubjectLink() != null } renderSamplesList(sampleTags, this) } @@ -88,8 +76,7 @@ object KDocRenderer { private fun PsiElement.extractExampleText() = when (this) { is KtDeclarationWithBody -> { - val bodyExpression = bodyExpression - when (bodyExpression) { + when (val bodyExpression = bodyExpression) { is KtBlockExpression -> bodyExpression.text.removeSurrounding("{", "}") else -> bodyExpression!!.text } @@ -111,8 +98,8 @@ object KDocRenderer { append(SECTION_END) } - private fun renderSamplesList(sampleTags: List, to: StringBuilder) { - if (sampleTags.isEmpty()) return + private fun renderSamplesList(sampleTags: Sequence, to: StringBuilder) { + if (!sampleTags.any()) return to.renderSection(KotlinBundle.message("kdoc.section.title.samples")) { sampleTags.forEach { @@ -122,9 +109,9 @@ object KDocRenderer { val target = subjectLink.getTargetElement() wrapTag("pre") { wrapTag("code") { - if (target == null) + if (target == null) { to.append("// " + KotlinBundle.message("kdoc.comment.unresolved")) - else { + } else { to.append(trimCommonIndent(target.extractExampleText()).htmlEscape()) } } @@ -134,32 +121,57 @@ object KDocRenderer { } } - private fun renderSeeAlso(docComment: KDocSection, to: StringBuilder) { - val seeTags = docComment.findTagsByName("see") - if (seeTags.isEmpty()) return + private fun renderSeeAlso(seeTags: Sequence, to: StringBuilder) { + if (!seeTags.any()) return + + val iterator = seeTags.iterator() to.renderSection(KotlinBundle.message("kdoc.section.title.see.also")) { - seeTags.forEachIndexed { index, tag -> + while (iterator.hasNext()) { + val tag = iterator.next() val subjectName = tag.getSubjectName() if (subjectName != null) { DocumentationManagerUtil.createHyperlink(this, subjectName, subjectName, false) } else { append(tag.getContent()) } - if (index < seeTags.size - 1) { + if (iterator.hasNext()) { append(", ") } } } } - private fun renderTagList(tags: List, title: String, to: StringBuilder) { - if (tags.isEmpty()) { + private fun renderThrows(throwsTags: Sequence, exceptionsTags: Sequence, to: StringBuilder) { + if (!throwsTags.any() && !exceptionsTags.any()) return + + to.renderSection(KotlinBundle.message("kdoc.section.title.throws")) { + + fun KDocTag.append() { + val subjectName = getSubjectName() + if (subjectName != null) { + append("

") + DocumentationManagerUtil.createHyperlink(this@renderSection, subjectName, subjectName, false) + append(" - ${markdownToHtml(getContent().trimStart())}") + } + } + + throwsTags.forEach { it.append() } + exceptionsTags.forEach { it.append() } + } + } + + + private fun renderTagList(tags: Sequence, title: String, to: StringBuilder) { + if (!tags.any()) { return } to.renderSection(title) { tags.forEach { - append("

${it.getSubjectName()} - ${markdownToHtml(it.getContent().trimStart())}") + val subjectName = it.getSubjectName() + if (subjectName != null) { + append("

$subjectName - ${markdownToHtml(it.getContent().trimStart())}") + } } } } @@ -172,7 +184,7 @@ object KDocRenderer { } } - fun markdownToHtml(markdown: String, allowSingleParagraph: Boolean = false): String { + private fun markdownToHtml(markdown: String, allowSingleParagraph: Boolean = false): String { val markdownTree = MarkdownParser(CommonMarkFlavourDescriptor()).buildMarkdownTreeFromString(markdown) val markdownNode = MarkdownNode(markdownTree, null, markdown) diff --git a/idea/testData/codeInsight/renderingKDoc/classRendering.kt b/idea/testData/codeInsight/renderingKDoc/classRendering.kt new file mode 100644 index 00000000000..84162dd2d40 --- /dev/null +++ b/idea/testData/codeInsight/renderingKDoc/classRendering.kt @@ -0,0 +1,24 @@ + +/** + * Hello darling + * @author DarkWing Duck + */ +class testClass + +/** + * Hello darling outher + * @author Morgana Macawber + */ +class outherClass { + /** + * Hello darling inner + * @author Launchpad McQuack + */ + inner class innerClass { + + } +} + +// RENDER:

Hello darling

Author:

DarkWing Duck
+// RENDER:

Hello darling outher

Author:

Morgana Macawber
+// RENDER:

Hello darling inner

Author:

Launchpad McQuack
\ No newline at end of file diff --git a/idea/testData/codeInsight/renderingKDoc/difficultKDoc.kt b/idea/testData/codeInsight/renderingKDoc/difficultKDoc.kt new file mode 100644 index 00000000000..91670a8eba4 --- /dev/null +++ b/idea/testData/codeInsight/renderingKDoc/difficultKDoc.kt @@ -0,0 +1,57 @@ + +/** + * + * This class has no useful logic; it's just a documentation example. + * + * @param T the type of a member in this class. + * @param X the type of a member in this class. + * @property name is blablabla for name + * @property name2 is blublublu for name2 + * @constructor primary ctor for it + */ +class klass(val name: String, val name2: String) { + /** + * This method has no useful logic; it's just a documentation example. + * + * @param M the type of a member in this method. + * @param K the type of a member in this group. + * @property[name] is blablabla for name + * @property name2 blublublu for name2 + * @throws IndexOutOfBoundsException if something wrong + * @throws ArrayIndexOutOfBoundsException if else something wrong + * @exception java.io.IOException if something else else wrong + * @see method2 + * @see method3 + * @return [returnMethod] if Duck is Dark + * @author DarkWing Duck + * @suppress something to suppress + * @sample sample + * @sample sample2 + */ + fun method(name: String, name2: String) { + + } + + fun method2() { + + } + + fun method3() { + + } + + fun returnMethod() { + + } + + fun sample() { + //this is the sample + } + + fun sample2() { + //this is the sample2 + } +} + +//RENDER:

This class has no useful logic; it's just a documentation example.

Params:

T - the type of a member in this class.

X - the type of a member in this class.

Properties:

name - is blablabla for name

name2 - is blublublu for name2

Constructor:

primary ctor for it
+//RENDER:

This method has no useful logic; it's just a documentation example.

Params:

M - the type of a member in this method.

K - the type of a member in this group.

Properties:

name - is blablabla for name

name2 - blublublu for name2

Returns:

returnMethod if Duck is Dark

Throws:

IndexOutOfBoundsException - if something wrong

ArrayIndexOutOfBoundsException - if else something wrong

java.io.IOException - if something else else wrong

Author:

DarkWing Duck

Suppress:

something to suppress

See Also:

method2, method3

Samples:

sample

//this is the sample

sample2

//this is the sample2
\ No newline at end of file diff --git a/idea/testData/codeInsight/renderingKDoc/functionRendering.kt b/idea/testData/codeInsight/renderingKDoc/functionRendering.kt new file mode 100644 index 00000000000..c6e99515c72 --- /dev/null +++ b/idea/testData/codeInsight/renderingKDoc/functionRendering.kt @@ -0,0 +1,36 @@ + +/** + * Hello darling + * @author DarkWing Duck + */ +fun testFun() {} + +class outherClass { + /** + * Hello darling instance + * @author Morgana Macawber + */ + fun instanceFun() { + /** + * Hello darling local + * @author Launchpad McQuack + */ + fun localFun() { + if (true) { + /** + * Hello darling superLocal + * @author Reginald Bushroot + */ + fun superLocalFun() { + + } + } + + } + } +} + +// RENDER:

Hello darling

Author:

DarkWing Duck
+// RENDER:

Hello darling instance

Author:

Morgana Macawber
+// RENDER:

Hello darling local

Author:

Launchpad McQuack
+// RENDER:

Hello darling superLocal

Author:

Reginald Bushroot
\ No newline at end of file diff --git a/idea/testData/codeInsight/renderingKDoc/propertyRendering.kt b/idea/testData/codeInsight/renderingKDoc/propertyRendering.kt new file mode 100644 index 00000000000..e1fe0286821 --- /dev/null +++ b/idea/testData/codeInsight/renderingKDoc/propertyRendering.kt @@ -0,0 +1,41 @@ + +/** + * Hello darling + * @author DarkWing Duck + */ +val prop = 2 + +/** + * Hello darling var + * @author Megavolt + */ +var prop = 2 + + +class outherClass { + /** + * Hello darling instance + * @author Morgana Macawber + */ + val instanceProp get() { + /** + * Hello darling local + * @author Launchpad McQuack + */ + val localProp get() { + if (true) { + /** + * Hello darling superLocal + * @author Reginald Bushroot + */ + val superLocalProp = 4 + } + } + } +} + +// RENDER:

Hello darling

Author:

DarkWing Duck
+// RENDER:

Hello darling var

Author:

Megavolt
+// RENDER:

Hello darling instance

Author:

Morgana Macawber
+// RENDER:

Hello darling local

Author:

Launchpad McQuack
+// RENDER:

Hello darling superLocal

Author:

Reginald Bushroot
\ No newline at end of file diff --git a/idea/testData/editor/quickDoc/OnEnumValueOfFunction.kt b/idea/testData/editor/quickDoc/OnEnumValueOfFunction.kt index aaf0f58b762..4193976ce31 100644 --- a/idea/testData/editor/quickDoc/OnEnumValueOfFunction.kt +++ b/idea/testData/editor/quickDoc/OnEnumValueOfFunction.kt @@ -9,4 +9,4 @@ fun use() { //INFO:
E
public final fun valueOf( //INFO: value: String -//INFO: ): E

Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)

Throws:

IllegalArgumentException - if this enum type has no constant with the specified name

+//INFO: ): E

Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)

Throws:

IllegalArgumentException - if this enum type has no constant with the specified name

diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndThrows.kt b/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndThrows.kt index 41d0846cf7e..ad268ba8bae 100644 --- a/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndThrows.kt +++ b/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndThrows.kt @@ -17,4 +17,4 @@ fun test() { //INFO:
OnMethodUsageWithReturnAndThrows.kt
public fun testMethod( //INFO: a: Int, //INFO: b: String -//INFO: ): Unit

Some documentation

Params:

a - Some int

b - String

Returns:

Return value

Throws:

IllegalArgumentException - if the weather is bad

+//INFO: ): Unit

Some documentation

Params:

a - Some int

b - String

Returns:

Return value

Throws:

IllegalArgumentException - if the weather is bad

diff --git a/idea/testData/wordSelection/DocComment/4.kt b/idea/testData/wordSelection/DocComment/4.kt index c8344f7e538..835877107c0 100644 --- a/idea/testData/wordSelection/DocComment/4.kt +++ b/idea/testData/wordSelection/DocComment/4.kt @@ -3,7 +3,7 @@ package p /** * Doc comment here */ -fun foo() { +fun foo() { } - + fun bar(){} \ No newline at end of file diff --git a/idea/testData/wordSelection/DocComment/5.kt b/idea/testData/wordSelection/DocComment/5.kt deleted file mode 100644 index 835877107c0..00000000000 --- a/idea/testData/wordSelection/DocComment/5.kt +++ /dev/null @@ -1,9 +0,0 @@ -package p - -/** - * Doc comment here - */ -fun foo() { -} - -fun bar(){} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractRenderingKDocTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractRenderingKDocTest.kt new file mode 100644 index 00000000000..865bde9426d --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractRenderingKDocTest.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.codeInsight + +import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase + +//BUNCH 201 +abstract class AbstractRenderingKDocTest : KotlinLightCodeInsightFixtureTestCase() { + protected fun doTest(path: String) = Unit +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractRenderingKDocTest.kt.201 b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractRenderingKDocTest.kt.201 new file mode 100644 index 00000000000..82702c83864 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractRenderingKDocTest.kt.201 @@ -0,0 +1,36 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.codeInsight + +import com.intellij.testFramework.UsefulTestCase +import org.jetbrains.kotlin.idea.KotlinQuickDocumentationProvider +import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.kotlin.test.InTextDirectivesUtils + +//BUNCH 201 +abstract class AbstractRenderingKDocTest : KotlinLightCodeInsightFixtureTestCase() { + + override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE + + protected fun doTest(path: String) { + myFixture.configureByFile(fileName()) + val file = myFixture.file + + val kDocProvider = KotlinQuickDocumentationProvider() + + val comments = mutableListOf() + kDocProvider.collectDocComments(file) { + val rendered = it.owner?.let { owner -> kDocProvider.generateRenderedDoc(owner) } + if (rendered != null) { + comments.add(rendered.replace("\n", "")) + } + } + + val expectedRenders = InTextDirectivesUtils.findLinesWithPrefixesRemoved(file.text, "// RENDER: ") + UsefulTestCase.assertOrderedEquals(comments, expectedRenders) + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/RenderingKDocTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/RenderingKDocTestGenerated.java new file mode 100644 index 00000000000..8ed45cb9a10 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/RenderingKDocTestGenerated.java @@ -0,0 +1,50 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.codeInsight; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("idea/testData/codeInsight/renderingKDoc") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class RenderingKDocTestGenerated extends AbstractRenderingKDocTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInRenderingKDoc() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/codeInsight/renderingKDoc"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("classRendering.kt") + public void testClassRendering() throws Exception { + runTest("idea/testData/codeInsight/renderingKDoc/classRendering.kt"); + } + + @TestMetadata("difficultKDoc.kt") + public void testDifficultKDoc() throws Exception { + runTest("idea/testData/codeInsight/renderingKDoc/difficultKDoc.kt"); + } + + @TestMetadata("functionRendering.kt") + public void testFunctionRendering() throws Exception { + runTest("idea/testData/codeInsight/renderingKDoc/functionRendering.kt"); + } + + @TestMetadata("propertyRendering.kt") + public void testPropertyRendering() throws Exception { + runTest("idea/testData/codeInsight/renderingKDoc/propertyRendering.kt"); + } +}