render annotations with @; render only @MustBeDocumented annotations; render all modifiers
diff --git a/.idea/runConfigurations/All_tests.xml b/.idea/runConfigurations/All_tests.xml
index b0528c8..57e4134 100644
--- a/.idea/runConfigurations/All_tests.xml
+++ b/.idea/runConfigurations/All_tests.xml
@@ -8,7 +8,7 @@
     <option name="MAIN_CLASS_NAME" value="" />
     <option name="METHOD_NAME" value="" />
     <option name="TEST_OBJECT" value="package" />
-    <option name="VM_PARAMETERS" value="" />
+    <option name="VM_PARAMETERS" value="-Xmx256m" />
     <option name="PARAMETERS" value="" />
     <option name="WORKING_DIRECTORY" value="" />
     <option name="ENV_VARIABLES" />
diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt
index bf33693..a02717f 100644
--- a/src/Kotlin/DocumentationBuilder.kt
+++ b/src/Kotlin/DocumentationBuilder.kt
@@ -15,12 +15,15 @@
 import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
 import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
 import org.jetbrains.kotlin.lexer.JetSingleValueToken
+import org.jetbrains.kotlin.lexer.JetTokens
 import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.psi.JetModifierListOwner
 import org.jetbrains.kotlin.psi.JetParameter
 import org.jetbrains.kotlin.resolve.DescriptorUtils
 import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
 import org.jetbrains.kotlin.resolve.constants.ConstantValue
 import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant
+import org.jetbrains.kotlin.resolve.descriptorUtil.isDocumentedAnnotation
 import org.jetbrains.kotlin.resolve.lazy.ResolveSession
 import org.jetbrains.kotlin.resolve.source.PsiSourceElement
 import org.jetbrains.kotlin.resolve.source.getPsi
@@ -50,6 +53,10 @@
     val boringBuiltinClasses = setOf(
             "kotlin.Unit", "kotlin.Byte", "kotlin.Short", "kotlin.Int", "kotlin.Long", "kotlin.Char", "kotlin.Boolean",
             "kotlin.Float", "kotlin.Double", "kotlin.String", "kotlin.Array", "kotlin.Any")
