From 972316cbfa6170c232ed275528e91dc1cdadae98 Mon Sep 17 00:00:00 2001 From: Tor Norbye Date: Mon, 15 Dec 2025 18:59:34 -0800 Subject: [PATCH] 1.6.9: Compatibility with IntelliJ 2025.3 --- .gitignore | 1 + CHANGELOG.md | 3 + README.md | 2 +- build.gradle | 6 +- .../cli/KDocFileFormattingOptions.kt | 6 +- .../kdocformatter/cli/EditorConfigsTest.kt | 2 +- .../cli/KDocFileFormatterTest.kt | 1644 ++--- gradle/wrapper/gradle-wrapper.jar | Bin 43764 -> 43705 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 4 +- gradlew.bat | 4 +- ide-plugin/CHANGELOG.md | 3 + ide-plugin/build.gradle.kts | 4 +- ide-plugin/gradle.properties | 6 +- library/build.gradle | 2 +- library/src/main/resources/version.properties | 2 +- .../facebook/ktfmt/kdoc/KDocFormatterTest.kt | 6564 ++++++++--------- 17 files changed, 4131 insertions(+), 4124 deletions(-) diff --git a/.gitignore b/.gitignore index 9c8ff27..ae7afa7 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ m2 *.swp .intellijPlatform .kotlin +local.properties diff --git a/CHANGELOG.md b/CHANGELOG.md index 8974045..9f75002 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ # KDoc Formatter Changelog +## [1.6.9] +- IDE-only update: Marked compatible with IntelliJ IDEA 2025.3. + ## [1.6.8] - IDE-only update: Marked compatible with IntelliJ IDEA 2025.2. diff --git a/README.md b/README.md index 9fcb527..8de3ef7 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ Options: @ Read filenames from file. -kdoc-formatter: Version 1.6.8 +kdoc-formatter: Version 1.6.9 https://github.com/tnorbye/kdoc-formatter ``` diff --git a/build.gradle b/build.gradle index dae7fc3..189d6a5 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { apply from: "$rootDir/version.gradle" ext { - gradlePluginVersion = '8.7.1' + gradlePluginVersion = '8.13.2' } repositories { @@ -17,8 +17,8 @@ buildscript { plugins { id 'java' - id 'org.jetbrains.kotlin.jvm' version '2.1.21' - id 'com.ncorti.ktfmt.gradle' version '0.22.0' + id 'org.jetbrains.kotlin.jvm' version '2.2.21' + id 'com.ncorti.ktfmt.gradle' version '0.25.0' } group 'kdocformatter' diff --git a/cli/src/main/kotlin/kdocformatter/cli/KDocFileFormattingOptions.kt b/cli/src/main/kotlin/kdocformatter/cli/KDocFileFormattingOptions.kt index ca573bf..09ae2a4 100644 --- a/cli/src/main/kotlin/kdocformatter/cli/KDocFileFormattingOptions.kt +++ b/cli/src/main/kotlin/kdocformatter/cli/KDocFileFormattingOptions.kt @@ -308,10 +308,10 @@ class KDocFileFormattingOptions { } return """ - Usage: kdoc-formatter [options] file(s) + Usage: kdoc-formatter [options] file(s) - Options: - """ + Options: + """ .trimIndent() + "\n" + formattedOptions + diff --git a/cli/src/test/kotlin/kdocformatter/cli/EditorConfigsTest.kt b/cli/src/test/kotlin/kdocformatter/cli/EditorConfigsTest.kt index afdf7c0..dd95a1e 100644 --- a/cli/src/test/kotlin/kdocformatter/cli/EditorConfigsTest.kt +++ b/cli/src/test/kotlin/kdocformatter/cli/EditorConfigsTest.kt @@ -28,7 +28,7 @@ class EditorConfigsTest { @TempDir @JvmField var temporaryFolder: File? = null } - class ConfigFile(val relativePath: String, @Language("EditorConfig") val contents: String) + class ConfigFile(val relativePath: String, @param:Language("EditorConfig") val contents: String) private fun createFileTree(vararg files: ConfigFile): File { val root = temporaryFolder!! diff --git a/cli/src/test/kotlin/kdocformatter/cli/KDocFileFormatterTest.kt b/cli/src/test/kotlin/kdocformatter/cli/KDocFileFormatterTest.kt index 07dc4ed..d40d0a8 100644 --- a/cli/src/test/kotlin/kdocformatter/cli/KDocFileFormatterTest.kt +++ b/cli/src/test/kotlin/kdocformatter/cli/KDocFileFormatterTest.kt @@ -56,61 +56,61 @@ class KDocFileFormatterTest { fun test() { val source = """ - class Test { - /** - * Returns whether lint should check all warnings, - * including those off by default, or null if - *not configured in this configuration. This is a really really really long sentence which needs to be broken up. - * And ThisIsALongSentenceWhichCannotBeBrokenUpAndMustBeIncludedAsAWholeWithoutNewlinesInTheMiddle. - * - * This is a separate section - * which should be flowed together with the first one. - * *bold* should not be removed even at beginning. - */ - private var checkAllWarnings: Boolean? = null - - /** Returns whether lint should check all warnings, - * including those off by default */ // additional - private var ignoreAll: Boolean? = null - - private val string = ""\" - /** This is NOT - a comment to reformat, it's - in a string */ - ""\" - } - """ + class Test { + /** + * Returns whether lint should check all warnings, + * including those off by default, or null if + *not configured in this configuration. This is a really really really long sentence which needs to be broken up. + * And ThisIsALongSentenceWhichCannotBeBrokenUpAndMustBeIncludedAsAWholeWithoutNewlinesInTheMiddle. + * + * This is a separate section + * which should be flowed together with the first one. + * *bold* should not be removed even at beginning. + */ + private var checkAllWarnings: Boolean? = null + + /** Returns whether lint should check all warnings, + * including those off by default */ // additional + private var ignoreAll: Boolean? = null + + private val string = ""\" + /** This is NOT + a comment to reformat, it's + in a string */ + ""\" + } + """ .trimIndent() val reformatted = reformatFile(source, KDocFormattingOptions(72)) assertEquals( """ - class Test { - /** - * Returns whether lint should check all warnings, including those - * off by default, or null if not configured in this configuration. - * This is a really really really long sentence which needs to be - * broken up. And - * ThisIsALongSentenceWhichCannotBeBrokenUpAndMustBeIncludedAsAWholeWithoutNewlinesInTheMiddle. - * - * This is a separate section which should be flowed together with - * the first one. *bold* should not be removed even at beginning. - */ - private var checkAllWarnings: Boolean? = null - - /** - * Returns whether lint should check all warnings, including those - * off by default - */ // additional - private var ignoreAll: Boolean? = null - - private val string = ""\" - /** This is NOT - a comment to reformat, it's - in a string */ - ""\" - } - """ + class Test { + /** + * Returns whether lint should check all warnings, including those + * off by default, or null if not configured in this configuration. + * This is a really really really long sentence which needs to be + * broken up. And + * ThisIsALongSentenceWhichCannotBeBrokenUpAndMustBeIncludedAsAWholeWithoutNewlinesInTheMiddle. + * + * This is a separate section which should be flowed together with + * the first one. *bold* should not be removed even at beginning. + */ + private var checkAllWarnings: Boolean? = null + + /** + * Returns whether lint should check all warnings, including those + * off by default + */ // additional + private var ignoreAll: Boolean? = null + + private val string = ""\" + /** This is NOT + a comment to reformat, it's + in a string */ + ""\" + } + """ .trimIndent(), reformatted) } @@ -119,24 +119,24 @@ class KDocFileFormatterTest { fun testBlockComment() { val source = """ - @file:JvmName("Constraints") + @file:JvmName("Constraints") - /* Copyright notice. - We don't touch this. + /* Copyright notice. + We don't touch this. + */ + class Test { + /* + * Returns whether lint should check all warnings, + * including those off by default, or null if + *not configured in this configuration. This is a really really really long sentence which needs to be broken up. + * + * Separate paragraph. */ - class Test { - /* - * Returns whether lint should check all warnings, - * including those off by default, or null if - *not configured in this configuration. This is a really really really long sentence which needs to be broken up. - * - * Separate paragraph. - */ - // We're not - // reformatting - // line comments in this test - } - """ + // We're not + // reformatting + // line comments in this test + } + """ .trimIndent() val reformatted = @@ -146,26 +146,26 @@ class KDocFileFormatterTest { KDocFileFormattingOptions().apply { blockComments = true }) assertEquals( """ - @file:JvmName("Constraints") + @file:JvmName("Constraints") - /* Copyright notice. - We don't touch this. - */ - class Test { - /* - Returns whether lint should check all - warnings, including those off by default, or - null if not configured in this configuration. - This is a really really really long - sentence which needs to be broken up. - - Separate paragraph. - */ - // We're not - // reformatting - // line comments in this test - } - """ + /* Copyright notice. + We don't touch this. + */ + class Test { + /* + Returns whether lint should check all + warnings, including those off by default, or + null if not configured in this configuration. + This is a really really really long + sentence which needs to be broken up. + + Separate paragraph. + */ + // We're not + // reformatting + // line comments in this test + } + """ .trimIndent(), reformatted) } @@ -174,28 +174,28 @@ class KDocFileFormatterTest { fun testFit() { val source = """ - class Test { - ... - ":app:writeDebugSigningConfigVersions", /** Intentionally not cacheable. See [com.android.build.gradle.internal.tasks.SigningConfigVersionsWriterTask] */ + class Test { + ... + ":app:writeDebugSigningConfigVersions", /** Intentionally not cacheable. See [com.android.build.gradle.internal.tasks.SigningConfigVersionsWriterTask] */ - ":feature1:checkDebugAarMetadata", - } - """ + ":feature1:checkDebugAarMetadata", + } + """ .trimIndent() val reformatted = reformatFile(source, KDocFormattingOptions(72)) assertEquals( """ - class Test { - ... - ":app:writeDebugSigningConfigVersions", - /** - * Intentionally not cacheable. See - * [com.android.build.gradle.internal.tasks.SigningConfigVersionsWriterTask] - */ - - ":feature1:checkDebugAarMetadata", - } - """ + class Test { + ... + ":app:writeDebugSigningConfigVersions", + /** + * Intentionally not cacheable. See + * [com.android.build.gradle.internal.tasks.SigningConfigVersionsWriterTask] + */ + + ":feature1:checkDebugAarMetadata", + } + """ .trimIndent(), reformatted) } @@ -205,12 +205,12 @@ class KDocFileFormatterTest { // https://github.com/tnorbye/kdoc-formatter/issues/76 val source = """ - /** - * Sample summary. - * - * More summary. - */ - """ + /** + * Sample summary. + * + * More summary. + */ + """ .trimIndent() .replace("\n", "\r\n") val reformatted = reformatFile(source, KDocFormattingOptions(72)) @@ -221,32 +221,32 @@ class KDocFileFormatterTest { fun testLineComment() { val source = """ - class Test { - /* - * we're not reformatting - * block comments - * in this test - */ - // We *ARE* - // reformatting - // line comments in this test - var x: String = 0; // Some - // more comments here that won't fit on @the same line. - var y: String = 0; // Some - // more comments here that won't fit [on - // the same - // line]. - - // This is separate - - fun test() { - if (lineWithIndentation.startsWith(" ") && // markdown preformatted text - (i == 1 || lineContent(lines[i - 2]).isBlank()) && // we've already ++'ed i above. - // Make sure it's not just deeply indented inside a different block - (paragraph.prev == null) - } - } - """ + class Test { + /* + * we're not reformatting + * block comments + * in this test + */ + // We *ARE* + // reformatting + // line comments in this test + var x: String = 0; // Some + // more comments here that won't fit on @the same line. + var y: String = 0; // Some + // more comments here that won't fit [on + // the same + // line]. + + // This is separate + + fun test() { + if (lineWithIndentation.startsWith(" ") && // markdown preformatted text + (i == 1 || lineContent(lines[i - 2]).isBlank()) && // we've already ++'ed i above. + // Make sure it's not just deeply indented inside a different block + (paragraph.prev == null) + } + } + """ .trimIndent() val reformatted = @@ -256,34 +256,34 @@ class KDocFileFormatterTest { KDocFileFormattingOptions().apply { lineComments = true }) assertEquals( """ - class Test { - /* - * we're not reformatting - * block comments - * in this test - */ - // We *ARE* reformatting line comments in - // this test - var x: String = 0; // Some more comments here - // that won't fit on @the same line. - var y: String = 0; // Some more comments here - // that won't fit [on the - // same line]. - - // This is separate - - fun test() { - if (lineWithIndentation.startsWith(" ") && - // markdown preformatted text - (i == 1 || lineContent(lines[i - 2]).isBlank()) && - // we've already ++'ed i above. - // Make sure it's not just deeply - // indented inside a different - // block - (paragraph.prev == null) - } - } - """ + class Test { + /* + * we're not reformatting + * block comments + * in this test + */ + // We *ARE* reformatting line comments in + // this test + var x: String = 0; // Some more comments here + // that won't fit on @the same line. + var y: String = 0; // Some more comments here + // that won't fit [on the + // same line]. + + // This is separate + + fun test() { + if (lineWithIndentation.startsWith(" ") && + // markdown preformatted text + (i == 1 || lineContent(lines[i - 2]).isBlank()) && + // we've already ++'ed i above. + // Make sure it's not just deeply + // indented inside a different + // block + (paragraph.prev == null) + } + } + """ .trimIndent(), reformatted) } @@ -292,80 +292,80 @@ class KDocFileFormatterTest { fun testReorderParameters() { val source = """ - class Test { - /** My comment - * @param third Description of third parameter - * @param second Description of second parameter - * @param first Description of first parameter */ - @Suppress("all") - fun test(first: String, @Suppress("unused") second: String, vararg third: String): String = "hello world" - - /** - * @param fourth Desc 4 - * @param third Desc 3 - * @param second Desc 2 - * @param first Desc 1 - */ - fun `test(third)`( - first: MutableMap>?, - // fourth: Boolean = false, - second: Boolean = false, - third: String = "fun(test: String, test2: String)", - /* , first: String */ - fourth: (Collection) -> Unit = {} - ) { - } - - /** - * (Signature and doc list different parameters) - * @param foo Desc 1 - * @param baz Desc 2 - */ - fun test2(foo: String, bar: String) { - } + class Test { + /** My comment + * @param third Description of third parameter + * @param second Description of second parameter + * @param first Description of first parameter */ + @Suppress("all") + fun test(first: String, @Suppress("unused") second: String, vararg third: String): String = "hello world" + + /** + * @param fourth Desc 4 + * @param third Desc 3 + * @param second Desc 2 + * @param first Desc 1 + */ + fun `test(third)`( + first: MutableMap>?, + // fourth: Boolean = false, + second: Boolean = false, + third: String = "fun(test: String, test2: String)", + /* , first: String */ + fourth: (Collection) -> Unit = {} + ) { } - """ + + /** + * (Signature and doc list different parameters) + * @param foo Desc 1 + * @param baz Desc 2 + */ + fun test2(foo: String, bar: String) { + } + } + """ .trimIndent() val reformatted = reformatFile(source, KDocFormattingOptions(72).apply { orderDocTags = true }) assertEquals( """ - class Test { - /** - * My comment - * - * @param first Description of first parameter - * @param second Description of second parameter - * @param third Description of third parameter - */ - @Suppress("all") - fun test(first: String, @Suppress("unused") second: String, vararg third: String): String = "hello world" - - /** - * @param first Desc 1 - * @param second Desc 2 - * @param third Desc 3 - * @param fourth Desc 4 - */ - fun `test(third)`( - first: MutableMap>?, - // fourth: Boolean = false, - second: Boolean = false, - third: String = "fun(test: String, test2: String)", - /* , first: String */ - fourth: (Collection) -> Unit = {} - ) { - } - - /** - * (Signature and doc list different parameters) - * - * @param foo Desc 1 - * @param baz Desc 2 - */ - fun test2(foo: String, bar: String) { - } + class Test { + /** + * My comment + * + * @param first Description of first parameter + * @param second Description of second parameter + * @param third Description of third parameter + */ + @Suppress("all") + fun test(first: String, @Suppress("unused") second: String, vararg third: String): String = "hello world" + + /** + * @param first Desc 1 + * @param second Desc 2 + * @param third Desc 3 + * @param fourth Desc 4 + */ + fun `test(third)`( + first: MutableMap>?, + // fourth: Boolean = false, + second: Boolean = false, + third: String = "fun(test: String, test2: String)", + /* , first: String */ + fourth: (Collection) -> Unit = {} + ) { } - """ + + /** + * (Signature and doc list different parameters) + * + * @param foo Desc 1 + * @param baz Desc 2 + */ + fun test2(foo: String, bar: String) { + } + } + """ .trimIndent(), reformatted.trim()) } @@ -419,47 +419,47 @@ class KDocFileFormatterTest { val reformatted = reformatFile(source, KDocFormattingOptions(72).apply { orderDocTags = true }) assertEquals( """ - class KType - class Test { - /** - * @param T The type of the instance to be created. - * @param type The [KType] representing the type to be instantiated. - * @return An instance of the specified type, or `null` if - * instantiation fails. - */ - public fun createInstance(type: KType): T? { - return null - } - } - + class KType + class Test { /** - * @param S the stage - * @param T the view - * @param clazz the class - * @param constructor to invoke + * @param T The type of the instance to be created. + * @param type The [KType] representing the type to be instantiated. + * @return An instance of the specified type, or `null` if + * instantiation fails. */ - fun ?, T : StageView<*>?> bind(clazz: Class, constructor: BiFunction) { + public fun createInstance(type: KType): T? { + return null } + } - object Kt { - /** - * Run the loop and wait until condition is true or the retry limit is - * reached. Returns the result afterwards. - * - * @param type of the desired result. - * @param supplier a function that returns the desired result. - * @param condition tests whether the result is desired. - * @param retryLimit Limit to retry before return the result. If not - * specified, try forever. - * @return the result from the last run (condition met or timeout). - */ - fun waitForAndReturn( - supplier: () -> T, - condition: (T) -> Boolean, - retryLimit: Int = NO_LIMIT, - ): T = TODO() - } - """ + /** + * @param S the stage + * @param T the view + * @param clazz the class + * @param constructor to invoke + */ + fun ?, T : StageView<*>?> bind(clazz: Class, constructor: BiFunction) { + } + + object Kt { + /** + * Run the loop and wait until condition is true or the retry limit is + * reached. Returns the result afterwards. + * + * @param type of the desired result. + * @param supplier a function that returns the desired result. + * @param condition tests whether the result is desired. + * @param retryLimit Limit to retry before return the result. If not + * specified, try forever. + * @return the result from the last run (condition met or timeout). + */ + fun waitForAndReturn( + supplier: () -> T, + condition: (T) -> Boolean, + retryLimit: Int = NO_LIMIT, + ): T = TODO() + } + """ .trimIndent(), reformatted.trim()) } @@ -470,29 +470,29 @@ class KDocFileFormatterTest { // for indent! val source = """ - //3456789012345678901234567890 <- 30 - /** - * This should fit on a single - * - * And this should also fit!! - * - * And this should not!!!!!!!!! - */ - """ + //3456789012345678901234567890 <- 30 + /** + * This should fit on a single + * + * And this should also fit!! + * + * And this should not!!!!!!!!! + */ + """ .trimIndent() val reformatted = """ - //3456789012345678901234567890 <- 30 - /** - * This should fit on a single - * - * And this should also fit!! - * - * And this should - * not!!!!!!!!! - */ - """ + //3456789012345678901234567890 <- 30 + /** + * This should fit on a single + * + * And this should also fit!! + * + * And this should + * not!!!!!!!!! + */ + """ .trimIndent() assertEquals( @@ -569,24 +569,24 @@ class KDocFileFormatterTest { fun testLineSuffixFits() { val source = """ - class ComposeIssueNotificationAction( - private val createInformationPopup: (Project, ComposePreviewManager, DataContext) -> InformationPopup = ::defaultCreateInformationPopup) - : AnAction(), RightAlignedToolbarAction, CustomComponentAction, Disposable { /** - * [Alarm] used to trigger the popup as a hint. - */ - private val popupAlarm = Alarm() - } - """ + class ComposeIssueNotificationAction( + private val createInformationPopup: (Project, ComposePreviewManager, DataContext) -> InformationPopup = ::defaultCreateInformationPopup) + : AnAction(), RightAlignedToolbarAction, CustomComponentAction, Disposable { /** + * [Alarm] used to trigger the popup as a hint. + */ + private val popupAlarm = Alarm() + } + """ .trimIndent() val reformatted = reformatFile(source, KDocFormattingOptions(1000, 1000)) assertEquals( """ - class ComposeIssueNotificationAction( - private val createInformationPopup: (Project, ComposePreviewManager, DataContext) -> InformationPopup = ::defaultCreateInformationPopup) - : AnAction(), RightAlignedToolbarAction, CustomComponentAction, Disposable { /** [Alarm] used to trigger the popup as a hint. */ - private val popupAlarm = Alarm() - } - """ + class ComposeIssueNotificationAction( + private val createInformationPopup: (Project, ComposePreviewManager, DataContext) -> InformationPopup = ::defaultCreateInformationPopup) + : AnAction(), RightAlignedToolbarAction, CustomComponentAction, Disposable { /** [Alarm] used to trigger the popup as a hint. */ + private val popupAlarm = Alarm() + } + """ .trimIndent(), reformatted) } @@ -595,39 +595,39 @@ class KDocFileFormatterTest { fun testLineSuffixDoesNotFit() { val source = """ - class ComposeIssueNotificationAction( - private val createInformationPopup: (Project, ComposePreviewManager, DataContext) -> InformationPopup = ::defaultCreateInformationPopup) - : AnAction(), RightAlignedToolbarAction, CustomComponentAction, Disposable { /** - * [Alarm] used to trigger the popup as a hint. - */ - private val popupAlarm = Alarm() - } - """ + class ComposeIssueNotificationAction( + private val createInformationPopup: (Project, ComposePreviewManager, DataContext) -> InformationPopup = ::defaultCreateInformationPopup) + : AnAction(), RightAlignedToolbarAction, CustomComponentAction, Disposable { /** + * [Alarm] used to trigger the popup as a hint. + */ + private val popupAlarm = Alarm() + } + """ .trimIndent() assertEquals( """ - class ComposeIssueNotificationAction( - private val createInformationPopup: (Project, ComposePreviewManager, DataContext) -> InformationPopup = ::defaultCreateInformationPopup) - : AnAction(), RightAlignedToolbarAction, CustomComponentAction, Disposable { - /** [Alarm] used to trigger the popup as a hint. */ - private val popupAlarm = Alarm() - } - """ + class ComposeIssueNotificationAction( + private val createInformationPopup: (Project, ComposePreviewManager, DataContext) -> InformationPopup = ::defaultCreateInformationPopup) + : AnAction(), RightAlignedToolbarAction, CustomComponentAction, Disposable { + /** [Alarm] used to trigger the popup as a hint. */ + private val popupAlarm = Alarm() + } + """ .trimIndent(), reformatFile(source, KDocFormattingOptions(60, 60))) assertEquals( """ - class ComposeIssueNotificationAction( - private val createInformationPopup: (Project, ComposePreviewManager, DataContext) -> InformationPopup = ::defaultCreateInformationPopup) - : AnAction(), RightAlignedToolbarAction, CustomComponentAction, Disposable { - /** - * [Alarm] used to trigger the popup as a hint. - */ - private val popupAlarm = Alarm() - } - """ + class ComposeIssueNotificationAction( + private val createInformationPopup: (Project, ComposePreviewManager, DataContext) -> InformationPopup = ::defaultCreateInformationPopup) + : AnAction(), RightAlignedToolbarAction, CustomComponentAction, Disposable { + /** + * [Alarm] used to trigger the popup as a hint. + */ + private val popupAlarm = Alarm() + } + """ .trimIndent(), reformatFile(source, KDocFormattingOptions(100, 72).apply { collapseSingleLine = false })) } @@ -637,13 +637,13 @@ class KDocFileFormatterTest { // Regression test for https://github.com/tnorbye/kdoc-formatter/issues/42 val source = """ - @Suppress("SpellCheckingInspection") - /** - * Lorem ipsum dolor sit amet, consectetur adipiscing elit. - */ - fun KDocFormatterTest() { - } - """ + @Suppress("SpellCheckingInspection") + /** + * Lorem ipsum dolor sit amet, consectetur adipiscing elit. + */ + fun KDocFormatterTest() { + } + """ .trimIndent() assertEquals(source, reformatFile(source, KDocFormattingOptions(60, 60))) @@ -653,15 +653,15 @@ class KDocFileFormatterTest { fun testGreedyVsOptimal() { val source = """ - # KDoc Formatter Plugin Changelog - - ## [1.5.5] - - Improved support for .editorconfig files; these settings will now be - reflected immediately (in prior versions you had to restart the IDE - because they were improperly cached) - - Fixed a copy/paste bug which prevented the "Collapse short comments - that fit on a single line" option from working. - """ + # KDoc Formatter Plugin Changelog + + ## [1.5.5] + - Improved support for .editorconfig files; these settings will now be + reflected immediately (in prior versions you had to restart the IDE + because they were improperly cached) + - Fixed a copy/paste bug which prevented the "Collapse short comments + that fit on a single line" option from working. + """ .trimIndent() assertEquals(source, reformatFile(source, KDocFormattingOptions(72), markdown = true)) @@ -671,48 +671,48 @@ class KDocFileFormatterTest { fun testGitRanges() { val source = """ - class Test { - /** - * Returns whether lint should check all warnings, - * including those off by default, or null if - *not configured in this configuration. This is a really really really long sentence which needs to be broken up. - * And ThisIsALongSentenceWhichCannotBeBrokenUpAndMustBeIncludedAsAWholeWithoutNewlinesInTheMiddle. - * - * This is a separate section - * which should be flowed together with the first one. - * *bold* should not be removed even at beginning. - */ - private var checkAllWarnings: Boolean? = null - - /** Returns whether lint should check all warnings, - * including those off by default */ // additional - private var ignoreAll: Boolean? = null - } - """ + class Test { + /** + * Returns whether lint should check all warnings, + * including those off by default, or null if + *not configured in this configuration. This is a really really really long sentence which needs to be broken up. + * And ThisIsALongSentenceWhichCannotBeBrokenUpAndMustBeIncludedAsAWholeWithoutNewlinesInTheMiddle. + * + * This is a separate section + * which should be flowed together with the first one. + * *bold* should not be removed even at beginning. + */ + private var checkAllWarnings: Boolean? = null + + /** Returns whether lint should check all warnings, + * including those off by default */ // additional + private var ignoreAll: Boolean? = null + } + """ .trimIndent() val diff = """ - diff --git a/README.md b/README.md - index c26815b..30a8dbb 100644 - --- README.md - +++ README.md - @@ -31,25 +31,29 @@ ${'$'} kdoc-formatter - Usage: kdoc-formatter [options] file(s) - diff --git Test.kt Test.kt - index d66825c..7a324fb 100644 - --- Test.kt - +++ Test.kt - @@ -15 +15 @@ class Test { - - * including those off by default */ // additional - + * modified including those off by default */ // additional - diff --git a/README.md b/README.md - index c26815b..30a8dbb 100644 - --- README.md - +++ README.md - @@ -31,25 +31,29 @@ ${'$'} kdoc-formatter - Usage: kdoc-formatter [options] file(s) - """ + diff --git a/README.md b/README.md + index c26815b..30a8dbb 100644 + --- README.md + +++ README.md + @@ -31,25 +31,29 @@ ${'$'} kdoc-formatter + Usage: kdoc-formatter [options] file(s) + diff --git Test.kt Test.kt + index d66825c..7a324fb 100644 + --- Test.kt + +++ Test.kt + @@ -15 +15 @@ class Test { + - * including those off by default */ // additional + + * modified including those off by default */ // additional + diff --git a/README.md b/README.md + index c26815b..30a8dbb 100644 + --- README.md + +++ README.md + @@ -31,25 +31,29 @@ ${'$'} kdoc-formatter + Usage: kdoc-formatter [options] file(s) + """ .trimIndent() val fileOptions = KDocFileFormattingOptions() @@ -725,26 +725,26 @@ class KDocFileFormatterTest { // Only the second comment should be formatted: assertEquals( """ - class Test { - /** - * Returns whether lint should check all warnings, - * including those off by default, or null if - *not configured in this configuration. This is a really really really long sentence which needs to be broken up. - * And ThisIsALongSentenceWhichCannotBeBrokenUpAndMustBeIncludedAsAWholeWithoutNewlinesInTheMiddle. - * - * This is a separate section - * which should be flowed together with the first one. - * *bold* should not be removed even at beginning. - */ - private var checkAllWarnings: Boolean? = null - - /** - * Returns whether lint should check all warnings, including those - * off by default - */ // additional - private var ignoreAll: Boolean? = null - } - """ + class Test { + /** + * Returns whether lint should check all warnings, + * including those off by default, or null if + *not configured in this configuration. This is a really really really long sentence which needs to be broken up. + * And ThisIsALongSentenceWhichCannotBeBrokenUpAndMustBeIncludedAsAWholeWithoutNewlinesInTheMiddle. + * + * This is a separate section + * which should be flowed together with the first one. + * *bold* should not be removed even at beginning. + */ + private var checkAllWarnings: Boolean? = null + + /** + * Returns whether lint should check all warnings, including those + * off by default + */ // additional + private var ignoreAll: Boolean? = null + } + """ .trimIndent(), reformatted) } @@ -753,458 +753,458 @@ class KDocFileFormatterTest { fun testFormatMd() { val source = """ - KDoc Formatter - ============== - - Reformats Kotlin KDoc comments, reflowing text and other cleanup, both - via IDE plugin and command line utility. - - This tool reflows comments in KDoc; either on a file or recursively - over nested folders, as well as an IntelliJ IDE plugin where you can - reflow the current comment around the cursor. - - Features - -------- - - * Reflow using optimal instead of greedy algorithm (though in the IDE - plugin you can turn on alternate formatting and invoking the action - repeatedly alternates between the two modes.) - - * Command line script which can recursively format a whole source - folder. - - * IDE plugin to format selected files or current comment. Preserves - caret position in the current comment. - - * Gradle plugin to format the source folders in the current project. - - * Block tags (like @param) are separated out from the main text, and - subsequent lines are indented. Blank spaces between doc tags - are removed. Preformatted text (indented 4 spaces or more) is left - alone. - - * Can be run in a mode where it only reformats comments that were - touched by the current git HEAD commit, or the currently staged - files. Can also be passed specific line ranges to limit formatting - to. - - * Multiline comments that would fit on a single line are converted to - a single line comment (configurable via options) - - * Adds hanging indents for ordered and unordered indents. - - * Cleans up the double spaces left by the IntelliJ "Convert to Kotlin" - action right before the closing comment token. - - * Removes trailing spaces. - - * Can optionally convert various remaining HTML tags in the comments - to the corresponding KDoc/markdown text. For example, bold is - converted into **bold**,

