diff --git a/idea/src/org/jetbrains/kotlin/idea/KotlinQuickDocumentationProvider.kt.173 b/idea/src/org/jetbrains/kotlin/idea/KotlinQuickDocumentationProvider.kt.173 new file mode 100644 index 00000000000..2d0f22d544c --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/KotlinQuickDocumentationProvider.kt.173 @@ -0,0 +1,366 @@ +/* + * Copyright 2010-2016 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. + */ + +package org.jetbrains.kotlin.idea + +import com.google.common.html.HtmlEscapers +import com.intellij.codeInsight.documentation.DocumentationManagerUtil +import com.intellij.codeInsight.javadoc.JavaDocInfoGeneratorFactory +import com.intellij.lang.documentation.AbstractDocumentationProvider +import com.intellij.lang.java.JavaDocumentationProvider +import com.intellij.openapi.diagnostic.Logger +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiWhiteSpace +import org.jetbrains.kotlin.asJava.LightClassUtil +import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny +import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde +import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject +import org.jetbrains.kotlin.idea.decompiler.navigation.SourceNavigationHelper +import org.jetbrains.kotlin.idea.kdoc.KDocRenderer +import org.jetbrains.kotlin.idea.kdoc.findKDoc +import org.jetbrains.kotlin.idea.kdoc.isBoringBuiltinClass +import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.idea.resolve.frontendService +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.psi.* +import org.jetbrains.kotlin.psi.psiUtil.* +import org.jetbrains.kotlin.renderer.ClassifierNamePolicy +import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DeprecationResolver +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.deprecatedByAnnotationReplaceWithExpression +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.utils.addToStdlib.constant + +class HtmlClassifierNamePolicy(val base: ClassifierNamePolicy) : ClassifierNamePolicy { + override fun renderClassifier(classifier: ClassifierDescriptor, renderer: DescriptorRenderer): String { + if (DescriptorUtils.isAnonymousObject(classifier)) { + + val supertypes = classifier.typeConstructor.supertypes + return buildString { + append("<anonymous object") + if (supertypes.isNotEmpty()) { + append(" : ") + supertypes.joinTo(this) { + val ref = it.constructor.declarationDescriptor + if (ref != null) + renderClassifier(ref, renderer) + else + "<ERROR CLASS>" + } + } + append(">") + } + } + + val name = base.renderClassifier(classifier, renderer) + if (classifier.isBoringBuiltinClass()) + return name + return buildString { + val ref = classifier.fqNameUnsafe.toString() + DocumentationManagerUtil.createHyperlink(this, ref, name, true) + } + } +} + +class KotlinQuickDocumentationProvider : AbstractDocumentationProvider() { + + override fun getQuickNavigateInfo(element: PsiElement?, originalElement: PsiElement?): String? { + return if (element == null) null else getText(element, originalElement, true) + } + + override fun generateDoc(element: PsiElement, originalElement: PsiElement?): String? { + return getText(element, originalElement, false) + } + + override fun getDocumentationElementForLink(psiManager: PsiManager, link: String, context: PsiElement?): PsiElement? { + val navElement = context?.navigationElement as? KtElement ?: return null + val bindingContext = navElement.analyze(BodyResolveMode.PARTIAL) + val contextDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, navElement] ?: return null + val descriptors = resolveKDocLink(bindingContext, navElement.getResolutionFacade(), + contextDescriptor, null, link.split('.')) + val target = descriptors.firstOrNull() ?: return null + return DescriptorToSourceUtilsIde.getAnyDeclaration(psiManager.project, target) + } + + override fun getDocumentationElementForLookupItem(psiManager: PsiManager, `object`: Any?, element: PsiElement?): PsiElement? { + if (`object` is DeclarationLookupObject) { + `object`.psiElement?.let { return it } + `object`.descriptor?.let { descriptor -> + return DescriptorToSourceUtilsIde.getAnyDeclaration(psiManager.project, descriptor) + } + } + return null + } + + companion object { + private val LOG = Logger.getInstance(KotlinQuickDocumentationProvider::class.java) + + private val DESCRIPTOR_RENDERER = DescriptorRenderer.HTML.withOptions { + classifierNamePolicy = HtmlClassifierNamePolicy(ClassifierNamePolicy.SHORT) + renderCompanionObjectName = true + } + + private fun renderEnumSpecialFunction(element: KtClass, functionDescriptor: FunctionDescriptor, quickNavigation: Boolean): String { + var renderedDecl = DESCRIPTOR_RENDERER.render(functionDescriptor) + + if (quickNavigation) return renderedDecl + + val declarationDescriptor = element.resolveToDescriptorIfAny() + val enumDescriptor = declarationDescriptor?.getSuperClassNotAny() ?: return renderedDecl + + val enumDeclaration = + DescriptorToSourceUtilsIde.getAnyDeclaration(element.project, enumDescriptor) as? KtDeclaration ?: return renderedDecl + + val enumSource = SourceNavigationHelper.getNavigationElement(enumDeclaration) + val functionName = functionDescriptor.fqNameSafe.shortName().asString() + val kdoc = enumSource.findDescendantOfType { + it.getChildrenOfType().any { it.findTagByName(functionName) != null } + } + + if (kdoc != null) { + val renderedComment = KDocRenderer.renderKDoc(kdoc.getDefaultSection()) + if (renderedComment.startsWith("

")) { + renderedDecl += renderedComment + } + else { + renderedDecl = "$renderedDecl
$renderedComment" + } + } + + return renderedDecl + } + + private fun renderEnum(element: KtClass, originalElement: PsiElement?, quickNavigation: Boolean): String? { + val referenceExpression = originalElement?.getNonStrictParentOfType() + if (referenceExpression != null) { + // When caret on special enum function (e.g SomeEnum.values()) + // element is not an KtReferenceExpression, but KtClass of enum + // so reference extracted from originalElement + val context = referenceExpression.analyze(BodyResolveMode.PARTIAL) + (context[BindingContext.REFERENCE_TARGET, referenceExpression] ?: + context[BindingContext.REFERENCE_TARGET, referenceExpression.getChildOfType()])?.let { + if (it is FunctionDescriptor) // To protect from SomeEnum.values() + return renderEnumSpecialFunction(element, it, quickNavigation) + } + } + return renderKotlinDeclaration(element, quickNavigation) + } + + private fun getText(element: PsiElement, originalElement: PsiElement?, quickNavigation: Boolean): String? { + if (element is PsiWhiteSpace) { + val itElement = findElementWithText(originalElement, "it") + val itReference = itElement?.getParentOfType(false) + if (itReference != null) { + return getText(itReference, originalElement, quickNavigation) + } + } + + if (element is KtTypeReference) { + val declaration = element.parent + if (declaration is KtCallableDeclaration && declaration.receiverTypeReference == element) { + val thisElement = findElementWithText(originalElement, "this") + if (thisElement != null) { + return getText(declaration, originalElement, quickNavigation) + } + } + } + + if (element is KtClass && element.isEnum()) { + // When caret on special enum function (e.g SomeEnum.values()) + // 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) } + + return buildString { + append(renderKotlinDeclaration(element, quickNavigation)) + ordinal?.let { + wrapTag("b") { + append("Enum constant ordinal: $ordinal") + } + } + } + } + else if (element is KtDeclaration) { + return renderKotlinDeclaration(element, quickNavigation) + } + else if (element is KtNameReferenceExpression && element.getReferencedName() == "it") { + return renderKotlinImplicitLambdaParameter(element, quickNavigation) + } + else if (element is KtLightDeclaration<*, *>) { + val origin = element.kotlinOrigin ?: return null + return renderKotlinDeclaration(origin, quickNavigation) + } + + if (quickNavigation) { + val referenceExpression = originalElement?.getNonStrictParentOfType() + if (referenceExpression != null) { + val context = referenceExpression.analyze(BodyResolveMode.PARTIAL) + val declarationDescriptor = context[BindingContext.REFERENCE_TARGET, referenceExpression] + if (declarationDescriptor != null) { + return mixKotlinToJava(declarationDescriptor, element, originalElement) + } + } + } + else { + // This element was resolved to non-kotlin element, it will be rendered with own provider + } + + return null + } + + private fun renderKotlinDeclaration(declaration: KtExpression, quickNavigation: Boolean): String { + val context = declaration.analyze(BodyResolveMode.PARTIAL) + val declarationDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration] + + if (declarationDescriptor == null) { + LOG.info("Failed to find descriptor for declaration " + declaration.getElementTextWithContext()) + return "No documentation available" + } + + return renderKotlin(context, declarationDescriptor, quickNavigation, declaration) + } + + private fun renderKotlinImplicitLambdaParameter(element: KtReferenceExpression, quickNavigation: Boolean): String? { + val context = element.analyze(BodyResolveMode.PARTIAL) + val target = element.mainReference.resolveToDescriptors(context).singleOrNull() as? ValueParameterDescriptor? ?: return null + return renderKotlin(context, target, quickNavigation, element) + } + + private fun renderKotlin( + context: BindingContext, + declarationDescriptor: DeclarationDescriptor, + quickNavigation: Boolean, + ktElement: KtElement + ): String { + @Suppress("NAME_SHADOWING") + var declarationDescriptor = declarationDescriptor + if (declarationDescriptor is ValueParameterDescriptor) { + val property = context[BindingContext.VALUE_PARAMETER_AS_PROPERTY, declarationDescriptor] + if (property != null) { + declarationDescriptor = property + } + } + + var renderedDecl = DESCRIPTOR_RENDERER.withOptions { + withDefinedIn = !DescriptorUtils.isLocal(declarationDescriptor) + }.render(declarationDescriptor) + + if (!quickNavigation) { + renderedDecl = "

$renderedDecl
" + } + + val deprecationProvider = ktElement.getResolutionFacade().frontendService() + renderedDecl += renderDeprecationInfo(declarationDescriptor, deprecationProvider) + + if (!quickNavigation) { + val comment = declarationDescriptor.findKDoc { DescriptorToSourceUtilsIde.getAnyDeclaration(ktElement.project, it) } + if (comment != null) { + val renderedComment = KDocRenderer.renderKDoc(comment) + if (renderedComment.startsWith("

")) { + renderedDecl += renderedComment + } + else { + renderedDecl = "$renderedDecl
$renderedComment" + } + } + else { + if (declarationDescriptor is CallableDescriptor) { // If we couldn't find KDoc, try to find javadoc in one of super's + val psi = declarationDescriptor.findPsi() as? KtFunction + if (psi != null) { + val lightElement = LightClassUtil.getLightClassMethod(psi) // Light method for super's scan in javadoc info gen + val javaDocInfoGenerator = JavaDocInfoGeneratorFactory.create(psi.project, lightElement) + val builder = StringBuilder() + if (javaDocInfoGenerator.generateDocInfoCore(builder, false)) + renderedDecl += builder.toString().substringAfter("") // Cut off light method signature + } + } + } + } + + return renderedDecl + } + + private fun renderDeprecationInfo( + declarationDescriptor: DeclarationDescriptor, + deprecationResolver: DeprecationResolver + ): String { + val deprecation = deprecationResolver.getDeprecations(declarationDescriptor).firstOrNull() ?: return "" + + return buildString { + wrapTag("DL") { + deprecation.message?.let { message -> + wrapTag("DT") { wrapTag("b") { append("Deprecated:") } } + wrapTag("DD") { + append(message.htmlEscape()) + } + } + deprecation.deprecatedByAnnotationReplaceWithExpression()?.let { replaceWith -> + wrapTag("DT") { wrapTag("b") { append("Replace with:") } } + wrapTag("DD") { + wrapTag("code") { append(replaceWith.htmlEscape()) } + } + } + } + } + } + + private fun String.htmlEscape(): String = HtmlEscapers.htmlEscaper().escape(this) + + private inline fun StringBuilder.wrap(prefix: String, postfix: String, crossinline body: () -> Unit) { + this.append(prefix) + body() + this.append(postfix) + } + + private inline fun StringBuilder.wrapTag(tag: String, crossinline body: () -> Unit) { + wrap("<$tag>", "", body) + } + + private fun mixKotlinToJava(declarationDescriptor: DeclarationDescriptor, element: PsiElement, originalElement: PsiElement?): String? { + val originalInfo = JavaDocumentationProvider().getQuickNavigateInfo(element, originalElement) + if (originalInfo != null) { + val renderedDecl = constant { DESCRIPTOR_RENDERER.withOptions { withDefinedIn = false } }.render(declarationDescriptor) + return renderedDecl + "
Java declaration:
" + originalInfo + } + + return null + } + + private fun findElementWithText(element: PsiElement?, text: String): PsiElement? { + return when { + element == null -> null + element.text == text -> element + element.prevLeaf()?.text == text -> element.prevLeaf() + else -> null + } + } + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocRenderer.kt.173 b/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocRenderer.kt.173 new file mode 100644 index 00000000000..8f91da47253 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocRenderer.kt.173 @@ -0,0 +1,323 @@ +/* + * 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. + */ + +package org.jetbrains.kotlin.idea.kdoc + +import com.intellij.codeInsight.documentation.DocumentationManagerUtil +import com.intellij.psi.PsiElement +import org.intellij.markdown.IElementType +import org.intellij.markdown.MarkdownElementTypes +import org.intellij.markdown.MarkdownTokenTypes +import org.intellij.markdown.ast.ASTNode +import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor +import org.intellij.markdown.parser.MarkdownParser +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.idea.util.wrapTag +import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink +import org.jetbrains.kotlin.kdoc.psi.impl.KDocName +import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection +import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag +import org.jetbrains.kotlin.psi.KtBlockExpression +import org.jetbrains.kotlin.psi.KtDeclarationWithBody +import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType + +object KDocRenderer { + fun renderKDoc(docComment: KDocTag): String { + val content = docComment.getContent() + val result = StringBuilder() + result.append(markdownToHtml(content, allowSingleParagraph = true)) + if (docComment is KDocSection) { + result.append("\n") + renderTag(docComment.findTagByName("receiver"), "Receiver", result) + val paramTags = docComment.findTagsByName("param").filter { it.getSubjectName() != null } + renderTagList(paramTags, "Parameters", result) + + renderTag(docComment.findTagByName("return"), "Returns", result) + + val throwsTags = (docComment.findTagsByName("exception").union(docComment.findTagsByName("throws"))) + .filter { it.getSubjectName() != null } + renderTagList(throwsTags, "Throws", result) + + renderTag(docComment.findTagByName("author"), "Author", result) + renderTag(docComment.findTagByName("since"), "Since", result) + + renderSeeAlso(docComment, result) + + val sampleTags = docComment.findTagsByName("sample").filter { it.getSubjectLink() != null } + renderSamplesList(sampleTags, result) + } + return result.toString() + } + + private fun KDocLink.createHyperlink(to: StringBuilder) { + DocumentationManagerUtil.createHyperlink(to, getLinkText(), getLinkText(), false) + } + + private fun KDocLink.getTargetElement(): PsiElement? { + return this.getChildrenOfType().last().mainReference.resolve() + } + + private fun PsiElement.extractExampleText() = when (this) { + is KtDeclarationWithBody -> { + val bodyExpression = bodyExpression + when (bodyExpression) { + is KtBlockExpression -> bodyExpression.text.removeSurrounding("{", "}") + else -> bodyExpression!!.text + } + } + else -> text + } + + private fun trimCommonIndent(text: String): String { + fun String.leadingIndent() = indexOfFirst { !it.isWhitespace() } + + val lines = text.split('\n') + val minIndent = lines.filter { it.trim().isNotEmpty() }.map(String::leadingIndent).min() ?: 0 + return lines.joinToString("\n") { it.drop(minIndent) } + } + + + private fun renderSamplesList(sampleTags: List, to: StringBuilder) { + if (sampleTags.isEmpty()) return + to.apply { + wrapTag("dl") { + append("

Samples:
") + sampleTags.forEach { + wrapTag("dd") { + it.getSubjectLink()?.let { subjectLink -> + subjectLink.createHyperlink(to) + val target = subjectLink.getTargetElement() + wrapTag("pre") { + wrapTag("code") { + if (target == null) + to.append("// Unresolved") + else { + to.append(trimCommonIndent(target.extractExampleText())) + } + } + } + } + } + } + } + } + } + + private fun renderSeeAlso(docComment: KDocSection, to: StringBuilder) { + val seeTags = docComment.findTagsByName("see") + if (seeTags.isEmpty()) return + to.append("
") + to.append("
").append("See Also:").append("") + to.append("
") + seeTags.forEachIndexed { index, tag -> + val subjectName = tag.getSubjectName() + if (subjectName != null) { + DocumentationManagerUtil.createHyperlink(to, subjectName, subjectName, false) + } + else { + to.append(tag.getContent()) + } + if (index < seeTags.size - 1) { + to.append(", ") + } + } + to.append("
") + } + + private fun renderTagList(tags: List, title: String, to: StringBuilder) { + if (tags.isEmpty()) { + return + } + to.append("
$title:
") + tags.forEach { + to.append("
${it.getSubjectName()} - ${markdownToHtml(it.getContent().trimStart())}
") + } + to.append("
\n") + } + + private fun renderTag(tag: KDocTag?, title: String, to: StringBuilder) { + if (tag != null) { + to.append("
$title:
") + to.append("
${markdownToHtml(tag.getContent())}
") + to.append("
\n") + } + } + + fun markdownToHtml(markdown: String, allowSingleParagraph: Boolean = false): String { + val markdownTree = MarkdownParser(CommonMarkFlavourDescriptor()).buildMarkdownTreeFromString(markdown) + val markdownNode = MarkdownNode(markdownTree, null, markdown) + + // Avoid wrapping the entire converted contents in a

tag if it's just a single paragraph + val maybeSingleParagraph = markdownNode.children.singleOrNull { it.type != MarkdownTokenTypes.EOL } + return if (maybeSingleParagraph != null && !allowSingleParagraph) { + maybeSingleParagraph.children.joinToString("") { + if (it.text == "\n") " " else it.toHtml() + } + } + else { + markdownNode.toHtml() + } + } + + class MarkdownNode(val node: ASTNode, val parent: MarkdownNode?, val markdown: String) { + val children: List = node.children.map { MarkdownNode(it, this, markdown) } + val endOffset: Int get() = node.endOffset + val startOffset: Int get() = node.startOffset + val type: IElementType get() = node.type + val text: String get() = markdown.substring(startOffset, endOffset) + fun child(type: IElementType): MarkdownNode? = children.firstOrNull { it.type == type } + } + + private fun MarkdownNode.visit(action: (MarkdownNode, () -> Unit) -> Unit) { + action(this) { + for (child in children) { + child.visit(action) + } + } + } + + private fun MarkdownNode.toHtml(): String { + if (node.type == MarkdownTokenTypes.WHITE_SPACE) { + return text // do not trim trailing whitespace + } + + val sb = StringBuilder() + visit { node, processChildren -> + fun wrapChildren(tag: String, newline: Boolean = false) { + sb.append("<$tag>") + processChildren() + sb.append("") + if (newline) sb.appendln() + } + + val nodeType = node.type + val nodeText = node.text + when (nodeType) { + MarkdownElementTypes.UNORDERED_LIST -> wrapChildren("ul", newline = true) + MarkdownElementTypes.ORDERED_LIST -> wrapChildren("ol", newline = true) + MarkdownElementTypes.LIST_ITEM -> wrapChildren("li") + MarkdownElementTypes.EMPH -> wrapChildren("em") + MarkdownElementTypes.STRONG -> wrapChildren("strong") + MarkdownElementTypes.ATX_1 -> wrapChildren("h1") + MarkdownElementTypes.ATX_2 -> wrapChildren("h2") + MarkdownElementTypes.ATX_3 -> wrapChildren("h3") + MarkdownElementTypes.ATX_4 -> wrapChildren("h4") + MarkdownElementTypes.ATX_5 -> wrapChildren("h5") + MarkdownElementTypes.ATX_6 -> wrapChildren("h6") + MarkdownElementTypes.BLOCK_QUOTE -> wrapChildren("blockquote") + MarkdownElementTypes.PARAGRAPH -> { + sb.trimEnd() + wrapChildren("p", newline = true) + } + MarkdownElementTypes.CODE_SPAN -> { + val startDelimiter = node.child(MarkdownTokenTypes.BACKTICK)?.text + if (startDelimiter != null) { + val text = node.text.substring(startDelimiter.length).removeSuffix(startDelimiter) + sb.append("").append(text.htmlEscape()).append("") + } + } + MarkdownElementTypes.CODE_BLOCK, + MarkdownElementTypes.CODE_FENCE -> { + sb.trimEnd() + sb.append("

")
+                    processChildren()
+                    sb.append("
") + } + MarkdownElementTypes.SHORT_REFERENCE_LINK, + MarkdownElementTypes.FULL_REFERENCE_LINK -> { + val linkLabelNode = node.child(MarkdownElementTypes.LINK_LABEL) + val linkLabelContent = linkLabelNode?.children + ?.dropWhile { it.type == MarkdownTokenTypes.LBRACKET } + ?.dropLastWhile { it.type == MarkdownTokenTypes.RBRACKET } + if (linkLabelContent != null) { + val label = linkLabelContent.joinToString(separator = "") { it.text } + val linkText = node.child(MarkdownElementTypes.LINK_TEXT)?.toHtml() ?: label + DocumentationManagerUtil.createHyperlink(sb, label, linkText, true) + } + else { + sb.append(node.text) + } + } + MarkdownElementTypes.INLINE_LINK -> { + val label = node.child(MarkdownElementTypes.LINK_TEXT)?.toHtml() + val destination = node.child(MarkdownElementTypes.LINK_DESTINATION)?.text + if (label != null && destination != null) { + sb.append("$label") + } + else { + sb.append(node.text) + } + } + MarkdownTokenTypes.TEXT, + MarkdownTokenTypes.WHITE_SPACE, + MarkdownTokenTypes.COLON, + MarkdownTokenTypes.SINGLE_QUOTE, + MarkdownTokenTypes.DOUBLE_QUOTE, + MarkdownTokenTypes.LPAREN, + MarkdownTokenTypes.RPAREN, + MarkdownTokenTypes.LBRACKET, + MarkdownTokenTypes.RBRACKET, + MarkdownTokenTypes.EXCLAMATION_MARK -> { + sb.append(nodeText) + } + MarkdownTokenTypes.CODE_LINE -> { + sb.append(nodeText.removePrefix(KDocTag.indentationWhiteSpaces).htmlEscape()) + } + MarkdownTokenTypes.CODE_FENCE_CONTENT -> { + sb.append(nodeText.htmlEscape()) + } + MarkdownTokenTypes.EOL -> { + val parentType = node.parent?.type + if (parentType == MarkdownElementTypes.CODE_BLOCK || parentType == MarkdownElementTypes.CODE_FENCE) { + sb.append("\n") + } + else { + sb.append(" ") + } + } + MarkdownTokenTypes.GT -> sb.append(">") + MarkdownTokenTypes.LT -> sb.append("<") + + MarkdownElementTypes.LINK_TEXT -> { + val childrenWithoutBrackets = node.children.drop(1).dropLast(1) + for (child in childrenWithoutBrackets) { + sb.append(child.toHtml()) + } + } + + MarkdownTokenTypes.EMPH -> { + val parentNodeType = node.parent?.type + if (parentNodeType != MarkdownElementTypes.EMPH && parentNodeType != MarkdownElementTypes.STRONG) { + sb.append(node.text) + } + } + + else -> { + processChildren() + } + } + } + return sb.toString().trimEnd() + } + + private fun StringBuilder.trimEnd() { + while (length > 0 && this[length - 1] == ' ') { + deleteCharAt(length - 1) + } + } + + private fun String.htmlEscape(): String = replace("&", "&").replace("<", "<").replace(">", ">") +} diff --git a/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocTemplate.kt.173 b/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocTemplate.kt.173 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/idea/testData/editor/quickDoc/AnonymousObjectLocalVariable.kt.173 b/idea/testData/editor/quickDoc/AnonymousObjectLocalVariable.kt.173 new file mode 100644 index 00000000000..886d34b5118 --- /dev/null +++ b/idea/testData/editor/quickDoc/AnonymousObjectLocalVariable.kt.173 @@ -0,0 +1,9 @@ +interface OurFace +open class OurClass + +fun context() { + val v = object : OurClass(), OurFace {} + v +} + +//INFO:
val v: <anonymous object : OurClass, OurFace>
diff --git a/idea/testData/editor/quickDoc/AtConstantWithUnderscore.kt.173 b/idea/testData/editor/quickDoc/AtConstantWithUnderscore.kt.173 new file mode 100644 index 00000000000..81ca171d352 --- /dev/null +++ b/idea/testData/editor/quickDoc/AtConstantWithUnderscore.kt.173 @@ -0,0 +1,12 @@ +class C { + /** Use [SOME_REFERENCED_VAL] to do something */ + fun foo() { + + } + + companion object { + val SOME_REFERENCED_VAL = 1 + } +} + +//INFO:
public final fun foo(): Unit defined in C

Use SOME_REFERENCED_VAL to do something

diff --git a/idea/testData/editor/quickDoc/AtFunctionParameter.kt.173 b/idea/testData/editor/quickDoc/AtFunctionParameter.kt.173 new file mode 100644 index 00000000000..2c63d9afe0a --- /dev/null +++ b/idea/testData/editor/quickDoc/AtFunctionParameter.kt.173 @@ -0,0 +1,3 @@ +fun some(f: (Int) -> String) : String? = null + +//INFO:
value-parameter f: (Int) → String
diff --git a/idea/testData/editor/quickDoc/AtImplicitLambdaParametEnd.kt.173 b/idea/testData/editor/quickDoc/AtImplicitLambdaParametEnd.kt.173 new file mode 100644 index 00000000000..a2116c0cda2 --- /dev/null +++ b/idea/testData/editor/quickDoc/AtImplicitLambdaParametEnd.kt.173 @@ -0,0 +1,7 @@ +fun foo() { + listOf(1).forEach { + println(it) + } +} + +//INFO:
value-parameter it: Int
diff --git a/idea/testData/editor/quickDoc/AtImplicitLambdaParameter.kt.173 b/idea/testData/editor/quickDoc/AtImplicitLambdaParameter.kt.173 new file mode 100644 index 00000000000..9e988b29111 --- /dev/null +++ b/idea/testData/editor/quickDoc/AtImplicitLambdaParameter.kt.173 @@ -0,0 +1,7 @@ +fun foo() { + listOf(1).forEach { + println(it) + } +} + +//INFO:
value-parameter it: Int
diff --git a/idea/testData/editor/quickDoc/AtLocalFunction.kt.173 b/idea/testData/editor/quickDoc/AtLocalFunction.kt.173 new file mode 100644 index 00000000000..63bb7dce809 --- /dev/null +++ b/idea/testData/editor/quickDoc/AtLocalFunction.kt.173 @@ -0,0 +1,9 @@ +fun context() { + fun local() { + + } + + local() +} + +//INFO:
local final fun local(): Unit
diff --git a/idea/testData/editor/quickDoc/AtTypeParameter.kt.173 b/idea/testData/editor/quickDoc/AtTypeParameter.kt.173 new file mode 100644 index 00000000000..bb239791a0b --- /dev/null +++ b/idea/testData/editor/quickDoc/AtTypeParameter.kt.173 @@ -0,0 +1,5 @@ +interface Base + +class Some<T: Base> + +//INFO:
<T : Base> defined in Some
diff --git a/idea/testData/editor/quickDoc/AtVariableDeclaration.kt.173 b/idea/testData/editor/quickDoc/AtVariableDeclaration.kt.173 new file mode 100644 index 00000000000..61e7d6aae90 --- /dev/null +++ b/idea/testData/editor/quickDoc/AtVariableDeclaration.kt.173 @@ -0,0 +1,8 @@ +fun some() : String? = null + +fun test() { + val test = some() +} + + +//INFO:
val test: String?
diff --git a/idea/testData/editor/quickDoc/ConstructorVarParameter.kt.173 b/idea/testData/editor/quickDoc/ConstructorVarParameter.kt.173 new file mode 100644 index 00000000000..e0550f31bc9 --- /dev/null +++ b/idea/testData/editor/quickDoc/ConstructorVarParameter.kt.173 @@ -0,0 +1,7 @@ +class C(var v: Int) { + fun foo() { + print(v) + } +} + +//INFO:
public final var v: Int defined in C
diff --git a/idea/testData/editor/quickDoc/EscapeHtmlInsideCodeBlocks.kt.173 b/idea/testData/editor/quickDoc/EscapeHtmlInsideCodeBlocks.kt.173 new file mode 100644 index 00000000000..4a2c308b672 --- /dev/null +++ b/idea/testData/editor/quickDoc/EscapeHtmlInsideCodeBlocks.kt.173 @@ -0,0 +1,14 @@ +/** + * Code block: + * ``` kotlin + * A + * ``` + * Code span: + * `` is type parameter + */ +class A + +//INFO:
public final class A<T> defined in root package in file EscapeHtmlInsideCodeBlocks.kt

Code block:

+//INFO:

+//INFO: A<T>
+//INFO: 

Code span: <T> is type parameter

diff --git a/idea/testData/editor/quickDoc/ExtensionReceiver.kt.173 b/idea/testData/editor/quickDoc/ExtensionReceiver.kt.173 new file mode 100644 index 00000000000..b48eb25c8f6 --- /dev/null +++ b/idea/testData/editor/quickDoc/ExtensionReceiver.kt.173 @@ -0,0 +1,10 @@ + +interface Foo + +fun foo(a: Any) {} + +fun Foo.bar() { + foo(this) +} + +//INFO:
public fun Foo.bar(): Unit defined in root package in file ExtensionReceiver.kt
diff --git a/idea/testData/editor/quickDoc/ExtensionReceiverEnd.kt.173 b/idea/testData/editor/quickDoc/ExtensionReceiverEnd.kt.173 new file mode 100644 index 00000000000..d3e5b5e5d0e --- /dev/null +++ b/idea/testData/editor/quickDoc/ExtensionReceiverEnd.kt.173 @@ -0,0 +1,10 @@ + +interface Foo + +fun foo(a: Any) {} + +fun Foo.bar() { + foo(this) +} + +//INFO:
public fun Foo.bar(): Unit defined in root package in file ExtensionReceiverEnd.kt
diff --git a/idea/testData/editor/quickDoc/IndentedCodeBlock.kt.173 b/idea/testData/editor/quickDoc/IndentedCodeBlock.kt.173 new file mode 100644 index 00000000000..c854f80022f --- /dev/null +++ b/idea/testData/editor/quickDoc/IndentedCodeBlock.kt.173 @@ -0,0 +1,22 @@ +/** + * val a = A() + * println(a) // comment + * ``` + * Code_block + * ``` + * val b = B() + * println(b) + * some text content + * + * Indented code block with tab + * Second line + */ +class A + +//INFO:
public final class A defined in root package in file IndentedCodeBlock.kt

val a = A()
+//INFO: println(a) // comment

+//INFO: <fenced>Code_block</fenced>
+//INFO: 
val b = B()
+//INFO: println(b)

some text content

+//INFO:
Indented code block with tab
+//INFO: 	Second line
diff --git a/idea/testData/editor/quickDoc/JavaClassUsedInKotlin.kt.173 b/idea/testData/editor/quickDoc/JavaClassUsedInKotlin.kt.173 new file mode 100644 index 00000000000..f905d3ee993 --- /dev/null +++ b/idea/testData/editor/quickDoc/JavaClassUsedInKotlin.kt.173 @@ -0,0 +1,8 @@ +fun testing() { + SomeClass>() +} + +//INFO:
public class SomeClass<T extends List>
+//INFO: extends Object
+//INFO: Some Java Class +//INFO:
Type parameters:
<T> -
diff --git a/idea/testData/editor/quickDoc/JavaDocFromOverridenClass.kt.173 b/idea/testData/editor/quickDoc/JavaDocFromOverridenClass.kt.173 new file mode 100644 index 00000000000..6d54330807d --- /dev/null +++ b/idea/testData/editor/quickDoc/JavaDocFromOverridenClass.kt.173 @@ -0,0 +1,9 @@ +class A : OverrideMe() { + override fun overrideMe() { + } +} + + +//INFO:
protected open fun overrideMe(): Unit defined in A
Description copied from class: OverrideMe
+//INFO: Some comment +//INFO:
Overrides:
overrideMe in class OverrideMe
diff --git a/idea/testData/editor/quickDoc/JavaDocFromOverridenInterface.kt.173 b/idea/testData/editor/quickDoc/JavaDocFromOverridenInterface.kt.173 new file mode 100644 index 00000000000..3581f116c53 --- /dev/null +++ b/idea/testData/editor/quickDoc/JavaDocFromOverridenInterface.kt.173 @@ -0,0 +1,9 @@ +class A : OverrideMe { + override fun overrideMe() { + } +} + + +//INFO:
public open fun overrideMe(): Unit defined in A
Description copied from interface: OverrideMe
+//INFO: Some comment +//INFO:
Specified by:
overrideMe in interface OverrideMe
diff --git a/idea/testData/editor/quickDoc/JavaMethodUsedInKotlin.kt.173 b/idea/testData/editor/quickDoc/JavaMethodUsedInKotlin.kt.173 new file mode 100644 index 00000000000..4d95c59736e --- /dev/null +++ b/idea/testData/editor/quickDoc/JavaMethodUsedInKotlin.kt.173 @@ -0,0 +1,13 @@ +fun ktTest() { + Test.foo("SomeTest") +} + +//INFO: Test
@Contract(pure = true) 
+//INFO: @NotNull 
+//INFO: public static Object[] foo(String param)
+//INFO: Java Method +//INFO: +//INFO: Inferred annotations available:
+//INFO: diff --git a/idea/testData/editor/quickDoc/KotlinClassUsedFromJava.java.173 b/idea/testData/editor/quickDoc/KotlinClassUsedFromJava.java.173 new file mode 100644 index 00000000000..cf31cfc0c75 --- /dev/null +++ b/idea/testData/editor/quickDoc/KotlinClassUsedFromJava.java.173 @@ -0,0 +1,9 @@ +import testing.Test; + +class KotlinClassUsedFromJava { + void test() { + Test(); + } +} + +//INFO:
public final class Test defined in testing in file KotlinClassUsedFromJava_Data.kt

Some comment

diff --git a/idea/testData/editor/quickDoc/KotlinPackageClassUsedFromJava.java.173 b/idea/testData/editor/quickDoc/KotlinPackageClassUsedFromJava.java.173 new file mode 100644 index 00000000000..1471e1049a4 --- /dev/null +++ b/idea/testData/editor/quickDoc/KotlinPackageClassUsedFromJava.java.173 @@ -0,0 +1,10 @@ +import testing.KotlinPackageClassUsedFromJava_DataKt; + +class KotlinPackageClassUsedFromJava { + void test() { + KotlinPackageClassUsedFromJava_DataKt.foo(); + } +} + +//INFO: testing
public final class testing.KotlinPackageClassUsedFromJava_DataKt
+//INFO: extends Object
diff --git a/idea/testData/editor/quickDoc/MethodFromStdLib.kt.173 b/idea/testData/editor/quickDoc/MethodFromStdLib.kt.173 new file mode 100644 index 00000000000..132a734ce0d --- /dev/null +++ b/idea/testData/editor/quickDoc/MethodFromStdLib.kt.173 @@ -0,0 +1,5 @@ +fun test() { + listOf(1, 2, 4).filter { it > 0 } +} + +//INFO:
public inline fun <T> Iterable<T>.filter(predicate: (T) → Boolean): List<T> defined in kotlin.collections in file CollectionsKt.class

Returns a list containing only elements matching the given predicate.

diff --git a/idea/testData/editor/quickDoc/OnClassDeclarationWithNoPackage.kt.173 b/idea/testData/editor/quickDoc/OnClassDeclarationWithNoPackage.kt.173 new file mode 100644 index 00000000000..a2dd4bad33f --- /dev/null +++ b/idea/testData/editor/quickDoc/OnClassDeclarationWithNoPackage.kt.173 @@ -0,0 +1,6 @@ +/** + * Usefull comment + */ +class Some + +//INFO:
public final class Some defined in root package in file OnClassDeclarationWithNoPackage.kt

Usefull comment

diff --git a/idea/testData/editor/quickDoc/OnEnumClassReference.kt.173 b/idea/testData/editor/quickDoc/OnEnumClassReference.kt.173 new file mode 100644 index 00000000000..dfb14429e45 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnEnumClassReference.kt.173 @@ -0,0 +1,10 @@ +/** + * Useless one + */ +enum class SomeEnum + +fun use() { + SomeEnum::class +} + +//INFO:
public final enum class SomeEnum : Enum<SomeEnum> defined in root package in file OnEnumClassReference.kt

Useless one

diff --git a/idea/testData/editor/quickDoc/OnEnumDeclaration.kt.173 b/idea/testData/editor/quickDoc/OnEnumDeclaration.kt.173 new file mode 100644 index 00000000000..fa04d7a560a --- /dev/null +++ b/idea/testData/editor/quickDoc/OnEnumDeclaration.kt.173 @@ -0,0 +1,6 @@ +/** + * Useless one + */ +enum class SomeEnum + +//INFO:
public final enum class SomeEnum : Enum<SomeEnum> defined in root package in file OnEnumDeclaration.kt

Useless one

diff --git a/idea/testData/editor/quickDoc/OnEnumEntry.kt.173 b/idea/testData/editor/quickDoc/OnEnumEntry.kt.173 new file mode 100644 index 00000000000..bfd7d3bd39b --- /dev/null +++ b/idea/testData/editor/quickDoc/OnEnumEntry.kt.173 @@ -0,0 +1,7 @@ +enum class TestEnum{ + A, B, C +} + + + +//INFO:
enum entry C defined in TestEnum
Enum constant ordinal: 2 diff --git a/idea/testData/editor/quickDoc/OnEnumEntryUsage.kt.173 b/idea/testData/editor/quickDoc/OnEnumEntryUsage.kt.173 new file mode 100644 index 00000000000..0c1419055c7 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnEnumEntryUsage.kt.173 @@ -0,0 +1,9 @@ +enum class TestEnum{ + A, B, C +} + +fun test() { + TestEnum.C +} + +//INFO:
enum entry C defined in TestEnum
Enum constant ordinal: 2 diff --git a/idea/testData/editor/quickDoc/OnEnumUsage.kt.173 b/idea/testData/editor/quickDoc/OnEnumUsage.kt.173 new file mode 100644 index 00000000000..117618fc88f --- /dev/null +++ b/idea/testData/editor/quickDoc/OnEnumUsage.kt.173 @@ -0,0 +1,12 @@ +/** + * Enum of 1, 2 + */ +enum class SomeEnum(val i: Int) { + One(1), Two(2); +} + +fun use() { + SomeEnum.One +} + +//INFO:
public final enum class SomeEnum : Enum<SomeEnum> defined in root package in file OnEnumUsage.kt

Enum of 1, 2

diff --git a/idea/testData/editor/quickDoc/OnEnumValueOfFunction.kt.173 b/idea/testData/editor/quickDoc/OnEnumValueOfFunction.kt.173 new file mode 100644 index 00000000000..cf38cac14f0 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnEnumValueOfFunction.kt.173 @@ -0,0 +1,11 @@ +enum class E { + A +} + +fun use() { + E.valueOf("A") +} + + +//INFO: public final fun valueOf(value: String): E defined in 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.)

+//INFO:
Throws:
IllegalArgumentException - if this enum type has no constant with the specified name
diff --git a/idea/testData/editor/quickDoc/OnEnumValuesFunction.kt.173 b/idea/testData/editor/quickDoc/OnEnumValuesFunction.kt.173 new file mode 100644 index 00000000000..ed70854ab83 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnEnumValuesFunction.kt.173 @@ -0,0 +1,9 @@ +enum class E { + +} + +fun use() { + E.values() +} + +//INFO: public final fun values(): Array<E> defined in E

Returns an array containing the constants of this enum type, in the order they're declared. This method may be used to iterate over the constants.

diff --git a/idea/testData/editor/quickDoc/OnFunctionDeclarationWithPackage.kt.173 b/idea/testData/editor/quickDoc/OnFunctionDeclarationWithPackage.kt.173 new file mode 100644 index 00000000000..b5695d06cf8 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnFunctionDeclarationWithPackage.kt.173 @@ -0,0 +1,16 @@ +package test + +/** + + * + * + * Test function + + * + * @param first Some + * @param second Other + */ +fun testFun(first: String, second: Int) = 12 + +//INFO:
public fun testFun(first: String, second: Int): Int defined in test in file OnFunctionDeclarationWithPackage.kt

Test function

+//INFO:
Parameters:
first - Some
second - Other
diff --git a/idea/testData/editor/quickDoc/OnInheritedMethodUsage.kt.173 b/idea/testData/editor/quickDoc/OnInheritedMethodUsage.kt.173 new file mode 100644 index 00000000000..ceb71bce1fa --- /dev/null +++ b/idea/testData/editor/quickDoc/OnInheritedMethodUsage.kt.173 @@ -0,0 +1,17 @@ +open class C() { + /** + * This method returns zero. + */ + open fun foo(): Int = 0 +} + +class D(): C() { + override fun foo(): Int = 1 +} + + +fun test() { + D().foo() +} + +//INFO:
public open fun foo(): Int defined in D

This method returns zero.

diff --git a/idea/testData/editor/quickDoc/OnInheritedPropertyUsage.kt.173 b/idea/testData/editor/quickDoc/OnInheritedPropertyUsage.kt.173 new file mode 100644 index 00000000000..ab9c857aa27 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnInheritedPropertyUsage.kt.173 @@ -0,0 +1,17 @@ +open class C() { + /** + * This property returns zero. + */ + open val foo: Int get() = 0 +} + +class D(): C() { + override val foo: Int get() = 1 +} + + +fun test() { + D().foo +} + +//INFO:
public open val foo: Int defined in D

This property returns zero.

diff --git a/idea/testData/editor/quickDoc/OnMethodUsage.kt.173 b/idea/testData/editor/quickDoc/OnMethodUsage.kt.173 new file mode 100644 index 00000000000..d7dd575d3a8 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnMethodUsage.kt.173 @@ -0,0 +1,16 @@ +/** +Some documentation + + * @param a Some int + * @param b String + */ +fun testMethod(a: Int, b: String) { + +} + +fun test() { + testMethod(1, "value") +} + +//INFO:
public fun testMethod(a: Int, b: String): Unit defined in root package in file OnMethodUsage.kt

Some documentation

+//INFO:
Parameters:
a - Some int
b - String
diff --git a/idea/testData/editor/quickDoc/OnMethodUsageMultiline.kt.173 b/idea/testData/editor/quickDoc/OnMethodUsageMultiline.kt.173 new file mode 100644 index 00000000000..38bac449780 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnMethodUsageMultiline.kt.173 @@ -0,0 +1,13 @@ +/** + * Some documentation + * on two lines. + */ +fun testMethod() { + +} + +fun test() { + testMethod() +} + +//INFO:
public fun testMethod(): Unit defined in root package in file OnMethodUsageMultiline.kt

Some documentation on two lines.

diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithBracketsInParam.kt.173 b/idea/testData/editor/quickDoc/OnMethodUsageWithBracketsInParam.kt.173 new file mode 100644 index 00000000000..f2ed28dcccf --- /dev/null +++ b/idea/testData/editor/quickDoc/OnMethodUsageWithBracketsInParam.kt.173 @@ -0,0 +1,16 @@ +/** +Some documentation + + * @param[a] Some int + * @param[b] String + */ +fun testMethod(a: Int, b: String) { + +} + +fun test() { + testMethod(1, "value") +} + +//INFO:
public fun testMethod(a: Int, b: String): Unit defined in root package in file OnMethodUsageWithBracketsInParam.kt

Some documentation

+//INFO:
Parameters:
a - Some int
b - String
diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithCodeBlock.kt.173 b/idea/testData/editor/quickDoc/OnMethodUsageWithCodeBlock.kt.173 new file mode 100644 index 00000000000..a1b336ec2e9 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnMethodUsageWithCodeBlock.kt.173 @@ -0,0 +1,35 @@ +/** + * Some documentation. + * + * ``` + * Code block + * Second line + * + * Third line + * ``` + * + * Text between code blocks. + * ``` + * ``` + * Text after code block. + */ +fun testMethod() { + +} + +class C { +} + +fun test() { + testMethod(1, "value") +} + +//INFO:
public fun testMethod(): Unit defined in root package in file OnMethodUsageWithCodeBlock.kt

Some documentation.

+//INFO:

+//INFO: Code block
+//INFO:     Second line
+//INFO:
+//INFO: Third line
+//INFO: 

Text between code blocks.

+//INFO:

+//INFO: 

Text after code block.

diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithMarkdown.kt.173 b/idea/testData/editor/quickDoc/OnMethodUsageWithMarkdown.kt.173 new file mode 100644 index 00000000000..654a5126fdc --- /dev/null +++ b/idea/testData/editor/quickDoc/OnMethodUsageWithMarkdown.kt.173 @@ -0,0 +1,36 @@ +/** + * Some documentation. **Bold** *underline* `code` foo: bar (baz) [quux] 'apos' + * + * [Kotlin](http://www.kotlinlang.org) + * [a**b**__d__ kas ](http://www.ibm.com) + * + * [C] + * + * [See **this** class][C] + * + * This is _emphasized text_ but text_with_underscores has to preserve the underscores. + * Single stars embedded in a word like Embedded*Star have to be preserved as well. + * + * Exclamation marks are also important! Also in `code blocks!` + * + * bt+ : ``prefix ` postfix`` + * backslash: `\` + */ +fun testMethod() { + +} + +class C { +} + +fun test() { + testMethod(1, "value") +} + +//INFO:
public fun testMethod(): Unit defined in root package in file OnMethodUsageWithMarkdown.kt

Some documentation. Bold underline code foo: bar (baz) quux 'apos'

+//INFO:

Kotlin abd kas

+//INFO:

C

+//INFO:

See this class

+//INFO:

This is emphasized text but text_with_underscores has to preserve the underscores. Single stars embedded in a word like Embedded*Star have to be preserved as well.

+//INFO:

Exclamation marks are also important! Also in code blocks!

+//INFO:

bt+ : prefix ` postfix backslash: \

diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithMultilineParam.kt.173 b/idea/testData/editor/quickDoc/OnMethodUsageWithMultilineParam.kt.173 new file mode 100644 index 00000000000..ff2fb1dd5c5 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnMethodUsageWithMultilineParam.kt.173 @@ -0,0 +1,16 @@ +/** + * Some documentation + * on two lines. + * + * @param test String + * on two lines + */ +fun testMethod(test: String) { +} + +fun test() { + testMethod("") +} + +//INFO:
public fun testMethod(test: String): Unit defined in root package in file OnMethodUsageWithMultilineParam.kt

Some documentation on two lines.

+//INFO:
Parameters:
test - String on two lines
\ No newline at end of file diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithReceiver.kt.173 b/idea/testData/editor/quickDoc/OnMethodUsageWithReceiver.kt.173 new file mode 100644 index 00000000000..104f1be6ad4 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnMethodUsageWithReceiver.kt.173 @@ -0,0 +1,19 @@ +/** +Some documentation + + * @receiver Some int + * @param b String + * @return Return [a] and nothing else + */ +fun Int.testMethod(b: String) { + +} + +fun test() { + 1.testMethod("value") +} + +//INFO:
public fun Int.testMethod(b: String): Unit defined in root package in file OnMethodUsageWithReceiver.kt

Some documentation

+//INFO:
Receiver:
Some int
+//INFO:
Parameters:
b - String
+//INFO:
Returns:
Return a and nothing else
diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndLink.kt.173 b/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndLink.kt.173 new file mode 100644 index 00000000000..ee1b9160c38 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndLink.kt.173 @@ -0,0 +1,18 @@ +/** +Some documentation + + * @param a Some int + * @param b String + * @return Return [a] and nothing else + */ +fun testMethod(a: Int, b: String) { + +} + +fun test() { + testMethod(1, "value") +} + +//INFO:
public fun testMethod(a: Int, b: String): Unit defined in root package in file OnMethodUsageWithReturnAndLink.kt

Some documentation

+//INFO:
Parameters:
a - Some int
b - String
+//INFO:
Returns:
Return a and nothing else
diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndThrows.kt.173 b/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndThrows.kt.173 new file mode 100644 index 00000000000..e868dfa30c3 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndThrows.kt.173 @@ -0,0 +1,20 @@ +/** +Some documentation + + * @param a Some int + * @param b String + * @return Return value + * @throws IllegalArgumentException if the weather is bad + */ +fun testMethod(a: Int, b: String) { + +} + +fun test() { + testMethod(1, "value") +} + +//INFO:
public fun testMethod(a: Int, b: String): Unit defined in root package in file OnMethodUsageWithReturnAndThrows.kt

Some documentation

+//INFO:
Parameters:
a - Some int
b - String
+//INFO:
Returns:
Return value
+//INFO:
Throws:
IllegalArgumentException - if the weather is bad
diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithSee.kt.173 b/idea/testData/editor/quickDoc/OnMethodUsageWithSee.kt.173 new file mode 100644 index 00000000000..65956d8f011 --- /dev/null +++ b/idea/testData/editor/quickDoc/OnMethodUsageWithSee.kt.173 @@ -0,0 +1,21 @@ +/** + * @see C + * @see D + * @see kotlin + */ +fun testMethod() { + +} + +class C { +} + +class D { +} + +fun test() { + testMethod(1, "value") +} + +//INFO:
public fun testMethod(): Unit defined in root package in file OnMethodUsageWithSee.kt

+//INFO:
See Also:
C, D, kotlin
diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithTypeParameter.kt.173 b/idea/testData/editor/quickDoc/OnMethodUsageWithTypeParameter.kt.173 new file mode 100644 index 00000000000..eab08dbc61f --- /dev/null +++ b/idea/testData/editor/quickDoc/OnMethodUsageWithTypeParameter.kt.173 @@ -0,0 +1,17 @@ +/** +Some documentation + + * @param T the type parameter + * @param a Some int + * @param b String + */ +fun testMethod(a: Int, b: String) { + +} + +fun test() { + testMethod(1, "value") +} + +//INFO:
public fun <T> testMethod(a: Int, b: String): Unit defined in root package in file OnMethodUsageWithTypeParameter.kt

Some documentation

+//INFO:
Parameters:
T - the type parameter
a - Some int
b - String
diff --git a/idea/testData/editor/quickDoc/Samples.kt.173 b/idea/testData/editor/quickDoc/Samples.kt.173 new file mode 100644 index 00000000000..d285fdc3487 --- /dev/null +++ b/idea/testData/editor/quickDoc/Samples.kt.173 @@ -0,0 +1,28 @@ +package magic + +object Samples { + fun sampleMagic() { + castTextSpell("[asd] [dse] [asz]") + } +} + +fun sampleScroll() { + val reader = Scroll("[asd] [dse] [asz]").reader() + castTextSpell(reader.readAll()) +} + +/** + * @sample Samples.sampleMagic + * @sample sampleScroll + */ +fun castTextSpell(spell: String) { + throw SecurityException("Magic prohibited outside Hogwarts") +} + +//INFO:
public fun castTextSpell(spell: String): Unit defined in magic in file Samples.kt

+//INFO:
Samples:
Samples.sampleMagic

+//INFO: castTextSpell("[asd] [dse] [asz]")
+//INFO: 
sampleScroll

+//INFO: val reader = Scroll("[asd] [dse] [asz]").reader()
+//INFO: castTextSpell(reader.readAll())
+//INFO: 
diff --git a/idea/testData/editor/quickDoc/TopLevelMethodFromJava.java.173 b/idea/testData/editor/quickDoc/TopLevelMethodFromJava.java.173 new file mode 100644 index 00000000000..7e8e13aa306 --- /dev/null +++ b/idea/testData/editor/quickDoc/TopLevelMethodFromJava.java.173 @@ -0,0 +1,11 @@ +package server + +import some.TopLevelMethodFromJava_DataKt + +class Testing { + void test() { + TopLevelMethodFromJava_DataKt.foo(12); + } +} + +//INFO:
public fun foo(bar: Int): Unit defined in some in file TopLevelMethodFromJava_Data.kt

KDoc foo

diff --git a/idea/testData/editor/quickDoc/TypeNamesFromStdLibNavigation.kt.173 b/idea/testData/editor/quickDoc/TypeNamesFromStdLibNavigation.kt.173 new file mode 100644 index 00000000000..37a73ee27b1 --- /dev/null +++ b/idea/testData/editor/quickDoc/TypeNamesFromStdLibNavigation.kt.173 @@ -0,0 +1,11 @@ +class A { + +} + +fun foo(x : A) { } + +fun main(args: Array) { + foo() +} + +//INFO:
public fun foo(x: A): Unit defined in root package in file TypeNamesFromStdLibNavigation.kt