+    val knownModifiers = setOf(
+            JetTokens.PUBLIC_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.INTERNAL_KEYWORD, JetTokens.PRIVATE_KEYWORD,
+            JetTokens.OPEN_KEYWORD, JetTokens.FINAL_KEYWORD,
+            JetTokens.OVERRIDE_KEYWORD)
 
     fun parseDocumentation(descriptor: DeclarationDescriptor): Content {
         val kdoc = KDocFinder.findKDoc(descriptor) ?: findStdlibKDoc(descriptor)
@@ -328,7 +335,7 @@
         DescriptorUtils.getFqName(this).asString() in boringBuiltinClasses
 
     fun DocumentationNode.appendAnnotations(annotated: Annotated) {
-        annotated.getAnnotations().forEach {
+        annotated.annotations.filter { it.source.getPsi() != null && it.mustBeDocumented() }.forEach {
             val annotationNode = it.build()
             if (annotationNode != null) {
                 append(annotationNode,
@@ -337,6 +344,20 @@
         }
     }
 
+    fun AnnotationDescriptor.mustBeDocumented(): Boolean {
+        val annotationClass = type.constructor.declarationDescriptor as? Annotated ?: return false
+        return annotationClass.isDocumentedAnnotation()
+    }
+
+    fun DocumentationNode.appendModifiers(descriptor: DeclarationDescriptor) {
+        val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? JetModifierListOwner ?: return
+        JetTokens.MODIFIER_KEYWORDS_ARRAY.filter { it !in knownModifiers }.forEach {
+            if (psi.hasModifier(it)) {
+                appendTextNode(it.value, Kind.Modifier)
+            }
+        }
+    }
+
     fun DocumentationNode.isDeprecation() = name == "Deprecated" || name == "deprecated"
 
     fun DocumentationNode.appendSourceLink(sourceElement: SourceElement) {
@@ -442,9 +463,6 @@
             else -> Kind.Class
         }
         val node = DocumentationNode(this, kind)
-        if (isInner()) {
-            node.appendTextNode("inner", Kind.Modifier)
-        }
         node.appendSupertypes(this)
         if (getKind() != ClassKind.OBJECT && getKind() != ClassKind.ENUM_ENTRY) {
             node.appendInPageChildren(getTypeConstructor().getParameters(), DocumentationReference.Kind.Detail)
@@ -462,6 +480,7 @@
                     DocumentationReference.Kind.Member)
         }
         node.appendAnnotations(this)
+        node.appendModifiers(this)
         node.appendSourceLink(getSource())
         register(this, node)
         return node
@@ -504,6 +523,7 @@
         node.appendInPageChildren(getValueParameters(), DocumentationReference.Kind.Detail)
         node.appendType(getReturnType())
         node.appendAnnotations(this)
+        node.appendModifiers(this)
         node.appendSourceLink(getSource())
         node.appendOperatorOverloadNote(this)
 
@@ -584,6 +604,7 @@
         getExtensionReceiverParameter()?.let { node.appendChild(it, DocumentationReference.Kind.Detail) }
         node.appendType(getReturnType())
         node.appendAnnotations(this)
+        node.appendModifiers(this)
         node.appendSourceLink(getSource())
         if (isVar()) {
             node.appendTextNode("var", DocumentationNode.Kind.Modifier)
@@ -623,13 +644,7 @@
 
     fun ValueParameterDescriptor.build(): DocumentationNode {
         val node = DocumentationNode(this, Kind.Parameter)
-        val varargType = getVarargElementType()
-        if (varargType != null) {
-            node.appendTextNode("vararg", Kind.Annotation, DocumentationReference.Kind.Annotation)
-            node.appendType(varargType)
-        } else {
-            node.appendType(getType())
-        }
+        node.appendType(varargElementType ?: type)
         if (declaresDefaultValue()) {
             val psi = getSource().getPsi() as? JetParameter
             if (psi != null) {
@@ -640,6 +655,7 @@
             }
         }
         node.appendAnnotations(this)
+        node.appendModifiers(this)
         register(this, node)
         return node
     }
diff --git a/src/Kotlin/KotlinLanguageService.kt b/src/Kotlin/KotlinLanguageService.kt
index a22ba8a..d61db54 100644
--- a/src/Kotlin/KotlinLanguageService.kt
+++ b/src/Kotlin/KotlinLanguageService.kt
@@ -154,8 +154,9 @@
         }
     }
 
-    private fun ContentBlock.renderParameter(node: DocumentationNode) {
+    private fun ContentBlock.renderParameter(node: DocumentationNode, renderMode: RenderMode) {
         renderAnnotationsForNode(node)
+        renderModifiersForNode(node, renderMode)
         identifier(node.name, IdentifierKind.ParameterName)
         symbol(":")
         nbsp()
@@ -212,7 +213,7 @@
     }
 
     private fun ContentBlock.renderAnnotation(node: DocumentationNode) {
-        identifier(node.name, IdentifierKind.AnnotationName)
+        identifier("@" + node.name, IdentifierKind.AnnotationName)
         val parameters = node.details(DocumentationNode.Kind.Parameter)
         if (!parameters.isEmpty()) {
             symbol("(")
@@ -229,9 +230,9 @@
         renderAnnotationsForNode(node)
         when (node.kind) {
             DocumentationNode.Kind.Class,
-            DocumentationNode.Kind.AnnotationClass -> keyword("class ")
+            DocumentationNode.Kind.AnnotationClass,
+            DocumentationNode.Kind.Enum -> keyword("class ")
             DocumentationNode.Kind.Interface -> keyword("interface ")
-            DocumentationNode.Kind.Enum -> keyword("enum class ")
             DocumentationNode.Kind.EnumItem -> keyword("enum val ")
             DocumentationNode.Kind.Object -> keyword("object ")
             else -> throw IllegalArgumentException("Node $node is not a class-like object")
@@ -266,7 +267,7 @@
 
         symbol("(")
         renderList(node.details(DocumentationNode.Kind.Parameter)) {
-            renderParameter(it)
+            renderParameter(it, renderMode)
         }
         symbol(")")
         if (needReturnType(node)) {
diff --git a/test/data/classes/annotatedClass.kt b/test/data/classes/annotatedClass.kt
index 62c6f0e..1b58f56 100644
--- a/test/data/classes/annotatedClass.kt
+++ b/test/data/classes/annotatedClass.kt
@@ -1 +1 @@
-data class Foo() {}
+@Strictfp class Foo() {}
diff --git a/test/data/classes/dataClass.kt b/test/data/classes/dataClass.kt
new file mode 100644
index 0000000..62c6f0e
--- /dev/null
+++ b/test/data/classes/dataClass.kt
@@ -0,0 +1 @@
+data class Foo() {}
diff --git a/test/data/format/annotationParams.kt b/test/data/format/annotationParams.kt
index ee5b524..f259a74 100644
--- a/test/data/format/annotationParams.kt
+++ b/test/data/format/annotationParams.kt
@@ -1 +1 @@
-inlineOptions(InlineOption.LOCAL_CONTINUE_AND_BREAK) fun f() {}
+@JvmName("FFF") fun f() {}
diff --git a/test/data/format/annotationParams.md b/test/data/format/annotationParams.md
index 80fe52c..8cdd6e9 100644
--- a/test/data/format/annotationParams.md
+++ b/test/data/format/annotationParams.md
@@ -3,6 +3,6 @@
 
 # f
 
-`inlineOptions([InlineOption.LOCAL_CONTINUE_AND_BREAK]) fun f(): Unit`
+`@JvmName("FFF") fun f(): Unit`
 
 
diff --git a/test/data/functions/annotatedFunction.kt b/test/data/functions/annotatedFunction.kt
index 11c1967..f7abbf6 100644
--- a/test/data/functions/annotatedFunction.kt
+++ b/test/data/functions/annotatedFunction.kt
@@ -1,2 +1,2 @@
-inline fun f() {
+@Strictfp fun f() {
 }
diff --git a/test/data/functions/functionWithAnnotatedParam.kt b/test/data/functions/functionWithAnnotatedParam.kt
index 640bec8..f858e67 100644
--- a/test/data/functions/functionWithAnnotatedParam.kt
+++ b/test/data/functions/functionWithAnnotatedParam.kt
@@ -1,2 +1,7 @@
-fun function(noinline notInlined: () -> Unit) {
+@Target(AnnotationTarget.VALUE_PARAMETER)
+@Retention(AnnotationRetention.SOURCE)
+@MustBeDocumented
+public annotation class Fancy
+
+fun function(@Fancy notInlined: () -> Unit) {
 }
diff --git a/test/data/functions/functionWithNoinlineParam.kt b/test/data/functions/functionWithNoinlineParam.kt
new file mode 100644
index 0000000..640bec8
--- /dev/null
+++ b/test/data/functions/functionWithNoinlineParam.kt
@@ -0,0 +1,2 @@
+fun function(noinline notInlined: () -> Unit) {
+}
diff --git a/test/data/functions/functionWithNotDocumentedAnnotation.kt b/test/data/functions/functionWithNotDocumentedAnnotation.kt
new file mode 100644
index 0000000..3c7e2ff
--- /dev/null
+++ b/test/data/functions/functionWithNotDocumentedAnnotation.kt
@@ -0,0 +1,2 @@
+@Suppress("FOO") fun f() {
+}
diff --git a/test/data/functions/inlineFunction.kt b/test/data/functions/inlineFunction.kt
new file mode 100644
index 0000000..11c1967
--- /dev/null
+++ b/test/data/functions/inlineFunction.kt
@@ -0,0 +1,2 @@
+inline fun f() {
+}
diff --git a/test/data/properties/annotatedProperty.kt b/test/data/properties/annotatedProperty.kt
index f70c28b..8990af2 100644
--- a/test/data/properties/annotatedProperty.kt
+++ b/test/data/properties/annotatedProperty.kt
@@ -1 +1 @@
-inline val property = "test"
\ No newline at end of file
+@Volatile var property = "test"
\ No newline at end of file
diff --git a/test/src/TestAPI.kt b/test/src/TestAPI.kt
index 165278f..88d1903 100644
--- a/test/src/TestAPI.kt
+++ b/test/src/TestAPI.kt
@@ -9,7 +9,6 @@
 import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
 import org.jetbrains.kotlin.config.ContentRoot
 import org.jetbrains.kotlin.config.KotlinSourceRoot
-import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
 import org.junit.Assert
 import java.io.File
 import kotlin.test.fail
@@ -33,8 +32,10 @@
     }
 
     val environment = AnalysisEnvironment(messageCollector) {
-        val stringRoot = PathManager.getResourceRoot(javaClass<String>(), "/java/lang/String.class")
+        val stringRoot = PathManager.getResourceRoot(String::class.java, "/java/lang/String.class")
         addClasspath(File(stringRoot))
+        val kotlinPairRoot = PathManager.getResourceRoot(Pair::class.java, "/kotlin/Pair.class")
+        addClasspath(File(kotlinPairRoot))
         addRoots(roots.toList())
     }
     val options = DocumentationOptions(includeNonPublic = true, skipEmptyPackages = false, sourceLinks = listOf<SourceLinkDefinition>())
diff --git a/test/src/format/MarkdownFormatTest.kt b/test/src/format/MarkdownFormatTest.kt
index 059b491..8800305 100644
--- a/test/src/format/MarkdownFormatTest.kt
+++ b/test/src/format/MarkdownFormatTest.kt
@@ -1,7 +1,8 @@
 package org.jetbrains.dokka.tests
 
+import org.jetbrains.dokka.KotlinLanguageService
+import org.jetbrains.dokka.MarkdownFormatService
 import org.junit.Test
-import org.jetbrains.dokka.*
 
 public class MarkdownFormatTest {
     private val markdownService = MarkdownFormatService(InMemoryLocationService, KotlinLanguageService())
@@ -30,7 +31,7 @@
         }
     }
 
-    Test fun annotationParams() {
+    @Test fun annotationParams() {
         verifyOutput("test/data/format/annotationParams.kt", ".md") { model, output ->
             markdownService.appendNodes(tempLocation, output, model.members.single().members)
         }
diff --git a/test/src/model/ClassTest.kt b/test/src/model/ClassTest.kt
index 05fc2fc..bcedf49 100644
--- a/test/src/model/ClassTest.kt
+++ b/test/src/model/ClassTest.kt
@@ -1,8 +1,11 @@
 package org.jetbrains.dokka.tests
 
+import org.jetbrains.dokka.Content
+import org.jetbrains.dokka.DocumentationNode
+import org.jetbrains.dokka.DocumentationReference
 import org.junit.Test
-import kotlin.test.*
-import org.jetbrains.dokka.*
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
 
 public class ClassTest {
     Test fun emptyClass() {
@@ -148,19 +151,24 @@
         }
     }
 
-    Test fun annotatedClass() {
-        verifyModel("test/data/classes/annotatedClass.kt") { model ->
-            with(model.members.single().members.single()) {
-                assertEquals(1, annotations.count())
-                with(annotations[0]) {
-                    assertEquals("data", name)
-                    assertEquals(Content.Empty, content)
-                    assertEquals(DocumentationNode.Kind.Annotation, kind)
-                }
+    @Test fun annotatedClass() {
+        verifyPackageMember("test/data/classes/annotatedClass.kt") { cls ->
+            assertEquals(1, cls.annotations.count())
+            with(cls.annotations[0]) {
+                assertEquals("Strictfp", name)
+                assertEquals(Content.Empty, content)
+                assertEquals(DocumentationNode.Kind.Annotation, kind)
             }
         }
     }
 
+    @Test fun dataClass() {
+        verifyPackageMember("test/data/classes/dataClass.kt") { cls ->
+            val modifiers = cls.details(DocumentationNode.Kind.Modifier).map { it.name }
+            assertTrue("data" in modifiers)
+        }
+    }
+
     Test fun annotatedClassWithAnnotationParameters() {
         verifyModel("test/data/classes/annotatedClassWithAnnotationParameters.kt") { model ->
             with(model.members.single().members.single()) {
diff --git a/test/src/model/FunctionTest.kt b/test/src/model/FunctionTest.kt
index 80ae223..734675d 100644
--- a/test/src/model/FunctionTest.kt
+++ b/test/src/model/FunctionTest.kt
@@ -7,7 +7,7 @@
 import kotlin.test.assertTrue
 
 public class FunctionTest {
-    Test fun function() {
+    @Test fun function() {
         verifyModel("test/data/functions/function.kt") { model ->
             with(model.members.single().members.single()) {
                 assertEquals("fn", name)
@@ -20,7 +20,7 @@
         }
     }
 
-    Test fun functionWithReceiver() {
+    @Test fun functionWithReceiver() {
         verifyModel("test/data/functions/functionWithReceiver.kt") { model ->
             with(model.members.single().members.single()) {
                 assertEquals("String", name)
@@ -52,7 +52,7 @@
         }
     }
 
-    Test fun genericFunction() {
+    @Test fun genericFunction() {
         verifyModel("test/data/functions/genericFunction.kt") { model ->
             with(model.members.single().members.single()) {
                 assertEquals("generic", name)
@@ -76,7 +76,7 @@
             }
         }
     }
-    Test fun genericFunctionWithConstraints() {
+    @Test fun genericFunctionWithConstraints() {
         verifyModel("test/data/functions/genericFunctionWithConstraints.kt") { model ->
             with(model.members.single().members.single()) {
                 assertEquals("generic", name)
@@ -115,7 +115,7 @@
         }
     }
 
-    Test fun functionWithParams() {
+    @Test fun functionWithParams() {
         verifyModel("test/data/functions/functionWithParams.kt") { model ->
             with(model.members.single().members.single()) {
                 assertEquals("function", name)
@@ -141,30 +141,50 @@
         }
     }
 
-    Test fun annotatedFunction() {
-        verifyModel("test/data/functions/annotatedFunction.kt") { model ->
-            with(model.members.single().members.single()) {
-                assertEquals(1, annotations.count())
-                with(annotations[0]) {
-                    assertEquals("inline", name)
-                    assertEquals(Content.Empty, content)
-                    assertEquals(DocumentationNode.Kind.Annotation, kind)
+    @Test fun annotatedFunction() {
+        verifyPackageMember("test/data/functions/annotatedFunction.kt") { func ->
+            assertEquals(1, func.annotations.count())
+            with(func.annotations[0]) {
+                assertEquals("Strictfp", name)
+                assertEquals(Content.Empty, content)
+                assertEquals(DocumentationNode.Kind.Annotation, kind)
+            }
+        }
+    }
+
+    @Test fun functionWithNotDocumentedAnnotation() {
+        verifyPackageMember("test/data/functions/functionWithNotDocumentedAnnotation.kt") { func ->
+            assertEquals(0, func.annotations.count())
+        }
+    }
+
+    @Test fun inlineFunction() {
+        verifyPackageMember("test/data/functions/inlineFunction.kt") { func ->
+            val modifiers = func.details(DocumentationNode.Kind.Modifier).map { it.name }
+            assertTrue("inline" in modifiers)
+        }
+    }
+
+    @Test fun functionWithAnnotatedParam() {
+        verifyModel("test/data/functions/functionWithAnnotatedParam.kt") { model ->
+            with(model.members.single().members.single { it.name == "function"} ) {
+                with(details.elementAt(2)) {
+                    assertEquals(1, annotations.count())
+                    with(annotations[0]) {
+                        assertEquals("Fancy", name)
+                        assertEquals(Content.Empty, content)
+                        assertEquals(DocumentationNode.Kind.Annotation, kind)
+                    }
                 }
             }
         }
     }
 
-    Test fun functionWithAnnotatedParam() {
-        verifyModel("test/data/functions/functionWithAnnotatedParam.kt") { model ->
-            with(model.members.single().members.single()) {
-                with(details.elementAt(2)) {
-                    assertEquals(1, annotations.count())
-                    with(annotations[0]) {
-                        assertEquals("noinline", name)
-                        assertEquals(Content.Empty, content)
-                        assertEquals(DocumentationNode.Kind.Annotation, kind)
-                    }
-                }
+    @Test fun functionWithNoinlineParam() {
+        verifyPackageMember("test/data/functions/functionWithNoinlineParam.kt") { func ->
+            with(func.details.elementAt(2)) {
+                val modifiers = details(DocumentationNode.Kind.Modifier).map { it.name }
+                assertTrue("noinline" in modifiers)
             }
         }
     }
diff --git a/test/src/model/PropertyTest.kt b/test/src/model/PropertyTest.kt
index 405b260..0853cbc 100644
--- a/test/src/model/PropertyTest.kt
+++ b/test/src/model/PropertyTest.kt
@@ -69,7 +69,7 @@
             with(model.members.single().members.single()) {
                 assertEquals(1, annotations.count())
                 with(annotations[0]) {
-                    assertEquals("inline", name)
+                    assertEquals("Volatile", name)
                     assertEquals(Content.Empty, content)
                     assertEquals(DocumentationNode.Kind.Annotation, kind)
                 }