is converted to a blank line, - \

Heading

is converted into # Heading, and so on. - - * Support for .editorconfig configuration files to automatically pick - up line widths. It will normally use the line width configured for - Kotlin files, but, if Markdown (.md) files are also configured, it - will use that width as the maximum comment width. This allows you to - have code line widths of for example 140 but limit comments to 70 - characters (possibly indented). For code, avoiding line breaking is - helpful, but for text, shorter lines are better for reading. - - Command Usage - ------------- - ``` - ${'$'} kdoc-formatter - Usage: kdoc-formatter [options] file(s) - - Options: - --max-line-width= - Sets the length of lines. Defaults to 72. - --max-comment-width= - Sets the maximum width of comments. This is helpful in a codebase - with large line lengths, such as 140 in the IntelliJ codebase. Here, - you don't want to limit the formatter maximum line width since - indented code still needs to be properly formatted, but you also - don't want comments to span 100+ characters, since that's less - readable. By default this option is not set. - --hanging-indent= - Sets the number of spaces to use for hanging indents, e.g. second - and subsequent lines in a bulleted list or kdoc blog tag. - --convert-markup - Convert unnecessary HTML tags like < and > into < and > - --single-line-comments= - With `collapse`, turns multi-line comments into a single line if it - fits, and with `expand` it will always format commands with /** and - */ on their own lines. The default is `collapse`. - --overlaps-git-changes= - If git is on the path, and the command is invoked in a git - repository, kdoc-formatter will invoke git to find the changes either - in the HEAD commit or in the staged files, and will format only the - KDoc comments that overlap these changes. - --lines , --line - Line range(s) to format, like 5:10 (1-based; default is all). Can be - specified multiple times. - --dry-run, -n - Prints the paths of the files whose contents would change if the - formatter were run normally. - --quiet, -q - Quiet mode - --help, -help, -h - Print this usage statement. - @ - Read filenames from file. - - kdoc-formatter: Version 1.3 - https://github.com/tnorbye/kdoc-formatter - ``` - - IntelliJ Plugin Usage - --------------------- - Install the IDE plugin. Then move the caret to a KDoc comment and invoke - Code > Reformat KDoc. You can configure a keyboard shortcut if you perform - this action frequently (go to Preferences, search for Keymap, and then - in the Keymap search field look for "KDoc", and then double click and - choose Add Keyboard Shortcut. - - You can also select one or more files in the - Project View and invoke the same action to format whole files. - - ![Screenshot](screenshot.png) - - Finally, you can configure various options in the Settings panel. - The line length settings are inherited from the IDE code style or - from the .editorconfig files, if any. However, you can turn on - "alternate" mode where invoking the action repeatedly will toggle - between normal formatting and alternate formatting each time you - invoke it. For a short comment that means toggling between a - multi-line and a single-line comment. But for a longer comment, - it will toggle between optimal line breaking (the default) and - greedy line breaking, which can look better for short paragraphs. - - You can also configure whether the formatter should do more than - formatting and actually replace markup constructs like bold - with markdown markup. - - ![Screenshot](screenshot-settings.png) - - - The plugin is available from the JetBrains Marketplace at - [https://plugins.jetbrains.com/plugin/15734-kotlin-kdoc-formatter](https://plugins.jetbrains.com/plugin/15734-kotlin-kdoc-formatter) - - Gradle Plugin Usage - ------------------- - The plugin is not yet distributed, so for now, download the zip file - and install it somewhere, then add this to your build.gradle file: - - ``` - buildscript { - repositories { - maven { url '/path/to/m2' } - } - dependencies { - classpath "com.github.tnorbye.kdoc-formatter:kdocformatter:1.1.1" - // (Sorry about the vanity URL -- - // I tried to get kdoc-formatter:kdoc-formatter:1.1.1 but that - // didn't meet the naming requirements for publishing: - // https://issues.sonatype.org/browse/OSSRH-63191) - } - } - plugins { - id 'kdoc-formatter' + KDoc Formatter + ============== + + Reformats Kotlin KDoc comments, reflowing text and other cleanup, both + via IDE plugin and command line utility. + + This tool reflows comments in KDoc; either on a file or recursively + over nested folders, as well as an IntelliJ IDE plugin where you can + reflow the current comment around the cursor. + + Features + -------- + + * Reflow using optimal instead of greedy algorithm (though in the IDE + plugin you can turn on alternate formatting and invoking the action + repeatedly alternates between the two modes.) + + * Command line script which can recursively format a whole source + folder. + + * IDE plugin to format selected files or current comment. Preserves + caret position in the current comment. + + * Gradle plugin to format the source folders in the current project. + + * Block tags (like @param) are separated out from the main text, and + subsequent lines are indented. Blank spaces between doc tags + are removed. Preformatted text (indented 4 spaces or more) is left + alone. + + * Can be run in a mode where it only reformats comments that were + touched by the current git HEAD commit, or the currently staged + files. Can also be passed specific line ranges to limit formatting + to. + + * Multiline comments that would fit on a single line are converted to + a single line comment (configurable via options) + + * Adds hanging indents for ordered and unordered indents. + + * Cleans up the double spaces left by the IntelliJ "Convert to Kotlin" + action right before the closing comment token. + + * Removes trailing spaces. + + * Can optionally convert various remaining HTML tags in the comments + to the corresponding KDoc/markdown text. For example, bold is + converted into **bold**,

is converted to a blank line, + \

Heading

is converted into # Heading, and so on. + + * Support for .editorconfig configuration files to automatically pick + up line widths. It will normally use the line width configured for + Kotlin files, but, if Markdown (.md) files are also configured, it + will use that width as the maximum comment width. This allows you to + have code line widths of for example 140 but limit comments to 70 + characters (possibly indented). For code, avoiding line breaking is + helpful, but for text, shorter lines are better for reading. + + Command Usage + ------------- + ``` + ${'$'} kdoc-formatter + Usage: kdoc-formatter [options] file(s) + + Options: + --max-line-width= + Sets the length of lines. Defaults to 72. + --max-comment-width= + Sets the maximum width of comments. This is helpful in a codebase + with large line lengths, such as 140 in the IntelliJ codebase. Here, + you don't want to limit the formatter maximum line width since + indented code still needs to be properly formatted, but you also + don't want comments to span 100+ characters, since that's less + readable. By default this option is not set. + --hanging-indent= + Sets the number of spaces to use for hanging indents, e.g. second + and subsequent lines in a bulleted list or kdoc blog tag. + --convert-markup + Convert unnecessary HTML tags like < and > into < and > + --single-line-comments= + With `collapse`, turns multi-line comments into a single line if it + fits, and with `expand` it will always format commands with /** and + */ on their own lines. The default is `collapse`. + --overlaps-git-changes= + If git is on the path, and the command is invoked in a git + repository, kdoc-formatter will invoke git to find the changes either + in the HEAD commit or in the staged files, and will format only the + KDoc comments that overlap these changes. + --lines , --line + Line range(s) to format, like 5:10 (1-based; default is all). Can be + specified multiple times. + --dry-run, -n + Prints the paths of the files whose contents would change if the + formatter were run normally. + --quiet, -q + Quiet mode + --help, -help, -h + Print this usage statement. + @ + Read filenames from file. + + kdoc-formatter: Version 1.3 + https://github.com/tnorbye/kdoc-formatter + ``` + + IntelliJ Plugin Usage + --------------------- + Install the IDE plugin. Then move the caret to a KDoc comment and invoke + Code > Reformat KDoc. You can configure a keyboard shortcut if you perform + this action frequently (go to Preferences, search for Keymap, and then + in the Keymap search field look for "KDoc", and then double click and + choose Add Keyboard Shortcut. + + You can also select one or more files in the + Project View and invoke the same action to format whole files. + + ![Screenshot](screenshot.png) + + Finally, you can configure various options in the Settings panel. + The line length settings are inherited from the IDE code style or + from the .editorconfig files, if any. However, you can turn on + "alternate" mode where invoking the action repeatedly will toggle + between normal formatting and alternate formatting each time you + invoke it. For a short comment that means toggling between a + multi-line and a single-line comment. But for a longer comment, + it will toggle between optimal line breaking (the default) and + greedy line breaking, which can look better for short paragraphs. + + You can also configure whether the formatter should do more than + formatting and actually replace markup constructs like bold + with markdown markup. + + ![Screenshot](screenshot-settings.png) + + + The plugin is available from the JetBrains Marketplace at + [https://plugins.jetbrains.com/plugin/15734-kotlin-kdoc-formatter](https://plugins.jetbrains.com/plugin/15734-kotlin-kdoc-formatter) + + Gradle Plugin Usage + ------------------- + The plugin is not yet distributed, so for now, download the zip file + and install it somewhere, then add this to your build.gradle file: + + ``` + buildscript { + repositories { + maven { url '/path/to/m2' } } - kdocformatter { - options = "--single-line-comments=collapse --max-line-width=100" + dependencies { + classpath "com.github.tnorbye.kdoc-formatter:kdocformatter:1.1.1" + // (Sorry about the vanity URL -- + // I tried to get kdoc-formatter:kdoc-formatter:1.1.1 but that + // didn't meet the naming requirements for publishing: + // https://issues.sonatype.org/browse/OSSRH-63191) } - ``` - Here, the [options] property lets you use any of the command line flags - from the kdoc-formatter command. - - Building and testing - -------------------- - To create an installation of the command line tool, run - ``` - ./gradlew install - ``` - The installation will be located in cli/build/install/kdocformatter. - - To create a zip, run - ``` - ./gradlew zip - ``` - To build the plugin, run - ``` - ./gradlew :plugin:buildPlugin - ``` - The plugin will be located in plugin/build/distributions/. - - To run/test the plugin in the IDE, run - ``` - ./gradlew runIde - ``` - - To reformat the source tree run - ``` - ./gradlew format - ``` - - To build the Gradle plugin locally: - ``` - cd gradle-plugin - ./gradlew publish - ``` - This will create a Maven local repository in m2/ which you can then - point to from your consuming projects as shown in the Gradle Plugin - Usage section above. - - Support Javadoc? - ---------------- - KDoc is pretty similar to javadoc and there's a good chance that most - of this functionality would work well. However, I already use - [google-java-formatter](https://github.com/google/google-java-format) - to format all Java source code, which does a great job reflowing - javadoc comments already (along with formatting the rest of the file), - so makign this tool support Java is not needed. - - Integrate into ktlint? - ---------------------- - I use [ktlint](https://github.com/pinterest/ktlint) to format and - pretty-print my Kotlin source code. However, it does not do comment - reformatting, which means I spend time either manually reflowing - myself when I edit comments, or worse, leave it unformatted. - - Given that I use ktlint for formatting, the Right Thing would have - been for me to figure out how it works, and implement the - functionality there. However, I'm busy with a million other things, - and this was just a quick weekend -- which unfortunately satisfies my - immediate formatting needs -- so I no longer have the same motivation - to get ktlint to support it. - """ + } + plugins { + id 'kdoc-formatter' + } + kdocformatter { + options = "--single-line-comments=collapse --max-line-width=100" + } + ``` + Here, the [options] property lets you use any of the command line flags + from the kdoc-formatter command. + + Building and testing + -------------------- + To create an installation of the command line tool, run + ``` + ./gradlew install + ``` + The installation will be located in cli/build/install/kdocformatter. + + To create a zip, run + ``` + ./gradlew zip + ``` + To build the plugin, run + ``` + ./gradlew :plugin:buildPlugin + ``` + The plugin will be located in plugin/build/distributions/. + + To run/test the plugin in the IDE, run + ``` + ./gradlew runIde + ``` + + To reformat the source tree run + ``` + ./gradlew format + ``` + + To build the Gradle plugin locally: + ``` + cd gradle-plugin + ./gradlew publish + ``` + This will create a Maven local repository in m2/ which you can then + point to from your consuming projects as shown in the Gradle Plugin + Usage section above. + + Support Javadoc? + ---------------- + KDoc is pretty similar to javadoc and there's a good chance that most + of this functionality would work well. However, I already use + [google-java-formatter](https://github.com/google/google-java-format) + to format all Java source code, which does a great job reflowing + javadoc comments already (along with formatting the rest of the file), + so makign this tool support Java is not needed. + + Integrate into ktlint? + ---------------------- + I use [ktlint](https://github.com/pinterest/ktlint) to format and + pretty-print my Kotlin source code. However, it does not do comment + reformatting, which means I spend time either manually reflowing + myself when I edit comments, or worse, leave it unformatted. + + Given that I use ktlint for formatting, the Right Thing would have + been for me to figure out how it works, and implement the + functionality there. However, I'm busy with a million other things, + and this was just a quick weekend -- which unfortunately satisfies my + immediate formatting needs -- so I no longer have the same motivation + to get ktlint to support it. + """ .trimIndent() val options = KDocFormattingOptions(72).apply { optimal = false } val reformatted = reformatFile(source, options, markdown = true) assertEquals( """ - KDoc Formatter - ============== - - Reformats Kotlin KDoc comments, reflowing text and other cleanup, both - via IDE plugin and command line utility. - - This tool reflows comments in KDoc; either on a file or recursively over - nested folders, as well as an IntelliJ IDE plugin where you can reflow - the current comment around the cursor. - - Features - -------- - * Reflow using optimal instead of greedy algorithm (though in the IDE - plugin you can turn on alternate formatting and invoking the action - repeatedly alternates between the two modes.) - * Command line script which can recursively format a whole source - folder. - * IDE plugin to format selected files or current comment. Preserves - caret position in the current comment. - * Gradle plugin to format the source folders in the current project. - * Block tags (like @param) are separated out from the main text, and - subsequent lines are indented. Blank spaces between doc tags are - removed. Preformatted text (indented 4 spaces or more) is left alone. - * Can be run in a mode where it only reformats comments that were - touched by the current git HEAD commit, or the currently staged files. - Can also be passed specific line ranges to limit formatting to. - * Multiline comments that would fit on a single line are converted to a - single line comment (configurable via options) - * Adds hanging indents for ordered and unordered indents. - * Cleans up the double spaces left by the IntelliJ "Convert to Kotlin" - action right before the closing comment token. - * Removes trailing spaces. - * Can optionally convert various remaining HTML tags in the comments to - the corresponding KDoc/markdown text. For example, **bold** is - converted into **bold**,

is converted to a blank line, - \

Heading

is converted into # Heading, and so on. - * Support for .editorconfig configuration files to automatically pick up - line widths. It will normally use the line width configured for Kotlin - files, but, if Markdown (.md) files are also configured, it will use - that width as the maximum comment width. This allows you to have code - line widths of for example 140 but limit comments to 70 characters - (possibly indented). For code, avoiding line breaking is helpful, but - for text, shorter lines are better for reading. - - Command Usage - ------------- - ``` - ${'$'} kdoc-formatter - Usage: kdoc-formatter [options] file(s) - - Options: - --max-line-width= - Sets the length of lines. Defaults to 72. - --max-comment-width= - Sets the maximum width of comments. This is helpful in a codebase - with large line lengths, such as 140 in the IntelliJ codebase. Here, - you don't want to limit the formatter maximum line width since - indented code still needs to be properly formatted, but you also - don't want comments to span 100+ characters, since that's less - readable. By default this option is not set. - --hanging-indent= - Sets the number of spaces to use for hanging indents, e.g. second - and subsequent lines in a bulleted list or kdoc blog tag. - --convert-markup - Convert unnecessary HTML tags like < and > into < and > - --single-line-comments= - With `collapse`, turns multi-line comments into a single line if it - fits, and with `expand` it will always format commands with /** and - */ on their own lines. The default is `collapse`. - --overlaps-git-changes= - If git is on the path, and the command is invoked in a git - repository, kdoc-formatter will invoke git to find the changes either - in the HEAD commit or in the staged files, and will format only the - KDoc comments that overlap these changes. - --lines , --line - Line range(s) to format, like 5:10 (1-based; default is all). Can be - specified multiple times. - --dry-run, -n - Prints the paths of the files whose contents would change if the - formatter were run normally. - --quiet, -q - Quiet mode - --help, -help, -h - Print this usage statement. - @ - Read filenames from file. - - kdoc-formatter: Version 1.3 - https://github.com/tnorbye/kdoc-formatter - ``` - - IntelliJ Plugin Usage - --------------------- - Install the IDE plugin. Then move the caret to a KDoc comment and invoke - Code > Reformat KDoc. You can configure a keyboard shortcut if you - perform this action frequently (go to Preferences, search for Keymap, - and then in the Keymap search field look for "KDoc", and then double - click and choose Add Keyboard Shortcut. - - You can also select one or more files in the Project View and invoke the - same action to format whole files. - - ![Screenshot](screenshot.png) - - Finally, you can configure various options in the Settings panel. The - line length settings are inherited from the IDE code style or from the - .editorconfig files, if any. However, you can turn on "alternate" mode - where invoking the action repeatedly will toggle between normal - formatting and alternate formatting each time you invoke it. For a short - comment that means toggling between a multi-line and a single-line - comment. But for a longer comment, it will toggle between optimal line - breaking (the default) and greedy line breaking, which can look better - for short paragraphs. - - You can also configure whether the formatter should do more than - formatting and actually replace markup constructs like **bold** with - markdown markup. - - ![Screenshot](screenshot-settings.png) - - The plugin is available from the JetBrains Marketplace at - [https://plugins.jetbrains.com/plugin/15734-kotlin-kdoc-formatter](https://plugins.jetbrains.com/plugin/15734-kotlin-kdoc-formatter) - - Gradle Plugin Usage - ------------------- - The plugin is not yet distributed, so for now, download the zip file and - install it somewhere, then add this to your build.gradle file: - ``` - buildscript { - repositories { - maven { url '/path/to/m2' } - } - dependencies { - classpath "com.github.tnorbye.kdoc-formatter:kdocformatter:1.1.1" - // (Sorry about the vanity URL -- - // I tried to get kdoc-formatter:kdoc-formatter:1.1.1 but that - // didn't meet the naming requirements for publishing: - // https://issues.sonatype.org/browse/OSSRH-63191) - } + KDoc Formatter + ============== + + Reformats Kotlin KDoc comments, reflowing text and other cleanup, both + via IDE plugin and command line utility. + + This tool reflows comments in KDoc; either on a file or recursively over + nested folders, as well as an IntelliJ IDE plugin where you can reflow + the current comment around the cursor. + + Features + -------- + * Reflow using optimal instead of greedy algorithm (though in the IDE + plugin you can turn on alternate formatting and invoking the action + repeatedly alternates between the two modes.) + * Command line script which can recursively format a whole source + folder. + * IDE plugin to format selected files or current comment. Preserves + caret position in the current comment. + * Gradle plugin to format the source folders in the current project. + * Block tags (like @param) are separated out from the main text, and + subsequent lines are indented. Blank spaces between doc tags are + removed. Preformatted text (indented 4 spaces or more) is left alone. + * Can be run in a mode where it only reformats comments that were + touched by the current git HEAD commit, or the currently staged files. + Can also be passed specific line ranges to limit formatting to. + * Multiline comments that would fit on a single line are converted to a + single line comment (configurable via options) + * Adds hanging indents for ordered and unordered indents. + * Cleans up the double spaces left by the IntelliJ "Convert to Kotlin" + action right before the closing comment token. + * Removes trailing spaces. + * Can optionally convert various remaining HTML tags in the comments to + the corresponding KDoc/markdown text. For example, **bold** is + converted into **bold**,

is converted to a blank line, + \

Heading

