diff --git a/README.md b/README.md index e413764651..dafdee4b57 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Main features of diktat are the following: # another option is "brew install ktlint" ``` -2. Load diKTat manually: [here](https://github.com/cqfn/diKTat/releases/download/v0.5.2/diktat.jar) +2. Load diKTat manually: [here](https://github.com/cqfn/diKTat/releases/download/v0.5.2/diktat-0.5.2.jar) **OR** use curl: ```bash diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt index 63f8202f38..924e5c84b0 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt @@ -12,10 +12,16 @@ import org.cqfn.diktat.ruleset.constants.Warnings.PACKAGE_NAME_MISSING import org.cqfn.diktat.ruleset.rules.DiktatRule import org.cqfn.diktat.ruleset.utils.* +import com.pinterest.ktlint.core.ast.ElementType.BLOCK_COMMENT import com.pinterest.ktlint.core.ast.ElementType.DOT_QUALIFIED_EXPRESSION +import com.pinterest.ktlint.core.ast.ElementType.EOL_COMMENT +import com.pinterest.ktlint.core.ast.ElementType.FILE_ANNOTATION_LIST import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER +import com.pinterest.ktlint.core.ast.ElementType.KDOC import com.pinterest.ktlint.core.ast.ElementType.PACKAGE_DIRECTIVE import com.pinterest.ktlint.core.ast.ElementType.REFERENCE_EXPRESSION +import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE +import com.pinterest.ktlint.core.ast.children import com.pinterest.ktlint.core.ast.isLeaf import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement @@ -218,8 +224,27 @@ class PackageNaming(configRules: List) : DiktatRule( ?: run { // there is missing package statement in a file, so it will be created and inserted val newPackageDirective = generatedPackageDirective.findLeafWithSpecificType(PACKAGE_DIRECTIVE)!! - packageDirectiveNode.treeParent.replaceChild(packageDirectiveNode, newPackageDirective) - newPackageDirective.treeParent.addChild(PsiWhiteSpaceImpl("\n\n"), newPackageDirective.treeNext) + val packageDirectiveParent = packageDirectiveNode.treeParent + // When package directive is missing in .kt file, + // the node is still present in the AST, and not always in a convenient place. + // E.g. `@file:Suppress("...") // comments` + // AST will be: FILE_ANNOTATION_LIST, PACKAGE_DIRECTIVE, WHITE_SPACE, EOL_COMMENT + // So, we can't just put new package directive in it's old place and rely on FileStructure rule + if (packageDirectiveNode != packageDirectiveParent.firstChildNode) { + // We will insert new package directive node before first node, which is not in the following list + val possibleTypesBeforePackageDirective = listOf(WHITE_SPACE, EOL_COMMENT, BLOCK_COMMENT, KDOC, PACKAGE_DIRECTIVE, FILE_ANNOTATION_LIST) + val addBefore = packageDirectiveParent.children().first { it.elementType !in possibleTypesBeforePackageDirective } + packageDirectiveParent.removeChild(packageDirectiveNode) + packageDirectiveParent.addChild(newPackageDirective, addBefore) + if (newPackageDirective.treePrev.elementType != WHITE_SPACE) { + packageDirectiveParent.addChild(PsiWhiteSpaceImpl("\n"), newPackageDirective) + } + } else { + packageDirectiveParent.replaceChild(packageDirectiveNode, newPackageDirective) + } + if (newPackageDirective.treeNext.elementType != WHITE_SPACE) { + packageDirectiveParent.addChild(PsiWhiteSpaceImpl("\n"), newPackageDirective.treeNext) + } } } diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/FileStructureRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/FileStructureRule.kt index 82b4bad358..4bba67399a 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/FileStructureRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/FileStructureRule.kt @@ -304,7 +304,7 @@ class FileStructureRule(configRules: List) : DiktatRule( if (elementType == WHITE_SPACE && text.count { it == '\n' } != 2) { FILE_NO_BLANK_LINE_BETWEEN_BLOCKS.warnAndFix(configRules, emitWarn, isFixMode, astNode.text.lines().first(), astNode.startOffset, astNode) { - (this as LeafPsiElement).replaceWithText("\n\n${text.replace("\n", "")}") + (this as LeafPsiElement).parent.node.replaceChild(this, PsiWhiteSpaceImpl("\n\n${text.replace("\n", "")}")) } } } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/PackageNamingWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/PackageNamingWarnTest.kt index 1f700f71ce..674a17102c 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/PackageNamingWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/PackageNamingWarnTest.kt @@ -51,6 +51,26 @@ class PackageNamingWarnTest : LintTestBase(::PackageNaming) { ) } + @Test + @Tag(WarningNames.PACKAGE_NAME_MISSING) + fun `missing package name with annotation (check)`() { + lintMethod( + """ + @file:Suppress("CONSTANT_UPPERCASE") + + import org.cqfn.diktat.a.b.c + + /** + * testComment + */ + class TestPackageName { } + + """.trimIndent(), + LintError(1, 37, ruleId, "${PACKAGE_NAME_MISSING.warnText()} $TEST_FILE_NAME", true), + rulesConfigList = rulesConfigList + ) + } + @Test @Tag(WarningNames.PACKAGE_NAME_INCORRECT_CASE) fun `package name should be in a lower case (check)`() { diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/PackagePathFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/PackagePathFixTest.kt index ba7aba84af..5bd83cc205 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/PackagePathFixTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/PackagePathFixTest.kt @@ -31,6 +31,32 @@ class PackagePathFixTest : FixTestBase( fixAndCompare("some/FixIncorrectExpected.kt", "some/FixIncorrectTest.kt") } + @Test + @Tag(WarningNames.PACKAGE_NAME_MISSING) + fun `fix missing package name with file annotation`() { + fixAndCompare("org/cqfn/diktat/some/name/FixMissingWithAnnotationExpected.kt", "org/cqfn/diktat/some/name/FixMissingWithAnnotationTest.kt") + } + + @Test + @Tag(WarningNames.PACKAGE_NAME_MISSING) + fun `fix missing package name with file annotation and comments`() { + fixAndCompare("org/cqfn/diktat/some/name/FixMissingWithAnnotationExpected2.kt", "org/cqfn/diktat/some/name/FixMissingWithAnnotationTest2.kt") + } + + @Test + @Tag(WarningNames.PACKAGE_NAME_MISSING) + fun `fix missing package name with file annotation and comments 2`() { + fixAndCompare("org/cqfn/diktat/some/name/FixMissingWithAnnotationExpected3.kt", "org/cqfn/diktat/some/name/FixMissingWithAnnotationTest3.kt") + } + + // If there is no import list in code, the node is still present in the AST, but without any whitespaces around + // So, this check covered case, when we manually add whitespace before package directive + @Test + @Tag(WarningNames.PACKAGE_NAME_MISSING) + fun `fix missing package name without import list`() { + fixAndCompare("org/cqfn/diktat/some/name/FixMissingWithoutImportExpected.kt", "org/cqfn/diktat/some/name/FixMissingWithoutImportTest.kt") + } + @Test @Tag(WarningNames.PACKAGE_NAME_MISSING) fun `fix missing package name with a proper location without domain`() { diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/TopLevelOrderRuleFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/TopLevelOrderRuleFixTest.kt index 4b6d875b60..cd5a6c8862 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/TopLevelOrderRuleFixTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/TopLevelOrderRuleFixTest.kt @@ -4,6 +4,7 @@ import org.cqfn.diktat.ruleset.rules.chapter3.files.TopLevelOrderRule import org.cqfn.diktat.util.FixTestBase import generated.WarningNames +import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test @@ -19,4 +20,12 @@ class TopLevelOrderRuleFixTest : FixTestBase("test/paragraph3/top_level", ::TopL fun `should fix top level order with comment`() { fixAndCompare("TopLevelWithCommentExpected.kt", "TopLevelWithCommentTest.kt") } + + // FixMe: should be considered this case (swapped order of kdoc and package directive) + @Disabled("Isn't working yet") + @Test + @Tag(WarningNames.TOP_LEVEL_ORDER) + fun `should fix top level order with header kdoc`() { + fixAndCompare("TopLevelWithHeaderKdocExpected.kt", "TopLevelWithHeaderKdocTest.kt") + } } diff --git a/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingExpected.kt b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingExpected.kt index 58da8cfa0f..c1a68822bb 100644 --- a/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingExpected.kt @@ -1,5 +1,4 @@ package org.cqfn.diktat.some.name - import org.cqfn.diktat.ktlint.core.Rule class TestPackageName { diff --git a/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationExpected.kt b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationExpected.kt new file mode 100644 index 0000000000..92cccc5b65 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationExpected.kt @@ -0,0 +1,7 @@ +@file:Suppress("CONSTANT_UPPERCASE") + +package org.cqfn.diktat.some.name +import org.cqfn.diktat.ktlint.core.Rule + +class TestPackageName { +} diff --git a/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationExpected2.kt b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationExpected2.kt new file mode 100644 index 0000000000..77803de762 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationExpected2.kt @@ -0,0 +1,6 @@ +@file:Suppress("CONSTANT_UPPERCASE") // comment +package org.cqfn.diktat.some.name +import org.cqfn.diktat.ktlint.core.Rule + +class TestPackageName { +} diff --git a/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationExpected3.kt b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationExpected3.kt new file mode 100644 index 0000000000..4194493d0f --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationExpected3.kt @@ -0,0 +1,9 @@ +/** + * comment + */ +@file:Suppress("CONSTANT_UPPERCASE") +package org.cqfn.diktat.some.name +import org.cqfn.diktat.ktlint.core.Rule + +class TestPackageName { +} diff --git a/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationTest.kt b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationTest.kt new file mode 100644 index 0000000000..57e4a1129a --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationTest.kt @@ -0,0 +1,6 @@ +@file:Suppress("CONSTANT_UPPERCASE") + +import org.cqfn.diktat.ktlint.core.Rule + +class TestPackageName { +} diff --git a/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationTest2.kt b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationTest2.kt new file mode 100644 index 0000000000..ad4353f719 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationTest2.kt @@ -0,0 +1,5 @@ +@file:Suppress("CONSTANT_UPPERCASE") // comment +import org.cqfn.diktat.ktlint.core.Rule + +class TestPackageName { +} diff --git a/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationTest3.kt b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationTest3.kt new file mode 100644 index 0000000000..76c83cb771 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithAnnotationTest3.kt @@ -0,0 +1,8 @@ +/** + * comment + */ +@file:Suppress("CONSTANT_UPPERCASE") +import org.cqfn.diktat.ktlint.core.Rule + +class TestPackageName { +} diff --git a/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithoutImportExpected.kt b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithoutImportExpected.kt new file mode 100644 index 0000000000..666790dfe6 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithoutImportExpected.kt @@ -0,0 +1,7 @@ +@file:Suppress("CONSTANT_UPPERCASE") +package org.cqfn.diktat.some.name + +val a = 5 + +class TestPackageName { +} diff --git a/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithoutImportTest.kt b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithoutImportTest.kt new file mode 100644 index 0000000000..34f61483b9 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/org/cqfn/diktat/some/name/FixMissingWithoutImportTest.kt @@ -0,0 +1,5 @@ +@file:Suppress("CONSTANT_UPPERCASE") +val a = 5 + +class TestPackageName { +} diff --git a/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/some/FixMissingExpected.kt b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/some/FixMissingExpected.kt index 651271a2f7..c4d5be09e7 100644 --- a/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/some/FixMissingExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/some/FixMissingExpected.kt @@ -1,5 +1,4 @@ package org.cqfn.diktat.some - import org.cqfn.diktat.ktlint.core.Rule class TestPackageName { diff --git a/diktat-rules/src/test/resources/test/paragraph3/top_level/TopLevelWithHeaderKdocExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/top_level/TopLevelWithHeaderKdocExpected.kt new file mode 100644 index 0000000000..82534d239f --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph3/top_level/TopLevelWithHeaderKdocExpected.kt @@ -0,0 +1,9 @@ +/** + * Header Kdoc + */ + +package test.paragraph3.top_level + +import org.cqfn.diktat.bar + +class A {} diff --git a/diktat-rules/src/test/resources/test/paragraph3/top_level/TopLevelWithHeaderKdocTest.kt b/diktat-rules/src/test/resources/test/paragraph3/top_level/TopLevelWithHeaderKdocTest.kt new file mode 100644 index 0000000000..f7613bf749 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph3/top_level/TopLevelWithHeaderKdocTest.kt @@ -0,0 +1,9 @@ +package test.paragraph3.top_level + +/** + * Header Kdoc + */ + +import org.cqfn.diktat.bar + +class A {}