diff --git a/README.md b/README.md index 1345f1b214..e413764651 100644 --- a/README.md +++ b/README.md @@ -55,11 +55,11 @@ 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.1/diktat.jar) +2. Load diKTat manually: [here](https://github.com/cqfn/diKTat/releases/download/v0.5.2/diktat.jar) **OR** use curl: ```bash - $ curl -sSLO https://github.com/cqfn/diKTat/releases/download/v0.5.1/diktat-0.5.1.jar + $ curl -sSLO https://github.com/cqfn/diKTat/releases/download/v0.5.2/diktat-0.5.2.jar ``` 3. Finally, run KTlint (with diKTat injected) to check your `*.kt` files in `dir/your/dir`: @@ -110,7 +110,7 @@ This plugin is available since version 0.1.5. You can see how the plugin is conf Add this plugin to your `build.gradle.kts`: ```kotlin plugins { - id("org.cqfn.diktat.diktat-gradle-plugin") version "0.5.1" + id("org.cqfn.diktat.diktat-gradle-plugin") version "0.5.2" } ``` @@ -121,7 +121,7 @@ buildscript { mavenCentral() } dependencies { - classpath("org.cqfn.diktat:diktat-gradle-plugin:0.5.1") + classpath("org.cqfn.diktat:diktat-gradle-plugin:0.5.2") } } @@ -194,7 +194,7 @@ spotless { ```kotlin spotless { kotlin { - diktat("0.5.1").configFile("full/path/to/diktat-analysis.yml") + diktat("0.5.2").configFile("full/path/to/diktat-analysis.yml") } } ``` @@ -225,7 +225,7 @@ Diktat can be run via spotless-maven-plugin since version 2.8.0 ```xml - 0.5.1 + 0.5.2 full/path/to/diktat-analysis.yml ``` diff --git a/diktat-common/pom.xml b/diktat-common/pom.xml index c13c5f7868..08c327317a 100644 --- a/diktat-common/pom.xml +++ b/diktat-common/pom.xml @@ -9,7 +9,7 @@ org.cqfn.diktat diktat-parent - 0.5.2-SNAPSHOT + 0.5.3-SNAPSHOT diff --git a/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/reader/JsonResourceConfigReader.kt b/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/reader/JsonResourceConfigReader.kt index 5a3cba90a9..9d175d2677 100644 --- a/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/reader/JsonResourceConfigReader.kt +++ b/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/reader/JsonResourceConfigReader.kt @@ -57,6 +57,9 @@ abstract class JsonResourceConfigReader { protected abstract fun parseResource(fileStream: BufferedReader): T companion object { + /** + * A [Logger] that can be used + */ val log: Logger = LoggerFactory.getLogger(JsonResourceConfigReader::class.java) } } diff --git a/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/rules/RulesConfigReader.kt b/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/rules/RulesConfigReader.kt index 9cc8ac6f61..a4f831f712 100644 --- a/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/rules/RulesConfigReader.kt +++ b/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/rules/RulesConfigReader.kt @@ -19,6 +19,9 @@ import java.util.concurrent.atomic.AtomicInteger import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromString +/** + * Name of common configuration + */ const val DIKTAT_COMMON = "DIKTAT_COMMON" /** @@ -49,7 +52,6 @@ data class RulesConfig( * @property config a map of strings with configuration options for a particular rule */ open class RuleConfiguration(protected val config: Map) -object EmptyConfiguration : RuleConfiguration(emptyMap()) /** * class returns the list of configurations that we have read from a yml: diktat-analysis.yml @@ -87,6 +89,9 @@ open class RulesConfigReader(override val classLoader: ClassLoader) : JsonResour } companion object { + /** + * A [Logger] that can be used + */ val log: Logger = LoggerFactory.getLogger(RulesConfigReader::class.java) } } diff --git a/diktat-gradle-plugin/build.gradle.kts b/diktat-gradle-plugin/build.gradle.kts index 58c649ba7b..4fd41e5386 100644 --- a/diktat-gradle-plugin/build.gradle.kts +++ b/diktat-gradle-plugin/build.gradle.kts @@ -3,7 +3,7 @@ import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.getCurr plugins { `java-gradle-plugin` - kotlin("jvm") version "1.4.32" + kotlin("jvm") version "1.3.72" jacoco id("pl.droidsonroids.jacoco.testkit") version "1.0.7" id("org.gradle.test-retry") version "1.2.1" @@ -26,10 +26,13 @@ val jacocoVersion = project.properties.getOrDefault("jacocoVersion", "0.8.6") as dependencies { implementation(kotlin("gradle-plugin-api")) - implementation("com.pinterest.ktlint:ktlint-core:$ktlintVersion") { - exclude("com.pinterest.ktlint", "ktlint-ruleset-standard") + implementation("org.cqfn.diktat:diktat-rules:$diktatVersion") { + exclude("org.jetbrains.kotlin", "kotlin-compiler-embeddable") + exclude("org.jetbrains.kotlin", "kotlin-stdlib-jdk8") + exclude("org.jetbrains.kotlin", "kotlin-stdlib-jdk7") + exclude("org.jetbrains.kotlin", "kotlin-stdlib") + exclude("org.jetbrains.kotlin", "kotlin-stdlib-common") } - implementation("org.cqfn.diktat:diktat-rules:$diktatVersion") testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitVersion") @@ -62,7 +65,8 @@ tasks.withType { apiVersion = "1.3" jvmTarget = "1.8" useIR = true - } + allWarningsAsErrors = true + } dependsOn.add(generateVersionsFile) } diff --git a/diktat-gradle-plugin/gradle-plugin-marker/pom.xml b/diktat-gradle-plugin/gradle-plugin-marker/pom.xml index 52660df203..e1cc2ecd2c 100644 --- a/diktat-gradle-plugin/gradle-plugin-marker/pom.xml +++ b/diktat-gradle-plugin/gradle-plugin-marker/pom.xml @@ -4,7 +4,7 @@ diktat-gradle-plugin org.cqfn.diktat - 0.5.2-SNAPSHOT + 0.5.3-SNAPSHOT 4.0.0 diff --git a/diktat-gradle-plugin/pom.xml b/diktat-gradle-plugin/pom.xml index b67b194feb..9d176b3710 100644 --- a/diktat-gradle-plugin/pom.xml +++ b/diktat-gradle-plugin/pom.xml @@ -5,7 +5,7 @@ diktat-parent org.cqfn.diktat - 0.5.2-SNAPSHOT + 0.5.3-SNAPSHOT 4.0.0 diff --git a/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePlugin.kt b/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePlugin.kt index 8223efec9d..eba7648171 100644 --- a/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePlugin.kt +++ b/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePlugin.kt @@ -44,9 +44,24 @@ class DiktatGradlePlugin : Plugin { } companion object { + /** + * Task to check diKTat + */ const val DIKTAT_CHECK_TASK = "diktatCheck" + + /** + * DiKTat configuration + */ const val DIKTAT_CONFIGURATION = "diktat" + + /** + * DiKTat extension + */ const val DIKTAT_EXTENSION = "diktat" + + /** + * Task to run diKTat with fix + */ const val DIKTAT_FIX_TASK = "diktatFix" } } diff --git a/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskBase.kt b/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskBase.kt index 984bf3aa23..7b7b0b4108 100644 --- a/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskBase.kt +++ b/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskBase.kt @@ -93,6 +93,9 @@ open class DiktatJavaExecTaskBase @Inject constructor( project.logger.debug("Setting JavaExec args to $args") } + /** + * Function to execute diKTat + */ @TaskAction override fun exec() { if (shouldRun) { diff --git a/diktat-maven-plugin/pom.xml b/diktat-maven-plugin/pom.xml index 5778ae1f52..4de52781fa 100644 --- a/diktat-maven-plugin/pom.xml +++ b/diktat-maven-plugin/pom.xml @@ -5,7 +5,7 @@ diktat-parent org.cqfn.diktat - 0.5.2-SNAPSHOT + 0.5.3-SNAPSHOT 4.0.0 diff --git a/diktat-rules/pom.xml b/diktat-rules/pom.xml index e8d2b7abc8..9c50023e13 100644 --- a/diktat-rules/pom.xml +++ b/diktat-rules/pom.xml @@ -9,7 +9,7 @@ org.cqfn.diktat diktat-parent - 0.5.2-SNAPSHOT + 0.5.3-SNAPSHOT @@ -124,6 +124,11 @@ + + + -Xinline-classes + + diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt index b28e621145..a447d06d27 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt @@ -28,7 +28,7 @@ typealias ListOfPairs = MutableList> "WRONG_NEWLINES" ) enum class Warnings( - val canBeAutoCorrected: Boolean, + private val canBeAutoCorrected: Boolean, val ruleId: String, private val warn: String) : Rule { // ======== dummy test warning ====== @@ -207,7 +207,9 @@ enum class Warnings( canBeAutoCorrected: Boolean = this.canBeAutoCorrected, autoFix: () -> Unit) { warn(configRules, emit, canBeAutoCorrected, freeText, offset, node) - fix(configRules, isFixMode, node, autoFix) + if (canBeAutoCorrected) { + fix(configRules, isFixMode, node, autoFix) + } } /** diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/dummy/DummyWarning.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/dummy/DummyWarning.kt index d7bb77507b..d1383a5446 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/dummy/DummyWarning.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/dummy/DummyWarning.kt @@ -17,6 +17,7 @@ class DummyWarning(configRules: List) : DiktatRule( Warnings.FILE_NAME_MATCH_CLASS ) ) { + @Suppress("UNUSED") private lateinit var filePath: String @Suppress("EmptyFunctionBlock") diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/generation/Generation.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/generation/Generation.kt index 62282fb6c9..56d46346f9 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/generation/Generation.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/generation/Generation.kt @@ -64,8 +64,8 @@ private fun validateYear() { val files = File("diktat-rules/src/test/resources/test/paragraph2/header") files .listFiles() - .filterNot { it.name.contains("CopyrightDifferentYearTest.kt") } - .forEach { file -> + ?.filterNot { it.name.contains("CopyrightDifferentYearTest.kt") } + ?.forEach { file -> val tempFile = createTempFile().toFile() tempFile.printWriter().use { writer -> file.forEachLine { line -> diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRule.kt index 60970ba4f7..0378140e08 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRule.kt @@ -21,7 +21,7 @@ private typealias DiktatConfigRule = org.cqfn.diktat.common.config.rules.Rule @Suppress("TooGenericExceptionCaught") abstract class DiktatRule(id: String, val configRules: List, - val inspections: List) : Rule(id) { + private val inspections: List) : Rule(id) { /** * Default value is false */ diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/IdentifierNaming.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/IdentifierNaming.kt index 65c54a71d9..821a979570 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/IdentifierNaming.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/IdentifierNaming.kt @@ -50,7 +50,6 @@ import com.pinterest.ktlint.core.ast.ElementType.DESTRUCTURING_DECLARATION import com.pinterest.ktlint.core.ast.ElementType.DESTRUCTURING_DECLARATION_ENTRY import com.pinterest.ktlint.core.ast.ElementType.FILE import com.pinterest.ktlint.core.ast.ElementType.FUNCTION_TYPE -import com.pinterest.ktlint.core.ast.ElementType.PROPERTY import com.pinterest.ktlint.core.ast.ElementType.REFERENCE_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.TYPE_PARAMETER import com.pinterest.ktlint.core.ast.ElementType.TYPE_REFERENCE @@ -163,7 +162,7 @@ class IdentifierNaming(configRules: List) : DiktatRule( var namesOfVariables = extractVariableIdentifiers(node) // Only local private properties will be autofix in order not to break code if there are usages in other files. // Destructuring declarations are only allowed for local variables/values, so we don't need to calculate `isFix` for every node in `namesOfVariables` - val isFix = isFixMode && if (node.elementType == PROPERTY) (node.psi as KtProperty).run { isLocal || isPrivate() } else true + val isFix = isFixMode && if (node.elementType == ElementType.PROPERTY) (node.psi as KtProperty).run { isLocal || isPrivate() } else true namesOfVariables .forEach { variableName -> // variable should not contain only one letter in it's name. This is a bad example: b512 diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/CommentsRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/CommentsRule.kt index 1029eb5330..4555fc9b57 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/CommentsRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/CommentsRule.kt @@ -145,7 +145,7 @@ class CommentsRule(configRules: List) : DiktatRule( private val importOrPackageRegex = """^(import|package)?\s+([a-zA-Z.])+;*$""".toRegex() private val functionRegex = """^(public|private|protected)*\s*(override|abstract|actual|expect)*\s?fun\s+\w+(\(.*\))?(\s*:\s*\w+)?\s*[{=]${'$'}""".toRegex() private val rightBraceRegex = """^\s*}$""".toRegex() - private val requirePartOfCode = """val |var |=|(\{((.|\n)*)\})""".toRegex() + private val requirePartOfCode = """val |var |=|(\{((.|\n)*)})""".toRegex() private val codeFileStartCases = listOf(classRegex, importOrPackageRegex, functionRegex, rightBraceRegex) private val eolCommentStart = """// \S""".toRegex() } diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/CommentsFormatting.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/CommentsFormatting.kt index 6d3067ff26..4aa1f66073 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/CommentsFormatting.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/CommentsFormatting.kt @@ -56,8 +56,6 @@ class CommentsFormatting(configRules: List) : DiktatRule( IF_ELSE_COMMENTS, WRONG_NEWLINES_AROUND_KDOC)) { /** * @param node - * @param autoCorrect - * @param emit */ override fun logic(node: ASTNode) { val configuration = CommentsFormattingConfiguration( diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocComments.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocComments.kt index 96842d2c7f..ec4c1ed5b9 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocComments.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocComments.kt @@ -51,8 +51,6 @@ class KdocComments(configRules: List) : DiktatRule( KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT, MISSING_KDOC_CLASS_ELEMENTS, MISSING_KDOC_TOP_LEVEL)) { /** * @param node - * @param autoCorrect - * @param emit */ override fun logic(node: ASTNode) { val config = configRules.getCommonConfiguration() @@ -76,13 +74,13 @@ class KdocComments(configRules: List) : DiktatRule( ?.findChildByType(KDOC) ?: return val propertiesInKdoc = kdocBeforeClass .kDocTags() - ?.filter { it.knownTag == KDocKnownTag.PROPERTY } + .filter { it.knownTag == KDocKnownTag.PROPERTY } val propertyNames = (node.psi as KtParameterList) .parameters .mapNotNull { it.nameIdentifier?.text } propertiesInKdoc - ?.filterNot { it.getSubjectName() == null || it.getSubjectName() in propertyNames } - ?.forEach { KDOC_EXTRA_PROPERTY.warn(configRules, emitWarn, isFixMode, it.text, it.node.startOffset, node) } + .filterNot { it.getSubjectName() == null || it.getSubjectName() in propertyNames } + .forEach { KDOC_EXTRA_PROPERTY.warn(configRules, emitWarn, isFixMode, it.text, it.node.startOffset, node) } } @Suppress("UnsafeCallOnNullableType", "ComplexMethod") @@ -126,7 +124,7 @@ class KdocComments(configRules: List) : DiktatRule( private fun checkBasicKdocBeforeClass(node: ASTNode, kdocBeforeClass: ASTNode) { val propertyInClassKdoc = kdocBeforeClass .kDocTags() - ?.firstOrNull { it.knownTag == KDocKnownTag.PROPERTY && it.getSubjectName() == node.findChildByType(IDENTIFIER)!!.text } + .firstOrNull { it.knownTag == KDocKnownTag.PROPERTY && it.getSubjectName() == node.findChildByType(IDENTIFIER)!!.text } if (propertyInClassKdoc == null && node.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside()) { KDOC_NO_CONSTRUCTOR_PROPERTY.warnAndFix(configRules, emitWarn, isFixMode, "add <${node.findChildByType(IDENTIFIER)!!.text}> to KDoc", node.startOffset, node) { @@ -142,12 +140,12 @@ class KdocComments(configRules: List) : DiktatRule( prevComment: ASTNode) { val propertyInClassKdoc = kdocBeforeClass .kDocTags() - ?.firstOrNull { it.knownTag == KDocKnownTag.PROPERTY && it.getSubjectName() == node.findChildByType(IDENTIFIER)!!.text } + .firstOrNull { it.knownTag == KDocKnownTag.PROPERTY && it.getSubjectName() == node.findChildByType(IDENTIFIER)!!.text } ?.node val propertyInLocalKdoc = if (prevComment.elementType == KDOC) { prevComment .kDocTags() - ?.firstOrNull { it.knownTag == KDocKnownTag.PROPERTY && it.getSubjectName() == node.findChildByType(IDENTIFIER)!!.text } + .firstOrNull { it.knownTag == KDocKnownTag.PROPERTY && it.getSubjectName() == node.findChildByType(IDENTIFIER)!!.text } ?.node } else { null diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocFormatting.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocFormatting.kt index 5d85013673..0fabddb676 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocFormatting.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocFormatting.kt @@ -71,8 +71,6 @@ class KdocFormatting(configRules: List) : DiktatRule( /** * @param node - * @param autoCorrect - * @param emit */ override fun logic(node: ASTNode) { versionRegex ?: run { @@ -86,8 +84,8 @@ class KdocFormatting(configRules: List) : DiktatRule( checkNoDeprecatedTag(node) checkEmptyTags(node.kDocTags()) checkSpaceAfterTag(node.kDocTags()) - node.kDocBasicTags()?.let { checkEmptyLineBeforeBasicTags(it) } - node.kDocBasicTags()?.let { checkEmptyLinesBetweenBasicTags(it) } + checkEmptyLineBeforeBasicTags(node.kDocBasicTags()) + checkEmptyLinesBetweenBasicTags(node.kDocBasicTags()) checkBasicTagsOrder(node) checkNewLineAfterSpecialTags(node) checkAuthorAndDate(node) @@ -111,7 +109,7 @@ class KdocFormatting(configRules: List) : DiktatRule( @Suppress("UnsafeCallOnNullableType") private fun checkNoDeprecatedTag(node: ASTNode) { val kdocTags = node.kDocTags() - kdocTags?.find { it.name == "deprecated" } + kdocTags.find { it.name == "deprecated" } ?.let { kdocTag -> KDOC_NO_DEPRECATED_TAG.warnAndFix(configRules, emitWarn, isFixMode, kdocTag.text, kdocTag.node.startOffset, kdocTag.node) { val kdocSection = kdocTag.node.treeParent @@ -175,12 +173,12 @@ class KdocFormatting(configRules: List) : DiktatRule( val kdocTags = node.kDocTags() // distinct basic tags which are present in current KDoc, in proper order val basicTagsOrdered = basicTagsList.filter { basicTag -> - kdocTags?.find { it.knownTag == basicTag } != null + kdocTags.find { it.knownTag == basicTag } != null } // all basic tags from current KDoc - val basicTags = kdocTags?.filter { basicTagsOrdered.contains(it.knownTag) } + val basicTags = kdocTags.filter { basicTagsOrdered.contains(it.knownTag) } val isTagsInCorrectOrder = basicTags - ?.fold(mutableListOf()) { acc, kdocTag -> + .fold(mutableListOf()) { acc, kdocTag -> if (acc.size > 0 && acc.last().knownTag != kdocTag.knownTag) { acc.add(kdocTag) } else if (acc.size == 0) { @@ -188,10 +186,9 @@ class KdocFormatting(configRules: List) : DiktatRule( } acc } - ?.map { it.knownTag } - ?.equals(basicTagsOrdered) + .map { it.knownTag } == basicTagsOrdered - if (kdocTags != null && !isTagsInCorrectOrder!!) { + if (!isTagsInCorrectOrder) { KDOC_WRONG_TAGS_ORDER.warnAndFix(configRules, emitWarn, isFixMode, basicTags.joinToString(", ") { "@${it.name}" }, basicTags .first() @@ -326,11 +323,11 @@ class KdocFormatting(configRules: List) : DiktatRule( private fun checkAuthorAndDate(node: ASTNode) { node.kDocTags() - ?.filter { + .filter { it.knownTag == KDocKnownTag.AUTHOR || it.knownTag == KDocKnownTag.SINCE && it.hasInvalidVersion() } - ?.forEach { + .forEach { KDOC_CONTAINS_DATE_OR_AUTHOR.warn(configRules, emitWarn, isFixMode, it.text.trim(), it.startOffset, it.node) } } @@ -342,7 +339,7 @@ class KdocFormatting(configRules: List) : DiktatRule( (treeNext == null || treeNext.elementType == WHITE_SPACE && treeNext.text.count { it == '\n' } == 1) } - private fun ASTNode.kDocBasicTags() = kDocTags()?.filter { basicTagsList.contains(it.knownTag) } + private fun ASTNode.kDocBasicTags() = kDocTags().filter { basicTagsList.contains(it.knownTag) } private fun ASTNode.previousAsterisk() = prevSibling { it.elementType == KDOC_LEADING_ASTERISK } diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt index fda5c905e0..4d05efe223 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt @@ -72,8 +72,6 @@ class KdocMethods(configRules: List) : DiktatRule( KDOC_WITHOUT_THROWS_TAG, MISSING_KDOC_ON_FUNCTION)) { /** * @param node - * @param autoCorrect - * @param emit */ override fun logic(node: ASTNode) { if (node.elementType == FUN && node.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside() && !node.isOverridden()) { diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/LineLength.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/LineLength.kt index f35eff56be..518f99f754 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/LineLength.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/LineLength.kt @@ -8,10 +8,11 @@ import org.cqfn.diktat.ruleset.rules.DiktatRule import org.cqfn.diktat.ruleset.utils.KotlinParser import org.cqfn.diktat.ruleset.utils.appendNewlineMergingWhiteSpace import org.cqfn.diktat.ruleset.utils.calculateLineColByOffset +import org.cqfn.diktat.ruleset.utils.findParentNodeWithSpecificType import org.cqfn.diktat.ruleset.utils.hasChildOfType +import com.pinterest.ktlint.core.ast.ElementType.ANNOTATION_ENTRY import com.pinterest.ktlint.core.ast.ElementType.BINARY_EXPRESSION -import com.pinterest.ktlint.core.ast.ElementType.BLOCK import com.pinterest.ktlint.core.ast.ElementType.BOOLEAN_CONSTANT import com.pinterest.ktlint.core.ast.ElementType.CALL_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.CHARACTER_CONSTANT @@ -21,6 +22,7 @@ import com.pinterest.ktlint.core.ast.ElementType.EQ import com.pinterest.ktlint.core.ast.ElementType.FILE import com.pinterest.ktlint.core.ast.ElementType.FLOAT_CONSTANT import com.pinterest.ktlint.core.ast.ElementType.FUN +import com.pinterest.ktlint.core.ast.ElementType.IF import com.pinterest.ktlint.core.ast.ElementType.IMPORT_LIST import com.pinterest.ktlint.core.ast.ElementType.INTEGER_CONSTANT import com.pinterest.ktlint.core.ast.ElementType.KDOC_MARKDOWN_INLINE_LINK @@ -105,14 +107,56 @@ class LineLength(configRules: List) : DiktatRule( CONDITION -> return checkCondition(parent, configuration) PROPERTY -> return checkProperty(parent, configuration) EOL_COMMENT -> return checkComment(parent, configuration) + STRING_TEMPLATE -> { + // as we are going from bottom to top we are excluding + // 1. IF, because it seems that string template is in condition + // 2. FUN with EQ, it seems that new line should be inserted after `=` + parent.findParentNodeWithSpecificType(IF)?.let { + parent = parent.treeParent + } ?: parent.findParentNodeWithSpecificType(FUN)?.let { node -> + // checking that string template is not in annotation + if (node.hasChildOfType(EQ) && !wrongNode.parents().any { it.elementType == ANNOTATION_ENTRY }) { + parent = node + } else { + return checkStringTemplate(parent, configuration) + } + } ?: return checkStringTemplate(parent, configuration) + } else -> parent = parent.treeParent } } while (parent.treeParent != null) return LongLineFixableCases.None } + /** + * This class finds where the string can be split + * + * @return StringTemplate - if the string can be split, + * BinaryExpression - if there is two concatenated strings and new line should be inserted after `+` + * None - if the string can't be split + */ + private fun checkStringTemplate(node: ASTNode, configuration: LineLengthConfiguration): LongLineFixableCases { + val leftOffset = positionByOffset(node.startOffset).second + val difference = configuration.lineLength.toInt() - leftOffset + // case when new line should be inserted after `+`. Example: "first" + "second" + if (difference > node.text.length) { + return LongLineFixableCases.BinaryExpression(node.treeParent) + } + val delimiterIndex = node.text.substring(0, configuration.lineLength.toInt() - leftOffset).lastIndexOf(' ') + if (delimiterIndex == -1) { + return LongLineFixableCases.None + } + // minus 2 here as we are inserting ` +` and we don't want it to exceed line length + val correcterDelimiter = if (leftOffset + delimiterIndex > configuration.lineLength.toInt() - 2) { + node.text.substring(0, delimiterIndex - 2).lastIndexOf(' ') + } else { + delimiterIndex + } + return LongLineFixableCases.StringTemplate(node, correcterDelimiter) + } + private fun checkFun(wrongNode: ASTNode) = - if (!wrongNode.hasChildOfType(BLOCK)) LongLineFixableCases.Fun(wrongNode) else LongLineFixableCases.None + if (wrongNode.hasChildOfType(EQ)) LongLineFixableCases.Fun(wrongNode) else LongLineFixableCases.None private fun checkComment(wrongNode: ASTNode, configuration: LineLengthConfiguration): LongLineFixableCases { val leftOffset = positionByOffset(wrongNode.startOffset).second @@ -153,24 +197,16 @@ class LineLength(configRules: List) : DiktatRule( } } else { val leftOffset = positionByOffset(newParent.findChildByType(STRING_TEMPLATE)!!.startOffset).second - if (newParent.findChildByType(STRING_TEMPLATE)!!.hasChildOfType(LONG_STRING_TEMPLATE_ENTRY)) { - val binList = wrongNode.findChildByType(STRING_TEMPLATE)!!.getChildren(null).filter { it.elementType in propertyList } - if (binList.size == 1) { - return LongLineFixableCases.None - } - return LongLineFixableCases.PropertyWithTemplateEntry(wrongNode, configuration.lineLength, leftOffset, binList.toMutableList()) - } else { - if (leftOffset > configuration.lineLength - STRING_PART_OFFSET) { - return LongLineFixableCases.None - } - val text = wrongNode.findChildByType(STRING_TEMPLATE)!!.text.trim('"') - val lastCharIndex = configuration.lineLength.toInt() - leftOffset - STRING_PART_OFFSET - val indexLastSpace = (text.substring(0, lastCharIndex).lastIndexOf(' ')) - if (indexLastSpace == -1) { - return LongLineFixableCases.None - } - return LongLineFixableCases.Property(wrongNode, indexLastSpace, text) + if (leftOffset > configuration.lineLength - STRING_PART_OFFSET) { + return LongLineFixableCases.None + } + val text = wrongNode.findChildByType(STRING_TEMPLATE)!!.text.trim('"') + val lastCharIndex = configuration.lineLength.toInt() - leftOffset - STRING_PART_OFFSET + val indexLastSpace = (text.substring(0, lastCharIndex).lastIndexOf(' ')) + if (indexLastSpace == -1) { + return LongLineFixableCases.None } + return LongLineFixableCases.Property(wrongNode, indexLastSpace, text) } } @@ -193,7 +229,8 @@ class LineLength(configRules: List) : DiktatRule( is LongLineFixableCases.Comment -> fixComment(fixableType) is LongLineFixableCases.Condition -> fixLongBinaryExpression(fixableType) is LongLineFixableCases.Property -> createSplitProperty(fixableType) - is LongLineFixableCases.PropertyWithTemplateEntry -> fixLongString(fixableType) + is LongLineFixableCases.StringTemplate -> fixStringTemplate(fixableType) + is LongLineFixableCases.BinaryExpression -> fixBinaryExpression(fixableType.node) is LongLineFixableCases.None -> return } } @@ -210,6 +247,19 @@ class LineLength(configRules: List) : DiktatRule( } } + @Suppress("UnsafeCallOnNullableType") + private fun fixBinaryExpression(node: ASTNode) { + val whiteSpaceAfterPlus = node.findChildByType(OPERATION_REFERENCE)!!.treeNext + node.replaceChild(whiteSpaceAfterPlus, PsiWhiteSpaceImpl("\n")) + } + + private fun fixStringTemplate(wrongStringTemplate: LongLineFixableCases.StringTemplate) { + val incorrectText = wrongStringTemplate.node.text + val firstPart = incorrectText.substring(0, wrongStringTemplate.delimiterIndex) + val secondPart = incorrectText.substring(wrongStringTemplate.delimiterIndex, incorrectText.length) + wrongStringTemplate.node.treeParent.replaceChild(wrongStringTemplate.node, KotlinParser().createNode("$firstPart\" +\n\"$secondPart")) + } + /** * This method fix too long binary expression: split after OPERATION_REFERENCE closest to max length * @@ -336,33 +386,6 @@ class LineLength(configRules: List) : DiktatRule( } } - private fun fixLongString(wrongProperty: LongLineFixableCases.PropertyWithTemplateEntry) { - val wrongNode = wrongProperty.node - val leftOffset = wrongProperty.leftOffset - val lineLength = wrongProperty.maximumLineLength - val binList = wrongProperty.binList - val allText = binList.joinToString("") { it.text } - var binaryText = "" - binList.forEachIndexed { index, astNode -> - binaryText += astNode.text - if (STRING_PART_OFFSET + leftOffset + binaryText.length > lineLength) { - if (astNode.elementType == LITERAL_STRING_TEMPLATE_ENTRY) { - val lastCharIndex = lineLength.toInt() - leftOffset - STRING_PART_OFFSET - val indexLastSpace = (allText.substring(0, lastCharIndex).lastIndexOf(' ')) - if (indexLastSpace == -1) { - return - } - splitTextAndCreateNode(wrongNode, allText, indexLastSpace) - return - } else if (index == 0) { - return - } - splitTextAndCreateNode(wrongNode, allText, binaryText.length) - return - } - } - } - private fun createSplitProperty(wrongProperty: LongLineFixableCases.Property) { val node = wrongProperty.node val indexLastSpace = wrongProperty.indexLastSpace @@ -400,6 +423,10 @@ class LineLength(configRules: List) : DiktatRule( class Comment(val node: ASTNode, val indexLastSpace: Int) : LongLineFixableCases() + class StringTemplate(val node: ASTNode, val delimiterIndex: Int) : LongLineFixableCases() + + class BinaryExpression(val node: ASTNode) : LongLineFixableCases() + class Condition( val maximumLineLength: Long, val leftOffset: Int, @@ -411,12 +438,6 @@ class LineLength(configRules: List) : DiktatRule( val node: ASTNode, val indexLastSpace: Int, val text: String) : LongLineFixableCases() - - class PropertyWithTemplateEntry( - val node: ASTNode, - val maximumLineLength: Long, - val leftOffset: Int, - val binList: MutableList) : LongLineFixableCases() } /** diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/MagicNumberRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/MagicNumberRule.kt index c53573e5d9..cf6174d2a0 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/MagicNumberRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/MagicNumberRule.kt @@ -8,7 +8,6 @@ import org.cqfn.diktat.ruleset.rules.DiktatRule import org.cqfn.diktat.ruleset.utils.* import com.pinterest.ktlint.core.ast.ElementType.BINARY_EXPRESSION -import com.pinterest.ktlint.core.ast.ElementType.CONST_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.ENUM_ENTRY import com.pinterest.ktlint.core.ast.ElementType.FLOAT_CONSTANT import com.pinterest.ktlint.core.ast.ElementType.FUN diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/StringConcatenationRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/StringConcatenationRule.kt index 25b7b34881..72b87de096 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/StringConcatenationRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/StringConcatenationRule.kt @@ -6,7 +6,6 @@ import org.cqfn.diktat.ruleset.rules.DiktatRule import org.cqfn.diktat.ruleset.utils.* import com.pinterest.ktlint.core.ast.ElementType.BINARY_EXPRESSION -import com.pinterest.ktlint.core.ast.ElementType.CALL_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.DOT_QUALIFIED_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.OPERATION_REFERENCE import com.pinterest.ktlint.core.ast.ElementType.PLUS 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 f1c70a54dc..82b4bad358 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 @@ -67,8 +67,7 @@ class FileStructureRule(configRules: List) : DiktatRule( } private val standardImportsAsName = StandardPlatforms .values() - .map { it to it.packages } - .toMap() + .associate { it to it.packages } .mapValues { (_, value) -> value.map { it.split(PACKAGE_SEPARATOR).map(Name::identifier) } } diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/NewlinesRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/NewlinesRule.kt index c9d6d79fc4..149d0a9878 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/NewlinesRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/NewlinesRule.kt @@ -544,15 +544,15 @@ class NewlinesRule(configRules: List) : DiktatRule( } val callsByNewLine: ListOfList = mutableListOf() var callsInOneNewLine: MutableList = mutableListOf() - this.forEach { node -> - if (node.treePrev.isFollowedByNewline() || node.treePrev.isWhiteSpaceWithNewline()) { + this.forEach { astNode -> + if (astNode.treePrev.isFollowedByNewline() || astNode.treePrev.isWhiteSpaceWithNewline()) { callsByNewLine.add(callsInOneNewLine) callsInOneNewLine = mutableListOf() - callsInOneNewLine.add(node) + callsInOneNewLine.add(astNode) } else { - callsInOneNewLine.add(node) + callsInOneNewLine.add(astNode) } - if (node.treePrev.elementType == POSTFIX_EXPRESSION && !node.treePrev.isFollowedByNewline() && configuration.maxCallsInOneLine == 1) { + if (astNode.treePrev.elementType == POSTFIX_EXPRESSION && !astNode.treePrev.isFollowedByNewline() && configuration.maxCallsInOneLine == 1) { return true } } diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/WhiteSpaceRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/WhiteSpaceRule.kt index 26b09d20a3..dff412dafc 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/WhiteSpaceRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/WhiteSpaceRule.kt @@ -388,7 +388,8 @@ class WhiteSpaceRule(configRules: List) : DiktatRule( 0 } else { // this can happen, e.g. in lambdas after an arrow, where block can be not surrounded by braces - val isBlockStartingWithComment = treeNext.elementType == BLOCK && treeNext.firstChildNode.isPartOfComment() + // treeNext may not have children ( {_, _ -> }) + val isBlockStartingWithComment = treeNext.elementType == BLOCK && treeNext.firstChildNode?.isPartOfComment() == true if (textContains('\n') || treeNext.isPartOfComment() || isBlockStartingWithComment) null else text.count { it == ' ' } } diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/ImmutableValNoVarRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/ImmutableValNoVarRule.kt index 520772ed87..bbbb6a33c6 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/ImmutableValNoVarRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/ImmutableValNoVarRule.kt @@ -30,7 +30,7 @@ class ImmutableValNoVarRule(configRules: List) : DiktatRule( .findAllVariablesWithAssignments { it.name != null && it.isVar } .filter { it.value.isEmpty() } - varNoAssignments.forEach { (property, usages) -> + varNoAssignments.forEach { (_, _) -> // FixMe: raise another warning and fix the code (change to val) for variables without assignment } diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/NullChecksRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/NullChecksRule.kt index 1db26b8083..f52999d07e 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/NullChecksRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/NullChecksRule.kt @@ -7,6 +7,8 @@ import org.cqfn.diktat.ruleset.utils.* import com.pinterest.ktlint.core.ast.ElementType import com.pinterest.ktlint.core.ast.ElementType.BINARY_EXPRESSION +import com.pinterest.ktlint.core.ast.ElementType.BLOCK +import com.pinterest.ktlint.core.ast.ElementType.BREAK import com.pinterest.ktlint.core.ast.ElementType.CONDITION import com.pinterest.ktlint.core.ast.ElementType.ELSE import com.pinterest.ktlint.core.ast.ElementType.IF @@ -20,6 +22,7 @@ import com.pinterest.ktlint.core.ast.parent import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.psi.KtBinaryExpression +import org.jetbrains.kotlin.psi.KtBlockExpression import org.jetbrains.kotlin.psi.KtIfExpression /** @@ -67,14 +70,20 @@ class NullChecksRule(configRules: List) : DiktatRule( when (condition.operationToken) { // `==` and `===` comparison can be fixed with `?:` operator ElementType.EQEQ, ElementType.EQEQEQ -> - warnAndFixOnNullCheck(condition, true, - "use '.let/.also/?:/e.t.c' instead of ${condition.text}") { + warnAndFixOnNullCheck( + condition, + isFixable(node, true), + "use '.let/.also/?:/e.t.c' instead of ${condition.text}" + ) { fixNullInIfCondition(node, condition, true) } // `!==` and `!==` comparison can be fixed with `.let/also` operators ElementType.EXCLEQ, ElementType.EXCLEQEQEQ -> - warnAndFixOnNullCheck(condition, true, - "use '.let/.also/?:/e.t.c' instead of ${condition.text}") { + warnAndFixOnNullCheck( + condition, + isFixable(node, false), + "use '.let/.also/?:/e.t.c' instead of ${condition.text}" + ) { fixNullInIfCondition(node, condition, false) } else -> return @@ -83,6 +92,27 @@ class NullChecksRule(configRules: List) : DiktatRule( } } + @Suppress("UnsafeCallOnNullableType") + private fun isFixable(condition: ASTNode, + isEqualToNull: Boolean): Boolean { + // Handle cases with `break` word in blocks + val typePair = if (isEqualToNull) { + (ELSE to THEN) + } else { + (THEN to ELSE) + } + val isBlockInIfWithBreak = condition.getBreakNodeFromIf(typePair.first) + val isOneLineBlockInIfWithBreak = condition + .treeParent + .findChildByType(typePair.second) + ?.let { it.findChildByType(BLOCK) ?: it } + ?.let { astNode -> + astNode.hasChildOfType(BREAK) && + (astNode.psi as? KtBlockExpression)?.statements?.size != 1 + } ?: false + return (!isBlockInIfWithBreak && !isOneLineBlockInIfWithBreak) + } + @Suppress("UnsafeCallOnNullableType", "TOO_LONG_FUNCTION") private fun fixNullInIfCondition(condition: ASTNode, binaryExpression: KtBinaryExpression, @@ -92,12 +122,22 @@ class NullChecksRule(configRules: List) : DiktatRule( val elseCodeLines = condition.extractLinesFromBlock(ELSE) val text = if (isEqualToNull) { when { - elseCodeLines.isNullOrEmpty() -> "$variableName ?: run {\n${thenCodeLines?.joinToString(separator = "\n")}\n}" + elseCodeLines.isNullOrEmpty() -> + if (condition.getBreakNodeFromIf(THEN)) { + "$variableName ?: break" + } else { + "$variableName ?: run {${thenCodeLines?.joinToString(prefix = "\n", postfix = "\n", separator = "\n")}}" + } thenCodeLines!!.singleOrNull() == "null" -> """ |$variableName?.let { |${elseCodeLines.joinToString(separator = "\n")} |} """.trimMargin() + thenCodeLines.singleOrNull() == "break" -> """ + |$variableName?.let { + |${elseCodeLines.joinToString(separator = "\n")} + |} ?: break + """.trimMargin() else -> """ |$variableName?.let { |${elseCodeLines.joinToString(separator = "\n")} @@ -108,17 +148,19 @@ class NullChecksRule(configRules: List) : DiktatRule( """.trimMargin() } } else { - if (elseCodeLines.isNullOrEmpty() || (elseCodeLines.singleOrNull() == "null")) { - "$variableName?.let {\n${thenCodeLines?.joinToString(separator = "\n")}\n}" - } else { - """ - |$variableName?.let { - |${thenCodeLines?.joinToString(separator = "\n")} - |} - |?: run { - |${elseCodeLines.joinToString(separator = "\n")} - |} - """.trimMargin() + when { + elseCodeLines.isNullOrEmpty() || (elseCodeLines.singleOrNull() == "null") -> + "$variableName?.let {${thenCodeLines?.joinToString(prefix = "\n", postfix = "\n", separator = "\n")}}" + elseCodeLines.singleOrNull() == "break" -> + "$variableName?.let {${thenCodeLines?.joinToString(prefix = "\n", postfix = "\n", separator = "\n")}} ?: break" + else -> """ + |$variableName?.let { + |${thenCodeLines?.joinToString(separator = "\n")} + |} + |?: run { + |${elseCodeLines.joinToString(separator = "\n")} + |} + """.trimMargin() } } val tree = KotlinParser().createNode(text) @@ -159,6 +201,13 @@ class NullChecksRule(configRules: List) : DiktatRule( } } + private fun ASTNode.getBreakNodeFromIf(type: IElementType) = this + .treeParent + .findChildByType(type) + ?.let { it.findChildByType(BLOCK) ?: it } + ?.findAllNodesWithCondition({ it.elementType == BREAK })?.isNotEmpty() + ?: false + private fun ASTNode.extractLinesFromBlock(type: IElementType): List? = treeParent .getFirstChildWithType(type) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/calculations/AccurateCalculationsRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/calculations/AccurateCalculationsRule.kt index fb32b85809..1fc69c2de1 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/calculations/AccurateCalculationsRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter4/calculations/AccurateCalculationsRule.kt @@ -110,8 +110,6 @@ class AccurateCalculationsRule(configRules: List) : DiktatRule( /** * @param node - * @param autoCorrect - * @param emit */ override fun logic(node: ASTNode) { when (val psi = node.psi) { diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter5/LambdaLengthRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter5/LambdaLengthRule.kt index de961cdbde..533266c3c7 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter5/LambdaLengthRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter5/LambdaLengthRule.kt @@ -33,9 +33,9 @@ class LambdaLengthRule(configRules: List) : DiktatRule( val copyNode = node.clone() as ASTNode val sizeLambda = countCodeLines(copyNode) if (sizeLambda > configuration.maxLambdaLength) { - copyNode.findAllNodesWithCondition({ it.elementType == ElementType.LAMBDA_EXPRESSION }).forEachIndexed { index, node -> + copyNode.findAllNodesWithCondition({ it.elementType == ElementType.LAMBDA_EXPRESSION }).forEachIndexed { index, astNode -> if (index > 0) { - node.treeParent.removeChild(node) + astNode.treeParent.removeChild(astNode) } } val isIt = copyNode.findAllDescendantsWithSpecificType(ElementType.REFERENCE_EXPRESSION).map { re -> re.text }.contains("it") diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt index d66c5db7f8..e68bb1c44c 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt @@ -27,7 +27,6 @@ import com.pinterest.ktlint.core.ast.ElementType.KDOC import com.pinterest.ktlint.core.ast.ElementType.LATEINIT_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.LBRACE import com.pinterest.ktlint.core.ast.ElementType.MODIFIER_LIST -import com.pinterest.ktlint.core.ast.ElementType.OPERATION_REFERENCE import com.pinterest.ktlint.core.ast.ElementType.OVERRIDE_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.PRIVATE_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.PROTECTED_KEYWORD @@ -41,7 +40,6 @@ import com.pinterest.ktlint.core.ast.lineNumber import com.pinterest.ktlint.core.ast.parent import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.TokenType -import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.CompositeElement import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl import org.jetbrains.kotlin.com.intellij.psi.tree.IElementType @@ -89,7 +87,7 @@ fun ASTNode.isTextLengthInRange(range: IntRange): Boolean = this.textLength in r /** * getting first child name with IDENTIFIER type * - * @return node with type [IDENTIFIER] or null if it is not present + * @return node with type [ElementType.IDENTIFIER] or null if it is not present */ fun ASTNode.getIdentifierName(): ASTNode? = this.getFirstChildWithType(ElementType.IDENTIFIER) @@ -511,15 +509,6 @@ fun ASTNode.hasSuppress(warningName: String) = parent({ node -> fun ASTNode.isOverridden(): Boolean = findChildByType(MODIFIER_LIST)?.findChildByType(OVERRIDE_KEYWORD) != null -/** - * creation of operation reference in a node - */ -fun ASTNode.createOperationReference(elementType: IElementType, text: String) { - val operationReference = CompositeElement(OPERATION_REFERENCE) - this.addChild(operationReference, null) - operationReference.addChild(LeafPsiElement(elementType, text), null) -} - /** * removing all newlines in WHITE_SPACE node and replacing it to a one newline saving the initial indenting format */ @@ -659,7 +648,7 @@ fun ASTNode.areChildrenBeforeChild(children: List, beforeChild: ASTNode @Suppress("UnsafeCallOnNullableType") fun ASTNode.areChildrenBeforeGroup(children: List, group: List): Boolean { require(children.isNotEmpty() && group.isNotEmpty()) { "no sense to operate on empty lists" } - return children.map { getChildren(null).indexOf(it) }.maxOrNull()!! < group.map { getChildren(null).indexOf(it) }.minOrNull()!! + return children.maxOf { getChildren(null).indexOf(it) } < group.minOf { getChildren(null).indexOf(it) } } /** @@ -715,13 +704,6 @@ fun ASTNode.hasTestAnnotation() = findChildByType(MODIFIER_LIST) ?.any { it.findLeafWithSpecificType(ElementType.IDENTIFIER)?.text == "Test" } ?: false -/** - * Returns the first line of this node's text if it is single, or the first line followed by [suffix] if there are more than one. - * - * @param suffix a suffix to append if there are more than one lines of text - */ -fun ASTNode.firstLineOfText(suffix: String = "") = text.lines().run { singleOrNull() ?: (first() + suffix) } - /** * Return the number in the file of the last line of this node's text */ diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/KdocUtils.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/KdocUtils.kt index a64b3dcd70..37ba57eb2a 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/KdocUtils.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/KdocUtils.kt @@ -18,7 +18,7 @@ import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag /** * @return a list of [KDocTag]s from this KDoc node */ -fun ASTNode.kDocTags(): List? { +fun ASTNode.kDocTags(): List { require(this.elementType == ElementType.KDOC) { "kDoc tags can be retrieved only from KDOC node" } return this.getAllChildrenWithType(KDOC_SECTION).flatMap { sectionNode -> sectionNode.getAllChildrenWithType(ElementType.KDOC_TAG) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PsiUtils.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PsiUtils.kt index e1443c7955..3bccf34d70 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PsiUtils.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PsiUtils.kt @@ -4,8 +4,6 @@ package org.cqfn.diktat.ruleset.utils -import com.pinterest.ktlint.core.ast.ElementType -import org.jetbrains.kotlin.com.intellij.psi.PsiElement import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBlockExpression import org.jetbrains.kotlin.psi.KtCallExpression @@ -59,26 +57,6 @@ fun KtProperty.getDeclarationScope() = .let { if (it is KtTryExpression) it.tryBlock else it } as KtBlockExpression? -/** - * Checks if this [PsiElement] is an ancestor of [block]. - * Nodes like `IF`, `TRY` are parents of `ELSE`, `CATCH`, but their scopes are not intersecting, and false is returned in this case. - * - * @param block - * @return boolean result - */ -fun PsiElement.isContainingScope(block: KtBlockExpression): Boolean { - when (block.parent.node.elementType) { - ElementType.ELSE -> getParentOfType(true) - ElementType.CATCH -> getParentOfType(true) - else -> null - }.let { - if (this == it) { - return false - } - } - return isAncestor(block, false) -} - /** * Method that tries to find a local property declaration with the same name as current [KtNameReferenceExpression] element * diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/StringCaseUtils.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/StringCaseUtils.kt index 829c8339cc..e05f8eee58 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/StringCaseUtils.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/StringCaseUtils.kt @@ -170,17 +170,21 @@ private fun convertUnknownCaseToCamel(str: String, isFirstLetterCapital: Boolean isPreviousLetterUnderscore = false result.toString() } else { - val result = if (char == '_') { - isPreviousLetterUnderscore = true - "" - } else if (isPreviousLetterUnderscore) { - isPreviousLetterCapital = true - isPreviousLetterUnderscore = false - char.toUpperCase().toString() - } else { - isPreviousLetterCapital = false - isPreviousLetterUnderscore = false - char.toString() + val result = when { + char == '_' -> { + isPreviousLetterUnderscore = true + "" + } + isPreviousLetterUnderscore -> { + isPreviousLetterCapital = true + isPreviousLetterUnderscore = false + char.toUpperCase().toString() + } + else -> { + isPreviousLetterCapital = false + isPreviousLetterUnderscore = false + char.toString() + } } result } diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/StringUtils.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/StringUtils.kt index 70dc19803b..c45db4fce7 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/StringUtils.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/StringUtils.kt @@ -58,12 +58,6 @@ fun String.containsOneLetterOrZero(): Boolean { return count == 1 || count == 0 } -/** - * @param sub a substring to search - * @return count of ocurrences - */ -fun String.countSubStringOccurrences(sub: String) = this.split(sub).size - 1 - /** * Splits [this] string by file path separator * diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/indentation/Checkers.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/indentation/Checkers.kt index 35b62e78aa..f1b1bc328e 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/indentation/Checkers.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/indentation/Checkers.kt @@ -1,5 +1,5 @@ /** - * Implementations of [CustomIndentationChecker] for [IndentationRule] + * Implementations of CustomIndentationChecker for IndentationRule */ package org.cqfn.diktat.ruleset.utils.indentation @@ -30,7 +30,6 @@ import com.pinterest.ktlint.core.ast.ElementType.LPAR import com.pinterest.ktlint.core.ast.ElementType.OPERATION_REFERENCE import com.pinterest.ktlint.core.ast.ElementType.REFERENCE_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.SAFE_ACCESS -import com.pinterest.ktlint.core.ast.ElementType.STRING_TEMPLATE import com.pinterest.ktlint.core.ast.ElementType.SUPER_TYPE_LIST import com.pinterest.ktlint.core.ast.ElementType.THEN import com.pinterest.ktlint.core.ast.ElementType.VALUE_ARGUMENT @@ -211,7 +210,6 @@ internal class DotCallChecker(config: IndentationConfig) : CustomIndentationChec } ?.let { node -> if (node.isFromStringTemplate()) { - val template = node.parents().takeWhile { it.elementType != STRING_TEMPLATE }.last() return CheckResult.from(indentError.actual, indentError.expected + (if (configuration.extendedIndentBeforeDot) 2 else 1) * configuration.indentationSize, true) } diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/indentation/CustomIndentationChecker.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/indentation/CustomIndentationChecker.kt index ffa018cca5..1cd102afa8 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/indentation/CustomIndentationChecker.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/indentation/CustomIndentationChecker.kt @@ -1,5 +1,5 @@ /** - * Utility classes for [IndentationRule] + * Utility classes for IndentationRule */ package org.cqfn.diktat.ruleset.utils.indentation diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleTest.kt index 45d7ff2bf6..f7774578ee 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleTest.kt @@ -6,7 +6,6 @@ import org.cqfn.diktat.ruleset.constants.Warnings.HEADER_MISSING_IN_NON_SINGLE_C import org.cqfn.diktat.ruleset.constants.Warnings.HEADER_MISSING_OR_WRONG_COPYRIGHT import org.cqfn.diktat.ruleset.constants.Warnings.HEADER_NOT_BEFORE_PACKAGE import org.cqfn.diktat.ruleset.constants.Warnings.HEADER_WRONG_FORMAT -import org.cqfn.diktat.ruleset.constants.Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR import org.cqfn.diktat.ruleset.rules.DIKTAT_RULE_SET_ID import org.cqfn.diktat.ruleset.rules.chapter2.comments.HeaderCommentRule import org.cqfn.diktat.util.LintTestBase diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/EmptyBlockWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/EmptyBlockWarnTest.kt index c2a87615f0..37e712e07b 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/EmptyBlockWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/EmptyBlockWarnTest.kt @@ -8,8 +8,6 @@ import org.cqfn.diktat.util.LintTestBase import com.pinterest.ktlint.core.LintError import generated.WarningNames -import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/FileStructureRuleTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/FileStructureRuleTest.kt index 9ac9122706..f0f3c630af 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/FileStructureRuleTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/FileStructureRuleTest.kt @@ -363,7 +363,7 @@ class FileStructureRuleTest : LintTestBase(::FileStructureRule) { @Test @Tag(WarningNames.UNUSED_IMPORT) - fun `Acute`() { + fun `Acute import`() { lintMethod( """ |package org.cqfn.diktat.example diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LineLengthFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LineLengthFixTest.kt index 465f873782..1568cfbf0c 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LineLengthFixTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LineLengthFixTest.kt @@ -45,4 +45,9 @@ class LineLengthFixTest : FixTestBase("test/paragraph3/long_line", ::LineLength) fun `shouldn't fix`() { fixAndCompare("LongExpressionNoFixExpected.kt", "LongExpressionNoFixTest.kt", rulesConfigListShortLineLength) } + + @Test + fun `should fix annotation`() { + fixAndCompare("LongLineAnnotationExpected.kt", "LongLineAnnotationTest.kt", rulesConfigListLineLength) + } } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LineLengthWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LineLengthWarnTest.kt index f3e55fad03..8342ba6fde 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LineLengthWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LineLengthWarnTest.kt @@ -19,6 +19,10 @@ class LineLengthWarnTest : LintTestBase(::LineLength) { RulesConfig(LONG_LINE.name, true, mapOf("lineLength" to "163")) ) + private val shortLineLength: List = listOf( + RulesConfig(LONG_LINE.name, true, + mapOf("lineLength" to "40")) + ) private val wrongUrl = "dhttps://www.google.com/search?q=djfhvkdfhvkdh+gthtdj%" + "3Bb&rlz=1C1GCEU_enRU909RU909&oq=posible+gthtdj%3Bb&aqs=chrome.." + "69i57j0l3.2680j1j7&sourceid=chrome&ie=UTF-8" @@ -221,4 +225,18 @@ class LineLengthWarnTest : LintTestBase(::LineLength) { LintError(9, 1, ruleId, "${LONG_LINE.warnText()} max line length 120, but was 123", false) ) } + + @Test + @Tag(WarningNames.LONG_LINE) + fun `check annotation and fun with expr body`() { + lintMethod( + """ + |@Query(value = "ASDAASDASDASDASDASDASDASDAASDASDASDASDASDASDASDAASDASDASDASDASDASD") + |fun foo() = println("ASDAASDASDASDASDASDASDASDAASDASDASDASDASDASDASDAASDASDASDASDASDASD") + """.trimMargin(), + LintError(1, 1, ruleId, "${LONG_LINE.warnText()} max line length 40, but was 84", false), + LintError(2, 1, ruleId, "${LONG_LINE.warnText()} max line length 40, but was 89", true), + rulesConfigList = shortLineLength + ) + } } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter4/NullChecksRuleFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter4/NullChecksRuleFixTest.kt index 5962baa5f9..088b705ff8 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter4/NullChecksRuleFixTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter4/NullChecksRuleFixTest.kt @@ -8,6 +8,12 @@ import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test class NullChecksRuleFixTest : FixTestBase("test/paragraph4/null_checks", ::NullChecksRule) { + @Test + @Tag(WarningNames.AVOID_NULL_CHECKS) + fun `should careful fix if conditions with break`() { + fixAndCompare("IfConditionBreakCheckExpected.kt", "IfConditionBreakCheckTest.kt") + } + @Test @Tag(WarningNames.AVOID_NULL_CHECKS) fun `should fix if conditions`() { diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtilsTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtilsTest.kt index f5fa29987a..c82cf91afb 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtilsTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtilsTest.kt @@ -746,6 +746,7 @@ private class PrettyPrintingVisitor(private val elementType: IElementType, ) } } + companion object { fun assertStringRepr( elementType: IElementType, @@ -757,7 +758,7 @@ private class PrettyPrintingVisitor(private val elementType: IElementType, KtLint.Params( text = code, ruleSets = listOf(RuleSet("test", PrettyPrintingVisitor(elementType, level, maxLevel, expected))), - cb = { _, _ -> Unit } + cb = { _, _ -> } ) ) } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/AvailableRulesDocTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/AvailableRulesDocTest.kt index 6ac304775e..d07c06287f 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/AvailableRulesDocTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/AvailableRulesDocTest.kt @@ -16,7 +16,7 @@ class AvailableRulesDocTest { val splitMarkDown = line .split("|") - val ruleName = splitMarkDown.get(SPLIT_MARK).trim() + val ruleName = splitMarkDown[SPLIT_MARK].trim() if (!ruleName.startsWith(TABLE_DELIMITER) && !ruleName.startsWith(RULE_NAME_HEADER)) { diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/RulesConfigYamlTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/RulesConfigYamlTest.kt index 97739f4a31..7df827bccb 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/RulesConfigYamlTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/RulesConfigYamlTest.kt @@ -19,6 +19,7 @@ import kotlinx.serialization.encodeToString * Special test that checks that developer has not forgotten to add his warning to a diktat-analysis.yml * This file is needed to be in tact with latest changes in Warnings.kt */ +@Suppress("UNUSED") inline class RulesConfigYamlTest(private val pathMap: Map = mapOf("diktat-analysis.yml" to "diKTat/diktat-rules/src/main/resources/diktat-analysis.yml", "diktat-analysis-huawei.yml" to "diKTat/diktat-rules/src/main/resources/diktat-analysis-huawei.yml", @@ -39,6 +40,7 @@ inline class RulesConfigYamlTest(private val pathMap: Map = } @Test + @Suppress("UNUSED") fun `check kotlin version`() { val currentKotlinVersion = KotlinVersion.CURRENT pathMap.keys.forEach { path -> diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/TestUtils.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/TestUtils.kt index 635b375bda..a0e0a61bbf 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/TestUtils.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/TestUtils.kt @@ -119,7 +119,7 @@ internal fun applyToCode(code: String, } }) ), - cb = { _, _ -> Unit } + cb = { _, _ -> } ) ) Assertions diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineAnnotationExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineAnnotationExpected.kt new file mode 100644 index 0000000000..e32daa3b6c --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineAnnotationExpected.kt @@ -0,0 +1,20 @@ +package test.paragraph3.long_line + +@Query(value = "select * from test inner join" + +" test_execution on test.id = test_execution.test_id and test_execution.st", nativeQuery = true) +fun retrieveBatches(limit: Int, offset: Int, executionId: Long): Some + +@Query(value = "select * from test inner join" + +" test_execution on test.id = test_execution.test_id and test_execution.status = 'READY' and test_execution.test_suite_execution_id = ?3 limit ?1 offset ?2", nativeQuery = true) +fun some(limit: Int, offset: Int, executionId: Long): List + +@Query(value = "select * from test inner joi", nativeQuery = true) +fun test(limit: Int, offset: Int, executionId: Long): List + +@Query(value = "select * from test inner joibbb", nativeQuery = true) +fun cornerCase(limit: Int, offset: Int, executionId: Long): List + +@Query(value = "select * from test inner join" + +" test_execution on test.id = test_execution.test_id and test_execution.status = 'READY' and test_execution.test_suite_execution_id = ?3 limit ?1 offset ?2", nativeQuery = true) +fun some(limit: Int, offset: Int, executionId: Long) = + println("testtesttesttesttesttesttesttesttesttesttesttest") diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineAnnotationTest.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineAnnotationTest.kt new file mode 100644 index 0000000000..ac80b16c8c --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineAnnotationTest.kt @@ -0,0 +1,16 @@ +package test.paragraph3.long_line + +@Query(value = "select * from test inner join test_execution on test.id = test_execution.test_id and test_execution.st", nativeQuery = true) +fun retrieveBatches(limit: Int, offset: Int, executionId: Long): Some + +@Query(value = "select * from test inner join test_execution on test.id = test_execution.test_id and test_execution.status = 'READY' and test_execution.test_suite_execution_id = ?3 limit ?1 offset ?2", nativeQuery = true) +fun some(limit: Int, offset: Int, executionId: Long): List + +@Query(value = "select * from test inner joi", nativeQuery = true) +fun test(limit: Int, offset: Int, executionId: Long): List + +@Query(value = "select * from test inner joibbb", nativeQuery = true) +fun cornerCase(limit: Int, offset: Int, executionId: Long): List + +@Query(value = "select * from test inner join test_execution on test.id = test_execution.test_id and test_execution.status = 'READY' and test_execution.test_suite_execution_id = ?3 limit ?1 offset ?2", nativeQuery = true) +fun some(limit: Int, offset: Int, executionId: Long) = println("testtesttesttesttesttesttesttesttesttesttesttest") diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueExpected.kt index 39cbaa24c2..d0f6f464c9 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueExpected.kt @@ -22,10 +22,10 @@ fun foo() { " woooooordsdcsdcsdcsdc $variable" val longStringExpression = "First part" + - "second Part" +"second Part" - val longStringExpression = "First very long part" + - "second Part" + val longStringExpression = "First very long" + +" part" + "second Part" val veryLooooooooooooooooooooooooooooooongVal = "text" diff --git a/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionBreakCheckExpected.kt b/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionBreakCheckExpected.kt new file mode 100644 index 0000000000..e4ff1130a7 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionBreakCheckExpected.kt @@ -0,0 +1,84 @@ +package test.paragraph4.null_checks + + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + if (result == null) { + foo() + } else { + break + } + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + result?.let { +foo() +} ?: break + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + if (result != null) { + break + } else { + foo() + } + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + result?.let { +foo() +} ?: break + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + result ?: break + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + if (result != null) { + break + } + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + if (result != null) { + foo() + break + } else { + break + } + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + if (result != null) { + result?.let { +goo() +} ?: break + } else { + break + } + } +} + diff --git a/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionBreakCheckTest.kt b/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionBreakCheckTest.kt new file mode 100644 index 0000000000..d3cf2ebd1c --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionBreakCheckTest.kt @@ -0,0 +1,92 @@ +package test.paragraph4.null_checks + + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + if (result == null) { + foo() + } else { + break + } + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + if (result == null) { + break + } else { + foo() + } + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + if (result != null) { + break + } else { + foo() + } + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + if (result != null) { + foo() + } else { + break + } + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + if (result == null) { + break + } + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + if (result != null) { + break + } + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + if (result != null) { + foo() + break + } else { + break + } + } +} + +fun foo() { + var result: Int? = 19 + while(result != 0 ) { + if (result != null) { + if (result != null) { + goo() + } else { + break + } + } else { + break + } + } +} + diff --git a/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionNullCheckExpected.kt b/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionNullCheckExpected.kt index 2a05252416..255982c5e8 100644 --- a/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionNullCheckExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionNullCheckExpected.kt @@ -47,3 +47,25 @@ value } } +fun foo() { + var result: Int? = 10 + while (result != 0 ) { + result?.let { +goo() +} +?: run { +for(i in 1..10) +break +} + } + while (result != 0) { + result = goo() + if (result != null) { + goo() + } else { + println(123) + break + } + } +} + diff --git a/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionNullCheckTest.kt b/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionNullCheckTest.kt index 5936fcb536..f95a7d34f0 100644 --- a/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionNullCheckTest.kt +++ b/diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionNullCheckTest.kt @@ -48,3 +48,24 @@ fun test() { } } +fun foo() { + var result: Int? = 10 + while (result != 0 ) { + if (result != null) { + goo() + } else { + for(i in 1..10) + break + } + } + while (result != 0) { + result = goo() + if (result != null) { + goo() + } else { + println(123) + break + } + } +} + diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example4Expected.kt b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example4Expected.kt index b36f911515..aa8dc3fae1 100644 --- a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example4Expected.kt +++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example4Expected.kt @@ -52,3 +52,9 @@ fun bar() { } } +@Suppress("") +fun foo() { + val y = "akgjsaujtmaksdkfasakgjsaujtmaksdkfasakgjsaujtmaksdkfasakgjsaujtm" + + " aksdkfasfasakgjsaujtmaksdfasafasakgjsaujtmaksdfasakgjsaujtmaksdfasakgjsaujtmaksdfasakgjsaujtmaksdfasakgjsaujtmaksdkgjsaujtmaksdfasakgjsaujtmaksd" +} + diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example4Test.kt b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example4Test.kt index 487190f619..831284655e 100644 --- a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example4Test.kt +++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example4Test.kt @@ -48,4 +48,9 @@ fun bar() { include("**/*.kt") } diktatExtension.reporter = PlainReporter(System.out) +} + +@Suppress("") +fun foo() { + val y = "akgjsaujtmaksdkfasakgjsaujtmaksdkfasakgjsaujtmaksdkfasakgjsaujtm aksdkfasfasakgjsaujtmaksdfasafasakgjsaujtmaksdfasakgjsaujtmaksdfasakgjsaujtmaksdfasakgjsaujtmaksdfasakgjsaujtmaksdkgjsaujtmaksdfasakgjsaujtmaksd" } \ No newline at end of file diff --git a/diktat-ruleset/pom.xml b/diktat-ruleset/pom.xml index e1bfad4b59..f222d9f5a3 100644 --- a/diktat-ruleset/pom.xml +++ b/diktat-ruleset/pom.xml @@ -8,7 +8,7 @@ org.cqfn.diktat diktat-parent - 0.5.2-SNAPSHOT + 0.5.3-SNAPSHOT diff --git a/diktat-test-framework/pom.xml b/diktat-test-framework/pom.xml index 763dd44987..2a05469336 100644 --- a/diktat-test-framework/pom.xml +++ b/diktat-test-framework/pom.xml @@ -9,7 +9,7 @@ org.cqfn.diktat diktat-parent - 0.5.2-SNAPSHOT + 0.5.3-SNAPSHOT diff --git a/diktat-test-framework/src/main/java/org/cqfn/diktat/test/framework/common/StreamGobbler.java b/diktat-test-framework/src/main/java/org/cqfn/diktat/test/framework/common/StreamGobbler.java index bb236cbd86..7484279135 100644 --- a/diktat-test-framework/src/main/java/org/cqfn/diktat/test/framework/common/StreamGobbler.java +++ b/diktat-test-framework/src/main/java/org/cqfn/diktat/test/framework/common/StreamGobbler.java @@ -13,9 +13,9 @@ public class StreamGobbler extends Thread { private static final Logger log = LoggerFactory.getLogger(StreamGobbler.class); - private InputStream inputStream; - private String streamType; - private ArrayList result; + private final InputStream inputStream; + private final String streamType; + private final ArrayList result; private volatile boolean isStopped = false; /** diff --git a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/config/TestArgumentsReader.kt b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/config/TestArgumentsReader.kt index c4222f6dd1..6e387548b7 100644 --- a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/config/TestArgumentsReader.kt +++ b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/config/TestArgumentsReader.kt @@ -86,7 +86,7 @@ class TestArgumentsReader( @Throws(IOException::class) override fun parseResource(fileStream: BufferedReader): List { val jsonValue = fileStream.lines().collect(Collectors.joining()) - return Json.decodeFromString>(jsonValue) + return Json.decodeFromString(jsonValue) } companion object { diff --git a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/config/TestConfig.kt b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/config/TestConfig.kt index ede63b6faa..71928094c9 100644 --- a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/config/TestConfig.kt +++ b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/config/TestConfig.kt @@ -54,6 +54,7 @@ class TestConfig internal constructor( * different profiles that can be used to control common processing part for tests * (processing differs for different programming languages) */ + @Suppress("UNUSED") enum class TestProfile { CXX, JAVA, KT, PYTHON } diff --git a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/config/TestConfigReader.kt b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/config/TestConfigReader.kt index 1ca166c75e..b196a0032d 100644 --- a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/config/TestConfigReader.kt +++ b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/config/TestConfigReader.kt @@ -26,6 +26,6 @@ class TestConfigReader(configFilePath: String, override val classLoader: ClassLo @Throws(IOException::class) override fun parseResource(fileStream: BufferedReader): TestConfig { val jsonValue: String = fileStream.lines().collect(Collectors.joining()) - return Json.decodeFromString(jsonValue) + return Json.decodeFromString(jsonValue) } } diff --git a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/FileComparator.kt b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/FileComparator.kt index 57c6f779ff..a90304a4b2 100644 --- a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/FileComparator.kt +++ b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/FileComparator.kt @@ -77,7 +77,7 @@ class FileComparator { * @param fileName - file where to write these list to, separated with newlines * @return a list of lines from the file */ - fun readFile(fileName: String): List { + private fun readFile(fileName: String): List { var list: List = ArrayList() try { Files.newBufferedReader(Paths.get(fileName)).use { list = it.lines().collect(Collectors.toList()) } diff --git a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/TestCheckWarn.kt b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/TestCheckWarn.kt index ef5c25eaaa..76a31d50a3 100644 --- a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/TestCheckWarn.kt +++ b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/TestCheckWarn.kt @@ -9,7 +9,7 @@ import org.slf4j.LoggerFactory */ class TestCheckWarn : TestCompare() { @Suppress("MISSING_KDOC_CLASS_ELEMENTS") override val log: Logger = LoggerFactory.getLogger(TestCheckWarn::class.java) - @Suppress("UnusedPrivateMember") private var testConfig: TestConfig? = null + @Suppress("UnusedPrivateMember", "UNUSED") private var testConfig: TestConfig? = null /** * Get tests execution result diff --git a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/TestComparatorUnit.kt b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/TestComparatorUnit.kt index 67bbd67f5e..b1dc4e4048 100644 --- a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/TestComparatorUnit.kt +++ b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/TestComparatorUnit.kt @@ -51,7 +51,7 @@ class TestComparatorUnit(private val resourceFilePath: String, * @param fileName * @return file content as a list of lines */ - fun readFile(fileName: String): List { + private fun readFile(fileName: String): List { var list: List = ArrayList() try { Files.newBufferedReader(Paths.get(fileName)).use { list = it.lines().collect(Collectors.toList()) } diff --git a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/TestMixed.kt b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/TestMixed.kt index e8d84178ce..063de83afc 100644 --- a/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/TestMixed.kt +++ b/diktat-test-framework/src/main/kotlin/org/cqfn/diktat/test/framework/processing/TestMixed.kt @@ -4,7 +4,11 @@ import org.cqfn.diktat.test.framework.common.TestBase import org.cqfn.diktat.test.framework.config.TestConfig import org.cqfn.diktat.test.framework.config.TestFrameworkProperties -@Suppress("MISSING_KDOC_TOP_LEVEL", "KDOC_NO_EMPTY_TAGS") // fixme: add documentation when implementation is done +@Suppress( + "MISSING_KDOC_TOP_LEVEL", + "KDOC_NO_EMPTY_TAGS", + "UNUSED" +) // fixme: add documentation when implementation is done class TestMixed : TestBase { private lateinit var testConfig: TestConfig diff --git a/examples/gradle-groovy-dsl/build.gradle b/examples/gradle-groovy-dsl/build.gradle index 9df743a17d..4d20f968d5 100644 --- a/examples/gradle-groovy-dsl/build.gradle +++ b/examples/gradle-groovy-dsl/build.gradle @@ -1,5 +1,5 @@ plugins { - id "org.cqfn.diktat.diktat-gradle-plugin" version "0.5.1" + id "org.cqfn.diktat.diktat-gradle-plugin" version "0.5.2" } repositories { diff --git a/examples/gradle-kotlin-dsl/build.gradle.kts b/examples/gradle-kotlin-dsl/build.gradle.kts index 3a0472a5ab..d7f193c14c 100644 --- a/examples/gradle-kotlin-dsl/build.gradle.kts +++ b/examples/gradle-kotlin-dsl/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("org.cqfn.diktat.diktat-gradle-plugin") version "0.5.1" + id("org.cqfn.diktat.diktat-gradle-plugin") version "0.5.2" } repositories { diff --git a/examples/maven/pom.xml b/examples/maven/pom.xml index 61b40ad32f..aca6c04ac6 100644 --- a/examples/maven/pom.xml +++ b/examples/maven/pom.xml @@ -8,7 +8,7 @@ 1.0.0-SNAPSHOT - 0.5.1 + 0.5.2 diff --git a/info/buildSrc/gradle.properties b/info/buildSrc/gradle.properties index a8b658efbe..662178744a 100644 --- a/info/buildSrc/gradle.properties +++ b/info/buildSrc/gradle.properties @@ -1 +1 @@ -version=0.5.2-SNAPSHOT +version=0.5.3-SNAPSHOT diff --git a/pom.xml b/pom.xml index c094aff007..8fa1aed5ca 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.cqfn.diktat diktat-parent - 0.5.2-SNAPSHOT + 0.5.3-SNAPSHOT pom diktat @@ -50,11 +50,11 @@ 30.1.1-jre 1.7.30 1.4 - 0.5.1 + 0.5.2 1.8.0 1.16.0 1.4.32 - 0.8.6 + 0.8.7 3.6.1 1.23 @@ -232,6 +232,8 @@ -Xuse-ir + -Werror + -Xopt-in=kotlin.RequiresOptIn true @@ -436,7 +438,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.6 + 3.0.1 sign-artifacts