is converted into # Heading, and so on. + * Support for .editorconfig configuration files to automatically pick up + line widths. It will normally use the line width configured for Kotlin + files, but, if Markdown (.md) files are also configured, it will use + that width as the maximum comment width. This allows you to have code + line widths of for example 140 but limit comments to 70 characters + (possibly indented). For code, avoiding line breaking is helpful, but + for text, shorter lines are better for reading. + + Command Usage + ------------- + ``` + ${'$'} kdoc-formatter + Usage: kdoc-formatter [options] file(s) + + Options: + --max-line-width= + Sets the length of lines. Defaults to 72. + --max-comment-width= + Sets the maximum width of comments. This is helpful in a codebase + with large line lengths, such as 140 in the IntelliJ codebase. Here, + you don't want to limit the formatter maximum line width since + indented code still needs to be properly formatted, but you also + don't want comments to span 100+ characters, since that's less + readable. By default this option is not set. + --hanging-indent= + Sets the number of spaces to use for hanging indents, e.g. second + and subsequent lines in a bulleted list or kdoc blog tag. + --convert-markup + Convert unnecessary HTML tags like < and > into < and > + --single-line-comments= + With `collapse`, turns multi-line comments into a single line if it + fits, and with `expand` it will always format commands with /** and + */ on their own lines. The default is `collapse`. + --overlaps-git-changes= + If git is on the path, and the command is invoked in a git + repository, kdoc-formatter will invoke git to find the changes either + in the HEAD commit or in the staged files, and will format only the + KDoc comments that overlap these changes. + --lines , --line + Line range(s) to format, like 5:10 (1-based; default is all). Can be + specified multiple times. + --dry-run, -n + Prints the paths of the files whose contents would change if the + formatter were run normally. + --quiet, -q + Quiet mode + --help, -help, -h + Print this usage statement. + @ + Read filenames from file. + + kdoc-formatter: Version 1.3 + https://github.com/tnorbye/kdoc-formatter + ``` + + IntelliJ Plugin Usage + --------------------- + Install the IDE plugin. Then move the caret to a KDoc comment and invoke + Code > Reformat KDoc. You can configure a keyboard shortcut if you + perform this action frequently (go to Preferences, search for Keymap, + and then in the Keymap search field look for "KDoc", and then double + click and choose Add Keyboard Shortcut. + + You can also select one or more files in the Project View and invoke the + same action to format whole files. + + ![Screenshot](screenshot.png) + + Finally, you can configure various options in the Settings panel. The + line length settings are inherited from the IDE code style or from the + .editorconfig files, if any. However, you can turn on "alternate" mode + where invoking the action repeatedly will toggle between normal + formatting and alternate formatting each time you invoke it. For a short + comment that means toggling between a multi-line and a single-line + comment. But for a longer comment, it will toggle between optimal line + breaking (the default) and greedy line breaking, which can look better + for short paragraphs. + + You can also configure whether the formatter should do more than + formatting and actually replace markup constructs like **bold** with + markdown markup. + + ![Screenshot](screenshot-settings.png) + + The plugin is available from the JetBrains Marketplace at + [https://plugins.jetbrains.com/plugin/15734-kotlin-kdoc-formatter](https://plugins.jetbrains.com/plugin/15734-kotlin-kdoc-formatter) + + Gradle Plugin Usage + ------------------- + The plugin is not yet distributed, so for now, download the zip file and + install it somewhere, then add this to your build.gradle file: + ``` + buildscript { + repositories { + maven { url '/path/to/m2' } } - plugins { - id 'kdoc-formatter' + dependencies { + classpath "com.github.tnorbye.kdoc-formatter:kdocformatter:1.1.1" + // (Sorry about the vanity URL -- + // I tried to get kdoc-formatter:kdoc-formatter:1.1.1 but that + // didn't meet the naming requirements for publishing: + // https://issues.sonatype.org/browse/OSSRH-63191) } - kdocformatter { - options = "--single-line-comments=collapse --max-line-width=100" - } - ``` + } + plugins { + id 'kdoc-formatter' + } + kdocformatter { + options = "--single-line-comments=collapse --max-line-width=100" + } + ``` - Here, the [options] property lets you use any of the command line flags - from the kdoc-formatter command. + Here, the [options] property lets you use any of the command line flags + from the kdoc-formatter command. - Building and testing - -------------------- - To create an installation of the command line tool, run + Building and testing + -------------------- + To create an installation of the command line tool, run - ``` - ./gradlew install - ``` + ``` + ./gradlew install + ``` - The installation will be located in cli/build/install/kdocformatter. + The installation will be located in cli/build/install/kdocformatter. - To create a zip, run + To create a zip, run - ``` - ./gradlew zip - ``` + ``` + ./gradlew zip + ``` - To build the plugin, run + To build the plugin, run - ``` - ./gradlew :plugin:buildPlugin - ``` + ``` + ./gradlew :plugin:buildPlugin + ``` - The plugin will be located in plugin/build/distributions/. + The plugin will be located in plugin/build/distributions/. - To run/test the plugin in the IDE, run + To run/test the plugin in the IDE, run - ``` - ./gradlew runIde - ``` + ``` + ./gradlew runIde + ``` - To reformat the source tree run + To reformat the source tree run - ``` - ./gradlew format - ``` + ``` + ./gradlew format + ``` - To build the Gradle plugin locally: - ``` - cd gradle-plugin - ./gradlew publish - ``` + To build the Gradle plugin locally: + ``` + cd gradle-plugin + ./gradlew publish + ``` - This will create a Maven local repository in m2/ which you can then - point to from your consuming projects as shown in the Gradle Plugin - Usage section above. + This will create a Maven local repository in m2/ which you can then + point to from your consuming projects as shown in the Gradle Plugin + Usage section above. - Support Javadoc? - ---------------- - KDoc is pretty similar to javadoc and there's a good chance that most of - this functionality would work well. However, I already use - [google-java-formatter](https://github.com/google/google-java-format) to - format all Java source code, which does a great job reflowing javadoc - comments already (along with formatting the rest of the file), so makign - this tool support Java is not needed. + Support Javadoc? + ---------------- + KDoc is pretty similar to javadoc and there's a good chance that most of + this functionality would work well. However, I already use + [google-java-formatter](https://github.com/google/google-java-format) to + format all Java source code, which does a great job reflowing javadoc + comments already (along with formatting the rest of the file), so makign + this tool support Java is not needed. - Integrate into ktlint? - ---------------------- - I use [ktlint](https://github.com/pinterest/ktlint) to format and - pretty-print my Kotlin source code. However, it does not do comment - reformatting, which means I spend time either manually reflowing myself - when I edit comments, or worse, leave it unformatted. + Integrate into ktlint? + ---------------------- + I use [ktlint](https://github.com/pinterest/ktlint) to format and + pretty-print my Kotlin source code. However, it does not do comment + reformatting, which means I spend time either manually reflowing myself + when I edit comments, or worse, leave it unformatted. - Given that I use ktlint for formatting, the Right Thing would have been - for me to figure out how it works, and implement the functionality - there. However, I'm busy with a million other things, and this was just - a quick weekend -- which unfortunately satisfies my immediate formatting - needs -- so I no longer have the same motivation to get ktlint to - support it. - """ + Given that I use ktlint for formatting, the Right Thing would have been + for me to figure out how it works, and implement the functionality + there. However, I'm busy with a million other things, and this was just + a quick weekend -- which unfortunately satisfies my immediate formatting + needs -- so I no longer have the same motivation to get ktlint to + support it. + """ .trimIndent(), reformatted) } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1b33c55baabb587c669f562ae36f953de2481846..9bbc975c742b298b441bfb90dbc124400a3751b9 100644 GIT binary patch delta 584 zcmexzm1*ZyrVZJAexH5Moc8h7)w{^+t*dqJ%=yhh23L$9JpFV=_k`zJ-?Q4DI*eSe z+ES)HSrVnWLtJ&)lO%hRkV9zl5qqWRt0e;bb zPPo`)y?HTAyZI&u&X<|2$FDHCf4;!v8}p=?Tm`^F0`u(|1ttf~&t$qP3KUSD>@TJQ zRwJ}Pim6NzEc8KA6)e;S6gs8=7IIL8sQL*MYEuRYO;Uj<%3UbMbV&^&!Zvx+LKmjT z8Zch6rYP7Tw?$Hn(UTJwWiS=$f{lB(C=e*%usDV})0AQIK~sat=ND@+Gg*Pyij!rR z*fa02W|%BsV++>4W{DKDGSIUEHd2$P+8ct!RF+CHDowUuTEZOZ%rJSQv*qOXOSPDN zT|sP-$p*_3ncsWB*qoD7JQcyZ9xan%cJP6Tb4-?AZpr*F6v98hoNaPJm@HV`yya5N z))6pqFXn@}P(3T0nEzM8*c_9KtE9o|_pFd&K35GBXP^9Kg(b6GH-z8S4GDzIl~T+b zdLd#meKKHu$5u))8cu$=GKINkGDPOUD)!0$C(BH(U!}!-e;Q0ok8Sc?V1zRO04>ts AA^-pY delta 642 zcmdmamFde>rVZJA^}0Q$xegf!xPEW^+5YDM%iT2bEgct9o+jH~+sJas#HZ=szO|** z=Pj=X_vx?W&DSwKck|WWn~hffsvnQ+42*W$b7b0$SCcOoZ`{W{^$^pk;4>8-A*-)$ z?n(Po`1$6Jn_u?t-L+tsPyZ2#X}8T6OS8pAU;kdgd+_Hw4z4TW0p9E!T+=f7-c&O% zFic^X{7^$?^Ho04eona9n#mGMxKhA=~8B%JN`M zMhm5wc-2v)$``sY$!Q`9xiU@DhI73ZxiGEKg>yIPs)NmWwMdF-ngLXpZSqV5ez36n zVkxF2rjrjWR+_xr6e6@_u@s~2uv{9vi*1pj2)BjFD+-%@&pRVP1f{O1glxTOp2-62Ph;v z`N1+vCd)9ea)af*Ol1*JCfnp$%Uu}%OuoN7g2}3C@`L5FlP#(sA=|h@iixuZC?qp^ z=L$=v$ZoI}|87Wh=&h7udff{aieKr*l+zDp?pf)_bbRvUf>kn;HCDMXNlgbbo!QRK I1x7am0No)LiU0rr diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index be2dc79..37f853b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 23d15a9..faf9300 100755 --- a/gradlew +++ b/gradlew @@ -114,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH="\\\"\\\"" +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 5eed7ee..9b42019 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH= +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/ide-plugin/CHANGELOG.md b/ide-plugin/CHANGELOG.md index d54f303..8e59675 100644 --- a/ide-plugin/CHANGELOG.md +++ b/ide-plugin/CHANGELOG.md @@ -2,6 +2,9 @@ # KDoc Formatter Plugin Changelog +## [1.6.9] +- Add support for 2025.3 EAP + ## [1.6.8] - Add support for IJP 2025.2 EAP diff --git a/ide-plugin/build.gradle.kts b/ide-plugin/build.gradle.kts index aa3e578..b82e3fe 100644 --- a/ide-plugin/build.gradle.kts +++ b/ide-plugin/build.gradle.kts @@ -9,8 +9,8 @@ private fun properties(key: String) = project.findProperty(key).toString() plugins { id("java") id("org.jetbrains.kotlin.jvm") - id("org.jetbrains.intellij.platform") version "2.6.0" - id("org.jetbrains.changelog") version "2.2.1" + id("org.jetbrains.intellij.platform") version "2.10.5" + id("org.jetbrains.changelog") version "2.5.0" id("com.android.lint") id("com.ncorti.ktfmt.gradle") } diff --git a/ide-plugin/gradle.properties b/ide-plugin/gradle.properties index 1593a36..630ee72 100644 --- a/ide-plugin/gradle.properties +++ b/ide-plugin/gradle.properties @@ -8,12 +8,12 @@ pluginRepositoryUrl = https://github.com/tnorbye/kdoc-formatter # See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html # for insight into build numbers and IntelliJ Platform versions. pluginSinceBuild = 243 -pluginUntilBuild = 252.* +pluginUntilBuild = 253.* # IntelliJ Platform Properties -> https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties platformType = IC -#platformVersion = 2024.3 -platformVersion = 252.21735.32 +platformVersion = 2025.2 +#platformVersion = 253.28294.334 # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html platformPlugins = org.jetbrains.kotlin,com.intellij.java,org.intellij.intelliLang diff --git a/library/build.gradle b/library/build.gradle index f0c14f4..cfdc541 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -22,7 +22,7 @@ lint { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib" testImplementation "junit:junit:4.13.2" - testImplementation "com.google.truth:truth:1.4.4" + testImplementation "com.google.truth:truth:1.4.5" } java { diff --git a/library/src/main/resources/version.properties b/library/src/main/resources/version.properties index 14c297f..7e01115 100644 --- a/library/src/main/resources/version.properties +++ b/library/src/main/resources/version.properties @@ -15,4 +15,4 @@ # # Release version definition -buildVersion = 1.6.8 +buildVersion = 1.6.9 diff --git a/library/src/test/kotlin/com/facebook/ktfmt/kdoc/KDocFormatterTest.kt b/library/src/test/kotlin/com/facebook/ktfmt/kdoc/KDocFormatterTest.kt index a136b45..41cc553 100644 --- a/library/src/test/kotlin/com/facebook/ktfmt/kdoc/KDocFormatterTest.kt +++ b/library/src/test/kotlin/com/facebook/ktfmt/kdoc/KDocFormatterTest.kt @@ -105,31 +105,31 @@ class KDocFormatterTest { fun test1() { checkFormatter( """ - /** - * Returns whether lint should check all warnings, - * including those off by default, or null if - *not configured in this configuration. This is a really really really long sentence which needs to be broken up. - * And ThisIsALongSentenceWhichCannotBeBrokenUpAndMustBeIncludedAsAWholeWithoutNewlinesInTheMiddle. - * - * This is a separate section - * which should be flowed together with the first one. - * *bold* should not be removed even at beginning. - */ - """ + /** + * Returns whether lint should check all warnings, + * including those off by default, or null if + *not configured in this configuration. This is a really really really long sentence which needs to be broken up. + * And ThisIsALongSentenceWhichCannotBeBrokenUpAndMustBeIncludedAsAWholeWithoutNewlinesInTheMiddle. + * + * This is a separate section + * which should be flowed together with the first one. + * *bold* should not be removed even at beginning. + */ + """ .trimIndent(), KDocFormattingOptions(72), """ - /** - * Returns whether lint should check all warnings, including those - * off by default, or null if not configured in this configuration. - * This is a really really really long sentence which needs to be - * broken up. And - * ThisIsALongSentenceWhichCannotBeBrokenUpAndMustBeIncludedAsAWholeWithoutNewlinesInTheMiddle. - * - * This is a separate section which should be flowed together with - * the first one. *bold* should not be removed even at beginning. - */ - """ + /** + * Returns whether lint should check all warnings, including those + * off by default, or null if not configured in this configuration. + * This is a really really really long sentence which needs to be + * broken up. And + * ThisIsALongSentenceWhichCannotBeBrokenUpAndMustBeIncludedAsAWholeWithoutNewlinesInTheMiddle. + * + * This is a separate section which should be flowed together with + * the first one. *bold* should not be removed even at beginning. + */ + """ .trimIndent()) } @@ -137,23 +137,23 @@ class KDocFormatterTest { fun testLongSeeTag() { val source = """ - /** - * Enables the warning explicit api mode. - * - * @see org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtensionConfig.explicitApiWarning - */ - """ + /** + * Enables the warning explicit api mode. + * + * @see org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtensionConfig.explicitApiWarning + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72), """ - /** - * Enables the warning explicit api mode. - * - * @see org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtensionConfig.explicitApiWarning - */ - """ + /** + * Enables the warning explicit api mode. + * + * @see org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtensionConfig.explicitApiWarning + */ + """ .trimIndent()) } @@ -161,8 +161,8 @@ class KDocFormatterTest { fun testPunctuationWithLink() { val source = """ - /** See [this link](https://example.com) */ - """ + /** See [this link](https://example.com) */ + """ .trimIndent() val options = KDocFormattingOptions(72) @@ -171,8 +171,8 @@ class KDocFormatterTest { source, options, """ - /** See [this link](https://example.com). */ - """ + /** See [this link](https://example.com). */ + """ .trimIndent()) } @@ -180,17 +180,17 @@ class KDocFormatterTest { fun testWithOffset() { val source = """ - /** Returns whether lint should check all warnings, - * including those off by default */ - """ + /** Returns whether lint should check all warnings, + * including those off by default */ + """ .trimIndent() val reformatted = """ - /** - * Returns whether lint should check all warnings, including those - * off by default - */ - """ + /** + * Returns whether lint should check all warnings, including those + * off by default + */ + """ .trimIndent() checkFormatter(source, KDocFormattingOptions(72), reformatted, indent = " ") val initialOffset = source.indexOf("default") @@ -205,17 +205,17 @@ class KDocFormatterTest { // beginning of line 2, which then implies a list item. val source = """ - /** Returns whether lint should check all warnings, - * including aaaaaa - off by default */ - """ + /** Returns whether lint should check all warnings, + * including aaaaaa - off by default */ + """ .trimIndent() val reformatted = """ - /** - * Returns whether lint should check all warnings, including - * aaaaaa - off by default - */ - """ + /** + * Returns whether lint should check all warnings, including + * aaaaaa - off by default + */ + """ .trimIndent() checkFormatter(source, KDocFormattingOptions(72), reformatted, indent = " ") val initialOffset = source.indexOf("default") @@ -228,41 +228,41 @@ class KDocFormatterTest { fun testHeader() { val source = """ - /** - * Information about a request to run lint. - * - * **NOTE: This is not a public or final API; if you rely on this be prepared - * to adjust your code for the next tools release.** - */ - """ + /** + * Information about a request to run lint. + * + * **NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.** + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72), """ - /** - * Information about a request to run lint. - * - * **NOTE: This is not a public or final API; if you rely on this be - * prepared to adjust your code for the next tools release.** - */ - """ + /** + * Information about a request to run lint. + * + * **NOTE: This is not a public or final API; if you rely on this be + * prepared to adjust your code for the next tools release.** + */ + """ .trimIndent()) checkFormatter( source, KDocFormattingOptions(40), """ - /** - * Information about a request to run - * lint. - * - * **NOTE: This is not a public or final - * API; if you rely on this be prepared - * to adjust your code for the next - * tools release.** - */ - """ + /** + * Information about a request to run + * lint. + * + * **NOTE: This is not a public or final + * API; if you rely on this be prepared + * to adjust your code for the next + * tools release.** + */ + """ .trimIndent(), indent = "") @@ -270,13 +270,13 @@ class KDocFormatterTest { source, KDocFormattingOptions(100, 100), """ - /** - * Information about a request to run lint. - * - * **NOTE: This is not a public or final API; if you rely on this be prepared to adjust your code - * for the next tools release.** - */ - """ + /** + * Information about a request to run lint. + * + * **NOTE: This is not a public or final API; if you rely on this be prepared to adjust your code + * for the next tools release.** + */ + """ .trimIndent(), indent = "") } @@ -285,23 +285,23 @@ class KDocFormatterTest { fun testSingle() { val source = """ - /** - * The lint client requesting the lint check - * - * @return the client, never null - */ - """ + /** + * The lint client requesting the lint check + * + * @return the client, never null + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72), """ - /** - * The lint client requesting the lint check - * - * @return the client, never null - */ - """ + /** + * The lint client requesting the lint check + * + * @return the client, never null + */ + """ .trimIndent()) } @@ -309,24 +309,24 @@ class KDocFormatterTest { fun testEmpty() { val source = """ - /** */ - """ + /** */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72), """ - /** */ - """ + /** */ + """ .trimIndent()) checkFormatter( source, KDocFormattingOptions(72).apply { collapseSingleLine = false }, """ - /** - */ - """ + /** + */ + """ .trimIndent()) } @@ -334,28 +334,28 @@ class KDocFormatterTest { fun testJavadocParams() { val source = """ - /** - * Sets the scope to use; lint checks which require a wider scope set - * will be ignored - * - * @param scope the scope - * - * @return this, for constructor chaining - */ - """ + /** + * Sets the scope to use; lint checks which require a wider scope set + * will be ignored + * + * @param scope the scope + * + * @return this, for constructor chaining + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72), """ - /** - * Sets the scope to use; lint checks which require a wider scope - * set will be ignored - * - * @param scope the scope - * @return this, for constructor chaining - */ - """ + /** + * Sets the scope to use; lint checks which require a wider scope + * set will be ignored + * + * @param scope the scope + * @return this, for constructor chaining + */ + """ .trimIndent()) } @@ -364,24 +364,24 @@ class KDocFormatterTest { // Regression test for https://github.com/tnorbye/kdoc-formatter/issues/72 val source = """ - /** - * Summary - * @param [ param1 ] some value - * @param[param2] another value - */ - """ + /** + * Summary + * @param [ param1 ] some value + * @param[param2] another value + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72), """ - /** - * Summary - * - * @param param1 some value - * @param param2 another value - */ - """ + /** + * Summary + * + * @param param1 some value + * @param param2 another value + */ + """ .trimIndent()) } @@ -390,42 +390,42 @@ class KDocFormatterTest { // Regression test for https://github.com/tnorbye/kdoc-formatter/issues/70 val source = """ - /** - * Single line is converted {@link foo} - * - * Multi line is converted {@link - * foo} - * - * Single line with hash is converted {@link #foo} - * - * Multi line with has is converted {@link - * #foo} - * - * Don't interpret {@code - * # This is not a header - * * this is - * * not a nested list - * } - */ - """ + /** + * Single line is converted {@link foo} + * + * Multi line is converted {@link + * foo} + * + * Single line with hash is converted {@link #foo} + * + * Multi line with has is converted {@link + * #foo} + * + * Don't interpret {@code + * # This is not a header + * * this is + * * not a nested list + * } + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72), """ - /** - * Single line is converted [foo] - * - * Multi line is converted [foo] - * - * Single line with hash is converted [foo] - * - * Multi line with has is converted [foo] - * - * Don't interpret {@code # This is not a header * this is * not a - * nested list } - */ - """ + /** + * Single line is converted [foo] + * + * Multi line is converted [foo] + * + * Single line with hash is converted [foo] + * + * Multi line with has is converted [foo] + * + * Don't interpret {@code # This is not a header * this is * not a + * nested list } + */ + """ .trimIndent(), // {@link} text is not rendered by dokka when it cannot resolve the symbols verifyDokka = false) @@ -436,37 +436,37 @@ class KDocFormatterTest { // Regression test for https://github.com/tnorbye/kdoc-formatter/issues/77 val source = """ - /** - * Some summary. - * {@code - * - * foo < bar?} - * Done. - * - * - * {@code - * ``` - * Some code. - * ``` - */ - """ + /** + * Some summary. + * {@code + * + * foo < bar?} + * Done. + * + * + * {@code + * ``` + * Some code. + * ``` + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72), """ - /** - * Some summary. {@code - * - * foo < bar?} Done. - * - * {@code - * - * ``` - * Some code. - * ``` - */ - """ + /** + * Some summary. {@code + * + * foo < bar?} Done. + * + * {@code + * + * ``` + * Some code. + * ``` + */ + """ .trimIndent()) } @@ -475,30 +475,30 @@ class KDocFormatterTest { // Regression test for https://github.com/tnorbye/kdoc-formatter/issues/78 val source = """ - /** - * Some summary - * - *
-             * line one
-             * ```
-             *     line two
-             * ```
-             */
-            """
+        /**
+         * Some summary
+         *
+         * 
+         * line one
+         * ```
+         *     line two
+         * ```
+         */
+        """
             .trimIndent()
     checkFormatter(
         source,
         KDocFormattingOptions(72),
         """
-            /**
-             * Some summary
-             * 
-             * line one
-             * ```
-             *     line two
-             * ```
-             */
-            """
+        /**
+         * Some summary
+         * 
+         * line one
+         * ```
+         *     line two
+         * ```
+         */
+        """
             .trimIndent())
   }
 
@@ -508,30 +508,30 @@ class KDocFormatterTest {
     // (second scenario
     val source =
         """
-            /**
-             * Some summary
-             *
-             * 
-             * ```
-             *     code
-             * ```
-             * 
- */ - """ + /** + * Some summary + * + *
+         * ```
+         *     code
+         * ```
+         * 
+ */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72), """ - /** - * Some summary - *
-             * ```
-             *     code
-             * ```
-             * 
- */ - """ + /** + * Some summary + *
+         * ```
+         *     code
+         * ```
+         * 
+ */ + """ .trimIndent()) } @@ -540,23 +540,23 @@ class KDocFormatterTest { // Regression test for https://github.com/tnorbye/kdoc-formatter/issues/79 val source = """ - /** - * Some summary. - * - * Another summary about {@param someParam}. - */ - """ + /** + * Some summary. + * + * Another summary about {@param someParam}. + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72), """ - /** - * Some summary. - * - * Another summary about [someParam]. - */ - """ + /** + * Some summary. + * + * Another summary about [someParam]. + */ + """ .trimIndent(), // {@param reference} text is not rendered by dokka when it cannot resolve the symbols verifyDokka = false) @@ -568,38 +568,38 @@ class KDocFormatterTest { // for indent! val source = """ - /** - * 89 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 - * - * 10 20 30 40 50 60 70 80 - */ - """ + /** + * 89 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 + * + * 10 20 30 40 50 60 70 80 + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72), """ - /** - * 89 123456789 123456789 123456789 123456789 123456789 123456789 - * 123456789 123456789 - * - * 10 20 30 40 50 60 70 80 - */ - """ + /** + * 89 123456789 123456789 123456789 123456789 123456789 123456789 + * 123456789 123456789 + * + * 10 20 30 40 50 60 70 80 + */ + """ .trimIndent()) checkFormatter( source, KDocFormattingOptions(40), """ - /** - * 89 123456789 123456789 123456789 - * 123456789 123456789 123456789 - * 123456789 123456789 - * - * 10 20 30 40 50 60 70 80 - */ - """ + /** + * 89 123456789 123456789 123456789 + * 123456789 123456789 123456789 + * 123456789 123456789 + * + * 10 20 30 40 50 60 70 80 + */ + """ .trimIndent()) } @@ -607,27 +607,27 @@ class KDocFormatterTest { fun testBlockTagsNoSeparators() { checkFormatter( """ - /** - * Marks the given warning as "ignored". - * - * @param context The scanning context - * @param issue the issue to be ignored - * @param location The location to ignore the warning at, if any - * @param message The message for the warning - */ - """ + /** + * Marks the given warning as "ignored". + * + * @param context The scanning context + * @param issue the issue to be ignored + * @param location The location to ignore the warning at, if any + * @param message The message for the warning + */ + """ .trimIndent(), KDocFormattingOptions(72), """ - /** - * Marks the given warning as "ignored". - * - * @param context The scanning context - * @param issue the issue to be ignored - * @param location The location to ignore the warning at, if any - * @param message The message for the warning - */ - """ + /** + * Marks the given warning as "ignored". + * + * @param context The scanning context + * @param issue the issue to be ignored + * @param location The location to ignore the warning at, if any + * @param message The message for the warning + */ + """ .trimIndent()) } @@ -637,41 +637,41 @@ class KDocFormatterTest { options.hangingIndent = 6 checkFormatter( """ - /** - * Creates a list of class entries from the given class path and specific set of files within - * it. - * - * @param client the client to report errors to and to use to read files - * @param classFiles the specific set of class files to look for - * @param classFolders the list of class folders to look in (to determine the package root) - * @param sort if true, sort the results - * @return the list of class entries, never null. - */ - """ + /** + * Creates a list of class entries from the given class path and specific set of files within + * it. + * + * @param client the client to report errors to and to use to read files + * @param classFiles the specific set of class files to look for + * @param classFolders the list of class folders to look in (to determine the package root) + * @param sort if true, sort the results + * @return the list of class entries, never null. + */ + """ .trimIndent(), options, """ - /** - * Creates a list of class entries - * from the given class path and - * specific set of files within it. - * - * @param client the client to - * report errors to and to use - * to read files - * @param classFiles the specific - * set of class files to look - * for - * @param classFolders the list of - * class folders to look in - * (to determine the package - * root) - * @param sort if true, sort the - * results - * @return the list of class - * entries, never null. - */ - """ + /** + * Creates a list of class entries + * from the given class path and + * specific set of files within it. + * + * @param client the client to + * report errors to and to use + * to read files + * @param classFiles the specific + * set of class files to look + * for + * @param classFolders the list of + * class folders to look in + * (to determine the package + * root) + * @param sort if true, sort the + * results + * @return the list of class + * entries, never null. + */ + """ .trimIndent()) } @@ -681,29 +681,29 @@ class KDocFormatterTest { options.hangingIndent = 6 checkFormatter( """ - /** - * Returns the project resources, if available - * - * @param includeModuleDependencies if true, include merged view of - * all module dependencies - * @param includeLibraries if true, include merged view of all - * library dependencies (this also requires all module dependencies) - * @return the project resources, or null if not available - */ - """ + /** + * Returns the project resources, if available + * + * @param includeModuleDependencies if true, include merged view of + * all module dependencies + * @param includeLibraries if true, include merged view of all + * library dependencies (this also requires all module dependencies) + * @return the project resources, or null if not available + */ + """ .trimIndent(), options, """ - /** - * Returns the project resources, if available - * - * @param includeModuleDependencies if true, include merged view of all - * module dependencies - * @param includeLibraries if true, include merged view of all library - * dependencies (this also requires all module dependencies) - * @return the project resources, or null if not available - */ - """ + /** + * Returns the project resources, if available + * + * @param includeModuleDependencies if true, include merged view of all + * module dependencies + * @param includeLibraries if true, include merged view of all library + * dependencies (this also requires all module dependencies) + * @return the project resources, or null if not available + */ + """ .trimIndent()) } @@ -711,21 +711,21 @@ class KDocFormatterTest { fun testBlockTagsHangingIndents2() { checkFormatter( """ - /** - * @param client the client to - * report errors to and to use to - * read files - */ - """ + /** + * @param client the client to + * report errors to and to use to + * read files + */ + """ .trimIndent(), KDocFormattingOptions(40).apply { hangingIndent = 2 }, """ - /** - * @param client the client to - * report errors to and to use to - * read files - */ - """ + /** + * @param client the client to + * report errors to and to use to + * read files + */ + """ .trimIndent()) } @@ -734,17 +734,17 @@ class KDocFormatterTest { // Also tests punctuation feature. val source = """ - /** - * This could all fit on one line - */ - """ + /** + * This could all fit on one line + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72), """ - /** This could all fit on one line */ - """ + /** This could all fit on one line */ + """ .trimIndent()) val options = KDocFormattingOptions(72) options.collapseSingleLine = false @@ -753,10 +753,10 @@ class KDocFormatterTest { source, options, """ - /** - * This could all fit on one line. - */ - """ + /** + * This could all fit on one line. + */ + """ .trimIndent()) } @@ -764,8 +764,8 @@ class KDocFormatterTest { fun testPunctuationWithLabelLink() { val source = """ - /** Default implementation of [MyInterface] */ - """ + /** Default implementation of [MyInterface] */ + """ .trimIndent() val options = KDocFormattingOptions(72) @@ -774,8 +774,8 @@ class KDocFormatterTest { source, options, """ - /** Default implementation of [MyInterface]. */ - """ + /** Default implementation of [MyInterface]. */ + """ .trimIndent()) } @@ -809,7 +809,7 @@ class KDocFormatterTest { * * This is a test. */ - """ + """ .trimIndent()) } @@ -819,17 +819,17 @@ class KDocFormatterTest { // * Do punctuate sentences that end with ` val source = """ - /** - * Calling `setCommunicationDevice()` without `clearCommunicationDevice()` - * - * Creates a [Pattern] corresponding to a [ReplaceString.oldPattern] - * - * There is more documentation for this tool in lint/docs/internal/document-checks.md.html - * - * Initial focus is on the subset used and supported by GitHub: - * https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/sarif-support-for-code-scanning#supported-sarif-output-file-properties - */ - """ + /** + * Calling `setCommunicationDevice()` without `clearCommunicationDevice()` + * + * Creates a [Pattern] corresponding to a [ReplaceString.oldPattern] + * + * There is more documentation for this tool in lint/docs/internal/document-checks.md.html + * + * Initial focus is on the subset used and supported by GitHub: + * https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/sarif-support-for-code-scanning#supported-sarif-output-file-properties + */ + """ .trimIndent() val options = KDocFormattingOptions(72) @@ -838,20 +838,20 @@ class KDocFormatterTest { source, options, """ - /** - * Calling `setCommunicationDevice()` without - * `clearCommunicationDevice()`. - * - * Creates a [Pattern] corresponding to a - * [ReplaceString.oldPattern]. - * - * There is more documentation for this tool in - * lint/docs/internal/document-checks.md.html - * - * Initial focus is on the subset used and supported by GitHub: - * https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/sarif-support-for-code-scanning#supported-sarif-output-file-properties - */ - """ + /** + * Calling `setCommunicationDevice()` without + * `clearCommunicationDevice()`. + * + * Creates a [Pattern] corresponding to a + * [ReplaceString.oldPattern]. + * + * There is more documentation for this tool in + * lint/docs/internal/document-checks.md.html + * + * Initial focus is on the subset used and supported by GitHub: + * https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/sarif-support-for-code-scanning#supported-sarif-output-file-properties + */ + """ .trimIndent()) } @@ -859,11 +859,11 @@ class KDocFormatterTest { fun testWrapingOfLinkText() { val source = """ - /** - * Sometimes the text of a link can have spaces, like [this link's text](https://example.com). - * The following text should wrap like usual. - */ - """ + /** + * Sometimes the text of a link can have spaces, like [this link's text](https://example.com). + * The following text should wrap like usual. + */ + """ .trimIndent() val options = KDocFormattingOptions(72) @@ -871,12 +871,12 @@ class KDocFormatterTest { source, options, """ - /** - * Sometimes the text of a link can have spaces, like - * [this link's text](https://example.com). The following text - * should wrap like usual. - */ - """ + /** + * Sometimes the text of a link can have spaces, like + * [this link's text](https://example.com). The following text + * should wrap like usual. + */ + """ .trimIndent()) } @@ -884,21 +884,21 @@ class KDocFormatterTest { fun testPreformattedTextIndented() { val source = """ - /** - * Parser for the list of forward socket connection returned by the - * `host:forward-list` command. - * - * Input example - * - * ``` - * - * HT75B1A00212 tcp:51222 tcp:5000 HT75B1A00212 tcp:51227 tcp:5001 - * HT75B1A00212 tcp:51232 tcp:5002 HT75B1A00212 tcp:51239 tcp:5003 - * HT75B1A00212 tcp:51244 tcp:5004 - * - * ``` - */ - """ + /** + * Parser for the list of forward socket connection returned by the + * `host:forward-list` command. + * + * Input example + * + * ``` + * + * HT75B1A00212 tcp:51222 tcp:5000 HT75B1A00212 tcp:51227 tcp:5001 + * HT75B1A00212 tcp:51232 tcp:5002 HT75B1A00212 tcp:51239 tcp:5003 + * HT75B1A00212 tcp:51244 tcp:5004 + * + * ``` + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72, 72).apply { convertMarkup = true }, source, indent = "") @@ -908,31 +908,31 @@ class KDocFormatterTest { fun testPreformattedText() { val source = """ - /** - * Code sample: - * - * val s = "hello, and this is code so should not be line broken at all, it should stay on one line"; - * println(s); - * - * This is not preformatted and can be combined into multiple sentences again. - */ - """ + /** + * Code sample: + * + * val s = "hello, and this is code so should not be line broken at all, it should stay on one line"; + * println(s); + * + * This is not preformatted and can be combined into multiple sentences again. + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(40), """ - /** - * Code sample: - * - * val s = "hello, and this is code so should not be line broken at all, it should stay on one line"; - * println(s); - * - * This is not preformatted and - * can be combined into multiple - * sentences again. - */ - """ + /** + * Code sample: + * + * val s = "hello, and this is code so should not be line broken at all, it should stay on one line"; + * println(s); + * + * This is not preformatted and + * can be combined into multiple + * sentences again. + */ + """ .trimIndent()) } @@ -940,33 +940,33 @@ class KDocFormatterTest { fun testPreformattedText2() { val source = """ - /** - * Code sample: - * ```kotlin - * val s = "hello, and this is code so should not be line broken at all, it should stay on one line"; - * println(s); - * ``` - * - * This is not preformatted and can be combined into multiple sentences again. - */ - """ + /** + * Code sample: + * ```kotlin + * val s = "hello, and this is code so should not be line broken at all, it should stay on one line"; + * println(s); + * ``` + * + * This is not preformatted and can be combined into multiple sentences again. + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(40), """ - /** - * Code sample: - * ```kotlin - * val s = "hello, and this is code so should not be line broken at all, it should stay on one line"; - * println(s); - * ``` - * - * This is not preformatted and - * can be combined into multiple - * sentences again. - */ - """ + /** + * Code sample: + * ```kotlin + * val s = "hello, and this is code so should not be line broken at all, it should stay on one line"; + * println(s); + * ``` + * + * This is not preformatted and + * can be combined into multiple + * sentences again. + */ + """ .trimIndent()) } @@ -974,32 +974,32 @@ class KDocFormatterTest { fun testPreformattedText3() { val source = """ - /** - * Code sample: - *
-             *     val s = "hello, and   this is code so should not be line broken at all, it should stay on one line";
-             *     println(s);
-             * 
- * This is not preformatted and can be combined into multiple sentences again. - */ - """ + /** + * Code sample: + *
+         *     val s = "hello, and   this is code so should not be line broken at all, it should stay on one line";
+         *     println(s);
+         * 
+ * This is not preformatted and can be combined into multiple sentences again. + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(40), """ - /** - * Code sample: - * ``` - * val s = "hello, and this is code so should not be line broken at all, it should stay on one line"; - * println(s); - * ``` - * - * This is not preformatted and - * can be combined into multiple - * sentences again. - */ - """ + /** + * Code sample: + * ``` + * val s = "hello, and this is code so should not be line broken at all, it should stay on one line"; + * println(s); + * ``` + * + * This is not preformatted and + * can be combined into multiple + * sentences again. + */ + """ .trimIndent(), //
 and ``` are rendered differently; this is an intentional diff
         verifyDokka = false)
@@ -1009,29 +1009,29 @@ class KDocFormatterTest {
   fun testPreformattedTextWithBlankLines() {
     val source =
         """
-            /**
-             * Code sample:
-             * ```kotlin
-             * val s = "hello, and this is code so should not be line broken at all, it should stay on one line";
-             *
-             * println(s);
-             * ```
-             */
-            """
+        /**
+         * Code sample:
+         * ```kotlin
+         * val s = "hello, and this is code so should not be line broken at all, it should stay on one line";
+         *
+         * println(s);
+         * ```
+         */
+        """
             .trimIndent()
     checkFormatter(
         source,
         KDocFormattingOptions(40),
         """
-            /**
-             * Code sample:
-             * ```kotlin
-             * val s = "hello, and this is code so should not be line broken at all, it should stay on one line";
-             *
-             * println(s);
-             * ```
-             */
-            """
+        /**
+         * Code sample:
+         * ```kotlin
+         * val s = "hello, and this is code so should not be line broken at all, it should stay on one line";
+         *
+         * println(s);
+         * ```
+         */
+        """
             .trimIndent())
   }
 
@@ -1039,29 +1039,29 @@ class KDocFormatterTest {
   fun testPreformattedTextWithBlankLinesAndTrailingSpaces() {
     val source =
         """
-            /**
-             * Code sample:
-             * ```kotlin
-             * val s = "hello, and this is code so should not be line broken at all, it should stay on one line";
-             *
-             * println(s);
-             * ```
-             */
-            """
+        /**
+         * Code sample:
+         * ```kotlin
+         * val s = "hello, and this is code so should not be line broken at all, it should stay on one line";
+         *
+         * println(s);
+         * ```
+         */
+        """
             .trimIndent()
     checkFormatter(
         source,
         KDocFormattingOptions(40),
         """
-            /**
-             * Code sample:
-             * ```kotlin
-             * val s = "hello, and this is code so should not be line broken at all, it should stay on one line";
-             *
-             * println(s);
-             * ```
-             */
-            """
+        /**
+         * Code sample:
+         * ```kotlin
+         * val s = "hello, and this is code so should not be line broken at all, it should stay on one line";
+         *
+         * println(s);
+         * ```
+         */
+        """
             .trimIndent())
   }
 
@@ -1069,41 +1069,41 @@ class KDocFormatterTest {
   fun testPreformattedTextSeparation() {
     val source =
         """
-            /**
-             * For example,
-             *
-             *     val s = "hello, and   this is code so should not be line broken at all, it should stay on one line";
-             *     println(s);
-             * And here's another example:
-             *     This is not preformatted text.
-             *
-             * And a third example,
-             *
-             * ```
-             * Preformatted.
-             * ```
-             */
-            """
+        /**
+         * For example,
+         *
+         *     val s = "hello, and   this is code so should not be line broken at all, it should stay on one line";
+         *     println(s);
+         * And here's another example:
+         *     This is not preformatted text.
+         *
+         * And a third example,
+         *
+         * ```
+         * Preformatted.
+         * ```
+         */
+        """
             .trimIndent()
     checkFormatter(
         source,
         KDocFormattingOptions(40),
         """
-            /**
-             * For example,
-             *
-             *     val s = "hello, and   this is code so should not be line broken at all, it should stay on one line";
-             *     println(s);
-             *
-             * And here's another example: This
-             * is not preformatted text.
-             *
-             * And a third example,
-             * ```
-             * Preformatted.
-             * ```
-             */
-            """
+        /**
+         * For example,
+         *
+         *     val s = "hello, and   this is code so should not be line broken at all, it should stay on one line";
+         *     println(s);
+         *
+         * And here's another example: This
+         * is not preformatted text.
+         *
+         * And a third example,
+         * ```
+         * Preformatted.
+         * ```
+         */
+        """
             .trimIndent())
   }
 
@@ -1113,29 +1113,29 @@ class KDocFormatterTest {
     // paragraphs
     val source =
         """
-            /**
-             * Here's paragraph 1.
-             *
-             * And here's paragraph 2.
-             * 

And here's paragraph 3. - *

And here's paragraph 4. - */ - """ + /** + * Here's paragraph 1. + * + * And here's paragraph 2. + *

And here's paragraph 3. + *

And here's paragraph 4. + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(40).apply { convertMarkup = true }, """ - /** - * Here's paragraph 1. - * - * And here's paragraph 2. - * - * And here's paragraph 3. - * - * And here's paragraph 4. - */ - """ + /** + * Here's paragraph 1. + * + * And here's paragraph 2. + * + * And here's paragraph 3. + * + * And here's paragraph 4. + */ + """ .trimIndent()) } @@ -1144,15 +1144,15 @@ class KDocFormatterTest { // From ktfmt Tokenizer.kt val source = """ - /** - * Tokenizer traverses a Kotlin parse tree (which blessedly contains whitespaces and comments, - * unlike Javac) and constructs a list of 'Tok's. - * - *

The google-java-format infra expects newline Toks to be separate from maximal-whitespace Toks, - * but Kotlin emits them together. So, we split them using Java's \R regex matcher. We don't use - * 'split' et al. because we want Toks for the newlines themselves. - */ - """ + /** + * Tokenizer traverses a Kotlin parse tree (which blessedly contains whitespaces and comments, + * unlike Javac) and constructs a list of 'Tok's. + * + *

The google-java-format infra expects newline Toks to be separate from maximal-whitespace Toks, + * but Kotlin emits them together. So, we split them using Java's \R regex matcher. We don't use + * 'split' et al. because we want Toks for the newlines themselves. + */ + """ .trimIndent() checkFormatter( source, @@ -1161,15 +1161,15 @@ class KDocFormatterTest { optimal = false }, """ - /** - * Tokenizer traverses a Kotlin parse tree (which blessedly contains whitespaces and comments, - * unlike Javac) and constructs a list of 'Tok's. - * - * The google-java-format infra expects newline Toks to be separate from maximal-whitespace Toks, - * but Kotlin emits them together. So, we split them using Java's \R regex matcher. We don't use - * 'split' et al. because we want Toks for the newlines themselves. - */ - """ + /** + * Tokenizer traverses a Kotlin parse tree (which blessedly contains whitespaces and comments, + * unlike Javac) and constructs a list of 'Tok's. + * + * The google-java-format infra expects newline Toks to be separate from maximal-whitespace Toks, + * but Kotlin emits them together. So, we split them using Java's \R regex matcher. We don't use + * 'split' et al. because we want Toks for the newlines themselves. + */ + """ .trimIndent(), indent = "") } @@ -1180,33 +1180,33 @@ class KDocFormatterTest { // paragraphs val source = """ - /** - * This is bold, this is italics, but nothing - * should be converted in `code` or in - * ``` - * preformatted text - * ``` - * And this \` is not code and should be converted. - */ - """ + /** + * This is bold, this is italics, but nothing + * should be converted in `code` or in + * ``` + * preformatted text + * ``` + * And this \` is not code and should be converted. + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(40).apply { convertMarkup = true }, """ - /** - * This is **bold**, this is - * *italics*, but nothing should be - * converted in `code` or in - * - * ``` - * preformatted text - * ``` - * - * And this \` is **not code and - * should be converted**. - */ - """ + /** + * This is **bold**, this is + * *italics*, but nothing should be + * converted in `code` or in + * + * ``` + * preformatted text + * ``` + * + * And this \` is **not code and + * should be converted**. + */ + """ .trimIndent()) } @@ -1214,43 +1214,43 @@ class KDocFormatterTest { fun testFormattingList() { val source = """ - /** - * 1. This is a numbered list. - * 2. This is another item. We should be wrapping extra text under the same item. - * 3. This is the third item. - * - * Unordered list: - * * First - * * Second - * * Third - * - * Other alternatives: - * - First - * - Second - */ - """ + /** + * 1. This is a numbered list. + * 2. This is another item. We should be wrapping extra text under the same item. + * 3. This is the third item. + * + * Unordered list: + * * First + * * Second + * * Third + * + * Other alternatives: + * - First + * - Second + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(40), """ - /** - * 1. This is a numbered list. - * 2. This is another item. We - * should be wrapping extra text - * under the same item. - * 3. This is the third item. - * - * Unordered list: - * * First - * * Second - * * Third - * - * Other alternatives: - * - First - * - Second - */ - """ + /** + * 1. This is a numbered list. + * 2. This is another item. We + * should be wrapping extra text + * under the same item. + * 3. This is the third item. + * + * Unordered list: + * * First + * * Second + * * Third + * + * Other alternatives: + * - First + * - Second + */ + """ .trimIndent()) } @@ -1258,38 +1258,38 @@ class KDocFormatterTest { fun testList1() { val source = """ - /** - * * pre.errorlines: General > Text > Default Text - * * .prefix: XML > Namespace Prefix - * * .attribute: XML > Attribute name - * * .value: XML > Attribute value - * * .tag: XML > Tag name - * * .lineno: For color, General > Code > Line number, Foreground, and for background-color, - * Editor > Gutter background - * * .error: General > Errors and Warnings > Error - */ - """ + /** + * * pre.errorlines: General > Text > Default Text + * * .prefix: XML > Namespace Prefix + * * .attribute: XML > Attribute name + * * .value: XML > Attribute value + * * .tag: XML > Tag name + * * .lineno: For color, General > Code > Line number, Foreground, and for background-color, + * Editor > Gutter background + * * .error: General > Errors and Warnings > Error + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(40), """ - /** - * * pre.errorlines: General > - * Text > Default Text - * * .prefix: XML > Namespace Prefix - * * .attribute: XML > Attribute - * name - * * .value: XML > Attribute value - * * .tag: XML > Tag name - * * .lineno: For color, General > - * Code > Line number, Foreground, - * and for background-color, - * Editor > Gutter background - * * .error: General > Errors and - * Warnings > Error - */ - """ + /** + * * pre.errorlines: General > + * Text > Default Text + * * .prefix: XML > Namespace Prefix + * * .attribute: XML > Attribute + * name + * * .value: XML > Attribute value + * * .tag: XML > Tag name + * * .lineno: For color, General > + * Code > Line number, Foreground, + * and for background-color, + * Editor > Gutter background + * * .error: General > Errors and + * Warnings > Error + */ + """ .trimIndent()) } @@ -1297,36 +1297,36 @@ class KDocFormatterTest { fun testIndentedList() { val source = """ - /** - * Basic usage: - * 1. Create a configuration via [UastEnvironment.Configuration.create] and mutate it as needed. - * 2. Create a project environment via [UastEnvironment.create]. - * You can create multiple environments in the same process (one for each "module"). - * 3. Call [analyzeFiles] to initialize PSI machinery and precompute resolve information. - */ - """ + /** + * Basic usage: + * 1. Create a configuration via [UastEnvironment.Configuration.create] and mutate it as needed. + * 2. Create a project environment via [UastEnvironment.create]. + * You can create multiple environments in the same process (one for each "module"). + * 3. Call [analyzeFiles] to initialize PSI machinery and precompute resolve information. + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(40), """ - /** - * Basic usage: - * 1. Create a configuration via - * [UastEnvironment.Configuration.create] - * and mutate it as needed. - * 2. Create a project environment - * via [UastEnvironment.create]. - * You can create multiple - * environments in the same - * process (one for each - * "module"). - * 3. Call [analyzeFiles] to - * initialize PSI machinery and - * precompute resolve - * information. - */ - """ + /** + * Basic usage: + * 1. Create a configuration via + * [UastEnvironment.Configuration.create] + * and mutate it as needed. + * 2. Create a project environment + * via [UastEnvironment.create]. + * You can create multiple + * environments in the same + * process (one for each + * "module"). + * 3. Call [analyzeFiles] to + * initialize PSI machinery and + * precompute resolve + * information. + */ + """ .trimIndent()) } @@ -1334,25 +1334,25 @@ class KDocFormatterTest { fun testDocTags() { val source = """ - /** - * @param configuration the configuration to look up which issues are - * enabled etc from - * @param platforms the platforms applying to this analysis - */ - """ + /** + * @param configuration the configuration to look up which issues are + * enabled etc from + * @param platforms the platforms applying to this analysis + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(40).apply { hangingIndent = 2 }, """ - /** - * @param configuration the - * configuration to look up which - * issues are enabled etc from - * @param platforms the platforms - * applying to this analysis - */ - """ + /** + * @param configuration the + * configuration to look up which + * issues are enabled etc from + * @param platforms the platforms + * applying to this analysis + */ + """ .trimIndent()) } @@ -1360,30 +1360,30 @@ class KDocFormatterTest { fun testAtInMiddle() { val source = """ - /** - * If non-null, this issue can **only** be suppressed with one of the - * given annotations: not with @Suppress, not with @SuppressLint, not - * with lint.xml, not with lintOptions{} and not with baselines. - * - * Test @IntRange and @FloatRange support annotation applied to - * arrays and vargs. - */ - """ + /** + * If non-null, this issue can **only** be suppressed with one of the + * given annotations: not with @Suppress, not with @SuppressLint, not + * with lint.xml, not with lintOptions{} and not with baselines. + * + * Test @IntRange and @FloatRange support annotation applied to + * arrays and vargs. + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72), """ - /** - * If non-null, this issue can **only** be suppressed with - * one of the given annotations: not with @Suppress, not - * with @SuppressLint, not with lint.xml, not with lintOptions{} and - * not with baselines. - * - * Test @IntRange and @FloatRange support annotation applied to - * arrays and vargs. - */ - """ + /** + * If non-null, this issue can **only** be suppressed with + * one of the given annotations: not with @Suppress, not + * with @SuppressLint, not with lint.xml, not with lintOptions{} and + * not with baselines. + * + * Test @IntRange and @FloatRange support annotation applied to + * arrays and vargs. + */ + """ .trimIndent(), ) } @@ -1392,33 +1392,33 @@ class KDocFormatterTest { fun testMaxCommentWidth() { checkFormatter( """ - /** - * Returns whether lint should check all warnings, - * including those off by default, or null if - *not configured in this configuration. This is a really really really long sentence which needs to be broken up. - * This is a separate section - * which should be flowed together with the first one. - * *bold* should not be removed even at beginning. - */ - """ + /** + * Returns whether lint should check all warnings, + * including those off by default, or null if + *not configured in this configuration. This is a really really really long sentence which needs to be broken up. + * This is a separate section + * which should be flowed together with the first one. + * *bold* should not be removed even at beginning. + */ + """ .trimIndent(), KDocFormattingOptions(maxLineWidth = 100, maxCommentWidth = 30), """ - /** - * Returns whether lint should - * check all warnings, including - * those off by default, or - * null if not configured in - * this configuration. This is - * a really really really long - * sentence which needs to be - * broken up. This is a separate - * section which should be flowed - * together with the first one. - * *bold* should not be removed - * even at beginning. - */ - """ + /** + * Returns whether lint should + * check all warnings, including + * those off by default, or + * null if not configured in + * this configuration. This is + * a really really really long + * sentence which needs to be + * broken up. This is a separate + * section which should be flowed + * together with the first one. + * *bold* should not be removed + * even at beginning. + */ + """ .trimIndent()) } @@ -1426,24 +1426,24 @@ class KDocFormatterTest { fun testHorizontalRuler() { checkFormatter( """ - /** - * This is a header. Should appear alone. - * -------------------------------------- - * - * This should not be on the same line as the header. - */ - """ + /** + * This is a header. Should appear alone. + * -------------------------------------- + * + * This should not be on the same line as the header. + */ + """ .trimIndent(), KDocFormattingOptions(maxLineWidth = 100, maxCommentWidth = 30), """ - /** - * This is a header. Should - * appear alone. - * -------------------------------------- - * This should not be on the same - * line as the header. - */ - """ + /** + * This is a header. Should + * appear alone. + * -------------------------------------- + * This should not be on the same + * line as the header. + */ + """ .trimIndent(), verifyDokka = false) } @@ -1452,32 +1452,32 @@ class KDocFormatterTest { fun testQuoteOnlyOnFirstLine() { checkFormatter( """ - /** - * More: - * > This whole paragraph should be treated as a block quote. - * This whole paragraph should be treated as a block quote. - * This whole paragraph should be treated as a block quote. - * This whole paragraph should be treated as a block quote. - * @sample Sample - */ - """ + /** + * More: + * > This whole paragraph should be treated as a block quote. + * This whole paragraph should be treated as a block quote. + * This whole paragraph should be treated as a block quote. + * This whole paragraph should be treated as a block quote. + * @sample Sample + */ + """ .trimIndent(), KDocFormattingOptions(maxLineWidth = 100, maxCommentWidth = 30), """ - /** - * More: - * > This whole paragraph should - * > be treated as a block quote. - * > This whole paragraph should - * > be treated as a block quote. - * > This whole paragraph should - * > be treated as a block quote. - * > This whole paragraph should - * > be treated as a block quote. - * - * @sample Sample - */ - """ + /** + * More: + * > This whole paragraph should + * > be treated as a block quote. + * > This whole paragraph should + * > be treated as a block quote. + * > This whole paragraph should + * > be treated as a block quote. + * > This whole paragraph should + * > be treated as a block quote. + * + * @sample Sample + */ + """ .trimIndent()) } @@ -1485,21 +1485,21 @@ class KDocFormatterTest { fun testNoBreakUrl() { checkFormatter( """ - /** - * # Design - * The splash screen icon uses the same specifications as - * [Adaptive Icons](https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive) - */ - """ + /** + * # Design + * The splash screen icon uses the same specifications as + * [Adaptive Icons](https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive) + */ + """ .trimIndent(), KDocFormattingOptions(maxLineWidth = 100, maxCommentWidth = 100), """ - /** - * # Design - * The splash screen icon uses the same specifications as - * [Adaptive Icons](https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive) - */ - """ + /** + * # Design + * The splash screen icon uses the same specifications as + * [Adaptive Icons](https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive) + */ + """ .trimIndent()) } @@ -1509,48 +1509,48 @@ class KDocFormatterTest { // https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-master-dev:build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/bundle/DynamicFeatureAndroidTestBuildTest.kt checkFormatter( """ - /** - * Base <------------ Middle DF <------------- DF <--------- Android Test DF - * / \ / \ | / \ \ - * v v v v v v \ \ - * appLib sharedLib midLib sharedMidLib featureLib testFeatureLib \ \ - * ^ ^_______________________________________/ / - * |________________________________________________________________/ - * - * DF has a feature-on-feature dep on Middle DF, both depend on Base, Android Test DF is an - * android test variant for DF. - * - * Base depends on appLib and sharedLib. - * Middle DF depends on midLib and sharedMidLib. - * DF depends on featureLib. - * DF also has an android test dependency on testFeatureLib, shared and sharedMidLib. - */ - """ + /** + * Base <------------ Middle DF <------------- DF <--------- Android Test DF + * / \ / \ | / \ \ + * v v v v v v \ \ + * appLib sharedLib midLib sharedMidLib featureLib testFeatureLib \ \ + * ^ ^_______________________________________/ / + * |________________________________________________________________/ + * + * DF has a feature-on-feature dep on Middle DF, both depend on Base, Android Test DF is an + * android test variant for DF. + * + * Base depends on appLib and sharedLib. + * Middle DF depends on midLib and sharedMidLib. + * DF depends on featureLib. + * DF also has an android test dependency on testFeatureLib, shared and sharedMidLib. + */ + """ .trimIndent(), KDocFormattingOptions(maxLineWidth = 100, maxCommentWidth = 30), """ - /** - * Base <------------ Middle DF <------------- DF <--------- Android Test DF - * / \ / \ | / \ \ - * v v v v v v \ \ - * appLib sharedLib midLib sharedMidLib featureLib testFeatureLib \ \ - * ^ ^_______________________________________/ / - * |________________________________________________________________/ - * - * DF has a feature-on-feature - * dep on Middle DF, both depend - * on Base, Android Test DF is an - * android test variant for DF. - * - * Base depends on appLib and - * sharedLib. Middle DF depends - * on midLib and sharedMidLib. DF - * depends on featureLib. DF also - * has an android test dependency - * on testFeatureLib, shared and - * sharedMidLib. - */ - """ + /** + * Base <------------ Middle DF <------------- DF <--------- Android Test DF + * / \ / \ | / \ \ + * v v v v v v \ \ + * appLib sharedLib midLib sharedMidLib featureLib testFeatureLib \ \ + * ^ ^_______________________________________/ / + * |________________________________________________________________/ + * + * DF has a feature-on-feature + * dep on Middle DF, both depend + * on Base, Android Test DF is an + * android test variant for DF. + * + * Base depends on appLib and + * sharedLib. Middle DF depends + * on midLib and sharedMidLib. DF + * depends on featureLib. DF also + * has an android test dependency + * on testFeatureLib, shared and + * sharedMidLib. + */ + """ .trimIndent()) } @@ -1558,25 +1558,25 @@ class KDocFormatterTest { fun testAsciiArt2() { checkFormatter( """ - /** - * +-> lib1 - * | - * feature1 ---+-> javalib1 - * | - * +-> baseModule - */ - """ + /** + * +-> lib1 + * | + * feature1 ---+-> javalib1 + * | + * +-> baseModule + */ + """ .trimIndent(), KDocFormattingOptions(maxLineWidth = 100, maxCommentWidth = 30), """ - /** - * +-> lib1 - * | - * feature1 ---+-> javalib1 - * | - * +-> baseModule - */ - """ + /** + * +-> lib1 + * | + * feature1 ---+-> javalib1 + * | + * +-> baseModule + */ + """ .trimIndent()) } @@ -1584,52 +1584,52 @@ class KDocFormatterTest { fun testAsciiArt3() { val source = """ - /** - * This test creates a layout of this shape: - * - * --------------- - * | t | | - * | | | - * | |-------| | - * | | t | | - * | | | | - * | | | | - * |--| |-------| - * | | | t | - * | | | | - * | | | | - * | |--| | - * | | | - * --------------- - * - * There are 3 staggered children and 3 pointers, the first is on child 1, the second is on - * child 2 in a space that overlaps child 1, and the third is in a space in child 3 that - * overlaps child 2. - */ - """ + /** + * This test creates a layout of this shape: + * + * --------------- + * | t | | + * | | | + * | |-------| | + * | | t | | + * | | | | + * | | | | + * |--| |-------| + * | | | t | + * | | | | + * | | | | + * | |--| | + * | | | + * --------------- + * + * There are 3 staggered children and 3 pointers, the first is on child 1, the second is on + * child 2 in a space that overlaps child 1, and the third is in a space in child 3 that + * overlaps child 2. + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(maxLineWidth = 100, maxCommentWidth = 30), """ - /** - * This test creates a layout of - * this shape: - * --------------- - * | t | | | | | | |-------| | | - * | t | | | | | | | | | | |--| - * |-------| | | | t | | | | | | - * | | | | |--| | | | | - * --------------- - * There are 3 staggered children - * and 3 pointers, the first is - * on child 1, the second is - * on child 2 in a space that - * overlaps child 1, and the - * third is in a space in child - * 3 that overlaps child 2. - */ - """ + /** + * This test creates a layout of + * this shape: + * --------------- + * | t | | | | | | |-------| | | + * | t | | | | | | | | | | |--| + * |-------| | | | t | | | | | | + * | | | | |--| | | | | + * --------------- + * There are 3 staggered children + * and 3 pointers, the first is + * on child 1, the second is + * on child 2 in a space that + * overlaps child 1, and the + * third is in a space in child + * 3 that overlaps child 2. + */ + """ .trimIndent(), indent = "") } @@ -1641,47 +1641,47 @@ class KDocFormatterTest { // From androidx' TwoDimensionalFocusTraversalOutTest.kt checkFormatter( """ - /** - * ___________________________ - * | grandparent | - * | _____________________ | - * | | parent | | - * | | _______________ | | ____________ - * | | | focusedItem | | | | nextItem | - * | | |______________| | | |___________| - * | |____________________| | - * |__________________________| - * - * __________________________ - * | grandparent | - * | ____________________ | - * | | parent | | - * | | ______________ | | - * | | | focusedItem | | | - * | | |_____________| | | - * | |___________________| | - * |_________________________| - */ - """ + /** + * ___________________________ + * | grandparent | + * | _____________________ | + * | | parent | | + * | | _______________ | | ____________ + * | | | focusedItem | | | | nextItem | + * | | |______________| | | |___________| + * | |____________________| | + * |__________________________| + * + * __________________________ + * | grandparent | + * | ____________________ | + * | | parent | | + * | | ______________ | | + * | | | focusedItem | | | + * | | |_____________| | | + * | |___________________| | + * |_________________________| + */ + """ .trimIndent(), KDocFormattingOptions(maxLineWidth = 100, 100), """ - /** - * ___________________________ | grandparent | | _____________________ | | | parent - * | | | | _______________ | | ____________ | | | focusedItem | | | | nextItem | | | - * |______________| | | |___________| | |____________________| | |__________________________| - * - * __________________________ - * | grandparent | - * | ____________________ | - * | | parent | | - * | | ______________ | | - * | | | focusedItem | | | - * | | |_____________| | | - * | |___________________| | - * |_________________________| - */ - """ + /** + * ___________________________ | grandparent | | _____________________ | | | parent + * | | | | _______________ | | ____________ | | | focusedItem | | | | nextItem | | | + * |______________| | | |___________| | |____________________| | |__________________________| + * + * __________________________ + * | grandparent | + * | ____________________ | + * | | parent | | + * | | ______________ | | + * | | | focusedItem | | | + * | | |_____________| | | + * | |___________________| | + * |_________________________| + */ + """ .trimIndent(), verifyDokka = false) } @@ -1690,26 +1690,26 @@ class KDocFormatterTest { fun testHtmlLists() { checkFormatter( """ - /** - *

    - *
  • Incremental merge will never clean the output. - *
  • The inputs must be able to tell which changes to relative files have been made. - *
  • Intermediate state must be saved between merges. - *
- */ - """ + /** + *
    + *
  • Incremental merge will never clean the output. + *
  • The inputs must be able to tell which changes to relative files have been made. + *
  • Intermediate state must be saved between merges. + *
+ */ + """ .trimIndent(), KDocFormattingOptions(maxLineWidth = 100, maxCommentWidth = 60).apply { hangingIndent = 2 }, """ - /** - *
    - *
  • Incremental merge will never clean the output. - *
  • The inputs must be able to tell which changes to - * relative files have been made. - *
  • Intermediate state must be saved between merges. - *
- */ - """ + /** + *
    + *
  • Incremental merge will never clean the output. + *
  • The inputs must be able to tell which changes to + * relative files have been made. + *
  • Intermediate state must be saved between merges. + *
+ */ + """ .trimIndent()) } @@ -1717,172 +1717,172 @@ class KDocFormatterTest { fun testVariousMarkup() { val source = """ - /** - * This document contains a bunch of markup examples - * that I will use - * to verify that things are handled - * correctly via markdown. - * - * This is a header. Should appear alone. - * -------------------------------------- - * This should not be on the same line as the header. - * - * This is a header. Should appear alone. - * - - * This should not be on the same line as the header. - * - * This is a header. Should appear alone. - * ====================================== - * This should not be on the same line as the header. - * - * This is a header. Should appear alone. - * = - * This should not be on the same line as the header. - * Note that we don't treat this as a header - * because it's not on its own line. Instead - * it's considered a separating line. - * --- - * More text. Should not be on the previous line. - * - * --- This usage of --- where it's not on its own - * line should not be used as a header or separator line. - * - * List stuff: - * 1. First item - * 2. Second item - * 3. Third item - * - * # Text styles # - * **Bold**, *italics*. \*Not italics\*. - * - * ## More text styles - * ~~strikethrough~~, _underlined_. - * - * ### Blockquotes # - * - * More: - * > This whole paragraph should be treated as a block quote. - * This whole paragraph should be treated as a block quote. - * This whole paragraph should be treated as a block quote. - * This whole paragraph should be treated as a block quote. - * - * ### Lists - * Plus lists: - * + First - * + Second - * + Third - * - * Dash lists: - * - First - * - Second - * - Third - * - * List items with multiple paragraphs: - * - * * This is my list item. It has - * text on many lines. - * - * This is a continuation of the first bullet. - * * And this is the second. - * - * ### Code blocks in list items - * - * Escapes: I should look for cases where I place a number followed - * by a period (or asterisk) at the beginning of a line and if so, - * escape it: - * - * The meaning of life: - * 42\. This doesn't seem to work in IntelliJ's markdown formatter. - * - * ### Horizontal rules - * ********* - * --------- - * *** - * * * * - * - - - - */ - """ + /** + * This document contains a bunch of markup examples + * that I will use + * to verify that things are handled + * correctly via markdown. + * + * This is a header. Should appear alone. + * -------------------------------------- + * This should not be on the same line as the header. + * + * This is a header. Should appear alone. + * - + * This should not be on the same line as the header. + * + * This is a header. Should appear alone. + * ====================================== + * This should not be on the same line as the header. + * + * This is a header. Should appear alone. + * = + * This should not be on the same line as the header. + * Note that we don't treat this as a header + * because it's not on its own line. Instead + * it's considered a separating line. + * --- + * More text. Should not be on the previous line. + * + * --- This usage of --- where it's not on its own + * line should not be used as a header or separator line. + * + * List stuff: + * 1. First item + * 2. Second item + * 3. Third item + * + * # Text styles # + * **Bold**, *italics*. \*Not italics\*. + * + * ## More text styles + * ~~strikethrough~~, _underlined_. + * + * ### Blockquotes # + * + * More: + * > This whole paragraph should be treated as a block quote. + * This whole paragraph should be treated as a block quote. + * This whole paragraph should be treated as a block quote. + * This whole paragraph should be treated as a block quote. + * + * ### Lists + * Plus lists: + * + First + * + Second + * + Third + * + * Dash lists: + * - First + * - Second + * - Third + * + * List items with multiple paragraphs: + * + * * This is my list item. It has + * text on many lines. + * + * This is a continuation of the first bullet. + * * And this is the second. + * + * ### Code blocks in list items + * + * Escapes: I should look for cases where I place a number followed + * by a period (or asterisk) at the beginning of a line and if so, + * escape it: + * + * The meaning of life: + * 42\. This doesn't seem to work in IntelliJ's markdown formatter. + * + * ### Horizontal rules + * ********* + * --------- + * *** + * * * * + * - - - + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(100, 100), """ - /** - * This document contains a bunch of markup examples that I will use to verify that things are - * handled correctly via markdown. - * - * This is a header. Should appear alone. - * -------------------------------------- - * This should not be on the same line as the header. - * - * This is a header. Should appear alone. - * - - * This should not be on the same line as the header. - * - * This is a header. Should appear alone. - * ====================================== - * This should not be on the same line as the header. - * - * This is a header. Should appear alone. - * = - * This should not be on the same line as the header. Note that we don't treat this as a header - * because it's not on its own line. Instead it's considered a separating line. - * --- - * More text. Should not be on the previous line. - * - * --- This usage of --- where it's not on its own line should not be used as a header or - * separator line. - * - * List stuff: - * 1. First item - * 2. Second item - * 3. Third item - * - * # Text styles # - * **Bold**, *italics*. \*Not italics\*. - * - * ## More text styles - * ~~strikethrough~~, _underlined_. - * - * ### Blockquotes # - * - * More: - * > This whole paragraph should be treated as a block quote. This whole paragraph should be - * > treated as a block quote. This whole paragraph should be treated as a block quote. This whole - * > paragraph should be treated as a block quote. - * - * ### Lists - * Plus lists: - * + First - * + Second - * + Third - * - * Dash lists: - * - First - * - Second - * - Third - * - * List items with multiple paragraphs: - * * This is my list item. It has text on many lines. - * - * This is a continuation of the first bullet. - * * And this is the second. - * - * ### Code blocks in list items - * - * Escapes: I should look for cases where I place a number followed by a period (or asterisk) at - * the beginning of a line and if so, escape it: - * - * The meaning of life: 42\. This doesn't seem to work in IntelliJ's markdown formatter. - * - * ### Horizontal rules - * ********* - * --------- - * *** - * * * * - * - - - - */ - """ + /** + * This document contains a bunch of markup examples that I will use to verify that things are + * handled correctly via markdown. + * + * This is a header. Should appear alone. + * -------------------------------------- + * This should not be on the same line as the header. + * + * This is a header. Should appear alone. + * - + * This should not be on the same line as the header. + * + * This is a header. Should appear alone. + * ====================================== + * This should not be on the same line as the header. + * + * This is a header. Should appear alone. + * = + * This should not be on the same line as the header. Note that we don't treat this as a header + * because it's not on its own line. Instead it's considered a separating line. + * --- + * More text. Should not be on the previous line. + * + * --- This usage of --- where it's not on its own line should not be used as a header or + * separator line. + * + * List stuff: + * 1. First item + * 2. Second item + * 3. Third item + * + * # Text styles # + * **Bold**, *italics*. \*Not italics\*. + * + * ## More text styles + * ~~strikethrough~~, _underlined_. + * + * ### Blockquotes # + * + * More: + * > This whole paragraph should be treated as a block quote. This whole paragraph should be + * > treated as a block quote. This whole paragraph should be treated as a block quote. This whole + * > paragraph should be treated as a block quote. + * + * ### Lists + * Plus lists: + * + First + * + Second + * + Third + * + * Dash lists: + * - First + * - Second + * - Third + * + * List items with multiple paragraphs: + * * This is my list item. It has text on many lines. + * + * This is a continuation of the first bullet. + * * And this is the second. + * + * ### Code blocks in list items + * + * Escapes: I should look for cases where I place a number followed by a period (or asterisk) at + * the beginning of a line and if so, escape it: + * + * The meaning of life: 42\. This doesn't seem to work in IntelliJ's markdown formatter. + * + * ### Horizontal rules + * ********* + * --------- + * *** + * * * * + * - - - + */ + """ .trimIndent()) } @@ -1890,26 +1890,26 @@ class KDocFormatterTest { fun testLineComments() { val source = """ - // - // Information about a request to run lint. - // - // **NOTE: This is not a public or final API; if you rely on this be prepared - // to adjust your code for the next tools release.** - // - """ + // + // Information about a request to run lint. + // + // **NOTE: This is not a public or final API; if you rely on this be prepared + // to adjust your code for the next tools release.** + // + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(40), """ - // Information about a request to - // run lint. - // - // **NOTE: This is not a public or - // final API; if you rely on this be - // prepared to adjust your code for - // the next tools release.** - """ + // Information about a request to + // run lint. + // + // **NOTE: This is not a public or + // final API; if you rely on this be + // prepared to adjust your code for + // the next tools release.** + """ .trimIndent()) } @@ -1917,16 +1917,16 @@ class KDocFormatterTest { fun testMoreLineComments() { val source = """ - // Do not clean - // this - """ + // Do not clean + // this + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(70), """ - // Do not clean this - """ + // Do not clean this + """ .trimIndent()) } @@ -1934,28 +1934,28 @@ class KDocFormatterTest { fun testListContinuations() { val source = """ - /** - * * This is my list item. It has - * text on many lines. - * - * This is a continuation of the first bullet. - * * And this is the second. - */ - """ + /** + * * This is my list item. It has + * text on many lines. + * + * This is a continuation of the first bullet. + * * And this is the second. + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(40), """ - /** - * * This is my list item. It has - * text on many lines. - * - * This is a continuation of the - * first bullet. - * * And this is the second. - */ - """ + /** + * * This is my list item. It has + * text on many lines. + * + * This is a continuation of the + * first bullet. + * * And this is the second. + */ + """ .trimIndent()) } @@ -1971,7 +1971,7 @@ class KDocFormatterTest { This is a continuation of the first bullet. * And this is the second. - """ + """ .trimIndent() .split("\n") .joinToString(separator = "\n") { " * $it".trimEnd() } + @@ -1981,14 +1981,14 @@ class KDocFormatterTest { source, KDocFormattingOptions(100), """ - /** - * List items with multiple paragraphs: - * * This is my list item. It has text on many lines. - * - * This is a continuation of the first bullet. - * * And this is the second. - */ - """ + /** + * List items with multiple paragraphs: + * * This is my list item. It has text on many lines. + * + * This is a continuation of the first bullet. + * * And this is the second. + */ + """ .trimIndent()) } @@ -1996,13 +1996,13 @@ class KDocFormatterTest { fun testAccidentalHeader() { val source = """ - /** - * Constructs a simplified version of the internal JVM description of the given method. This is - * in the same format as {@link #getMethodDescription} above, the difference being we don't have - * the actual PSI for the method type, we just construct the signature from the [method] name, - * the list of [argumentTypes] and optionally include the [returnType]. - */ - """ + /** + * Constructs a simplified version of the internal JVM description of the given method. This is + * in the same format as {@link #getMethodDescription} above, the difference being we don't have + * the actual PSI for the method type, we just construct the signature from the [method] name, + * the list of [argumentTypes] and optionally include the [returnType]. + */ + """ .trimIndent() checkFormatter( source, @@ -2011,15 +2011,15 @@ class KDocFormatterTest { // be re-interpreted as a header next time we format it! // Idea: @{link #} should become {@link#} or with a nbsp; """ - /** - * Constructs a simplified version of the internal JVM - * description of the given method. This is in the same format as - * [getMethodDescription] above, the difference being we don't - * have the actual PSI for the method type, we just construct the - * signature from the [method] name, the list of [argumentTypes] and - * optionally include the [returnType]. - */ - """ + /** + * Constructs a simplified version of the internal JVM + * description of the given method. This is in the same format as + * [getMethodDescription] above, the difference being we don't + * have the actual PSI for the method type, we just construct the + * signature from the [method] name, the list of [argumentTypes] and + * optionally include the [returnType]. + */ + """ .trimIndent(), // {@link} text is not rendered by dokka when it cannot resolve the symbols verifyDokka = false) @@ -2029,30 +2029,30 @@ class KDocFormatterTest { fun testTODO() { val source = """ - /** - * Adds the given dependency graph (the output of the Gradle dependency task) - * to be constructed when mocking a Gradle model for this project. - *

- * To generate this, run for example - *

-             *     ./gradlew :app:dependencies
-             * 
- * and then look at the debugCompileClasspath (or other graph that you want - * to model). - * TODO: Adds the given dependency graph (the output of the Gradle dependency task) - * to be constructed when mocking a Gradle model for this project. - * TODO: More stuff to do here - * @param dependencyGraph the graph description - * @return this for constructor chaining - * TODO: Consider looking at the localization="suggested" attribute in - * the platform attrs.xml to catch future recommended attributes. - * TODO: Also adds the given dependency graph (the output of the Gradle dependency task) - * to be constructed when mocking a Gradle model for this project. - * TODO(b/144576310): Cover multi-module search. - * Searching in the search bar should show an option to change module if there are resources in it. - * TODO(myldap): Cover filter usage. Eg: Look for a framework resource by enabling its filter. - */ - """ + /** + * Adds the given dependency graph (the output of the Gradle dependency task) + * to be constructed when mocking a Gradle model for this project. + *

+ * To generate this, run for example + *

+         *     ./gradlew :app:dependencies
+         * 
+ * and then look at the debugCompileClasspath (or other graph that you want + * to model). + * TODO: Adds the given dependency graph (the output of the Gradle dependency task) + * to be constructed when mocking a Gradle model for this project. + * TODO: More stuff to do here + * @param dependencyGraph the graph description + * @return this for constructor chaining + * TODO: Consider looking at the localization="suggested" attribute in + * the platform attrs.xml to catch future recommended attributes. + * TODO: Also adds the given dependency graph (the output of the Gradle dependency task) + * to be constructed when mocking a Gradle model for this project. + * TODO(b/144576310): Cover multi-module search. + * Searching in the search bar should show an option to change module if there are resources in it. + * TODO(myldap): Cover filter usage. Eg: Look for a framework resource by enabling its filter. + */ + """ .trimIndent() checkFormatter( source, @@ -2064,40 +2064,40 @@ class KDocFormatterTest { // be re-interpreted as a header next time we format it! // Idea: @{link #} should become {@link#} or with a nbsp; """ - /** - * Adds the given dependency graph (the output of the Gradle - * dependency task) to be constructed when mocking a Gradle model - * for this project. - * - * To generate this, run for example - * - * ``` - * ./gradlew :app:dependencies - * ``` - * - * and then look at the debugCompileClasspath (or other graph that - * you want to model). - * - * @param dependencyGraph the graph description - * @return this for constructor chaining - * - * TODO: Adds the given dependency graph (the output of the Gradle - * dependency task) to be constructed when mocking a Gradle model - * for this project. - * TODO: More stuff to do here - * TODO: Consider looking at the localization="suggested" attribute - * in the platform attrs.xml to catch future recommended - * attributes. - * TODO: Also adds the given dependency graph (the output of the - * Gradle dependency task) to be constructed when mocking a Gradle - * model for this project. - * TODO(b/144576310): Cover multi-module search. Searching in the - * search bar should show an option to change module if there are - * resources in it. - * TODO(myldap): Cover filter usage. Eg: Look for a framework - * resource by enabling its filter. - */ - """ + /** + * Adds the given dependency graph (the output of the Gradle + * dependency task) to be constructed when mocking a Gradle model + * for this project. + * + * To generate this, run for example + * + * ``` + * ./gradlew :app:dependencies + * ``` + * + * and then look at the debugCompileClasspath (or other graph that + * you want to model). + * + * @param dependencyGraph the graph description + * @return this for constructor chaining + * + * TODO: Adds the given dependency graph (the output of the Gradle + * dependency task) to be constructed when mocking a Gradle model + * for this project. + * TODO: More stuff to do here + * TODO: Consider looking at the localization="suggested" attribute + * in the platform attrs.xml to catch future recommended + * attributes. + * TODO: Also adds the given dependency graph (the output of the + * Gradle dependency task) to be constructed when mocking a Gradle + * model for this project. + * TODO(b/144576310): Cover multi-module search. Searching in the + * search bar should show an option to change module if there are + * resources in it. + * TODO(myldap): Cover filter usage. Eg: Look for a framework + * resource by enabling its filter. + */ + """ .trimIndent(), // We indent TO-DO text deliberately, though this changes the structure to // make each item have its own paragraph which doesn't happen by default. @@ -2109,21 +2109,21 @@ class KDocFormatterTest { fun testReorderTags() { val source = """ - /** - * Constructs a new location range for the given file, from start to - * end. If the length of the range is not known, end may be null. - * - * @return Something - * @sample Other - * @param file the associated file (but see the documentation for - * [Location.file] for more information on what the file - * represents) - * - * @param end the ending position, or null - * @param[ start ] the starting position, or null - * @see More - */ - """ + /** + * Constructs a new location range for the given file, from start to + * end. If the length of the range is not known, end may be null. + * + * @return Something + * @sample Other + * @param file the associated file (but see the documentation for + * [Location.file] for more information on what the file + * represents) + * + * @param end the ending position, or null + * @param[ start ] the starting position, or null + * @see More + */ + """ .trimIndent() checkFormatter( FormattingTask( @@ -2135,20 +2135,20 @@ class KDocFormatterTest { // be re-interpreted as a header next time we format it! // Idea: @{link #} should become {@link#} or with a nbsp; """ - /** - * Constructs a new location range for the given file, from start to - * end. If the length of the range is not known, end may be null. - * - * @param file the associated file (but see the documentation for - * [Location.file] for more information on what the file - * represents) - * @param start the starting position, or null - * @param end the ending position, or null - * @return Something - * @sample Other - * @see More - */ - """ + /** + * Constructs a new location range for the given file, from start to + * end. If the length of the range is not known, end may be null. + * + * @param file the associated file (but see the documentation for + * [Location.file] for more information on what the file + * represents) + * @param start the starting position, or null + * @param end the ending position, or null + * @return Something + * @sample Other + * @see More + */ + """ .trimIndent(), ) } @@ -2157,24 +2157,24 @@ class KDocFormatterTest { fun testNoReorderSample() { val source = """ - /** - * Constructs a new location range for the given file, from start to - * end. If the length of the range is not known, end may be null. - * - * @sample abc - * - * You might want to see another sample. - * - * @sample xyz - * - * Makes sense? - * @return Something - * @see more - * @sample foo - * - * Note that samples after another tag don't get special treatment. - */ - """ + /** + * Constructs a new location range for the given file, from start to + * end. If the length of the range is not known, end may be null. + * + * @sample abc + * + * You might want to see another sample. + * + * @sample xyz + * + * Makes sense? + * @return Something + * @see more + * @sample foo + * + * Note that samples after another tag don't get special treatment. + */ + """ .trimIndent() checkFormatter( FormattingTask( @@ -2183,26 +2183,26 @@ class KDocFormatterTest { " ", orderedParameterNames = listOf("file", "start", "end")), """ - /** - * Constructs a new location range for the given file, from start to - * end. If the length of the range is not known, end may be null. - * - * @sample abc - * - * You might want to see another sample. - * - * @sample xyz - * - * Makes sense? - * - * @return Something - * @sample foo - * - * Note that samples after another tag don't get special treatment. - * - * @see more - */ - """ + /** + * Constructs a new location range for the given file, from start to + * end. If the length of the range is not known, end may be null. + * + * @sample abc + * + * You might want to see another sample. + * + * @sample xyz + * + * Makes sense? + * + * @return Something + * @sample foo + * + * Note that samples after another tag don't get special treatment. + * + * @see more + */ + """ .trimIndent(), ) } @@ -2213,48 +2213,48 @@ class KDocFormatterTest { // frameworks/support/biometric/biometric-ktx/src/main/java/androidx/biometric/auth/CredentialAuthExtensions.kt val source = """ - /** - * Shows an authentication prompt to the user. - * - * @param host A wrapper for the component that will host the prompt. - * @param crypto A cryptographic object to be associated with this authentication. - * - * @return [AuthenticationResult] for a successful authentication. - * - * @throws AuthPromptErrorException when an unrecoverable error has been encountered and - * authentication has stopped. - * @throws AuthPromptFailureException when an authentication attempt by the user has been rejected. - * - * @see CredentialAuthPrompt.authenticate( - * AuthPromptHost host, - * BiometricPrompt.CryptoObject, - * AuthPromptCallback - * ) - * - * @sample androidx.biometric.samples.auth.credentialAuth - */ + /** + * Shows an authentication prompt to the user. + * + * @param host A wrapper for the component that will host the prompt. + * @param crypto A cryptographic object to be associated with this authentication. + * + * @return [AuthenticationResult] for a successful authentication. + * + * @throws AuthPromptErrorException when an unrecoverable error has been encountered and + * authentication has stopped. + * @throws AuthPromptFailureException when an authentication attempt by the user has been rejected. + * + * @see CredentialAuthPrompt.authenticate( + * AuthPromptHost host, + * BiometricPrompt.CryptoObject, + * AuthPromptCallback + * ) + * + * @sample androidx.biometric.samples.auth.credentialAuth + */ """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72, 72).apply { hangingIndent = 2 }, """ - /** - * Shows an authentication prompt to the user. - * - * @param host A wrapper for the component that will host the prompt. - * @param crypto A cryptographic object to be associated with this - * authentication. - * @return [AuthenticationResult] for a successful authentication. - * @throws AuthPromptErrorException when an unrecoverable error has been - * encountered and authentication has stopped. - * @throws AuthPromptFailureException when an authentication attempt by - * the user has been rejected. - * @sample androidx.biometric.samples.auth.credentialAuth - * @see CredentialAuthPrompt.authenticate( AuthPromptHost host, - * BiometricPrompt.CryptoObject, AuthPromptCallback ) - */ - """ + /** + * Shows an authentication prompt to the user. + * + * @param host A wrapper for the component that will host the prompt. + * @param crypto A cryptographic object to be associated with this + * authentication. + * @return [AuthenticationResult] for a successful authentication. + * @throws AuthPromptErrorException when an unrecoverable error has been + * encountered and authentication has stopped. + * @throws AuthPromptFailureException when an authentication attempt by + * the user has been rejected. + * @sample androidx.biometric.samples.auth.credentialAuth + * @see CredentialAuthPrompt.authenticate( AuthPromptHost host, + * BiometricPrompt.CryptoObject, AuthPromptCallback ) + */ + """ .trimIndent(), indent = "", ) @@ -2267,478 +2267,478 @@ class KDocFormatterTest { // indentation, trimming blank lines from the end, etc. val source = """ - /** - * Interface to be implemented by lint detectors that want to analyze - * Java source files (or other similar source files, such as Kotlin files.) - *

- * There are several different common patterns for detecting issues: - *

    - *
  • Checking calls to a given method. For this see - * {@link #getApplicableMethodNames()} and - * {@link #visitMethodCall(JavaContext, UCallExpression, PsiMethod)}
  • - *
  • Instantiating a given class. For this, see - * {@link #getApplicableConstructorTypes()} and - * {@link #visitConstructor(JavaContext, UCallExpression, PsiMethod)}
  • - *
  • Referencing a given constant. For this, see - * {@link #getApplicableReferenceNames()} and - * {@link #visitReference(JavaContext, UReferenceExpression, PsiElement)}
  • - *
  • Extending a given class or implementing a given interface. - * For this, see {@link #applicableSuperClasses()} and - * {@link #visitClass(JavaContext, UClass)}
  • - *
  • More complicated scenarios: perform a general AST - * traversal with a visitor. In this case, first tell lint which - * AST node types you're interested in with the - * {@link #getApplicableUastTypes()} method, and then provide a - * {@link UElementHandler} from the {@link #createUastHandler(JavaContext)} - * where you override the various applicable handler methods. This is - * done rather than a general visitor from the root node to avoid - * having to have every single lint detector (there are hundreds) do a full - * tree traversal on its own.
  • - *
- *

- * {@linkplain SourceCodeScanner} exposes the UAST API to lint checks. - * UAST is short for "Universal AST" and is an abstract syntax tree library - * which abstracts away details about Java versus Kotlin versus other similar languages - * and lets the client of the library access the AST in a unified way. - *

- * UAST isn't actually a full replacement for PSI; it augments PSI. - * Essentially, UAST is used for the inside of methods (e.g. method bodies), - * and things like field initializers. PSI continues to be used at the outer - * level: for packages, classes, and methods (declarations and signatures). - * There are also wrappers around some of these for convenience. - *

- * The {@linkplain SourceCodeScanner} interface reflects this fact. For example, - * when you indicate that you want to check calls to a method named {@code foo}, - * the call site node is a UAST node (in this case, {@link UCallExpression}, - * but the called method itself is a {@link PsiMethod}, since that method - * might be anywhere (including in a library that we don't have source for, - * so UAST doesn't make sense.) - *

- *

Migrating JavaPsiScanner to SourceCodeScanner

- * As described above, PSI is still used, so a lot of code will remain the - * same. For example, all resolve methods, including those in UAST, will - * continue to return PsiElement, not necessarily a UElement. For example, - * if you resolve a method call or field reference, you'll get a - * {@link PsiMethod} or {@link PsiField} back. - *

- * However, the visitor methods have all changed, generally to change - * to UAST types. For example, the signature - * {@link JavaPsiScanner#visitMethodCall(JavaContext, JavaElementVisitor, PsiMethodCallExpression, PsiMethod)} - * should be changed to {@link SourceCodeScanner#visitMethodCall(JavaContext, UCallExpression, PsiMethod)}. - *

- * Similarly, replace {@link JavaPsiScanner#createPsiVisitor} with {@link SourceCodeScanner#createUastHandler}, - * {@link JavaPsiScanner#getApplicablePsiTypes()} with {@link SourceCodeScanner#getApplicableUastTypes()}, etc. - *

- * There are a bunch of new methods on classes like {@link JavaContext} which lets - * you pass in a {@link UElement} to match the existing {@link PsiElement} methods. - *

- * If you have code which does something specific with PSI classes, - * the following mapping table in alphabetical order might be helpful, since it lists the - * corresponding UAST classes. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Mapping between PSI and UAST classes
PSIUAST
com.intellij.psi.org.jetbrains.uast.
IElementTypeUastBinaryOperator
PsiAnnotationUAnnotation
PsiAnonymousClassUAnonymousClass
PsiArrayAccessExpressionUArrayAccessExpression
PsiBinaryExpressionUBinaryExpression
PsiCallExpressionUCallExpression
PsiCatchSectionUCatchClause
PsiClassUClass
PsiClassObjectAccessExpressionUClassLiteralExpression
PsiConditionalExpressionUIfExpression
PsiDeclarationStatementUDeclarationsExpression
PsiDoWhileStatementUDoWhileExpression
PsiElementUElement
PsiExpressionUExpression
PsiForeachStatementUForEachExpression
PsiIdentifierUSimpleNameReferenceExpression
PsiIfStatementUIfExpression
PsiImportStatementUImportStatement
PsiImportStaticStatementUImportStatement
PsiJavaCodeReferenceElementUReferenceExpression
PsiLiteralULiteralExpression
PsiLocalVariableULocalVariable
PsiMethodUMethod
PsiMethodCallExpressionUCallExpression
PsiNameValuePairUNamedExpression
PsiNewExpressionUCallExpression
PsiParameterUParameter
PsiParenthesizedExpressionUParenthesizedExpression
PsiPolyadicExpressionUPolyadicExpression
PsiPostfixExpressionUPostfixExpression or UUnaryExpression
PsiPrefixExpressionUPrefixExpression or UUnaryExpression
PsiReferenceUReferenceExpression
PsiReferenceUResolvable
PsiReferenceExpressionUReferenceExpression
PsiReturnStatementUReturnExpression
PsiSuperExpressionUSuperExpression
PsiSwitchLabelStatementUSwitchClauseExpression
PsiSwitchStatementUSwitchExpression
PsiThisExpressionUThisExpression
PsiThrowStatementUThrowExpression
PsiTryStatementUTryExpression
PsiTypeCastExpressionUBinaryExpressionWithType
PsiWhileStatementUWhileExpression
- * Note however that UAST isn't just a "renaming of classes"; there are - * some changes to the structure of the AST as well. Particularly around - * calls. - * - *

Parents

- * In UAST, you get your parent {@linkplain UElement} by calling - * {@code getUastParent} instead of {@code getParent}. This is to avoid - * method name clashes on some elements which are both UAST elements - * and PSI elements at the same time - such as {@link UMethod}. - *

Children

- * When you're going in the opposite direction (e.g. you have a {@linkplain PsiMethod} - * and you want to look at its content, you should not use - * {@link PsiMethod#getBody()}. This will only give you the PSI child content, - * which won't work for example when dealing with Kotlin methods. - * Normally lint passes you the {@linkplain UMethod} which you should be procesing - * instead. But if for some reason you need to look up the UAST method - * body from a {@linkplain PsiMethod}, use this: - *
-             *     UastContext context = UastUtils.getUastContext(element);
-             *     UExpression body = context.getMethodBody(method);
-             * 
- * Similarly if you have a {@link PsiField} and you want to look up its field - * initializer, use this: - *
-             *     UastContext context = UastUtils.getUastContext(element);
-             *     UExpression initializer = context.getInitializerBody(field);
-             * 
- * - *

Call names

- * In PSI, a call was represented by a PsiCallExpression, and to get to things - * like the method called or to the operand/qualifier, you'd first need to get - * the "method expression". In UAST there is no method expression and this - * information is available directly on the {@linkplain UCallExpression} element. - * Therefore, here's how you'd change the code: - *
-             * <    call.getMethodExpression().getReferenceName();
-             * ---
-             * >    call.getMethodName()
-             * 
- *

Call qualifiers

- * Similarly, - *
-             * <    call.getMethodExpression().getQualifierExpression();
-             * ---
-             * >    call.getReceiver()
-             * 
- *

Call arguments

- * PSI had a separate PsiArgumentList element you had to look up before you could - * get to the actual arguments, as an array. In UAST these are available directly on - * the call, and are represented as a list instead of an array. - *
-             * <    PsiExpression[] args = call.getArgumentList().getExpressions();
-             * ---
-             * >    List args = call.getValueArguments();
-             * 
- * Typically you also need to go through your code and replace array access, - * arg\[i], with list access, {@code arg.get(i)}. Or in Kotlin, just arg\[i]... - * - *

Instanceof

- * You may have code which does something like "parent instanceof PsiAssignmentExpression" - * to see if something is an assignment. Instead, use one of the many utilities - * in {@link UastExpressionUtils} - such as {@link UastExpressionUtils#isAssignment(UElement)}. - * Take a look at all the methods there now - there are methods for checking whether - * a call is a constructor, whether an expression is an array initializer, etc etc. - * - *

Android Resources

- * Don't do your own AST lookup to figure out if something is a reference to - * an Android resource (e.g. see if the class refers to an inner class of a class - * named "R" etc.) There is now a new utility class which handles this: - * {@link ResourceReference}. Here's an example of code which has a {@link UExpression} - * and wants to know it's referencing a R.styleable resource: - *
-             *        ResourceReference reference = ResourceReference.get(expression);
-             *        if (reference == null || reference.getType() != ResourceType.STYLEABLE) {
-             *            return;
-             *        }
-             *        ...
-             * 
- * - *

Binary Expressions

- * If you had been using {@link PsiBinaryExpression} for things like checking comparator - * operators or arithmetic combination of operands, you can replace this with - * {@link UBinaryExpression}. But you normally shouldn't; you should use - * {@link UPolyadicExpression} instead. A polyadic expression is just like a binary - * expression, but possibly with more than two terms. With the old parser backend, - * an expression like "A + B + C" would be represented by nested binary expressions - * (first A + B, then a parent element which combined that binary expression with C). - * However, this will now be provided as a {@link UPolyadicExpression} instead. And - * the binary case is handled trivially without the need to special case it. - *

Method name changes

- * The following table maps some common method names and what their corresponding - * names are in UAST. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Mapping between PSI and UAST method names
PSIUAST
getArgumentListgetValueArguments
getCatchSectionsgetCatchClauses
getDeclaredElementsgetDeclarations
getElseBranchgetElseExpression
getInitializergetUastInitializer
getLExpressiongetLeftOperand
getOperationTokenTypegetOperator
getOwnergetUastParent
getParentgetUastParent
getRExpressiongetRightOperand
getReturnValuegetReturnExpression
getTextasSourceString
getThenBranchgetThenExpression
getTypegetExpressionType
getTypeParametersgetTypeArguments
resolveMethodresolve
- *

Handlers versus visitors

- * If you are processing a method on your own, or even a full class, you should switch - * from JavaRecursiveElementVisitor to AbstractUastVisitor. - * However, most lint checks don't do their own full AST traversal; they instead - * participate in a shared traversal of the tree, registering element types they're - * interested with using {@link #getApplicableUastTypes()} and then providing - * a visitor where they implement the corresponding visit methods. However, from - * these visitors you should not be calling super.visitX. To remove this - * whole confusion, lint now provides a separate class, {@link UElementHandler}. - * For the shared traversal, just provide this handler instead and implement the - * appropriate visit methods. It will throw an error if you register element types - * in {@linkplain #getApplicableUastTypes()} that you don't override. - * - *

- *

Migrating JavaScanner to SourceCodeScanner

- * First read the javadoc on how to convert from the older {@linkplain JavaScanner} - * interface over to {@linkplain JavaPsiScanner}. While {@linkplain JavaPsiScanner} is itself - * deprecated, it's a lot closer to {@link SourceCodeScanner} so a lot of the same concepts - * apply; then follow the above section. - *

- */ - """ + /** + * Interface to be implemented by lint detectors that want to analyze + * Java source files (or other similar source files, such as Kotlin files.) + *

+ * There are several different common patterns for detecting issues: + *

    + *
  • Checking calls to a given method. For this see + * {@link #getApplicableMethodNames()} and + * {@link #visitMethodCall(JavaContext, UCallExpression, PsiMethod)}
  • + *
  • Instantiating a given class. For this, see + * {@link #getApplicableConstructorTypes()} and + * {@link #visitConstructor(JavaContext, UCallExpression, PsiMethod)}
  • + *
  • Referencing a given constant. For this, see + * {@link #getApplicableReferenceNames()} and + * {@link #visitReference(JavaContext, UReferenceExpression, PsiElement)}
  • + *
  • Extending a given class or implementing a given interface. + * For this, see {@link #applicableSuperClasses()} and + * {@link #visitClass(JavaContext, UClass)}
  • + *
  • More complicated scenarios: perform a general AST + * traversal with a visitor. In this case, first tell lint which + * AST node types you're interested in with the + * {@link #getApplicableUastTypes()} method, and then provide a + * {@link UElementHandler} from the {@link #createUastHandler(JavaContext)} + * where you override the various applicable handler methods. This is + * done rather than a general visitor from the root node to avoid + * having to have every single lint detector (there are hundreds) do a full + * tree traversal on its own.
  • + *
+ *

+ * {@linkplain SourceCodeScanner} exposes the UAST API to lint checks. + * UAST is short for "Universal AST" and is an abstract syntax tree library + * which abstracts away details about Java versus Kotlin versus other similar languages + * and lets the client of the library access the AST in a unified way. + *

+ * UAST isn't actually a full replacement for PSI; it augments PSI. + * Essentially, UAST is used for the inside of methods (e.g. method bodies), + * and things like field initializers. PSI continues to be used at the outer + * level: for packages, classes, and methods (declarations and signatures). + * There are also wrappers around some of these for convenience. + *

+ * The {@linkplain SourceCodeScanner} interface reflects this fact. For example, + * when you indicate that you want to check calls to a method named {@code foo}, + * the call site node is a UAST node (in this case, {@link UCallExpression}, + * but the called method itself is a {@link PsiMethod}, since that method + * might be anywhere (including in a library that we don't have source for, + * so UAST doesn't make sense.) + *

+ *

Migrating JavaPsiScanner to SourceCodeScanner

+ * As described above, PSI is still used, so a lot of code will remain the + * same. For example, all resolve methods, including those in UAST, will + * continue to return PsiElement, not necessarily a UElement. For example, + * if you resolve a method call or field reference, you'll get a + * {@link PsiMethod} or {@link PsiField} back. + *

+ * However, the visitor methods have all changed, generally to change + * to UAST types. For example, the signature + * {@link JavaPsiScanner#visitMethodCall(JavaContext, JavaElementVisitor, PsiMethodCallExpression, PsiMethod)} + * should be changed to {@link SourceCodeScanner#visitMethodCall(JavaContext, UCallExpression, PsiMethod)}. + *

+ * Similarly, replace {@link JavaPsiScanner#createPsiVisitor} with {@link SourceCodeScanner#createUastHandler}, + * {@link JavaPsiScanner#getApplicablePsiTypes()} with {@link SourceCodeScanner#getApplicableUastTypes()}, etc. + *

+ * There are a bunch of new methods on classes like {@link JavaContext} which lets + * you pass in a {@link UElement} to match the existing {@link PsiElement} methods. + *

+ * If you have code which does something specific with PSI classes, + * the following mapping table in alphabetical order might be helpful, since it lists the + * corresponding UAST classes. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Mapping between PSI and UAST classes
PSIUAST
com.intellij.psi.org.jetbrains.uast.
IElementTypeUastBinaryOperator
PsiAnnotationUAnnotation
PsiAnonymousClassUAnonymousClass
PsiArrayAccessExpressionUArrayAccessExpression
PsiBinaryExpressionUBinaryExpression
PsiCallExpressionUCallExpression
PsiCatchSectionUCatchClause
PsiClassUClass
PsiClassObjectAccessExpressionUClassLiteralExpression
PsiConditionalExpressionUIfExpression
PsiDeclarationStatementUDeclarationsExpression
PsiDoWhileStatementUDoWhileExpression
PsiElementUElement
PsiExpressionUExpression
PsiForeachStatementUForEachExpression
PsiIdentifierUSimpleNameReferenceExpression
PsiIfStatementUIfExpression
PsiImportStatementUImportStatement
PsiImportStaticStatementUImportStatement
PsiJavaCodeReferenceElementUReferenceExpression
PsiLiteralULiteralExpression
PsiLocalVariableULocalVariable
PsiMethodUMethod
PsiMethodCallExpressionUCallExpression
PsiNameValuePairUNamedExpression
PsiNewExpressionUCallExpression
PsiParameterUParameter
PsiParenthesizedExpressionUParenthesizedExpression
PsiPolyadicExpressionUPolyadicExpression
PsiPostfixExpressionUPostfixExpression or UUnaryExpression
PsiPrefixExpressionUPrefixExpression or UUnaryExpression
PsiReferenceUReferenceExpression
PsiReferenceUResolvable
PsiReferenceExpressionUReferenceExpression
PsiReturnStatementUReturnExpression
PsiSuperExpressionUSuperExpression
PsiSwitchLabelStatementUSwitchClauseExpression
PsiSwitchStatementUSwitchExpression
PsiThisExpressionUThisExpression
PsiThrowStatementUThrowExpression
PsiTryStatementUTryExpression
PsiTypeCastExpressionUBinaryExpressionWithType
PsiWhileStatementUWhileExpression
+ * Note however that UAST isn't just a "renaming of classes"; there are + * some changes to the structure of the AST as well. Particularly around + * calls. + * + *

Parents

+ * In UAST, you get your parent {@linkplain UElement} by calling + * {@code getUastParent} instead of {@code getParent}. This is to avoid + * method name clashes on some elements which are both UAST elements + * and PSI elements at the same time - such as {@link UMethod}. + *

Children

+ * When you're going in the opposite direction (e.g. you have a {@linkplain PsiMethod} + * and you want to look at its content, you should not use + * {@link PsiMethod#getBody()}. This will only give you the PSI child content, + * which won't work for example when dealing with Kotlin methods. + * Normally lint passes you the {@linkplain UMethod} which you should be procesing + * instead. But if for some reason you need to look up the UAST method + * body from a {@linkplain PsiMethod}, use this: + *
+        *     UastContext context = UastUtils.getUastContext(element);
+        *     UExpression body = context.getMethodBody(method);
+        * 
+ * Similarly if you have a {@link PsiField} and you want to look up its field + * initializer, use this: + *
+        *     UastContext context = UastUtils.getUastContext(element);
+        *     UExpression initializer = context.getInitializerBody(field);
+        * 
+ * + *

Call names

+ * In PSI, a call was represented by a PsiCallExpression, and to get to things + * like the method called or to the operand/qualifier, you'd first need to get + * the "method expression". In UAST there is no method expression and this + * information is available directly on the {@linkplain UCallExpression} element. + * Therefore, here's how you'd change the code: + *
+        * <    call.getMethodExpression().getReferenceName();
+        * ---
+        * >    call.getMethodName()
+        * 
+ *

Call qualifiers

+ * Similarly, + *
+        * <    call.getMethodExpression().getQualifierExpression();
+        * ---
+        * >    call.getReceiver()
+        * 
+ *

Call arguments

+ * PSI had a separate PsiArgumentList element you had to look up before you could + * get to the actual arguments, as an array. In UAST these are available directly on + * the call, and are represented as a list instead of an array. + *
+        * <    PsiExpression[] args = call.getArgumentList().getExpressions();
+        * ---
+        * >    List args = call.getValueArguments();
+        * 
+ * Typically you also need to go through your code and replace array access, + * arg\[i], with list access, {@code arg.get(i)}. Or in Kotlin, just arg\[i]... + * + *

Instanceof

+ * You may have code which does something like "parent instanceof PsiAssignmentExpression" + * to see if something is an assignment. Instead, use one of the many utilities + * in {@link UastExpressionUtils} - such as {@link UastExpressionUtils#isAssignment(UElement)}. + * Take a look at all the methods there now - there are methods for checking whether + * a call is a constructor, whether an expression is an array initializer, etc etc. + * + *

Android Resources

+ * Don't do your own AST lookup to figure out if something is a reference to + * an Android resource (e.g. see if the class refers to an inner class of a class + * named "R" etc.) There is now a new utility class which handles this: + * {@link ResourceReference}. Here's an example of code which has a {@link UExpression} + * and wants to know it's referencing a R.styleable resource: + *
+        *        ResourceReference reference = ResourceReference.get(expression);
+        *        if (reference == null || reference.getType() != ResourceType.STYLEABLE) {
+        *            return;
+        *        }
+        *        ...
+        * 
+ * + *

Binary Expressions

+ * If you had been using {@link PsiBinaryExpression} for things like checking comparator + * operators or arithmetic combination of operands, you can replace this with + * {@link UBinaryExpression}. But you normally shouldn't; you should use + * {@link UPolyadicExpression} instead. A polyadic expression is just like a binary + * expression, but possibly with more than two terms. With the old parser backend, + * an expression like "A + B + C" would be represented by nested binary expressions + * (first A + B, then a parent element which combined that binary expression with C). + * However, this will now be provided as a {@link UPolyadicExpression} instead. And + * the binary case is handled trivially without the need to special case it. + *

Method name changes

+ * The following table maps some common method names and what their corresponding + * names are in UAST. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Mapping between PSI and UAST method names
PSIUAST
getArgumentListgetValueArguments
getCatchSectionsgetCatchClauses
getDeclaredElementsgetDeclarations
getElseBranchgetElseExpression
getInitializergetUastInitializer
getLExpressiongetLeftOperand
getOperationTokenTypegetOperator
getOwnergetUastParent
getParentgetUastParent
getRExpressiongetRightOperand
getReturnValuegetReturnExpression
getTextasSourceString
getThenBranchgetThenExpression
getTypegetExpressionType
getTypeParametersgetTypeArguments
resolveMethodresolve
+ *

Handlers versus visitors

+ * If you are processing a method on your own, or even a full class, you should switch + * from JavaRecursiveElementVisitor to AbstractUastVisitor. + * However, most lint checks don't do their own full AST traversal; they instead + * participate in a shared traversal of the tree, registering element types they're + * interested with using {@link #getApplicableUastTypes()} and then providing + * a visitor where they implement the corresponding visit methods. However, from + * these visitors you should not be calling super.visitX. To remove this + * whole confusion, lint now provides a separate class, {@link UElementHandler}. + * For the shared traversal, just provide this handler instead and implement the + * appropriate visit methods. It will throw an error if you register element types + * in {@linkplain #getApplicableUastTypes()} that you don't override. + * + *

+ *

Migrating JavaScanner to SourceCodeScanner

+ * First read the javadoc on how to convert from the older {@linkplain JavaScanner} + * interface over to {@linkplain JavaPsiScanner}. While {@linkplain JavaPsiScanner} is itself + * deprecated, it's a lot closer to {@link SourceCodeScanner} so a lot of the same concepts + * apply; then follow the above section. + *

+ */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(120, 120).apply { hangingIndent = 2 }, """ - /** - * Interface to be implemented by lint detectors that want to analyze Java source files (or other similar source - * files, such as Kotlin files.) - * - * There are several different common patterns for detecting issues: - *

    - *
  • Checking calls to a given method. For this see [getApplicableMethodNames] and [visitMethodCall]
  • - *
  • Instantiating a given class. For this, see [getApplicableConstructorTypes] and [visitConstructor]
  • - *
  • Referencing a given constant. For this, see [getApplicableReferenceNames] and [visitReference]
  • - *
  • Extending a given class or implementing a given interface. For this, see [applicableSuperClasses] and - * [visitClass]
  • - *
  • More complicated scenarios: perform a general AST traversal with a visitor. In this case, first tell lint - * which AST node types you're interested in with the [getApplicableUastTypes] method, and then provide a - * [UElementHandler] from the [createUastHandler] where you override the various applicable handler methods. This - * is done rather than a general visitor from the root node to avoid having to have every single lint detector - * (there are hundreds) do a full tree traversal on its own.
  • - *
- * - * {@linkplain SourceCodeScanner} exposes the UAST API to lint checks. UAST is short for "Universal AST" and is an - * abstract syntax tree library which abstracts away details about Java versus Kotlin versus other similar languages - * and lets the client of the library access the AST in a unified way. - * - * UAST isn't actually a full replacement for PSI; it **augments** PSI. Essentially, UAST is used for the **inside** - * of methods (e.g. method bodies), and things like field initializers. PSI continues to be used at the outer level: - * for packages, classes, and methods (declarations and signatures). There are also wrappers around some of these - * for convenience. - * - * The {@linkplain SourceCodeScanner} interface reflects this fact. For example, when you indicate that you want to - * check calls to a method named {@code foo}, the call site node is a UAST node (in this case, [UCallExpression], - * but the called method itself is a [PsiMethod], since that method might be anywhere (including in a library that - * we don't have source for, so UAST doesn't make sense.) - * - * ## Migrating JavaPsiScanner to SourceCodeScanner - * As described above, PSI is still used, so a lot of code will remain the same. For example, all resolve methods, - * including those in UAST, will continue to return PsiElement, not necessarily a UElement. For example, if you - * resolve a method call or field reference, you'll get a [PsiMethod] or [PsiField] back. - * - * However, the visitor methods have all changed, generally to change to UAST types. For example, the signature - * [JavaPsiScanner.visitMethodCall] should be changed to [SourceCodeScanner.visitMethodCall]. - * - * Similarly, replace [JavaPsiScanner.createPsiVisitor] with [SourceCodeScanner.createUastHandler], - * [JavaPsiScanner.getApplicablePsiTypes] with [SourceCodeScanner.getApplicableUastTypes], etc. - * - * There are a bunch of new methods on classes like [JavaContext] which lets you pass in a [UElement] to match the - * existing [PsiElement] methods. - * - * If you have code which does something specific with PSI classes, the following mapping table in alphabetical - * order might be helpful, since it lists the corresponding UAST classes. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Mapping between PSI and UAST classes
PSIUAST
com.intellij.psi.org.jetbrains.uast.
IElementTypeUastBinaryOperator
PsiAnnotationUAnnotation
PsiAnonymousClassUAnonymousClass
PsiArrayAccessExpressionUArrayAccessExpression
PsiBinaryExpressionUBinaryExpression
PsiCallExpressionUCallExpression
PsiCatchSectionUCatchClause
PsiClassUClass
PsiClassObjectAccessExpressionUClassLiteralExpression
PsiConditionalExpressionUIfExpression
PsiDeclarationStatementUDeclarationsExpression
PsiDoWhileStatementUDoWhileExpression
PsiElementUElement
PsiExpressionUExpression
PsiForeachStatementUForEachExpression
PsiIdentifierUSimpleNameReferenceExpression
PsiIfStatementUIfExpression
PsiImportStatementUImportStatement
PsiImportStaticStatementUImportStatement
PsiJavaCodeReferenceElementUReferenceExpression
PsiLiteralULiteralExpression
PsiLocalVariableULocalVariable
PsiMethodUMethod
PsiMethodCallExpressionUCallExpression
PsiNameValuePairUNamedExpression
PsiNewExpressionUCallExpression
PsiParameterUParameter
PsiParenthesizedExpressionUParenthesizedExpression
PsiPolyadicExpressionUPolyadicExpression
PsiPostfixExpressionUPostfixExpression or UUnaryExpression
PsiPrefixExpressionUPrefixExpression or UUnaryExpression
PsiReferenceUReferenceExpression
PsiReferenceUResolvable
PsiReferenceExpressionUReferenceExpression
PsiReturnStatementUReturnExpression
PsiSuperExpressionUSuperExpression
PsiSwitchLabelStatementUSwitchClauseExpression
PsiSwitchStatementUSwitchExpression
PsiThisExpressionUThisExpression
PsiThrowStatementUThrowExpression
PsiTryStatementUTryExpression
PsiTypeCastExpressionUBinaryExpressionWithType
PsiWhileStatementUWhileExpression
Note however that UAST isn't just a - * "renaming of classes"; there are some changes to the structure of the AST as well. Particularly around calls. - * - * ### Parents - * In UAST, you get your parent {@linkplain UElement} by calling {@code getUastParent} instead of {@code getParent}. - * This is to avoid method name clashes on some elements which are both UAST elements and PSI elements at the same - * time - such as [UMethod]. - * - * ### Children - * When you're going in the opposite direction (e.g. you have a {@linkplain PsiMethod} and you want to look at its - * content, you should **not** use [PsiMethod.getBody]. This will only give you the PSI child content, which won't - * work for example when dealing with Kotlin methods. Normally lint passes you the {@linkplain UMethod} which you - * should be procesing instead. But if for some reason you need to look up the UAST method body from a {@linkplain - * PsiMethod}, use this: - * ``` - * UastContext context = UastUtils.getUastContext(element); - * UExpression body = context.getMethodBody(method); - * ``` - * - * Similarly if you have a [PsiField] and you want to look up its field initializer, use this: - * ``` - * UastContext context = UastUtils.getUastContext(element); - * UExpression initializer = context.getInitializerBody(field); - * ``` - * - * ### Call names - * In PSI, a call was represented by a PsiCallExpression, and to get to things like the method called or to the - * operand/qualifier, you'd first need to get the "method expression". In UAST there is no method expression and - * this information is available directly on the {@linkplain UCallExpression} element. Therefore, here's how you'd - * change the code: - * ``` - * < call.getMethodExpression().getReferenceName(); - * --- - * > call.getMethodName() - * ``` - * - * ### Call qualifiers - * Similarly, - * ``` - * < call.getMethodExpression().getQualifierExpression(); - * --- - * > call.getReceiver() - * ``` - * - * ### Call arguments - * PSI had a separate PsiArgumentList element you had to look up before you could get to the actual arguments, as an - * array. In UAST these are available directly on the call, and are represented as a list instead of an array. - * - * ``` - * < PsiExpression[] args = call.getArgumentList().getExpressions(); - * --- - * > List args = call.getValueArguments(); - * ``` - * - * Typically you also need to go through your code and replace array access, arg\[i], with list access, {@code - * arg.get(i)}. Or in Kotlin, just arg\[i]... - * - * ### Instanceof - * You may have code which does something like "parent instanceof PsiAssignmentExpression" to see if - * something is an assignment. Instead, use one of the many utilities in [UastExpressionUtils] - such - * as [UastExpressionUtils.isAssignment]. Take a look at all the methods there now - there are methods - * for checking whether a call is a constructor, whether an expression is an array initializer, etc etc. - * - * ### Android Resources - * Don't do your own AST lookup to figure out if something is a reference to an Android resource (e.g. see if the - * class refers to an inner class of a class named "R" etc.) There is now a new utility class which handles this: - * [ResourceReference]. Here's an example of code which has a [UExpression] and wants to know it's referencing a - * R.styleable resource: - * ``` - * ResourceReference reference = ResourceReference.get(expression); - * if (reference == null || reference.getType() != ResourceType.STYLEABLE) { - * return; - * } - * ... - * ``` - * - * ### Binary Expressions - * If you had been using [PsiBinaryExpression] for things like checking comparator operators or arithmetic - * combination of operands, you can replace this with [UBinaryExpression]. **But you normally shouldn't; you should - * use [UPolyadicExpression] instead**. A polyadic expression is just like a binary expression, but possibly with - * more than two terms. With the old parser backend, an expression like "A + B + C" would be represented by nested - * binary expressions (first A + B, then a parent element which combined that binary expression with C). However, - * this will now be provided as a [UPolyadicExpression] instead. And the binary case is handled trivially without - * the need to special case it. - * - * ### Method name changes - * The following table maps some common method names and what their corresponding names are in UAST. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Mapping between PSI and UAST method names
PSIUAST
getArgumentListgetValueArguments
getCatchSectionsgetCatchClauses
getDeclaredElementsgetDeclarations
getElseBranchgetElseExpression
getInitializergetUastInitializer
getLExpressiongetLeftOperand
getOperationTokenTypegetOperator
getOwnergetUastParent
getParentgetUastParent
getRExpressiongetRightOperand
getReturnValuegetReturnExpression
getTextasSourceString
getThenBranchgetThenExpression
getTypegetExpressionType
getTypeParametersgetTypeArguments
resolveMethodresolve
- * - * ### Handlers versus visitors - * If you are processing a method on your own, or even a full class, you should switch from - * JavaRecursiveElementVisitor to AbstractUastVisitor. However, most lint checks don't do their own full AST - * traversal; they instead participate in a shared traversal of the tree, registering element types they're - * interested with using [getApplicableUastTypes] and then providing a visitor where they implement the - * corresponding visit methods. However, from these visitors you should **not** be calling super.visitX. To remove - * this whole confusion, lint now provides a separate class, [UElementHandler]. For the shared traversal, just - * provide this handler instead and implement the appropriate visit methods. It will throw an error if you register - * element types in {@linkplain #getApplicableUastTypes()} that you don't override. - * - * ### Migrating JavaScanner to SourceCodeScanner - * First read the javadoc on how to convert from the older {@linkplain JavaScanner} interface over to {@linkplain - * JavaPsiScanner}. While {@linkplain JavaPsiScanner} is itself deprecated, it's a lot closer to [SourceCodeScanner] - * so a lot of the same concepts apply; then follow the above section. - */ - """ + /** + * Interface to be implemented by lint detectors that want to analyze Java source files (or other similar source + * files, such as Kotlin files.) + * + * There are several different common patterns for detecting issues: + *
    + *
  • Checking calls to a given method. For this see [getApplicableMethodNames] and [visitMethodCall]
  • + *
  • Instantiating a given class. For this, see [getApplicableConstructorTypes] and [visitConstructor]
  • + *
  • Referencing a given constant. For this, see [getApplicableReferenceNames] and [visitReference]
  • + *
  • Extending a given class or implementing a given interface. For this, see [applicableSuperClasses] and + * [visitClass]
  • + *
  • More complicated scenarios: perform a general AST traversal with a visitor. In this case, first tell lint + * which AST node types you're interested in with the [getApplicableUastTypes] method, and then provide a + * [UElementHandler] from the [createUastHandler] where you override the various applicable handler methods. This + * is done rather than a general visitor from the root node to avoid having to have every single lint detector + * (there are hundreds) do a full tree traversal on its own.
  • + *
+ * + * {@linkplain SourceCodeScanner} exposes the UAST API to lint checks. UAST is short for "Universal AST" and is an + * abstract syntax tree library which abstracts away details about Java versus Kotlin versus other similar languages + * and lets the client of the library access the AST in a unified way. + * + * UAST isn't actually a full replacement for PSI; it **augments** PSI. Essentially, UAST is used for the **inside** + * of methods (e.g. method bodies), and things like field initializers. PSI continues to be used at the outer level: + * for packages, classes, and methods (declarations and signatures). There are also wrappers around some of these + * for convenience. + * + * The {@linkplain SourceCodeScanner} interface reflects this fact. For example, when you indicate that you want to + * check calls to a method named {@code foo}, the call site node is a UAST node (in this case, [UCallExpression], + * but the called method itself is a [PsiMethod], since that method might be anywhere (including in a library that + * we don't have source for, so UAST doesn't make sense.) + * + * ## Migrating JavaPsiScanner to SourceCodeScanner + * As described above, PSI is still used, so a lot of code will remain the same. For example, all resolve methods, + * including those in UAST, will continue to return PsiElement, not necessarily a UElement. For example, if you + * resolve a method call or field reference, you'll get a [PsiMethod] or [PsiField] back. + * + * However, the visitor methods have all changed, generally to change to UAST types. For example, the signature + * [JavaPsiScanner.visitMethodCall] should be changed to [SourceCodeScanner.visitMethodCall]. + * + * Similarly, replace [JavaPsiScanner.createPsiVisitor] with [SourceCodeScanner.createUastHandler], + * [JavaPsiScanner.getApplicablePsiTypes] with [SourceCodeScanner.getApplicableUastTypes], etc. + * + * There are a bunch of new methods on classes like [JavaContext] which lets you pass in a [UElement] to match the + * existing [PsiElement] methods. + * + * If you have code which does something specific with PSI classes, the following mapping table in alphabetical + * order might be helpful, since it lists the corresponding UAST classes. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Mapping between PSI and UAST classes
PSIUAST
com.intellij.psi.org.jetbrains.uast.
IElementTypeUastBinaryOperator
PsiAnnotationUAnnotation
PsiAnonymousClassUAnonymousClass
PsiArrayAccessExpressionUArrayAccessExpression
PsiBinaryExpressionUBinaryExpression
PsiCallExpressionUCallExpression
PsiCatchSectionUCatchClause
PsiClassUClass
PsiClassObjectAccessExpressionUClassLiteralExpression
PsiConditionalExpressionUIfExpression
PsiDeclarationStatementUDeclarationsExpression
PsiDoWhileStatementUDoWhileExpression
PsiElementUElement
PsiExpressionUExpression
PsiForeachStatementUForEachExpression
PsiIdentifierUSimpleNameReferenceExpression
PsiIfStatementUIfExpression
PsiImportStatementUImportStatement
PsiImportStaticStatementUImportStatement
PsiJavaCodeReferenceElementUReferenceExpression
PsiLiteralULiteralExpression
PsiLocalVariableULocalVariable
PsiMethodUMethod
PsiMethodCallExpressionUCallExpression
PsiNameValuePairUNamedExpression
PsiNewExpressionUCallExpression
PsiParameterUParameter
PsiParenthesizedExpressionUParenthesizedExpression
PsiPolyadicExpressionUPolyadicExpression
PsiPostfixExpressionUPostfixExpression or UUnaryExpression
PsiPrefixExpressionUPrefixExpression or UUnaryExpression
PsiReferenceUReferenceExpression
PsiReferenceUResolvable
PsiReferenceExpressionUReferenceExpression
PsiReturnStatementUReturnExpression
PsiSuperExpressionUSuperExpression
PsiSwitchLabelStatementUSwitchClauseExpression
PsiSwitchStatementUSwitchExpression
PsiThisExpressionUThisExpression
PsiThrowStatementUThrowExpression
PsiTryStatementUTryExpression
PsiTypeCastExpressionUBinaryExpressionWithType
PsiWhileStatementUWhileExpression
Note however that UAST isn't just a + * "renaming of classes"; there are some changes to the structure of the AST as well. Particularly around calls. + * + * ### Parents + * In UAST, you get your parent {@linkplain UElement} by calling {@code getUastParent} instead of {@code getParent}. + * This is to avoid method name clashes on some elements which are both UAST elements and PSI elements at the same + * time - such as [UMethod]. + * + * ### Children + * When you're going in the opposite direction (e.g. you have a {@linkplain PsiMethod} and you want to look at its + * content, you should **not** use [PsiMethod.getBody]. This will only give you the PSI child content, which won't + * work for example when dealing with Kotlin methods. Normally lint passes you the {@linkplain UMethod} which you + * should be procesing instead. But if for some reason you need to look up the UAST method body from a {@linkplain + * PsiMethod}, use this: + * ``` + * UastContext context = UastUtils.getUastContext(element); + * UExpression body = context.getMethodBody(method); + * ``` + * + * Similarly if you have a [PsiField] and you want to look up its field initializer, use this: + * ``` + * UastContext context = UastUtils.getUastContext(element); + * UExpression initializer = context.getInitializerBody(field); + * ``` + * + * ### Call names + * In PSI, a call was represented by a PsiCallExpression, and to get to things like the method called or to the + * operand/qualifier, you'd first need to get the "method expression". In UAST there is no method expression and + * this information is available directly on the {@linkplain UCallExpression} element. Therefore, here's how you'd + * change the code: + * ``` + * < call.getMethodExpression().getReferenceName(); + * --- + * > call.getMethodName() + * ``` + * + * ### Call qualifiers + * Similarly, + * ``` + * < call.getMethodExpression().getQualifierExpression(); + * --- + * > call.getReceiver() + * ``` + * + * ### Call arguments + * PSI had a separate PsiArgumentList element you had to look up before you could get to the actual arguments, as an + * array. In UAST these are available directly on the call, and are represented as a list instead of an array. + * + * ``` + * < PsiExpression[] args = call.getArgumentList().getExpressions(); + * --- + * > List args = call.getValueArguments(); + * ``` + * + * Typically you also need to go through your code and replace array access, arg\[i], with list access, {@code + * arg.get(i)}. Or in Kotlin, just arg\[i]... + * + * ### Instanceof + * You may have code which does something like "parent instanceof PsiAssignmentExpression" to see if + * something is an assignment. Instead, use one of the many utilities in [UastExpressionUtils] - such + * as [UastExpressionUtils.isAssignment]. Take a look at all the methods there now - there are methods + * for checking whether a call is a constructor, whether an expression is an array initializer, etc etc. + * + * ### Android Resources + * Don't do your own AST lookup to figure out if something is a reference to an Android resource (e.g. see if the + * class refers to an inner class of a class named "R" etc.) There is now a new utility class which handles this: + * [ResourceReference]. Here's an example of code which has a [UExpression] and wants to know it's referencing a + * R.styleable resource: + * ``` + * ResourceReference reference = ResourceReference.get(expression); + * if (reference == null || reference.getType() != ResourceType.STYLEABLE) { + * return; + * } + * ... + * ``` + * + * ### Binary Expressions + * If you had been using [PsiBinaryExpression] for things like checking comparator operators or arithmetic + * combination of operands, you can replace this with [UBinaryExpression]. **But you normally shouldn't; you should + * use [UPolyadicExpression] instead**. A polyadic expression is just like a binary expression, but possibly with + * more than two terms. With the old parser backend, an expression like "A + B + C" would be represented by nested + * binary expressions (first A + B, then a parent element which combined that binary expression with C). However, + * this will now be provided as a [UPolyadicExpression] instead. And the binary case is handled trivially without + * the need to special case it. + * + * ### Method name changes + * The following table maps some common method names and what their corresponding names are in UAST. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Mapping between PSI and UAST method names
PSIUAST
getArgumentListgetValueArguments
getCatchSectionsgetCatchClauses
getDeclaredElementsgetDeclarations
getElseBranchgetElseExpression
getInitializergetUastInitializer
getLExpressiongetLeftOperand
getOperationTokenTypegetOperator
getOwnergetUastParent
getParentgetUastParent
getRExpressiongetRightOperand
getReturnValuegetReturnExpression
getTextasSourceString
getThenBranchgetThenExpression
getTypegetExpressionType
getTypeParametersgetTypeArguments
resolveMethodresolve
+ * + * ### Handlers versus visitors + * If you are processing a method on your own, or even a full class, you should switch from + * JavaRecursiveElementVisitor to AbstractUastVisitor. However, most lint checks don't do their own full AST + * traversal; they instead participate in a shared traversal of the tree, registering element types they're + * interested with using [getApplicableUastTypes] and then providing a visitor where they implement the + * corresponding visit methods. However, from these visitors you should **not** be calling super.visitX. To remove + * this whole confusion, lint now provides a separate class, [UElementHandler]. For the shared traversal, just + * provide this handler instead and implement the appropriate visit methods. It will throw an error if you register + * element types in {@linkplain #getApplicableUastTypes()} that you don't override. + * + * ### Migrating JavaScanner to SourceCodeScanner + * First read the javadoc on how to convert from the older {@linkplain JavaScanner} interface over to {@linkplain + * JavaPsiScanner}. While {@linkplain JavaPsiScanner} is itself deprecated, it's a lot closer to [SourceCodeScanner] + * so a lot of the same concepts apply; then follow the above section. + */ + """ .trimIndent(), // {@link} tags are not rendered from [references] when Dokka cannot resolve the symbols verifyDokka = false) @@ -2749,27 +2749,27 @@ class KDocFormatterTest { // Make sure that when we convert

, it's preserved. val source = """ - /** - *

    - *
  • test
  • - *
- *

- * After. - */ - """ + /** + *

    + *
  • test
  • + *
+ *

+ * After. + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(120, 120), """ - /** - *

    - *
  • test
  • - *
- * - * After. - */ - """ + /** + *
    + *
  • test
  • + *
+ * + * After. + */ + """ .trimIndent()) } @@ -2778,40 +2778,40 @@ class KDocFormatterTest { // "-" alone can mean beginning of a list, but not as part of a word val source = """ - /** - * which you can render with something like this: - * `dot -Tpng -o/tmp/graph.png toString.dot` - */ - """ + /** + * which you can render with something like this: + * `dot -Tpng -o/tmp/graph.png toString.dot` + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(65), """ - /** - * which you can render with something like this: `dot -Tpng - * -o/tmp/graph.png toString.dot` - */ - """ + /** + * which you can render with something like this: `dot -Tpng + * -o/tmp/graph.png toString.dot` + */ + """ .trimIndent()) val source2 = """ - /** - * ABCDE which you can render with something like this: - * `dot - Tpng -o/tmp/graph.png toString.dot` - */ - """ + /** + * ABCDE which you can render with something like this: + * `dot - Tpng -o/tmp/graph.png toString.dot` + */ + """ .trimIndent() checkFormatter( source2, KDocFormattingOptions(65), """ - /** - * ABCDE which you can render with something like this: - * `dot - Tpng -o/tmp/graph.png toString.dot` - */ - """ + /** + * ABCDE which you can render with something like this: + * `dot - Tpng -o/tmp/graph.png toString.dot` + */ + """ .trimIndent()) } @@ -2820,25 +2820,25 @@ class KDocFormatterTest { // Don't break before a TODO val source = """ - /** - * This is a long line that will break a little early to breaking at TODO: - * - * This is a long line that wont break a little early to breaking at DODO: - */ - """ + /** + * This is a long line that will break a little early to breaking at TODO: + * + * This is a long line that wont break a little early to breaking at DODO: + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72, 72).apply { optimal = false }, """ - /** - * This is a long line that will break a little early to breaking - * at TODO: - * - * This is a long line that wont break a little early to breaking at - * DODO: - */ - """ + /** + * This is a long line that will break a little early to breaking + * at TODO: + * + * This is a long line that wont break a little early to breaking at + * DODO: + */ + """ .trimIndent()) } @@ -2847,30 +2847,30 @@ class KDocFormatterTest { // Don't join preformatted text with previous TODO comment val source = """ - /** - * TODO: Work. - * ``` - * Preformatted. - * - * More preformatted. - * ``` - */ - """ + /** + * TODO: Work. + * ``` + * Preformatted. + * + * More preformatted. + * ``` + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72, 72), """ - /** - * TODO: Work. - * - * ``` - * Preformatted. - * - * More preformatted. - * ``` - */ - """ + /** + * TODO: Work. + * + * ``` + * Preformatted. + * + * More preformatted. + * ``` + */ + """ .trimIndent()) } @@ -2879,61 +2879,61 @@ class KDocFormatterTest { // Make sure we convert {@link} and NOT {@linkplain} if convertMarkup is true. val source = """ - /** - * {@link SourceCodeScanner} exposes the UAST API to lint checks. - * The {@link SourceCodeScanner} interface reflects this fact. - * - * {@linkplain SourceCodeScanner} exposes the UAST API to lint checks. - * The {@linkplain SourceCodeScanner} interface reflects this fact. - * - * It will throw an error if you register element types in - * {@link #getApplicableUastTypes()} that you don't override. - * - * First read the javadoc on how to convert from the older {@link - * JavaScanner} interface over to {@link JavaPsiScanner}. - * - * 1. A file header, which is the exact contents of {@link FILE_HEADER} encoded - * as ASCII characters. - * - * Given an error message produced by this lint detector for the - * given issue type, determines whether this corresponds to the - * warning (produced by {@link #reportBaselineIssues(LintDriver, - * Project)} above) that one or more issues have been - * fixed (present in baseline but not in project.) - * - * {@link #getQualifiedName(PsiClass)} method. - */ - """ + /** + * {@link SourceCodeScanner} exposes the UAST API to lint checks. + * The {@link SourceCodeScanner} interface reflects this fact. + * + * {@linkplain SourceCodeScanner} exposes the UAST API to lint checks. + * The {@linkplain SourceCodeScanner} interface reflects this fact. + * + * It will throw an error if you register element types in + * {@link #getApplicableUastTypes()} that you don't override. + * + * First read the javadoc on how to convert from the older {@link + * JavaScanner} interface over to {@link JavaPsiScanner}. + * + * 1. A file header, which is the exact contents of {@link FILE_HEADER} encoded + * as ASCII characters. + * + * Given an error message produced by this lint detector for the + * given issue type, determines whether this corresponds to the + * warning (produced by {@link #reportBaselineIssues(LintDriver, + * Project)} above) that one or more issues have been + * fixed (present in baseline but not in project.) + * + * {@link #getQualifiedName(PsiClass)} method. + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72, 72), """ - /** - * [SourceCodeScanner] exposes the UAST API to lint checks. The - * [SourceCodeScanner] interface reflects this fact. - * - * {@linkplain SourceCodeScanner} exposes the UAST API to lint - * checks. The {@linkplain SourceCodeScanner} interface reflects - * this fact. - * - * It will throw an error if you register element types in - * [getApplicableUastTypes] that you don't override. - * - * First read the javadoc on how to convert from the older - * [JavaScanner] interface over to [JavaPsiScanner]. - * 1. A file header, which is the exact contents of [FILE_HEADER] - * encoded as ASCII characters. - * - * Given an error message produced by this lint detector for the - * given issue type, determines whether this corresponds to the - * warning (produced by [reportBaselineIssues] above) that one or - * more issues have been fixed (present in baseline but not in - * project.) - * - * [getQualifiedName] method. - */ - """ + /** + * [SourceCodeScanner] exposes the UAST API to lint checks. The + * [SourceCodeScanner] interface reflects this fact. + * + * {@linkplain SourceCodeScanner} exposes the UAST API to lint + * checks. The {@linkplain SourceCodeScanner} interface reflects + * this fact. + * + * It will throw an error if you register element types in + * [getApplicableUastTypes] that you don't override. + * + * First read the javadoc on how to convert from the older + * [JavaScanner] interface over to [JavaPsiScanner]. + * 1. A file header, which is the exact contents of [FILE_HEADER] + * encoded as ASCII characters. + * + * Given an error message produced by this lint detector for the + * given issue type, determines whether this corresponds to the + * warning (produced by [reportBaselineIssues] above) that one or + * more issues have been fixed (present in baseline but not in + * project.) + * + * [getQualifiedName] method. + */ + """ .trimIndent(), // When dokka cannot resolve the links it doesn't render {@link} which makes // before and after not match @@ -2945,51 +2945,51 @@ class KDocFormatterTest { // Regression test for https://github.com/tnorbye/kdoc-formatter/issues/36 val source = """ - /** - * Paragraph - * * Top Bullet - * * Sub-Bullet 1 - * * Sub-Bullet 2 - * * Sub-Sub-Bullet 1 - * 1. Top level - * 1. First item - * 2. Second item - */ - """ + /** + * Paragraph + * * Top Bullet + * * Sub-Bullet 1 + * * Sub-Bullet 2 + * * Sub-Sub-Bullet 1 + * 1. Top level + * 1. First item + * 2. Second item + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72, 72), """ - /** - * Paragraph - * * Top Bullet - * * Sub-Bullet 1 - * * Sub-Bullet 2 - * * Sub-Sub-Bullet 1 - * 1. Top level - * 1. First item - * 2. Second item - */ - """ + /** + * Paragraph + * * Top Bullet + * * Sub-Bullet 1 + * * Sub-Bullet 2 + * * Sub-Sub-Bullet 1 + * 1. Top level + * 1. First item + * 2. Second item + */ + """ .trimIndent()) checkFormatter( source, KDocFormattingOptions(72, 72).apply { nestedListIndent = 4 }, """ - /** - * Paragraph - * * Top Bullet - * * Sub-Bullet 1 - * * Sub-Bullet 2 - * * Sub-Sub-Bullet 1 - * 1. Top level - * 1. First item - * 2. Second item - */ - """ + /** + * Paragraph + * * Top Bullet + * * Sub-Bullet 1 + * * Sub-Bullet 2 + * * Sub-Sub-Bullet 1 + * 1. Top level + * 1. First item + * 2. Second item + */ + """ .trimIndent()) } @@ -2998,25 +2998,25 @@ class KDocFormatterTest { // Corresponds to b/189247595 val source = """ - /** - * Gets current ABCD Workspace information from the output of ```abcdtools info```. - * - * Migrated from - * http://com.example - */ - """ + /** + * Gets current ABCD Workspace information from the output of ```abcdtools info```. + * + * Migrated from + * http://com.example + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72, 72), """ - /** - * Gets current ABCD Workspace information from the output - * of ```abcdtools info```. - * - * Migrated from http://com.example - */ - """ + /** + * Gets current ABCD Workspace information from the output + * of ```abcdtools info```. + * + * Migrated from http://com.example + */ + """ .trimIndent()) } @@ -3025,22 +3025,22 @@ class KDocFormatterTest { // Make sure we correctly break at the max line width val source = """ - /** - * Handles a chain of qualified expressions, i.e. `a[5].b!!.c()[4].f()` - * - * This is by far the most complicated part of this formatter. We start by breaking the expression - * to the steps it is executed in (which are in the opposite order of how the syntax tree is - * built). - * - * We then calculate information to know which parts need to be groups, and finally go part by - * part, emitting it to the [builder] while closing and opening groups. - * - * @param brokeBeforeBrace used for tracking if a break was taken right before the lambda - * expression. Useful for scoping functions where we want good looking indentation. For example, - * here we have correct indentation before `bar()` and `car()` because we can detect the break - * after the equals: - */ - """ + /** + * Handles a chain of qualified expressions, i.e. `a[5].b!!.c()[4].f()` + * + * This is by far the most complicated part of this formatter. We start by breaking the expression + * to the steps it is executed in (which are in the opposite order of how the syntax tree is + * built). + * + * We then calculate information to know which parts need to be groups, and finally go part by + * part, emitting it to the [builder] while closing and opening groups. + * + * @param brokeBeforeBrace used for tracking if a break was taken right before the lambda + * expression. Useful for scoping functions where we want good looking indentation. For example, + * here we have correct indentation before `bar()` and `car()` because we can detect the break + * after the equals: + */ + """ .trimIndent() checkFormatter( source, @@ -3049,22 +3049,22 @@ class KDocFormatterTest { hangingIndent = 2 }, """ - /** - * Handles a chain of qualified expressions, i.e. `a[5].b!!.c()[4].f()` - * - * This is by far the most complicated part of this formatter. We start by breaking the - * expression to the steps it is executed in (which are in the opposite order of how the syntax - * tree is built). - * - * We then calculate information to know which parts need to be groups, and finally go part by - * part, emitting it to the [builder] while closing and opening groups. - * - * @param brokeBeforeBrace used for tracking if a break was taken right before the lambda - * expression. Useful for scoping functions where we want good looking indentation. For - * example, here we have correct indentation before `bar()` and `car()` because we can detect - * the break after the equals: - */ - """ + /** + * Handles a chain of qualified expressions, i.e. `a[5].b!!.c()[4].f()` + * + * This is by far the most complicated part of this formatter. We start by breaking the + * expression to the steps it is executed in (which are in the opposite order of how the syntax + * tree is built). + * + * We then calculate information to know which parts need to be groups, and finally go part by + * part, emitting it to the [builder] while closing and opening groups. + * + * @param brokeBeforeBrace used for tracking if a break was taken right before the lambda + * expression. Useful for scoping functions where we want good looking indentation. For + * example, here we have correct indentation before `bar()` and `car()` because we can detect + * the break after the equals: + */ + """ .trimIndent()) } @@ -3074,41 +3074,41 @@ class KDocFormatterTest { // Nonsensical text derived from the original using the lorem() method and // replacing same-length & same capitalization words from lorem ipsum """ - /** - * * Do do occaecat sunt in culpa: - * * Id id reprehenderit cillum non `adipiscing` enim enim ad occaecat - * * Cupidatat non officia anim adipiscing enim non reprehenderit in officia est: - * * Do non officia anim voluptate esse non mollit mollit id tempor, enim u consequat. irure - * in occaecat - * * Cupidatat, in qui officia anim voluptate esse eu fugiat fugiat in mollit, anim anim id - * occaecat - * * In h anim id laborum: - * * Do non sunt voluptate esse non culpa mollit id tempor, enim u consequat. irure in occaecat - * * Cupidatat, in qui anim voluptate esse non culpa mollit est do tempor, enim enim ad occaecat - */ - """ + /** + * * Do do occaecat sunt in culpa: + * * Id id reprehenderit cillum non `adipiscing` enim enim ad occaecat + * * Cupidatat non officia anim adipiscing enim non reprehenderit in officia est: + * * Do non officia anim voluptate esse non mollit mollit id tempor, enim u consequat. irure + * in occaecat + * * Cupidatat, in qui officia anim voluptate esse eu fugiat fugiat in mollit, anim anim id + * occaecat + * * In h anim id laborum: + * * Do non sunt voluptate esse non culpa mollit id tempor, enim u consequat. irure in occaecat + * * Cupidatat, in qui anim voluptate esse non culpa mollit est do tempor, enim enim ad occaecat + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72, 72), """ - /** - * * Do do occaecat sunt in culpa: - * * Id id reprehenderit cillum non `adipiscing` enim enim ad - * occaecat - * * Cupidatat non officia anim adipiscing enim non reprehenderit - * in officia est: - * * Do non officia anim voluptate esse non mollit mollit id - * tempor, enim u consequat. irure in occaecat - * * Cupidatat, in qui officia anim voluptate esse eu fugiat - * fugiat in mollit, anim anim id occaecat - * * In h anim id laborum: - * * Do non sunt voluptate esse non culpa mollit id tempor, enim - * u consequat. irure in occaecat - * * Cupidatat, in qui anim voluptate esse non culpa mollit est - * do tempor, enim enim ad occaecat - */ - """ + /** + * * Do do occaecat sunt in culpa: + * * Id id reprehenderit cillum non `adipiscing` enim enim ad + * occaecat + * * Cupidatat non officia anim adipiscing enim non reprehenderit + * in officia est: + * * Do non officia anim voluptate esse non mollit mollit id + * tempor, enim u consequat. irure in occaecat + * * Cupidatat, in qui officia anim voluptate esse eu fugiat + * fugiat in mollit, anim anim id occaecat + * * In h anim id laborum: + * * Do non sunt voluptate esse non culpa mollit id tempor, enim + * u consequat. irure in occaecat + * * Cupidatat, in qui anim voluptate esse non culpa mollit est + * do tempor, enim enim ad occaecat + */ + """ .trimIndent(), // We indent the last bullets as if they are nested list items; this // is likely the intent (though with indent only being 2, dokka would @@ -3121,22 +3121,22 @@ class KDocFormatterTest { // https://github.com/facebook/ktfmt/issues/310 val source = """ - /** - * This is my SampleInterface interface. - * @sample com.example.java.sample.library.extra.long.path.MyCustomSampleInterfaceImplementationForTesting - */ - """ + /** + * This is my SampleInterface interface. + * @sample com.example.java.sample.library.extra.long.path.MyCustomSampleInterfaceImplementationForTesting + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72, 72), """ - /** - * This is my SampleInterface interface. - * - * @sample com.example.java.sample.library.extra.long.path.MyCustomSampleInterfaceImplementationForTesting - */ - """ + /** + * This is my SampleInterface interface. + * + * @sample com.example.java.sample.library.extra.long.path.MyCustomSampleInterfaceImplementationForTesting + */ + """ .trimIndent()) } @@ -3147,60 +3147,60 @@ class KDocFormatterTest { // Nonsensical text derived from the original using the lorem() method and // replacing same-length & same capitalization words from lorem ipsum """ - /** - * eiusmod.com - * - - - - * PARIATUR_MOLLIT - * - - - - * Laborum: 1.4 - * - - - - * Pariatur: - * https://officia.officia.com - * https://id.laborum.laborum.com - * https://sit.eiusmod.com - * https://non-in.officia.com - * https://anim.laborum.com - * https://exercitation.ullamco.com - * - - - - * Adipiscing do tempor: - * - NON: IN/IN - * - in 2IN officia? EST - * - do EIUSMOD eiusmod? NON - * - Mollit est do incididunt Nostrud non? IN - * - Mollit pariatur pariatur culpa? QUI - * - - - - * Lorem eiusmod magna/adipiscing: - * - Do eiusmod magna/adipiscing - */ - """ + /** + * eiusmod.com + * - - - + * PARIATUR_MOLLIT + * - - - + * Laborum: 1.4 + * - - - + * Pariatur: + * https://officia.officia.com + * https://id.laborum.laborum.com + * https://sit.eiusmod.com + * https://non-in.officia.com + * https://anim.laborum.com + * https://exercitation.ullamco.com + * - - - + * Adipiscing do tempor: + * - NON: IN/IN + * - in 2IN officia? EST + * - do EIUSMOD eiusmod? NON + * - Mollit est do incididunt Nostrud non? IN + * - Mollit pariatur pariatur culpa? QUI + * - - - + * Lorem eiusmod magna/adipiscing: + * - Do eiusmod magna/adipiscing + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72, 72), """ - /** - * eiusmod.com - * - - - - * PARIATUR_MOLLIT - * - - - - * Laborum: 1.4 - * - - - - * Pariatur: https://officia.officia.com - * https://id.laborum.laborum.com https://sit.eiusmod.com - * https://non-in.officia.com https://anim.laborum.com - * https://exercitation.ullamco.com - * - - - - * Adipiscing do tempor: - * - NON: IN/IN - * - in 2IN officia? EST - * - do EIUSMOD eiusmod? NON - * - Mollit est do incididunt Nostrud non? IN - * - Mollit pariatur pariatur culpa? QUI - * - - - - * Lorem eiusmod magna/adipiscing: - * - Do eiusmod magna/adipiscing - */ - """ + /** + * eiusmod.com + * - - - + * PARIATUR_MOLLIT + * - - - + * Laborum: 1.4 + * - - - + * Pariatur: https://officia.officia.com + * https://id.laborum.laborum.com https://sit.eiusmod.com + * https://non-in.officia.com https://anim.laborum.com + * https://exercitation.ullamco.com + * - - - + * Adipiscing do tempor: + * - NON: IN/IN + * - in 2IN officia? EST + * - do EIUSMOD eiusmod? NON + * - Mollit est do incididunt Nostrud non? IN + * - Mollit pariatur pariatur culpa? QUI + * - - - + * Lorem eiusmod magna/adipiscing: + * - Do eiusmod magna/adipiscing + */ + """ .trimIndent()) } @@ -3210,11 +3210,11 @@ class KDocFormatterTest { // Nonsensical text derived from the original using the lorem() method and // replacing same-length & same capitalization words from lorem ipsum """ - /** - * @return Amet do non adipiscing sed consequat duis non Officia ID (amet sed consequat non - * adipiscing sed eiusmod), magna consequat. - */ - """ + /** + * @return Amet do non adipiscing sed consequat duis non Officia ID (amet sed consequat non + * adipiscing sed eiusmod), magna consequat. + */ + """ .trimIndent() val lorem = loremize(source) assertThat(lorem).isEqualTo(source) @@ -3222,12 +3222,12 @@ class KDocFormatterTest { source, KDocFormattingOptions(72, 72).apply { hangingIndent = 2 }, """ - /** - * @return Amet do non adipiscing sed consequat duis non Officia ID - * (amet sed consequat non adipiscing sed eiusmod), magna - * consequat. - */ - """ + /** + * @return Amet do non adipiscing sed consequat duis non Officia ID + * (amet sed consequat non adipiscing sed eiusmod), magna + * consequat. + */ + """ .trimIndent()) } @@ -3237,36 +3237,36 @@ class KDocFormatterTest { // Nonsensical text derived from the original using the lorem() method and // replacing same-length & same capitalization words from lorem ipsum """ - /** - * @property dataItemOrderRandomizer sit tempor enim pariatur non culpa id [Pariatur]z in qui anim. - * Anim id-lorem sit magna [Consectetur] pariatur. - * @property randomBytesProvider non mollit anim pariatur non culpa qui qui `mollit` lorem amet - * consectetur [Pariatur]z in IssuerSignedItem culpa. - * @property preserveMapOrder officia id pariatur non culpa id lorem pariatur culpa culpa id o est - * amet consectetur sed sed do ENIM minim. - * @property reprehenderit p esse cillum officia est do enim enim nostrud nisi d non sunt mollit id - * est tempor enim. - */ - """ + /** + * @property dataItemOrderRandomizer sit tempor enim pariatur non culpa id [Pariatur]z in qui anim. + * Anim id-lorem sit magna [Consectetur] pariatur. + * @property randomBytesProvider non mollit anim pariatur non culpa qui qui `mollit` lorem amet + * consectetur [Pariatur]z in IssuerSignedItem culpa. + * @property preserveMapOrder officia id pariatur non culpa id lorem pariatur culpa culpa id o est + * amet consectetur sed sed do ENIM minim. + * @property reprehenderit p esse cillum officia est do enim enim nostrud nisi d non sunt mollit id + * est tempor enim. + */ + """ .trimIndent() checkFormatter( source, KDocFormattingOptions(72, 72).apply { hangingIndent = 2 }, """ - /** - * @property dataItemOrderRandomizer sit tempor enim pariatur non - * culpa id [Pariatur]z in qui anim. Anim id-lorem sit magna - * [Consectetur] pariatur. - * @property randomBytesProvider non mollit anim pariatur non culpa - * qui qui `mollit` lorem amet consectetur [Pariatur]z in - * IssuerSignedItem culpa. - * @property preserveMapOrder officia id pariatur non culpa id lorem - * pariatur culpa culpa id o est amet consectetur sed sed do ENIM - * minim. - * @property reprehenderit p esse cillum officia est do enim enim - * nostrud nisi d non sunt mollit id est tempor enim. - */ - """ + /** + * @property dataItemOrderRandomizer sit tempor enim pariatur non + * culpa id [Pariatur]z in qui anim. Anim id-lorem sit magna + * [Consectetur] pariatur. + * @property randomBytesProvider non mollit anim pariatur non culpa + * qui qui `mollit` lorem amet consectetur [Pariatur]z in + * IssuerSignedItem culpa. + * @property preserveMapOrder officia id pariatur non culpa id lorem + * pariatur culpa culpa id o est amet consectetur sed sed do ENIM + * minim. + * @property reprehenderit p esse cillum officia est do enim enim + * nostrud nisi d non sunt mollit id est tempor enim. + */ + """ .trimIndent()) } @@ -3275,72 +3275,72 @@ class KDocFormatterTest { // Some tests for the knit plugin -- https://github.com/Kotlin/kotlinx-knit val source = """ - /** - * - * - * - * - * - * ```kotlin - * fun exit(): Nothing = exitProcess(0) - * ``` - * - * - * - * - * - * - * - * - * [captureOutput]: https://example.com/kotlinx-knit-test/kotlinx.knit.test/capture-output.html - * - * - * Make sure we never line break + * + * + * + * + * ```kotlin + * fun exit(): Nothing = exitProcess(0) + * ``` + * + * + * + * + * + * + * + * + * [captureOutput]: https://example.com/kotlinx-knit-test/kotlinx.knit.test/capture-output.html + * + * + * Make sure we never line break - * - * - * - * ```kotlin - * fun exit(): Nothing = exitProcess(0) - * ``` - * - * - * - * - * - * - * - * - * [captureOutput]: - * https://example.com/kotlinx-knit-test/kotlinx.knit.test/capture-output.html - * - * - * Make sure we never line break + * + * + * + * ```kotlin + * fun exit(): Nothing = exitProcess(0) + * ``` + * + * + * + * + * + * + * + * + * [captureOutput]: + * https://example.com/kotlinx-knit-test/kotlinx.knit.test/capture-output.html + * + * + * Make sure we never line break