diff --git a/.idea/artifacts/KotlinPlugin.xml b/.idea/artifacts/KotlinPlugin.xml
index 3d1bf9b325a..719f52019c5 100644
--- a/.idea/artifacts/KotlinPlugin.xml
+++ b/.idea/artifacts/KotlinPlugin.xml
@@ -45,6 +45,7 @@
+
diff --git a/.idea/libraries/markdown.xml b/.idea/libraries/markdown.xml
new file mode 100644
index 00000000000..5fbeaedaec3
--- /dev/null
+++ b/.idea/libraries/markdown.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/idea/idea.iml b/idea/idea.iml
index a3c6acca7e9..8f40f4b0dc8 100644
--- a/idea/idea.iml
+++ b/idea/idea.iml
@@ -45,5 +45,6 @@
+
-
+
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/JetQuickDocumentationProvider.java b/idea/src/org/jetbrains/kotlin/idea/JetQuickDocumentationProvider.java
index 1dc5375bd54..ce6f81df26b 100644
--- a/idea/src/org/jetbrains/kotlin/idea/JetQuickDocumentationProvider.java
+++ b/idea/src/org/jetbrains/kotlin/idea/JetQuickDocumentationProvider.java
@@ -16,39 +16,42 @@
package org.jetbrains.kotlin.idea;
-import com.google.common.base.Predicate;
import com.intellij.lang.documentation.AbstractDocumentationProvider;
import com.intellij.lang.java.JavaDocumentationProvider;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiWhiteSpace;
+import com.intellij.psi.PsiManager;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.asJava.KotlinLightMethod;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource;
+import org.jetbrains.kotlin.descriptors.SourceElement;
+import org.jetbrains.kotlin.idea.caches.resolve.KotlinCacheService;
+import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade;
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
import org.jetbrains.kotlin.idea.kdoc.KDocFinder;
import org.jetbrains.kotlin.idea.kdoc.KDocRenderer;
+import org.jetbrains.kotlin.idea.kdoc.KdocPackage;
+import org.jetbrains.kotlin.idea.project.ResolveSessionForBodies;
import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag;
import org.jetbrains.kotlin.psi.JetDeclaration;
-import org.jetbrains.kotlin.psi.JetPackageDirective;
+import org.jetbrains.kotlin.psi.JetElement;
import org.jetbrains.kotlin.psi.JetPsiUtil;
import org.jetbrains.kotlin.psi.JetReferenceExpression;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.BindingContext;
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode;
+import org.jetbrains.kotlin.resolve.source.PsiSourceElement;
+
+import java.util.Collection;
+import java.util.Collections;
public class JetQuickDocumentationProvider extends AbstractDocumentationProvider {
private static final Logger LOG = Logger.getInstance(JetQuickDocumentationProvider.class);
- private static final Predicate SKIP_WHITESPACE_AND_EMPTY_PACKAGE = new Predicate() {
- @Override
- public boolean apply(PsiElement input) {
- // Skip empty package because there can be comments before it
- // Skip whitespaces
- return (input instanceof JetPackageDirective && input.getChildren().length == 0) || input instanceof PsiWhiteSpace;
- }
- };
-
@Override
public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
return getText(element, originalElement, true);
@@ -118,4 +121,33 @@ public class JetQuickDocumentationProvider extends AbstractDocumentationProvider
return null;
}
+
+ @Override
+ public PsiElement getDocumentationElementForLink(PsiManager psiManager, String link, PsiElement context) {
+ if (!(context instanceof JetElement)) {
+ return null;
+ }
+ JetElement jetElement = (JetElement) context;
+ Project project = psiManager.getProject();
+ KotlinCacheService cacheService = KotlinCacheService.getInstance(project);
+ ResolveSessionForBodies session = cacheService.getLazyResolveSession(jetElement);
+ ResolutionFacade facade = cacheService.getResolutionFacade(Collections.singletonList(jetElement));
+ BindingContext bindingContext = facade.analyze(jetElement, BodyResolveMode.FULL);
+ DeclarationDescriptor contextDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, context);
+ if (contextDescriptor == null) {
+ return null;
+ }
+ Collection descriptors =
+ KdocPackage.resolveKDocLink(session, contextDescriptor, null, StringUtil.split(link, ","));
+ if (!descriptors.isEmpty()) {
+ DeclarationDescriptor target = descriptors.iterator().next();
+ if (target instanceof DeclarationDescriptorWithSource) {
+ SourceElement source = ((DeclarationDescriptorWithSource) target).getSource();
+ if (source instanceof PsiSourceElement) {
+ return ((PsiSourceElement) source).getPsi();
+ }
+ }
+ }
+ return null;
+ }
}
diff --git a/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocRenderer.kt b/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocRenderer.kt
index d24e8ad4163..26c0f4f6dd9 100644
--- a/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocRenderer.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocRenderer.kt
@@ -16,9 +16,15 @@
package org.jetbrains.kotlin.idea.kdoc
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
-import com.intellij.openapi.util.text.StringUtil
+import com.intellij.codeInsight.documentation.DocumentationManagerUtil
+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.parser.MarkdownParser
+import org.intellij.markdown.parser.dialects.commonmark.CommonMarkMarkerProcessor
import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
+import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
object KDocRenderer {
fun renderKDoc(docComment: KDocTag): String {
@@ -26,6 +32,7 @@ object KDocRenderer {
val result = StringBuilder("")
result.append(markdownToHtml(content))
if (docComment is KDocSection) {
+ result.append("\n")
val paramTags = docComment.findTagsByName("param").filter { it.getSubjectName() != null }
renderTagList(paramTags, "Parameters", result)
@@ -37,11 +44,28 @@ object KDocRenderer {
renderTag(docComment.findTagByName("author"), "Author", result)
renderTag(docComment.findTagByName("since"), "Since", result)
+
+ renderSeeAlso(docComment, result)
}
result.append("
")
return result.toString()
}
+ 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 ->
+ DocumentationManagerUtil.createHyperlink(to, tag.getSubjectName(), tag.getSubjectName(), false)
+ if (index < seeTags.size() - 1) {
+ to.append(", ")
+ }
+ }
+ to.append("
");
+ }
+
private fun renderTagList(tags: List, title: String, to: StringBuilder) {
if (tags.isEmpty()) {
return
@@ -50,19 +74,166 @@ object KDocRenderer {
tags.forEach {
to.append("${it.getSubjectName()} - ${markdownToHtml(it.getContent().trimLeading())}")
}
- to.append("")
+ 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("
")
+ to.append("\n")
}
}
fun markdownToHtml(markdown: String): String {
- // TODO Integrate a real Markdown parser
- return StringUtil.replace(markdown, "\n", "
");
+ val markdownTree = MarkdownParser(CommonMarkMarkerProcessor.Factory).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.filter { it.type == MarkdownElementTypes.PARAGRAPH }.singleOrNull()
+ if (maybeSingleParagraph != null) {
+ return maybeSingleParagraph.children.map { it.toHtml() }.join("")
+ } else {
+ return 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 }
+ }
+
+ fun MarkdownNode.visit(action: (MarkdownNode, () -> Unit) -> Unit) {
+ action(this) {
+ for (child in children) {
+ child.visit(action)
+ }
+ }
+ }
+
+ public fun MarkdownNode.toHtml(): String {
+ val sb = StringBuilder()
+ visit {(node, processChildren) ->
+ val nodeType = node.type
+ val nodeText = node.text
+ when (nodeType) {
+ MarkdownElementTypes.UNORDERED_LIST -> {
+ sb.appendln("")
+ processChildren()
+ sb.appendln("
")
+ }
+ MarkdownElementTypes.ORDERED_LIST -> {
+ sb.appendln("")
+ processChildren()
+ sb.appendln("
")
+ }
+ MarkdownElementTypes.LIST_ITEM -> {
+ sb.append("")
+ processChildren()
+ sb.appendln("")
+ }
+ MarkdownElementTypes.EMPH -> {
+ sb.append("")
+ processChildren()
+ sb.append("")
+ }
+ MarkdownElementTypes.STRONG -> {
+ sb.append("")
+ processChildren()
+ sb.append("")
+ }
+ MarkdownElementTypes.ATX_1 -> {
+ sb.append("")
+ processChildren()
+ sb.append("
")
+ }
+ MarkdownElementTypes.ATX_2 -> {
+ sb.append("")
+ processChildren()
+ sb.append("
")
+ }
+ MarkdownElementTypes.ATX_3 -> {
+ sb.append("")
+ processChildren()
+ sb.append("
")
+ }
+ MarkdownElementTypes.ATX_4 -> {
+ sb.append("")
+ processChildren()
+ sb.append("
")
+ }
+ MarkdownElementTypes.ATX_5 -> {
+ sb.append("")
+ processChildren()
+ sb.append("
")
+ }
+ MarkdownElementTypes.ATX_6 -> {
+ sb.append("")
+ processChildren()
+ sb.append("
")
+ }
+ MarkdownElementTypes.BLOCK_QUOTE -> {
+ sb.append("")
+ processChildren()
+ sb.append("
")
+ }
+ MarkdownElementTypes.PARAGRAPH -> {
+ sb.append("")
+ processChildren()
+ sb.appendln("
")
+ }
+ MarkdownElementTypes.CODE_SPAN -> {
+ sb.append("")
+ processChildren()
+ sb.append("")
+ }
+ MarkdownElementTypes.CODE_BLOCK -> {
+ sb.append("")
+ processChildren()
+ sb.append("")
+ }
+ MarkdownElementTypes.SHORT_REFERENCE_LINK,
+ MarkdownElementTypes.FULL_REFERENCE_LINK -> {
+ val label = node.child(MarkdownElementTypes.LINK_LABEL)?.child(MarkdownTokenTypes.TEXT)?.text
+ if (label != null) {
+ val linkText = node.child(MarkdownElementTypes.LINK_TEXT)?.child(MarkdownTokenTypes.TEXT)?.text ?: label
+ DocumentationManagerUtil.createHyperlink(sb, label, linkText, true)
+ } else {
+ sb.append(node.text)
+ }
+ }
+ MarkdownElementTypes.INLINE_LINK -> {
+ val label = node.child(MarkdownElementTypes.LINK_TEXT)?.child(MarkdownTokenTypes.TEXT)?.text
+ val destination = node.child(MarkdownElementTypes.LINK_DESTINATION)?.text
+ if (label != null && destination != null) {
+ sb.append("a href=\"${destination}\">${label.htmlEscape()}")
+ } else {
+ sb.append(node.text)
+ }
+ }
+ MarkdownTokenTypes.TEXT,
+ MarkdownTokenTypes.WHITE_SPACE,
+ MarkdownTokenTypes.COLON,
+ MarkdownTokenTypes.DOUBLE_QUOTE,
+ MarkdownTokenTypes.LPAREN,
+ MarkdownTokenTypes.RPAREN,
+ MarkdownTokenTypes.LBRACKET,
+ MarkdownTokenTypes.RBRACKET -> {
+ sb.append(nodeText)
+ }
+ MarkdownTokenTypes.GT -> sb.append(">")
+ MarkdownTokenTypes.LT -> sb.append("<")
+ else -> {
+ processChildren()
+ }
+ }
+ }
+ return sb.toString()
+ }
+
+ fun String.htmlEscape(): String = replace("&", "&").replace("<", "<").replace(">", ">")
}
diff --git a/idea/testData/editor/quickDoc/JavaMethodUsedInKotlin.kt b/idea/testData/editor/quickDoc/JavaMethodUsedInKotlin.kt
index 130341fb6f1..a98e6526025 100644
--- a/idea/testData/editor/quickDoc/JavaMethodUsedInKotlin.kt
+++ b/idea/testData/editor/quickDoc/JavaMethodUsedInKotlin.kt
@@ -2,4 +2,4 @@ fun ktTest() {
Test.foo("SomeTest")
}
-// INFO: public open fun foo(param: String!): Array<(out) Any!>!
Java declaration:
Test...
\ No newline at end of file
+//INFO: public open fun foo(param: String!): Array<(out) Any!>!
Java declaration:
Test...
diff --git a/idea/testData/editor/quickDoc/KotlinPackageClassUsedFromJava.java b/idea/testData/editor/quickDoc/KotlinPackageClassUsedFromJava.java
index 9d64e69288e..969e5b498e2 100644
--- a/idea/testData/editor/quickDoc/KotlinPackageClassUsedFromJava.java
+++ b/idea/testData/editor/quickDoc/KotlinPackageClassUsedFromJava.java
@@ -6,4 +6,4 @@ class KotlinClassUsedFromJava {
}
}
-// INFO: [light_idea_test_case] testing...
\ No newline at end of file
+//INFO: [light_idea_test_case] testing.TestingPackage...
diff --git a/idea/testData/editor/quickDoc/MethodFromStdLib.kt b/idea/testData/editor/quickDoc/MethodFromStdLib.kt
index 57fb7c02a15..72cc73da994 100644
--- a/idea/testData/editor/quickDoc/MethodFromStdLib.kt
+++ b/idea/testData/editor/quickDoc/MethodFromStdLib.kt
@@ -2,4 +2,5 @@ fun test() {
listOf(1, 2, 4).filter { it > 0 }
}
-// INFO: inline public fun <T> Iterable<T>.filter(predicate: (T) → Boolean): List<T>
Returns a list containing all elements matching the given [predicate]
+//INFO: inline public fun <T> Iterable<T>.filter(predicate: (T) → Boolean): List<T>
Returns a list containing all elements matching the given predicate
+//INFO:
diff --git a/idea/testData/editor/quickDoc/OnClassDeclarationWithNoPackage.kt b/idea/testData/editor/quickDoc/OnClassDeclarationWithNoPackage.kt
index e85de36f4aa..b329cc907b0 100644
--- a/idea/testData/editor/quickDoc/OnClassDeclarationWithNoPackage.kt
+++ b/idea/testData/editor/quickDoc/OnClassDeclarationWithNoPackage.kt
@@ -3,4 +3,5 @@
*/
class Some
-// INFO: internal final class Some
Usefull comment
\ No newline at end of file
+//INFO: internal final class Some
Usefull comment
+//INFO:
diff --git a/idea/testData/editor/quickDoc/OnFunctionDeclarationWithPackage.kt b/idea/testData/editor/quickDoc/OnFunctionDeclarationWithPackage.kt
index 7f1a2cd4f31..758db8e473b 100644
--- a/idea/testData/editor/quickDoc/OnFunctionDeclarationWithPackage.kt
+++ b/idea/testData/editor/quickDoc/OnFunctionDeclarationWithPackage.kt
@@ -12,4 +12,6 @@ package test
*/
fun testFun(first: String, second: Int) = 12
-// INFO: internal fun testFun(first: String, second: Int): Int
Test function
- Parameters:
first - Somesecond - Other
\ No newline at end of file
+//INFO: internal fun testFun(first: String, second: Int): Int
Test function
+//INFO:
- Parameters:
first - Somesecond - Other
+//INFO:
diff --git a/idea/testData/editor/quickDoc/OnInheritedMethodUsage.kt b/idea/testData/editor/quickDoc/OnInheritedMethodUsage.kt
index be307e58bf7..337d5fa80c9 100644
--- a/idea/testData/editor/quickDoc/OnInheritedMethodUsage.kt
+++ b/idea/testData/editor/quickDoc/OnInheritedMethodUsage.kt
@@ -14,4 +14,5 @@ fun test() {
D().foo()
}
-// INFO: internal open fun foo(): Int
This method returns zero.
\ No newline at end of file
+//INFO: internal open fun foo(): Int
This method returns zero.
+//INFO:
diff --git a/idea/testData/editor/quickDoc/OnInheritedPropertyUsage.kt b/idea/testData/editor/quickDoc/OnInheritedPropertyUsage.kt
index 66ab6538482..902c241713a 100644
--- a/idea/testData/editor/quickDoc/OnInheritedPropertyUsage.kt
+++ b/idea/testData/editor/quickDoc/OnInheritedPropertyUsage.kt
@@ -14,4 +14,5 @@ fun test() {
D().foo
}
-// INFO: internal open val foo: Int
This property returns zero.
\ No newline at end of file
+//INFO: internal open val foo: Int
This property returns zero.
+//INFO:
diff --git a/idea/testData/editor/quickDoc/OnMethodUsage.kt b/idea/testData/editor/quickDoc/OnMethodUsage.kt
index 9f1ab9a90f4..fa3c76d7675 100644
--- a/idea/testData/editor/quickDoc/OnMethodUsage.kt
+++ b/idea/testData/editor/quickDoc/OnMethodUsage.kt
@@ -1,5 +1,5 @@
/**
- Some documentation
+Some documentation
* @param a Some int
* @param b String
@@ -12,4 +12,6 @@ fun test() {
testMethod(1, "value")
}
-// INFO: internal fun testMethod(a: Int, b: String): Unit
Some documentation
- Parameters:
a - Some intb - String
\ No newline at end of file
+//INFO: internal fun testMethod(a: Int, b: String): Unit
Some documentation
+//INFO:
- Parameters:
a - Some intb - String
+//INFO:
diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithBracketsInParam.kt b/idea/testData/editor/quickDoc/OnMethodUsageWithBracketsInParam.kt
index 59df5c27d7e..acd0dde376e 100644
--- a/idea/testData/editor/quickDoc/OnMethodUsageWithBracketsInParam.kt
+++ b/idea/testData/editor/quickDoc/OnMethodUsageWithBracketsInParam.kt
@@ -1,5 +1,5 @@
/**
- Some documentation
+Some documentation
* @param[a] Some int
* @param[b] String
@@ -12,4 +12,6 @@ fun test() {
testMethod(1, "value")
}
-// INFO: internal fun testMethod(a: Int, b: String): Unit
Some documentation
- Parameters:
a - Some intb - String
\ No newline at end of file
+//INFO: internal fun testMethod(a: Int, b: String): Unit
Some documentation
+//INFO:
- Parameters:
a - Some intb - String
+//INFO:
diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithMarkdown.kt b/idea/testData/editor/quickDoc/OnMethodUsageWithMarkdown.kt
new file mode 100644
index 00000000000..5039d12cdf4
--- /dev/null
+++ b/idea/testData/editor/quickDoc/OnMethodUsageWithMarkdown.kt
@@ -0,0 +1,26 @@
+/**
+ * Some documentation. **Bold** *underline* `code` foo: bar (baz) [quux]
+ *
+ * [Kotlin](http://www.kotlinlang.org)
+ *
+ * [C]
+ *
+ * [See this class][C]
+ */
+fun testMethod() {
+
+}
+
+class C {
+}
+
+fun test() {
+ testMethod(1, "value")
+}
+
+//INFO: internal fun testMethod(): Unit
Some documentation. Bold underline code foo: bar (baz) quux
+//INFO: a href="http://www.kotlinlang.org">Kotlin
+//INFO: C
+//INFO: See this class
+//INFO:
+//INFO:
diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndThrows.kt b/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndThrows.kt
index caedc42a566..3bb5eec0621 100644
--- a/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndThrows.kt
+++ b/idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndThrows.kt
@@ -14,4 +14,8 @@ fun test() {
testMethod(1, "value")
}
-// INFO: internal fun testMethod(a: Int, b: String): Unit
Some documentation
- Parameters:
a - Some intb - String
- Returns:
- Return value
- Throws:
IllegalArgumentException - if the weather is bad
\ No newline at end of file
+//INFO: internal fun testMethod(a: Int, b: String): Unit
Some documentation
+//INFO:
- Parameters:
a - Some intb - String
+//INFO: - Returns:
- Return value
+//INFO: - Throws:
IllegalArgumentException - if the weather is bad
+//INFO:
diff --git a/idea/testData/editor/quickDoc/OnMethodUsageWithSee.kt b/idea/testData/editor/quickDoc/OnMethodUsageWithSee.kt
new file mode 100644
index 00000000000..cb4d1a9d12b
--- /dev/null
+++ b/idea/testData/editor/quickDoc/OnMethodUsageWithSee.kt
@@ -0,0 +1,20 @@
+/**
+ * @see C
+ * @see D
+ */
+fun testMethod() {
+
+}
+
+class C {
+}
+
+class D {
+}
+
+fun test() {
+ testMethod(1, "value")
+}
+
+//INFO: internal fun testMethod(): Unit
+//INFO:
- See Also:
C, D
diff --git a/idea/testData/editor/quickDoc/TopLevelMethodFromJava.java b/idea/testData/editor/quickDoc/TopLevelMethodFromJava.java
index fde04a1cd48..a58793107d9 100644
--- a/idea/testData/editor/quickDoc/TopLevelMethodFromJava.java
+++ b/idea/testData/editor/quickDoc/TopLevelMethodFromJava.java
@@ -8,4 +8,5 @@ class Testing {
}
}
-// INFO: internal fun foo(bar: Int): Unit
KDoc foo
\ No newline at end of file
+//INFO: internal fun foo(bar: Int): Unit
KDoc foo
+//INFO:
diff --git a/idea/testData/kdoc/navigate/simple.kt b/idea/testData/kdoc/navigate/simple.kt
new file mode 100644
index 00000000000..3d922364e73
--- /dev/null
+++ b/idea/testData/kdoc/navigate/simple.kt
@@ -0,0 +1,5 @@
+class C {
+}
+
+fun foo() {
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/AbstractJetQuickDocProviderTest.java b/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/AbstractJetQuickDocProviderTest.java
index 8cf596c1243..928ae15245e 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/AbstractJetQuickDocProviderTest.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/AbstractJetQuickDocProviderTest.java
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.idea.JetLightCodeInsightFixtureTestCase;
import org.jetbrains.kotlin.idea.ProjectDescriptorWithStdlibSources;
import org.jetbrains.kotlin.test.InTextDirectivesUtils;
import org.jetbrains.kotlin.test.util.UtilPackage;
-import org.junit.Assert;
import java.io.File;
import java.util.List;
@@ -44,6 +43,12 @@ public abstract class AbstractJetQuickDocProviderTest extends JetLightCodeInsigh
PsiElement targetElement = documentationManager.findTargetElement(myFixture.getEditor(), myFixture.getFile());
String info = CtrlMouseHandler.getInfo(targetElement, element);
+ if (info != null) {
+ info = StringUtil.convertLineSeparators(info);
+ }
+ if (info != null && !info.endsWith("\n")) {
+ info += "\n";
+ }
File testDataFile = new File(path);
String textData = FileUtil.loadFile(testDataFile, true);
@@ -56,14 +61,15 @@ public abstract class AbstractJetQuickDocProviderTest extends JetLightCodeInsigh
textData + "\n\n//INFO: " + info,
testDataFile.getAbsolutePath());
}
- else if (directives.size() == 1) {
- assertNotNull(info);
+ else {
+ StringBuilder expectedInfoBuilder = new StringBuilder();
+ for (String directive : directives) {
+ expectedInfoBuilder.append(directive).append("\n");
+ }
+ String expectedInfo = expectedInfoBuilder.toString();
- String expectedInfo = directives.get(0);
-
- // We can avoid testing for too long comments with \n character by placing '...' in test data
- if (expectedInfo.endsWith("...")) {
- if (!info.startsWith(StringUtil.trimEnd(expectedInfo, "..."))) {
+ if (expectedInfo.endsWith("...\n")) {
+ if (!info.startsWith(StringUtil.trimEnd(expectedInfo, "...\n"))) {
wrapToFileComparisonFailure(info, path, textData);
}
}
@@ -71,18 +77,16 @@ public abstract class AbstractJetQuickDocProviderTest extends JetLightCodeInsigh
wrapToFileComparisonFailure(info, path, textData);
}
}
- else {
- Assert.fail("Too many '// INFO:' directives in file " + path);
- }
}
private static void wrapToFileComparisonFailure(String info, String filePath, String fileData) {
- int newLineIndex = info.indexOf('\n');
- if (newLineIndex != -1) {
- info = info.substring(0, newLineIndex) + "...";
+ List infoLines = StringUtil.split(info, "\n");
+ StringBuilder infoBuilder = new StringBuilder();
+ for (String line : infoLines) {
+ infoBuilder.append("//INFO: ").append(line).append("\n");
}
- String correctedFileText = fileData.replaceFirst("//\\s?INFO: .*", "// INFO: " + info);
+ String correctedFileText = fileData.replaceAll("//\\s?INFO: .*\n?", "") + infoBuilder.toString();
throw new FileComparisonFailure("Unexpected info", fileData, correctedFileText, new File(filePath).getAbsolutePath());
}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/JetQuickDocProviderTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/JetQuickDocProviderTestGenerated.java
index 4df205fb321..c984eb02e15 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/JetQuickDocProviderTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/JetQuickDocProviderTestGenerated.java
@@ -120,12 +120,24 @@ public class JetQuickDocProviderTestGenerated extends AbstractJetQuickDocProvide
doTest(fileName);
}
+ @TestMetadata("OnMethodUsageWithMarkdown.kt")
+ public void testOnMethodUsageWithMarkdown() throws Exception {
+ String fileName = JetTestUtils.navigationMetadata("idea/testData/editor/quickDoc/OnMethodUsageWithMarkdown.kt");
+ doTest(fileName);
+ }
+
@TestMetadata("OnMethodUsageWithReturnAndThrows.kt")
public void testOnMethodUsageWithReturnAndThrows() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/editor/quickDoc/OnMethodUsageWithReturnAndThrows.kt");
doTest(fileName);
}
+ @TestMetadata("OnMethodUsageWithSee.kt")
+ public void testOnMethodUsageWithSee() throws Exception {
+ String fileName = JetTestUtils.navigationMetadata("idea/testData/editor/quickDoc/OnMethodUsageWithSee.kt");
+ doTest(fileName);
+ }
+
@TestMetadata("TopLevelMethodFromJava.java")
public void testTopLevelMethodFromJava() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/editor/quickDoc/TopLevelMethodFromJava.java");
diff --git a/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/QuickDocNavigationTest.kt b/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/QuickDocNavigationTest.kt
new file mode 100644
index 00000000000..123cc74b56d
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/editor/quickDoc/QuickDocNavigationTest.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.editor.quickDoc
+
+import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase
+import org.jetbrains.kotlin.idea.JetQuickDocumentationProvider
+import org.jetbrains.kotlin.idea.PluginTestCaseBase
+import org.jetbrains.kotlin.psi.JetClass
+import org.jetbrains.kotlin.psi.JetFunction
+import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
+import org.junit.Assert
+
+public class QuickDocNavigationTest() : LightPlatformCodeInsightFixtureTestCase() {
+ override fun getTestDataPath(): String {
+ return PluginTestCaseBase.getTestDataPathBase() + "/kdoc/navigate/"
+ }
+
+ public fun testSimple() {
+ myFixture.configureByFile(getTestName(true) + ".kt")
+ val source = myFixture.getElementAtCaret().getParentOfType(false)
+ val target = JetQuickDocumentationProvider().getDocumentationElementForLink(
+ myFixture.getPsiManager(), "C", source);
+ Assert.assertTrue(target is JetClass)
+ Assert.assertEquals("C", (target as JetClass).getName())
+ }
+}
diff --git a/update_dependencies.xml b/update_dependencies.xml
index f8ce6d184c9..c3fc70056f2 100644
--- a/update_dependencies.xml
+++ b/update_dependencies.xml
@@ -220,6 +220,10 @@
+
+
+