aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Jemerov <yole@jetbrains.com>2016-01-12 16:14:21 +0100
committerDmitry Jemerov <yole@jetbrains.com>2016-01-12 16:14:21 +0100
commita3ec2e2afd6f4140ac78f7630fa9c2ca1f8ca8af (patch)
treec0a87789124c2fff312c5b32f1a4e6815129abca
parent99b6196bde4773fd26bd733ecf5e3984ce0a4c63 (diff)
downloaddokka-a3ec2e2afd6f4140ac78f7630fa9c2ca1f8ca8af.tar.gz
dokka-a3ec2e2afd6f4140ac78f7630fa9c2ca1f8ca8af.tar.bz2
dokka-a3ec2e2afd6f4140ac78f7630fa9c2ca1f8ca8af.zip
generate signature-based anchors for overloads; use signature instead of name as an anchor for in-page links
-rw-r--r--core/src/main/kotlin/Formats/HtmlFormatService.kt5
-rw-r--r--core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt3
-rw-r--r--core/src/main/kotlin/Formats/MarkdownFormatService.kt18
-rw-r--r--core/src/main/kotlin/Formats/StructuredFormatService.kt12
-rw-r--r--core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt6
-rw-r--r--core/src/main/kotlin/Kotlin/DocumentationBuilder.kt20
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinLanguageService.kt2
-rw-r--r--core/src/main/kotlin/Model/Content.kt10
-rw-r--r--core/src/main/kotlin/Model/DocumentationNode.kt2
-rw-r--r--core/src/main/kotlin/Model/DocumentationReference.kt12
-rw-r--r--core/src/main/kotlin/javadoc/docbase.kt2
-rw-r--r--core/src/test/kotlin/model/ClassTest.kt2
-rw-r--r--core/src/test/kotlin/model/FunctionTest.kt2
-rw-r--r--core/testdata/format/bracket.html1
-rw-r--r--core/testdata/format/brokenLink.html1
-rw-r--r--core/testdata/format/codeSpan.html1
-rw-r--r--core/testdata/format/deprecated.class.html2
-rw-r--r--core/testdata/format/htmlEscaping.html1
-rw-r--r--core/testdata/format/javaDeprecated.html1
-rw-r--r--core/testdata/format/javaSupertype.html2
-rw-r--r--core/testdata/format/overloads.html4
-rw-r--r--core/testdata/format/overloadsWithDescription.html8
-rw-r--r--core/testdata/format/overloadsWithDifferentDescriptions.html6
-rw-r--r--core/testdata/format/parameterAnchor.html5
-rw-r--r--core/testdata/format/parenthesis.html1
-rw-r--r--core/testdata/format/see.html3
-rw-r--r--core/testdata/format/tripleBackticks.html1
-rw-r--r--core/testdata/format/uninterpretedEmphasisCharacters.html1
28 files changed, 87 insertions, 47 deletions
diff --git a/core/src/main/kotlin/Formats/HtmlFormatService.kt b/core/src/main/kotlin/Formats/HtmlFormatService.kt
index f78439ba..f0d7e6c8 100644
--- a/core/src/main/kotlin/Formats/HtmlFormatService.kt
+++ b/core/src/main/kotlin/Formats/HtmlFormatService.kt
@@ -22,8 +22,9 @@ open class HtmlFormatService @Inject constructor(@Named("folders") locationServi
return "<span class=\"keyword\">${formatText(text)}</span>"
}
- override fun formatIdentifier(text: String, kind: IdentifierKind): String {
- return "<span class=\"identifier\">${formatText(text)}</span>"
+ override fun formatIdentifier(text: String, kind: IdentifierKind, signature: String?): String {
+ val id = signature?.let { " id=\"$it\"" }.orEmpty()
+ return "<span class=\"identifier\"$id>${formatText(text)}</span>"
}
override fun appendBlockCode(to: StringBuilder, line: String, language: String) {
diff --git a/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
index f869bc75..14157cff 100644
--- a/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
+++ b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
@@ -124,7 +124,8 @@ class KotlinWebsiteFormatService @Inject constructor(locationService: LocationSe
return "<span class=\"keyword\">${formatText(text)}</span>"
}
- override fun formatIdentifier(text: String, kind: IdentifierKind): String {
+ override fun formatIdentifier(text: String, kind: IdentifierKind, signature: String?): String {
+ val id = signature?.let { " id=\"$it\"" }.orEmpty()
return "<span class=\"${identifierClassName(kind)}\">${formatText(text)}</span>"
}
diff --git a/core/src/main/kotlin/Formats/MarkdownFormatService.kt b/core/src/main/kotlin/Formats/MarkdownFormatService.kt
index 4e16b1a8..7a93801e 100644
--- a/core/src/main/kotlin/Formats/MarkdownFormatService.kt
+++ b/core/src/main/kotlin/Formats/MarkdownFormatService.kt
@@ -12,20 +12,10 @@ open class MarkdownFormatService
return items.map { formatLink(it) }.joinToString(" / ")
}
- override fun formatText(text: String): String {
- return text.htmlEscape()
- }
-
- override fun formatSymbol(text: String): String {
- return text.htmlEscape()
- }
-
- override fun formatKeyword(text: String): String {
- return text.htmlEscape()
- }
- override fun formatIdentifier(text: String, kind: IdentifierKind): String {
- return text.htmlEscape()
- }
+ override fun formatText(text: String): String = text.htmlEscape()
+ override fun formatSymbol(text: String): String = text.htmlEscape()
+ override fun formatKeyword(text: String): String = text.htmlEscape()
+ override fun formatIdentifier(text: String, kind: IdentifierKind, signature: String?): String = text.htmlEscape()
override fun formatCode(code: String): String {
return "`$code`"
diff --git a/core/src/main/kotlin/Formats/StructuredFormatService.kt b/core/src/main/kotlin/Formats/StructuredFormatService.kt
index 1d464396..9221004c 100644
--- a/core/src/main/kotlin/Formats/StructuredFormatService.kt
+++ b/core/src/main/kotlin/Formats/StructuredFormatService.kt
@@ -31,7 +31,7 @@ abstract class StructuredFormatService(locationService: LocationService,
abstract fun formatText(text: String): String
abstract fun formatSymbol(text: String): String
abstract fun formatKeyword(text: String): String
- abstract fun formatIdentifier(text: String, kind: IdentifierKind): String
+ abstract fun formatIdentifier(text: String, kind: IdentifierKind, signature: String?): String
fun formatEntity(text: String): String = text
abstract fun formatLink(text: String, href: String): String
open fun formatLink(link: FormatLink): String = formatLink(formatText(link.text), link.href)
@@ -60,7 +60,7 @@ abstract class StructuredFormatService(locationService: LocationService,
is ContentText -> to.append(formatText(content.text))
is ContentSymbol -> to.append(formatSymbol(content.text))
is ContentKeyword -> to.append(formatKeyword(content.text))
- is ContentIdentifier -> to.append(formatIdentifier(content.text, content.kind))
+ is ContentIdentifier -> to.append(formatIdentifier(content.text, content.kind, content.signature))
is ContentNonBreakingSpace -> to.append(formatNonBreakingSpace())
is ContentSoftLineBreak -> to.append(formatSoftLineBreak())
is ContentIndentedSoftLineBreak -> to.append(formatIndentedSoftLineBreak())
@@ -107,7 +107,8 @@ abstract class StructuredFormatService(locationService: LocationService,
fun locationHref(from: Location, to: DocumentationNode): String {
val topLevelPage = to.references(RefKind.TopLevelPage).singleOrNull()?.to
if (topLevelPage != null) {
- return from.relativePathTo(locationService.location(topLevelPage), to.name)
+ val signature = to.detailOrNull(NodeKind.Signature)
+ return from.relativePathTo(locationService.location(topLevelPage), signature?.name ?: to.name)
}
return from.relativePathTo(locationService.location(to))
}
@@ -180,9 +181,12 @@ abstract class StructuredFormatService(locationService: LocationService,
}
}
- private fun formatOverloadGroup(items: MutableList<DocumentationNode>) {
+ private fun formatOverloadGroup(items: List<DocumentationNode>) {
items.forEach {
val rendered = languageService.render(it)
+ it.detailOrNull(NodeKind.Signature)?.let {
+ appendAnchor(to, it.name)
+ }
appendAsSignature(to, rendered) {
to.append(formatCode(formatText(location, rendered)))
it.appendSourceLink()
diff --git a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
index 67bf1f08..9d75792c 100644
--- a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
+++ b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
@@ -6,15 +6,15 @@ import com.intellij.psi.util.InheritanceUtil
fun getSignature(element: PsiElement?) = when(element) {
is PsiClass -> element.qualifiedName
- is PsiField -> element.containingClass!!.qualifiedName + "#" + element.name
+ is PsiField -> element.containingClass!!.qualifiedName + "$" + element.name
is PsiMethod ->
- element.containingClass!!.qualifiedName + "#" + element.name + "(" +
+ element.containingClass!!.qualifiedName + "$" + element.name + "(" +
element.parameterList.parameters.map { it.type.typeSignature() }.joinToString(",") + ")"
else -> null
}
private fun PsiType.typeSignature(): String = when(this) {
- is PsiArrayType -> "Array<${componentType.typeSignature()}>"
+ is PsiArrayType -> "Array((${componentType.typeSignature()}))"
else -> mapTypeName(this)
}
diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
index f91f160b..3c4c0c39 100644
--- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
+++ b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
@@ -227,6 +227,10 @@ class DocumentationBuilder
appendSourceLink(sourceElement.getPsi(), options.sourceLinks)
}
+ fun DocumentationNode.appendSignature(descriptor: DeclarationDescriptor) {
+ appendTextNode(descriptor.signature(), NodeKind.Signature, RefKind.Detail)
+ }
+
fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: RefKind): DocumentationNode? {
// do not include generated code
if (descriptor is CallableMemberDescriptor && descriptor.kind != CallableMemberDescriptor.Kind.DECLARATION)
@@ -440,6 +444,7 @@ class DocumentationBuilder
node.appendAnnotations(this)
node.appendModifiers(this)
node.appendSourceLink(source)
+ node.appendSignature(this)
overriddenDescriptors.forEach {
addOverrideLink(it, this)
@@ -468,6 +473,7 @@ class DocumentationBuilder
node.appendAnnotations(this)
node.appendModifiers(this)
node.appendSourceLink(source)
+ node.appendSignature(this)
if (isVar) {
node.appendTextNode("var", NodeKind.Modifier)
}
@@ -518,6 +524,7 @@ class DocumentationBuilder
}
node.appendAnnotations(this)
node.appendModifiers(this)
+ node.appendSignature(this)
if (varargElementType != null && node.details(NodeKind.Modifier).none { it.name == "vararg" }) {
node.appendTextNode("vararg", NodeKind.Modifier)
}
@@ -699,10 +706,10 @@ fun CallableMemberDescriptor.getExtensionClassDescriptor(): ClassifierDescriptor
fun DeclarationDescriptor.signature(): String = when(this) {
is ClassDescriptor, is PackageFragmentDescriptor -> DescriptorUtils.getFqName(this).asString()
- is PropertyDescriptor -> containingDeclaration.signature() + "#" + name + receiverSignature()
- is FunctionDescriptor -> containingDeclaration.signature() + "#" + name + parameterSignature()
- is ValueParameterDescriptor -> containingDeclaration.signature() + ":" + name
- is TypeParameterDescriptor -> containingDeclaration.signature() + "<" + name
+ is PropertyDescriptor -> containingDeclaration.signature() + "$" + name + receiverSignature()
+ is FunctionDescriptor -> containingDeclaration.signature() + "$" + name + parameterSignature()
+ is ValueParameterDescriptor -> containingDeclaration.signature() + "/" + name
+ is TypeParameterDescriptor -> containingDeclaration.signature() + "*" + name
else -> throw UnsupportedOperationException("Don't know how to calculate signature for $this")
}
@@ -727,7 +734,10 @@ fun CallableMemberDescriptor.parameterSignature(): String {
fun KotlinType.signature(): String {
val declarationDescriptor = constructor.declarationDescriptor ?: return "<null>"
val typeName = DescriptorUtils.getFqName(declarationDescriptor).asString()
- return typeName + arguments.joinToString(prefix = "<", postfix = ">") { it.type.signature() }
+ if (arguments.isEmpty()) {
+ return typeName
+ }
+ return typeName + arguments.joinToString(prefix = "((", postfix = "))") { it.type.signature() }
}
fun DeclarationDescriptor.signatureWithSourceLocation(): String {
diff --git a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
index a5bb5ee7..a0d8f95d 100644
--- a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
+++ b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
@@ -215,7 +215,7 @@ class KotlinLanguageService : LanguageService {
renderAnnotationsForNode(node)
}
renderModifiersForNode(node, renderMode)
- identifier(node.name, IdentifierKind.ParameterName)
+ identifier(node.name, IdentifierKind.ParameterName, node.detailOrNull(NodeKind.Signature)?.name)
symbol(":")
nbsp()
val parameterType = node.detail(NodeKind.Type)
diff --git a/core/src/main/kotlin/Model/Content.kt b/core/src/main/kotlin/Model/Content.kt
index 4c69f6cb..0a38a524 100644
--- a/core/src/main/kotlin/Model/Content.kt
+++ b/core/src/main/kotlin/Model/Content.kt
@@ -45,7 +45,9 @@ data class ContentKeyword(val text: String) : ContentNode {
get() = text.length
}
-data class ContentIdentifier(val text: String, val kind: IdentifierKind = IdentifierKind.Other) : ContentNode {
+data class ContentIdentifier(val text: String,
+ val kind: IdentifierKind = IdentifierKind.Other,
+ val signature: String? = null) : ContentNode {
override val textLength: Int
get() = text.length
}
@@ -140,7 +142,11 @@ fun content(body: ContentBlock.() -> Unit): ContentBlock {
fun ContentBlock.text(value: String) = append(ContentText(value))
fun ContentBlock.keyword(value: String) = append(ContentKeyword(value))
fun ContentBlock.symbol(value: String) = append(ContentSymbol(value))
-fun ContentBlock.identifier(value: String, kind: IdentifierKind = IdentifierKind.Other) = append(ContentIdentifier(value, kind))
+
+fun ContentBlock.identifier(value: String, kind: IdentifierKind = IdentifierKind.Other, signature: String? = null) {
+ append(ContentIdentifier(value, kind, signature))
+}
+
fun ContentBlock.nbsp() = append(ContentNonBreakingSpace)
fun ContentBlock.softLineBreak() = append(ContentSoftLineBreak)
fun ContentBlock.indentedSoftLineBreak() = append(ContentIndentedSoftLineBreak)
diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt
index 3cedb8e6..f7e935b2 100644
--- a/core/src/main/kotlin/Model/DocumentationNode.kt
+++ b/core/src/main/kotlin/Model/DocumentationNode.kt
@@ -42,6 +42,7 @@ enum class NodeKind {
SourceUrl,
SourcePosition,
+ Signature,
ExternalLink,
@@ -115,6 +116,7 @@ open class DocumentationNode(val name: String,
fun links(kind: NodeKind): List<DocumentationNode> = links.filter { it.kind == kind }
fun detail(kind: NodeKind): DocumentationNode = details.filter { it.kind == kind }.single()
+ fun detailOrNull(kind: NodeKind): DocumentationNode? = details.filter { it.kind == kind }.singleOrNull()
fun member(kind: NodeKind): DocumentationNode = members.filter { it.kind == kind }.single()
fun link(kind: NodeKind): DocumentationNode = links.filter { it.kind == kind }.single()
diff --git a/core/src/main/kotlin/Model/DocumentationReference.kt b/core/src/main/kotlin/Model/DocumentationReference.kt
index 0b40e83a..0c87d719 100644
--- a/core/src/main/kotlin/Model/DocumentationReference.kt
+++ b/core/src/main/kotlin/Model/DocumentationReference.kt
@@ -1,5 +1,6 @@
package org.jetbrains.dokka
+import com.google.inject.Inject
import com.google.inject.Singleton
enum class RefKind {
@@ -35,7 +36,8 @@ class PendingDocumentationReference(val lazyNodeFrom: () -> DocumentationNode?,
}
@Singleton
-class NodeReferenceGraph() {
+class NodeReferenceGraph
+ @Inject constructor(val logger: DokkaLogger) {
private val nodeMap = hashMapOf<String, DocumentationNode>()
val references = arrayListOf<PendingDocumentationReference>()
@@ -55,7 +57,13 @@ class NodeReferenceGraph() {
references.add(PendingDocumentationReference({ -> nodeMap[fromSignature]}, { -> nodeMap[toSignature]}, kind))
}
- fun lookup(signature: String): DocumentationNode? = nodeMap[signature]
+ fun lookup(signature: String): DocumentationNode? {
+ val result = nodeMap[signature]
+ if (result == null) {
+ logger.warn("Can't find node by signature $signature")
+ }
+ return result
+ }
fun resolveReferences() {
references.forEach { it.resolve() }
diff --git a/core/src/main/kotlin/javadoc/docbase.kt b/core/src/main/kotlin/javadoc/docbase.kt
index 25733464..5ddaa37f 100644
--- a/core/src/main/kotlin/javadoc/docbase.kt
+++ b/core/src/main/kotlin/javadoc/docbase.kt
@@ -366,7 +366,7 @@ class MethodAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : Docume
class FieldAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeAdapter(module, node), ProgramElementDoc by ProgramElementAdapter(module, node), FieldDoc {
override fun isSynthetic(): Boolean = false
- override fun constantValueExpression(): String? = node.details(NodeKind.Value).firstOrNull()?.let { it.name }
+ override fun constantValueExpression(): String? = node.detailOrNull(NodeKind.Value)?.let { it.name }
override fun constantValue(): Any? = constantValueExpression()
override fun type(): Type = TypeAdapter(module, node.detail(NodeKind.Type))
diff --git a/core/src/test/kotlin/model/ClassTest.kt b/core/src/test/kotlin/model/ClassTest.kt
index 0a824f1c..d4e6f26b 100644
--- a/core/src/test/kotlin/model/ClassTest.kt
+++ b/core/src/test/kotlin/model/ClassTest.kt
@@ -51,7 +51,7 @@ public class ClassTest {
assertEquals("name", name)
assertEquals(NodeKind.Parameter, kind)
assertEquals(Content.Empty, content)
- assertEquals("String", details.single().name)
+ assertEquals("String", detail(NodeKind.Type).name)
assertTrue(links.none())
assertTrue(members.none())
}
diff --git a/core/src/test/kotlin/model/FunctionTest.kt b/core/src/test/kotlin/model/FunctionTest.kt
index 0a65b640..af85d569 100644
--- a/core/src/test/kotlin/model/FunctionTest.kt
+++ b/core/src/test/kotlin/model/FunctionTest.kt
@@ -130,7 +130,7 @@ Documentation""", content.description.toTestString())
assertEquals("x", name)
assertEquals(NodeKind.Parameter, kind)
assertEquals("parameter", content.summary.toTestString())
- assertEquals("Int", details.single().name)
+ assertEquals("Int", detail(NodeKind.Type).name)
assertTrue(members.none())
assertTrue(links.none())
}
diff --git a/core/testdata/format/bracket.html b/core/testdata/format/bracket.html
index 5630073d..1cd8ccd1 100644
--- a/core/testdata/format/bracket.html
+++ b/core/testdata/format/bracket.html
@@ -6,6 +6,7 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/foo">foo</a><br/>
<br/>
<h1>foo</h1>
+<a name="$foo()"></a>
<code><span class="keyword">fun </span><span class="identifier">foo</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<p>bar[]</p>
<br/>
diff --git a/core/testdata/format/brokenLink.html b/core/testdata/format/brokenLink.html
index 32135787..2f6d65cc 100644
--- a/core/testdata/format/brokenLink.html
+++ b/core/testdata/format/brokenLink.html
@@ -6,6 +6,7 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/f">f</a><br/>
<br/>
<h1>f</h1>
+<a name="$f()"></a>
<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<p>This references <a href="#">noSuchIdentifier</a>.</p>
<br/>
diff --git a/core/testdata/format/codeSpan.html b/core/testdata/format/codeSpan.html
index cc553043..ce633e7c 100644
--- a/core/testdata/format/codeSpan.html
+++ b/core/testdata/format/codeSpan.html
@@ -6,6 +6,7 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/foo">foo</a><br/>
<br/>
<h1>foo</h1>
+<a name="$foo()"></a>
<code><span class="keyword">fun </span><span class="identifier">foo</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<p>This is a <code>code span</code>.</p>
<br/>
diff --git a/core/testdata/format/deprecated.class.html b/core/testdata/format/deprecated.class.html
index b9939cd8..71470c63 100644
--- a/core/testdata/format/deprecated.class.html
+++ b/core/testdata/format/deprecated.class.html
@@ -13,6 +13,7 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/f">f</a><br/>
<br/>
<h1>f</h1>
+<a name="$f()"></a>
<code><span class="keyword">fun </span><s><span class="identifier">f</span></s><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<strong>Deprecated:</strong> This function sucks<br/>
<br/>
@@ -21,6 +22,7 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/p">p</a><br/>
<br/>
<h1>p</h1>
+<a name="$p"></a>
<code><span class="keyword">val </span><s><span class="identifier">p</span></s><span class="symbol">: </span><span class="identifier">Int</span></code><br/>
<strong>Deprecated:</strong> This property sucks<br/>
<br/>
diff --git a/core/testdata/format/htmlEscaping.html b/core/testdata/format/htmlEscaping.html
index a485c08f..f5b97781 100644
--- a/core/testdata/format/htmlEscaping.html
+++ b/core/testdata/format/htmlEscaping.html
@@ -6,6 +6,7 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/x">x</a><br/>
<br/>
<h1>x</h1>
+<a name="$x()"></a>
<code><span class="keyword">fun </span><span class="symbol">&lt;</span><span class="identifier">T</span><span class="symbol">&gt;</span> <span class="identifier">x</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">T</span><span class="symbol">?</span></code><br/>
<p>Special characters: &lt; is "less than", &gt; is "greater than", &amp; is "ampersand"</p>
<br/>
diff --git a/core/testdata/format/javaDeprecated.html b/core/testdata/format/javaDeprecated.html
index 236c6490..b378bf4f 100644
--- a/core/testdata/format/javaDeprecated.html
+++ b/core/testdata/format/javaDeprecated.html
@@ -6,6 +6,7 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/-foo/index">Foo</a>&nbsp;/&nbsp;<a href="test/-foo/foo">foo</a><br/>
<br/>
<h1>foo</h1>
+<a name="Foo$foo()"></a>
<code><span class="keyword">open</span> <span class="keyword">fun </span><s><span class="identifier">foo</span></s><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<strong>Deprecated:</strong> use <code><a href="test/-foo/bar">#bar</a></code> instead <p></p>
<br/>
diff --git a/core/testdata/format/javaSupertype.html b/core/testdata/format/javaSupertype.html
index 4c847281..8d626212 100644
--- a/core/testdata/format/javaSupertype.html
+++ b/core/testdata/format/javaSupertype.html
@@ -27,7 +27,7 @@
<td>
<a href="test/-c/-bar/return-foo">returnFoo</a></td>
<td>
-<code><span class="keyword">open</span> <span class="keyword">fun </span><span class="identifier">returnFoo</span><span class="symbol">(</span><span class="identifier">foo</span><span class="symbol">:</span>&nbsp;<a href="test/-c/-foo/index"><span class="identifier">Foo</span></a><span class="symbol">)</span><span class="symbol">: </span><a href="test/-c/-foo/index"><span class="identifier">Foo</span></a></code></td>
+<code><span class="keyword">open</span> <span class="keyword">fun </span><span class="identifier">returnFoo</span><span class="symbol">(</span><span class="identifier" id="C.Bar$returnFoo(C.Foo)/foo">foo</span><span class="symbol">:</span>&nbsp;<a href="test/-c/-foo/index"><span class="identifier">Foo</span></a><span class="symbol">)</span><span class="symbol">: </span><a href="test/-c/-foo/index"><span class="identifier">Foo</span></a></code></td>
</tr>
</tbody>
</table>
diff --git a/core/testdata/format/overloads.html b/core/testdata/format/overloads.html
index 896d79a9..3557f660 100644
--- a/core/testdata/format/overloads.html
+++ b/core/testdata/format/overloads.html
@@ -13,8 +13,8 @@
<td>
<a href="test/f">f</a></td>
<td>
-<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier">x</span><span class="symbol">:</span>&nbsp;<span class="identifier">Int</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
-<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier">x</span><span class="symbol">:</span>&nbsp;<span class="identifier">String</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><p>Performs an action on x.</p>
+<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier" id="$f(kotlin.Int)/x">x</span><span class="symbol">:</span>&nbsp;<span class="identifier">Int</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
+<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier" id="$f(kotlin.String)/x">x</span><span class="symbol">:</span>&nbsp;<span class="identifier">String</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><p>Performs an action on x.</p>
</td>
</tr>
</tbody>
diff --git a/core/testdata/format/overloadsWithDescription.html b/core/testdata/format/overloadsWithDescription.html
index a0efb472..1ab62981 100644
--- a/core/testdata/format/overloadsWithDescription.html
+++ b/core/testdata/format/overloadsWithDescription.html
@@ -6,9 +6,11 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/f">f</a><br/>
<br/>
<h1>f</h1>
-<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier">x</span><span class="symbol">:</span>&nbsp;<span class="identifier">Int</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
-<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier">x</span><span class="symbol">:</span>&nbsp;<span class="identifier">String</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
-<p>Performs an action on <a href="test/f#x">x</a>.</p>
+<a name="$f(kotlin.Int)"></a>
+<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier" id="$f(kotlin.Int)/x">x</span><span class="symbol">:</span>&nbsp;<span class="identifier">Int</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
+<a name="$f(kotlin.String)"></a>
+<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier" id="$f(kotlin.String)/x">x</span><span class="symbol">:</span>&nbsp;<span class="identifier">String</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
+<p>Performs an action on <a href="test/f#$f(kotlin.Int)/x">x</a>.</p>
<p>This is a long description.</p>
<br/>
<br/>
diff --git a/core/testdata/format/overloadsWithDifferentDescriptions.html b/core/testdata/format/overloadsWithDifferentDescriptions.html
index 30a37e75..eba1e0fc 100644
--- a/core/testdata/format/overloadsWithDifferentDescriptions.html
+++ b/core/testdata/format/overloadsWithDifferentDescriptions.html
@@ -6,7 +6,8 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/f">f</a><br/>
<br/>
<h1>f</h1>
-<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier">x</span><span class="symbol">:</span>&nbsp;<span class="identifier">Int</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
+<a name="$f(kotlin.Int)"></a>
+<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier" id="$f(kotlin.Int)/x">x</span><span class="symbol">:</span>&nbsp;<span class="identifier">Int</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<p>Performs an action on x.</p>
<p>This is a long description.</p>
<br/>
@@ -16,7 +17,8 @@
<code>x</code> - the int value to perform the action on.<br/>
<br/>
<br/>
-<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier">x</span><span class="symbol">:</span>&nbsp;<span class="identifier">String</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
+<a name="$f(kotlin.String)"></a>
+<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier" id="$f(kotlin.String)/x">x</span><span class="symbol">:</span>&nbsp;<span class="identifier">String</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<p>Performs an action on x.</p>
<p>This is a long description.</p>
<br/>
diff --git a/core/testdata/format/parameterAnchor.html b/core/testdata/format/parameterAnchor.html
index c5920fb7..717bb0fd 100644
--- a/core/testdata/format/parameterAnchor.html
+++ b/core/testdata/format/parameterAnchor.html
@@ -6,8 +6,9 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/process-files">processFiles</a><br/>
<br/>
<h1>processFiles</h1>
-<code><span class="keyword">fun </span><span class="symbol">&lt;</span><span class="identifier">T</span><span class="symbol">&gt;</span> <span class="identifier">processFiles</span><span class="symbol">(</span><span class="identifier">processor</span><span class="symbol">:</span>&nbsp;<span class="symbol">(</span><span class="symbol">)</span>&nbsp;<span class="symbol">-&gt;</span>&nbsp;<span class="identifier">T</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">List</span><span class="symbol">&lt;</span><span class="identifier">T</span><span class="symbol">&gt;</span></code><br/>
-<p>Runs <a href="test/process-files#processor">processor</a> for each file and collects its results into single list</p>
+<a name="$processFiles(kotlin.Function0((processFiles.T)))"></a>
+<code><span class="keyword">fun </span><span class="symbol">&lt;</span><span class="identifier">T</span><span class="symbol">&gt;</span> <span class="identifier">processFiles</span><span class="symbol">(</span><span class="identifier" id="$processFiles(kotlin.Function0((processFiles.T)))/processor">processor</span><span class="symbol">:</span>&nbsp;<span class="symbol">(</span><span class="symbol">)</span>&nbsp;<span class="symbol">-&gt;</span>&nbsp;<span class="identifier">T</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">List</span><span class="symbol">&lt;</span><span class="identifier">T</span><span class="symbol">&gt;</span></code><br/>
+<p>Runs <a href="test/process-files#$processFiles(kotlin.Function0((processFiles.T)))/processor">processor</a> for each file and collects its results into single list</p>
<h3>Parameters</h3>
<a name="processor"></a>
<code>processor</code> - function to receive context for symbol resolution and file for processing<br/>
diff --git a/core/testdata/format/parenthesis.html b/core/testdata/format/parenthesis.html
index c36b311b..b1266fd4 100644
--- a/core/testdata/format/parenthesis.html
+++ b/core/testdata/format/parenthesis.html
@@ -6,6 +6,7 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/foo">foo</a><br/>
<br/>
<h1>foo</h1>
+<a name="$foo()"></a>
<code><span class="keyword">fun </span><span class="identifier">foo</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<p>foo (bar)</p>
<br/>
diff --git a/core/testdata/format/see.html b/core/testdata/format/see.html
index b3ffb74b..e5ae4669 100644
--- a/core/testdata/format/see.html
+++ b/core/testdata/format/see.html
@@ -5,6 +5,7 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/quux">quux</a><br/>
<br/>
<h1>quux</h1>
+<a name="$quux()"></a>
<code><span class="keyword">fun </span><span class="identifier">quux</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<strong>See Also</strong><br/>
<p><a href="test/foo">foo</a></p>
@@ -15,12 +16,14 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/foo">foo</a><br/>
<br/>
<h1>foo</h1>
+<a name="$foo()"></a>
<code><span class="keyword">fun </span><span class="identifier">foo</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<br/>
<br/>
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/bar">bar</a><br/>
<br/>
<h1>bar</h1>
+<a name="$bar()"></a>
<code><span class="keyword">fun </span><span class="identifier">bar</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<br/>
<br/>
diff --git a/core/testdata/format/tripleBackticks.html b/core/testdata/format/tripleBackticks.html
index 13954985..4fe604c3 100644
--- a/core/testdata/format/tripleBackticks.html
+++ b/core/testdata/format/tripleBackticks.html
@@ -6,6 +6,7 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/f">f</a><br/>
<br/>
<h1>f</h1>
+<a name="$f()"></a>
<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<p>Description</p>
<pre><code>code sample</code></pre><br/>
diff --git a/core/testdata/format/uninterpretedEmphasisCharacters.html b/core/testdata/format/uninterpretedEmphasisCharacters.html
index 9afd88d9..00350140 100644
--- a/core/testdata/format/uninterpretedEmphasisCharacters.html
+++ b/core/testdata/format/uninterpretedEmphasisCharacters.html
@@ -6,6 +6,7 @@
<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/foo">foo</a><br/>
<br/>
<h1>foo</h1>
+<a name="$foo()"></a>
<code><span class="keyword">fun </span><span class="identifier">foo</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<p>This is <emph>emphasized text</emph> but text_with_underscores has to preserve the underscores.
Single stars embedded in a word like Embedded*Star have to be preserved as well.</p>