diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
index 822297b063..9ac717ed6f 100644
--- a/.github/workflows/build_and_test.yml
+++ b/.github/workflows/build_and_test.yml
@@ -3,6 +3,9 @@ name: Build and test
on:
pull_request
+env:
+ GRADLE_OPTS: -Dorg.gradle.daemon=false
+
jobs:
test:
name: Unit Test
diff --git a/.github/workflows/diktat_snapshot.yml b/.github/workflows/diktat_snapshot.yml
index 37fa345dfb..7e9789c40a 100644
--- a/.github/workflows/diktat_snapshot.yml
+++ b/.github/workflows/diktat_snapshot.yml
@@ -6,6 +6,9 @@ on:
pull_request:
branches: [ master ]
+env:
+ GRADLE_OPTS: -Dorg.gradle.daemon=false
+
jobs:
diktat_snapshot_check:
runs-on: ubuntu-latest
diff --git a/.github/workflows/functional_tests.yml b/.github/workflows/functional_tests.yml
index 84027cee7d..01728aafb0 100644
--- a/.github/workflows/functional_tests.yml
+++ b/.github/workflows/functional_tests.yml
@@ -7,7 +7,7 @@ on:
branches: [ master ]
env:
- DIKTAT_VERSION: 0.1.2
+ DIKTAT_VERSION: 0.1.5
KTLINT_VERSION: 0.39.0
GRADLE_OPTS: -Dorg.gradle.daemon=false # to speed up gradle run
@@ -21,7 +21,7 @@ jobs:
- name: Setup environment
run: |
cat pom.xml | grep ".*" | head -1 |awk -F'[><]' '{ENVIRON[DIKTAT_VERSION]=$3 ; print ENVIRON[DIKTAT_VERSION]}'
- cat pom.xml | grep ".*" | head -1 |awk -F'[><]' '{ENVIRON[KTLINE_VERSION]=$3 ; print ENVIRON[KTLINE_VERSION]}'
+ cat pom.xml | grep ".*" | head -1 |awk -F'[><]' '{ENVIRON[KTLINT_VERSION]=$3 ; print ENVIRON[KTLINT_VERSION]}'
curl -sSLO https://github.com/pinterest/ktlint/releases/download/$KTLINT_VERSION/ktlint && chmod a+x ktlint
curl -sSLO https://github.com/cqfn/diKTat/releases/download/v$DIKTAT_VERSION/diktat-$DIKTAT_VERSION.jar
@@ -36,7 +36,7 @@ jobs:
- name: Run diKTat from cli
continue-on-error: true
run: |
- ./ktlint -R diktat-$DIKTAT_VERSION.jar "diktat-rules/src/test/resources/test/funcTest/FunctionalTestFile.kt" &> out
+ ./ktlint -R diktat-$DIKTAT_VERSION.jar "examples/maven/src/main/kotlin/Test.kt" &> out
- name: Check output
id: cli-check
@@ -44,20 +44,37 @@ jobs:
cat out
grep -E "\[VARIABLE_NAME_INCORRECT_FORMAT\]" out
- - name: Run diKTat from gradle
+ - name: Run diKTat from gradle kotlin DSL
continue-on-error: true
- run: gradle diktatFunctionalTest &> out
+ working-directory: ./examples/gradle-kotlin-dsl
+ run: |
+ gradle diktatCheck &> out
+
+ - name: Check gradle from kotlin DSL
+ working-directory: ./examples/gradle-kotlin-dsl
+ run: |
+ cat out
+ grep -E "\[VARIABLE_NAME_INCORRECT_FORMAT\]" out
+
+ - name: Run diKTat from gradle groovy DSL
+ continue-on-error: true
+ working-directory: ./examples/gradle-groovy-dsl
+ run: |
+ gradle diktatCheck &> out
- - name: Check gradle
+ - name: Check gradle from groovy DSL
+ working-directory: ./examples/gradle-groovy-dsl
run: |
cat out
grep -E "\[VARIABLE_NAME_INCORRECT_FORMAT\]" out
- name: Run diKTat from maven
+ working-directory: ./examples/maven
continue-on-error: true
- run: mvn -B diktat:check@functional-test &> out
+ run: mvn -B diktat:check &> out
- name: Check maven
+ working-directory: ./examples/maven
run: |
cat out
grep -E "\[VARIABLE_NAME_INCORRECT_FORMAT\]" out
diff --git a/.github/workflows/metrics_for_master.yml b/.github/workflows/metrics_for_master.yml
index b5509b6ee5..5092727af3 100644
--- a/.github/workflows/metrics_for_master.yml
+++ b/.github/workflows/metrics_for_master.yml
@@ -5,6 +5,9 @@ on:
branches:
- 'master'
+env:
+ GRADLE_OPTS: -Dorg.gradle.daemon=false
+
jobs:
master_flow:
name: Master branch update
@@ -25,7 +28,8 @@ jobs:
restore-keys: |
${{ runner.os }}-maven-build-
- name: Run tests
- run: mvn -B test -DskipPluginMarker
+ # we need to run `install` goal here so that gradle will be able to resolve dependencies and run tests on diktat-gradle-plugin
+ run: mvn -B install -DskipPluginMarker
- name: Generate code coverage report
uses: codecov/codecov-action@v1
with:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 4e76dc0a35..4fffc01f9a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -67,13 +67,19 @@ jobs:
asset_path: ./diktat-ruleset/target/diktat-${{ env.RELEASE_VERSION }}.jar
asset_name: diktat-${{ env.RELEASE_VERSION }}.jar
asset_content_type: application/zip
- - name: Update versions in pom.xml and documentation
+ - name: Update versions in pom.xml and documentation, update examples
id: update-versions
run: |
mvn -B versions:set -DnextSnapshot=true -DprocessAllModules=true versions:commit
mvn versions:set-property -Dproperty=diktat-check.version -DnewVersion=${{ env.RELEASE_VERSION }}
sed -i "s/$PREVIOUS_VERSION/$RELEASE_VERSION/g" README.md
sed -i "s/$PREVIOUS_VERSION/$RELEASE_VERSION/g" build.gradle.kts
+ sed -i "s/$PREVIOUS_VERSION/$RELEASE_VERSION/g" .github/workflows/functional_tests.yml
+ for file in examples/maven/pom.xml examples/gradle-groovy-dsl/build.gradle examples/gradle-kotlin-dsl/build.gradle.kts
+ do
+ sed -i "s/$PREVIOUS_VERSION/$RELEASE_VERSION/g" $file
+ cp diktat-rules/src/main/resources/diktat-analysis.yml $(dirname $file)
+ done
- name: Create pull request
uses: peter-evans/create-pull-request@v3
with:
diff --git a/README.md b/README.md
index 49eeae55d2..3c958f812c 100644
--- a/README.md
+++ b/README.md
@@ -93,6 +93,9 @@ Add this plugin to your pom.xml:
${project.basedir}/src/test/kotlin
diktat-analysis.yml
+
+ ${project.basedir}/src/test/kotlin/excluded
+
@@ -103,7 +106,7 @@ To run diktat in **only-check** mode use command `$ mvn diktat:check@diktat`.
To run diktat in **autocorrect** mode use command `$ mvn diktat:fix@diktat`.
## Run with Gradle using diktat-gradle-plugin
-This plugin is available since version 0.1.5. You can see how the plugin is configured in our project for self-checks: [build.gradle.kts](build.gradle.kts).
+This plugin is available since version 0.1.5. You can see how the plugin is configured in our examples: [build.gradle.kts](examples/gradle-kotlin-dsl/build.gradle.kts).
Add this plugin to your `build.gradle.kts`:
```kotlin
plugins {
@@ -130,6 +133,7 @@ You can then configure diktat using `diktat` extension:
diktat {
inputs = files("src/**/*.kt") // file collection that will be checked by diktat
debug = true // turn on debug logging
+ excludes = files("src/test/kotlin/excluded") // these files will not be checked by diktat
}
```
@@ -153,7 +157,7 @@ For example:
# all rules are enabled by the default. To disable add 'enabled: false' to the config.
enabled: true
configuration:
- isCopyrightMandatory: true,
+ isCopyrightMandatory: true
copyrightText: Copyright (c) Jeff Lebowski, 2012-2020. All rights reserved.
```
Note, that you can specify and put `diktat-analysis.yml` that contains configuration of diktat in the parent directory of your project on the same level where `build.gradle/pom.xml` is stored. \
diff --git a/build.gradle.kts b/build.gradle.kts
deleted file mode 100644
index ac2e6e6c86..0000000000
--- a/build.gradle.kts
+++ /dev/null
@@ -1,53 +0,0 @@
-val ktlint by configurations.creating
-
-repositories {
- mavenCentral()
- jcenter()
-}
-dependencies {
- ktlint("com.pinterest:ktlint:0.39.0") {
- // need to exclude standard ruleset to use only diktat rules
- exclude("com.pinterest.ktlint", "ktlint-ruleset-standard")
- }
-
- // diktat ruleset
- ktlint("org.cqfn.diktat:diktat-rules:0.1.5")
-}
-
-val outputDir = "${project.buildDir}/reports/diktat/"
-val inputFiles = project.fileTree(mapOf("dir" to "src", "include" to "**/*.kt"))
-
-val diktatCheck by tasks.creating(JavaExec::class) {
- inputs.files(inputFiles)
- outputs.dir(outputDir)
-
- description = "Check Kotlin code style."
- classpath = ktlint
- main = "com.pinterest.ktlint.Main"
-
- // specify proper path to sources that should be checked here
- args = listOf("**/src/main/kotlin/**/*.kt")
-}
-
-val diktatFormat by tasks.creating(JavaExec::class) {
- inputs.files(inputFiles)
- outputs.dir(outputDir)
-
- description = "Fix Kotlin code style deviations."
- classpath = ktlint
- main = "com.pinterest.ktlint.Main"
-
- // specify proper path to sources that should be checked here
- args = listOf("-F", "**/src/main/kotlin/**/*.kt")
-}
-
-val diktatFunctionalTest by tasks.creating(JavaExec::class) {
- inputs.files(inputFiles)
- outputs.dir(outputDir)
-
- description = "Diktat functional test"
- classpath = ktlint
- main = "com.pinterest.ktlint.Main"
-
- args = listOf("diktat-rules/src/test/resources/test/funcTest/FunctionalTestFile.kt")
-}
\ No newline at end of file
diff --git a/diktat-analysis.yml b/diktat-analysis.yml
index 4fdbdf87cf..4d6ea1c15d 100644
--- a/diktat-analysis.yml
+++ b/diktat-analysis.yml
@@ -297,4 +297,12 @@
enabled: true
# Checks if extension function with the same signature don't have related classes
- name: EXTENSION_FUNCTION_SAME_SIGNATURE
+ enabled: true
+# Checks if there is empty primary constructor
+- name: EMPTY_PRIMARY_CONSTRUCTOR
+ enabled: true
+# In case of not using field keyword in property accessors,
+# there should be explicit backing property with the name of real property
+# Example: val table get() {if (_table == null) ...} -> table should have _table
+- name: NO_CORRESPONDING_PROPERTY
enabled: true
\ No newline at end of file
diff --git a/diktat-common/src/main/kotlin/org/cqfn/diktat/common/cli/CliArgument.kt b/diktat-common/src/main/kotlin/org/cqfn/diktat/common/cli/CliArgument.kt
index c391df76c0..8e7176dd4a 100644
--- a/diktat-common/src/main/kotlin/org/cqfn/diktat/common/cli/CliArgument.kt
+++ b/diktat-common/src/main/kotlin/org/cqfn/diktat/common/cli/CliArgument.kt
@@ -2,7 +2,7 @@ package org.cqfn.diktat.common.cli
import org.apache.commons.cli.Option
-import kotlinx.serialization.*
+import kotlinx.serialization.Serializable
/**
* This class is used to serialize/deserialize json representation
diff --git a/diktat-common/src/test/kotlin/org/cqfn/diktat/test/ConfigReaderTest.kt b/diktat-common/src/test/kotlin/org/cqfn/diktat/test/ConfigReaderTest.kt
index 5a07324021..f989351a28 100644
--- a/diktat-common/src/test/kotlin/org/cqfn/diktat/test/ConfigReaderTest.kt
+++ b/diktat-common/src/test/kotlin/org/cqfn/diktat/test/ConfigReaderTest.kt
@@ -7,7 +7,8 @@ import org.junit.jupiter.api.Test
class ConfigReaderTest {
@Test
fun `testing json reading`() {
- val rulesConfigList: List? = RulesConfigReader(javaClass.classLoader).readResource("src/test/resources/test-rules-config.yml")
+ val rulesConfigList: List? = RulesConfigReader(javaClass.classLoader)
+ .readResource("src/test/resources/test-rules-config.yml")
require(rulesConfigList != null)
assert(rulesConfigList.any { it.name == "CLASS_NAME_INCORRECT" && it.enabled })
assert(rulesConfigList.find { it.name == "CLASS_NAME_INCORRECT" }?.configuration == mapOf())
diff --git a/diktat-gradle-plugin/build.gradle.kts b/diktat-gradle-plugin/build.gradle.kts
index d75a7f5521..5884c5c153 100644
--- a/diktat-gradle-plugin/build.gradle.kts
+++ b/diktat-gradle-plugin/build.gradle.kts
@@ -2,7 +2,8 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
`java-gradle-plugin`
- kotlin("jvm") version "1.4.10"
+ kotlin("jvm") version "1.4.20"
+ jacoco
}
repositories {
@@ -15,8 +16,9 @@ repositories {
}
// default value is needed for correct gradle loading in IDEA; actual value from maven is used during build
-val ktlintVersion: String = project.properties.getOrDefault("ktlintVersion", "0.39.0") as String
-val diktatVersion = project.version.takeIf { it.toString() != Project.DEFAULT_VERSION } ?: "0.1.6-SNAPSHOT"
+val ktlintVersion = project.properties.getOrDefault("ktlintVersion", "0.39.0") as String
+val diktatVersion = project.version.takeIf { it.toString() != Project.DEFAULT_VERSION } ?: "0.1.5"
+val junitVersion = project.properties.getOrDefault("junitVersion", "5.7.0") as String
dependencies {
implementation(kotlin("gradle-plugin-api"))
@@ -25,6 +27,9 @@ dependencies {
}
implementation("com.pinterest.ktlint:ktlint-reporter-plain:$ktlintVersion")
implementation("org.cqfn.diktat:diktat-rules:$diktatVersion")
+
+ testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitVersion")
}
val generateVersionsFile by tasks.registering {
@@ -51,7 +56,9 @@ tasks.withType {
// fixme: kotlin 1.3 is required for gradle <6.8
languageVersion = "1.3"
apiVersion = "1.3"
+ jvmTarget = "1.8"
}
+
dependsOn.add(generateVersionsFile)
}
@@ -67,3 +74,20 @@ gradlePlugin {
java {
withSourcesJar()
}
+
+// === testing & code coverage, consistent with maven
+tasks.withType {
+ useJUnitPlatform()
+ extensions.configure(JacocoTaskExtension::class) {
+ setDestinationFile(file("target/jacoco.exec"))
+ }
+}
+
+tasks.jacocoTestReport {
+ dependsOn(tasks.test)
+ reports {
+ // xml report is used by codecov
+ xml.isEnabled = true
+ xml.destination = file("target/site/jacoco/jacoco.xml")
+ }
+}
diff --git a/diktat-gradle-plugin/pom.xml b/diktat-gradle-plugin/pom.xml
index 2fb387649f..27ffb001f6 100644
--- a/diktat-gradle-plugin/pom.xml
+++ b/diktat-gradle-plugin/pom.xml
@@ -62,18 +62,39 @@
exec-maven-pluginfalse
+
+ gradle-test
+ test
+
+ ${gradle.executable}
+
+ clean
+ jacocoTestReport
+ -Pgroup=${project.groupId}
+ -Pversion=${project.version}
+ -Pdescription=${project.description}
+ -PktlintVersion=${ktlint.version}
+ -PjunitVersion=${junit.version}
+ -S
+
+ ${skip.gradle.build}
+
+
+ exec
+
+ gradleprepare-package${gradle.executable}
- clean${gradle.task}-Pgroup=${project.groupId}-Pversion=${project.version}-Pdescription=${project.description}-PktlintVersion=${ktlint.version}
+ -PjunitVersion=${junit.version}-S${skip.gradle.build}
diff --git a/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatExtension.kt b/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatExtension.kt
index 5049afae45..8fbdc68ed7 100644
--- a/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatExtension.kt
+++ b/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatExtension.kt
@@ -28,4 +28,9 @@ open class DiktatExtension {
* Paths that will be scanned for .kt(s) files
*/
lateinit var inputs: FileCollection
+
+ /**
+ * Paths that will be excluded from diktat run
+ */
+ var excludes: FileCollection? = null
}
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 ea4ca76647..6185f8ea2c 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
@@ -20,6 +20,7 @@ class DiktatGradlePlugin : Plugin {
diktatExtension.inputs = project.fileTree("src").apply {
include("**/*.kt")
}
+ diktatExtension.excludes = project.files()
diktatExtension.reporter = PlainReporter(System.out)
// only gradle 7+ (or maybe 6.8) will embed kotlin 1.4+, kx.serialization is incompatible with kotlin 1.3, so until then we have to use JavaExec wrapper
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 87faf159c7..fdae93ca40 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
@@ -12,6 +12,7 @@ import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.VerificationTask
import javax.inject.Inject
+import java.io.File
/**
* A base diktat task for gradle <6.8, which wraps [JavaExec]
@@ -45,8 +46,16 @@ open class DiktatJavaExecTaskBase @Inject constructor(
if (diktatExtension.debug) {
add("--debug")
}
- add(diktatExtension.inputs.files.joinToString { it.path })
+ diktatExtension.inputs.files.forEach {
+ val pattern = project.trimRootDir(it.path)
+ add("\"$pattern\"")
+ }
+ diktatExtension.excludes?.files?.forEach {
+ val pattern = project.trimRootDir(it.path)
+ add("\"!$pattern\"")
+ }
}
+ logger.debug("Setting JavaExec args to $args")
}
/**
@@ -88,3 +97,10 @@ fun Project.registerDiktatFixTask(diktatExtension: DiktatExtension, diktatConfig
DIKTAT_FIX_TASK, DiktatJavaExecTaskBase::class.java, gradle.gradleVersion,
diktatExtension, diktatConfiguration, listOf("-F ")
)
+
+private fun Project.trimRootDir(path: String) = if (path.startsWith(rootDir.absolutePath)) {
+ path.drop(rootDir.absolutePath.length)
+ } else {
+ path
+ }
+ .trim(File.separatorChar)
diff --git a/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginTest.kt b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginTest.kt
new file mode 100644
index 0000000000..d489d99dec
--- /dev/null
+++ b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginTest.kt
@@ -0,0 +1,31 @@
+package org.cqfn.diktat.plugin.gradle
+
+import org.gradle.api.Project
+import org.gradle.testfixtures.ProjectBuilder
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+class DiktatGradlePluginTest {
+ private val projectBuilder = ProjectBuilder.builder()
+ private lateinit var project: Project
+
+ @BeforeEach
+ fun setUp() {
+ project = projectBuilder.build()
+ project.pluginManager.apply(DiktatGradlePlugin::class.java)
+ }
+
+ @Test
+ fun `check that tasks are registered`() {
+ Assertions.assertTrue(project.tasks.findByName("diktatCheck") != null)
+ Assertions.assertTrue(project.tasks.findByName("diktatFix") != null)
+ }
+
+ @Test
+ fun `check default extension properties`() {
+ val diktatExtension = project.extensions.getByName("diktat") as DiktatExtension
+ Assertions.assertFalse(diktatExtension.debug)
+ Assertions.assertIterableEquals(project.fileTree("src").files, diktatExtension.inputs.files)
+ }
+}
diff --git a/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt
new file mode 100644
index 0000000000..2cd3e5f274
--- /dev/null
+++ b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt
@@ -0,0 +1,65 @@
+package org.cqfn.diktat.plugin.gradle
+
+import org.gradle.api.Project
+import org.gradle.testfixtures.ProjectBuilder
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import java.io.File
+
+class DiktatJavaExecTaskTest {
+ private val projectBuilder = ProjectBuilder.builder()
+ private lateinit var project: Project
+
+ @BeforeEach
+ fun setUp() {
+ project = projectBuilder.build()
+ }
+
+ @Test
+ fun `check command line for various inputs`() {
+ val pwd = project.file(".")
+ assertCommandLineEquals(
+ listOf(null, "\"${listOf("src", "**", "*.kt").joinToString(File.separator)}\""),
+ DiktatExtension().apply {
+ inputs = project.files("src/**/*.kt")
+ }
+ )
+ }
+
+ @Test
+ fun `check command line in debug mode`() {
+ val pwd = project.file(".")
+ assertCommandLineEquals(
+ listOf(null, "--debug", "\"${listOf("src", "**", "*.kt").joinToString(File.separator)}\""),
+ DiktatExtension().apply {
+ inputs = project.files("src/**/*.kt")
+ debug = true
+ }
+ )
+ }
+
+ @Test
+ fun `check command line with excludes`() {
+ val pwd = project.file(".")
+ assertCommandLineEquals(
+ listOf(null, "\"${listOf("src", "**", "*.kt").joinToString(File.separator)}\"",
+ "\"!${listOf("src", "main", "kotlin", "generated").joinToString(File.separator)}\""
+ ),
+ DiktatExtension().apply {
+ inputs = project.files("src/**/*.kt")
+ excludes = project.files("src/main/kotlin/generated")
+ }
+ )
+ }
+
+ private fun registerDiktatTask(extension: DiktatExtension) = project.tasks.register(
+ "test", DiktatJavaExecTaskBase::class.java,
+ "6.7", extension, project.configurations.create("diktat")
+ )
+
+ private fun assertCommandLineEquals(expected: List, extension: DiktatExtension) {
+ val task = registerDiktatTask(extension).get()
+ Assertions.assertIterableEquals(expected, task.commandLine)
+ }
+}
diff --git a/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/UtilsTest.kt b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/UtilsTest.kt
new file mode 100644
index 0000000000..5347b7e123
--- /dev/null
+++ b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/UtilsTest.kt
@@ -0,0 +1,24 @@
+package org.cqfn.diktat.plugin.gradle
+
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.Test
+
+class UtilsTest {
+ @Test
+ fun `test gradle version`() {
+ Assertions.assertEquals(
+ GradleVersion.fromString("6.6.1"),
+ GradleVersion(6, 6, 1, null)
+ )
+
+ Assertions.assertEquals(
+ GradleVersion.fromString("6.7"),
+ GradleVersion(6, 7, 0, null)
+ )
+
+ Assertions.assertEquals(
+ GradleVersion.fromString("6.7-rc-5"),
+ GradleVersion(6, 7, 0, "rc-5")
+ )
+ }
+}
diff --git a/diktat-maven-plugin/pom.xml b/diktat-maven-plugin/pom.xml
index 8eb3af6454..47ed32b33c 100644
--- a/diktat-maven-plugin/pom.xml
+++ b/diktat-maven-plugin/pom.xml
@@ -47,6 +47,25 @@
ktlint-reporter-plain${ktlint.version}
+
+ junit
+ junit
+ 3.8.2
+ test
+
+
+ org.apache.maven.plugin-testing
+ maven-plugin-testing-harness
+ 3.3.0
+ test
+
+
+
+ org.apache.maven
+ maven-compat
+ ${maven.api.version}
+ test
+
@@ -77,6 +96,10 @@
+
+ 1.4
+ 1.4
+
diff --git a/diktat-maven-plugin/src/main/kotlin/org/cqfn/diktat/plugin/maven/DiktatBaseMojo.kt b/diktat-maven-plugin/src/main/kotlin/org/cqfn/diktat/plugin/maven/DiktatBaseMojo.kt
index 72d9a97fb0..244fad589a 100644
--- a/diktat-maven-plugin/src/main/kotlin/org/cqfn/diktat/plugin/maven/DiktatBaseMojo.kt
+++ b/diktat-maven-plugin/src/main/kotlin/org/cqfn/diktat/plugin/maven/DiktatBaseMojo.kt
@@ -23,8 +23,14 @@ abstract class DiktatBaseMojo : AbstractMojo() {
/**
* Paths that will be scanned for .kt(s) files
*/
- @Parameter(property = "diktat.inputs")
- var inputs = listOf("\${project.basedir}/src")
+ @Parameter(property = "diktat.inputs", defaultValue = "\${project.basedir}/src")
+ lateinit var inputs: List
+
+ /**
+ * Paths that will be excluded if encountered during diktat run
+ */
+ @Parameter(property = "diktat.excludes", defaultValue = "")
+ lateinit var excludes: List
/**
* Flag that indicates whether to turn debug logging on
@@ -45,7 +51,7 @@ abstract class DiktatBaseMojo : AbstractMojo() {
* Property that can be used to access various maven settings
*/
@Parameter(defaultValue = "\${project}", readonly = true)
- lateinit var mavenProject: MavenProject
+ private lateinit var mavenProject: MavenProject
/**
* @param params instance of [KtLint.Params] used in analysis
@@ -63,7 +69,9 @@ abstract class DiktatBaseMojo : AbstractMojo() {
if (!File(configFile).exists()) {
throw MojoExecutionException("Configuration file $configFile doesn't exist")
}
- log.info("Running diKTat plugin with configuration file $configFile and inputs $inputs")
+ log.info("Running diKTat plugin with configuration file $configFile and inputs $inputs" +
+ if (excludes.isNotEmpty()) " and excluding $excludes" else ""
+ )
val ruleSets by lazy {
listOf(DiktatRuleSetProvider(configFile).get())
@@ -97,12 +105,14 @@ abstract class DiktatBaseMojo : AbstractMojo() {
* @throws MojoExecutionException if [RuleExecutionException] has been thrown by ktlint
*/
private fun checkDirectory(directory: File, lintErrors: MutableList, ruleSets: Iterable) {
+ val (excludedDirs, excludedFiles) = excludes.map(::File).partition { it.isDirectory }
directory
.walk()
.filter { file ->
file.isDirectory || file.extension.let { it == "kt" || it == "kts" }
}
.filter { it.isFile }
+ .filterNot { file -> file in excludedFiles || excludedDirs.any { file.startsWith(it) } }
.forEach { file ->
log.debug("Checking file $file")
try {
diff --git a/diktat-maven-plugin/src/test/kotlin/org/cqfn/diktat/plugin/maven/DiktatBaseMojoTest.kt b/diktat-maven-plugin/src/test/kotlin/org/cqfn/diktat/plugin/maven/DiktatBaseMojoTest.kt
new file mode 100644
index 0000000000..3041133cc4
--- /dev/null
+++ b/diktat-maven-plugin/src/test/kotlin/org/cqfn/diktat/plugin/maven/DiktatBaseMojoTest.kt
@@ -0,0 +1,55 @@
+package org.cqfn.diktat.plugin.maven
+
+import junit.framework.Assert
+import org.apache.maven.plugin.testing.AbstractMojoTestCase
+import kotlin.io.path.ExperimentalPathApi
+import kotlin.io.path.createTempFile
+import kotlin.io.path.writeText
+
+/**
+ * Tests for mojo configuration
+ * FixMe: inject project version from outside
+ * FixMe: `@Parameter` properties are not set
+ */
+@OptIn(ExperimentalPathApi::class)
+class DiktatBaseMojoTest : AbstractMojoTestCase() {
+ fun `test plugin configuration`() {
+ val pom = createTempFile()
+ pom.writeText(
+ """
+
+ 4.0.0
+
+ org.cqfn.diktat
+ diktat-test
+ 0.1.6-SNAPSHOT
+
+
+
+
+ org.cqfn.diktat
+ diktat-maven-plugin
+ 0.1.6-SNAPSHOT
+
+ diktat-analysis.yml
+
+
+
+
+ check
+
+
+
+
+
+
+
+ """.trimIndent()
+ )
+ val diktatCheckMojo = lookupMojo("check", pom.toFile()) as DiktatCheckMojo
+ Assert.assertEquals(false, diktatCheckMojo.debug)
+ Assert.assertEquals("diktat-analysis.yml", diktatCheckMojo.diktatConfigFile)
+ }
+}
diff --git a/diktat-rules/src/main/kotlin/generated/WarningNames.kt b/diktat-rules/src/main/kotlin/generated/WarningNames.kt
index c101070ae1..9a7f3d4ce0 100644
--- a/diktat-rules/src/main/kotlin/generated/WarningNames.kt
+++ b/diktat-rules/src/main/kotlin/generated/WarningNames.kt
@@ -35,14 +35,14 @@ public object WarningNames {
public const val GENERIC_NAME: String = "GENERIC_NAME"
+ public const val BACKTICKS_PROHIBITED: String = "BACKTICKS_PROHIBITED"
+
public const val FUNCTION_NAME_INCORRECT_CASE: String = "FUNCTION_NAME_INCORRECT_CASE"
public const val FUNCTION_BOOLEAN_PREFIX: String = "FUNCTION_BOOLEAN_PREFIX"
public const val FILE_NAME_INCORRECT: String = "FILE_NAME_INCORRECT"
- public const val FILE_NAME_MATCH_CLASS: String = "FILE_NAME_MATCH_CLASS"
-
public const val EXCEPTION_SUFFIX: String = "EXCEPTION_SUFFIX"
public const val CONFUSING_IDENTIFIER_NAMING: String = "CONFUSING_IDENTIFIER_NAMING"
@@ -137,8 +137,6 @@ public object WarningNames {
public const val LONG_LINE: String = "LONG_LINE"
- public const val BACKTICKS_PROHIBITED: String = "BACKTICKS_PROHIBITED"
-
public const val REDUNDANT_SEMICOLON: String = "REDUNDANT_SEMICOLON"
public const val WRONG_NEWLINES: String = "WRONG_NEWLINES"
@@ -165,6 +163,12 @@ public object WarningNames {
public const val LOCAL_VARIABLE_EARLY_DECLARATION: String = "LOCAL_VARIABLE_EARLY_DECLARATION"
+ public const val STRING_TEMPLATE_CURLY_BRACES: String = "STRING_TEMPLATE_CURLY_BRACES"
+
+ public const val STRING_TEMPLATE_QUOTES: String = "STRING_TEMPLATE_QUOTES"
+
+ public const val FILE_NAME_MATCH_CLASS: String = "FILE_NAME_MATCH_CLASS"
+
public const val NULLABLE_PROPERTY_TYPE: String = "NULLABLE_PROPERTY_TYPE"
public const val TYPE_ALIAS: String = "TYPE_ALIAS"
@@ -176,10 +180,6 @@ public object WarningNames {
public const val GENERIC_VARIABLE_WRONG_DECLARATION: String =
"GENERIC_VARIABLE_WRONG_DECLARATION"
- public const val STRING_TEMPLATE_CURLY_BRACES: String = "STRING_TEMPLATE_CURLY_BRACES"
-
- public const val STRING_TEMPLATE_QUOTES: String = "STRING_TEMPLATE_QUOTES"
-
public const val FLOAT_IN_ACCURATE_CALCULATIONS: String = "FLOAT_IN_ACCURATE_CALCULATIONS"
public const val AVOID_NULL_CHECKS: String = "AVOID_NULL_CHECKS"
@@ -219,4 +219,8 @@ public object WarningNames {
"TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED"
public const val EXTENSION_FUNCTION_SAME_SIGNATURE: String = "EXTENSION_FUNCTION_SAME_SIGNATURE"
+
+ public const val EMPTY_PRIMARY_CONSTRUCTOR: String = "EMPTY_PRIMARY_CONSTRUCTOR"
+
+ public const val NO_CORRESPONDING_PROPERTY: String = "NO_CORRESPONDING_PROPERTY"
}
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 7bc8ea670c..14449b4a9b 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
@@ -12,126 +12,126 @@ typealias EmitType = ((offset: Int, errorMessage: String, canBeAutoCorrected: Bo
* This class represent individual inspections of diktat code style.
* A [Warnings] entry contains rule name, warning message and is used in code check.
*/
-@Suppress("ForbiddenComment", "MagicNumber", "WRONG_DECLARATIONS_ORDER")
-enum class Warnings(private val canBeAutoCorrected: Boolean, private val warn: String) : Rule {
+@Suppress("ForbiddenComment", "MagicNumber", "WRONG_DECLARATIONS_ORDER", "MaxLineLength")
+enum class Warnings(val canBeAutoCorrected: Boolean, val ruleId: String, private val warn: String) : Rule {
// ======== chapter 1 ========
- PACKAGE_NAME_MISSING(true, "no package name declared in a file"),
- PACKAGE_NAME_INCORRECT_CASE(true, "package name should be completely in a lower case"),
- PACKAGE_NAME_INCORRECT_PREFIX(true, "package name should start from company's domain"),
+ PACKAGE_NAME_MISSING(true, "1.2.1", "no package name declared in a file"),
+ PACKAGE_NAME_INCORRECT_CASE(true, "1.2.1", "package name should be completely in a lower case"),
+ PACKAGE_NAME_INCORRECT_PREFIX(true, "1.2.1", "package name should start from company's domain"),
// FixMe: should add autofix
- PACKAGE_NAME_INCORRECT_SYMBOLS(false, "package name should contain only latin (ASCII) letters or numbers. For separation of words use dot"),
- PACKAGE_NAME_INCORRECT_PATH(true, "package name does not match the directory hierarchy for this file, the real package name should be"),
- INCORRECT_PACKAGE_SEPARATOR(true, "package name parts should be separated only by dots - there should be no other symbols like underscores (_)"),
- CLASS_NAME_INCORRECT(true, "class/enum/interface name should be in PascalCase and should contain only latin (ASCII) letters or numbers"),
- OBJECT_NAME_INCORRECT(true, "object structure name should be in PascalCase and should contain only latin (ASCII) letters or numbers"),
- VARIABLE_NAME_INCORRECT_FORMAT(true, "variable name should be in camel case (correct: checkIpConfig, incorrect: CheckIPConfig)" +
- " should contain only latin (ASCII) letters or numbers and should start from lower letter"),
- VARIABLE_NAME_INCORRECT(false, "variable name should contain more than one letter"),
- CONSTANT_UPPERCASE(true, " properties from companion object or on file level mostly in all cases are constants - please use upper snake case for them"),
- VARIABLE_HAS_PREFIX(true, "variable has prefix (like mVariable or M_VARIABLE), generally it is a bad code style (Android - is the only exception)"),
- IDENTIFIER_LENGTH(false, "identifier's length is incorrect, it should be in range of [2, 64] symbols"),
- ENUM_VALUE(true, "enum values should be in selected UPPER_CASE snake/PascalCase format"),
- GENERIC_NAME(true, "generic name should contain only one single capital letter, it can be followed by a number"),
- FUNCTION_NAME_INCORRECT_CASE(true, "function/method name should be in lowerCamelCase"),
- FUNCTION_BOOLEAN_PREFIX(true, "functions that return the value of Boolean type should have or prefix"),
- FILE_NAME_INCORRECT(true, "file name is incorrect - it should end with .kt extension and be in PascalCase"),
- FILE_NAME_MATCH_CLASS(true, "file name is incorrect - it should match with the class described in it if there is the only one class declared"),
- EXCEPTION_SUFFIX(true, "all exception classes should have \"Exception\" suffix"),
- CONFUSING_IDENTIFIER_NAMING(false, "it's a bad name for identifier"),
+ PACKAGE_NAME_INCORRECT_SYMBOLS(false, "1.2.1", "package name should contain only latin (ASCII) letters or numbers. For separation of words use dot"),
+ PACKAGE_NAME_INCORRECT_PATH(true, "1.2.1", "package name does not match the directory hierarchy for this file, the real package name should be"),
+ INCORRECT_PACKAGE_SEPARATOR(true, "1.2.1", "package name parts should be separated only by dots - there should be no other symbols like underscores (_)"),
+ CLASS_NAME_INCORRECT(true, "1.3.1", "class/enum/interface name should be in PascalCase and should contain only latin (ASCII) letters or numbers"),
+ OBJECT_NAME_INCORRECT(true, "1.3.1", "object structure name should be in PascalCase and should contain only latin (ASCII) letters or numbers"),
+ VARIABLE_NAME_INCORRECT_FORMAT(true, "1.6.1", "variable name should be in lowerCamelCase and should contain only latin (ASCII) letters or numbers and should start from lower letter"),
+ VARIABLE_NAME_INCORRECT(false, "1.1.1", "variable name should contain more than one letter"),
+ CONSTANT_UPPERCASE(true, "1.5.1", " properties from companion object or on file level mostly in all cases are constants - please use upper snake case for them"),
+ VARIABLE_HAS_PREFIX(true, "1.1.1", "variable has prefix (like mVariable or M_VARIABLE), generally it is a bad code style (Android - is the only exception)"),
+ IDENTIFIER_LENGTH(false, "1.1.1", "identifier's length is incorrect, it should be in range of [2, 64] symbols"),
+ ENUM_VALUE(true, "1.3.1", "enum values should be in selected UPPER_CASE snake/PascalCase format"),
+ GENERIC_NAME(true, "1.1.1", "generic name should contain only one single capital letter, it can be followed by a number"),
+ BACKTICKS_PROHIBITED(false, "1.1.1", "backticks should not be used in identifier's naming. The only exception test methods marked with @Test annotation"),
+ FUNCTION_NAME_INCORRECT_CASE(true, "1.4.1", "function/method name should be in lowerCamelCase"),
+ FUNCTION_BOOLEAN_PREFIX(true, "1.6.2", "functions that return the value of Boolean type should have or prefix"),
+ FILE_NAME_INCORRECT(true, "1.1.1", "file name is incorrect - it should end with .kt extension and be in PascalCase"),
+ EXCEPTION_SUFFIX(true, "1.1.1", "all exception classes should have \"Exception\" suffix"),
+ CONFUSING_IDENTIFIER_NAMING(false, "1.1.1", "it's a bad name for identifier"),
// ======== chapter 2 ========
- MISSING_KDOC_TOP_LEVEL(false, "all public and internal top-level classes and functions should have Kdoc"),
- MISSING_KDOC_CLASS_ELEMENTS(false, "all public, internal and protected classes, functions and variables inside the class should have Kdoc"),
- MISSING_KDOC_ON_FUNCTION(true, "all public, internal and protected functions should have Kdoc with proper tags"),
- KDOC_TRIVIAL_KDOC_ON_FUNCTION(false, "KDocs should not be trivial (e.g. method getX should not de documented as 'returns X')"),
- KDOC_WITHOUT_PARAM_TAG(true, "all methods which take arguments should have @param tags in KDoc"),
- KDOC_WITHOUT_RETURN_TAG(true, "all methods which return values should have @return tag in KDoc"),
- KDOC_WITHOUT_THROWS_TAG(true, "all methods which throw exceptions should have @throws tag in KDoc"),
- KDOC_EMPTY_KDOC(false, "KDoc should never be empty"),
- KDOC_WRONG_SPACES_AFTER_TAG(true, "there should be exactly one white space after tag name in KDoc"),
- KDOC_WRONG_TAGS_ORDER(true, "in KDoc standard tags are arranged in order @param, @return, @throws, but are"),
- KDOC_NEWLINES_BEFORE_BASIC_TAGS(true, "in KDoc block of standard tags @param, @return, @throws should contain newline before only if there is other content before it"),
- KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS(true, "in KDoc standard tags @param, @return, @throws should not containt newline between them, but these tags do"),
- KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS(true, "in KDoc there should be exactly one empty line after special tags"),
- KDOC_NO_EMPTY_TAGS(false, "no empty descriptions in tag blocks are allowed"),
- KDOC_NO_DEPRECATED_TAG(true, "KDoc doesn't support @deprecated tag, use @Deprecated annotation instead"),
- KDOC_NO_CONSTRUCTOR_PROPERTY(true, "all properties from the primary constructor should be documented in a @property tag in KDoc"),
- KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT(true, "replace comment before property with @property tag in class KDoc"),
- HEADER_WRONG_FORMAT(true, "file header comments should be properly formatted"),
- HEADER_MISSING_OR_WRONG_COPYRIGHT(true, "file header comment must include copyright information inside a block comment"),
- WRONG_COPYRIGHT_YEAR(true, "year defined in copyright and current year are different"),
- HEADER_CONTAINS_DATE_OR_AUTHOR(false, "file header comment should not contain creation date and author name"),
- HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE(false, "files that contain multiple or no classes should contain description of what is inside of this file"),
- HEADER_NOT_BEFORE_PACKAGE(true, "header KDoc should be placed before package and imports"),
- COMMENTED_OUT_CODE(false, "you should not comment out code, use VCS to save it in history and delete this block"),
- WRONG_NEWLINES_AROUND_KDOC(true, "there should be a blank line above the kDoc and there should not be no blank lines after kDoc"),
- FIRST_COMMENT_NO_SPACES(true, "there should not be any spaces before first comment"),
- COMMENT_WHITE_SPACE(true, "there should be a white space between code and comment also between code start token and comment text"),
- IF_ELSE_COMMENTS(true, "invalid comments structure. Comment should be inside the block"),
+ MISSING_KDOC_TOP_LEVEL(false, "2.1.1", "all public and internal top-level classes and functions should have Kdoc"),
+ MISSING_KDOC_CLASS_ELEMENTS(false, "2.1.1", "all public, internal and protected classes, functions and variables inside the class should have Kdoc"),
+ MISSING_KDOC_ON_FUNCTION(true, "2.1.1", "all public, internal and protected functions should have Kdoc with proper tags"),
+ KDOC_TRIVIAL_KDOC_ON_FUNCTION(false, "2.3.1", "KDocs should not be trivial (e.g. method getX should not de documented as 'returns X')"),
+ KDOC_WITHOUT_PARAM_TAG(true, "2.1.2", "all methods which take arguments should have @param tags in KDoc"),
+ KDOC_WITHOUT_RETURN_TAG(true, "2.1.2", "all methods which return values should have @return tag in KDoc"),
+ KDOC_WITHOUT_THROWS_TAG(true, "2.1.2", "all methods which throw exceptions should have @throws tag in KDoc"),
+ KDOC_EMPTY_KDOC(false, "2.1.3", "KDoc should never be empty"),
+ KDOC_WRONG_SPACES_AFTER_TAG(true, "2.1.3", "there should be exactly one white space after tag name in KDoc"),
+ KDOC_WRONG_TAGS_ORDER(true, "2.1.3", "in KDoc standard tags are arranged in order @param, @return, @throws, but are"),
+ KDOC_NEWLINES_BEFORE_BASIC_TAGS(true, "2.1.3", "in KDoc block of standard tags @param, @return, @throws should contain newline before only if there is other content before it"),
+ KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS(true, "2.1.3", "in KDoc standard tags @param, @return, @throws should not containt newline between them, but these tags do"),
+ KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS(true, "2.1.3", "in KDoc there should be exactly one empty line after special tags"),
+ KDOC_NO_EMPTY_TAGS(false, "2.2.1", "no empty descriptions in tag blocks are allowed"),
+ KDOC_NO_DEPRECATED_TAG(true, "2.1.3", "KDoc doesn't support @deprecated tag, use @Deprecated annotation instead"),
+ KDOC_NO_CONSTRUCTOR_PROPERTY(true, "2.1.1", "all properties from the primary constructor should be documented in a @property tag in KDoc"),
+ KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT(true, "2.1.1", "replace comment before property with @property tag in class KDoc"),
+ HEADER_WRONG_FORMAT(true, "2.2.1", "file header comments should be properly formatted"),
+ HEADER_MISSING_OR_WRONG_COPYRIGHT(true, "2.2.1", "file header comment must include copyright information inside a block comment"),
+ WRONG_COPYRIGHT_YEAR(true, "2.2.1", "year defined in copyright and current year are different"),
+ HEADER_CONTAINS_DATE_OR_AUTHOR(false, "2.2.1", "file header comment should not contain creation date and author name"),
+ HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE(false, "2.2.1", "files that contain multiple or no classes should contain description of what is inside of this file"),
+ HEADER_NOT_BEFORE_PACKAGE(true, "2.2.1", "header KDoc should be placed before package and imports"),
+ COMMENTED_OUT_CODE(false, "2.4.2", "you should not comment out code, use VCS to save it in history and delete this block"),
+ WRONG_NEWLINES_AROUND_KDOC(true, "2.4.1", "there should be a blank line above the kDoc and there should not be no blank lines after kDoc"),
+ FIRST_COMMENT_NO_SPACES(true, "2.4.1", "there should not be any spaces before first comment"),
+ COMMENT_WHITE_SPACE(true, "2.4.1", "there should be a white space between code and comment also between code start token and comment text"),
+ IF_ELSE_COMMENTS(true, "2.4.1", "invalid comments structure. Comment should be inside the block"),
// ======== chapter 3 ========
- FILE_IS_TOO_LONG(false, "file has more number of lines than expected"),
- FILE_CONTAINS_ONLY_COMMENTS(false, "source code files which contain only comments should be avoided"),
- FILE_INCORRECT_BLOCKS_ORDER(true, "general structure of kotlin source file is wrong, parts are in incorrect order"),
- FILE_NO_BLANK_LINE_BETWEEN_BLOCKS(true, "general structure of kotlin source file is wrong, general code blocks sohuld be separated by empty lines"),
- FILE_UNORDERED_IMPORTS(true, "imports should be ordered alphabetically and shouldn't be separated by newlines"),
- FILE_WILDCARD_IMPORTS(false, "wildcard imports should not be used"),
- NO_BRACES_IN_CONDITIONALS_AND_LOOPS(true, "in if, else, when, for, do, and while statements braces should be used. Exception: single line if statement."),
- WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES(true, "the declaration part of a class-like code structures (class/interface/etc.) should be in the proper order"),
- BLANK_LINE_BETWEEN_PROPERTIES(true, "there should be no blank lines between properties without comments; comment or KDoc on property should have blank line before"),
- BRACES_BLOCK_STRUCTURE_ERROR(true, "braces should follow 1TBS style"),
- WRONG_INDENTATION(true, "only spaces are allowed for indentation and each indentation should equal to 4 spaces (tabs are not allowed)"),
- EMPTY_BLOCK_STRUCTURE_ERROR(true, "incorrect format of empty block"),
- MORE_THAN_ONE_STATEMENT_PER_LINE(true, "There should not be more than one code statement in one line"),
- LONG_LINE(true, "This line is longer than allowed"),
- BACKTICKS_PROHIBITED(false, "Backticks should not be used in identifier's naming. The only exception test methods marked with @Test annotation"),
- REDUNDANT_SEMICOLON(true, "there should be no redundant semicolon at the end of lines"),
- WRONG_NEWLINES(true, "incorrect line breaking"),
+ FILE_IS_TOO_LONG(false, "3.1.1", "file has more number of lines than expected"),
+ FILE_CONTAINS_ONLY_COMMENTS(false, "3.1.2", "empty files or files that contain only comments should be avoided"),
+ FILE_INCORRECT_BLOCKS_ORDER(true, "3.1.2", "general structure of kotlin source file is wrong, parts are in incorrect order"),
+ FILE_NO_BLANK_LINE_BETWEEN_BLOCKS(true, "3.1.2", "general structure of kotlin source file is wrong, general code blocks sohuld be separated by empty lines"),
+ FILE_UNORDERED_IMPORTS(true, "3.1.2", "imports should be ordered alphabetically and shouldn't be separated by newlines"),
+ FILE_WILDCARD_IMPORTS(false, "3.1.2", "wildcard imports should not be used"),
+ NO_BRACES_IN_CONDITIONALS_AND_LOOPS(true, "3.2.1", "in if, else, when, for, do, and while statements braces should be used. Exception: single line if statement."),
+ WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES(true, "3.1.4", "the declaration part of a class-like code structures (class/interface/etc.) should be in the proper order"),
+ BLANK_LINE_BETWEEN_PROPERTIES(true, "3.1.4", "there should be no blank lines between properties without comments; comment or KDoc on property should have blank line before"),
+ BRACES_BLOCK_STRUCTURE_ERROR(true, "3.2.2", "braces should follow 1TBS style"),
+ WRONG_INDENTATION(true, "3.3.1", "only spaces are allowed for indentation and each indentation should equal to 4 spaces (tabs are not allowed)"),
+ EMPTY_BLOCK_STRUCTURE_ERROR(true, "3.4.1", "incorrect format of empty block"),
+ MORE_THAN_ONE_STATEMENT_PER_LINE(true, "3.6.1", "there should not be more than one code statement in one line"),
+ LONG_LINE(true, "3.5.1", "this line is longer than allowed"),
+ REDUNDANT_SEMICOLON(true, "3.6.2", "there should be no redundant semicolon at the end of lines"),
+ WRONG_NEWLINES(true, "3.6.2", "incorrect line breaking"),
// FixMe: autofixing will be added for this rule
- STRING_CONCATENATION(false, "strings should not be concatenated using plus operator - use string templates instead if the statement fits one line"),
- TOO_MANY_BLANK_LINES(true, "too many consecutive blank lines"),
- WRONG_WHITESPACE(true, "incorrect usage of whitespaces for code separation"),
- TOO_MANY_CONSECUTIVE_SPACES(true, "too many consecutive spaces"),
- ANNOTATION_NEW_LINE(true, "annotations must be on new line"),
- ENUMS_SEPARATED(true, "split enumeration error"),
- WHEN_WITHOUT_ELSE(true, "each when statement must have else at the end"),
- LONG_NUMERICAL_VALUES_SEPARATED(true, "long numerical values should be separated with underscore"),
- WRONG_DECLARATIONS_ORDER(true, "declarations of constants and enum members should be sorted alphabetically"),
- WRONG_MULTIPLE_MODIFIERS_ORDER(true, "sequence of modifiers is incorrect"),
- LOCAL_VARIABLE_EARLY_DECLARATION(false, "local variables should be declared close to the line where they are first used"),
+ STRING_CONCATENATION(false, "3.15.1", "strings should not be concatenated using plus operator - use string templates instead if the statement fits one line"),
+ TOO_MANY_BLANK_LINES(true, "3.7.1", "too many consecutive blank lines"),
+ WRONG_WHITESPACE(true, "3.8.1", "incorrect usage of whitespaces for code separation"),
+ TOO_MANY_CONSECUTIVE_SPACES(true, "3.8.1", "too many consecutive spaces"),
+ ANNOTATION_NEW_LINE(true, "3.12.1", "annotations must be on new line"),
+ ENUMS_SEPARATED(true, "3.9.1", "enum is incorrectly formatted"),
+ WHEN_WITHOUT_ELSE(true, "3.11.1", "each 'when' statement must have else at the end"),
+ LONG_NUMERICAL_VALUES_SEPARATED(true, "3.14.2", "long numerical values should be separated with underscore"),
+ WRONG_DECLARATIONS_ORDER(true, "3.1.4", "declarations of constants and enum members should be sorted alphabetically"),
+ WRONG_MULTIPLE_MODIFIERS_ORDER(true, "3.14.1", "sequence of modifier-keywords is incorrect"),
+ LOCAL_VARIABLE_EARLY_DECLARATION(false, "3.10.2", "local variables should be declared close to the line where they are first used"),
+ STRING_TEMPLATE_CURLY_BRACES(true, "3.15.2", "string template has redundant curly braces"),
+ STRING_TEMPLATE_QUOTES(true, "3.15.2", "string template has redundant quotes"),
+ FILE_NAME_MATCH_CLASS(true, "3.1.2", "file name is incorrect - it should match with the class described in it if there is the only one class declared"),
// ======== chapter 4 ========
- NULLABLE_PROPERTY_TYPE(true, "try to avoid use of nullable types"),
- TYPE_ALIAS(false, "variable's type is too complex and should be replaced with typealias"),
- SMART_CAST_NEEDED(true, "You can omit explicit casting"),
- SAY_NO_TO_VAR(false, "Usage of a mutable variables with [var] modifier - is a bad style, use [val] instead"),
- GENERIC_VARIABLE_WRONG_DECLARATION(true, "variable should have explicit type declaration"),
- STRING_TEMPLATE_CURLY_BRACES(true, "string template has redundant curly braces"),
- STRING_TEMPLATE_QUOTES(true, "string template has redundant quotes"),
+ NULLABLE_PROPERTY_TYPE(true, "4.3.1", "try to avoid use of nullable types"),
+ TYPE_ALIAS(false, "4.2.2", "variable's type is too complex and should be replaced with typealias"),
+ SMART_CAST_NEEDED(true, "4.2.1", "you can omit explicit casting"),
+ SAY_NO_TO_VAR(false, "4.1.3", "Usage of a mutable variables with [var] modifier - is a bad style, use [val] instead"),
+ GENERIC_VARIABLE_WRONG_DECLARATION(true, "4.3.2", "variable should have explicit type declaration"),
// FixMe: change float literal to BigDecimal? Or kotlin equivalent?
- FLOAT_IN_ACCURATE_CALCULATIONS(false, "floating-point values shouldn't be used in accurate calculations"),
- AVOID_NULL_CHECKS(false, "Try to avoid explicit null-checks. Use '.let/.also/?:/e.t.c' instead of"),
-
+ FLOAT_IN_ACCURATE_CALCULATIONS(false, "4.1.1", "floating-point values shouldn't be used in accurate calculations"),
+ AVOID_NULL_CHECKS(false, "4.3.3", "Try to avoid explicit null-checks. Use '.let/.also/?:/e.t.c' instead of"),
// ======== chapter 5 ========
- TOO_LONG_FUNCTION(false, "function is too long: split it or make more primitive"),
- AVOID_NESTED_FUNCTIONS(true, "try to avoid using nested functions"),
- LAMBDA_IS_NOT_LAST_PARAMETER(false, "lambda inside function parameters should be in the end"),
- TOO_MANY_PARAMETERS(false, "function has too many parameters"),
- NESTED_BLOCK(false, "function has too many nested blocks and should be simplified"),
- WRONG_OVERLOADING_FUNCTION_ARGUMENTS(false, "use default argument instead of function overloading"),
+ TOO_LONG_FUNCTION(false, "5.1.1", "function is too long: split it or make more primitive"),
+ AVOID_NESTED_FUNCTIONS(true, "5.1.3", "try to avoid using nested functions"),
+ LAMBDA_IS_NOT_LAST_PARAMETER(false, "5.2.1", "lambda inside function parameters should be in the end"),
+ TOO_MANY_PARAMETERS(false, "5.2.2", "function has too many parameters"),
+ NESTED_BLOCK(false, "5.1.2", "function has too many nested blocks and should be simplified"),
+ WRONG_OVERLOADING_FUNCTION_ARGUMENTS(false, "5.2.3", "use default argument instead of function overloading"),
// ======== chapter 6 ========
- SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY(true, "if a class has single constructor, it should be converted to a primary constructor"),
- USE_DATA_CLASS(false, "this class can be converted to a data class"),
- WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR(false, "Use `field` keyword instead of property name inside property accessors"),
- MULTIPLE_INIT_BLOCKS(true, "Avoid using multiple `init` blocks, this logic can be moved to constructors or properties declarations"),
- CLASS_SHOULD_NOT_BE_ABSTRACT(true, "class should not be abstract, because it has no abstract functions"),
- CUSTOM_GETTERS_SETTERS(false, "Custom getters and setters are not recommended, use class methods instead"),
- COMPACT_OBJECT_INITIALIZATION(true, "class instance can be initialized in `apply` block"),
- USELESS_SUPERTYPE(true,"unnecessary supertype specification"),
- TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED(true, "trivial property accessors are not recommended"),
- EXTENSION_FUNCTION_SAME_SIGNATURE(false, "extension functions should not have same signature if their receiver classes are related"),
+ SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY(true, "6.1.1", "if a class has single constructor, it should be converted to a primary constructor"),
+ USE_DATA_CLASS(false, "6.1.2", "this class can be converted to a data class"),
+ WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR(false, "6.1.9", "use `field` keyword instead of property name inside property accessors"),
+ MULTIPLE_INIT_BLOCKS(true, "6.1.4", "avoid using multiple `init` blocks, this logic can be moved to constructors or properties declarations"),
+ CLASS_SHOULD_NOT_BE_ABSTRACT(true, "6.1.6", "class should not be abstract, because it has no abstract functions"),
+ CUSTOM_GETTERS_SETTERS(false, "6.1.8", "custom getters and setters are not recommended, use class methods instead"),
+ COMPACT_OBJECT_INITIALIZATION(true, "6.1.11", "class instance can be initialized in `apply` block"),
+ USELESS_SUPERTYPE(true, "6.1.5", "unnecessary supertype specification"),
+ TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED(true, "6.1.10", "trivial property accessors are not recommended"),
+ EXTENSION_FUNCTION_SAME_SIGNATURE(false, "6.2.2", "extension functions should not have same signature if their receiver classes are related"),
+ EMPTY_PRIMARY_CONSTRUCTOR(true,"6.1.3", "avoid empty primary constructor"),
+ NO_CORRESPONDING_PROPERTY(false, "6.1.7", "backing property should have the same name, but there is no corresponding property")
;
/**
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/WarningsTableGenerator.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/WarningsTableGenerator.kt
new file mode 100644
index 0000000000..c20c83f731
--- /dev/null
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/WarningsTableGenerator.kt
@@ -0,0 +1,32 @@
+package cqfn.diktat.ruleset.constants
+
+import org.cqfn.diktat.ruleset.constants.Warnings
+import java.io.File
+
+const val DIKTAT_GUIDE: String = "guide/diktat-coding-convention.md#"
+
+@Suppress("MagicNumber")
+fun main() {
+ val allWarnings = Warnings.values()
+ allWarnings.sortBy { warn ->
+ val numbers = warn.ruleId.split(".")
+ val chapter = numbers[0].toInt()
+ val subChapter = numbers[1].toInt()
+ val rule = numbers[2].toInt()
+
+ // small hacky trick to compare rules like 1.1.13 properly (sorting using numbers instead of lexicographically)
+ chapter * 100000 + subChapter * 100 + rule
+ }
+
+ val maxRuleIdLength = allWarnings.maxBy { it.ruleId.length }?.ruleId?.length ?: 0
+ val maxRuleNameLength = allWarnings.maxBy { it.name.length }?.name?.length ?: 0
+ val separator = "| ${"-".repeat(maxRuleNameLength)} | ${"-".repeat(maxRuleIdLength)} | --- |\n"
+
+ val header = "| Diktat Rule | Code Style | Auto-fixed? |\n"
+
+ val tableWithWarnings = allWarnings.map { warn ->
+ "| ${warn.name} | [${warn.ruleId}](${DIKTAT_GUIDE}r${warn.ruleId}) | ${if (warn.canBeAutoCorrected) "yes" else "no"} |"
+ }.joinToString("\n")
+
+ File("info/rules-mapping.md").writeText("$header$separator$tableWithWarnings")
+}
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/AvoidEmptyPrimaryConstructor.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/AvoidEmptyPrimaryConstructor.kt
new file mode 100644
index 0000000000..00694a13be
--- /dev/null
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/AvoidEmptyPrimaryConstructor.kt
@@ -0,0 +1,35 @@
+package org.cqfn.diktat.ruleset.rules
+
+import com.pinterest.ktlint.core.Rule
+import com.pinterest.ktlint.core.ast.ElementType.CLASS
+import org.cqfn.diktat.common.config.rules.RulesConfig
+import org.cqfn.diktat.ruleset.constants.Warnings.EMPTY_PRIMARY_CONSTRUCTOR
+import org.jetbrains.kotlin.com.intellij.lang.ASTNode
+import org.jetbrains.kotlin.psi.KtClass
+
+class AvoidEmptyPrimaryConstructor(private val configRules: List) : Rule("avoid-empty-primary-constructor") {
+
+
+ private var isFixMode: Boolean = false
+ private lateinit var emitWarn: ((offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit)
+
+ override fun visit(node: ASTNode,
+ autoCorrect: Boolean,
+ emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) {
+ emitWarn = emit
+ isFixMode = autoCorrect
+
+ if (node.elementType == CLASS)
+ checkCLass(node.psi as KtClass)
+ }
+
+ @Suppress("UnsafeCallOnNullableType")
+ private fun checkCLass(ktClass: KtClass) {
+ if(ktClass.primaryConstructor?.valueParameters?.isNotEmpty() != false || ktClass.primaryConstructorModifierList != null)
+ return
+ EMPTY_PRIMARY_CONSTRUCTOR.warnAndFix(configRules, emitWarn, isFixMode, ktClass.nameIdentifier!!.text,
+ ktClass.node.startOffset, ktClass.node) {
+ ktClass.node.removeChild(ktClass.primaryConstructor!!.node)
+ }
+ }
+}
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/BlockStructureBraces.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/BlockStructureBraces.kt
index f84d8cb823..a3e117353a 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/BlockStructureBraces.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/BlockStructureBraces.kt
@@ -51,6 +51,7 @@ import org.jetbrains.kotlin.psi.KtTryExpression
* - braces around `else`/`catch`/`finally`/`while` (in `do-while` loop)
*/
class BlockStructureBraces(private val configRules: List) : Rule("block-structure") {
+
private var isFixMode: Boolean = false
private lateinit var emitWarn: ((offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit)
@@ -178,6 +179,15 @@ class BlockStructureBraces(private val configRules: List) : Rule("b
if (braceSpace == null || braceSpace.elementType != WHITE_SPACE) {
node.addChild(PsiWhiteSpaceImpl(" "), nodeBefore)
} else {
+ if (braceSpace.treePrev.elementType in COMMENT_TYPE) {
+ val commentBefore = braceSpace.treePrev
+ if (commentBefore.treePrev.elementType == WHITE_SPACE) {
+ commentBefore.treeParent.removeChild(commentBefore.treePrev)
+ }
+ commentBefore.treeParent.removeChild(commentBefore)
+ node.treeParent.addChild(commentBefore.clone() as ASTNode, node)
+ node.treeParent.addChild(PsiWhiteSpaceImpl("\n"), node)
+ }
braceSpace.treeParent.replaceWhiteSpaceText(braceSpace, " ")
}
}
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt
index 7148055352..d84fb58c48 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt
@@ -71,6 +71,7 @@ class DiktatRuleSetProvider(private val diktatConfigFile: String = "diktat-analy
::BracesInConditionalsAndLoopsRule,
::BlockStructureBraces,
::EmptyBlock,
+ ::AvoidEmptyPrimaryConstructor,
::EnumsSeparated,
::SingleLineStatementsRule,
::MultipleModifiersSequence,
@@ -78,6 +79,7 @@ class DiktatRuleSetProvider(private val diktatConfigFile: String = "diktat-analy
::CustomGetterSetterRule,
::CompactInitialization,
// other rules
+ ::ImplicitBackingPropertyRule,
::StringTemplateFormatRule,
::DataClassesRule,
::LocalVariablesRule,
@@ -107,10 +109,10 @@ class DiktatRuleSetProvider(private val diktatConfigFile: String = "diktat-analy
::ExtensionFunctionsSameNameRule,
// formatting: moving blocks, adding line breaks, indentations etc.
::ConsecutiveSpacesRule,
- ::WhiteSpaceRule, // this rule should be after other rules that can cause wrong spacing
::HeaderCommentRule,
::FileStructureRule, // this rule should be right before indentation because it should operate on already valid code
::NewlinesRule, // newlines need to be inserted right before fixing indentation
+ ::WhiteSpaceRule, // this rule should be after other rules that can cause wrong spacing
::IndentationRule // indentation rule should be the last because it fixes formatting after all the changes done by previous rules
)
.map {
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/FunctionLength.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/FunctionLength.kt
index 5e42246e18..f1a5a4bc22 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/FunctionLength.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/FunctionLength.kt
@@ -1,10 +1,7 @@
package org.cqfn.diktat.ruleset.rules
import com.pinterest.ktlint.core.Rule
-import com.pinterest.ktlint.core.ast.ElementType.BLOCK_COMMENT
-import com.pinterest.ktlint.core.ast.ElementType.EOL_COMMENT
import com.pinterest.ktlint.core.ast.ElementType.FUN
-import com.pinterest.ktlint.core.ast.ElementType.KDOC
import org.cqfn.diktat.common.config.rules.RuleConfiguration
import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.common.config.rules.getRuleConfig
@@ -19,7 +16,6 @@ import org.jetbrains.kotlin.psi.KtFunction
class FunctionLength(private val configRules: List) : Rule("function-length") {
companion object {
- val FUNCTION_ALLOW_COMMENT = listOf(EOL_COMMENT, KDOC, BLOCK_COMMENT)
private const val MAX_FUNCTION_LENGTH = 30L
}
@@ -47,7 +43,7 @@ class FunctionLength(private val configRules: List) : Rule("functio
} else {
((node.psi as KtFunction).bodyExpression?.node?.clone() ?: return) as ASTNode
}
- copyNode.findAllNodesWithCondition({ it.elementType in FUNCTION_ALLOW_COMMENT }).forEach { it.treeParent.removeChild(it) }
+ copyNode.findAllNodesWithCondition({ it.elementType in COMMENT_TYPE }).forEach { it.treeParent.removeChild(it) }
val functionText = copyNode.text.lines().filter { it.isNotBlank() }
if (functionText.size > configuration.maxFunctionLength)
TOO_LONG_FUNCTION.warn(configRules, emitWarn, isFixMode,
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/ImplicitBackingPropertyRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/ImplicitBackingPropertyRule.kt
new file mode 100644
index 0000000000..2677036941
--- /dev/null
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/ImplicitBackingPropertyRule.kt
@@ -0,0 +1,110 @@
+package org.cqfn.diktat.ruleset.rules
+
+import com.pinterest.ktlint.core.Rule
+import com.pinterest.ktlint.core.ast.ElementType.BLOCK
+import com.pinterest.ktlint.core.ast.ElementType.CLASS_BODY
+import com.pinterest.ktlint.core.ast.ElementType.DOT_QUALIFIED_EXPRESSION
+import com.pinterest.ktlint.core.ast.ElementType.FILE
+import com.pinterest.ktlint.core.ast.ElementType.GET_KEYWORD
+import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER
+import com.pinterest.ktlint.core.ast.ElementType.PROPERTY
+import com.pinterest.ktlint.core.ast.ElementType.PROPERTY_ACCESSOR
+import com.pinterest.ktlint.core.ast.ElementType.REFERENCE_EXPRESSION
+import com.pinterest.ktlint.core.ast.ElementType.RETURN
+import com.pinterest.ktlint.core.ast.ElementType.SET_KEYWORD
+import com.pinterest.ktlint.core.ast.ElementType.VALUE_PARAMETER
+import org.cqfn.diktat.common.config.rules.RulesConfig
+import org.cqfn.diktat.ruleset.constants.Warnings.NO_CORRESPONDING_PROPERTY
+import org.cqfn.diktat.ruleset.utils.findAllNodesWithSpecificType
+import org.cqfn.diktat.ruleset.utils.getFirstChildWithType
+import org.cqfn.diktat.ruleset.utils.getIdentifierName
+import org.cqfn.diktat.ruleset.utils.hasAnyChildOfTypes
+import org.cqfn.diktat.ruleset.utils.hasChildOfType
+import org.cqfn.diktat.ruleset.utils.prettyPrint
+import org.jetbrains.kotlin.com.intellij.lang.ASTNode
+import org.jetbrains.kotlin.psi.KtProperty
+
+/**
+ * This rule checks if there is a backing property for field with property accessors, in case they don't use field keyword
+ */
+class ImplicitBackingPropertyRule(private val configRules: List) : Rule("implicit-backing-property") {
+ private lateinit var emitWarn: ((offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit)
+ private var isFixMode: Boolean = false
+
+ override fun visit(node: ASTNode,
+ autoCorrect: Boolean,
+ emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) {
+ emitWarn = emit
+ isFixMode = autoCorrect
+
+ if (node.elementType == CLASS_BODY) {
+ findAllProperties(node)
+ }
+ }
+
+ @Suppress("UnsafeCallOnNullableType")
+ private fun findAllProperties(node: ASTNode) {
+ val properties = node.getChildren(null).filter { it.elementType == PROPERTY }
+
+ val propsWithBackSymbol = properties
+ .filter { it.getFirstChildWithType(IDENTIFIER)!!.text.startsWith("_") }
+ .map {
+ it.getFirstChildWithType(IDENTIFIER)!!.text
+ }
+
+ properties.filter { it.hasAnyChildOfTypes(PROPERTY_ACCESSOR) }.forEach {
+ validateAccessors(it, propsWithBackSymbol)
+ }
+ }
+
+ private fun validateAccessors(node: ASTNode, propsWithBackSymbol: List) {
+ val accessors = node.findAllNodesWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) } // exclude get with expression body
+
+ accessors.filter { it.hasChildOfType(GET_KEYWORD) }.forEach { handleGetAccessors(it, node, propsWithBackSymbol) }
+ accessors.filter { it.hasChildOfType(SET_KEYWORD) }.forEach { handleSetAccessors(it, node, propsWithBackSymbol) }
+ }
+
+ @Suppress("UnsafeCallOnNullableType")
+ private fun handleGetAccessors(accessor: ASTNode, node: ASTNode, propsWithBackSymbol: List) {
+ val refExprs = accessor
+ .findAllNodesWithSpecificType(RETURN)
+ .filterNot { it.hasChildOfType(DOT_QUALIFIED_EXPRESSION) }
+ .flatMap { it.findAllNodesWithSpecificType(REFERENCE_EXPRESSION) }
+
+ val localProps = accessor
+ .findAllNodesWithSpecificType(PROPERTY)
+ .map { (it.psi as KtProperty).name!! }
+ // If refExprs is empty then we assume that it returns some constant
+ if (refExprs.isNotEmpty()) {
+ handleReferenceExpressions(node, refExprs, propsWithBackSymbol, localProps)
+ }
+ }
+
+ @Suppress("UnsafeCallOnNullableType")
+ private fun handleSetAccessors(accessor: ASTNode, node: ASTNode, propsWithBackSymbol: List) {
+ val refExprs = accessor.findAllNodesWithSpecificType(REFERENCE_EXPRESSION)
+
+ // In set we don't check for local properties. At least one reference expression should contain field or _prop
+ if (refExprs.isNotEmpty()) {
+ handleReferenceExpressions(node, refExprs, propsWithBackSymbol, null)
+ }
+ }
+
+ @Suppress("UnsafeCallOnNullableType")
+ private fun handleReferenceExpressions(node: ASTNode,
+ expressions: List,
+ backingPropertiesNames: List,
+ localProperties: List?) {
+ if (expressions.none {
+ backingPropertiesNames.contains(it.text) || it.text == "field" || localProperties?.contains(it.text) == true
+ }) {
+ raiseWarning(node, node.getFirstChildWithType(IDENTIFIER)!!.text)
+ }
+ }
+
+ private fun raiseWarning(node: ASTNode, propName: String) {
+ NO_CORRESPONDING_PROPERTY.warn(configRules, emitWarn, isFixMode,
+ "$propName has no corresponding property with name _$propName", node.startOffset, node)
+ }
+
+}
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/NullChecksRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/NullChecksRule.kt
index dc31c9d782..d4ea4ea891 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/NullChecksRule.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/NullChecksRule.kt
@@ -6,6 +6,7 @@ import com.pinterest.ktlint.core.ast.ElementType
import com.pinterest.ktlint.core.ast.ElementType.BINARY_EXPRESSION
import com.pinterest.ktlint.core.ast.ElementType.CONDITION
import com.pinterest.ktlint.core.ast.ElementType.IF
+import com.pinterest.ktlint.core.ast.ElementType.IF_KEYWORD
import com.pinterest.ktlint.core.ast.ElementType.NULL
import com.pinterest.ktlint.core.ast.parent
import org.cqfn.diktat.common.config.rules.RulesConfig
@@ -13,6 +14,7 @@ import org.cqfn.diktat.ruleset.constants.Warnings.AVOID_NULL_CHECKS
import org.cqfn.diktat.ruleset.utils.*
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.psi.KtBinaryExpression
+import org.jetbrains.kotlin.psi.KtIfExpression
/**
* This rule check and fixes explicit null checks (explicit comparison with `null`)
@@ -30,8 +32,11 @@ class NullChecksRule(private val configRules: List) : Rule("null-ch
if (node.elementType == CONDITION) {
node.parent(IF)?.let {
- // this can be autofixed as the condition stays in if-statement
- conditionInIfStatement(node)
+ // excluding complex cases with else-if statements, because they look better with explicit null-check
+ if (!isComplexIfStatement(it)) {
+ // this can be autofixed as the condition stays in simple if-statement
+ conditionInIfStatement(node)
+ }
}
}
@@ -44,6 +49,16 @@ class NullChecksRule(private val configRules: List) : Rule("null-ch
}
}
+ /**
+ * checks that if-statement is a complex condition
+ * You can name a statement - "complex if-statement" if it has other if in the else branch (else-if structure)
+ */
+ private fun isComplexIfStatement(parentIf: ASTNode): Boolean {
+ val parentIfPsi = parentIf.psi
+ require(parentIfPsi is KtIfExpression)
+ return (parentIfPsi.`else`?.node?.firstChildNode?.elementType == IF_KEYWORD)
+ }
+
private fun conditionInIfStatement(node: ASTNode) {
node.findAllNodesWithSpecificType(BINARY_EXPRESSION).forEach { binaryExprNode ->
val condition = (binaryExprNode.psi as KtBinaryExpression)
@@ -69,11 +84,21 @@ class NullChecksRule(private val configRules: List) : Rule("null-ch
@Suppress("UnsafeCallOnNullableType")
private fun isNullCheckBinaryExpession(condition: KtBinaryExpression): Boolean =
- // check that binary expession has `null` as right or left operand
- setOf(condition.right, condition.left).map { it!!.node.elementType }.contains(NULL) &&
- // checks that it is the comparison condition
- setOf(ElementType.EQEQ, ElementType.EQEQEQ, ElementType.EXCLEQ, ElementType.EXCLEQEQEQ).contains(condition.operationToken)
+ // check that binary expession has `null` as right or left operand
+ setOf(condition.right, condition.left).map { it!!.node.elementType }.contains(NULL) &&
+ // checks that it is the comparison condition
+ setOf(ElementType.EQEQ, ElementType.EQEQEQ, ElementType.EXCLEQ, ElementType.EXCLEQEQEQ).contains(condition.operationToken) &&
+ // no need to raise warning or fix null checks in complex expressions
+ !condition.isComplexCondition()
+ /**
+ * checks if condition is a complex expression. For example:
+ * (a == 5) - is not a complex condition, but (a == 5 && b != 6) is a complex condition
+ */
+ private fun KtBinaryExpression.isComplexCondition(): Boolean {
+ // KtBinaryExpression is complex if it has a parent that is also a binary expression
+ return this.parent is KtBinaryExpression
+ }
private fun warnAndFixOnNullCheck(condition: KtBinaryExpression, canBeAutoFixed: Boolean, autofix: () -> Unit) {
AVOID_NULL_CHECKS.warnAndFix(
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/PackageNaming.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/PackageNaming.kt
index 3c47a097ae..e33625edb1 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/PackageNaming.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/PackageNaming.kt
@@ -16,7 +16,6 @@ import org.cqfn.diktat.ruleset.constants.Warnings.PACKAGE_NAME_INCORRECT_PREFIX
import org.cqfn.diktat.ruleset.constants.Warnings.PACKAGE_NAME_INCORRECT_SYMBOLS
import org.cqfn.diktat.ruleset.constants.Warnings.PACKAGE_NAME_MISSING
import org.cqfn.diktat.ruleset.utils.*
-import org.jetbrains.kotlin.backend.common.onlyIf
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl
@@ -44,8 +43,10 @@ class PackageNaming(private val configRules: List) : Rule("package-
emitWarn = emit
val configuration by configRules.getCommonConfiguration()
- domainName = configuration.onlyIf({ isDefault }) {
- log.error("Not able to find an external configuration for domain name in the common configuration (is it missing in yml config?)")
+ domainName = configuration.also {
+ if (it.isDefault) {
+ log.error("Not able to find an external configuration for domain name in the common configuration (is it missing in yml config?)")
+ }
}
.domainName
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/classes/SingleInitRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/classes/SingleInitRule.kt
index 43c4f5d7bd..256c8760c2 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/classes/SingleInitRule.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/classes/SingleInitRule.kt
@@ -12,7 +12,6 @@ import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.ruleset.constants.Warnings
import org.cqfn.diktat.ruleset.utils.getAllChildrenWithType
import org.cqfn.diktat.ruleset.utils.getIdentifierName
-import org.jetbrains.kotlin.backend.common.onlyIf
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl
@@ -44,7 +43,8 @@ class SingleInitRule(private val configRule: List) : Rule("multiple
node.children()
.filter { it.elementType == CLASS_INITIALIZER }
.toList()
- .onlyIf({ size > 1 }) { initBlocks ->
+ .takeIf { it.size > 1 }
+ ?.let { initBlocks ->
val className = node.treeParent.getIdentifierName()?.text
Warnings.MULTIPLE_INIT_BLOCKS.warnAndFix(configRule, emitWarn, isFixMode,
"in class <$className> found ${initBlocks.size} `init` blocks", node.startOffset, node) {
@@ -97,7 +97,8 @@ class SingleInitRule(private val configRule: List) : Rule("multiple
.filter { (property, assignments) ->
!(property.psi as KtProperty).hasBody() && assignments.size == 1
}
- .onlyIf({ isNotEmpty() }) {
+ .takeIf { it.isNotEmpty() }
+ ?.let {
Warnings.MULTIPLE_INIT_BLOCKS.warnAndFix(configRule, emitWarn, isFixMode,
"`init` block has assignments that can be moved to declarations", initBlock.startOffset, initBlock
) {
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/files/BlankLinesRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/files/BlankLinesRule.kt
index f5f6c22260..023da07666 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/files/BlankLinesRule.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/files/BlankLinesRule.kt
@@ -3,11 +3,16 @@ package org.cqfn.diktat.ruleset.rules.files
import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType.BLOCK
import com.pinterest.ktlint.core.ast.ElementType.CLASS_BODY
+import com.pinterest.ktlint.core.ast.ElementType.FILE
+import com.pinterest.ktlint.core.ast.ElementType.FUNCTION_LITERAL
+import com.pinterest.ktlint.core.ast.ElementType.LAMBDA_EXPRESSION
import com.pinterest.ktlint.core.ast.ElementType.LBRACE
import com.pinterest.ktlint.core.ast.ElementType.RBRACE
import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE
import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.ruleset.constants.Warnings.TOO_MANY_BLANK_LINES
+import org.cqfn.diktat.ruleset.utils.findAllNodesWithSpecificType
+import org.cqfn.diktat.ruleset.utils.getFirstChildWithType
import org.cqfn.diktat.ruleset.utils.leaveExactlyNumNewLines
import org.cqfn.diktat.ruleset.utils.leaveOnlyOneNewLine
import org.cqfn.diktat.ruleset.utils.numNewLines
@@ -39,7 +44,7 @@ class BlankLinesRule(private val configRules: List) : Rule("blank-l
}
private fun handleBlankLine(node: ASTNode) {
- if (node.treeParent.elementType.let { it == BLOCK || it == CLASS_BODY }) {
+ if (node.treeParent.elementType.let { it == BLOCK || it == CLASS_BODY || it == FUNCTION_LITERAL }) {
if ((node.treeNext.elementType == RBRACE) xor (node.treePrev.elementType == LBRACE)) {
// if both are present, this is not beginning or end
// if both are null, then this block is empty and is handled in another rule
@@ -53,7 +58,10 @@ class BlankLinesRule(private val configRules: List) : Rule("blank-l
private fun handleTooManyBlankLines(node: ASTNode) {
TOO_MANY_BLANK_LINES.warnAndFix(configRules, emitWarn, isFixMode, "do not use more than two consecutive blank lines", node.startOffset, node) {
- node.leaveExactlyNumNewLines(2)
+ if (node.treeParent.elementType != FILE && node.treeParent.getFirstChildWithType(WHITE_SPACE) == node)
+ node.leaveExactlyNumNewLines(1)
+ else
+ node.leaveExactlyNumNewLines(2)
}
}
}
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/files/NewlinesRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/files/NewlinesRule.kt
index 70b34eed57..2b54696df0 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/files/NewlinesRule.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/files/NewlinesRule.kt
@@ -70,7 +70,6 @@ import org.cqfn.diktat.ruleset.utils.isFollowedByNewline
import org.cqfn.diktat.ruleset.utils.isSingleLineIfElse
import org.cqfn.diktat.ruleset.utils.leaveOnlyOneNewLine
import org.cqfn.diktat.ruleset.utils.log
-import org.jetbrains.kotlin.backend.common.onlyIf
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.PsiElement
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
@@ -298,7 +297,7 @@ class NewlinesRule(private val configRules: List) : Rule("newlines"
val colon = funNode.findChildByType(COLON)!!
val expression = node.findChildByType(RETURN_KEYWORD)!!.nextCodeSibling()!!
funNode.apply {
- removeRange(colon, null)
+ removeRange(if (colon.treePrev.elementType == WHITE_SPACE) colon.treePrev else colon, null)
addChild(PsiWhiteSpaceImpl(" "), null)
addChild(LeafPsiElement(EQ, "="), null)
addChild(PsiWhiteSpaceImpl(" "), null)
@@ -340,7 +339,8 @@ class NewlinesRule(private val configRules: List) : Rule("newlines"
.takeWhile { !it.textContains('\n') }
.filter { it.elementType == VALUE_PARAMETER }
.toList()
- .onlyIf({ size > 1 }) {
+ .takeIf { it.size > 1 }
+ ?.let {
WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode, "first parameter should be placed on a separate line " +
"or all other parameters should be aligned with it in declaration of <${node.getParentIdentifier()}>", node.startOffset, node) {
node.appendNewlineMergingWhiteSpace(it.first().treePrev.takeIf { it.elementType == WHITE_SPACE }, it.first())
@@ -354,7 +354,8 @@ class NewlinesRule(private val configRules: List) : Rule("newlines"
!it.treeNext.run { elementType == WHITE_SPACE && textContains('\n') }
}
.toList()
- .onlyIf({ isNotEmpty() }) { invalidCommas ->
+ .takeIf { it.isNotEmpty() }
+ ?.let { invalidCommas ->
WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode,
"$entryType should be placed on different lines in declaration of <${node.getParentIdentifier()}>", node.startOffset, node) {
invalidCommas.forEach { comma ->
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/CommentsFormatting.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/CommentsFormatting.kt
index d504b340d4..300f43a53e 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/CommentsFormatting.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/CommentsFormatting.kt
@@ -54,7 +54,6 @@ class CommentsFormatting(private val configRules: List) : Rule("kdo
companion object {
private const val APPROPRIATE_COMMENT_SPACES = 1
private const val MAX_SPACES = 1
- private val COMMENT_TYPE = listOf(EOL_COMMENT, KDOC, BLOCK_COMMENT)
}
private var isFixMode: Boolean = false
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/KdocComments.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/KdocComments.kt
index 53a5615673..7b10ba4cb1 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/KdocComments.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/KdocComments.kt
@@ -41,11 +41,13 @@ import org.cqfn.diktat.ruleset.constants.Warnings.KDOC_NO_CONSTRUCTOR_PROPERTY
import org.cqfn.diktat.ruleset.constants.Warnings.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT
import org.cqfn.diktat.ruleset.constants.Warnings.MISSING_KDOC_TOP_LEVEL
import org.cqfn.diktat.ruleset.constants.Warnings.MISSING_KDOC_CLASS_ELEMENTS
+import org.cqfn.diktat.ruleset.utils.isOverridden
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
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.TokenSet
import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
+import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.psiUtil.parents
/**
@@ -159,12 +161,14 @@ class KdocComments(private val configRules: List) : Rule("kdoc-comm
@Suppress("UnsafeCallOnNullableType")
private fun createKdocBasicKdoc(node: ASTNode) {
- KDOC_NO_CONSTRUCTOR_PROPERTY.warnAndFix(configRules, emitWarn, isFixMode,
- "add <${node.findChildByType(IDENTIFIER)!!.text}> to KDoc", node.startOffset, node) {
- val newKdoc = KotlinParser().createNode("/**\n * @property ${node.findChildByType(IDENTIFIER)!!.text}\n */")
- val classNode = node.parent({ it.elementType == CLASS })!!
- classNode.addChild(PsiWhiteSpaceImpl("\n"), classNode.firstChildNode)
- classNode.addChild(newKdoc.findChildByType(KDOC)!!, classNode.firstChildNode)
+ if (node.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside()) {
+ KDOC_NO_CONSTRUCTOR_PROPERTY.warnAndFix(configRules, emitWarn, isFixMode,
+ "add <${node.findChildByType(IDENTIFIER)!!.text}> to KDoc", node.startOffset, node) {
+ val newKdoc = KotlinParser().createNode("/**\n * @property ${node.findChildByType(IDENTIFIER)!!.text}\n */")
+ val classNode = node.parent({ it.elementType == CLASS })!!
+ classNode.addChild(PsiWhiteSpaceImpl("\n"), classNode.firstChildNode)
+ classNode.addChild(newKdoc.findChildByType(KDOC)!!, classNode.firstChildNode)
+ }
}
}
@@ -259,7 +263,10 @@ class KdocComments(private val configRules: List) : Rule("kdoc-comm
if (classBody != null && modifier.isAccessibleOutside()) {
classBody
.getChildren(statementsToDocument)
- .filterNot { it.elementType == FUN && it.isStandardMethod() }
+ .filterNot { (it.elementType == FUN && it.isStandardMethod())
+ || (it.elementType == FUN && it.isOverridden())
+ || (it.elementType == PROPERTY && it.isOverridden())
+ }
.forEach { checkDoc(it, MISSING_KDOC_CLASS_ELEMENTS) }
}
}
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/KdocFormatting.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/KdocFormatting.kt
index 1cbf3bd793..77e036eb4d 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/KdocFormatting.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/KdocFormatting.kt
@@ -76,8 +76,6 @@ class KdocFormatting(private val configRules: List) : Rule("kdoc-fo
emitWarn = emit
fileName = node.getRootNode().getFileName()
- val declarationTypes = setOf(CLASS, FUN, PROPERTY)
-
if (node.elementType == KDOC && isKdocNotEmpty(node)) {
checkNoDeprecatedTag(node)
checkEmptyTags(node.kDocTags())
@@ -278,7 +276,7 @@ class KdocFormatting(private val configRules: List) : Rule("kdoc-fo
}
}
- @Suppress("UnsafeCallOnNullableType", "TOO_LONG_FUNCTION")
+ @Suppress("UnsafeCallOnNullableType", "TOO_LONG_FUNCTION", "ComplexMethod")
private fun checkNewLineAfterSpecialTags(node: ASTNode) {
val presentSpecialTagNodes = node
.getFirstChildWithType(KDOC_SECTION)
@@ -304,13 +302,13 @@ class KdocFormatting(private val configRules: List) : Rule("kdoc-fo
node.removeChild(node.lastChildNode) // KDOC_LEADING_ASTERISK
node.removeChild(node.lastChildNode) // WHITE_SPACE
}
- if (node.lastChildNode.elementType != KDOC_LEADING_ASTERISK) {
+ if (node.treeParent.lastChildNode != node && node.lastChildNode.elementType != KDOC_LEADING_ASTERISK) {
val indent = node
.prevSibling { it.elementType == WHITE_SPACE }
?.text
?.substringAfter('\n')
?.count { it == ' ' } ?: 0
- node.addChild(LeafPsiElement(WHITE_SPACE, "\n${" ".repeat(indent)}"), null)
+ node.addChild(PsiWhiteSpaceImpl("\n${" ".repeat(indent)}"), null)
node.addChild(LeafPsiElement(KDOC_LEADING_ASTERISK, "*"), null)
}
}
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/ASTConstants.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/ASTConstants.kt
index 1d4c8c40cf..cb7876db6c 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/ASTConstants.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/ASTConstants.kt
@@ -1,7 +1,12 @@
package org.cqfn.diktat.ruleset.utils
+import com.pinterest.ktlint.core.ast.ElementType
+import com.pinterest.ktlint.core.ast.ElementType.BLOCK_COMMENT
+import com.pinterest.ktlint.core.ast.ElementType.EOL_COMMENT
+import com.pinterest.ktlint.core.ast.ElementType.KDOC
import com.pinterest.ktlint.core.ast.ElementType.LBRACE
import com.pinterest.ktlint.core.ast.ElementType.RBRACE
+import com.pinterest.ktlint.core.ast.ElementType.SEMICOLON
import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE
/**
@@ -15,7 +20,9 @@ internal const val SET_PREFIX = "set"
/**
* List of element types present in empty code block `{ }`
*/
-val emptyBlockList = listOf(LBRACE, WHITE_SPACE, RBRACE)
+val emptyBlockList = listOf(LBRACE, WHITE_SPACE, SEMICOLON, RBRACE)
+
+val COMMENT_TYPE = listOf(BLOCK_COMMENT, EOL_COMMENT, KDOC)
internal const val EMPTY_BLOCK_TEXT = "{}"
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/FunctonASTNodeUtils.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/FunctonASTNodeUtils.kt
index 0fe4cd741b..562a31638d 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/FunctonASTNodeUtils.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/FunctonASTNodeUtils.kt
@@ -6,6 +6,7 @@ import com.pinterest.ktlint.core.ast.ElementType.BLOCK
import com.pinterest.ktlint.core.ast.ElementType.CONSTRUCTOR_CALLEE
import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER
import com.pinterest.ktlint.core.ast.ElementType.MODIFIER_LIST
+import com.pinterest.ktlint.core.ast.ElementType.OVERRIDE_KEYWORD
import org.cqfn.diktat.ruleset.rules.PackageNaming.Companion.PACKAGE_PATH_ANCHOR
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.psi.KtFunction
@@ -57,6 +58,12 @@ fun ASTNode.isStandardMethod() = also(::checkNodeIsFun)
?.let { it.text in STANDARD_METHODS }
?: false
+
+fun ASTNode.isOverridden() : Boolean =
+ getFirstChildWithType(MODIFIER_LIST)
+ ?.hasChildOfType(OVERRIDE_KEYWORD) ?: false
+
+
private fun ASTNode.argList(): ASTNode? {
checkNodeIsFun(this)
return this.getFirstChildWithType(ElementType.VALUE_PARAMETER_LIST)
diff --git a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml
index 6a09997c0d..abacac11c0 100644
--- a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml
+++ b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml
@@ -296,3 +296,11 @@
# Checks if extension function with the same signature don't have related classes
- name: EXTENSION_FUNCTION_SAME_SIGNATURE
enabled: true
+# Checks if there is empty primary constructor
+- name: EMPTY_PRIMARY_CONSTRUCTOR
+ enabled: true
+# In case of not using field keyword in property accessors,
+# there should be explicit backing property with the name of real property
+# Example: val table get() {if (_table == null) ...} -> table should have _table
+- name: NO_CORRESPONDING_PROPERTY
+ enabled: true
\ No newline at end of file
diff --git a/diktat-rules/src/main/resources/diktat-analysis.yml b/diktat-rules/src/main/resources/diktat-analysis.yml
index 17d166c0b1..385c80565e 100644
--- a/diktat-rules/src/main/resources/diktat-analysis.yml
+++ b/diktat-rules/src/main/resources/diktat-analysis.yml
@@ -298,3 +298,11 @@
# Checks if extension function with the same signature don't have related classes
- name: EXTENSION_FUNCTION_SAME_SIGNATURE
enabled: true
+# Checks if there is empty primary constructor
+- name: EMPTY_PRIMARY_CONSTRUCTOR
+ enabled: true
+# In case of not using field keyword in property accessors,
+# there should be explicit backing property with the name of real property
+# Example: val table get() {if (_table == null) ...} -> table should have _table
+- name: NO_CORRESPONDING_PROPERTY
+ enabled: true
\ No newline at end of file
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocCommentsWarnTest.kt
similarity index 90%
rename from diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocWarnTest.kt
rename to diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocCommentsWarnTest.kt
index a8d18e0799..47745b69a8 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocWarnTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocCommentsWarnTest.kt
@@ -10,7 +10,7 @@ import org.cqfn.diktat.util.LintTestBase
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Tags
-class KdocWarnTest : LintTestBase(::KdocComments) {
+class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
private val ruleId: String = "$DIKTAT_RULE_SET_ID:kdoc-comments"
@Test
@@ -129,6 +129,40 @@ class KdocWarnTest : LintTestBase(::KdocComments) {
)
}
+ @Test
+ @Tag(WarningNames.MISSING_KDOC_CLASS_ELEMENTS)
+ fun `Kdoc shouldn't not be mandatory for overridden functions and props`() {
+ val code =
+ """
+ /**
+ * class that contains fields, functions and public subclasses
+ **/
+ class SomeGoodName : Another {
+ val variable: String = ""
+ private val privateVariable: String = ""
+ override val someVal: String = ""
+ fun perfectFunction() {
+ }
+
+ override fun overrideFunction() {
+ }
+
+ class InternalClass {
+ }
+
+ private class InternalClass {
+ }
+
+ public fun main() {}
+ }
+ """.trimIndent()
+ lintMethod(code,
+ LintError(5, 5, ruleId, "${MISSING_KDOC_CLASS_ELEMENTS.warnText()} variable"),
+ LintError(8, 5, ruleId, "${MISSING_KDOC_CLASS_ELEMENTS.warnText()} perfectFunction"),
+ LintError(14, 5, ruleId, "${MISSING_KDOC_CLASS_ELEMENTS.warnText()} InternalClass")
+ )
+ }
+
@Test
@Tag(WarningNames.MISSING_KDOC_CLASS_ELEMENTS)
fun `Kdoc shouldn't present for each class element because Test annotation`() {
@@ -398,8 +432,7 @@ class KdocWarnTest : LintTestBase(::KdocComments) {
|}
""".trimMargin(),
LintError(1, 1, ruleId, "${MISSING_KDOC_TOP_LEVEL.warnText()} Example"),
- LintError(2, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add to KDoc", true),
- LintError(3, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add to KDoc", true)
+ LintError(2, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add to KDoc", true)
)
}
}
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LocalVariablesWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LocalVariablesWarnTest.kt
index 9de6f71e15..2b9d8a6136 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LocalVariablesWarnTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LocalVariablesWarnTest.kt
@@ -549,4 +549,24 @@ class LocalVariablesWarnTest : LintTestBase(::LocalVariablesRule) {
""".trimMargin()
)
}
+
+ @Test
+ @Tag(WarningNames.LOCAL_VARIABLE_EARLY_DECLARATION)
+ fun `should not trigger on triple quoted strings`() {
+ lintMethod(
+ """
+ |class Example {
+ | fun some() {
+ | val code = ${"\"\"\""}
+ | class Some {
+ | fun for() : String {
+ | }
+ | }
+ | ${"\"\"\""}.trimIndent()
+ | bar(code)
+ | }
+ |}
+ """.trimMargin()
+ )
+ }
}
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/NewlinesRuleFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/NewlinesRuleFixTest.kt
index cf2062db62..7ba385f029 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/NewlinesRuleFixTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/NewlinesRuleFixTest.kt
@@ -54,4 +54,10 @@ class NewlinesRuleFixTest : FixTestBase("test/paragraph3/newlines", ::NewlinesRu
fun `should insert newlines in a long parameter or supertype list`() {
fixAndCompare("ParameterListExpected.kt", "ParameterListTest.kt")
}
+
+ @Test
+ @Tag(WarningNames.WRONG_NEWLINES)
+ fun `should fix one line function with and without semicolon`() {
+ fixAndCompare("OneLineFunctionExpected.kt", "OneLineFunctionTest.kt")
+ }
}
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter4/NullChecksRuleWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter4/NullChecksRuleWarnTest.kt
index 0cd9ebc139..c34596ea5b 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter4/NullChecksRuleWarnTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter4/NullChecksRuleWarnTest.kt
@@ -37,7 +37,7 @@ class NullChecksRuleWarnTest : LintTestBase(::NullChecksRule) {
"""
| fun foo() {
| var myVar: Int? = null
- | if ((myVar == null) && (true)) {
+ | if ((myVar == null) && (true) || isValid) {
| println("null")
| return
| }
@@ -116,4 +116,55 @@ class NullChecksRuleWarnTest : LintTestBase(::NullChecksRule) {
LintError(5, 19, ruleId, "${Warnings.AVOID_NULL_CHECKS.warnText()} myVar == null", false),
)
}
+
+ @Test
+ @Tag(WarningNames.AVOID_NULL_CHECKS)
+ fun `equals to null, but in complex else-if statement`() {
+ lintMethod(
+ """
+ | fun foo0() {
+ | if (myVar != null) {
+ | println("not null")
+ | } else if (true) {
+ | println()
+ | }
+ | }
+ """.trimMargin()
+ )
+ }
+
+ @Test
+ @Tag(WarningNames.AVOID_NULL_CHECKS)
+ fun `equals to null, but in complex else-if statement with dummy comment`() {
+ lintMethod(
+ """
+ | fun foo0() {
+ | if (myVar != null) {
+ | println("not null")
+ | } else /* test comment */ if (true) {
+ | println()
+ | }
+ | }
+ """.trimMargin()
+ )
+ }
+
+ @Test
+ @Tag(WarningNames.AVOID_NULL_CHECKS)
+ fun `equals to null, but the expression is not a else-if`() {
+ lintMethod(
+ """
+ | fun foo0() {
+ | if (myVar != null) {
+ | println("not null")
+ | } else {
+ | if (true) {
+ | println()
+ | }
+ | }
+ | }
+ """.trimMargin(),
+ LintError(2, 10, ruleId, "${Warnings.AVOID_NULL_CHECKS.warnText()} myVar != null", true),
+ )
+ }
}
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/EmptyPrimaryConstructorFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/EmptyPrimaryConstructorFixTest.kt
new file mode 100644
index 0000000000..2498d08324
--- /dev/null
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/EmptyPrimaryConstructorFixTest.kt
@@ -0,0 +1,16 @@
+package org.cqfn.diktat.ruleset.chapter6
+
+import generated.WarningNames
+import org.cqfn.diktat.ruleset.rules.AvoidEmptyPrimaryConstructor
+import org.cqfn.diktat.util.FixTestBase
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+class EmptyPrimaryConstructorFixTest: FixTestBase("test/chapter6/primary_constructor", ::AvoidEmptyPrimaryConstructor) {
+
+ @Test
+ @Tag(WarningNames.EMPTY_PRIMARY_CONSTRUCTOR)
+ fun `should remove empty primary constructor`() {
+ fixAndCompare("EmptyPCExpected.kt", "EmptyPCTest.kt")
+ }
+}
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/EmptyPrimaryConstructorWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/EmptyPrimaryConstructorWarnTest.kt
new file mode 100644
index 0000000000..ec2e7d244c
--- /dev/null
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/EmptyPrimaryConstructorWarnTest.kt
@@ -0,0 +1,62 @@
+package org.cqfn.diktat.ruleset.chapter6
+
+import com.pinterest.ktlint.core.LintError
+import generated.WarningNames
+import org.cqfn.diktat.ruleset.constants.Warnings.EMPTY_PRIMARY_CONSTRUCTOR
+import org.cqfn.diktat.ruleset.rules.AvoidEmptyPrimaryConstructor
+import org.cqfn.diktat.ruleset.rules.DIKTAT_RULE_SET_ID
+import org.cqfn.diktat.util.LintTestBase
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+class EmptyPrimaryConstructorWarnTest: LintTestBase(::AvoidEmptyPrimaryConstructor) {
+ private val ruleId = "$DIKTAT_RULE_SET_ID:avoid-empty-primary-constructor"
+
+ @Test
+ @Tag(WarningNames.EMPTY_PRIMARY_CONSTRUCTOR)
+ fun `simple classes with empty primary constructor`() {
+ lintMethod(
+ """
+ |class Some() {
+ | val a = 10
+ | constructor(a: String): this() {
+ | this.a = a
+ | }
+ |}
+ |
+ |class Some1() {
+ | val a = 10
+ | companion object {}
+ |}
+ |
+ |class Some2 {
+ | val a = 10
+ | constructor(a: String): this() {
+ | this.a = a
+ | }
+ |}
+ |
+ |class Some3 private constructor () {
+ |
+ |}
+ """.trimMargin(),
+ LintError(1,1,ruleId, "${EMPTY_PRIMARY_CONSTRUCTOR.warnText()} Some", true),
+ LintError(8,1,ruleId, "${EMPTY_PRIMARY_CONSTRUCTOR.warnText()} Some1", true)
+ )
+ }
+
+ @Test
+ @Tag(WarningNames.EMPTY_PRIMARY_CONSTRUCTOR)
+ fun `correct example with empty primary constructor and modifiers`() {
+ lintMethod(
+ """
+ |class Some1 private constructor () {
+ |
+ |}
+ |
+ |class Some2 @Inject constructor() {
+ |}
+ """.trimMargin()
+ )
+ }
+}
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/ImplicitBackingPropertyWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/ImplicitBackingPropertyWarnTest.kt
new file mode 100644
index 0000000000..54cc0cf0b2
--- /dev/null
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/ImplicitBackingPropertyWarnTest.kt
@@ -0,0 +1,165 @@
+package org.cqfn.diktat.ruleset.chapter6
+
+import com.pinterest.ktlint.core.LintError
+import generated.WarningNames.NO_CORRESPONDING_PROPERTY
+import org.cqfn.diktat.ruleset.constants.Warnings
+import org.cqfn.diktat.ruleset.rules.DIKTAT_RULE_SET_ID
+import org.cqfn.diktat.ruleset.rules.ImplicitBackingPropertyRule
+import org.cqfn.diktat.util.LintTestBase
+import org.junit.jupiter.api.Tag
+import org.junit.jupiter.api.Test
+
+class ImplicitBackingPropertyWarnTest: LintTestBase(::ImplicitBackingPropertyRule) {
+ private val ruleId = "$DIKTAT_RULE_SET_ID:implicit-backing-property"
+
+ @Test
+ @Tag(NO_CORRESPONDING_PROPERTY)
+ fun `not trigger on backing property`() {
+ lintMethod(
+ """
+ |class Some(val a: Int = 5) {
+ | private var _table: Map? = null
+ | val table:Map
+ | get() {
+ | if (_table == null) {
+ | _table = HashMap()
+ | }
+ | return _table ?: throw AssertionError("Set to null by another thread")
+ | }
+ | set(value) { field = value }
+ |}
+ """.trimMargin()
+ )
+ }
+
+ @Test
+ @Tag(NO_CORRESPONDING_PROPERTY)
+ fun `trigger on backing property`() {
+ lintMethod(
+ """
+ |class Some(val a: Int = 5) {
+ | private var a: Map? = null
+ | val table:Map
+ | get() {
+ | if (a == null) {
+ | a = HashMap()
+ | }
+ | return a ?: throw AssertionError("Set to null by another thread")
+ | }
+ | set(value) { field = value }
+ |}
+ """.trimMargin(),
+ LintError(3,4,ruleId, "${Warnings.NO_CORRESPONDING_PROPERTY.warnText()} table has no corresponding property with name _table")
+ )
+ }
+
+ @Test
+ @Tag(NO_CORRESPONDING_PROPERTY)
+ fun `don't trigger on regular backing property`() {
+ lintMethod(
+ """
+ |class Some(val a: Int = 5) {
+ | private var _a: Map? = null
+ | private val _some:Int? = null
+ |}
+ """.trimMargin()
+ )
+ }
+
+ @Test
+ @Tag(NO_CORRESPONDING_PROPERTY)
+ fun `don't trigger on regular property`() {
+ lintMethod(
+ """
+ |class Some(val a: Int = 5) {
+ | private var a: Map? = null
+ | private val some:Int? = null
+ | private val _prop: String? = null
+ |}
+ """.trimMargin()
+ )
+ }
+
+ @Test
+ @Tag(NO_CORRESPONDING_PROPERTY)
+ fun `should not trigger if property has field in accessor`() {
+ lintMethod(
+ """
+ |class Some(val a: Int = 5) {
+ | val table:Map
+ | set(value) { field = value }
+ | val _table: Map? = null
+ |
+ | val some: Int
+ | get() = 3
+ |}
+ """.trimMargin()
+ )
+ }
+
+ @Test
+ @Tag(NO_CORRESPONDING_PROPERTY)
+ fun `should not trigger on property with constant return`() {
+ lintMethod(
+ """
+ |class Some(val a: Int = 5) {
+ | val table:Int
+ | get() {
+ | return 3
+ | }
+ | set(value) { field = value }
+ |}
+ """.trimMargin()
+ )
+ }
+
+ @Test
+ @Tag(NO_CORRESPONDING_PROPERTY)
+ fun `should not trigger on property with chain call return`() {
+ lintMethod(
+ """
+ |class Some(val a: Int = 5) {
+ | val table:Int
+ | get() {
+ | val some = listOf(1,2,3)
+ | return some.filter { it -> it == 3}.first()
+ | }
+ | set(value) { field = value }
+ |}
+ """.trimMargin()
+ )
+ }
+
+ @Test
+ @Tag(NO_CORRESPONDING_PROPERTY)
+ fun `should not trigger set accessor`() {
+ lintMethod(
+ """
+ |class Some(val a: Int = 5) {
+ | val foo
+ | set(value) {
+ | if(isDelegate) log.debug(value)
+ | field = value
+ | }
+ |}
+ """.trimMargin()
+ )
+ }
+
+ @Test
+ @Tag(NO_CORRESPONDING_PROPERTY)
+ fun `should trigger set accessor`() {
+ lintMethod(
+ """
+ |class Some(val a: Int = 5) {
+ | val foo
+ | set(value) {
+ | if(isDelegate) log.debug(value)
+ | a = value
+ | }
+ |}
+ """.trimMargin(),
+ LintError(2,4 ,ruleId, "${Warnings.NO_CORRESPONDING_PROPERTY.warnText()} foo has no corresponding property with name _foo")
+ )
+ }
+}
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt
index 2dceac75a0..3f85f87cb3 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt
@@ -96,6 +96,12 @@ class DiktatSmokeTest : FixTestBase("test/smoke/src/main/kotlin",
fixAndCompare("Example3Expected.kt", "Example3Test.kt")
}
+ @Test
+ @Tag("DiktatRuleSetProvider")
+ fun `smoke test #4`() {
+ fixAndCompare("Example4Expected.kt", "Example4Test.kt")
+ }
+
@Test
@Tag("DiktatRuleSetProvider")
fun `regression - should not fail if package is not set`() {
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/WarningsGenerationTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/WarningsGenerationTest.kt
new file mode 100644
index 0000000000..fddc80fb86
--- /dev/null
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/WarningsGenerationTest.kt
@@ -0,0 +1,13 @@
+package org.cqfn.diktat.ruleset.utils
+
+import org.cqfn.diktat.ruleset.constants.Warnings
+import org.junit.jupiter.api.Test
+
+class WarningsGenerationTest {
+ @Test
+ fun `checking that warnings has all proper fields filled`() {
+ Warnings.values().forEach { warn ->
+ assert(warn.ruleId.split(".").size == 3)
+ }
+ }
+}
diff --git a/diktat-rules/src/test/resources/test/chapter6/primary_constructor/EmptyPCExpected.kt b/diktat-rules/src/test/resources/test/chapter6/primary_constructor/EmptyPCExpected.kt
new file mode 100644
index 0000000000..750cd85cc3
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/chapter6/primary_constructor/EmptyPCExpected.kt
@@ -0,0 +1,18 @@
+package test.chapter6.primary_constructor
+
+class Test {
+ var a: Int = 0
+ var b: Int = 0
+}
+
+class Test {
+ var a = "Property"
+
+ init {
+ println("some init")
+ }
+
+ constructor(a: String): this() {
+ this.a = a
+ }
+}
diff --git a/diktat-rules/src/test/resources/test/chapter6/primary_constructor/EmptyPCTest.kt b/diktat-rules/src/test/resources/test/chapter6/primary_constructor/EmptyPCTest.kt
new file mode 100644
index 0000000000..04369eab8b
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/chapter6/primary_constructor/EmptyPCTest.kt
@@ -0,0 +1,18 @@
+package test.chapter6.primary_constructor
+
+class Test() {
+ var a: Int = 0
+ var b: Int = 0
+}
+
+class Test() {
+ var a = "Property"
+
+ init {
+ println("some init")
+ }
+
+ constructor(a: String): this() {
+ this.a = a
+ }
+}
diff --git a/diktat-rules/src/test/resources/test/funcTest/FunctionalTestFile.kt b/diktat-rules/src/test/resources/test/funcTest/FunctionalTestFile.kt
deleted file mode 100644
index 85168cfe7d..0000000000
--- a/diktat-rules/src/test/resources/test/funcTest/FunctionalTestFile.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package test.funcTest
-
-class FunctionalTestFile {
- val AAAA = 5
-}
diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocExpected.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocExpected.kt
index b9e7799a4f..4743bc6509 100644
--- a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocExpected.kt
+++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocExpected.kt
@@ -22,9 +22,8 @@ class A constructor(
){}
/**
- * @property name
- * @property lastName
-*/
+ * @property lastName
+ */
class A constructor(
private var name: String,
val lastName: String
@@ -37,3 +36,18 @@ class A constructor(
class A constructor(
val name: String
){}
+
+class Example(private val foo: Int)
+
+/**
+ * @property g
+ * @property e
+ * @property s
+*/
+class Example constructor(
+ val g: String,
+ private var q: String,
+ @param:JsonProperty("shortName") private val shortName: String,
+ val e: String,
+ protected val s: String
+){}
diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocTest.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocTest.kt
index 09899c53c7..26e317b8bb 100644
--- a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocTest.kt
+++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocTest.kt
@@ -30,3 +30,13 @@ class A constructor(
*/
val name: String
){}
+
+class Example(private val foo: Int)
+
+class Example constructor(
+ val g: String,
+ private var q: String,
+ @param:JsonProperty("shortName") private val shortName: String,
+ val e: String,
+ protected val s: String
+){}
diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingFullExpected.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingFullExpected.kt
index 54b5583235..aa36ac1821 100644
--- a/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingFullExpected.kt
+++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingFullExpected.kt
@@ -17,3 +17,10 @@ class Example {
@Deprecated(message = "Use testNew")
fun test(a: Int): Int = 2 * a
}
+
+class Foo {
+ /**
+ * @implNote lorem ipsum
+ */
+ private fun foo() {}
+}
diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingFullTest.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingFullTest.kt
index 78ffb4bdcc..daaa408802 100644
--- a/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingFullTest.kt
+++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingFullTest.kt
@@ -17,3 +17,10 @@ class Example {
*/
fun test(a: Int): Int = 2 * a
}
+
+class Foo {
+ /**
+ * @implNote lorem ipsum
+ */
+ private fun foo() {}
+}
diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/SpecialTagsInKdocExpected.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/SpecialTagsInKdocExpected.kt
index 8410afedcd..c50aaf35a8 100644
--- a/diktat-rules/src/test/resources/test/paragraph2/kdoc/SpecialTagsInKdocExpected.kt
+++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/SpecialTagsInKdocExpected.kt
@@ -9,7 +9,6 @@ class SpecialTagsInKdoc {
* @implSpec bar
*
* @implNote baz
- *
*/
fun test() = Unit
}
diff --git a/diktat-rules/src/test/resources/test/paragraph3/blank_lines/CodeBlockWithBlankLinesExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/blank_lines/CodeBlockWithBlankLinesExpected.kt
index e6835f1341..2a5b877daf 100644
--- a/diktat-rules/src/test/resources/test/paragraph3/blank_lines/CodeBlockWithBlankLinesExpected.kt
+++ b/diktat-rules/src/test/resources/test/paragraph3/blank_lines/CodeBlockWithBlankLinesExpected.kt
@@ -4,4 +4,10 @@ class Example {
fun foo() {
bar()
}
+
+ fun bar() {
+ println()
+ println()
+ }
}
+
diff --git a/diktat-rules/src/test/resources/test/paragraph3/blank_lines/CodeBlockWithBlankLinesTest.kt b/diktat-rules/src/test/resources/test/paragraph3/blank_lines/CodeBlockWithBlankLinesTest.kt
index 49e09402a2..902d0a26bf 100644
--- a/diktat-rules/src/test/resources/test/paragraph3/blank_lines/CodeBlockWithBlankLinesTest.kt
+++ b/diktat-rules/src/test/resources/test/paragraph3/blank_lines/CodeBlockWithBlankLinesTest.kt
@@ -7,4 +7,12 @@ class Example {
bar()
}
+
+ fun bar() {
+
+
+ println()
+ println()
+ }
}
+
diff --git a/diktat-rules/src/test/resources/test/paragraph3/blank_lines/RedundantBlankLinesExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/blank_lines/RedundantBlankLinesExpected.kt
index d227da0a2c..e71d8117dd 100644
--- a/diktat-rules/src/test/resources/test/paragraph3/blank_lines/RedundantBlankLinesExpected.kt
+++ b/diktat-rules/src/test/resources/test/paragraph3/blank_lines/RedundantBlankLinesExpected.kt
@@ -1,8 +1,14 @@
package test.paragraph3.blank_lines
class Example {
-
val foo = 0
fun bar() { }
+
+ fun foo() {
+ list.map {
+ bar()
+ }
+ }
}
+
diff --git a/diktat-rules/src/test/resources/test/paragraph3/blank_lines/RedundantBlankLinesTest.kt b/diktat-rules/src/test/resources/test/paragraph3/blank_lines/RedundantBlankLinesTest.kt
index c875259e9d..7848551585 100644
--- a/diktat-rules/src/test/resources/test/paragraph3/blank_lines/RedundantBlankLinesTest.kt
+++ b/diktat-rules/src/test/resources/test/paragraph3/blank_lines/RedundantBlankLinesTest.kt
@@ -8,4 +8,12 @@ class Example {
fun bar() { }
+
+ fun foo() {
+ list.map {
+
+ bar()
+ }
+ }
}
+
diff --git a/diktat-rules/src/test/resources/test/paragraph3/block_brace/IfElseBracesExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/block_brace/IfElseBracesExpected.kt
index 74837933c5..94f1bc7db5 100644
--- a/diktat-rules/src/test/resources/test/paragraph3/block_brace/IfElseBracesExpected.kt
+++ b/diktat-rules/src/test/resources/test/paragraph3/block_brace/IfElseBracesExpected.kt
@@ -35,4 +35,13 @@ fun foo4(){
}else if (x < 4){
println(5)
}
+}
+
+fun foo() {
+ //comment1
+ // comment
+if(x) {
+ //comment2
+ foo()
+ }
}
\ No newline at end of file
diff --git a/diktat-rules/src/test/resources/test/paragraph3/block_brace/IfElseBracesTest.kt b/diktat-rules/src/test/resources/test/paragraph3/block_brace/IfElseBracesTest.kt
index f4587207ee..95e09901f2 100644
--- a/diktat-rules/src/test/resources/test/paragraph3/block_brace/IfElseBracesTest.kt
+++ b/diktat-rules/src/test/resources/test/paragraph3/block_brace/IfElseBracesTest.kt
@@ -31,4 +31,13 @@ fun foo4(){
}else if (x < 4){
println(5)
}
+}
+
+fun foo() {
+ //comment1
+ if(x) // comment
+ {
+ //comment2
+ foo()
+ }
}
\ No newline at end of file
diff --git a/diktat-rules/src/test/resources/test/paragraph3/newlines/FunctionalStyleExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/newlines/FunctionalStyleExpected.kt
index 94641ee4b1..e7eccb61dc 100644
--- a/diktat-rules/src/test/resources/test/paragraph3/newlines/FunctionalStyleExpected.kt
+++ b/diktat-rules/src/test/resources/test/paragraph3/newlines/FunctionalStyleExpected.kt
@@ -10,3 +10,5 @@ fun foo(list: List?) {
?.qux()
?:foobar
}
+
+fun bar(x :Int,y:Int) = x+ y
diff --git a/diktat-rules/src/test/resources/test/paragraph3/newlines/FunctionalStyleTest.kt b/diktat-rules/src/test/resources/test/paragraph3/newlines/FunctionalStyleTest.kt
index cf029827e2..4315b7dadc 100644
--- a/diktat-rules/src/test/resources/test/paragraph3/newlines/FunctionalStyleTest.kt
+++ b/diktat-rules/src/test/resources/test/paragraph3/newlines/FunctionalStyleTest.kt
@@ -7,3 +7,6 @@ fun foo(list: List?) {
?:
foobar
}
+
+fun bar(x :Int,y:Int) :Int {
+ return x+ y }
diff --git a/diktat-rules/src/test/resources/test/paragraph3/newlines/OneLineFunctionExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/newlines/OneLineFunctionExpected.kt
new file mode 100644
index 0000000000..f68b0c37ec
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/paragraph3/newlines/OneLineFunctionExpected.kt
@@ -0,0 +1,6 @@
+package test.paragraph3.newlines
+
+class Example {
+ fun doubleA() = 2 * a
+ fun doubleA() = 2 * a
+}
diff --git a/diktat-rules/src/test/resources/test/paragraph3/newlines/OneLineFunctionTest.kt b/diktat-rules/src/test/resources/test/paragraph3/newlines/OneLineFunctionTest.kt
new file mode 100644
index 0000000000..bdcdc2f84a
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/paragraph3/newlines/OneLineFunctionTest.kt
@@ -0,0 +1,10 @@
+package test.paragraph3.newlines
+
+class Example {
+ fun doubleA(): Int {
+ return 2 * a;
+ }
+ fun doubleA(): Int {
+ return 2 * a
+ }
+}
diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Expected.kt b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Expected.kt
index 4f6be67d67..b68b282c9d 100644
--- a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Expected.kt
+++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Expected.kt
@@ -24,5 +24,13 @@ private fun foo(node: ASTNode) {
// this is a generated else block
}
}
+ val qwe = a && b
+ val qwe = a &&
+ b
+
+ // comment
+ if (x) {
+ foo()
+ }
}
diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Test.kt b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Test.kt
index cd34b64f85..7ebef71daa 100644
--- a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Test.kt
+++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Test.kt
@@ -15,4 +15,11 @@ private fun foo (node: ASTNode) {
when (node.elementType) {
CLASS, FUN, PRIMARY_CONSTRUCTOR, SECONDARY_CONSTRUCTOR -> checkAnnotation(node)
}
+ val qwe = a
+ && b
+ val qwe = a &&
+ b
+
+ if (x) // comment
+ foo()
}
\ No newline at end of file
diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example3Expected.kt b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example3Expected.kt
index 231a5813b9..32d8804eda 100644
--- a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example3Expected.kt
+++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example3Expected.kt
@@ -45,3 +45,10 @@ class Example {
}
}
+class Foo {
+ /**
+ * @implNote lorem ipsum
+ */
+ private fun foo() {}
+}
+
diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example3Test.kt b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example3Test.kt
index cefa503487..ddd801edf8 100644
--- a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example3Test.kt
+++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example3Test.kt
@@ -40,3 +40,12 @@ class Example {
foo()
}
}
+
+
+class Foo {
+ /**
+ * @implNote lorem ipsum
+ */
+ private fun foo() {}
+}
+
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
new file mode 100644
index 0000000000..cab9a2e5d2
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example4Expected.kt
@@ -0,0 +1,26 @@
+package org.cqfn.diktat
+
+class SpecialTagsInKdoc {
+ /**
+ * Empty function to test KDocs
+ * @apiNote foo
+ *
+ * @implSpec bar
+ *
+ * @implNote baz
+ *
+ * @return
+ */
+ fun test() = Unit
+}
+
+fun `method name incorrect, part 4`() {
+ val code = """
+ class TestPackageName {
+ fun methODTREE(): String {
+ }
+ }
+ """.trimIndent()
+ lintMethod(code, LintError(2, 7, ruleId, "${FUNCTION_NAME_INCORRECT_CASE.warnText()} methODTREE", true))
+}
+
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
new file mode 100644
index 0000000000..4ccb47ed9b
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example4Test.kt
@@ -0,0 +1,25 @@
+package org.cqfn.diktat
+
+class SpecialTagsInKdoc {
+
+ /**
+ * Empty function to test KDocs
+ * @apiNote foo
+ * @implSpec bar
+ *
+ *
+ * @implNote baz
+ */
+ fun test() = Unit
+}
+
+fun `method name incorrect, part 4`() {
+ val code = """
+ class TestPackageName {
+ fun methODTREE(): String {
+ }
+ }
+ """.trimIndent()
+ lintMethod(code, LintError(2, 7, ruleId, "${FUNCTION_NAME_INCORRECT_CASE.warnText()} methODTREE", true))
+}
+
diff --git a/examples/gradle-groovy-dsl/build.gradle b/examples/gradle-groovy-dsl/build.gradle
new file mode 100644
index 0000000000..35da1ddf8c
--- /dev/null
+++ b/examples/gradle-groovy-dsl/build.gradle
@@ -0,0 +1,11 @@
+plugins {
+ id "org.cqfn.diktat.diktat-gradle-plugin" version "0.1.5"
+}
+
+repositories {
+ mavenCentral()
+}
+
+diktat {
+ inputs = files("src/**/*.kt")
+}
diff --git a/examples/gradle/diktat-analysis.yml b/examples/gradle-groovy-dsl/diktat-analysis.yml
similarity index 93%
rename from examples/gradle/diktat-analysis.yml
rename to examples/gradle-groovy-dsl/diktat-analysis.yml
index 99cb7048bf..17d166c0b1 100644
--- a/examples/gradle/diktat-analysis.yml
+++ b/examples/gradle-groovy-dsl/diktat-analysis.yml
@@ -282,9 +282,19 @@
# Use extra functions for it instead.
- name: CUSTOM_GETTERS_SETTERS
enabled: true
+# Checks if null-check was used explicitly (for example: if (a == null))
+# Try to avoid explicit null checks (explicit comparison with `null`)
+# Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.
+# But Kotlin architects wanted Kotlin to be fully compatible with Java, that's why `null` keyword was also introduced in Kotlin.
+# There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`, `.let {}`, `.also {}`, e.t.c
+- name: AVOID_NULL_CHECKS
+ enabled: true
# Checks if class instantiation can be wrapped in `apply` for better readability
- name: COMPACT_OBJECT_INITIALIZATION
enabled: true
# Checks explicit supertype qualification
- name: USELESS_SUPERTYPE
- enabled: true
\ No newline at end of file
+ enabled: true
+# Checks if extension function with the same signature don't have related classes
+- name: EXTENSION_FUNCTION_SAME_SIGNATURE
+ enabled: true
diff --git a/examples/gradle/src/main/kotlin/Test.kt b/examples/gradle-groovy-dsl/src/main/kotlin/Test.kt
similarity index 86%
rename from examples/gradle/src/main/kotlin/Test.kt
rename to examples/gradle-groovy-dsl/src/main/kotlin/Test.kt
index 885e2f69c9..ed2b851143 100644
--- a/examples/gradle/src/main/kotlin/Test.kt
+++ b/examples/gradle-groovy-dsl/src/main/kotlin/Test.kt
@@ -7,5 +7,7 @@ class incorrectname: Exception {
// fun myCommentedFunction() {
// }
-
+
+val Incorrect_Val = 5
+
}
diff --git a/examples/gradle-kotlin-dsl/build.gradle.kts b/examples/gradle-kotlin-dsl/build.gradle.kts
new file mode 100644
index 0000000000..bd6af41e63
--- /dev/null
+++ b/examples/gradle-kotlin-dsl/build.gradle.kts
@@ -0,0 +1,11 @@
+plugins {
+ id("org.cqfn.diktat.diktat-gradle-plugin") version "0.1.5"
+}
+
+repositories {
+ mavenCentral()
+}
+
+diktat {
+ inputs = files("src/**/*.kt")
+}
diff --git a/examples/gradle-kotlin-dsl/diktat-analysis.yml b/examples/gradle-kotlin-dsl/diktat-analysis.yml
new file mode 100644
index 0000000000..17d166c0b1
--- /dev/null
+++ b/examples/gradle-kotlin-dsl/diktat-analysis.yml
@@ -0,0 +1,300 @@
+- name: DIKTAT_COMMON
+ configuration:
+ # put your package name here - it will be autofixed and checked
+ domainName: your.name.here
+ testDirs: test
+- name: CLASS_NAME_INCORRECT
+ enabled: true
+- name: CONSTANT_UPPERCASE
+ enabled: true
+- name: ENUM_VALUE
+ enabled: true
+- name: EXCEPTION_SUFFIX
+ enabled: true
+- name: FILE_NAME_INCORRECT
+ enabled: true
+- name: FILE_NAME_MATCH_CLASS
+ enabled: true
+- name: FUNCTION_BOOLEAN_PREFIX
+ enabled: true
+- name: FUNCTION_NAME_INCORRECT_CASE
+ enabled: true
+- name: GENERIC_NAME
+ enabled: true
+- name: IDENTIFIER_LENGTH
+ enabled: true
+- name: OBJECT_NAME_INCORRECT
+ enabled: true
+- name: PACKAGE_NAME_INCORRECT_CASE
+ enabled: true # configuration domainName is taken from DIKTAT_COMMON
+- name: PACKAGE_NAME_INCORRECT_PREFIX
+ enabled: false
+- name: PACKAGE_NAME_INCORRECT_SYMBOLS
+ enabled: true
+- name: PACKAGE_NAME_INCORRECT_PATH
+ enabled: false # configuration domainName is taken from DIKTAT_COMMON
+- name: PACKAGE_NAME_MISSING
+ enabled: true
+- name: VARIABLE_HAS_PREFIX
+ enabled: true
+- name: VARIABLE_NAME_INCORRECT
+ enabled: true
+- name: VARIABLE_NAME_INCORRECT_FORMAT
+ enabled: true
+- name: MISSING_KDOC_ON_FUNCTION
+ enabled: true
+- name: MISSING_KDOC_TOP_LEVEL
+ enabled: true
+- name: MISSING_KDOC_CLASS_ELEMENTS
+ enabled: true
+- name: KDOC_WITHOUT_PARAM_TAG
+ enabled: true
+- name: KDOC_WITHOUT_RETURN_TAG
+ enabled: true
+- name: KDOC_WITHOUT_THROWS_TAG
+ enabled: true
+- name: KDOC_EMPTY_KDOC
+ enabled: true
+- name: INCORRECT_PACKAGE_SEPARATOR
+ enabled: true
+- name: KDOC_NO_DEPRECATED_TAG
+ enabled: true
+- name: KDOC_NO_EMPTY_TAGS
+ enabled: true
+- name: KDOC_WRONG_SPACES_AFTER_TAG
+ enabled: true
+- name: KDOC_WRONG_TAGS_ORDER
+ enabled: true
+- name: KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS
+ enabled: true
+- name: KDOC_NEWLINES_BEFORE_BASIC_TAGS
+ enabled: true
+- name: KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS
+ enabled: true
+- name: KDOC_TRIVIAL_KDOC_ON_FUNCTION
+ enabled: 'true'
+- name: HEADER_WRONG_FORMAT
+ enabled: true
+- name: HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE
+ enabled: true
+- name: HEADER_MISSING_OR_WRONG_COPYRIGHT
+ enabled: true
+ configuration:
+ isCopyrightMandatory: true
+ copyrightText: 'Copyright (c) Your Company Name Here. 2010-2020'
+- name: HEADER_NOT_BEFORE_PACKAGE
+ enabled: true
+- name: HEADER_CONTAINS_DATE_OR_AUTHOR
+ enabled: true
+- name: FILE_IS_TOO_LONG
+ enabled: true
+ configuration:
+ maxSize: '2000'
+ ignoreFolders: ''
+- name: COMMENTED_OUT_CODE
+ enabled: true
+- name: FILE_CONTAINS_ONLY_COMMENTS
+ enabled: true
+ # order imports alphabetically
+- name: FILE_UNORDERED_IMPORTS
+ enabled: true
+ configuration:
+ # use logical imports grouping with sorting inside of a group
+ useRecommendedImportsOrder: true
+- name: FILE_INCORRECT_BLOCKS_ORDER
+ enabled: true
+- name: FILE_NO_BLANK_LINE_BETWEEN_BLOCKS
+ enabled: true
+# Check: warns if wildcard imports are used except allows. (e.g. import org.cqfn.diktat.*)
+- name: FILE_WILDCARD_IMPORTS
+ enabled: true
+ configuration:
+ allowedWildcards: "" # Allowed wildcards for imports (e.g. "import org.cqfn.diktat.*, import org.jetbrains.kotlin.*")
+ useRecommendedImportsOrder: true
+- name: NO_BRACES_IN_CONDITIONALS_AND_LOOPS
+ enabled: true
+- name: WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES
+ enabled: true
+- name: BLANK_LINE_BETWEEN_PROPERTIES
+ enabled: true
+- name: BRACES_BLOCK_STRUCTURE_ERROR
+ enabled: true
+ configuration:
+ openBraceNewline: 'True'
+ closeBraceNewline: 'True'
+- name: WRONG_INDENTATION
+ enabled: true
+ configuration:
+ newlineAtEnd: true
+ extendedIndentOfParameters: true
+ alignedParameters: true
+ extendedIndentAfterOperators: true
+ indentationSize: 4
+- name: EMPTY_BLOCK_STRUCTURE_ERROR
+ enabled: true
+ configuration:
+ styleEmptyBlockWithNewline: 'True'
+ allowEmptyBlocks: 'False'
+- name: MORE_THAN_ONE_STATEMENT_PER_LINE
+ enabled: true
+- name: LONG_LINE
+ enabled: true
+ configuration:
+ lineLength: '120'
+- name: REDUNDANT_SEMICOLON
+ enabled: true
+- name: WRONG_NEWLINES
+ enabled: true
+ configuration:
+ maxParametersInOneLine: 2
+- name: TOO_MANY_CONSECUTIVE_SPACES
+ enabled: true
+ configuration:
+ max_spaces: '1'
+ saveInitialFormattingForEnums: false
+- name: TOO_MANY_BLANK_LINES
+ enabled: true
+- name: WRONG_WHITESPACE
+ enabled: true
+- name: BACKTICKS_PROHIBITED
+ enabled: true
+- name: STRING_CONCATENATION
+ enabled: true
+- name: WHEN_WITHOUT_ELSE
+ enabled: true
+- name: ANNOTATION_NEW_LINE
+ enabled: true
+- name: ENUMS_SEPARATED
+ enabled: true
+- name: LONG_NUMERICAL_VALUES_SEPARATED
+ enabled: true
+ configuration:
+ maxNumberLength: '5'
+ maxBlockLength: '3'
+- name: WRONG_DECLARATIONS_ORDER
+ enabled: true
+ configuration:
+ sortEnum: true
+ sortProperty: true
+- name: WRONG_MULTIPLE_MODIFIERS_ORDER
+ enabled: true
+- name: CONFUSING_IDENTIFIER_NAMING
+ enabled: true
+# Inspection that checks if there is a blank line before kDoc and none after
+- name: WRONG_NEWLINES_AROUND_KDOC
+ enabled: true
+# Inspection that checks if there is no blank lines before first comment
+- name: FIRST_COMMENT_NO_SPACES
+ enabled: true
+# Inspection that checks if there are blank lines between code and comment and between code start token and comment's text
+- name: COMMENT_WHITE_SPACE
+ enabled: true
+ configuration:
+ maxSpacesBeforeComment: 2
+ maxSpacesInComment: 1
+# Inspection that checks if all comment's are inside if-else code blocks. Exception is general if comment
+- name: IF_ELSE_COMMENTS
+ enabled: true
+- name: WRONG_COPYRIGHT_YEAR
+ enabled: true
+# Inspection that checks if local variables are declared close to the first usage site
+- name: LOCAL_VARIABLE_EARLY_DECLARATION
+ enabled: true
+# Try to avoid initialize val by null (e.g. val a: Int? = null -> val a: Int = 0)
+- name: NULLABLE_PROPERTY_TYPE
+ enabled: true
+# Type aliases provide alternative names for existing types when type's reference text is longer 25 chars
+- name: TYPE_ALIAS
+ enabled: true
+ configuration:
+ typeReferenceLength: '25' # max length of type reference
+- name: SMART_CAST_NEEDED
+ enabled: true
+- name: GENERIC_VARIABLE_WRONG_DECLARATION
+ enabled: true
+# Inspection that checks if string template has redundant curly braces
+- name: STRING_TEMPLATE_CURLY_BRACES
+ enabled: true
+# Variables with `val` modifier - are immutable (read-only). Usage of such variables instead of `var` variables increases
+# robustness and readability of code, because `var` variables can be reassigned several times in the business logic.
+# This rule prohibits usage of `var`s as local variables - the only exception is accumulators and counters
+- name: SAY_NO_TO_VAR
+ enabled: true
+# Inspection that checks if string template has redundant quotes
+- name: STRING_TEMPLATE_QUOTES
+ enabled: true
+# Checks that floating-point values are not used in arithmetic expressions
+- name: FLOAT_IN_ACCURATE_CALCULATIONS
+ enabled: true
+# Checks that function length isn't too long
+- name: TOO_LONG_FUNCTION
+ enabled: true
+ configuration:
+ maxFunctionLength: '30' # max length of function
+ isIncludeHeader: 'false' # count function's header
+# Warns if there are nested functions
+- name: AVOID_NESTED_FUNCTIONS
+ enabled: true
+# Checks that lambda inside function parameters is in the end
+- name: LAMBDA_IS_NOT_LAST_PARAMETER
+ enabled: true
+# Checks that function doesn't contains too many parameters
+- name: TOO_MANY_PARAMETERS
+ enabled: true
+ configuration:
+ maxParameterListSize: '5' # max parameters size
+# Checks that function doesn't have too many nested blocks
+- name: NESTED_BLOCK
+ enabled: true
+ configuration:
+ maxNestedBlockQuantity: '4'
+# Checks that function use default values, instead overloading
+- name: WRONG_OVERLOADING_FUNCTION_ARGUMENTS
+ enabled: true
+# Checks that KDoc in constructor has property tag
+- name: KDOC_NO_CONSTRUCTOR_PROPERTY
+ enabled: true
+# Checks that KDoc in constructor has property tag but with comment inside constructor
+- name: KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT
+ enabled: true
+# if a class has single constructor, it should be converted to a primary constructor
+- name: SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY
+ enabled: true
+# Checks if class can be made as data class
+- name: USE_DATA_CLASS
+ enabled: true
+# Checks that never use the name of a variable in the custom getter or setter
+- name: WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR
+ enabled: true
+# Checks that classes have only one init block
+- name: MULTIPLE_INIT_BLOCKS
+ enabled: true
+# Checks that there are abstract functions in abstract class
+- name: CLASS_SHOULD_NOT_BE_ABSTRACT
+ enabled: true
+# Checks if there are any trivial getters or setters
+- name: TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED
+ enabled: true
+# Checks that no custom getters and setters are used for properties. It is a more wide rule than TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED
+# Kotlin compiler automatically generates `get` and `set` methods for properties and also lets the possibility to override it.
+# But in all cases it is very confusing when `get` and `set` are overridden for a developer who uses this particular class.
+# Developer expects to get the value of the property, but receives some unknown value and some extra side effect hidden by the custom getter/setter.
+# Use extra functions for it instead.
+- name: CUSTOM_GETTERS_SETTERS
+ enabled: true
+# Checks if null-check was used explicitly (for example: if (a == null))
+# Try to avoid explicit null checks (explicit comparison with `null`)
+# Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.
+# But Kotlin architects wanted Kotlin to be fully compatible with Java, that's why `null` keyword was also introduced in Kotlin.
+# There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`, `.let {}`, `.also {}`, e.t.c
+- name: AVOID_NULL_CHECKS
+ enabled: true
+# Checks if class instantiation can be wrapped in `apply` for better readability
+- name: COMPACT_OBJECT_INITIALIZATION
+ enabled: true
+# Checks explicit supertype qualification
+- name: USELESS_SUPERTYPE
+ enabled: true
+# Checks if extension function with the same signature don't have related classes
+- name: EXTENSION_FUNCTION_SAME_SIGNATURE
+ enabled: true
diff --git a/examples/gradle-kotlin-dsl/src/main/kotlin/Test.kt b/examples/gradle-kotlin-dsl/src/main/kotlin/Test.kt
new file mode 100644
index 0000000000..80975f0974
--- /dev/null
+++ b/examples/gradle-kotlin-dsl/src/main/kotlin/Test.kt
@@ -0,0 +1,13 @@
+package incorrect
+
+class incorrectname: Exception {
+ fun INCORRECT_FUNCTION() {
+ throw Exception()
+ }
+
+ // fun myCommentedFunction() {
+ // }
+
+ val Incorrect_Val = 5
+
+}
diff --git a/examples/gradle/build.gradle.kts b/examples/gradle/build.gradle.kts
deleted file mode 100644
index 365f2749a1..0000000000
--- a/examples/gradle/build.gradle.kts
+++ /dev/null
@@ -1,44 +0,0 @@
-val ktlint by configurations.creating
-
-repositories {
- mavenCentral()
- jcenter()
-}
-
-dependencies {
- ktlint("com.pinterest:ktlint:0.39.0") {
- // need to exclude standard ruleset to use only diktat rules
- exclude("com.pinterest.ktlint", "ktlint-ruleset-standard")
- }
-
- // diktat ruleset
- ktlint("org.cqfn.diktat:diktat-rules:0.1.3") {
- }
-}
-
-val outputDir = "${project.buildDir}/reports/diktat/"
-val inputFiles = project.fileTree(mapOf("dir" to "src", "include" to "**/*.kt"))
-
-val diktatCheck by tasks.creating(JavaExec::class) {
- inputs.files(inputFiles)
- outputs.dir(outputDir)
-
- description = "Check Kotlin code style."
- classpath = ktlint
- main = "com.pinterest.ktlint.Main"
-
- // specify proper path to sources that should be checked here
- args = listOf("src/main/kotlin/**/*.kt")
-}
-
-val diktatFormat by tasks.creating(JavaExec::class) {
- inputs.files(inputFiles)
- outputs.dir(outputDir)
-
- description = "Fix Kotlin code style deviations."
- classpath = ktlint
- main = "com.pinterest.ktlint.Main"
-
- // specify proper path here
- args = listOf("-F","src/main/kotlin/**/*.kt")
-}
diff --git a/examples/maven/diktat-analysis.yml b/examples/maven/diktat-analysis.yml
index 99cb7048bf..17d166c0b1 100644
--- a/examples/maven/diktat-analysis.yml
+++ b/examples/maven/diktat-analysis.yml
@@ -282,9 +282,19 @@
# Use extra functions for it instead.
- name: CUSTOM_GETTERS_SETTERS
enabled: true
+# Checks if null-check was used explicitly (for example: if (a == null))
+# Try to avoid explicit null checks (explicit comparison with `null`)
+# Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.
+# But Kotlin architects wanted Kotlin to be fully compatible with Java, that's why `null` keyword was also introduced in Kotlin.
+# There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`, `.let {}`, `.also {}`, e.t.c
+- name: AVOID_NULL_CHECKS
+ enabled: true
# Checks if class instantiation can be wrapped in `apply` for better readability
- name: COMPACT_OBJECT_INITIALIZATION
enabled: true
# Checks explicit supertype qualification
- name: USELESS_SUPERTYPE
- enabled: true
\ No newline at end of file
+ enabled: true
+# Checks if extension function with the same signature don't have related classes
+- name: EXTENSION_FUNCTION_SAME_SIGNATURE
+ enabled: true
diff --git a/examples/maven/pom.xml b/examples/maven/pom.xml
index b96bdd69fa..96a3500c0b 100644
--- a/examples/maven/pom.xml
+++ b/examples/maven/pom.xml
@@ -3,59 +3,30 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0org.cqfn.diktat
- diktat-maven
+ diktat-examples-mavenpom1.0.0-SNAPSHOT
-
-
-
- ossrh
- https://oss.sonatype.org/content/repositories/snapshots
-
-
-
- org.apache.maven.plugins
- maven-antrun-plugin
- 3.0.0
+ org.cqfn.diktat
+ diktat-maven-plugin
+ 0.1.5
+
+ diktat-analysis.yml
+
+ ${project.basedir}/src/main/kotlin
+
+
- diktat
- none
-
-
-
-
-
-
-
+ diktat-check
- run
+ check
-
-
- com.pinterest
- ktlint
- 0.39.0
-
-
- com.pinterest.ktlint
- ktlint-ruleset-standard
-
-
-
-
- org.cqfn.diktat
- diktat-rules
- 0.1.3
-
-
diff --git a/examples/maven/src/main/kotlin/Test.kt b/examples/maven/src/main/kotlin/Test.kt
index 885e2f69c9..80975f0974 100644
--- a/examples/maven/src/main/kotlin/Test.kt
+++ b/examples/maven/src/main/kotlin/Test.kt
@@ -1,11 +1,13 @@
package incorrect
class incorrectname: Exception {
- fun INCORRECT_FUNCTION() {
- throw Exception()
+ fun INCORRECT_FUNCTION() {
+ throw Exception()
}
-
+
// fun myCommentedFunction() {
// }
-
+
+ val Incorrect_Val = 5
+
}
diff --git a/info/available-rules.md b/info/available-rules.md
index 02aeda2454..7f513d8c1d 100644
--- a/info/available-rules.md
+++ b/info/available-rules.md
@@ -95,9 +95,11 @@
| 5 | 5.2.3 | WRONG_OVERLOADING_FUNCTION_ARGUMENTS | Check: function has overloading instead use default arguments | no | -|
| 6 | 6.1.1 | SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY | Check: warns if there is only one secondary constructor in a class Fix: converts it to a primary constructor | yes | no | Support more complicated logic of constructor conversion |
| 6 | 6.1.2 | USE_DATA_CLASS | Check: if class can be made as data class | no | - | yes |
+| 6 | 6.1.3 | EMPTY_PRIMARY_CONSTRUCTOR | Check: if there is empty primary constructor | yes| - | yes |
| 6 | 6.1.4 | MULTIPLE_INIT_BLOCKS | Checks that classes have only one init block | yes | no | - |
| 6 | 6.1.5 | USELESS_SUPERTYPE | Check: if override function can be removed | yes| - | |
| 6 | 6.1.6 | CLASS_SHOULD_NOT_BE_ABSTRACT | Checks: if abstract class has any abstract method. If not, warns that class should not be abstract Fix: deletes abstract modifier | yes | - | - |
+| 6 | 6.1.7 | NO_CORRESPONDING_PROPERTY | Checks: if in case of using "backing property" scheme, the name of real and back property are the same | no | - | - |
| 6 | 6.1.9 | WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR | Check: used the name of a variable in the custom getter or setter | no | - |
| 6 | 6.1.10 | TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED | Check: if there are any trivial getters or setters Fix: Delete trivial getter or setter | yes | - | - |
| 6 | 6.1.8 | CUSTOM_GETTERS_SETTERS | Check: Inspection that checks that no custom getters and setters are used for properties | no | - | - |
diff --git a/info/guide/diktat-coding-convention.md b/info/guide/diktat-coding-convention.md
index e911270db3..a2075b6aa5 100644
--- a/info/guide/diktat-coding-convention.md
+++ b/info/guide/diktat-coding-convention.md
@@ -2,7 +2,9 @@
### Purpose of this document
-For code to be considered "good", it must entail the following characteristics:
+The purpose of this document is to provide a specification that software developers could reference to enhance their ability to write consistent, easy-to-read, and high-quality code.
+Such a specification will ultimately improve software development efficiency and product competitiveness.
+For the code to be considered high-quality, it must entail the following characteristics:
1. Simplicity
2. Maintainability
3. Reliability
@@ -11,73 +13,72 @@ For code to be considered "good", it must entail the following characteristics:
6. Portability
7. Reusability
-Programming is a profession that involves creativity.
-Software developers can reference this specification, which will enhance their ability to write consistent, easy-to-read, and high-quality code.
-This will ultimately improve product competitiveness and software development efficiency.
### General principles
-As a very modern and advanced programming language (completely like other languages), Kotlin complies with the following general principles:
-1. Clarity: Clarity is a necessary feature of programs that are easy to maintain and refactor.
-2. Simplicity: Simple code is easy to understand and implement.
-3. Consistency: Unification is particularly important when the same team works on the same project, utilizing similar styles. It enables code to be easily modified, reviewed, and understood by the team members.
+Like other modern programming languages, Kotlin is an advanced programming language that complies with the following general principles:
+1. Clarity — a necessary feature of programs that are easy to maintain and refactor.
+2. Simplicity — a code is easy to understand and implement.
+3. Consistency — enables a code to be easily modified, reviewed and understood by the team members. Unification is particularly important when the same team works on the same project, utilizing similar styles.enables code to be easily modified, reviewed and understood by the team members.
-In addition, we need to consider the following factors when programming on Kotlin:
+Also, we need to consider the following factors when programming on Kotlin:
-1. Write clean and simple Kotlin code
+1. Writing clean and simple Kotlin code
Kotlin combines two of the main programming paradigms: functional and object-oriented.
- Both of these paradigms are trusted, well-known software engineering practices.
- As a young programming language, Kotlin builds on well-established languages such as Java, C++, C#, and Scala.
- This is why Kotlin introduces many features that help you write cleaner, more readable code, while also reducing the number of complex code structures. For example: type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, when statements, much easier work with collections, type auto conversion, and other syntactic sugar.
+ Both of these paradigms are trusted and well-known software engineering practices.
+ As a young programming language, Kotlin is built on the top of well-established languages such as Java, C++, C#, and Scala.
+ This enables Kotlin to introduce many features that help you write cleaner, more readable code, while also reducing the number of complex code structures. For example, type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, when statements, much easier work with collections, type auto conversion, and other syntactic sugar.
-2. Follow Kotlin idioms
+2. Following Kotlin idioms
- The author of Kotlin, Andrey Breslav, mentioned that it is both pragmatic and practical, but not academic.
- Its pragmatic features enable ideas to easily be transformed into real working software. This programming language is closer to natural languages than its predecessors, and it implements the following design principles: readability, reusability, interoperability, security, and tool-friendliness (https://blog.jetbrains.com/kotlin/2018/10/kotlinconf-2018-announcements/).
+ The author of Kotlin, Andrey Breslav, mentioned that Kotlin is both pragmatic and practical, but not academic.
+ Its pragmatic features enable ideas to be transformed into real working software easily. Kotlin is closer to natural languages than its predecessors, and it implements the following design principles: readability, reusability, interoperability, security, and tool-friendliness (https://blog.jetbrains.com/kotlin/2018/10/kotlinconf-2018-announcements/).
-3. Use Kotlin efficiently
+3. Using Kotlin efficiently
- Some Kotlin features help you write higher-performance code: including rich coroutine library, sequences, inline functions/classes, arrays of basic types, tailRec, and CallsInPlace of contract.
+ Some Kotlin features can help you to write higher-performance code: including rich coroutine library, sequences, inline functions/classes, arrays of basic types, tailRec, and CallsInPlace of contract.
### Terminology
-**Rules**: conventions that should be followed when programming.
+**Rules** — conventions that should be followed when programming.
-**Recommendations**: conventions that should be considered when programming.
+**Recommendations** — conventions that should be considered when programming.
-**Explanation**: necessary explanations of rules and recommendations.
+**Explanation** — necessary explanations of rules and recommendations.
-**Valid Example**: examples (recommended) of rules and recommendations.
+**Valid Example** — recommended examples of rules and recommendations.
-**Invalid Example**: examples (not recommended) of rules and recommendations.
+**Invalid Example** — not recommended examples of rules and recommendations.
Unless otherwise stated, this specification applies to versions 1.3 and later of Kotlin.
### Exceptions
-Even though exceptions may exist, it is important to understand why rules and recommendations are needed.
-Depending on your project situation or personal habits, you can break some of the rules. However, remember that one exception leads to many and can completely destroy the consistency of code. As such, there should be very few exceptions.
-When modifying open-source code or third-party code, you can choose to implement the style used by the code (as opposed to using the existing specifications) to maintain consistency.
-Software that is directly based on the interface of the Android native operating system, such as the Android Framework, remains consistent with the Android style.
+Even though exceptions may exist, it is essential to understand why rules and recommendations are needed.
+Depending on your project situation or personal habits, you can break some of the rules. However, remember that one exception may lead to many and eventually can destroy code consistency. As such, there should be very few exceptions.
+When modifying open-source code or third-party code, you can choose to use the code style from this open-source project (instead of using the existing specifications) to maintain consistency.
+Software that is directly based on the Android native operating system interface, such as the Android Framework, remains consistent with the Android style.
# 1. Naming
-In programming, it is difficult to meaningfully and appropriately name variables, functions, classes, etc. Good names clearly express the main ideas and functionality of your code, as well as avoid misinterpretation, unnecessary coding and decoding, magic numbers, and inappropriate abbreviations.
+In programming, it is not always easy to meaningfully and appropriately name variables, functions, classes, etc. Using meaningful names helps you clearly express your code's main ideas and functionality and avoid misinterpretation, unnecessary coding and decoding, "magic" numbers, and inappropriate abbreviations.
-### Rule 1.0.1: file encoding format must be UTF-8 only
-The source file encoding format (including comments) must be UTF-8 only. The ASCII horizontal space character (0x20, that is, space) is the only permitted whitespace character. Tabs should not be used for indentation.
+Note: The source file encoding format (including comments) must be UTF-8 only. The ASCII horizontal space character (0x20, that is, space) is the only permitted whitespace character. Tabs should not be used for indentation.
-### 1.1 Identifiers naming
-### Rule 1.1.1: Identifiers
+### 1.1 Identifier names
+### 1.1.1: Identifiers naming conventions
+
+For identifiers, use the following naming conventions:
1. All identifiers should use only ASCII letters or digits, and the names should match regular expressions `\w{2,64}`.
Explanation: Each valid identifier name should match the regular expression `\w{2,64}`.
`{2,64}` means that the name length is 2 to 64 characters, and the length of the variable name should be proportional to its life range, functionality, and responsibility.
-Name lengths of less than 31 characters are generally recommended, but this depends on the project. Otherwise, class declaration with generics or inheritance from a super class can cause line breaking for example. No special prefix or suffix should be used in the names. The following examples are inappropriate: name_, mName, s_name, and kName.
+Name lengths of less than 31 characters are generally recommended. However, this depends on the project. Otherwise, a class declaration with generics or inheritance from a superclass can cause line breaking.
+No special prefix or suffix should be used in the names. The following examples are inappropriate: name_, mName, s_name, and kName.
-2. For files, choose names that describe their content. Use camel case (PascalCase) and `.kt` extension.
+2. Choose file names that would describe the content. Use camel case (PascalCase) and `.kt` extension.
3. Typical examples of naming:
@@ -95,14 +96,13 @@ Name lengths of less than 31 characters are generally recommended, but this depe
val `my dummy name-with-minus` = "value"
```
-The only exception is function names in `Unit tests`.
+The only exception is function names in `Unit tests.`
5. Backticks (``) should not be used for identifiers, except the names of test methods (marked with @Test annotation):
```kotlin
@Test fun `my test`() { /*...*/ }
```
-6. The following table contains some characters that cause confusion. Be careful when using them as identifiers, or use other names instead.
-
+6. The following table contains some characters that may cause confusion. Be careful when using them as identifiers. To avoid issues, use other names instead.
| Expected | Confusing name | Suggested name |
| ------------- | ------------------------ | ---------------- |
| 0 (zero) | O, D | obj, dgt |
@@ -115,29 +115,31 @@ The only exception is function names in `Unit tests`.
| rn, m | m,rn | mbr, item |
**Exceptions**
-- The i,j,k variables used in loops are part of the industry standard. One symbol can be used for for such variables.
+- The i,j,k variables used in loops are part of the industry standard. One symbol can be used for such variables.
- The `e` variable can be used to catch exceptions in catch block: `catch (e: Exception) {}`
-- The Java community generally does not recommend the use of prefixes; however, when developing Android code, you can use the s and m prefixes for static and non-public non-static fields, respectively.
-Note that prefixing can also negatively affect the style, as well as the auto generation of getters and setters.
+- The Java community generally does not recommend the use of prefixes. However, when developing Android code, you can use the s and m prefixes for static and non-public non-static fields, respectively.
+Note that prefixing can also negatively affect the style and the auto-generation of getters and setters.
| Type | Naming style |
| ---- | ---- |
-| Interfaces, classes, annotations, enumerated types, and object type names | Camel case starting with a capital letter. Test classes have a Test suffix. The filename is 'TopClassName'.kt. |
-| Class fields, local variables, methods, and method parameters | Camel case starting with a small letter. Test methods may be underlined with '_'., the only exception is [backing properties](#r6.1.7)
+| Interfaces, classes, annotations, enumerated types, and object type names | Camel case, starting with a capital letter. Test classes have a Test suffix. The filename is 'TopClassName'.kt. |
+| Class fields, local variables, methods, and method parameters | Camel case starting with a low case letter. Test methods can be underlined with '_'; the only exception is [backing properties](#r6.1.7).
| Static constants and enumerated values | Only uppercase underlined with '_' |
| Generic type variable | Single capital letter, which can be followed by a number, for example: `E, T, U, X, T2` |
| Exceptions | Same as class names, but with a suffix Exception, for example: `AccessException` and `NullPointerException`|
### 1.2 Packages names
-### Rule 1.2.1: Package names are in lower case and separated by dots. Code developed within your company should start with `your.company.domain`, and numbers are permitted in package names.
-Package names are all written in lowercase, and consecutive words are simply concatenated together (no underscores). Package names should contain both the product and module names, as well as the department or team name to prevent conflicts with other teams. Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`.
+### Rule 1.2.1: Package names dots
+Package names are in lower case and separated by dots. Code developed within your company should start with `your.company.domain.` Numbers are permitted in package names.
+Each file should have a `package` directive.
+Package names are all written in lowercase, and consecutive words are concatenated together (no underscores). Package names should contain both the product and module names, and the department (or team) name to prevent conflicts with other teams. Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`.
**Exceptions:**
-- In certain cases, such as open-source projects or commercial cooperation, package names should not start with `your.company.domain`.- In some cases, if the package name starts with a number or other characters, but these characters cannot be used at the beginning of the Java/Kotlin package name, or the package name contains reserved Java keywords, underscores are allowed.
-- Underscores are sometimes permitted if the package name starts with a number or other character, which cannot be used at the beginning of the Java/Kotlin package name; or the package name contains reserved Java keywords. For example: org.example.hyphenated_name, int_.example, com.example._123name
-For example: `org.example.hyphenated_name`,` int_.example`, `com.example._123name`
+- In certain cases, such as open-source projects or commercial cooperation, package names should not start with `your.company.domain.`
+- If the package name starts with a number or other characters that cannot be used at the beginning of the Java/Kotlin package name, then underscores are allowed. For example: `com.example._123name`.
+- Underscores are sometimes permitted if the package name contains reserved Java/Kotlin keywords, such as `org.example.hyphenated_name`, `int_.example`.
**Valid example**:
```kotlin
@@ -146,13 +148,13 @@ package your.company.domain.mobilecontrol.views
### 1.3 Classes, enumerations, interfaces
-### Rule 1.3.1: Classes, enumerations, interface names use camel case nomenclature
+### Rule 1.3.1: Classes, enumerations, interface names use Camel case
+Classes, enumerations, and interface names use `UpperCamelCase` nomenclature. Follow the naming rules described below:
+1. A class name is usually a noun (or a noun phrase) denoted using the camel case nomenclature, such as UpperCamelCase. For example: `Character` or `ImmutableList`.
+An interface name can also be a noun or noun phrase (such as `List`) or an adjective or adjective phrase (such as `Readable`).
+Note that verbs are not used to name classes. However, nouns (such as `Customer`, `WikiPage`, and `Account`) can be used. Try to avoid using vague words such as `Manager` and `Process`.
-1. The class name is usually a noun or a noun phrase using the camel case nomenclature, such as UpperCamelCase. For example: `Character` or `ImmutableList`.
-The name of an interface can also be a noun or noun phrase (such as `List`), or an adjective or adjective phrase (such as `Readable`).
-Note that verbs should not be used to name classes; however, nouns (such as `Customer`, `WikiPage`, and `Account`) can be used. Try to avoid vague words like Manager and Process.
-
-2. Test classes start with the name of the class they are testing and end with Test. For example: HashTest or HashIntegrationTest
+2. Test classes start with the name of the class they are testing and end with 'Test'. For example, `HashTest` or `HashIntegrationTest`.
**Invalid example**:
```kotlin
@@ -172,19 +174,19 @@ class Order {}
### 1.4 Functions
-### Rule 1.4.1: function names should be in camel case
-
-1. Function names are usually verbs or verb phrases, and use the camel case nomenclature (`lowerCamelCase`).
+### Rule 1.4.1: Function names should be in camel case
+Function names should use `lowerCamelCase` nomenclature. Follow the naming rules described below:
+1. Function names are usually verbs or verb phrases denoted with the camel case nomenclature (`lowerCamelCase`).
For example: `sendMessage`, `stopProcess`, or `calculateValue`.
-The format is as follows:
+To name functions use the following formatting rules:
-a) To get, modify, or calculate a certain value: get + non-boolean field(). However, note that getters are automatically generated by the Kotlin compiler for some classes, and the special get syntax is preferred for fields: kotlin private val field: String get() { }.
+a) To get, modify, or calculate a certain value: get + non-boolean field(). Note that the Kotlin compiler automatically generates getters for some classes, applying the special syntax preferred for the 'get' fields: kotlin private val field: String get() { }. kotlin private val field: String get() { }.
```kotlin
private val field: String
get() {
}
```
-Additionally, calling property access syntax is preferred to calling getter directly. (In this case, the Kotlin compiler will automatically call the corresponding getter).
+Note: The calling property access syntax is preferred to call getter directly. In this case, the Kotlin compiler automatically calls the corresponding getter.
b) `is` + boolean variable name()
@@ -193,11 +195,11 @@ c) `set` + field/attribute name(). However, note that the syntax and code genera
d) `has` + Noun / adjective ()
e) verb()
-The verb is mainly used on the object of the action itself, such as `document.print ()`
+Note: Note: Verb are primarily used for the action objects, such as `document.print ()`
f) verb + noun()
-g) The Callback function allows for names that use the preposition + verb format, such as: `onCreate()`, `onDestroy()`, `toString()`.
+g) The Callback function allows the names that use the preposition + verb format, such as: `onCreate()`, `onDestroy()`, `toString()`.
**Invalid example**:
@@ -219,22 +221,22 @@ fun draw()
fun addKeyListener(Listener)
```
-2. An underscore can be included in the JUnit test function name, and should be a logical component used to separate names. Each logical part is written in lowerCamelCase. For example: a typical pattern _, such as pop_emptyStack
-
+2. An underscore (`_`) can be included in the JUnit test function name and should be used as a separator. Each logical part denoted in `lowerCamelCase`, for example, a typical pattern of using underscore: `pop_emptyStack`.
-### 1.5 Constants
-### Rule 1.5.1 Constant names should be in UPPER case, words separated by underscore
+### 1.5 Constants
+### Rule 1.5.1 Constant names should be in UPPER case, words in the name are separated by underscore
+Constant names should be in UPPER case, words separated by underscore. The jeneral constant naming conventions are listed below:
+1. Constants are attributes created with the `const` keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed.
-1. Constants are attributes created with the const keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant value that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. If an object state can be changed, the value is not a constant.
+1. Constants are attributes created with the const keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant value that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. If an object state can be changed, the value is not a constant.
2. Constant names should contain only uppercase letters separated by underscores. They should have a val or const val modifier to explicitly make them final. In most cases, if you need to specify a constant value, then you need to create it with the "const val" modifier. Note that not all `val` variables are constants.
-
3. Objects that have immutable content, such as `Logger` and `Lock`, can be in uppercase as constants or have camel case as regular variables.
4. Use meaningful constants instead of `magic numbers`. SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants.
Magic constants like `NUM_FIVE = 5` or `NUM_5 = 5` should not be treated as constants. This is because mistakes will easily be made if they are changed to `NUM_5 = 50` or 55.
-Typically, these constants represent business logic values like measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms.
-Magic numbers can be avoided through the following methods:
+These constants typically represent business logic values, such as measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms.
+You can avoid using magic numbers with the following method:
- Using library functions and APIs. For example, instead of checking that `size == 0`, use `isEmpty()` function. To work with `time`, use built-ins from `java.time API`.
- Enumerations can be used to name patterns. Refer to [Recommended usage scenario for enumeration in 3.9](#c3.9)
@@ -254,12 +256,12 @@ const val String APPLICATION_NAME = "Launcher";
### 1.6 Non-constant fields (variables)
-### Rule 1.6.1: The name of the non-constant field should use camel case and start with a lowercase letter.
-
-A local variable cannot be treated as a constant even if it is final and immutable. Therefore, it should not use the preceding rules. The name of variables with a type from collections (sets, lists, etc.) should contain plural nouns.
+### Rule 1.6.1: Non-constant field name
+Non-constant field names should use camel case and start with a lowercase letter.
+A local variable cannot be treated as a constant even if it is final and immutable. Therefore, it should not use the preceding rules. Names of collection type variables (sets, lists, etc.) should contain plural nouns.
For example: `var namesList: List`
-Names of non-constant variables should use lower camel case. The name of the final immutable field used to store the singleton object can use the same notation with camel case.
+Names of non-constant variables should use `lowerCamelCase`. The name of the final immutable field used to store the singleton object can use the same camel case notation.
**Invalid example**:
```kotlin
@@ -274,13 +276,13 @@ val users: List = listOf();
val mutableCollection: MutableSet = HashSet()
```
-### Recommendation 1.6.2: Avoid using Boolean variable names with negative meaning.
+### Rule 1.6.2: Boolean variable names with negative meaning
-*Note*: When using a logical operator and name with negative meaning, the code may be difficult to understand, which is referred to as the "double negative".
+Avoid using Boolean variable names with negative meaning. When using a logical operator and name with negative meaning, the code may be difficult to understand, which is referred to as the "double negative".
For instance, it is not easy to understand the meaning of !isNotError.
The JavaBeans specification automatically generates isXxx() getters for attributes of Boolean classes.
-However, methods that return Boolean type do not all have this notation.
-For Boolean local variables or methods, it is highly recommended that you add non-meaningful prefixes, including is (which is commonly used by JavaBeans), or has, can, should, must. Modern integrated development environments (IDEs) such as Intellij are already capable of doing this for you when you generate getters in Java. For Kotlin, this process is even easier as everything is on the byte-code level under the hood.
+However, not all methods returning Boolean type have this notation.
+For Boolean local variables or methods, it is highly recommended that you add non-meaningful prefixes, including is (commonly used by JavaBeans), has, can, should, and must. Modern integrated development environments (IDEs) such as Intellij are already capable of doing this for you when you generate getters in Java. For Kotlin, this process is even more straightforward as everything is on the byte-code level under the hood.
**Invalid example**:
```kotlin
@@ -302,13 +304,13 @@ fun hasNext()
```
# 2. Comments
-The best practice involves beginning your code with a short summary, which can be one sentence.
-You should balance between writing no comments at all and obvious comments for each line of code.
+The best practice is to begin your code with a summary, which can be one sentence.
+Try to balance between writing no comments at all and obvious commentary statements for each line of code.
Comments should be accurately and clearly expressed, without repeating the name of the class, interface, or method.
-Comments are not a solution to bad code. Instead, you should fix the code as soon as you notice an issue, or plan to fix it (with a TODO comment including a Jira number).
-Comments should accurately reflect the design ideas and logic of the code, and then describe the code's business logic.
+Comments are not a solution to the wrong code. Instead, you should fix the code as soon as you notice an issue or plan to fix it (by entering a TODO comment, including a Jira number).
+Comments should accurately reflect the code's design ideas and logic and further describe its business logic.
As a result, other programmers will be able to save time when trying to understand the code.
-Imagine that you are writing the comments to help your future self understand the original ideas behind the code.
+Imagine that you are writing the comments to help yourself to understand the original ideas behind the code in the future.
### 2.1 General form of Kdoc
@@ -330,18 +332,19 @@ It is also shown in the following single-line form:
```kotlin
/** Short form of KDoc. */
```
-When the entire KDoc block can be stored in one line (and there is no KDoc mark @XXX), a single-line form can be used. For detailed instructions on how to use KDoc, refer to [Official Document](https://docs.oracle.com/en/Kotlin/Kotlinse/11/tools/KDoc.html).
+Use a single-line form when you store the entire KDoc block in one line (and there is no KDoc mark @XXX). For detailed instructions on how to use KDoc, refer to [Official Document](https://docs.oracle.com/en/Kotlin/Kotlinse/11/tools/KDoc.html).
### Rule 2.1.1: KDoc is used for each public, protected or internal code element
At a minimum, KDoc should be used for every public, protected, or internal decorated class, interface, enumeration, method, and member field (property). Other code blocks can also have KDocs if needed.
+Instead of using comments before properties in class - use `@property` tag in a KDoc of a class.
+All properties of the primary constructor should be also documented in a KDoc with a `@property` tag.
-Exceptions:
+**Exceptions:**
-1. For setters/getters of properties obvious comments are optional.
- (Note that simple `get/set` methods are generated by Kotlin under the hood). For example, getFoo can also be `return foo`.
+1. For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note, that Kotlin generates simple `get/set` methods under the hood.
-2. It is optional to add comments for simple one-line methods like:
+2. It is optional to add comments for simple one-line methods, such as shown in the example below:
```kotlin
val isEmpty: Boolean
get() = this.size == 0
@@ -353,9 +356,11 @@ or
fun isEmptyList(list: List) = list.size == 0
```
-3. You can skip KDocs for a method's override if the method is almost like the super class method.
+Note: You can skip KDocs for a method's override if it is almost the same as the superclass method.
+### Rule 2.1.2: Describing methods with arguments, return value or can throw exceptions
+When the method has arguments, return value, or can throw exceptions, it must be described in the KDoc block: with @param, @return, @throws
-### Rule 2.1.2: When the method has arguments, return value, can throw exceptions, etc., it must be described in the KDoc block: with @param, @return, @throws, etc.
+### Rule 2.1.2: When the method has arguments, return value, can throw exceptions, etc., it must be described in the KDoc block: with @param, @return, @throws, etc.
**Valid examples**:
@@ -390,27 +395,29 @@ fun isEmptyList(list: List) = list.size == 0
}
```
-### Rule 2.1.3: There is only one space between the Kdoc tag and content. Tags are arranged in the following order: @param, @return, and @throws
+### Rule 2.1.3: Only one space between the Kdoc tag and content. Tags are arranged in the order.
+There should be only one space between the Kdoc tag and content. Tags are arranged in the following order: @param, @return, and @throws.
-This is how Kdoc should look like and what it should contain:
+Therefore, Kdoc should contain the following:
- Functional and technical description, explaining the principles, intentions, contracts, API, etc.
- The function description and @tags (`implSpec`, `apiNote`, and `implNote`) require an empty line after them.
- `@implSpec`: A specification related to API implementation, and it should let the implementer decide whether to override it.
-- `@apiNote`: Explain the API precautions, including whether to allow null and whether the method is thread safe, as well as the algorithm complexity, input and output range, exceptions, etc.
+- `@apiNote`: Explain the API precautions, including whether to allow null and whether the method is thread-safe, as well as the algorithm complexity, input, and output range, exceptions, etc.
- `@implNote`: A note related to API implementation, which implementers should keep in mind.
-- Then one empty line, followed by regular `@param`, `@return`, `@throws` and other comments.
-- The conventional standard "block labels" are arranged in order: `@param`, `@return`, `@throws`.
-- Empty descriptions in tag blocks are not permitted. It is better not to write Kdoc than to waste code line on empty space.
+- One empty line, followed by regular `@param`, `@return`, `@throws`, and other comments.
+- The conventional standard "block labels" arranged in the following order: `@param`, `@return`, `@throws`.
+Kdoc should not contain:
+- Empty descriptions in tag blocks. It is better not to write Kdoc than waste code line space.
- There should be no empty lines between the method/class declaration and the end of Kdoc (`*/` symbols).
-- (!) KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation.
+Important note: KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation.
-If a tag block cannot be described in one line, you should indent the content of the new line by `4 spaces` from the `@` position to achieve alignment (`@` counts as one + three spaces).
+If a tag block cannot be described in one line, you should indent the content of the new line by `four spaces` from the `@` position to achieve alignment (`@` counts as one + three spaces).
-**Exception:** When the descriptive text in a tag block is too long to wrap, the alignment can be indented with the descriptive text in the previous line. The descriptive text of multiple tags does not need to be aligned.
+**Exception:** When the descriptive text in a tag block is too long to wrap, you can indent the alignment with the descriptive text in the last line. The descriptive text of multiple tags does not need to be aligned.
See [3.8 Horizontal space](#c3.8).
-In Kotlin compared to Java you are able to put several classes inside one file so each class should have a Kdoc formatted comment (this is also stated in rule 2.1).
-This comment should contain @since tag. The good style is to write the version of the application when functionality was released. It should be written after a `@since` tag.
+In Kotlin, compared to Java, you are able to put several classes inside one file, so each class should have a Kdoc formatted comment (as stated in rule 2.1).
+This comment should contain @since tag. The right style is to write the application version when its functionality is released. It should be entered after the `@since` tag.
**Examples:**
@@ -435,7 +442,7 @@ Other KDoc tags (such as @param type parameters and @see.) can be added as follo
### 2.2 Comments to the file header
### Rule 2.2.1: Comments on the file header must include copyright information, without the creation date and author's name (use VCS for history management instead). The content inside files that contain multiple or no classes should also be described.
-Comments on the file header should be stored before the package name and imports. If you need to add more content to the comment, you can subsequently add it in the same format.
+Comments on the file header should be placed before the package name and imports. If you need to add more content to the comment, you can subsequently add it in the same format.
The following examples for Huawei describe the format of the **copyright license**: \
Chinese version: `版权所有 (c) 华为技术有限公司 2012-2020` \
@@ -460,28 +467,28 @@ The following example is a copyright statement for Huawei, without other functio
```
The following factors should be considered when writing the file header or comments for top-level classes:
-- File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc `*/` symbol. If it is a comment for a top-level class, class declaration should start immediately without using a newline.
-- Maintain a unified format. The specific format can be formulated by the project (for example, in opensource) and you need to follow it.
+- File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc `*/` symbol. If it is a comment for a top-level class, the class declaration should start immediately without using a newline.
+- Maintain a unified format. The specific format can be formulated by the project (for example, if you use existing opensource project), and you need to follow it.
- A top-level file-Kdoc must include a copyright and functional description, especially if there is more than one top-level class.
-- Do not include empty comment blocks. As described in the preceding example, if there is no content after the option `@apiNote`, the entire tag block should be deleted.
-- The industry does not include historical information in comments. The corresponding history can be found in VCS (git, svn, etc.). As such, it is not recommended to include historical data in the comments of the Kotlin source code.
+- Do not include empty comment blocks.If there is no content after the option `@apiNote`, the entire tag block should be deleted.
+- The industry practice is not to include historical information in comments. The corresponding history can be found in VCS (git, svn, etc.). Therefore, it is not recommended to include historical data in the comments of the Kotlin source code.
### 2.3 Comments on the function header
-### Rule 2.3.1: Do not use or make unnecessary and useless comments.
+### Rule 2.3.1: Do not make unnecessary and useless comments.
Comments on the function header are placed above function declarations or definitions. A newline should not exist between a function declaration and its Kdoc. Use the preceding [KDoc](#c2.1) style rules.
-In Chapter 1 of the current code style, we stated that the function name should self-comment its functionality as much as possible. Therefore, in the Kdoc, try to mention things that are not stored in the function name.
+As stated in Chapter 1, the function name should reflect its functionality as much as possible. Therefore, in the Kdoc, try to describe the functionality that is not mentioned in the function name.
Avoid unnecessary comments on dummy coding.
-The content of the function header comment is optional, but not limited to function description, return value, performance constraints, usage, memory conventions, algorithm implementation, reentrant requirements, etc.
-The module's external interface declaration and its comments should clearly convey important and useful information.
+The function header comment's content is optional, but not limited to function description, return value, performance constraints, usage, memory conventions, algorithm implementation, reentrant requirements, etc.
### 2.4 Code comments
-### Rule 2.4.1: Add a blank line between the body of the comment and Kdoc tag-blocks. There must be one space between the comment's character and content. There must be a newline between a Kdoc and the preceding code.
-
-- There must be one space between the comment character and the content of the comment; there must be a newline between a Kdoc and the previous code above.
-An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular name space (code block) (for example, between the function declaration and first comment in a function body).
+### Rule 2.4.1: Add a blank line between the body of the comment and Kdoc tag-blocks.
+It is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules:
+- There must be one space between the comment character and the content of the comment
+- There must be a newline between a Kdoc and the pressiding code
+- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular name space (code block) (for example, between the function declaration and first comment in a function body).
**Valid Examples:**
```kotlin
@@ -523,7 +530,7 @@ An empty line should not exist between a Kdoc and the code it is describing. You
```
- Leave one single space between the comment on the right side of the code and the code.
-Conditional comments in the `if-else-if` scenario: To help other programmers understand the code, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`.
+If you use conditional comments in the `if-else-if` scenario, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`. This makes your code more understandable.
When the if-block is used with curly braces, the comment should be placed on the next line after opening the curly braces.
Compared to Java, the `if` statement in Kotlin statements returns a value. For this reason, a comment block can describe a whole `if-statement`.
@@ -558,16 +565,16 @@ val someVal = if (nr % 15 == 0) {
val x = 0 // this is a comment
```
-### Rule 2.4.2: Do not comment unused code blocks (including imports). Delete these code blocks immediately.
-
-Code is not used to store history. git, svn, or other VCS tools should be used for this purpose.
+### Rule 2.4.2: Do not comment on unused code blocks
+Do not comment on unused code blocks, including imports. Delete these code blocks immediately.
+A code is not used to store history. Git, svn, or other VCS tools should be used for this purpose.
Unused imports increase the coupling of the code and are not conducive to maintenance. The commented out code cannot be properly maintained.
When you attempt to reuse the code, there is a high probability that you will introduce defects that are easily missed.
The correct approach is to delete the unnecessary code directly and immediately when it is not used.
If you need the code again, consider porting or rewriting it as changes could have occurred since you first commented on the code.
-### Recommendation 2.4.3: Code formally delivered to the client typically should not contain TODO/FIXME comments.
-
+### Recommendation 2.4.3: Code delivered to the client should not contain TODO/FIXME comments.
+The code officially delivered to the client typically should not contain TODO/FIXME comments.
`TODO` comments are typically used to describe modification points that need to be improved and added. For example, refactoring FIXME comments are typically used to describe known defects and bugs that will be subsequently fixed and are not critical for an application.
They should all have a unified style to facilitate the unified text search processing.
@@ -577,20 +584,19 @@ They should all have a unified style to facilitate the unified text search proce
// FIXME: Jira-XXX - fix NPE in this code block
```
-In the version development stage, these annotations can be used to highlight the issues in code, but all of them should be fixed before a new product version is released.
+At a version development stage, these annotations can be used to highlight the issues in the code, but all of them should be fixed before a new product version is released.
# 3. General formatting (typesetting)
### 3.1 File-related rules
### Rule 3.1.1: Avoid files that are too long. Files should not exceed 2000 lines (non-empty and non-commented lines).
-If the file is too long, it is probably complex and can therefore be split into smaller files, functions, or modules.
-It is recommended that you horizontally or vertically split the file according to responsibilities or hierarchy, respectively.
-Code generation is the only exception to this.
-Auto-generated files that are not manually modified can be longer.
-
-### Rule 3.1.2: A source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line.
+If the file is too long and complex, it should be split into smaller files, functions, or modules.
+It is recommended to horizontally or vertically split the file according to responsibilities or hierarchy of its parts.
+The only exception to this rule is code generation - the auto-generated files that are not manually modified can be longer.
-a) They should be in the following order:
+### Rule 3.1.2: Code blocks in the source file should be separated by one blank line.
+A source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line.
+a) Code blocks should be in the following order:
1. Kdoc for licensed or copyrighted files
2. `@file` annotation
3. Package name
@@ -604,7 +610,9 @@ c) Import statements are alphabetically arranged, without using line breaks and
d) **Recommendation**: One `.kt` source file should contain only one class declaration, and its name should match the filename
-### Recommendation 3.1.3: Import statements should appear in the following order: Android, internal company imports, external imports, java core dependencies, and Kotlin standard library. Each group should be separated by a blank line.
+e) Avoid empty files that do not contain the code or contain only imports/comments/package name
+
+### Recommendation 3.1.3: Import statements order.
From top to bottom, the order is the following:
1. Android
@@ -613,7 +621,7 @@ From top to bottom, the order is the following:
4. Java core packages
5. kotlin stdlib
-Each category should be alphabetically arranged. This style is compatible with [Android import order](https://source.android.com/setup/contribute/code-style#order-import-statements).
+Each category should be alphabetically arranged. Each group should be separated by a blank line. This style is compatible with [Android import order](https://source.android.com/setup/contribute/code-style#order-import-statements).
**Valid example**:
```kotlin
@@ -634,9 +642,9 @@ import kotlin.system.exitProcess // kotlin standard library
import kotlinx.coroutines.* // official kotlin extension library
```
-### Recommendation 3.1.4: The declaration part of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Their declaration should be separated by blank lines.
-
-Note:
+### Recommendation 3.1.4: The declaration parts of class-like code structures (class, interface, etc.) should be placed in the order.
+The declaration parts of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Blank lines should separate their declaration.
+Notes:
1. There should be no blank lines between properties.
**Exceptions**: When there is a comment before a property on a separate line or annotations on a separate line.
2. Properties with comments/Kdoc should be separated by a newline before the comment/Kdoc.
@@ -649,7 +657,7 @@ The declaration part of a class or interface should be in the following order:
- Init-blocks
- Constructors
- Methods or nested classes. Put nested classes next to the code they are used by.
-If the classes are meant to be used externally and are not referenced inside the class, put them at the end after the companion object.
+If the classes are meant to be used externally and are not referenced inside the class, put them after the companion object.
- Companion object
**Exception:**
@@ -659,7 +667,7 @@ All variants of a `(private) val` logger should be placed in the beginning of th
### 3.2 Braces
### Rule 3.2.1: Braces must be used in conditional statements and loop blocks.
-In `if`, `else`, `for`, `do`, and `while` statements, even if the program body is empty or contains only one statement, braces should be used. In special Kotlin when statements, you do not need to use braces for statements with one line.
+Braces should always be used in `if`, `else`, `for`, `do`, and `while` statements, even if the program body is empty or contains only one statement. In special Kotlin `when` statements, you do not need to use braces for single-line statements.
**Valid example:**
@@ -672,7 +680,7 @@ when (node.elementType) {
CLASS -> checkClassElements(node)
}
```
-**Exception:** The only exception is ternary operator in Kotlin (it is a single line `if () <> else <>` )
+**Exception:** The only exception is ternary operator in Kotlin (a single line `if () <> else <>` )
**Invalid example:**
@@ -699,7 +707,7 @@ if (condition) {
### Rule 3.2.2 For *non-empty* blocks and block structures, the opening brace is placed at the end of the line
-The K&R style (1TBS or OTBS) should be followed for *non-empty* code blocks with braces:
+Follow the K&R style (1TBS or OTBS) for *non-empty* code blocks with braces:
- The opening brace and first line of the code block are on the same line.
- The closing brace is on its own new line.
- The closing brace can be followed by a newline. The only exceptions are `else`, `finally`, and `while` (from `do-while` statement), or `catch` keywords.
@@ -758,18 +766,18 @@ do {
### 3.3 Indentation
### Rule 3.3.1: Use spaces for indentation. Each indentation equals four spaces.
-Only spaces are permitted for indentation, and each indentation should equal `4 spaces` (tabs are not permitted).
+Only spaces are permitted for indentation, and each indentation should equal `four spaces` (tabs are not permitted).
If you prefer using tabs, simply configure them to automatically change to spaces in your IDE.
-These code blocks should be indented if they are placed on the new line and the following conditions are met:
-- The code block is placed immediately after an opening brace.
-- The code block is placed after each operator, including assignment operator (`+`/`-`/`&&`/`=`/etc.).
+These code blocks should be indented if they are placed on the new line, and the following conditions are met:
+- The code block is placed immediately after an opening brace
+- The code block is placed after each operator, including the assignment operator (`+`/`-`/`&&`/`=`/etc.)
- The code block is a call chain of methods:
```kotlin
someObject
.map()
.filter()
```
-- The code block is placed immediately the opening parenthesis.
+- The code block is placed immediately after the opening parenthesis.
- The code block is placed immediately after an arrow in lambda:
```kotlin
@@ -788,10 +796,10 @@ b) Arguments in argument lists can be aligned if they are on different lines.
3. Eight spaces are used for functional-like styles when the newline is placed before the dot.
4. Super type lists: \
-a) Four spaces are used if the colon before the super type list is on a new line. \
-b) Four spaces are used before each super type, and eight are used if the colon is on a new line.
+a) Four spaces are used if the colon before the supertype list is on a new line. \
+b) Four spaces are used before each supertype, and eight spaces are used if the colon is on a new line.
-**Note:** there should be an indentation after all statements such as `if`, `for`, etc.; however, according to this code style, such statements require braces.
+**Note:** there should be an indentation after all statements such as `if`, `for`, etc. However, according to this code style, such statements require braces.
```kotlin
if (condition)
@@ -799,7 +807,7 @@ if (condition)
```
**Exceptions**:
-- When breaking parameter list of a method/class constructor it can be aligned with `8 spaces`. Or a parameter that was moved to a new line can be on the same level as the previous argument:
+- When breaking parameter list of a method/class constructor it can be aligned with `8 spaces`. A parameter that was moved to a new line can be on the same level as the previous argument:
```kotlin
fun visit(
@@ -811,14 +819,14 @@ fun visit(
}
```
-- Operators like `+`/`-`/`*`/e.t.c can be indented with `8 spaces`:
+- Such operators as `+`/`-`/`*` can be indented with `8 spaces`:
```kotlin
val abcdef = "my splitted" +
" string"
```
-- List of super types should be indented with `4 spaces` if they are on different lines, or with `8 spaces` if leading colon is also on a separate line
+- A list of supertypes should be indented with `4 spaces` if they are on different lines, or with `8 spaces` if the leading colon is also on a separate line
```kotlin
class A :
@@ -831,14 +839,12 @@ class A
### 3.4 Empty blocks
-### Recommendation 3.4.1: Try to avoid empty blocks, and ensure braces start on a new line.
-
-An empty code block can be closed immediately on the same line, and on the next line. However, a newline is recommended between opening and closing braces `{}`.
-(See the examples below.)
+### Recommendation 3.4.1: Avoid empty blocks, and ensure braces start on a new line.
-**Generally, empty code blocks are prohibited** and are very bad practice (especially for catch block).
-They are only appropriate for overridden functions, when the functionality of the base class is not needed in the class-inheritor.
+An empty code block can be closed immediately on the same line and the next line. However, a newline is recommended between opening and closing braces `{}` (see the examples below.)
+Generally, empty code blocks are prohibited; using them is considered a bad practice (especially for catch block).
+They are only appropriate for overridden functions when the base class's functionality is not needed in the class-inheritor.
```kotlin
override fun foo() {
}
@@ -860,7 +866,7 @@ try {
} catch (e: Some) {}
```
-Use this valid code instead:
+Use the following valid code instead:
```kotlin
try {
doSomething()
@@ -872,11 +878,11 @@ try {
### 3.5 Line length
### Recommendation 3.5.1: Line length should be less than 120 symbols.
-This international code style prohibits `non-Latin` (`non-ASCII`) symbols.
+The international code style prohibits `non-Latin` (`non-ASCII`) symbols.
(See [Rule 1.1.1: Identifiers](#r1.1.1)) However, if you still intend on using them, follow the following convention:
- One wide character occupies the width of two narrow characters.
-The "wide" and "narrow" part of a character are defined by its [east asian width Unicode attribute](https://unicode.org/reports/tr11/).
+The "wide" and "narrow" parts of a character are defined by its [east Asian width Unicode attribute](https://unicode.org/reports/tr11/).
Typically, narrow characters are also called "half-width" characters.
All characters in the ASCII character set include letters (such as `a, A`), numbers (such as `0, 3`), and punctuation spaces (such as `,` , `{`), all of which are narrow characters.
Wide characters are also called "full-width" characters. Chinese characters (such as `中, 文`), Chinese punctuation (`,` , `;` ), full-width letters and numbers (such as `A、3`) are "full-width" characters.
@@ -886,14 +892,14 @@ Each one of these characters represents two narrow characters.
**Exceptions:**
-1. The long URL or long JSON method reference in KDoc
-2. The `package` and `import` statements
-3. The command line in the comment, enabling it to be cut and pasted into the shell for use
+1. The long URL or long JSON method reference in KDoc.
+2. The `package` and `import` statements.
+3. The command line in the comment, enabling it to be cut and pasted into the shell for use.
### 3.6 Line breaks (newlines)
### Recommendation 3.6.1: Each line can have a maximum of one statement.
-Each line can have a maximum of one code statement. This recommendation prohibits the use of code with `;`, because it worsens code visibility.
+Each line can have a maximum of one code statement. This recommendation prohibits the use of code with `;` because it decreases code visibility.
**Invalid example:**
```kotlin
@@ -908,13 +914,13 @@ val b = ""
### Rule 3.6.2: Rules for line-breaking
-1) Compared to Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline.
- There should be no redundant semicolon at the end of lines.
+1) Unlike Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline.
+ There should be no redundant semicolon at the end of the lines.
When a newline is needed to split the line, it should be placed after operators like `&&`/`||`/`+`/etc. and all infix functions (for example, `xor`).
However, the newline should be placed before operators such as `.`, `?.`, `?:`, and `::`.
-Note that all operators for comparing such as `==`, `>`, `<`, e.t.c should not be split.
+Note that all comparison operators, such as `==`, `>`, `<`, should not be split.
**Invalid example**:
```kotlin
@@ -929,7 +935,7 @@ Note that all operators for comparing such as `==`, `>`, `<`, e.t.c should not b
}
```
-**Note**, that you need to follow the functional style, meaning each function call in a chain with `.` should start at a new line if the chain of functions contains more than one call:
+**Note:** You need to follow the functional style, meaning each function call in a chain with `.` should start at a new line if the chain of functions contains more than one call:
```kotlin
val value = otherValue!!
.map { x -> x }
@@ -939,7 +945,7 @@ Note that all operators for comparing such as `==`, `>`, `<`, e.t.c should not b
}
.size
```
-**Note**, that parser prohibits the separation of operator `!!` from the value it is checking.
+**Note:** The parser prohibits the separation of the `!!` operator from the value it is checking.
**Exception**: If a functional chain is used inside the branches of a ternary operator, it does not need to be split with newlines.
@@ -953,8 +959,8 @@ if (condition) list.map { foo(it) }.filter { bar(it) } else list.drop(1)
A brace should be placed immediately after the name without any spaces in declarations or at call sites.
4) Newlines should be placed right after the comma (`,`).
5) If a lambda statement contains more than one line in its body, a newline should be placed after an arrow if the lambda statement has explicit parameters.
- If it uses an implicit parameter (`it`), the newline should be placed after the opening brace (`{`).
- See the following examples.
+ If it uses an implicit parameter (`it`), the newline should be placed after the opening brace (`{`).
+ The following examples illustrate this rule:
**Invalid example:**
@@ -974,8 +980,8 @@ value.map { name ->
val someValue = { node:String -> node }
```
-6) When the function contains only a single expression, it can be expressed as [expression function](https://kotlinlang.org/docs/reference/functions.html#single-expression-functions).
- The following style should not be used.
+6) When the function contains only a single expression, it can be written as [expression function](https://kotlinlang.org/docs/reference/functions.html#single-expression-functions).
+ The below example shows the style that should not be used.
Instead of:
```kotlin
@@ -1021,7 +1027,7 @@ fun foo(
}
```
-8) If super type list has more than 2 elements, they should be separated by newlines.
+8) If the supertype list has more than two elements, they should be separated by newlines
**Valid example:**
```kotlin
@@ -1035,9 +1041,8 @@ class MyFavouriteVeryLongClassHolder :
### 3.7 Blank lines
### Recommendation 3.7.1: Reduce unnecessary blank lines and maintain a compact code size
-By reducing unnecessary blank lines, you can display more code on one screen, which in turn improves code readability.
-
-- Blank lines should separate content based on relevance, and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [Rule 3.1.2](#r3.1.2)).
+By reducing unnecessary blank lines, you can display more code on one screen, which improves code readability.
+- Blank lines should separate content based on relevance and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [Rule 3.1.2](#r3.1.2)).
- Do not use more than one line inside methods, type definitions, and initialization expressions.
- Generally, do not use more than two consecutive blank lines in a row.
- Do not put newlines in the beginning or end of code blocks with curly braces.
@@ -1056,12 +1061,12 @@ fun baz() {
### 3.8 Horizontal space
### Rule 3.8.1: Usage of whitespace for code separation
-**Note:** This recommendation corresponds to cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space. (This logic is described in another rule.)
+**Note:** This recommendation is for the cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space (described in another rule.)
-1. All keywords (such as `if`, `when`, and `for`) should be separated with a single whitespace from the opening parenthesis.
- The only exception is the `constructor` keyword, which should not be separated.
+1. Separate keywords like `if`, `when`, `for`, e.t.c. from the opening parenthesis with single whitespace.
+ The only exception is the `constructor` keyword, which should not be separated from the opening parenthesis.
-2. Separate all keywords (such as `else` or `try`) from the opening brace (`{`) with a single whitespace.
+2. Separate keywords like `else` or `try` from the opening brace (`{`) with a single whitespace.
If `else` is used in a ternary-style statement without braces, there should be a single space between `else` and the statement after: `if (condition) foo() else bar()`
3. Use a **single** whitespace before all opening braces (`{`). The only exception is the passing of a lambda as a parameter inside parentheses:
@@ -1082,15 +1087,15 @@ fun baz() {
`Object::toString`
- The dot separator (`.`) that stays on the same line with an object name:\
`object.toString()`
-- Safe access modifiers: `?.` and `!!`, that stay on the same line with an object name:\
+- Safe access modifiers `?.` and `!!` that stay on the same line with an object name:\
`object?.toString()`
- Operator `..` for creating ranges:\
`1..100`
-5. Spaces should be used after (`,`), (`:`), and (`;`), except when the symbol is at the end of the line.
+5. Use spaces after (`,`), (`:`), and (`;`), except when the symbol is at the end of the line.
However, note that this code style prohibits the use of (`;`) in the middle of a line ([Rule 3.2.2](#r3.2.2)).
There should be no whitespaces at the end of a line.
- The only scenario where there should be no space after a colon is when the colon is used in annotation to specify a use-site target (for example, `@param:JsonProperty`).
+ The only scenario where there should be no space after a colon is when the colon is used in the annotation to specify a use-site target (for example, `@param:JsonProperty`).
There should be no spaces before `,` , `:` and `;`.
**Exceptions** for spaces and colons are the following:
@@ -1108,13 +1113,13 @@ fun baz() {
}
```
-6. There should be *only one space* between identifier and it's type: `list: List`
-If the type is nullable there should be no space before `?`.
+6. There should be *only one space* between the identifier and it's type: `list: List`
+If the type is nullable, there should be no space before `?`.
7. When using `[]` operator (`get/set`) there should be **no** spaces between identifier and `[` : `someList[0]`.
8. There should be no space between a method or constructor name (both at declaration and at call site) and a parenthesis:
- `foo() {}`. Note that this sub-rule is related only to spaces, the rules for whitespaces are described in [Rule 3.6.2](#r3.6.2).
+ `foo() {}`. Note that this sub-rule is related only to spaces; the rules for whitespaces are described in [Rule 3.6.2](#r3.6.2).
This rule does not prohibit, for example, the following code:
```kotlin
fun foo
@@ -1123,19 +1128,19 @@ fun foo
)
```
-9. Never put a space after `(`, `[`, `<` (when used as bracket in templates) or before `)`, `]`, `>` (when used as bracket in templates).
+9. Never put a space after `(`, `[`, `<` (when used as a bracket in templates) or before `)`, `]`, `>` (when used as a bracket in templates).
-10. There should be no spaces between prefix/postfix operator (like `!!` or `++`) and it's operand.
+10. There should be no spaces between prefix/postfix operator (like `!!` or `++`), and it's an operand.
### Recommendation 3.8.2: No spaces should be inserted for horizontal alignment.
-*Horizontal alignment* refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used, becuase:
+*Horizontal alignment* refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used because:
-- When modifying code, it takes a lot of time for new developers to format, support, and fix alignment issues.
+- When modifying code, it takes much time for new developers to format, support, and fix alignment issues.
- Long identifier names will break the alignment and lead to less presentable code.
- Alignment possesses more disadvantages than advantages. To reduce maintenance costs, misalignment is the best choice.
-Recommendation: Alignment only looks good for `enum class`, where it can be used in table format to improve code readability:
+Recommendation: Alignment only looks suitable for `enum class`, where it can be used in table format to improve code readability:
```kotlin
enum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean, private val warn: String) : Rule {
PACKAGE_NAME_MISSING (1, true, "no package name declared in a file"),
@@ -1160,7 +1165,7 @@ enum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean
### 3.9 Enumerations
### Recommendation 3.9.1: Enum values are separated by a comma and line break, with ';' placed on the new line.
-1) Enum values are separated by comma and a line break. `;` is put on the new line:
+1) Enum values are separated by a comma and a line break. `;` is put on the new line:
```kotlin
enum class Warnings {
A,
@@ -1170,15 +1175,15 @@ enum class Warnings {
}
```
-This will help resolve conflicts and reduce the value's number during merging pull requests.
+This will help to resolve conflicts and reduce the number of conflicts during merging pull requests.
Also use [trailing comma](https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma).
-2) If the enum is simple (no properties, methods, and comments inside), it can be declared in a single line:
+2) If the enum is simple (no properties, methods, and comments inside), you can declare it in a single line:
```kotlin
enum class Suit { CLUBS, HEARTS, SPADES, DIAMONDS }
```
-3) Enum classes take preference if possible, for example, instead of two Boolean properties like:
+3) Enum classes take preference (if it is possible to use it). For example, instead of two boolean properties:
```kotlin
val isCelsius = true
@@ -1186,12 +1191,13 @@ val isFahrenheit = false
```
use enum class:
+
```kotlin
enum class TemperatureScale { CELSIUS, FAHRENHEIT }
```
- The variable value only changes within a fixed range and is defined with the enum type.
-- Avoid comparison with magic numbers of `-1, 0, and 1`, instead of this use enums:
+- Avoid comparison with magic numbers of `-1, 0, and 1`; use enums instead.
```kotlin
enum class ComparisonResult {
@@ -1206,31 +1212,31 @@ enum class ComparisonResult {
### 3.10 Variable declaration
### Rule 3.10.1: Declare one variable per line.
-Each property or variable declaration must be declared on a separate line.
+Each property or variable must be declared on a separate line.
**Invalid example**:
```kotlin
val n1: Int; val n2: Int
```
-### Recommendation 3.10.2: Variables should be declared close to the line where they are first used.
-To minimize their scope, local variables should be declared close to the point where they are first used. This will also increase readability of the code.
-Local variables are usually initialized during declaration or initialized immediately after.
-The member fields of the class should be declared collectively (see [Rule 3.1.2](#s3.1.2) for details on class structure).
+### Recommendation 3.10.2: Variables should be declared near the line where they are first used.
+Declare local variables close to the point where they are first used to minimize their scope. This will also increase the readability of the code.
+Local variables are usually initialized during their declaration or immediately after.
+The member fields of the class should be declared collectively (see [Rule 3.1.2](#r3.1.2) for details on the class structure).
### 3.11 When expression
-### Rule 3.11.1: 'when' statements must have an 'else' branch, unless the condition variable is enumerated or a sealed type.
-Each `when` statement contains an `else` statement group, even if it does not contain any code.
+### Rule 3.11.1: The 'when' statement must have an 'else' branch unless the condition variable is enumerated or a sealed type.
+Each `when` statement should contain an `else` statement group, even if it does not contain any code.
-**Exception:** If a when statement of type `enum or sealed` contains all values of a enum - there is no need to have "else" branch.
+**Exception:** If 'when' statement of the `enum or sealed` type contains all enum values, there is no need to have an "else" branch.
The compiler can issue a warning when it is missing.
### 3.12 Annotations
### Recommendation 3.12.1: Each annotation applied to a class, method, or constructor should be placed on its own line.
-1. Annotations applied to the class, method, or constructor are placed on separate lines (one annotation per line).
+1. Annotations applied to the class, method or constructor are placed on separate lines (one annotation per line).
**Valid example**:
```kotlin
@@ -1246,7 +1252,7 @@ fun getNameIfPresent() { /* ... */ }
@CustomAnnotation class Foo {}
```
-3. 3. Multiple annotations applied to a field or property can appear on the same line as the field.
+3. Multiple annotations applied to a field or property can appear on the same line as the corresponding field.
**Valid example**:
```kotlin
@@ -1255,9 +1261,9 @@ fun getNameIfPresent() { /* ... */ }
### 3.13 Layout of comments
-### Recommendation 3.13.1: Block comments are at the same indentation level as the surrounding code.
+### Recommendation 3.13.1: Block comments location.
-Block comments are at the same indentation level as the surrounding code. See examples below.
+Block comments should be placed at the same indentation level as the surrounding code. See examples below.
**Valid example**:
@@ -1275,7 +1281,7 @@ class SomeClass {
### 3.14 Modifiers and constant values
-### Recommendation 3.14.1: If a declaration has multiple modifiers, always follow proper sequence.
+### Recommendation 3.14.1: If a declaration has multiple modifiers, always follow the proper sequence.
**Valid sequence:**
```kotlin
@@ -1300,9 +1306,8 @@ operator
data
```
-### Recommendation 3.14.2: Long numerical values should be separated by an underscore.
-
-**Note:** Underscores make it easier to read and find errors in numeric constants.
+### Recommendation 3.14.2: An underscore should separate long numerical values.
+**Note:** Using underscores simplifies reading and helps to find errors in numeric constants.
```kotlin
val oneMillion = 1_000_000
val creditCardNumber = 1234_5678_9012_3456L
@@ -1313,8 +1318,8 @@ val bytes = 0b11010010_01101001_10010100_10010010
### 3.15 Strings
-### Rule 3.15.1: Concatenation of Strings is prohibited if the string can fit on one line. Use raw strings and string templates instead.
-Kotlin has significantly improved the use of Strings:
+### Rule 3.15.1: Concatenation of Strings is prohibited if the string can fit on one line.
+String concatenation is prohibited if the string can fit on one line. Use raw strings and string templates instead. Kotlin has significantly improved the use of Strings:
[String templates](https://kotlinlang.org/docs/reference/basic-types.html#string-templates), [Raw strings](https://kotlinlang.org/docs/reference/basic-types.html#string-literals)
As such, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines and you do not need to split them with newlines.
@@ -1331,9 +1336,9 @@ val value = "$myStr concatenated"
```
### Rule 3.15.2: String template format
-**Redundant curly braces in string templates.**
+**Redundant curly braces in string templates**
-In case string template contains only one variable, - there is no need to use string template. Use this variable directly.
+If there is only one variable in a string template, there is no need to use such a template. Use this variable directly.
**Invalid example**:
```kotlin
val someString = "${myArgument} ${myArgument.foo()}"
@@ -1344,7 +1349,8 @@ val someString = "${myArgument} ${myArgument.foo()}"
val someString = "$myArgument ${myArgument.foo()}"
```
-**Redundant string template.**
+**Redundant string template**
+
In case string template contains only one variable - there is no need to use string template. Use this variable directly.
**Invalid example**:
@@ -1361,34 +1367,33 @@ val someString = myArgument
### 4.1 Variables
### Rule 4.1.1: Do not use Float and Double types when accurate calculations are needed.
Floating-point numbers provide a good approximation over a wide range of values, but they cannot produce accurate results in some cases.
-Binary floating-point numbers are unsuitable for precise calculations, because it is impossible to represent 0.1 or any other negative power of 10 in a `binary representation` with a finite length.
+Binary floating-point numbers are unsuitable for precise calculations because it is impossible to represent 0.1 or any other negative power of 10 in a `binary representation` with a finite length.
-The following example seems to be simple code that is obvious:
+The following code example seems to be obvious:
```kotlin
val myValue = 2.0 - 1.1
println(myValue)
```
-However, it will print a value such as: `0.8999999999999999`
+However, it will print the following value: `0.8999999999999999`
-As such, if you need to make precise calculations (for example, when dealing with currency, finance, or an exact science), `Int`, `Long`, `BigDecimal`, etc. are recommended.
-Among them, `BigDecimal` should serve as a good choice.
+Therefore, for precise calculations (for example, in finance or exact sciences), using such types as `Int`, `Long`, `BigDecimal`are recommended.
+The `BigDecimal` type should serve as a good choice.
**Invalid example:** \
-If a float value contains more than six to seven decimal numbers, it will be rounded off.
+Float values containing more than six or seven decimal numbers will be rounded.
```kotlin
val eFloat = 2.7182818284f // Float, will be rounded to 2.7182817
```
-**Valid example** (when accurate calculations are needed):
+**Valid example** (when precise calculations are needed):
```kotlin
val income = BigDecimal("2.0")
val expense = BigDecimal("1.1")
println(income.subtract(expense)) // you will obtain 0.9 here
```
-### Rule 4.1.2: The numbers of a float type should not be directly compared with the equality operator (==) or other methods like compareTo and equals.
-
+### Rule 4.1.2: Numeric float type values should not be directly compared with the equality operator (==) or other methods like `compareTo()` and `equals()`.
Since floating-point numbers involve precision problems in computer representation, it is better to use `BigDecimal` as recommended in [Rule 4.1.1](#r4.1.1) to make accurate computations and comparisons. The following code describes these problems.
**Invalid example**:
@@ -1425,9 +1430,9 @@ if (abs(foo - bar) > 1e-6f) {
### Rule 4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR].
Variables with the `val` modifier are immutable (read-only).
-Code robustness and readability increase through the use of such variables, as opposed to `var` variables.
-This is because var variables can be reassigned several times in the business logic.
-Of course, in some scenarios with loops or accumulators, only `var`s are permitted.
+Code robustness and readability increase when using `val` variables instead of `var` variables.
+This is because `var` variables can be reassigned several times in the business logic.
+However, in some scenarios with loops or accumulators, only `var`s are permitted.
### 4.2 Types
@@ -1462,7 +1467,7 @@ fun bar(x: String?) {
}
```
-Smart cast and contracts are better because they reduce boilerplate code and forced type conversion.
+Smart cast and contracts are a better choice because they reduce boilerplate code and features forced type conversion.
**Invalid example**:
```kotlin
@@ -1480,12 +1485,12 @@ fun foo(s: String?) {
}
```
-### Recommendation 4.2.2: Try to use type alias to represent types and make code more readable.
+### Recommendation 4.2.2: Try to use type alias to represent types making code more readable.
Type aliases provide alternative names for existing types.
-If the type name is too long, you can replace it with a shorter name. It helps to shorten long generic types.
+If the type name is too long, you can replace it with a shorter name, which helps to shorten long generic types.
For example, code looks much more readable if you introduce a `typealias` instead of a long chain of nested generic types.
-We recommend the use of a `typealias` if the type contains **more than two** nested generic types and is longer than **25 chars**.
+We recommend using a `typealias` if the type contains **more than two** nested generic types and is longer than **25 chars**.
**Invalid example**:
```kotlin
@@ -1510,7 +1515,7 @@ typealias Predicate = (T) -> Boolean
Kotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types.
### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib.
-To avoid `NullPointerException` and help compiler checks prevent NPE, try to avoid using nullable types (with `?` symbol).
+To avoid `NullPointerException` and help compiler to prevent Null Poniter Exceptions, avoid using nullable types (with `?` symbol).
**Invalid example**:
```kotlin
@@ -1523,8 +1528,8 @@ val a: Int = 0
```
Nevertheless, if you use Java libraries extensively, you will have to use nullable types and enrich your code with `!!` and `?` symbols.
-Avoid using nullable types for Kotlin stdlib (declared in [official documentation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/)) avoid using nullable types.
-Try to use initializers for empty collections. ), and try using initializers for empty collections. For example: If you want to initialize a list instead of using `null` use `emptyList()`.
+Avoid using nullable types for Kotlin stdlib (declared in [official documentation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/)).
+Try to use initializers for empty collections. For example, if you want to initialize a list instead of `null` use `emptyList()`.
**Invalid example**:
```kotlin
@@ -1537,14 +1542,14 @@ val a: List = emptyList()
```
### Recommendation 4.3.2: Variables of generic types should have an explicit type declaration.
-As in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments:
+Like in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments:
```kotlin
val myVariable: Map = emptyMap()
```
-However, the compiler can inherit type parameters from the right value, and as such, will not force users to explicitly declare the type.
-These declarations are not recommended because programmers would need to find its return value and understand the variable type by looking at the method.
+However, the compiler can inherit type parameters from the r-value (value assigned to a variable). Therefore, it will not force users to declare the type explicitly.
+These declarations are not recommended because programmers would need to find the return value and understand the variable type by looking at the method.
**Invalid example**:
```kotlin
@@ -1563,48 +1568,47 @@ You should utilize this approach, along with functional style, when you write Ko
The concepts behind functional style are as follows:
Functions are the smallest unit of combinable and reusable code.
They should have clean logic, **high cohesion**, and **low coupling** to effectively organize the code.
-The code in functions should be simple, and should not conceal the author's original intentions.
+The code in functions should be simple and not conceal the author's original intentions.
Additionally, it should have a clean abstraction, and control statements should be used in a straightforward manner.
-The side effects (code that does not affect a function's return value, but affects global/object instance variables) should not be used for state changes.
+The side effects (code that does not affect a function's return value, but affects global/object instance variables) should not be used for state changes of an object.
The only exceptions to this are state machines.
-Kotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming.
-This language features built-in mechanisms that support functional programming. In addition, standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments.
+Kotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming, featuring the corresponding built-in mechanisms.
+In addition, standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments.
As [previously discussed](#r4.1.3), Kotlin supports and encourages the use of immutable types, which in turn motivates programmers to write pure functions that avoid side effects and have a corresponding output for specific input.
-The pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls and each step features the following characteristics:
-1. Simple
-2. Verifiable
-3. Testable
-4. Replaceable
-5. Pluggable
-6. Extensible
+The pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls, and each step features the following characteristics:
+1. Simplicity
+2. Verifiability
+3. Testability
+4. Replaceability
+5. Pluggability
+6. Extensibility
7. Immutable results
-There can be only one side effect in this data stream, which can be placed only at the end of execution queue.
+There can be only one side effect in this data stream, which can be placed only at the end of the execution queue.
-### Rule 5.1.1: Avoid functions that are too long. They should consist of 30 lines (non-empty and non-comment) in total.
+### Rule 5.1.1: Avoid functions that are too long.
The function should be displayable on one screen and only implement one certain logic.
-If a function is too long, it often means that it is complex and be split or made more primitive.
+If a function is too long, it often means that it is complex and be split or made more primitive. Functions should consist of 30 lines (non-empty and non-comment) in total.
**Exception:** Some functions that implement complex algorithms may exceed 30 lines due to aggregation and comprehensiveness.
Linter warnings for such functions **can be suppressed**.
-Even if a long function works well, new problems or bugs due to complex logic may appear once it is modified by someone else.
-As such, it is recommended that you split such functions into several separated and shorter ones that are easier to manage.
-This will enable other programmers to read and modify the code properly.
-
-### Rule 5.1.2: Avoid deep nesting of function code blocks. It should be limited to four levels.
+Even if a long function works well, new problems or bugs may appear due to the function's complex logic once it is modified by someone else.
+Therefore, it is recommended that you split such functions into several separate and shorter functions that are easier to manage.
+This approach will enable other programmers to read and modify the code properly.
+### Rule 5.1.2: Avoid deep nesting of function code blocks, limiting to four levels.
The nesting depth of a function's code block is the depth of mutual inclusion between the code control blocks in the function (for example: if, for, while, and when).
Each nesting level will increase the amount of effort needed to read the code because you need to remember the current "stack" (for example, entering conditional statements and loops).
-**Exception:** The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function, and the nesting levels of enclosing methods are not accumulated.
-Functional decomposition should be implemented to avoid confusing for the developer who read the code.
+**Exception:** The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function wheres the nesting levels of enclosing methods are not accumulated.
+Functional decomposition should be implemented to avoid confusion for the developer who reads the code.
This will help the reader switch between context.
### Rule 5.1.3: Avoid using nested functions.
-Nested functions create more complex function context, thereby confusing readers.
-Additionally, the visibility context may not be obvious to the reader of the code.
+Nested functions create a more complex function context, thereby confusing readers.
+With nested functions the visibility context may not be evident to the code reader.
**Invalid example**:
```kotlin
@@ -1618,9 +1622,9 @@ fun foo() {
### 5.2 Function arguments
-### Rule 5.2.1: The lambda parameter of the function should be placed last in the argument list.
+### Rule 5.2.1: The lambda parameter of the function should be placed at the end of the argument list.
-With a such notation, it is easier to use curly brackets, which in turn leads to code with better readability.
+With such notation, it is easier to use curly brackets, which in turn leads to better code readability.
**Valid example**:
```kotlin
@@ -1635,17 +1639,16 @@ println("hey")
}
```
-### Rule 5.2.2: Number of parameters of function should be limited to 5
+### Rule 5.2.2: Number of function parameters should be limited to 5
A long argument list is a [code smell](https://en.wikipedia.org/wiki/Code_smell) that leads to less reliable code.
-If there are **more than five** parameters, maintenance becomes more difficult and conflicts become much more difficult to merge.
-As such, it is recommended that you reduce the number of parameters.
-If groups of parameters appear in different functions multiple times, these parameters are closely related and can be encapsulated into a single Data Class.
+It is recommended that you reduce the number of parameters. Having **more than five** parameters leads to difficulties in maintenance and conflicts merging.
+If parameter groups appear in different functions multiple times, these parameters are closely related and can be encapsulated into a single Data Class.
It is recommended that you use Data Classes and Maps to unify these function arguments.
### Rule 5.2.3 Use default values for function arguments instead of overloading them
-In Java default values for function arguments are prohibited. That's why each time when it is needed to create a function with less arguments, this function should be overloaded.
-In Kotlin you can use default arguments instead.
+In Java, default values for function arguments are prohibited. That is why when you need to create a function with fewer arguments, the function should be overloaded.
+In Kotlin, you can use default arguments instead.
**Invalid example**:
```kotlin
@@ -1693,15 +1696,14 @@ class Test private constructor(var a: Int) {
```
### Rule 6.1.2: Prefer data classes instead of classes without any functional logic.
-Some people say that data class - is a code smell. But in case you really need to use it and your x1code is becoming more simple because of that -
-you can use Kotlin `data classes`. Main purpose of these classes is to hold data.
-But also `data classes` will automatically generate several useful methods:
+Some people say that the data class is a code smell. But if you need to use it, and as a result, your code is becoming more simple, you can use Kotlin `data class`. The main purpose of this class is to hold data,
+but also `data class` will automatically generate several useful methods:
- equals()/hashCode() pair;
- toString()
- componentN() functions corresponding to the properties in their order of declaration;
- copy() function
-So instead of using `normal` classes:
+Therefore, instead of using `normal` classes:
```kotlin
class Test {
@@ -1730,18 +1732,17 @@ class Test() {
}
```
-**Prefer:**
+**prefer data classes:**
```kotlin
data class Test1(var a: Int = 0, var b: Int = 0)
```
-**Exception #1**: Note, that data classes cannot be abstract, open, sealed or inner, that's why these types of classes cannot be changed to data class.
+**Exception #1**: Note, that data classes cannot be abstract, open, sealed or inner, that's why these types of classes cannot be changed to a data class.
-**Exception #2**: No need to convert a class to data class in case this class extends some other class or implements an interface.
+**Exception #2**: No need to convert a class to data class if this class extends some other class or implements an interface.
-### Rule 6.1.3: Do not use the primary constructor if it is empty and has no sense.
-The primary constructor is part of the class header: it goes after the class name (and optional type parameters).
-But in is useless - it can be omitted.
+### Rule 6.1.3: Do not use the primary constructor if it is empty or useless.
+The primary constructor is a part of the class header; it goes after the class name and (optional) type parameters but can be omitted if it is useless.
**Invalid example**:
```kotlin
@@ -1778,11 +1779,11 @@ class Test {
### Rule 6.1.4: several init blocks are redundant and generally should not be used in your class.
The primary constructor cannot contain any code. That's why Kotlin has introduced `init` blocks.
These blocks are used to store the code that should be run during the initialization of the class.
-Kotlin allows to write multiple initialization blocks that are executed in the same order as they appear in the class body.
-Even when you have the [Rule 3.1.2](#r3.1.2) this makes code less readable as the programmer needs to keep in mind all init blocks and trace the execution of the code.
-So in your code you should try to use single `init` block to reduce the complexity. In case you need to do some logging or make some calculations before the assignment
-of some class property - you can use powerful functional programming. This will reduce the possibility of the error, when occasionally someone will change the order of your `init` blocks.
-And it will make the logic of the code more coupled. It is always enough to use one `init` block to implement your idea in Kotlin.
+Kotlin allows writing multiple initialization blocks that are executed in the same order as they appear in the class body.
+Even when you follow (rule 3.2)[#r3.2], this makes your code less readable as the programmer needs to keep in mind all init blocks and trace the execution of the code.
+So in your code, you should try to use a single `init` block to reduce the complexity. In case you need to do some logging or make some calculations before the assignment
+of some class property, you can use powerful functional programming. This will reduce the possibility of the error if your `init` blocks' order is accidentally changed and
+make the code logic more coupled. It is always enough to use one `init` block to implement your idea in Kotlin.
**Invalid example**:
```kotlin
@@ -1813,9 +1814,9 @@ class YourClass(var name: String) {
}
```
-Also - init block was not added to Kotlin to help you simply initialize your properties it is needed for more complex tasks.
-So if `init` block contains only assignments of variables - move it directly to properties, so they will be correctly initialized near the declaration.
-In some case this rule can be in clash with [6.1.1](#r6.1.1), but that should not stop you.
+The `init` block was not added to Kotlin to help you initialize your properties; it is needed for more complex tasks.
+Therefore if the `init` block contains only assignments of variables - move it directly to properties, so that they will be correctly initialized near the declaration.
+In some cases, this rule can be in clash with [6.1.1](#r6.1.1), but that should not stop you.
**Invalid example**:
```kotlin
@@ -1851,8 +1852,8 @@ class Square() : Rectangle() {
```
### Rule 6.1.6: Abstract class should have at least one abstract method.
-Abstract classes are used to force a developer to implement some of its parts in its inheritors.
-In case when abstract class has no abstract methods - then it was set `abstract` incorrectly and can be converted to a normal class.
+Abstract classes are used to force a developer to implement some of its parts in their inheritors.
+When the abstract class has no abstract methods, it was set `abstract` incorrectly and can be converted to a regular class.
**Invalid example**:
```kotlin
@@ -1882,7 +1883,7 @@ class NotAbstract {
### Rule 6.1.7: in case of using "implicit backing property" scheme, the name of real and back property should be the same.
Kotlin has a mechanism of [backing properties](https://kotlinlang.org/docs/reference/properties.html#backing-properties).
-In some cases implicit backing is not enough and it should be done explicitly:
+In some cases, implicit backing is not enough and it should be done explicitly:
```kotlin
private var _table: Map? = null
val table: Map
@@ -1894,45 +1895,52 @@ val table: Map
}
```
-In this case the name of backing property (`_table`) should be the same to the name of real property (`table`), but should have underscore (`_`) prefix.
+In this case the name of the backing property (`_table`) should be the same as the name of the real property (`table`) but should have an underscore (`_`) prefix.
It is one of the exceptions from the [identifier names rule](#r1.2)
### Recommendation 6.1.8: avoid using custom getters and setters.
Kotlin has a perfect mechanism of [properties](https://kotlinlang.org/docs/reference/properties.html#properties-and-fields).
-Kotlin compiler automatically generates `get` and `set` methods for properties and also lets the possibility to override it:
+Kotlin compiler automatically generates `get` and `set` methods for properties and also provides the possibility to override it.
+
+**Invalid example:**
```kotlin
-// Bad example ======
class A {
var size: Int = 0
set(value) {
println("Side effect")
field = value
}
- get() = this.hashCode() * 2
+ // user of this class does not expect calling A.size receive size * 2
+ get() = field * 2
}
```
From the callee code these methods look like an access to this property: `A().isEmpty = true` for setter and `A().isEmpty` for getter.
-But in all cases it is very confusing when `get` and `set` are overriden for a developer who uses this particular class.
-Developer expects to get the value of the property, but receives some unknown value and some extra side effect hidden by the custom getter/setter.
-Use extra functions for it instead.
-**Invalid example:**
+However, when `get` and `set` are overridden, it is very confusing for a developer who uses this particular class.
+The developer expects to get the property value but receives some unknown value and some extra side-effect hidden by the custom getter/setter.
+Use extra functions instead to avoid confusion.
+
+
+
+**Valid example**:
```kotlin
-// Bad example ======
class A {
var size: Int = 0
fun initSize(value: Int) {
// some custom logic
}
- fun goodNameThatDescribesThisGetter() = this.hashCode() * 2
+ // this will not confuse developer and he will get exactly what he expects
+ fun goodNameThatDescribesThisGetter() = this.size * 2
}
```
+**Exception:** `Private setters` are only exceptions that are not prohibited by this rule.
+
### Rule 6.1.9: never use the name of a variable in the custom getter or setter (possible_bug).
-Even if you have ignored [recommendation 6.1.8](#r6.1.8) you should be careful with using the name of the property in your custom getter/setter
-as it can accidentally cause a recursive call and a `StackOverflow Error`. Use `field` keyword instead.
+If you have ignored [recommendation 6.1.8](#r6.1.8) you should be careful with using the name of the property in your custom getter/setter
+as it can accidentally cause a recursive call and a `StackOverflow Error`. Use the `field` keyword instead.
**Invalid example (very bad)**:
```kotlin
@@ -1945,9 +1953,9 @@ var isEmpty: Boolean
```
### Recommendation 6.1.10 no trivial getters and setters are allowed in the code.
-In Java - trivial getters - are getters that are simply returning the value of a field.
-Trivial setters - are simply setting the field with a value without any transformation.
-But in Kotlin trivial getters/setters are generated by the default. There is no need to use it explicitly for all types of data-structures in Kotlin.
+In Java, trivial getters - are the getters that are just returning the field value.
+Trivial setters - are merely setting the field with a value without any transformation.
+However, in Kotlin, trivial getters/setters are generated by the default. There is no need to use it explicitly for all types of data structures in Kotlin.
**Invalid example**:
```kotlin
@@ -1972,9 +1980,9 @@ class A {
```
### Rule 6.1.11: use apply for grouping object initialization.
-In the good old Java before functional programming became popular - lot of classes from commonly used libraries used configuration paradigm.
-To use these classes you had to create an object with the constructor that had 0-2 arguments and set the fields that were needed to run an object.
-In Kotlin to reduce the number of dummy code lines and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added:
+In Java, before functional programming became popular, many classes from common libraries used configuration paradigm.
+To use these classes, you had to create an object with the constructor with 0-2 arguments and set the fields needed to run the object.
+In Kotlin, to reduce the number of dummy code line and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added:
**Invalid example**:
```kotlin
@@ -2020,16 +2028,17 @@ fun main() {
### 6.2 Extension functions
-[Extension functions](https://kotlinlang.org/docs/reference/extensions.html) - is a killer-feature in Kotlin.
+[Extension functions](https://kotlinlang.org/docs/reference/extensions.html) is a killer-feature in Kotlin.
It gives you a chance to extend classes that were already implemented in external libraries and help you to make classes less heavy.
Extension functions are resolved statically.
### Recommendation 6.2.1: use extension functions for making logic of classes less coupled.
-It is recommended that for classes non-tightly coupled functions with rare usages in the class should be implemented as extension functions where possible.
-They should be implemented in the same class/file where they are used. This is non-deterministic rule, so it cannot be checked or fixed automatically by static analyzer.
+It is recommended that for classes, the non-tightly coupled functions, which are rarely used in the class, should be implemented as extension functions where possible.
+They should be implemented in the same class/file where they are used. This is a non-deterministic rule, so the code cannot be checked or fixed automatically by a static analyzer.
-### Rule 6.2.2: there should be no extension functions with the same name and signature if they extend base and inheritor classes (possible_bug).
-As extension functions are resolved statically. In this case there can be a situation when a developer implements two extension functions - one is for the base class and another one for the inheritor.
+### Rule 6.2.2: No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug).
+As extension functions are resolved statically. In this case, there could be a situation when a developer implements two extension functions: one is for the base class and another for the inheritor.
+This can lead to an issue when an incorrect method is used.
And that can lead to an issue when incorrect method is used.
**Invalid example**:
@@ -2050,18 +2059,17 @@ fun main() { printClassName(B()) }
### 6.3 Interfaces
-`Interface`s in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state.
+An `Interface` in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state.
They can have properties, but these need to be abstract or to provide accessor implementations.
Kotlin's interfaces can define attributes and functions.
-In Kotlin and Java, the interface is the main presentation means of application programming interface (API) design, and should take precedence over the use of (abstract) classes.
+In Kotlin and Java, the interface is the main presentation means of application programming interface (API) design and should take precedence over the use of (abstract) classes.
### 6.4 Objects
### Rule 6.4.1: Avoid using utility classes/objects, use extensions instead.
-As described in [6.2 Extension functions](#c6.2) - extension functions - is a very powerful mechanism.
-So instead of using utility classes/objects, use it instead.
-This allows you to remove the unnecessary complexity and wrapping class/object and to use top-level functions instead.
+As described in [6.2 Extension functions](#c6.2), extension functions are a powerful. Instead of using utility classes/objects, use it extention functions.
+This allows you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead.
**Invalid example**:
```kotlin
@@ -2083,8 +2091,8 @@ fun String.stringInfo(): Int {
```
### Recommendation 6.4.2: Objects should be used for Stateless Interfaces.
-Kotlin’s object are extremely useful when we need to implement a some interface from an external library that doesn’t have any state.
-No need to use class for such structures.
+Kotlin’s objects are extremely useful when you need to implement some interface from an external library that doesn’t have any state.
+There is no need to use classes for such structures.
**Valid example**:
```
diff --git a/info/guide/guide-chapter-0.md b/info/guide/guide-chapter-0.md
index 3bcff49394..0b04b6b4f8 100644
--- a/info/guide/guide-chapter-0.md
+++ b/info/guide/guide-chapter-0.md
@@ -2,7 +2,9 @@
### Purpose of this document
-For code to be considered "good", it must entail the following characteristics:
+The purpose of this document is to provide a specification that software developers could reference to enhance their ability to write consistent, easy-to-read, and high-quality code.
+Such a specification will ultimately improve software development efficiency and product competitiveness.
+For the code to be considered high-quality, it must entail the following characteristics:
1. Simplicity
2. Maintainability
3. Reliability
@@ -11,55 +13,52 @@ For code to be considered "good", it must entail the following characteristics:
6. Portability
7. Reusability
-Programming is a profession that involves creativity.
-Software developers can reference this specification, which will enhance their ability to write consistent, easy-to-read, and high-quality code.
-This will ultimately improve product competitiveness and software development efficiency.
### General principles
-As a very modern and advanced programming language (completely like other languages), Kotlin complies with the following general principles:
-1. Clarity: Clarity is a necessary feature of programs that are easy to maintain and refactor.
-2. Simplicity: Simple code is easy to understand and implement.
-3. Consistency: Unification is particularly important when the same team works on the same project, utilizing similar styles. It enables code to be easily modified, reviewed, and understood by the team members.
+Like other modern programming languages, Kotlin is an advanced programming language that complies with the following general principles:
+1. Clarity — a necessary feature of programs that are easy to maintain and refactor.
+2. Simplicity — a code is easy to understand and implement.
+3. Consistency — enables a code to be easily modified, reviewed and understood by the team members. Unification is particularly important when the same team works on the same project, utilizing similar styles.enables code to be easily modified, reviewed and understood by the team members.
-In addition, we need to consider the following factors when programming on Kotlin:
+Also, we need to consider the following factors when programming on Kotlin:
-1. Write clean and simple Kotlin code
+1. Writing clean and simple Kotlin code
Kotlin combines two of the main programming paradigms: functional and object-oriented.
- Both of these paradigms are trusted, well-known software engineering practices.
- As a young programming language, Kotlin builds on well-established languages such as Java, C++, C#, and Scala.
- This is why Kotlin introduces many features that help you write cleaner, more readable code, while also reducing the number of complex code structures. For example: type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, when statements, much easier work with collections, type auto conversion, and other syntactic sugar.
+ Both of these paradigms are trusted and well-known software engineering practices.
+ As a young programming language, Kotlin is built on the top of well-established languages such as Java, C++, C#, and Scala.
+ This enables Kotlin to introduce many features that help you write cleaner, more readable code, while also reducing the number of complex code structures. For example, type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, when statements, much easier work with collections, type auto conversion, and other syntactic sugar.
-2. Follow Kotlin idioms
+2. Following Kotlin idioms
- The author of Kotlin, Andrey Breslav, mentioned that it is both pragmatic and practical, but not academic.
- Its pragmatic features enable ideas to easily be transformed into real working software. This programming language is closer to natural languages than its predecessors, and it implements the following design principles: readability, reusability, interoperability, security, and tool-friendliness (https://blog.jetbrains.com/kotlin/2018/10/kotlinconf-2018-announcements/).
+ The author of Kotlin, Andrey Breslav, mentioned that Kotlin is both pragmatic and practical, but not academic.
+ Its pragmatic features enable ideas to be transformed into real working software easily. Kotlin is closer to natural languages than its predecessors, and it implements the following design principles: readability, reusability, interoperability, security, and tool-friendliness (https://blog.jetbrains.com/kotlin/2018/10/kotlinconf-2018-announcements/).
-3. Use Kotlin efficiently
+3. Using Kotlin efficiently
- Some Kotlin features help you write higher-performance code: including rich coroutine library, sequences, inline functions/classes, arrays of basic types, tailRec, and CallsInPlace of contract.
+ Some Kotlin features can help you to write higher-performance code: including rich coroutine library, sequences, inline functions/classes, arrays of basic types, tailRec, and CallsInPlace of contract.
### Terminology
-**Rules**: conventions that should be followed when programming.
+**Rules** — conventions that should be followed when programming.
-**Recommendations**: conventions that should be considered when programming.
+**Recommendations** — conventions that should be considered when programming.
-**Explanation**: necessary explanations of rules and recommendations.
+**Explanation** — necessary explanations of rules and recommendations.
-**Valid Example**: examples (recommended) of rules and recommendations.
+**Valid Example** — recommended examples of rules and recommendations.
-**Invalid Example**: examples (not recommended) of rules and recommendations.
+**Invalid Example** — not recommended examples of rules and recommendations.
Unless otherwise stated, this specification applies to versions 1.3 and later of Kotlin.
### Exceptions
-Even though exceptions may exist, it is important to understand why rules and recommendations are needed.
-Depending on your project situation or personal habits, you can break some of the rules. However, remember that one exception leads to many and can completely destroy the consistency of code. As such, there should be very few exceptions.
-When modifying open-source code or third-party code, you can choose to implement the style used by the code (as opposed to using the existing specifications) to maintain consistency.
-Software that is directly based on the interface of the Android native operating system, such as the Android Framework, remains consistent with the Android style.
+Even though exceptions may exist, it is essential to understand why rules and recommendations are needed.
+Depending on your project situation or personal habits, you can break some of the rules. However, remember that one exception may lead to many and eventually can destroy code consistency. As such, there should be very few exceptions.
+When modifying open-source code or third-party code, you can choose to use the code style from this open-source project (instead of using the existing specifications) to maintain consistency.
+Software that is directly based on the Android native operating system interface, such as the Android Framework, remains consistent with the Android style.
\ No newline at end of file
diff --git a/info/guide/guide-chapter-1.md b/info/guide/guide-chapter-1.md
index 74f60c863d..75aaa2eadb 100644
--- a/info/guide/guide-chapter-1.md
+++ b/info/guide/guide-chapter-1.md
@@ -1,18 +1,20 @@
# 1. Naming
-In programming, it is difficult to meaningfully and appropriately name variables, functions, classes, etc. Good names clearly express the main ideas and functionality of your code, as well as avoid misinterpretation, unnecessary coding and decoding, magic numbers, and inappropriate abbreviations.
+In programming, it is not always easy to meaningfully and appropriately name variables, functions, classes, etc. Using meaningful names helps you clearly express your code's main ideas and functionality and avoid misinterpretation, unnecessary coding and decoding, "magic" numbers, and inappropriate abbreviations.
-### Rule 1.0.1: file encoding format must be UTF-8 only
-The source file encoding format (including comments) must be UTF-8 only. The ASCII horizontal space character (0x20, that is, space) is the only permitted whitespace character. Tabs should not be used for indentation.
+Note: The source file encoding format (including comments) must be UTF-8 only. The ASCII horizontal space character (0x20, that is, space) is the only permitted whitespace character. Tabs should not be used for indentation.
-### 1.1 Identifiers naming
-### Rule 1.1.1: Identifiers
+### 1.1 Identifier names
+### 1.1.1: Identifiers naming conventions
+
+For identifiers, use the following naming conventions:
1. All identifiers should use only ASCII letters or digits, and the names should match regular expressions `\w{2,64}`.
Explanation: Each valid identifier name should match the regular expression `\w{2,64}`.
`{2,64}` means that the name length is 2 to 64 characters, and the length of the variable name should be proportional to its life range, functionality, and responsibility.
-Name lengths of less than 31 characters are generally recommended, but this depends on the project. Otherwise, class declaration with generics or inheritance from a super class can cause line breaking for example. No special prefix or suffix should be used in the names. The following examples are inappropriate: name_, mName, s_name, and kName.
+Name lengths of less than 31 characters are generally recommended. However, this depends on the project. Otherwise, a class declaration with generics or inheritance from a superclass can cause line breaking.
+No special prefix or suffix should be used in the names. The following examples are inappropriate: name_, mName, s_name, and kName.
-2. For files, choose names that describe their content. Use camel case (PascalCase) and `.kt` extension.
+2. Choose file names that would describe the content. Use camel case (PascalCase) and `.kt` extension.
3. Typical examples of naming:
@@ -30,14 +32,13 @@ Name lengths of less than 31 characters are generally recommended, but this depe
val `my dummy name-with-minus` = "value"
```
-The only exception is function names in `Unit tests`.
+The only exception is function names in `Unit tests.`
5. Backticks (``) should not be used for identifiers, except the names of test methods (marked with @Test annotation):
```kotlin
@Test fun `my test`() { /*...*/ }
```
-6. The following table contains some characters that cause confusion. Be careful when using them as identifiers, or use other names instead.
-
+6. The following table contains some characters that may cause confusion. Be careful when using them as identifiers. To avoid issues, use other names instead.
| Expected | Confusing name | Suggested name |
| ------------- | ------------------------ | ---------------- |
| 0 (zero) | O, D | obj, dgt |
@@ -50,29 +51,31 @@ The only exception is function names in `Unit tests`.
| rn, m | m,rn | mbr, item |
**Exceptions**
-- The i,j,k variables used in loops are part of the industry standard. One symbol can be used for for such variables.
+- The i,j,k variables used in loops are part of the industry standard. One symbol can be used for such variables.
- The `e` variable can be used to catch exceptions in catch block: `catch (e: Exception) {}`
-- The Java community generally does not recommend the use of prefixes; however, when developing Android code, you can use the s and m prefixes for static and non-public non-static fields, respectively.
-Note that prefixing can also negatively affect the style, as well as the auto generation of getters and setters.
+- The Java community generally does not recommend the use of prefixes. However, when developing Android code, you can use the s and m prefixes for static and non-public non-static fields, respectively.
+Note that prefixing can also negatively affect the style and the auto-generation of getters and setters.
| Type | Naming style |
| ---- | ---- |
-| Interfaces, classes, annotations, enumerated types, and object type names | Camel case starting with a capital letter. Test classes have a Test suffix. The filename is 'TopClassName'.kt. |
-| Class fields, local variables, methods, and method parameters | Camel case starting with a small letter. Test methods may be underlined with '_'., the only exception is [backing properties](#r6.1.7)
+| Interfaces, classes, annotations, enumerated types, and object type names | Camel case, starting with a capital letter. Test classes have a Test suffix. The filename is 'TopClassName'.kt. |
+| Class fields, local variables, methods, and method parameters | Camel case starting with a low case letter. Test methods can be underlined with '_'; the only exception is [backing properties](#r6.1.7).
| Static constants and enumerated values | Only uppercase underlined with '_' |
| Generic type variable | Single capital letter, which can be followed by a number, for example: `E, T, U, X, T2` |
| Exceptions | Same as class names, but with a suffix Exception, for example: `AccessException` and `NullPointerException`|
### 1.2 Packages names
-### Rule 1.2.1: Package names are in lower case and separated by dots. Code developed within your company should start with `your.company.domain`, and numbers are permitted in package names.
-Package names are all written in lowercase, and consecutive words are simply concatenated together (no underscores). Package names should contain both the product and module names, as well as the department or team name to prevent conflicts with other teams. Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`.
+### Rule 1.2.1: Package names dots
+Package names are in lower case and separated by dots. Code developed within your company should start with `your.company.domain.` Numbers are permitted in package names.
+Each file should have a `package` directive.
+Package names are all written in lowercase, and consecutive words are concatenated together (no underscores). Package names should contain both the product and module names, and the department (or team) name to prevent conflicts with other teams. Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`.
**Exceptions:**
-- In certain cases, such as open-source projects or commercial cooperation, package names should not start with `your.company.domain`.- In some cases, if the package name starts with a number or other characters, but these characters cannot be used at the beginning of the Java/Kotlin package name, or the package name contains reserved Java keywords, underscores are allowed.
-- Underscores are sometimes permitted if the package name starts with a number or other character, which cannot be used at the beginning of the Java/Kotlin package name; or the package name contains reserved Java keywords. For example: org.example.hyphenated_name, int_.example, com.example._123name
-For example: `org.example.hyphenated_name`,` int_.example`, `com.example._123name`
+- In certain cases, such as open-source projects or commercial cooperation, package names should not start with `your.company.domain.`
+- If the package name starts with a number or other characters that cannot be used at the beginning of the Java/Kotlin package name, then underscores are allowed. For example: `com.example._123name`.
+- Underscores are sometimes permitted if the package name contains reserved Java/Kotlin keywords, such as `org.example.hyphenated_name`, `int_.example`.
**Valid example**:
```kotlin
@@ -81,13 +84,13 @@ package your.company.domain.mobilecontrol.views
### 1.3 Classes, enumerations, interfaces
-### Rule 1.3.1: Classes, enumerations, interface names use camel case nomenclature
+### Rule 1.3.1: Classes, enumerations, interface names use Camel case
+Classes, enumerations, and interface names use `UpperCamelCase` nomenclature. Follow the naming rules described below:
+1. A class name is usually a noun (or a noun phrase) denoted using the camel case nomenclature, such as UpperCamelCase. For example: `Character` or `ImmutableList`.
+An interface name can also be a noun or noun phrase (such as `List`) or an adjective or adjective phrase (such as `Readable`).
+Note that verbs are not used to name classes. However, nouns (such as `Customer`, `WikiPage`, and `Account`) can be used. Try to avoid using vague words such as `Manager` and `Process`.
-1. The class name is usually a noun or a noun phrase using the camel case nomenclature, such as UpperCamelCase. For example: `Character` or `ImmutableList`.
-The name of an interface can also be a noun or noun phrase (such as `List`), or an adjective or adjective phrase (such as `Readable`).
-Note that verbs should not be used to name classes; however, nouns (such as `Customer`, `WikiPage`, and `Account`) can be used. Try to avoid vague words like Manager and Process.
-
-2. Test classes start with the name of the class they are testing and end with Test. For example: HashTest or HashIntegrationTest
+2. Test classes start with the name of the class they are testing and end with 'Test'. For example, `HashTest` or `HashIntegrationTest`.
**Invalid example**:
```kotlin
@@ -107,19 +110,19 @@ class Order {}
### 1.4 Functions
-### Rule 1.4.1: function names should be in camel case
-
-1. Function names are usually verbs or verb phrases, and use the camel case nomenclature (`lowerCamelCase`).
+### Rule 1.4.1: Function names should be in camel case
+Function names should use `lowerCamelCase` nomenclature. Follow the naming rules described below:
+1. Function names are usually verbs or verb phrases denoted with the camel case nomenclature (`lowerCamelCase`).
For example: `sendMessage`, `stopProcess`, or `calculateValue`.
-The format is as follows:
+To name functions use the following formatting rules:
-a) To get, modify, or calculate a certain value: get + non-boolean field(). However, note that getters are automatically generated by the Kotlin compiler for some classes, and the special get syntax is preferred for fields: kotlin private val field: String get() { }.
+a) To get, modify, or calculate a certain value: get + non-boolean field(). Note that the Kotlin compiler automatically generates getters for some classes, applying the special syntax preferred for the 'get' fields: kotlin private val field: String get() { }. kotlin private val field: String get() { }.
```kotlin
private val field: String
get() {
}
```
-Additionally, calling property access syntax is preferred to calling getter directly. (In this case, the Kotlin compiler will automatically call the corresponding getter).
+Note: The calling property access syntax is preferred to call getter directly. In this case, the Kotlin compiler automatically calls the corresponding getter.
b) `is` + boolean variable name()
@@ -128,11 +131,11 @@ c) `set` + field/attribute name(). However, note that the syntax and code genera
d) `has` + Noun / adjective ()
e) verb()
-The verb is mainly used on the object of the action itself, such as `document.print ()`
+Note: Note: Verb are primarily used for the action objects, such as `document.print ()`
f) verb + noun()
-g) The Callback function allows for names that use the preposition + verb format, such as: `onCreate()`, `onDestroy()`, `toString()`.
+g) The Callback function allows the names that use the preposition + verb format, such as: `onCreate()`, `onDestroy()`, `toString()`.
**Invalid example**:
@@ -154,22 +157,22 @@ fun draw()
fun addKeyListener(Listener)
```
-2. An underscore can be included in the JUnit test function name, and should be a logical component used to separate names. Each logical part is written in lowerCamelCase. For example: a typical pattern _, such as pop_emptyStack
-
+2. An underscore (`_`) can be included in the JUnit test function name and should be used as a separator. Each logical part denoted in `lowerCamelCase`, for example, a typical pattern of using underscore: `pop_emptyStack`.
-### 1.5 Constants
-### Rule 1.5.1 Constant names should be in UPPER case, words separated by underscore
+### 1.5 Constants
+### Rule 1.5.1 Constant names should be in UPPER case, words in the name are separated by underscore
+Constant names should be in UPPER case, words separated by underscore. The jeneral constant naming conventions are listed below:
+1. Constants are attributes created with the `const` keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed.
-1. Constants are attributes created with the const keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant value that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. If an object state can be changed, the value is not a constant.
+1. Constants are attributes created with the const keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant value that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. If an object state can be changed, the value is not a constant.
2. Constant names should contain only uppercase letters separated by underscores. They should have a val or const val modifier to explicitly make them final. In most cases, if you need to specify a constant value, then you need to create it with the "const val" modifier. Note that not all `val` variables are constants.
-
3. Objects that have immutable content, such as `Logger` and `Lock`, can be in uppercase as constants or have camel case as regular variables.
4. Use meaningful constants instead of `magic numbers`. SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants.
Magic constants like `NUM_FIVE = 5` or `NUM_5 = 5` should not be treated as constants. This is because mistakes will easily be made if they are changed to `NUM_5 = 50` or 55.
-Typically, these constants represent business logic values like measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms.
-Magic numbers can be avoided through the following methods:
+These constants typically represent business logic values, such as measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms.
+You can avoid using magic numbers with the following method:
- Using library functions and APIs. For example, instead of checking that `size == 0`, use `isEmpty()` function. To work with `time`, use built-ins from `java.time API`.
- Enumerations can be used to name patterns. Refer to [Recommended usage scenario for enumeration in 3.9](#c3.9)
@@ -189,12 +192,12 @@ const val String APPLICATION_NAME = "Launcher";
### 1.6 Non-constant fields (variables)
-### Rule 1.6.1: The name of the non-constant field should use camel case and start with a lowercase letter.
-
-A local variable cannot be treated as a constant even if it is final and immutable. Therefore, it should not use the preceding rules. The name of variables with a type from collections (sets, lists, etc.) should contain plural nouns.
+### Rule 1.6.1: Non-constant field name
+Non-constant field names should use camel case and start with a lowercase letter.
+A local variable cannot be treated as a constant even if it is final and immutable. Therefore, it should not use the preceding rules. Names of collection type variables (sets, lists, etc.) should contain plural nouns.
For example: `var namesList: List`
-Names of non-constant variables should use lower camel case. The name of the final immutable field used to store the singleton object can use the same notation with camel case.
+Names of non-constant variables should use `lowerCamelCase`. The name of the final immutable field used to store the singleton object can use the same camel case notation.
**Invalid example**:
```kotlin
@@ -209,13 +212,13 @@ val users: List = listOf();
val mutableCollection: MutableSet = HashSet()
```
-### Recommendation 1.6.2: Avoid using Boolean variable names with negative meaning.
+### Rule 1.6.2: Boolean variable names with negative meaning
-*Note*: When using a logical operator and name with negative meaning, the code may be difficult to understand, which is referred to as the "double negative".
+Avoid using Boolean variable names with negative meaning. When using a logical operator and name with negative meaning, the code may be difficult to understand, which is referred to as the "double negative".
For instance, it is not easy to understand the meaning of !isNotError.
The JavaBeans specification automatically generates isXxx() getters for attributes of Boolean classes.
-However, methods that return Boolean type do not all have this notation.
-For Boolean local variables or methods, it is highly recommended that you add non-meaningful prefixes, including is (which is commonly used by JavaBeans), or has, can, should, must. Modern integrated development environments (IDEs) such as Intellij are already capable of doing this for you when you generate getters in Java. For Kotlin, this process is even easier as everything is on the byte-code level under the hood.
+However, not all methods returning Boolean type have this notation.
+For Boolean local variables or methods, it is highly recommended that you add non-meaningful prefixes, including is (commonly used by JavaBeans), has, can, should, and must. Modern integrated development environments (IDEs) such as Intellij are already capable of doing this for you when you generate getters in Java. For Kotlin, this process is even more straightforward as everything is on the byte-code level under the hood.
**Invalid example**:
```kotlin
diff --git a/info/guide/guide-chapter-2.md b/info/guide/guide-chapter-2.md
index 4a87f99ed2..9949be1ea7 100644
--- a/info/guide/guide-chapter-2.md
+++ b/info/guide/guide-chapter-2.md
@@ -1,12 +1,12 @@
# 2. Comments
-The best practice involves beginning your code with a short summary, which can be one sentence.
-You should balance between writing no comments at all and obvious comments for each line of code.
+The best practice is to begin your code with a summary, which can be one sentence.
+Try to balance between writing no comments at all and obvious commentary statements for each line of code.
Comments should be accurately and clearly expressed, without repeating the name of the class, interface, or method.
-Comments are not a solution to bad code. Instead, you should fix the code as soon as you notice an issue, or plan to fix it (with a TODO comment including a Jira number).
-Comments should accurately reflect the design ideas and logic of the code, and then describe the code's business logic.
+Comments are not a solution to the wrong code. Instead, you should fix the code as soon as you notice an issue or plan to fix it (by entering a TODO comment, including a Jira number).
+Comments should accurately reflect the code's design ideas and logic and further describe its business logic.
As a result, other programmers will be able to save time when trying to understand the code.
-Imagine that you are writing the comments to help your future self understand the original ideas behind the code.
+Imagine that you are writing the comments to help yourself to understand the original ideas behind the code in the future.
### 2.1 General form of Kdoc
@@ -28,7 +28,7 @@ It is also shown in the following single-line form:
```kotlin
/** Short form of KDoc. */
```
-When the entire KDoc block can be stored in one line (and there is no KDoc mark @XXX), a single-line form can be used. For detailed instructions on how to use KDoc, refer to [Official Document](https://docs.oracle.com/en/Kotlin/Kotlinse/11/tools/KDoc.html).
+Use a single-line form when you store the entire KDoc block in one line (and there is no KDoc mark @XXX). For detailed instructions on how to use KDoc, refer to [Official Document](https://docs.oracle.com/en/Kotlin/Kotlinse/11/tools/KDoc.html).
### Rule 2.1.1: KDoc is used for each public, protected or internal code element
@@ -65,12 +65,11 @@ class Example(
)
```
-Exceptions:
+**Exceptions:**
-1. For setters/getters of properties obvious comments are optional.
- (Note that simple `get/set` methods are generated by Kotlin under the hood). For example, getFoo can also be `return foo`.
+1. For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note, that Kotlin generates simple `get/set` methods under the hood.
-2. It is optional to add comments for simple one-line methods like:
+2. It is optional to add comments for simple one-line methods, such as shown in the example below:
```kotlin
val isEmpty: Boolean
get() = this.size == 0
@@ -82,9 +81,11 @@ or
fun isEmptyList(list: List) = list.size == 0
```
-3. You can skip KDocs for a method's override if the method is almost like the super class method.
+Note: You can skip KDocs for a method's override if it is almost the same as the superclass method.
+### Rule 2.1.2: Describing methods with arguments, return value or can throw exceptions
+When the method has arguments, return value, or can throw exceptions, it must be described in the KDoc block: with @param, @return, @throws
-### Rule 2.1.2: When the method has arguments, return value, can throw exceptions, etc., it must be described in the KDoc block: with @param, @return, @throws, etc.
+### Rule 2.1.2: When the method has arguments, return value, can throw exceptions, etc., it must be described in the KDoc block: with @param, @return, @throws, etc.
**Valid examples**:
@@ -119,27 +120,29 @@ fun isEmptyList(list: List) = list.size == 0
}
```
-### Rule 2.1.3: There is only one space between the Kdoc tag and content. Tags are arranged in the following order: @param, @return, and @throws
+### Rule 2.1.3: Only one space between the Kdoc tag and content. Tags are arranged in the order.
+There should be only one space between the Kdoc tag and content. Tags are arranged in the following order: @param, @return, and @throws.
-This is how Kdoc should look like and what it should contain:
+Therefore, Kdoc should contain the following:
- Functional and technical description, explaining the principles, intentions, contracts, API, etc.
- The function description and @tags (`implSpec`, `apiNote`, and `implNote`) require an empty line after them.
- `@implSpec`: A specification related to API implementation, and it should let the implementer decide whether to override it.
-- `@apiNote`: Explain the API precautions, including whether to allow null and whether the method is thread safe, as well as the algorithm complexity, input and output range, exceptions, etc.
+- `@apiNote`: Explain the API precautions, including whether to allow null and whether the method is thread-safe, as well as the algorithm complexity, input, and output range, exceptions, etc.
- `@implNote`: A note related to API implementation, which implementers should keep in mind.
-- Then one empty line, followed by regular `@param`, `@return`, `@throws` and other comments.
-- The conventional standard "block labels" are arranged in order: `@param`, `@return`, `@throws`.
-- Empty descriptions in tag blocks are not permitted. It is better not to write Kdoc than to waste code line on empty space.
+- One empty line, followed by regular `@param`, `@return`, `@throws`, and other comments.
+- The conventional standard "block labels" arranged in the following order: `@param`, `@return`, `@throws`.
+Kdoc should not contain:
+- Empty descriptions in tag blocks. It is better not to write Kdoc than waste code line space.
- There should be no empty lines between the method/class declaration and the end of Kdoc (`*/` symbols).
-- (!) KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation.
+Important note: KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation.
-If a tag block cannot be described in one line, you should indent the content of the new line by `4 spaces` from the `@` position to achieve alignment (`@` counts as one + three spaces).
+If a tag block cannot be described in one line, you should indent the content of the new line by `four spaces` from the `@` position to achieve alignment (`@` counts as one + three spaces).
-**Exception:** When the descriptive text in a tag block is too long to wrap, the alignment can be indented with the descriptive text in the previous line. The descriptive text of multiple tags does not need to be aligned.
+**Exception:** When the descriptive text in a tag block is too long to wrap, you can indent the alignment with the descriptive text in the last line. The descriptive text of multiple tags does not need to be aligned.
See [3.8 Horizontal space](#c3.8).
-In Kotlin compared to Java you are able to put several classes inside one file so each class should have a Kdoc formatted comment (this is also stated in rule 2.1).
-This comment should contain @since tag. The good style is to write the version of the application when functionality was released. It should be written after a `@since` tag.
+In Kotlin, compared to Java, you are able to put several classes inside one file, so each class should have a Kdoc formatted comment (as stated in rule 2.1).
+This comment should contain @since tag. The right style is to write the application version when its functionality is released. It should be entered after the `@since` tag.
**Examples:**
@@ -164,7 +167,7 @@ Other KDoc tags (such as @param type parameters and @see.) can be added as follo
### 2.2 Comments to the file header
### Rule 2.2.1: Comments on the file header must include copyright information, without the creation date and author's name (use VCS for history management instead). The content inside files that contain multiple or no classes should also be described.
-Comments on the file header should be stored before the package name and imports. If you need to add more content to the comment, you can subsequently add it in the same format.
+Comments on the file header should be placed before the package name and imports. If you need to add more content to the comment, you can subsequently add it in the same format.
The following examples for Huawei describe the format of the **copyright license**: \
Chinese version: `版权所有 (c) 华为技术有限公司 2012-2020` \
@@ -189,28 +192,28 @@ The following example is a copyright statement for Huawei, without other functio
```
The following factors should be considered when writing the file header or comments for top-level classes:
-- File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc `*/` symbol. If it is a comment for a top-level class, class declaration should start immediately without using a newline.
-- Maintain a unified format. The specific format can be formulated by the project (for example, in opensource) and you need to follow it.
+- File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc `*/` symbol. If it is a comment for a top-level class, the class declaration should start immediately without using a newline.
+- Maintain a unified format. The specific format can be formulated by the project (for example, if you use existing opensource project), and you need to follow it.
- A top-level file-Kdoc must include a copyright and functional description, especially if there is more than one top-level class.
-- Do not include empty comment blocks. As described in the preceding example, if there is no content after the option `@apiNote`, the entire tag block should be deleted.
-- The industry does not include historical information in comments. The corresponding history can be found in VCS (git, svn, etc.). As such, it is not recommended to include historical data in the comments of the Kotlin source code.
+- Do not include empty comment blocks.If there is no content after the option `@apiNote`, the entire tag block should be deleted.
+- The industry practice is not to include historical information in comments. The corresponding history can be found in VCS (git, svn, etc.). Therefore, it is not recommended to include historical data in the comments of the Kotlin source code.
### 2.3 Comments on the function header
-### Rule 2.3.1: Do not use or make unnecessary and useless comments.
+### Rule 2.3.1: Do not make unnecessary and useless comments.
Comments on the function header are placed above function declarations or definitions. A newline should not exist between a function declaration and its Kdoc. Use the preceding [KDoc](#c2.1) style rules.
-In Chapter 1 of the current code style, we stated that the function name should self-comment its functionality as much as possible. Therefore, in the Kdoc, try to mention things that are not stored in the function name.
+As stated in Chapter 1, the function name should reflect its functionality as much as possible. Therefore, in the Kdoc, try to describe the functionality that is not mentioned in the function name.
Avoid unnecessary comments on dummy coding.
-The content of the function header comment is optional, but not limited to function description, return value, performance constraints, usage, memory conventions, algorithm implementation, reentrant requirements, etc.
-The module's external interface declaration and its comments should clearly convey important and useful information.
+The function header comment's content is optional, but not limited to function description, return value, performance constraints, usage, memory conventions, algorithm implementation, reentrant requirements, etc.
### 2.4 Code comments
-### Rule 2.4.1: Add a blank line between the body of the comment and Kdoc tag-blocks. There must be one space between the comment's character and content. There must be a newline between a Kdoc and the preceding code.
-
-- There must be one space between the comment character and the content of the comment; there must be a newline between a Kdoc and the previous code above.
-An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular name space (code block) (for example, between the function declaration and first comment in a function body).
+### Rule 2.4.1: Add a blank line between the body of the comment and Kdoc tag-blocks.
+It is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules:
+- There must be one space between the comment character and the content of the comment
+- There must be a newline between a Kdoc and the pressiding code
+- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular name space (code block) (for example, between the function declaration and first comment in a function body).
**Valid Examples:**
```kotlin
@@ -252,7 +255,7 @@ An empty line should not exist between a Kdoc and the code it is describing. You
```
- Leave one single space between the comment on the right side of the code and the code.
-Conditional comments in the `if-else-if` scenario: To help other programmers understand the code, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`.
+If you use conditional comments in the `if-else-if` scenario, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`. This makes your code more understandable.
When the if-block is used with curly braces, the comment should be placed on the next line after opening the curly braces.
Compared to Java, the `if` statement in Kotlin statements returns a value. For this reason, a comment block can describe a whole `if-statement`.
@@ -287,16 +290,16 @@ val someVal = if (nr % 15 == 0) {
val x = 0 // this is a comment
```
-### Rule 2.4.2: Do not comment unused code blocks (including imports). Delete these code blocks immediately.
-
-Code is not used to store history. git, svn, or other VCS tools should be used for this purpose.
+### Rule 2.4.2: Do not comment on unused code blocks
+Do not comment on unused code blocks, including imports. Delete these code blocks immediately.
+A code is not used to store history. Git, svn, or other VCS tools should be used for this purpose.
Unused imports increase the coupling of the code and are not conducive to maintenance. The commented out code cannot be properly maintained.
When you attempt to reuse the code, there is a high probability that you will introduce defects that are easily missed.
The correct approach is to delete the unnecessary code directly and immediately when it is not used.
If you need the code again, consider porting or rewriting it as changes could have occurred since you first commented on the code.
-### Recommendation 2.4.3: Code formally delivered to the client typically should not contain TODO/FIXME comments.
-
+### Recommendation 2.4.3: Code delivered to the client should not contain TODO/FIXME comments.
+The code officially delivered to the client typically should not contain TODO/FIXME comments.
`TODO` comments are typically used to describe modification points that need to be improved and added. For example, refactoring FIXME comments are typically used to describe known defects and bugs that will be subsequently fixed and are not critical for an application.
They should all have a unified style to facilitate the unified text search processing.
@@ -306,4 +309,4 @@ They should all have a unified style to facilitate the unified text search proce
// FIXME: Jira-XXX - fix NPE in this code block
```
-In the version development stage, these annotations can be used to highlight the issues in code, but all of them should be fixed before a new product version is released.
+At a version development stage, these annotations can be used to highlight the issues in the code, but all of them should be fixed before a new product version is released.
\ No newline at end of file
diff --git a/info/guide/guide-chapter-3.md b/info/guide/guide-chapter-3.md
index 01f440d06a..0425a8780e 100644
--- a/info/guide/guide-chapter-3.md
+++ b/info/guide/guide-chapter-3.md
@@ -3,14 +3,13 @@
### 3.1 File-related rules
### Rule 3.1.1: Avoid files that are too long. Files should not exceed 2000 lines (non-empty and non-commented lines).
-If the file is too long, it is probably complex and can therefore be split into smaller files, functions, or modules.
-It is recommended that you horizontally or vertically split the file according to responsibilities or hierarchy, respectively.
-Code generation is the only exception to this.
-Auto-generated files that are not manually modified can be longer.
+If the file is too long and complex, it should be split into smaller files, functions, or modules.
+It is recommended to horizontally or vertically split the file according to responsibilities or hierarchy of its parts.
+The only exception to this rule is code generation - the auto-generated files that are not manually modified can be longer.
-### Rule 3.1.2: A source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line.
-
-a) They should be in the following order:
+### Rule 3.1.2: Code blocks in the source file should be separated by one blank line.
+A source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line.
+a) Code blocks should be in the following order:
1. Kdoc for licensed or copyrighted files
2. `@file` annotation
3. Package name
@@ -24,7 +23,9 @@ c) Import statements are alphabetically arranged, without using line breaks and
d) **Recommendation**: One `.kt` source file should contain only one class declaration, and its name should match the filename
-### Recommendation 3.1.3: Import statements should appear in the following order: Android, internal company imports, external imports, java core dependencies, and Kotlin standard library. Each group should be separated by a blank line.
+e) Avoid empty files that do not contain the code or contain only imports/comments/package name
+
+### Recommendation 3.1.3: Import statements order.
From top to bottom, the order is the following:
1. Android
@@ -33,7 +34,7 @@ From top to bottom, the order is the following:
4. Java core packages
5. kotlin stdlib
-Each category should be alphabetically arranged. This style is compatible with [Android import order](https://source.android.com/setup/contribute/code-style#order-import-statements).
+Each category should be alphabetically arranged. Each group should be separated by a blank line. This style is compatible with [Android import order](https://source.android.com/setup/contribute/code-style#order-import-statements).
**Valid example**:
```kotlin
@@ -54,9 +55,9 @@ import kotlin.system.exitProcess // kotlin standard library
import kotlinx.coroutines.* // official kotlin extension library
```
-### Recommendation 3.1.4: The declaration part of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Their declaration should be separated by blank lines.
-
-Note:
+### Recommendation 3.1.4: The declaration parts of class-like code structures (class, interface, etc.) should be placed in the order.
+The declaration parts of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Blank lines should separate their declaration.
+Notes:
1. There should be no blank lines between properties.
**Exceptions**: When there is a comment before a property on a separate line or annotations on a separate line.
2. Properties with comments/Kdoc should be separated by a newline before the comment/Kdoc.
@@ -69,7 +70,7 @@ The declaration part of a class or interface should be in the following order:
- Init-blocks
- Constructors
- Methods or nested classes. Put nested classes next to the code they are used by.
-If the classes are meant to be used externally and are not referenced inside the class, put them at the end after the companion object.
+If the classes are meant to be used externally and are not referenced inside the class, put them after the companion object.
- Companion object
**Exception:**
@@ -79,7 +80,7 @@ All variants of a `(private) val` logger should be placed in the beginning of th
### 3.2 Braces
### Rule 3.2.1: Braces must be used in conditional statements and loop blocks.
-In `if`, `else`, `for`, `do`, and `while` statements, even if the program body is empty or contains only one statement, braces should be used. In special Kotlin when statements, you do not need to use braces for statements with one line.
+Braces should always be used in `if`, `else`, `for`, `do`, and `while` statements, even if the program body is empty or contains only one statement. In special Kotlin `when` statements, you do not need to use braces for single-line statements.
**Valid example:**
@@ -92,7 +93,7 @@ when (node.elementType) {
CLASS -> checkClassElements(node)
}
```
-**Exception:** The only exception is ternary operator in Kotlin (it is a single line `if () <> else <>` )
+**Exception:** The only exception is ternary operator in Kotlin (a single line `if () <> else <>` )
**Invalid example:**
@@ -119,7 +120,7 @@ if (condition) {
### Rule 3.2.2 For *non-empty* blocks and block structures, the opening brace is placed at the end of the line
-The K&R style (1TBS or OTBS) should be followed for *non-empty* code blocks with braces:
+Follow the K&R style (1TBS or OTBS) for *non-empty* code blocks with braces:
- The opening brace and first line of the code block are on the same line.
- The closing brace is on its own new line.
- The closing brace can be followed by a newline. The only exceptions are `else`, `finally`, and `while` (from `do-while` statement), or `catch` keywords.
@@ -178,18 +179,18 @@ do {
### 3.3 Indentation
### Rule 3.3.1: Use spaces for indentation. Each indentation equals four spaces.
-Only spaces are permitted for indentation, and each indentation should equal `4 spaces` (tabs are not permitted).
+Only spaces are permitted for indentation, and each indentation should equal `four spaces` (tabs are not permitted).
If you prefer using tabs, simply configure them to automatically change to spaces in your IDE.
-These code blocks should be indented if they are placed on the new line and the following conditions are met:
-- The code block is placed immediately after an opening brace.
-- The code block is placed after each operator, including assignment operator (`+`/`-`/`&&`/`=`/etc.).
+These code blocks should be indented if they are placed on the new line, and the following conditions are met:
+- The code block is placed immediately after an opening brace
+- The code block is placed after each operator, including the assignment operator (`+`/`-`/`&&`/`=`/etc.)
- The code block is a call chain of methods:
```kotlin
someObject
.map()
.filter()
```
-- The code block is placed immediately the opening parenthesis.
+- The code block is placed immediately after the opening parenthesis.
- The code block is placed immediately after an arrow in lambda:
```kotlin
@@ -208,10 +209,10 @@ b) Arguments in argument lists can be aligned if they are on different lines.
3. Eight spaces are used for functional-like styles when the newline is placed before the dot.
4. Super type lists: \
-a) Four spaces are used if the colon before the super type list is on a new line. \
-b) Four spaces are used before each super type, and eight are used if the colon is on a new line.
+a) Four spaces are used if the colon before the supertype list is on a new line. \
+b) Four spaces are used before each supertype, and eight spaces are used if the colon is on a new line.
-**Note:** there should be an indentation after all statements such as `if`, `for`, etc.; however, according to this code style, such statements require braces.
+**Note:** there should be an indentation after all statements such as `if`, `for`, etc. However, according to this code style, such statements require braces.
```kotlin
if (condition)
@@ -219,7 +220,7 @@ if (condition)
```
**Exceptions**:
-- When breaking parameter list of a method/class constructor it can be aligned with `8 spaces`. Or a parameter that was moved to a new line can be on the same level as the previous argument:
+- When breaking parameter list of a method/class constructor it can be aligned with `8 spaces`. A parameter that was moved to a new line can be on the same level as the previous argument:
```kotlin
fun visit(
@@ -231,14 +232,14 @@ fun visit(
}
```
-- Operators like `+`/`-`/`*`/e.t.c can be indented with `8 spaces`:
+- Such operators as `+`/`-`/`*` can be indented with `8 spaces`:
```kotlin
val abcdef = "my splitted" +
" string"
```
-- List of super types should be indented with `4 spaces` if they are on different lines, or with `8 spaces` if leading colon is also on a separate line
+- A list of supertypes should be indented with `4 spaces` if they are on different lines, or with `8 spaces` if the leading colon is also on a separate line
```kotlin
class A :
@@ -251,14 +252,12 @@ class A
### 3.4 Empty blocks
-### Recommendation 3.4.1: Try to avoid empty blocks, and ensure braces start on a new line.
-
-An empty code block can be closed immediately on the same line, and on the next line. However, a newline is recommended between opening and closing braces `{}`.
-(See the examples below.)
+### Recommendation 3.4.1: Avoid empty blocks, and ensure braces start on a new line.
-**Generally, empty code blocks are prohibited** and are very bad practice (especially for catch block).
-They are only appropriate for overridden functions, when the functionality of the base class is not needed in the class-inheritor.
+An empty code block can be closed immediately on the same line and the next line. However, a newline is recommended between opening and closing braces `{}` (see the examples below.)
+Generally, empty code blocks are prohibited; using them is considered a bad practice (especially for catch block).
+They are only appropriate for overridden functions when the base class's functionality is not needed in the class-inheritor.
```kotlin
override fun foo() {
}
@@ -280,7 +279,7 @@ try {
} catch (e: Some) {}
```
-Use this valid code instead:
+Use the following valid code instead:
```kotlin
try {
doSomething()
@@ -292,11 +291,11 @@ try {
### 3.5 Line length
### Recommendation 3.5.1: Line length should be less than 120 symbols.
-This international code style prohibits `non-Latin` (`non-ASCII`) symbols.
+The international code style prohibits `non-Latin` (`non-ASCII`) symbols.
(See [Rule 1.1.1: Identifiers](#r1.1.1)) However, if you still intend on using them, follow the following convention:
- One wide character occupies the width of two narrow characters.
-The "wide" and "narrow" part of a character are defined by its [east asian width Unicode attribute](https://unicode.org/reports/tr11/).
+The "wide" and "narrow" parts of a character are defined by its [east Asian width Unicode attribute](https://unicode.org/reports/tr11/).
Typically, narrow characters are also called "half-width" characters.
All characters in the ASCII character set include letters (such as `a, A`), numbers (such as `0, 3`), and punctuation spaces (such as `,` , `{`), all of which are narrow characters.
Wide characters are also called "full-width" characters. Chinese characters (such as `中, 文`), Chinese punctuation (`,` , `;` ), full-width letters and numbers (such as `A、3`) are "full-width" characters.
@@ -306,14 +305,14 @@ Each one of these characters represents two narrow characters.
**Exceptions:**
-1. The long URL or long JSON method reference in KDoc
-2. The `package` and `import` statements
-3. The command line in the comment, enabling it to be cut and pasted into the shell for use
+1. The long URL or long JSON method reference in KDoc.
+2. The `package` and `import` statements.
+3. The command line in the comment, enabling it to be cut and pasted into the shell for use.
### 3.6 Line breaks (newlines)
### Recommendation 3.6.1: Each line can have a maximum of one statement.
-Each line can have a maximum of one code statement. This recommendation prohibits the use of code with `;`, because it worsens code visibility.
+Each line can have a maximum of one code statement. This recommendation prohibits the use of code with `;` because it decreases code visibility.
**Invalid example:**
```kotlin
@@ -328,13 +327,13 @@ val b = ""
### Rule 3.6.2: Rules for line-breaking
-1) Compared to Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline.
- There should be no redundant semicolon at the end of lines.
+1) Unlike Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline.
+ There should be no redundant semicolon at the end of the lines.
When a newline is needed to split the line, it should be placed after operators like `&&`/`||`/`+`/etc. and all infix functions (for example, `xor`).
However, the newline should be placed before operators such as `.`, `?.`, `?:`, and `::`.
-Note that all operators for comparing such as `==`, `>`, `<`, e.t.c should not be split.
+Note that all comparison operators, such as `==`, `>`, `<`, should not be split.
**Invalid example**:
```kotlin
@@ -349,7 +348,7 @@ Note that all operators for comparing such as `==`, `>`, `<`, e.t.c should not b
}
```
-**Note**, that you need to follow the functional style, meaning each function call in a chain with `.` should start at a new line if the chain of functions contains more than one call:
+**Note:** You need to follow the functional style, meaning each function call in a chain with `.` should start at a new line if the chain of functions contains more than one call:
```kotlin
val value = otherValue!!
.map { x -> x }
@@ -359,7 +358,7 @@ Note that all operators for comparing such as `==`, `>`, `<`, e.t.c should not b
}
.size
```
-**Note**, that parser prohibits the separation of operator `!!` from the value it is checking.
+**Note:** The parser prohibits the separation of the `!!` operator from the value it is checking.
**Exception**: If a functional chain is used inside the branches of a ternary operator, it does not need to be split with newlines.
@@ -373,8 +372,8 @@ if (condition) list.map { foo(it) }.filter { bar(it) } else list.drop(1)
A brace should be placed immediately after the name without any spaces in declarations or at call sites.
4) Newlines should be placed right after the comma (`,`).
5) If a lambda statement contains more than one line in its body, a newline should be placed after an arrow if the lambda statement has explicit parameters.
- If it uses an implicit parameter (`it`), the newline should be placed after the opening brace (`{`).
- See the following examples.
+ If it uses an implicit parameter (`it`), the newline should be placed after the opening brace (`{`).
+ The following examples illustrate this rule:
**Invalid example:**
@@ -394,8 +393,8 @@ value.map { name ->
val someValue = { node:String -> node }
```
-6) When the function contains only a single expression, it can be expressed as [expression function](https://kotlinlang.org/docs/reference/functions.html#single-expression-functions).
- The following style should not be used.
+6) When the function contains only a single expression, it can be written as [expression function](https://kotlinlang.org/docs/reference/functions.html#single-expression-functions).
+ The below example shows the style that should not be used.
Instead of:
```kotlin
@@ -441,7 +440,7 @@ fun foo(
}
```
-8) If super type list has more than 2 elements, they should be separated by newlines.
+8) If the supertype list has more than two elements, they should be separated by newlines
**Valid example:**
```kotlin
@@ -455,9 +454,8 @@ class MyFavouriteVeryLongClassHolder :
### 3.7 Blank lines
### Recommendation 3.7.1: Reduce unnecessary blank lines and maintain a compact code size
-By reducing unnecessary blank lines, you can display more code on one screen, which in turn improves code readability.
-
-- Blank lines should separate content based on relevance, and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [Rule 3.1.2](#r3.1.2)).
+By reducing unnecessary blank lines, you can display more code on one screen, which improves code readability.
+- Blank lines should separate content based on relevance and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [Rule 3.1.2](#r3.1.2)).
- Do not use more than one line inside methods, type definitions, and initialization expressions.
- Generally, do not use more than two consecutive blank lines in a row.
- Do not put newlines in the beginning or end of code blocks with curly braces.
@@ -476,12 +474,12 @@ fun baz() {
### 3.8 Horizontal space
### Rule 3.8.1: Usage of whitespace for code separation
-**Note:** This recommendation corresponds to cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space. (This logic is described in another rule.)
+**Note:** This recommendation is for the cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space (described in another rule.)
-1. All keywords (such as `if`, `when`, and `for`) should be separated with a single whitespace from the opening parenthesis.
- The only exception is the `constructor` keyword, which should not be separated.
+1. Separate keywords like `if`, `when`, `for`, e.t.c. from the opening parenthesis with single whitespace.
+ The only exception is the `constructor` keyword, which should not be separated from the opening parenthesis.
-2. Separate all keywords (such as `else` or `try`) from the opening brace (`{`) with a single whitespace.
+2. Separate keywords like `else` or `try` from the opening brace (`{`) with a single whitespace.
If `else` is used in a ternary-style statement without braces, there should be a single space between `else` and the statement after: `if (condition) foo() else bar()`
3. Use a **single** whitespace before all opening braces (`{`). The only exception is the passing of a lambda as a parameter inside parentheses:
@@ -502,15 +500,15 @@ fun baz() {
`Object::toString`
- The dot separator (`.`) that stays on the same line with an object name:\
`object.toString()`
-- Safe access modifiers: `?.` and `!!`, that stay on the same line with an object name:\
+- Safe access modifiers `?.` and `!!` that stay on the same line with an object name:\
`object?.toString()`
- Operator `..` for creating ranges:\
`1..100`
-5. Spaces should be used after (`,`), (`:`), and (`;`), except when the symbol is at the end of the line.
+5. Use spaces after (`,`), (`:`), and (`;`), except when the symbol is at the end of the line.
However, note that this code style prohibits the use of (`;`) in the middle of a line ([Rule 3.2.2](#r3.2.2)).
There should be no whitespaces at the end of a line.
- The only scenario where there should be no space after a colon is when the colon is used in annotation to specify a use-site target (for example, `@param:JsonProperty`).
+ The only scenario where there should be no space after a colon is when the colon is used in the annotation to specify a use-site target (for example, `@param:JsonProperty`).
There should be no spaces before `,` , `:` and `;`.
**Exceptions** for spaces and colons are the following:
@@ -528,13 +526,13 @@ fun baz() {
}
```
-6. There should be *only one space* between identifier and it's type: `list: List`
-If the type is nullable there should be no space before `?`.
+6. There should be *only one space* between the identifier and it's type: `list: List`
+If the type is nullable, there should be no space before `?`.
7. When using `[]` operator (`get/set`) there should be **no** spaces between identifier and `[` : `someList[0]`.
8. There should be no space between a method or constructor name (both at declaration and at call site) and a parenthesis:
- `foo() {}`. Note that this sub-rule is related only to spaces, the rules for whitespaces are described in [Rule 3.6.2](#r3.6.2).
+ `foo() {}`. Note that this sub-rule is related only to spaces; the rules for whitespaces are described in [Rule 3.6.2](#r3.6.2).
This rule does not prohibit, for example, the following code:
```kotlin
fun foo
@@ -543,19 +541,19 @@ fun foo
)
```
-9. Never put a space after `(`, `[`, `<` (when used as bracket in templates) or before `)`, `]`, `>` (when used as bracket in templates).
+9. Never put a space after `(`, `[`, `<` (when used as a bracket in templates) or before `)`, `]`, `>` (when used as a bracket in templates).
-10. There should be no spaces between prefix/postfix operator (like `!!` or `++`) and it's operand.
+10. There should be no spaces between prefix/postfix operator (like `!!` or `++`), and it's an operand.
### Recommendation 3.8.2: No spaces should be inserted for horizontal alignment.
-*Horizontal alignment* refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used, becuase:
+*Horizontal alignment* refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used because:
-- When modifying code, it takes a lot of time for new developers to format, support, and fix alignment issues.
+- When modifying code, it takes much time for new developers to format, support, and fix alignment issues.
- Long identifier names will break the alignment and lead to less presentable code.
- Alignment possesses more disadvantages than advantages. To reduce maintenance costs, misalignment is the best choice.
-Recommendation: Alignment only looks good for `enum class`, where it can be used in table format to improve code readability:
+Recommendation: Alignment only looks suitable for `enum class`, where it can be used in table format to improve code readability:
```kotlin
enum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean, private val warn: String) : Rule {
PACKAGE_NAME_MISSING (1, true, "no package name declared in a file"),
@@ -580,7 +578,7 @@ enum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean
### 3.9 Enumerations
### Recommendation 3.9.1: Enum values are separated by a comma and line break, with ';' placed on the new line.
-1) Enum values are separated by comma and a line break. `;` is put on the new line:
+1) Enum values are separated by a comma and a line break. `;` is put on the new line:
```kotlin
enum class Warnings {
A,
@@ -590,15 +588,15 @@ enum class Warnings {
}
```
-This will help resolve conflicts and reduce the value's number during merging pull requests.
+This will help to resolve conflicts and reduce the number of conflicts during merging pull requests.
Also use [trailing comma](https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma).
-2) If the enum is simple (no properties, methods, and comments inside), it can be declared in a single line:
+2) If the enum is simple (no properties, methods, and comments inside), you can declare it in a single line:
```kotlin
enum class Suit { CLUBS, HEARTS, SPADES, DIAMONDS }
```
-3) Enum classes take preference if possible, for example, instead of two Boolean properties like:
+3) Enum classes take preference (if it is possible to use it). For example, instead of two boolean properties:
```kotlin
val isCelsius = true
@@ -606,12 +604,13 @@ val isFahrenheit = false
```
use enum class:
+
```kotlin
enum class TemperatureScale { CELSIUS, FAHRENHEIT }
```
- The variable value only changes within a fixed range and is defined with the enum type.
-- Avoid comparison with magic numbers of `-1, 0, and 1`, instead of this use enums:
+- Avoid comparison with magic numbers of `-1, 0, and 1`; use enums instead.
```kotlin
enum class ComparisonResult {
@@ -626,31 +625,31 @@ enum class ComparisonResult {
### 3.10 Variable declaration
### Rule 3.10.1: Declare one variable per line.
-Each property or variable declaration must be declared on a separate line.
+Each property or variable must be declared on a separate line.
**Invalid example**:
```kotlin
val n1: Int; val n2: Int
```
-### Recommendation 3.10.2: Variables should be declared close to the line where they are first used.
-To minimize their scope, local variables should be declared close to the point where they are first used. This will also increase readability of the code.
-Local variables are usually initialized during declaration or initialized immediately after.
-The member fields of the class should be declared collectively (see [Rule 3.1.2](#s3.1.2) for details on class structure).
+### Recommendation 3.10.2: Variables should be declared near the line where they are first used.
+Declare local variables close to the point where they are first used to minimize their scope. This will also increase the readability of the code.
+Local variables are usually initialized during their declaration or immediately after.
+The member fields of the class should be declared collectively (see [Rule 3.1.2](#r3.1.2) for details on the class structure).
### 3.11 When expression
-### Rule 3.11.1: 'when' statements must have an 'else' branch, unless the condition variable is enumerated or a sealed type.
-Each `when` statement contains an `else` statement group, even if it does not contain any code.
+### Rule 3.11.1: The 'when' statement must have an 'else' branch unless the condition variable is enumerated or a sealed type.
+Each `when` statement should contain an `else` statement group, even if it does not contain any code.
-**Exception:** If a when statement of type `enum or sealed` contains all values of a enum - there is no need to have "else" branch.
+**Exception:** If 'when' statement of the `enum or sealed` type contains all enum values, there is no need to have an "else" branch.
The compiler can issue a warning when it is missing.
### 3.12 Annotations
### Recommendation 3.12.1: Each annotation applied to a class, method, or constructor should be placed on its own line.
-1. Annotations applied to the class, method, or constructor are placed on separate lines (one annotation per line).
+1. Annotations applied to the class, method or constructor are placed on separate lines (one annotation per line).
**Valid example**:
```kotlin
@@ -666,7 +665,7 @@ fun getNameIfPresent() { /* ... */ }
@CustomAnnotation class Foo {}
```
-3. 3. Multiple annotations applied to a field or property can appear on the same line as the field.
+3. Multiple annotations applied to a field or property can appear on the same line as the corresponding field.
**Valid example**:
```kotlin
@@ -675,9 +674,9 @@ fun getNameIfPresent() { /* ... */ }
### 3.13 Layout of comments
-### Recommendation 3.13.1: Block comments are at the same indentation level as the surrounding code.
+### Recommendation 3.13.1: Block comments location.
-Block comments are at the same indentation level as the surrounding code. See examples below.
+Block comments should be placed at the same indentation level as the surrounding code. See examples below.
**Valid example**:
@@ -695,7 +694,7 @@ class SomeClass {
### 3.14 Modifiers and constant values
-### Recommendation 3.14.1: If a declaration has multiple modifiers, always follow proper sequence.
+### Recommendation 3.14.1: If a declaration has multiple modifiers, always follow the proper sequence.
**Valid sequence:**
```kotlin
@@ -720,9 +719,8 @@ operator
data
```
-### Recommendation 3.14.2: Long numerical values should be separated by an underscore.
-
-**Note:** Underscores make it easier to read and find errors in numeric constants.
+### Recommendation 3.14.2: An underscore should separate long numerical values.
+**Note:** Using underscores simplifies reading and helps to find errors in numeric constants.
```kotlin
val oneMillion = 1_000_000
val creditCardNumber = 1234_5678_9012_3456L
@@ -733,8 +731,8 @@ val bytes = 0b11010010_01101001_10010100_10010010
### 3.15 Strings
-### Rule 3.15.1: Concatenation of Strings is prohibited if the string can fit on one line. Use raw strings and string templates instead.
-Kotlin has significantly improved the use of Strings:
+### Rule 3.15.1: Concatenation of Strings is prohibited if the string can fit on one line.
+String concatenation is prohibited if the string can fit on one line. Use raw strings and string templates instead. Kotlin has significantly improved the use of Strings:
[String templates](https://kotlinlang.org/docs/reference/basic-types.html#string-templates), [Raw strings](https://kotlinlang.org/docs/reference/basic-types.html#string-literals)
As such, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines and you do not need to split them with newlines.
@@ -751,9 +749,9 @@ val value = "$myStr concatenated"
```
### Rule 3.15.2: String template format
-**Redundant curly braces in string templates.**
+**Redundant curly braces in string templates**
-In case string template contains only one variable, - there is no need to use string template. Use this variable directly.
+If there is only one variable in a string template, there is no need to use such a template. Use this variable directly.
**Invalid example**:
```kotlin
val someString = "${myArgument} ${myArgument.foo()}"
@@ -764,7 +762,8 @@ val someString = "${myArgument} ${myArgument.foo()}"
val someString = "$myArgument ${myArgument.foo()}"
```
-**Redundant string template.**
+**Redundant string template**
+
In case string template contains only one variable - there is no need to use string template. Use this variable directly.
**Invalid example**:
diff --git a/info/guide/guide-chapter-4.md b/info/guide/guide-chapter-4.md
index 0a497bbe01..680fde253a 100644
--- a/info/guide/guide-chapter-4.md
+++ b/info/guide/guide-chapter-4.md
@@ -3,34 +3,33 @@
### 4.1 Variables
### Rule 4.1.1: Do not use Float and Double types when accurate calculations are needed.
Floating-point numbers provide a good approximation over a wide range of values, but they cannot produce accurate results in some cases.
-Binary floating-point numbers are unsuitable for precise calculations, because it is impossible to represent 0.1 or any other negative power of 10 in a `binary representation` with a finite length.
+Binary floating-point numbers are unsuitable for precise calculations because it is impossible to represent 0.1 or any other negative power of 10 in a `binary representation` with a finite length.
-The following example seems to be simple code that is obvious:
+The following code example seems to be obvious:
```kotlin
val myValue = 2.0 - 1.1
println(myValue)
```
-However, it will print a value such as: `0.8999999999999999`
+However, it will print the following value: `0.8999999999999999`
-As such, if you need to make precise calculations (for example, when dealing with currency, finance, or an exact science), `Int`, `Long`, `BigDecimal`, etc. are recommended.
-Among them, `BigDecimal` should serve as a good choice.
+Therefore, for precise calculations (for example, in finance or exact sciences), using such types as `Int`, `Long`, `BigDecimal`are recommended.
+The `BigDecimal` type should serve as a good choice.
**Invalid example:** \
-If a float value contains more than six to seven decimal numbers, it will be rounded off.
+Float values containing more than six or seven decimal numbers will be rounded.
```kotlin
val eFloat = 2.7182818284f // Float, will be rounded to 2.7182817
```
-**Valid example** (when accurate calculations are needed):
+**Valid example** (when precise calculations are needed):
```kotlin
val income = BigDecimal("2.0")
val expense = BigDecimal("1.1")
println(income.subtract(expense)) // you will obtain 0.9 here
```
-### Rule 4.1.2: The numbers of a float type should not be directly compared with the equality operator (==) or other methods like compareTo and equals.
-
+### Rule 4.1.2: Numeric float type values should not be directly compared with the equality operator (==) or other methods like `compareTo()` and `equals()`.
Since floating-point numbers involve precision problems in computer representation, it is better to use `BigDecimal` as recommended in [Rule 4.1.1](#r4.1.1) to make accurate computations and comparisons. The following code describes these problems.
**Invalid example**:
@@ -67,9 +66,9 @@ if (abs(foo - bar) > 1e-6f) {
### Rule 4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR].
Variables with the `val` modifier are immutable (read-only).
-Code robustness and readability increase through the use of such variables, as opposed to `var` variables.
-This is because var variables can be reassigned several times in the business logic.
-Of course, in some scenarios with loops or accumulators, only `var`s are permitted.
+Code robustness and readability increase when using `val` variables instead of `var` variables.
+This is because `var` variables can be reassigned several times in the business logic.
+However, in some scenarios with loops or accumulators, only `var`s are permitted.
### 4.2 Types
@@ -104,7 +103,7 @@ fun bar(x: String?) {
}
```
-Smart cast and contracts are better because they reduce boilerplate code and forced type conversion.
+Smart cast and contracts are a better choice because they reduce boilerplate code and features forced type conversion.
**Invalid example**:
```kotlin
@@ -122,12 +121,12 @@ fun foo(s: String?) {
}
```
-### Recommendation 4.2.2: Try to use type alias to represent types and make code more readable.
+### Recommendation 4.2.2: Try to use type alias to represent types making code more readable.
Type aliases provide alternative names for existing types.
-If the type name is too long, you can replace it with a shorter name. It helps to shorten long generic types.
+If the type name is too long, you can replace it with a shorter name, which helps to shorten long generic types.
For example, code looks much more readable if you introduce a `typealias` instead of a long chain of nested generic types.
-We recommend the use of a `typealias` if the type contains **more than two** nested generic types and is longer than **25 chars**.
+We recommend using a `typealias` if the type contains **more than two** nested generic types and is longer than **25 chars**.
**Invalid example**:
```kotlin
@@ -152,7 +151,7 @@ typealias Predicate = (T) -> Boolean
Kotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types.
### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib.
-To avoid `NullPointerException` and help compiler checks prevent NPE, try to avoid using nullable types (with `?` symbol).
+To avoid `NullPointerException` and help compiler to prevent Null Poniter Exceptions, avoid using nullable types (with `?` symbol).
**Invalid example**:
```kotlin
@@ -165,8 +164,8 @@ val a: Int = 0
```
Nevertheless, if you use Java libraries extensively, you will have to use nullable types and enrich your code with `!!` and `?` symbols.
-Avoid using nullable types for Kotlin stdlib (declared in [official documentation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/)) avoid using nullable types.
-Try to use initializers for empty collections. ), and try using initializers for empty collections. For example: If you want to initialize a list instead of using `null` use `emptyList()`.
+Avoid using nullable types for Kotlin stdlib (declared in [official documentation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/)).
+Try to use initializers for empty collections. For example, if you want to initialize a list instead of `null` use `emptyList()`.
**Invalid example**:
```kotlin
@@ -179,14 +178,14 @@ val a: List = emptyList()
```
### Recommendation 4.3.2: Variables of generic types should have an explicit type declaration.
-As in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments:
+Like in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments:
```kotlin
val myVariable: Map = emptyMap()
```
-However, the compiler can inherit type parameters from the right value, and as such, will not force users to explicitly declare the type.
-These declarations are not recommended because programmers would need to find its return value and understand the variable type by looking at the method.
+However, the compiler can inherit type parameters from the r-value (value assigned to a variable). Therefore, it will not force users to declare the type explicitly.
+These declarations are not recommended because programmers would need to find the return value and understand the variable type by looking at the method.
**Invalid example**:
```kotlin
diff --git a/info/guide/guide-chapter-5.md b/info/guide/guide-chapter-5.md
index 19fbeacbe7..5f0f5b7403 100644
--- a/info/guide/guide-chapter-5.md
+++ b/info/guide/guide-chapter-5.md
@@ -6,48 +6,47 @@ You should utilize this approach, along with functional style, when you write Ko
The concepts behind functional style are as follows:
Functions are the smallest unit of combinable and reusable code.
They should have clean logic, **high cohesion**, and **low coupling** to effectively organize the code.
-The code in functions should be simple, and should not conceal the author's original intentions.
+The code in functions should be simple and not conceal the author's original intentions.
Additionally, it should have a clean abstraction, and control statements should be used in a straightforward manner.
-The side effects (code that does not affect a function's return value, but affects global/object instance variables) should not be used for state changes.
+The side effects (code that does not affect a function's return value, but affects global/object instance variables) should not be used for state changes of an object.
The only exceptions to this are state machines.
-Kotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming.
-This language features built-in mechanisms that support functional programming. In addition, standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments.
+Kotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming, featuring the corresponding built-in mechanisms.
+In addition, standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments.
As [previously discussed](#r4.1.3), Kotlin supports and encourages the use of immutable types, which in turn motivates programmers to write pure functions that avoid side effects and have a corresponding output for specific input.
-The pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls and each step features the following characteristics:
-1. Simple
-2. Verifiable
-3. Testable
-4. Replaceable
-5. Pluggable
-6. Extensible
+The pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls, and each step features the following characteristics:
+1. Simplicity
+2. Verifiability
+3. Testability
+4. Replaceability
+5. Pluggability
+6. Extensibility
7. Immutable results
-There can be only one side effect in this data stream, which can be placed only at the end of execution queue.
+There can be only one side effect in this data stream, which can be placed only at the end of the execution queue.
-### Rule 5.1.1: Avoid functions that are too long. They should consist of 30 lines (non-empty and non-comment) in total.
+### Rule 5.1.1: Avoid functions that are too long.
The function should be displayable on one screen and only implement one certain logic.
-If a function is too long, it often means that it is complex and be split or made more primitive.
+If a function is too long, it often means that it is complex and be split or made more primitive. Functions should consist of 30 lines (non-empty and non-comment) in total.
**Exception:** Some functions that implement complex algorithms may exceed 30 lines due to aggregation and comprehensiveness.
Linter warnings for such functions **can be suppressed**.
-Even if a long function works well, new problems or bugs due to complex logic may appear once it is modified by someone else.
-As such, it is recommended that you split such functions into several separated and shorter ones that are easier to manage.
-This will enable other programmers to read and modify the code properly.
-
-### Rule 5.1.2: Avoid deep nesting of function code blocks. It should be limited to four levels.
+Even if a long function works well, new problems or bugs may appear due to the function's complex logic once it is modified by someone else.
+Therefore, it is recommended that you split such functions into several separate and shorter functions that are easier to manage.
+This approach will enable other programmers to read and modify the code properly.
+### Rule 5.1.2: Avoid deep nesting of function code blocks, limiting to four levels.
The nesting depth of a function's code block is the depth of mutual inclusion between the code control blocks in the function (for example: if, for, while, and when).
Each nesting level will increase the amount of effort needed to read the code because you need to remember the current "stack" (for example, entering conditional statements and loops).
-**Exception:** The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function, and the nesting levels of enclosing methods are not accumulated.
-Functional decomposition should be implemented to avoid confusing for the developer who read the code.
+**Exception:** The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function wheres the nesting levels of enclosing methods are not accumulated.
+Functional decomposition should be implemented to avoid confusion for the developer who reads the code.
This will help the reader switch between context.
### Rule 5.1.3: Avoid using nested functions.
-Nested functions create more complex function context, thereby confusing readers.
-Additionally, the visibility context may not be obvious to the reader of the code.
+Nested functions create a more complex function context, thereby confusing readers.
+With nested functions the visibility context may not be evident to the code reader.
**Invalid example**:
```kotlin
@@ -61,9 +60,9 @@ fun foo() {
### 5.2 Function arguments
-### Rule 5.2.1: The lambda parameter of the function should be placed last in the argument list.
+### Rule 5.2.1: The lambda parameter of the function should be placed at the end of the argument list.
-With a such notation, it is easier to use curly brackets, which in turn leads to code with better readability.
+With such notation, it is easier to use curly brackets, which in turn leads to better code readability.
**Valid example**:
```kotlin
@@ -78,17 +77,16 @@ println("hey")
}
```
-### Rule 5.2.2: Number of parameters of function should be limited to 5
+### Rule 5.2.2: Number of function parameters should be limited to 5
A long argument list is a [code smell](https://en.wikipedia.org/wiki/Code_smell) that leads to less reliable code.
-If there are **more than five** parameters, maintenance becomes more difficult and conflicts become much more difficult to merge.
-As such, it is recommended that you reduce the number of parameters.
-If groups of parameters appear in different functions multiple times, these parameters are closely related and can be encapsulated into a single Data Class.
+It is recommended that you reduce the number of parameters. Having **more than five** parameters leads to difficulties in maintenance and conflicts merging.
+If parameter groups appear in different functions multiple times, these parameters are closely related and can be encapsulated into a single Data Class.
It is recommended that you use Data Classes and Maps to unify these function arguments.
### Rule 5.2.3 Use default values for function arguments instead of overloading them
-In Java default values for function arguments are prohibited. That's why each time when it is needed to create a function with less arguments, this function should be overloaded.
-In Kotlin you can use default arguments instead.
+In Java, default values for function arguments are prohibited. That is why when you need to create a function with fewer arguments, the function should be overloaded.
+In Kotlin, you can use default arguments instead.
**Invalid example**:
```kotlin
diff --git a/info/guide/guide-chapter-6.md b/info/guide/guide-chapter-6.md
index 9bea69eb32..6ad5cac182 100644
--- a/info/guide/guide-chapter-6.md
+++ b/info/guide/guide-chapter-6.md
@@ -27,15 +27,14 @@ class Test private constructor(var a: Int) {
```
### Rule 6.1.2: Prefer data classes instead of classes without any functional logic.
-Some people say that data class - is a code smell. But in case you really need to use it and your x1code is becoming more simple because of that -
-you can use Kotlin `data classes`. Main purpose of these classes is to hold data.
-But also `data classes` will automatically generate several useful methods:
+Some people say that the data class is a code smell. But if you need to use it, and as a result, your code is becoming more simple, you can use Kotlin `data class`. The main purpose of this class is to hold data,
+but also `data class` will automatically generate several useful methods:
- equals()/hashCode() pair;
- toString()
- componentN() functions corresponding to the properties in their order of declaration;
- copy() function
-So instead of using `normal` classes:
+Therefore, instead of using `normal` classes:
```kotlin
class Test {
@@ -64,18 +63,17 @@ class Test() {
}
```
-**Prefer:**
+**prefer data classes:**
```kotlin
data class Test1(var a: Int = 0, var b: Int = 0)
```
-**Exception #1**: Note, that data classes cannot be abstract, open, sealed or inner, that's why these types of classes cannot be changed to data class.
+**Exception #1**: Note, that data classes cannot be abstract, open, sealed or inner, that's why these types of classes cannot be changed to a data class.
-**Exception #2**: No need to convert a class to data class in case this class extends some other class or implements an interface.
+**Exception #2**: No need to convert a class to data class if this class extends some other class or implements an interface.
-### Rule 6.1.3: Do not use the primary constructor if it is empty and has no sense.
-The primary constructor is part of the class header: it goes after the class name (and optional type parameters).
-But in is useless - it can be omitted.
+### Rule 6.1.3: Do not use the primary constructor if it is empty or useless.
+The primary constructor is a part of the class header; it goes after the class name and (optional) type parameters but can be omitted if it is useless.
**Invalid example**:
```kotlin
@@ -112,11 +110,11 @@ class Test {
### Rule 6.1.4: several init blocks are redundant and generally should not be used in your class.
The primary constructor cannot contain any code. That's why Kotlin has introduced `init` blocks.
These blocks are used to store the code that should be run during the initialization of the class.
-Kotlin allows to write multiple initialization blocks that are executed in the same order as they appear in the class body.
-Even when you have the [Rule 3.1.2](#r3.1.2) this makes code less readable as the programmer needs to keep in mind all init blocks and trace the execution of the code.
-So in your code you should try to use single `init` block to reduce the complexity. In case you need to do some logging or make some calculations before the assignment
-of some class property - you can use powerful functional programming. This will reduce the possibility of the error, when occasionally someone will change the order of your `init` blocks.
-And it will make the logic of the code more coupled. It is always enough to use one `init` block to implement your idea in Kotlin.
+Kotlin allows writing multiple initialization blocks that are executed in the same order as they appear in the class body.
+Even when you follow (rule 3.2)[#r3.2], this makes your code less readable as the programmer needs to keep in mind all init blocks and trace the execution of the code.
+So in your code, you should try to use a single `init` block to reduce the complexity. In case you need to do some logging or make some calculations before the assignment
+of some class property, you can use powerful functional programming. This will reduce the possibility of the error if your `init` blocks' order is accidentally changed and
+make the code logic more coupled. It is always enough to use one `init` block to implement your idea in Kotlin.
**Invalid example**:
```kotlin
@@ -147,9 +145,9 @@ class YourClass(var name: String) {
}
```
-Also - init block was not added to Kotlin to help you simply initialize your properties it is needed for more complex tasks.
-So if `init` block contains only assignments of variables - move it directly to properties, so they will be correctly initialized near the declaration.
-In some case this rule can be in clash with [6.1.1](#r6.1.1), but that should not stop you.
+The `init` block was not added to Kotlin to help you initialize your properties; it is needed for more complex tasks.
+Therefore if the `init` block contains only assignments of variables - move it directly to properties, so that they will be correctly initialized near the declaration.
+In some cases, this rule can be in clash with [6.1.1](#r6.1.1), but that should not stop you.
**Invalid example**:
```kotlin
@@ -185,8 +183,8 @@ class Square() : Rectangle() {
```
### Rule 6.1.6: Abstract class should have at least one abstract method.
-Abstract classes are used to force a developer to implement some of its parts in its inheritors.
-In case when abstract class has no abstract methods - then it was set `abstract` incorrectly and can be converted to a normal class.
+Abstract classes are used to force a developer to implement some of its parts in their inheritors.
+When the abstract class has no abstract methods, it was set `abstract` incorrectly and can be converted to a regular class.
**Invalid example**:
```kotlin
@@ -216,7 +214,7 @@ class NotAbstract {
### Rule 6.1.7: in case of using "implicit backing property" scheme, the name of real and back property should be the same.
Kotlin has a mechanism of [backing properties](https://kotlinlang.org/docs/reference/properties.html#backing-properties).
-In some cases implicit backing is not enough and it should be done explicitly:
+In some cases, implicit backing is not enough and it should be done explicitly:
```kotlin
private var _table: Map? = null
val table: Map
@@ -228,12 +226,14 @@ val table: Map
}
```
-In this case the name of backing property (`_table`) should be the same to the name of real property (`table`), but should have underscore (`_`) prefix.
+In this case the name of the backing property (`_table`) should be the same as the name of the real property (`table`) but should have an underscore (`_`) prefix.
It is one of the exceptions from the [identifier names rule](#r1.2)
### Recommendation 6.1.8: avoid using custom getters and setters.
Kotlin has a perfect mechanism of [properties](https://kotlinlang.org/docs/reference/properties.html#properties-and-fields).
-Kotlin compiler automatically generates `get` and `set` methods for properties and also lets the possibility to override it:
+Kotlin compiler automatically generates `get` and `set` methods for properties and also provides the possibility to override it.
+
+**Invalid example:**
```kotlin
class A {
var size: Int = 0
@@ -247,11 +247,14 @@ class A {
```
From the callee code these methods look like an access to this property: `A().isEmpty = true` for setter and `A().isEmpty` for getter.
-But in all cases it is very confusing when `get` and `set` are overridden for a developer who uses this particular class.
-Developer expects to get the value of the property, but receives some unknown value and some extra side effect hidden by the custom getter/setter.
-Use extra functions for it instead.
-**Invalid example:**
+However, when `get` and `set` are overridden, it is very confusing for a developer who uses this particular class.
+The developer expects to get the property value but receives some unknown value and some extra side-effect hidden by the custom getter/setter.
+Use extra functions instead to avoid confusion.
+
+
+
+**Valid example**:
```kotlin
class A {
var size: Int = 0
@@ -267,8 +270,8 @@ class A {
**Exception:** `Private setters` are only exceptions that are not prohibited by this rule.
### Rule 6.1.9: never use the name of a variable in the custom getter or setter (possible_bug).
-Even if you have ignored [recommendation 6.1.8](#r6.1.8) you should be careful with using the name of the property in your custom getter/setter
-as it can accidentally cause a recursive call and a `StackOverflow Error`. Use `field` keyword instead.
+If you have ignored [recommendation 6.1.8](#r6.1.8) you should be careful with using the name of the property in your custom getter/setter
+as it can accidentally cause a recursive call and a `StackOverflow Error`. Use the `field` keyword instead.
**Invalid example (very bad)**:
```kotlin
@@ -281,9 +284,9 @@ var isEmpty: Boolean
```
### Recommendation 6.1.10 no trivial getters and setters are allowed in the code.
-In Java - trivial getters - are getters that are simply returning the value of a field.
-Trivial setters - are simply setting the field with a value without any transformation.
-But in Kotlin trivial getters/setters are generated by the default. There is no need to use it explicitly for all types of data-structures in Kotlin.
+In Java, trivial getters - are the getters that are just returning the field value.
+Trivial setters - are merely setting the field with a value without any transformation.
+However, in Kotlin, trivial getters/setters are generated by the default. There is no need to use it explicitly for all types of data structures in Kotlin.
**Invalid example**:
```kotlin
@@ -308,9 +311,9 @@ class A {
```
### Rule 6.1.11: use apply for grouping object initialization.
-In the good old Java before functional programming became popular - lot of classes from commonly used libraries used configuration paradigm.
-To use these classes you had to create an object with the constructor that had 0-2 arguments and set the fields that were needed to run an object.
-In Kotlin to reduce the number of dummy code lines and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added:
+In Java, before functional programming became popular, many classes from common libraries used configuration paradigm.
+To use these classes, you had to create an object with the constructor with 0-2 arguments and set the fields needed to run the object.
+In Kotlin, to reduce the number of dummy code line and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added:
**Invalid example**:
```kotlin
@@ -356,16 +359,17 @@ fun main() {
### 6.2 Extension functions
-[Extension functions](https://kotlinlang.org/docs/reference/extensions.html) - is a killer-feature in Kotlin.
+[Extension functions](https://kotlinlang.org/docs/reference/extensions.html) is a killer-feature in Kotlin.
It gives you a chance to extend classes that were already implemented in external libraries and help you to make classes less heavy.
Extension functions are resolved statically.
### Recommendation 6.2.1: use extension functions for making logic of classes less coupled.
-It is recommended that for classes non-tightly coupled functions with rare usages in the class should be implemented as extension functions where possible.
-They should be implemented in the same class/file where they are used. This is non-deterministic rule, so it cannot be checked or fixed automatically by static analyzer.
+It is recommended that for classes, the non-tightly coupled functions, which are rarely used in the class, should be implemented as extension functions where possible.
+They should be implemented in the same class/file where they are used. This is a non-deterministic rule, so the code cannot be checked or fixed automatically by a static analyzer.
-### Rule 6.2.2: there should be no extension functions with the same name and signature if they extend base and inheritor classes (possible_bug).
-As extension functions are resolved statically. In this case there can be a situation when a developer implements two extension functions - one is for the base class and another one for the inheritor.
+### Rule 6.2.2: No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug).
+As extension functions are resolved statically. In this case, there could be a situation when a developer implements two extension functions: one is for the base class and another for the inheritor.
+This can lead to an issue when an incorrect method is used.
And that can lead to an issue when incorrect method is used.
**Invalid example**:
@@ -386,18 +390,17 @@ fun main() { printClassName(B()) }
### 6.3 Interfaces
-`Interface`s in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state.
+An `Interface` in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state.
They can have properties, but these need to be abstract or to provide accessor implementations.
Kotlin's interfaces can define attributes and functions.
-In Kotlin and Java, the interface is the main presentation means of application programming interface (API) design, and should take precedence over the use of (abstract) classes.
+In Kotlin and Java, the interface is the main presentation means of application programming interface (API) design and should take precedence over the use of (abstract) classes.
### 6.4 Objects
### Rule 6.4.1: Avoid using utility classes/objects, use extensions instead.
-As described in [6.2 Extension functions](#c6.2) - extension functions - is a very powerful mechanism.
-So instead of using utility classes/objects, use it instead.
-This allows you to remove the unnecessary complexity and wrapping class/object and to use top-level functions instead.
+As described in [6.2 Extension functions](#c6.2), extension functions are a powerful. Instead of using utility classes/objects, use it extention functions.
+This allows you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead.
**Invalid example**:
```kotlin
@@ -419,8 +422,8 @@ fun String.stringInfo(): Int {
```
### Recommendation 6.4.2: Objects should be used for Stateless Interfaces.
-Kotlin’s object are extremely useful when we need to implement a some interface from an external library that doesn’t have any state.
-No need to use class for such structures.
+Kotlin’s objects are extremely useful when you need to implement some interface from an external library that doesn’t have any state.
+There is no need to use classes for such structures.
**Valid example**:
```
diff --git a/info/guide/guide-chapter-8.md b/info/guide/guide-chapter-8.md
index b133365b85..7c19482263 100644
--- a/info/guide/guide-chapter-8.md
+++ b/info/guide/guide-chapter-8.md
@@ -65,3 +65,19 @@ myVar?.let {
println("null")
} ?: run { println("not null") }
```
+
+**Exceptions:** in case of complex expressions like multiple `else-if` structures, or a long conditional statement there is a common sense to use explicit comparison with `null`.
+
+**Valid examples:**
+
+```kotlin
+if (myVar != null) {
+ println("not null")
+} else if (anotherCondition) {
+ println("Other condition")
+}
+```
+
+```kotlin
+if (myVar == null || otherValue == 5 && isValid) {}
+```
diff --git a/info/rules-mapping.md b/info/rules-mapping.md
new file mode 100644
index 0000000000..7ed2128362
--- /dev/null
+++ b/info/rules-mapping.md
@@ -0,0 +1,104 @@
+| Diktat Rule | Code Style | Auto-fixed? |
+| ----------------------------------------- | ------ | --- |
+| VARIABLE_NAME_INCORRECT | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | no |
+| VARIABLE_HAS_PREFIX | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | yes |
+| IDENTIFIER_LENGTH | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | no |
+| GENERIC_NAME | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | yes |
+| BACKTICKS_PROHIBITED | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | no |
+| FILE_NAME_INCORRECT | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | yes |
+| EXCEPTION_SUFFIX | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | yes |
+| CONFUSING_IDENTIFIER_NAMING | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | no |
+| PACKAGE_NAME_MISSING | [1.2.1](guide/diktat-coding-convention.md#r1.2.1) | yes |
+| PACKAGE_NAME_INCORRECT_CASE | [1.2.1](guide/diktat-coding-convention.md#r1.2.1) | yes |
+| PACKAGE_NAME_INCORRECT_PREFIX | [1.2.1](guide/diktat-coding-convention.md#r1.2.1) | yes |
+| PACKAGE_NAME_INCORRECT_SYMBOLS | [1.2.1](guide/diktat-coding-convention.md#r1.2.1) | no |
+| PACKAGE_NAME_INCORRECT_PATH | [1.2.1](guide/diktat-coding-convention.md#r1.2.1) | yes |
+| INCORRECT_PACKAGE_SEPARATOR | [1.2.1](guide/diktat-coding-convention.md#r1.2.1) | yes |
+| CLASS_NAME_INCORRECT | [1.3.1](guide/diktat-coding-convention.md#r1.3.1) | yes |
+| OBJECT_NAME_INCORRECT | [1.3.1](guide/diktat-coding-convention.md#r1.3.1) | yes |
+| ENUM_VALUE | [1.3.1](guide/diktat-coding-convention.md#r1.3.1) | yes |
+| FUNCTION_NAME_INCORRECT_CASE | [1.4.1](guide/diktat-coding-convention.md#r1.4.1) | yes |
+| CONSTANT_UPPERCASE | [1.5.1](guide/diktat-coding-convention.md#r1.5.1) | yes |
+| VARIABLE_NAME_INCORRECT_FORMAT | [1.6.1](guide/diktat-coding-convention.md#r1.6.1) | yes |
+| FUNCTION_BOOLEAN_PREFIX | [1.6.2](guide/diktat-coding-convention.md#r1.6.2) | yes |
+| MISSING_KDOC_TOP_LEVEL | [2.1.1](guide/diktat-coding-convention.md#r2.1.1) | no |
+| MISSING_KDOC_CLASS_ELEMENTS | [2.1.1](guide/diktat-coding-convention.md#r2.1.1) | no |
+| MISSING_KDOC_ON_FUNCTION | [2.1.1](guide/diktat-coding-convention.md#r2.1.1) | yes |
+| KDOC_NO_CONSTRUCTOR_PROPERTY | [2.1.1](guide/diktat-coding-convention.md#r2.1.1) | yes |
+| KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT | [2.1.1](guide/diktat-coding-convention.md#r2.1.1) | yes |
+| KDOC_WITHOUT_PARAM_TAG | [2.1.2](guide/diktat-coding-convention.md#r2.1.2) | yes |
+| KDOC_WITHOUT_RETURN_TAG | [2.1.2](guide/diktat-coding-convention.md#r2.1.2) | yes |
+| KDOC_WITHOUT_THROWS_TAG | [2.1.2](guide/diktat-coding-convention.md#r2.1.2) | yes |
+| KDOC_EMPTY_KDOC | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | no |
+| KDOC_WRONG_SPACES_AFTER_TAG | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | yes |
+| KDOC_WRONG_TAGS_ORDER | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | yes |
+| KDOC_NEWLINES_BEFORE_BASIC_TAGS | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | yes |
+| KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | yes |
+| KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | yes |
+| KDOC_NO_DEPRECATED_TAG | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | yes |
+| KDOC_NO_EMPTY_TAGS | [2.2.1](guide/diktat-coding-convention.md#r2.2.1) | no |
+| HEADER_WRONG_FORMAT | [2.2.1](guide/diktat-coding-convention.md#r2.2.1) | yes |
+| HEADER_MISSING_OR_WRONG_COPYRIGHT | [2.2.1](guide/diktat-coding-convention.md#r2.2.1) | yes |
+| WRONG_COPYRIGHT_YEAR | [2.2.1](guide/diktat-coding-convention.md#r2.2.1) | yes |
+| HEADER_CONTAINS_DATE_OR_AUTHOR | [2.2.1](guide/diktat-coding-convention.md#r2.2.1) | no |
+| HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE | [2.2.1](guide/diktat-coding-convention.md#r2.2.1) | no |
+| HEADER_NOT_BEFORE_PACKAGE | [2.2.1](guide/diktat-coding-convention.md#r2.2.1) | yes |
+| KDOC_TRIVIAL_KDOC_ON_FUNCTION | [2.3.1](guide/diktat-coding-convention.md#r2.3.1) | no |
+| WRONG_NEWLINES_AROUND_KDOC | [2.4.1](guide/diktat-coding-convention.md#r2.4.1) | yes |
+| FIRST_COMMENT_NO_SPACES | [2.4.1](guide/diktat-coding-convention.md#r2.4.1) | yes |
+| COMMENT_WHITE_SPACE | [2.4.1](guide/diktat-coding-convention.md#r2.4.1) | yes |
+| IF_ELSE_COMMENTS | [2.4.1](guide/diktat-coding-convention.md#r2.4.1) | yes |
+| COMMENTED_OUT_CODE | [2.4.2](guide/diktat-coding-convention.md#r2.4.2) | no |
+| FILE_IS_TOO_LONG | [3.1.1](guide/diktat-coding-convention.md#r3.1.1) | no |
+| FILE_CONTAINS_ONLY_COMMENTS | [3.1.2](guide/diktat-coding-convention.md#r3.1.2) | no |
+| FILE_INCORRECT_BLOCKS_ORDER | [3.1.2](guide/diktat-coding-convention.md#r3.1.2) | yes |
+| FILE_NO_BLANK_LINE_BETWEEN_BLOCKS | [3.1.2](guide/diktat-coding-convention.md#r3.1.2) | yes |
+| FILE_UNORDERED_IMPORTS | [3.1.2](guide/diktat-coding-convention.md#r3.1.2) | yes |
+| FILE_WILDCARD_IMPORTS | [3.1.2](guide/diktat-coding-convention.md#r3.1.2) | no |
+| FILE_NAME_MATCH_CLASS | [3.1.2](guide/diktat-coding-convention.md#r3.1.2) | yes |
+| WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES | [3.1.4](guide/diktat-coding-convention.md#r3.1.4) | yes |
+| BLANK_LINE_BETWEEN_PROPERTIES | [3.1.4](guide/diktat-coding-convention.md#r3.1.4) | yes |
+| WRONG_DECLARATIONS_ORDER | [3.1.4](guide/diktat-coding-convention.md#r3.1.4) | yes |
+| NO_BRACES_IN_CONDITIONALS_AND_LOOPS | [3.2.1](guide/diktat-coding-convention.md#r3.2.1) | yes |
+| BRACES_BLOCK_STRUCTURE_ERROR | [3.2.2](guide/diktat-coding-convention.md#r3.2.2) | yes |
+| WRONG_INDENTATION | [3.3.1](guide/diktat-coding-convention.md#r3.3.1) | yes |
+| EMPTY_BLOCK_STRUCTURE_ERROR | [3.4.1](guide/diktat-coding-convention.md#r3.4.1) | yes |
+| LONG_LINE | [3.5.1](guide/diktat-coding-convention.md#r3.5.1) | yes |
+| MORE_THAN_ONE_STATEMENT_PER_LINE | [3.6.1](guide/diktat-coding-convention.md#r3.6.1) | yes |
+| REDUNDANT_SEMICOLON | [3.6.2](guide/diktat-coding-convention.md#r3.6.2) | yes |
+| WRONG_NEWLINES | [3.6.2](guide/diktat-coding-convention.md#r3.6.2) | yes |
+| TOO_MANY_BLANK_LINES | [3.7.1](guide/diktat-coding-convention.md#r3.7.1) | yes |
+| WRONG_WHITESPACE | [3.8.1](guide/diktat-coding-convention.md#r3.8.1) | yes |
+| TOO_MANY_CONSECUTIVE_SPACES | [3.8.1](guide/diktat-coding-convention.md#r3.8.1) | yes |
+| ENUMS_SEPARATED | [3.9.1](guide/diktat-coding-convention.md#r3.9.1) | yes |
+| LOCAL_VARIABLE_EARLY_DECLARATION | [3.10.2](guide/diktat-coding-convention.md#r3.10.2) | no |
+| WHEN_WITHOUT_ELSE | [3.11.1](guide/diktat-coding-convention.md#r3.11.1) | yes |
+| ANNOTATION_NEW_LINE | [3.12.1](guide/diktat-coding-convention.md#r3.12.1) | yes |
+| WRONG_MULTIPLE_MODIFIERS_ORDER | [3.14.1](guide/diktat-coding-convention.md#r3.14.1) | yes |
+| LONG_NUMERICAL_VALUES_SEPARATED | [3.14.2](guide/diktat-coding-convention.md#r3.14.2) | yes |
+| STRING_CONCATENATION | [3.15.1](guide/diktat-coding-convention.md#r3.15.1) | no |
+| STRING_TEMPLATE_CURLY_BRACES | [3.15.2](guide/diktat-coding-convention.md#r3.15.2) | yes |
+| STRING_TEMPLATE_QUOTES | [3.15.2](guide/diktat-coding-convention.md#r3.15.2) | yes |
+| FLOAT_IN_ACCURATE_CALCULATIONS | [4.1.1](guide/diktat-coding-convention.md#r4.1.1) | no |
+| SAY_NO_TO_VAR | [4.1.3](guide/diktat-coding-convention.md#r4.1.3) | no |
+| SMART_CAST_NEEDED | [4.2.1](guide/diktat-coding-convention.md#r4.2.1) | yes |
+| TYPE_ALIAS | [4.2.2](guide/diktat-coding-convention.md#r4.2.2) | no |
+| NULLABLE_PROPERTY_TYPE | [4.3.1](guide/diktat-coding-convention.md#r4.3.1) | yes |
+| GENERIC_VARIABLE_WRONG_DECLARATION | [4.3.2](guide/diktat-coding-convention.md#r4.3.2) | yes |
+| AVOID_NULL_CHECKS | [4.3.3](guide/diktat-coding-convention.md#r4.3.3) | no |
+| TOO_LONG_FUNCTION | [5.1.1](guide/diktat-coding-convention.md#r5.1.1) | no |
+| NESTED_BLOCK | [5.1.2](guide/diktat-coding-convention.md#r5.1.2) | no |
+| AVOID_NESTED_FUNCTIONS | [5.1.3](guide/diktat-coding-convention.md#r5.1.3) | yes |
+| LAMBDA_IS_NOT_LAST_PARAMETER | [5.2.1](guide/diktat-coding-convention.md#r5.2.1) | no |
+| TOO_MANY_PARAMETERS | [5.2.2](guide/diktat-coding-convention.md#r5.2.2) | no |
+| WRONG_OVERLOADING_FUNCTION_ARGUMENTS | [5.2.3](guide/diktat-coding-convention.md#r5.2.3) | no |
+| SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY | [6.1.1](guide/diktat-coding-convention.md#r6.1.1) | yes |
+| USE_DATA_CLASS | [6.1.2](guide/diktat-coding-convention.md#r6.1.2) | no |
+| MULTIPLE_INIT_BLOCKS | [6.1.4](guide/diktat-coding-convention.md#r6.1.4) | yes |
+| USELESS_SUPERTYPE | [6.1.5](guide/diktat-coding-convention.md#r6.1.5) | yes |
+| CLASS_SHOULD_NOT_BE_ABSTRACT | [6.1.6](guide/diktat-coding-convention.md#r6.1.6) | yes |
+| CUSTOM_GETTERS_SETTERS | [6.1.8](guide/diktat-coding-convention.md#r6.1.8) | no |
+| WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR | [6.1.9](guide/diktat-coding-convention.md#r6.1.9) | no |
+| TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED | [6.1.10](guide/diktat-coding-convention.md#r6.1.10) | yes |
+| COMPACT_OBJECT_INITIALIZATION | [6.1.11](guide/diktat-coding-convention.md#r6.1.11) | yes |
+| EXTENSION_FUNCTION_SAME_SIGNATURE | [6.2.2](guide/diktat-coding-convention.md#r6.2.2) | no |
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index ffac531fdd..cdba8737ec 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,7 +42,7 @@
1.81.8UTF-8
- 1.4.10
+ 1.4.20true1.0.10.39.0
@@ -327,19 +327,9 @@
${project.basedir}/src/main/kotlin
${project.basedir}/src/test/kotlin
- diktat-analysis.yml
-
-
-
- functional-test
- none
-
- check
-
-
-
- ${project.basedir}/src/test/resources/test/funcTest
-
+
+ ${project.basedir}/src/main/kotlin/generated
+ diktat-analysis.yml
diff --git a/wp/pictures/class.PNG b/wp/pictures/class.PNG
new file mode 100644
index 0000000000..f21aef475c
Binary files /dev/null and b/wp/pictures/class.PNG differ
diff --git a/wp/pictures/data_flow.PNG b/wp/pictures/data_flow.PNG
new file mode 100644
index 0000000000..9a2677797a
Binary files /dev/null and b/wp/pictures/data_flow.PNG differ
diff --git a/wp/pictures/detekt.png b/wp/pictures/detekt.png
new file mode 100644
index 0000000000..88852441ef
Binary files /dev/null and b/wp/pictures/detekt.png differ
diff --git a/wp/pictures/diktat.png b/wp/pictures/diktat.png
new file mode 100644
index 0000000000..7dcc31afe8
Binary files /dev/null and b/wp/pictures/diktat.png differ
diff --git a/wp/pictures/kotlinRating.png b/wp/pictures/kotlinRating.png
new file mode 100644
index 0000000000..82297cbd26
Binary files /dev/null and b/wp/pictures/kotlinRating.png differ
diff --git a/wp/pictures/ktfmt.png b/wp/pictures/ktfmt.png
new file mode 100644
index 0000000000..68d948f02a
Binary files /dev/null and b/wp/pictures/ktfmt.png differ
diff --git a/wp/pictures/ktlint.png b/wp/pictures/ktlint.png
new file mode 100644
index 0000000000..1044e0f0f5
Binary files /dev/null and b/wp/pictures/ktlint.png differ
diff --git a/wp/logo.png b/wp/pictures/logo.png
similarity index 100%
rename from wp/logo.png
rename to wp/pictures/logo.png
diff --git a/wp/pictures/sequence.jpg b/wp/pictures/sequence.jpg
new file mode 100644
index 0000000000..b461c73cb3
Binary files /dev/null and b/wp/pictures/sequence.jpg differ
diff --git a/wp/pictures/web-example.png b/wp/pictures/web-example.png
new file mode 100644
index 0000000000..1353ca41e9
Binary files /dev/null and b/wp/pictures/web-example.png differ
diff --git a/wp/references.bib b/wp/references.bib
new file mode 100644
index 0000000000..2debfb190b
--- /dev/null
+++ b/wp/references.bib
@@ -0,0 +1,85 @@
+
+%% This BibTeX bibliography file was created using BibDesk.
+%% http://bibdesk.sourceforge.net/
+
+%% Created for Daniel Lawson at 2016-03-27 19:31:34 +0100
+
+
+%% Saved with string encoding Unicode (UTF-8)
+
+@article{ref:kremenek,
+ Author = {Kremenek, Ted},
+ url = "https://llvm.org/devmtg/2008-08/Kremenek_StaticAnalyzer.pdf",
+ Title = {Finding Software Bugs With the Clang Static Analyzer},
+ Year = {2008}}
+
+@article{ref:spa,
+ Author = {Yegor Bugaenko},
+ Title = {New Object Calculus to Improve Static Program Analysis},
+ Year = {September 30, 2020}
+}
+
+@article{ref:effective,
+ Author = {Wu Jingyue},
+ Title = {Effective Dynamic Detection of Alias Analysis Errors},
+ Year = {2013},
+ pages = "279-289",
+ journal = "Proceedings of the 9th Joint Meeting on Foundations of Software, Engineering"
+}
+
+@article{ref:simple,
+ Author = {Wand Mitchell},
+ Title = {A Simple Algorithm and Proof for Type Inference},
+ Year = {1987},
+ journal = "Fundamenta Informaticae 10.2",
+ pages = "115–121"
+}
+
+@article{ref:dis,
+ Author = {Jiri Slaby},
+ Title = {Automatic Bug-finding Techniques for Large Software Projects},
+ Year = {2013}
+}
+
+@book{ref:ast,
+title={Abstract Syntax Tree},
+author={Miller, F.P. and Vandome, A.F. and John, M.B.},
+isbn={9786133773127},
+url={https://books.google.ru/books?id=5ns7YgEACAAJ},
+year={2010},
+publisher={VDM Publishing}
+}
+
+@book{ref:cleancode,
+title={Clean Code: A Handbook of Agile Software Craftsmanship},
+author={Martin, R.C.},
+isbn={9780132350884},
+lccn={20080240},
+series={Robert C. Martin series},
+url={https://books.google.ru/books?id=dwSfGQAACAAJ},
+year={2009},
+publisher={Prentice Hall}
+}
+
+@book{ref:sca,
+ title={Static Code Analysis: Lint, Static Code Analysis, Data-Flow Analysis, Parasoft, Clang, List of Tools for Static Code Analysis},
+ author={LLC Books},
+ isbn={9781155282619},
+ url={https://books.google.ru/books?id=rYurSQAACAAJ},
+ year={2010},
+ publisher={General Books LLC}
+}
+
+@book{ref:kotlinInAction,
+title={Kotlin in Action},
+author={Dmitry Jemerov, Svetlana Isakova},
+pages = {88-91},
+year={2017},
+publisher={ Manning Publications}
+}
+@article{ref:offKotlin,
+ Author = {Jetbrains},
+ Title = {Kotlin official documentation},
+ url = "https://kotlinlang.org/docs/reference/",
+ year = {2020}
+}
\ No newline at end of file
diff --git a/wp/sections/appendix.tex b/wp/sections/appendix.tex
new file mode 100644
index 0000000000..73050a904d
--- /dev/null
+++ b/wp/sections/appendix.tex
@@ -0,0 +1,8 @@
+\subsection{Class diagram}
+ \includegraphics[scale=0.5]{pictures/class.PNG}
+
+\subsection{Data Flow diagram}
+ \includegraphics[scale=0.6]{pictures/data_flow.PNG}
+
+\subsection{Sequence diagram}
+ \includegraphics[scale=0.33]{pictures/sequence.jpg}
\ No newline at end of file
diff --git a/wp/sections/chapter 4/cli.tex b/wp/sections/chapter 4/cli.tex
deleted file mode 100644
index 39dbc6a3c5..0000000000
--- a/wp/sections/chapter 4/cli.tex
+++ /dev/null
@@ -1,24 +0,0 @@
-You can run diKTat as CLI-application. In order to do that you need to:
-\begin{enumerate}
- \item Install KTlint manually at \url{https://github.com/pinterest/ktlint/releases}
- \par
- \textbf{OR} use curl:
- \par
- \verb|curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.39.0/|
- \par
- \verb|ktlint && chmod a+x ktlint|
- \par
- \textbf{OR} use brew:
- \par
- \verb|brew install ktlint|
- \item Load diKTat manually at \url{no.url}
- \par
- \textbf{OR} use curl:
- \par
- \verb|curl -sSLO https://github.com/cqfn/diKTat/releases/download/v0.1.1/|
- \par
- \verb|diktat-0.1.1.jar|
- \item Finally, run KTlint (with diKTat injected) to check your \verb|*.kt| files in \verb|dir/your/dir|:
- \par
- \verb|./ktlint -R diktat.jar "dir/your/dir/**/*.kt"|
-\end{enumerate}
diff --git a/wp/sections/chapter 4/gradle.tex b/wp/sections/chapter 4/gradle.tex
deleted file mode 100644
index 29d66dc671..0000000000
--- a/wp/sections/chapter 4/gradle.tex
+++ /dev/null
@@ -1,44 +0,0 @@
-You can see how it is configured in our project for self-checks: \verb|build.gradle.kts|. Check our github: \url{https://github.com/cqfn/diKTat}.
-\par Add the code below to your \verb|build.gradle.kts|:
-\par
-\begin{verbatim}
-val ktlint by configurations.creating
-
-dependencies {
- ktlint("com.pinterest:ktlint:0.39.0") {
- // need to exclude standard ruleset to use only diktat rules
- exclude("com.pinterest.ktlint", "ktlint-ruleset-standard")
- }
-
- // diktat ruleset
- ktlint("org.cqfn.diktat:diktat-rules:0.1.1")
-}
-
-val outputDir = "${project.buildDir}/reports/diktat/"
-val inputFiles = project.fileTree(mapOf("dir" to "src", "include" to "**/*.kt"))
-
-val diktatCheck by tasks.creating(JavaExec::class) {
- inputs.files(inputFiles)
- outputs.dir(outputDir)
-
- description = "Check Kotlin code style."
- classpath = ktlint
- main = "com.pinterest.ktlint.Main"
-
- // specify proper path to sources that should be checked here
- args = listOf("src/main/kotlin/**/*.kt")
-}
-
-val diktatFormat by tasks.creating(JavaExec::class) {
- inputs.files(inputFiles)
- outputs.dir(outputDir)
-
- description = "Fix Kotlin code style deviations."
- classpath = ktlint
- main = "com.pinterest.ktlint.Main"
-
- // specify proper path to sources that should be checked here
- args = listOf("-F", "src/main/kotlin/**/*.kt")
-}
-\end{verbatim}
-\par To run diktat to check/fix code style - run: \verb|gradle diktatCheck|.
\ No newline at end of file
diff --git a/wp/sections/chapter 4/maven.tex b/wp/sections/chapter 4/maven.tex
deleted file mode 100644
index e71ee74085..0000000000
--- a/wp/sections/chapter 4/maven.tex
+++ /dev/null
@@ -1,37 +0,0 @@
-\textbf{Use maven-antrun-plugin}
-\par You can find a code snippet of maven-antrun-plugin on our github page: \url{https://github.com/cqfn/diKTat}
-\par In case you want to add autofixer with diKTat ruleset just extend the snippet above with \verb|.|
-
-\par To run diktat to check/fix code style - run: \verb|mvn antrun:run@diktat.|
-\newline
-\textbf{Use the new diktat-maven-plugin}
-\par You can see how it is configured in our project for self-checks: pom.xml. This plugin should be available since version 0.1.2. It requires less configuration but may contain bugs. If you use it and encounter any problems, feel free to open issues on github: \url{https://github.com/cqfn/diKTat}.
-
-Add this plugin to your pom.xml:
-\begin{verbatim}
-
- org.cqfn.diktat
- diktat-maven-plugin
- ${diktat.version}
-
-
- diktat
- none
-
- check
- fix
-
-
-
- ${project.basedir}/src/main/kotlin
- ${project.basedir}/src/test/kotlin
-
- diktat-analysis.yml
-
-
-
-
-\end{verbatim}
-
-\par To run diktat check use command \verb| mvn diktat:check@diktat|.
-\par To run diktat in autocorrect mode use command \verb|mvn diktat:fix@diktat|.
\ No newline at end of file
diff --git a/wp/sections/chapter 4/rulesetConfiguration.tex b/wp/sections/chapter 4/rulesetConfiguration.tex
deleted file mode 100644
index ed12cde5f4..0000000000
--- a/wp/sections/chapter 4/rulesetConfiguration.tex
+++ /dev/null
@@ -1 +0,0 @@
-You change rules configuration in \textbf{diktat-analysis.yml}. Each rule has a description and each rule is configured by default. If rule doesn't have a default configuration than it can't be configurable.
\ No newline at end of file
diff --git a/wp/sections/compare.tex b/wp/sections/compare.tex
new file mode 100644
index 0000000000..015b1f36f3
--- /dev/null
+++ b/wp/sections/compare.tex
@@ -0,0 +1,79 @@
+\subsection{About ktlint}
+\par Ktlint is a popular an anti-bikeshedding Kotlin linter with a built-in formatter created by pinterest. It tries to capture (reflect) official code style from kotlinlang.org and Android Kotlin Style Guide and then automatically apply these rules to your codebase. Ktlint checks and can automatically fix code and it claims to be simple and easy to use. As it is focused more on checking code-style and code-smell related issues, ktlint inspections are working with Abstract Syntax Tree generated by Kotlin parser. Ktlint framework has some basic utilities to make the work with Kotlin AST easier, but anyway all inspections work with original ASTNode.
+
+Ktlint has been developing since 2016 and from then on it has 3.8k stars, 309 forks and 390 closed PRs (at least on the moment of writing this article). It looks to be the most popular and mature linter in the Kotlin community right now. There have been written ~15k lines of code.
+
+Ktlint has it’s own set of rules, which divides on standard and experimental rules. But unfortunately the number of fixers\&checkers in the standard ruleset is very few ($\approx$20 rules) and inspections are very trivial.
+
+Ktlint can be used as a plugin via Maven, Gradle or command line app. To configure rules in Ktlint you should modify .editorconfig file - this is the only configuration that ktlint provides. Actually you even can’t configure specific rules (for example to disable or suppress any of them), instead you can provide some common settings like the number of spaces for indenting. In other words, ktlint has a ”fixed hardcoded” codestyle that is not very configurable. Properties should be specified under $.kt,kts$.
+
+If you want to implement your own rules you need to create a your own ruleset. Ktlint is very user-friendly for creation of custom rulesets. In this case ktlint will parse the code using a Kotlin parser and will trigger your inspection (as visitor) for each and every node of AST. Ktlint is using java’s ServiceLoader to discover all available ”RuleSets”. ServiceLoader is used to inject your own implementation of rules for the static analysis. In this case ktlint becomes a third-party dependency and a framework. Basically you should provide implementation of RuleSetProviderinterface.
+
+Ktlint refers to article on medium on how to create a ruleset and a rule.
+
+\par A lot of projects uses ktlint as their code formatting tool. For example, OmiseGo \footnote{\url{https://github.com/omgnetwork/android-sdk}} (currently rebranding to OMG Network) - a quite popular cryptocurrency.
+
+\par To summarize: Ktlint is very mature and useful as a framework for creating your own checker\&fixer of Kotlin code and doing AST-analysis. It can be very useful if you need only simple inspections that check (and fix) code-style issues (like indents).
+\subsection{About detekt}
+\par Detekt is a static code analysis tool. It operates on an abstract syntax tree (AST) and meta-information provided by Kotlin compiler. On then top of that info, it does a complex analysis of the code. However, this project is more focused on checking the code rather than fixing. Similarly, to ktlint, it has it’s own rules and inspections. Detekt uses wrapped ktlint to redefine rules as it’s formatting rules.
+
+Detekt supports such features as code smell analysis, bugs searching and code-style checking. It has a highly configurable rule sets (can even make suppression of issues from the code). And the number of checkers is quite big: it has more than 100 inspections. Detekt has IntelliJ integration, third-party integrations for Maven, Bazel and Github actions, mechanism for suppression of their warnings with @Suppressannotation and many more. It is being developed since 2016 and today it has 3.2k stars, 411 forks and 1850 closed PRs. It has about 45k lines of code. And it’s codebase is the biggest comparing to other analyzers.
+\par Detekt is used in such projects as fountain or Kaspresso. "Fountain is an Android Kotlin library conceived to make your life easier when dealing with paged endpoint services" \footnote{\url{https://github.com/xmartlabs/fountain}} and Kaspresso is a framework for UI testing on Android made by KasperskyLab \footnote{\url{https://github.com/KasperskyLab/Kaspresso}}.
+
+\par To summarize: Detekt is very useful as a Kotlin static analyser for CI/CD. It tries to find bugs in the code and is focused more on checking of the code. Detekt has 100+ rules that check the code.
+
+\subsection{About ktfmt}
+\par Ktfmt is a program that formats Kotlin code, based on google-java-format. It's development has started in Facebook in the end of 2019. It can be added to your project through a Maven dependency, Gradle dependency, IntelliJ plugin or you can run it through a command line. Ktfmt is not a configurable application, so to change any rule logic you need to download the project and redefine some constants. Ktfmt has 214 stars, 16 forks, 20 closed PRs and around 7500 lines of code.
+
+\par To summarize: no one knows why Facebook has invested their money in this tool. Nothing new was not introduced.
+
+\subsection{About diKTat}
+Diktat as well as ktlint and detekt is a static code analysis tool. But diktat is not only a tool, but also a coding convention that in details describes all the rules that you should follow when writing a code on Kotlin. It’s development has started in 2020 and at the time of writing this article diKTat has 150 stars and 13 forks. DiKTat operates on AST provided by kotlin compiler. So why diKTat is better?
+
+First of all, it supports much more rules than ktlint. It’s ruleset includes more than 100 rules, that can both check and fix your code.
+
+Second, diKTat is configurable. A lot of rules have their own settings, and all of them can be easily understood. For example, you can choose whether you need a copyright, choose a length of line or you can configure your indents.
+
+Third, diKTat is very easy to configure. You don’t need to spend hours only to understand what each rule is doing. Diktat’s ruleset is a .yml file, where each rule is commented out with the description. Also you can suppress error on the particular lines of code using @Suppress annotation in your code.
+
+DiKTat can be used as a CI/CD tool in order to avoid merging errors in the code. Overall it can find code smells and code style issues. Also it can find pretty not obvious bugs by complex AST analysis. Diktat works with maven, gradle and as command-line application powered by ktlint.
+
+\par To summarize: diktat contains a strict coding convention that was not yet introduced by other linters. It works both as a checker and as a fixer. Diktat has much more inspections (100+) and is very configurable (each inspection can be disabled/configured separately), so you can configure it for your particular project.
+
+\subsection{A few words about Jetbrains}
+\par Jetbrains created one of the best IDEs for Java and Kotlin called IntelliJ. This IDE supports a built-in linter. However, it is not a well-configurable tool, you are not able to specify your own coding convention and it is not useful for CI/CD as it is highly coupled with UI. Unfortunately such static analysis is not so effective as it cannot prevent merging of the code with bugs into the repository. As experience shows - many developers simply ignorethose static analysis errors until they are blocked from merging their pull requests. So it is not so suitable for CI/CD, but very good for finding and fixing issues inside your IDE.
+
+\subsection{Graphics}
+
+\subsubsection{Detekt Code Frequency}
+\hfill\\
+ \includegraphics[scale = 0.5]{pictures/detekt.png}
+\subsubsection{Ktlint Code Frequency}
+\hfill\\
+ \includegraphics[scale=0.5]{pictures/ktlint.png}
+\subsubsection{Ktfmt Code Frequency}
+\hfill\\
+ \includegraphics[scale=0.5]{pictures/ktfmt.png}
+\subsubsection{DiKTat Code Frequency}
+\hfill\\
+ \includegraphics[scale=0.5]{pictures/diktat.png}
+\subsection{Summary}
+
+\begin{center}
+\begin{tabular}{ |p{3cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}| }
+\hline
+\multicolumn{5}{|c|}{\textbf{Comparing table}} \\
+\hline
+& diKTat& ktlint &detekt & ktfmt \\
+\hline
+starting year & 2020 & 2016 & 2016 & 2019 \\
+stars & 130 & 3.2k & 3.8k & 214\\
+forks & 12 & 299 & 411 & 16\\
+closed PRs & 226 & 390 & 1850 & 20 \\
+lines of code & 22k & 15k & 45k & 7,5k\\
+number of rules & $>$100 & $\approx$ 20 & $>$100 & $\approx$ 10 \\
+\hline
+
+\hline
+\end{tabular}
+\end{center}
\ No newline at end of file
diff --git a/wp/sections/conclusion.tex b/wp/sections/conclusion.tex
new file mode 100644
index 0000000000..dda3a19a79
--- /dev/null
+++ b/wp/sections/conclusion.tex
@@ -0,0 +1,2 @@
+\par DiKTat is a static code analyzer that finds and fixes code style inconsistencies. DiKTat is configurable, easy-to-use and it implements CI/CD pipelines, which distinguishes it from analogues. We offer many convenient ways to use diktat in projects, so you can use it as Maven/Gradle plugin, CLI tool, Web or github actions. It supports more than 100 rules, where each of them has clear explanation and can be configured by user.
+\par When the development of diKTat will finish, we are going to support rules, update frameworks and track latest kotlin language releases to keep diKTat relevant.
\ No newline at end of file
diff --git a/wp/sections/definition.tex b/wp/sections/definition.tex
new file mode 100644
index 0000000000..a0b2db8257
--- /dev/null
+++ b/wp/sections/definition.tex
@@ -0,0 +1,7 @@
+Before continue, it is necessary to define some terms so that the reader correctly understands the context of what was written.
+The first and basic concept that should be introduced is \textbf{"rule"}. In diKTat, a \textbf{“rule”} is the logic described in a class, which checks a certain paragraph of code style for compliance with the code.
+ You should also know that \textbf{set} - is a well-defined collection of distinct objects, considered as an object in its own right.
+ \textbf{Ruleset}, in turn, is a set of such "rules". Suppose $W_i$ is set of checks of i-th rule and $F_i$ is set of fixers of i-th rule. Then $I_i = W_i \cup F_i $ is the set of checks and fixers of the i-th rule. Let R be a ruleset, therefore $R = \sum_{k=1}^n I_k$, where n is number of turned-on rules, $I_k$ is k-th rule.
+ \textbf{Abstract syntax tree (AST)} is a tree representation of the abstract syntactic structure of source code written in a programming language. Each node of the tree denotes a construct occurring in the source code.
+ \textbf{CICD} - continuous integration (CI) and continuous delivery (CD) is a methodology that allows application development teams to make changes to code more frequently and reliably.
+ \textbf{KDoc} - is the language used to document Kotlin code (the equivalent of Java's JavaDoc).
\ No newline at end of file
diff --git a/wp/sections/diKTat.tex b/wp/sections/diKTat.tex
new file mode 100644
index 0000000000..47445425e6
--- /dev/null
+++ b/wp/sections/diKTat.tex
@@ -0,0 +1,5 @@
+\subsection{What is diKTat?}
+DiKTat - is a formal strict code style (\url{https://github.com/cqfn/diKTat}) and a linter with a set of rules that implement this code style for Kotlin language. Basically, it is a collection of Kotlin code style rules implemented as AST visitors on top of KTlint framework (\url{https://github.com/pinterest/ktlint}). Diktat warns and fixes code style errors and code smells based on configuration file. DiKTat is a highly configurable framework, that can be extended further by adding custom rules. It can be run as command line application or with maven or gradle plugins. In this paper, we will explain how DiKTat works, describes advantages and disadvantages and how it differs from other static analyzers.
+
+\subsection{Why diKTat?}
+So why did we decide to create diKTat? We looked at similar projects and realized that they have defects and their functionality does not give you a chance to implement modern configurable code style. That’s why we came to a conclusion that we need to create convenient and easy-to-use tool for developers. Why is it easy-to-use? First of all, diKTat has its own highly configurable ruleset. You just need to fill your own options on rules in ruleset or either use default one. Basically, ruleset is an yml file with a description of each rule. Secondly, there are a lot of developers that use different tools for building projects. Most popular are Maven and Gradle. DiKTat supports these ones and it also has cli. Finally, each developer has their own codestyle and sometimes they don’t want static analyzers to trigger on some lines of code. In diKTat you can easily disable a rule.
\ No newline at end of file
diff --git a/wp/sections/download.tex b/wp/sections/download.tex
new file mode 100644
index 0000000000..be69ad8549
--- /dev/null
+++ b/wp/sections/download.tex
@@ -0,0 +1,8 @@
+\subsection{CLI-application}
+\par You can run diKTat as a CLI-application by installing it first. You can find detailed instructions on how to install and run on different OS on github (\url{https://github.com/cqfn/diKTat/blob/master/README.md#run-as-cli-application}). After the run, errors will be found and displayed. Each error consists of a rule name, a description of the rule so that the user can understands the error, the line and column number where the error was found.\\
+\subsection{Plugins}
+\par Alternatively, you can add a diktat maven or gradle plugin directly to the project: detailed instructions for maven can be found here - \url{https://github.com/cqfn/diKTat/blob/master/README.md#run-with-maven}and for gralde - \url{https://github.com/cqfn/diKTat/blob/master/README.md#run-with-gradle-plugin}.\\
+\subsection{Configuratifon file}
+As described above, diKTat has a configuration file. Note that you should place the \textsl{diktat-analysis.yml} file containing the diktat configuration in the parent directory of your project when running as a CLI application. Diktat-maven-plugin and diktat-gradle-plugin have a separate option for configuration file path.
+\subsection{WEB}
+\par Of course, the easiest way to use it without any downloads or installations is the web version of the app. You can try it by following the link \url{https://ktlint-demo.herokuapp.com/demo}. Web app supports both checking and fixing, using either ktlint or diktat ruleset. For diktat you can also upload a custom configuration file.
diff --git a/wp/sections/examples.tex b/wp/sections/examples.tex
new file mode 100644
index 0000000000..3292ceff48
--- /dev/null
+++ b/wp/sections/examples.tex
@@ -0,0 +1 @@
+Describe how does diKtat work on real projects
\ No newline at end of file
diff --git a/wp/sections/feature.tex b/wp/sections/feature.tex
new file mode 100644
index 0000000000..308601ea11
--- /dev/null
+++ b/wp/sections/feature.tex
@@ -0,0 +1,137 @@
+\par As described above, diKTat is very configurable and user-friendly. But these are not all of its advantages and features. Below will be presented and described unusual and important killer-features of diKTat.
+
+\subsection{Configuration file}
+\par
+It's worth starting with the configuration file. This is a file in which the user can manually turn rules on and off or configure the rules settings. Below is one of the rules in the configuration file.
+
+
+\begin{center}
+\begin{tabular}{@{}l@{}}
+ name: FILE\underline{ }IS\underline{ }TOO\underline{ }LONG\\
+ \hspace{1cm}enabled: true\\
+ \hspace{1cm}configuration:\\
+ \hspace{2 cm}maxSize: '2000'\\
+ \hspace{2 cm}ignoreFolders: ' '\\
+\end{tabular}
+\end{center}
+
+Each rule in this file has 3 fields: name - the name of the rule, enabled - whether the rule is enabled or disabled (all rules are enabled by default), configuration - parameters for the rule. With the first two, everything is obvious. The third parameter is less obvious. The configuration is a set of "properties" to configure this rule. For example, for a rule "FILE\underline{ }IS\underline{ }TOO\underline{ }LONG", that checks the number of lines in a Kotlin file, the user can configure the maximum number of lines allowed in the file - by changing the "maxSize" in the configuration, or the user can specify paths to folders that do not need to be checked - by writing the path in "ignoreFolders". \\
+
+\subsection{Create ASTNode}
+\par
+Another feature is a method that allows you to construct an abstract syntax node from text. This algorithm can parse the code even partially, when you do not need to save the hierarchy of the file (with imports/packages/classes).
+For example it can parse and provide you a sub-tree for these lines of code:
+
+\begin{lstlisting}[caption={Example of creating node.}, label={lst:example1}, language=Kotlin]
+ val nodeFromText: ASTNode = KotlinParser().createNode("val age: Int = 21")
+\end{lstlisting}
+
+\tikzstyle{every node}=[draw=black,thick,anchor=west, scale = 0.5]
+
+\begin{tikzpicture}[%
+ grow via three points={one child at (0.3,-0.8) and
+ two children at (0.3,-0.8) and (0.3,-1.5)},
+ scale=0.5,
+ edge from parent path={(\tikzparentnode.south) |- (\tikzchildnode.west)}]
+
+ \node {PROPERTY}
+ child { node {val}}
+ child {node {WHITE\underline{ }SPACE}}
+ child {node {IDENTIFIER}}
+ child {node {COLON}}
+ child {node {WHITE\underline{ }SPACE}}
+ child {node {TYPE\underline{ }REFERENCE}
+ child {node {USER\underline{ }TYPE}
+ child {node {REFERENCE\underline{ }EXPRESSION}
+ child {node {IDENTIFIER}}
+ }
+ }
+ }
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child {node {WHITE\underline{ }SPACE}}
+ child {node {EQ}}
+ child {node {WHITE\underline{ }SPACE}}
+ child {node {INTEGER\underline{ }CONSTANT}
+ child {node {INTEGER\underline{ }LIRETAL}}
+ };
+\end{tikzpicture}
+
+As you can see in the examples, we pass to the method the text of the source code that we want to transform and the flag, which is set to false by default. The flag should be set to true in order to immediately build a tree with a root node of the FILE type. What's going on inside this method? First of all, the system properties are set (for example: set "idea.io.use.nio2" to true). Further in the method, the text is checked. If the text of the code contains such keywords as import or package, then the method builds a tree with a root node of the FILE type, otherwise it tries with a different root type. In both cases, at the end, if the tree contains an ERROR\underline{ }ELEMENT type of node, it means that an error was made in the code and the method was unable to build the tree and, therefore, throws an exception.\\
+This helps us to implement such complex inspections like the detection of commented code, helps easily fix the code without manually building sub-trees in visitors\\
+
+\subsection{"SUPPRESS annotation"}
+\par
+What if the user wants one of the diKTat rules not to check a piece of code? The \textsl{SUPPRESS} annotation will help with this. This annotation can be supplied to ignore a certain rule. For instance, if run this code:
+
+\begin{lstlisting}[caption={Function with incorrect name.}, label={lst:example1}, language=Kotlin]
+ /**
+* This is example
+*/
+
+package org.cqfn.diktat
+
+/**
+* Simple class
+*/
+class User(private val name: String, private val age: Int) {
+ /**
+ * Function with incorrect name
+ *
+ * @return is username longer than age
+ */
+ fun IsInCoRrEcTnAMe() = name.length > age
+}
+
+\end{lstlisting}
+
+There will be warning:
+$$
+\texttt{ \small{ $\big[$FUNCTION\underline{ }NAME\underline{ }INCORRECT\underline{ }CASE$\big]$ function/method name should be in lowerCamelCase}}
+$$
+
+But if there is a \textsl{@SUPPRESS} before this method, then there will be no errors at run.
+\begin{lstlisting}[caption={Function with incorrect name, but with suppress.}, label={lst:example1}, language=Kotlin]
+ /**
+* This is example
+*/
+
+package org.cqfn.diktat
+
+/**
+* Simple class
+*/
+@Suppress("FUNCTION_NAME_INCORRECT_CASE")
+class User(private val name: String, private val age: Int) {
+ /**
+ * Function with incorrect name
+ *
+ * @return is username longer than age
+ */
+ fun IsInCoRrEcTnAMe() = name.length > age
+}
+
+\end{lstlisting}
+
+The example shows that the method has SUPPRESS annotation. Therefore, the \\ FUNCTION\underline{ }NAME\underline{ }INCORRECT\underline{ }CASE rule will be ignored on this method and there will be no error. The search method for a given annotation goes up recursively to the root element of type FILE, looking for the annotation. This means that Suppress can be placed not only in front of knowingly incorrect code, but also at the upper levels of the abstract tree. In our example, the annotation is not in front of the method, but in front of the class and still works. Also, you can put several annotations:
+\begin{lstlisting}[caption={Function with incorrect name, but with suppress.}, label={lst:example1}, language=Kotlin]
+@set:[Suppress("WRONG_DECLARATION_ORDER") Suppress("IDENTIFIER_LENGTH")]
+\end{lstlisting}
+
+\subsection{WEB}
+\par
+Also worth mentioning is the existence of a web version of diKTat.. This is a very handy tool that can be used quickly, and most importantly, it is very simple. The link can be found in or you can find it in "\nameref{sec:download}" chapter or in ktlint project as reference.\footnote{\url{https://github.com/pinterest/ktlint\#online-demo}}
+\begin{figure}[H]
+ \centering
+ \includegraphics[scale=0.3]{pictures/web-example.png}
+ \caption{Example of web application}
+\end{figure}
+
+\subsection{Validation rules}
+\par
+As it has been mention earlier, diktat has a highly customizable configuration file, but manually editing it is error-prone, for example, name of the rule can be incorrect due to a typo. Diktat will validate configuration file on startup and suggest the closest name based on \textsl{Levenshtein} method.
+
+\subsection{CI-CD}
+\par
+One of the most important parts of open source project is CI/CD pipeline as it brings considerable benefits to the entire software development process. It improves code quality, customer satisfaction and reduces costs, including time, of making new features.
\ No newline at end of file
diff --git a/wp/sections/introduction.tex b/wp/sections/introduction.tex
index 1e118db080..af000f4b51 100644
--- a/wp/sections/introduction.tex
+++ b/wp/sections/introduction.tex
@@ -1,26 +1,7 @@
-It is necessary to conform to a specific style of code during software development, otherwise it will reduce the ability to better understand programmers’ intent and
-find more functional defects. Analyzers, in turn, have methods for finding and correcting style errors.
+It is necessary to conform to a specific style of code during software development, otherwise it will reduce the ability to better understand programmers’ intent and find more functional defects. Analyzers, in turn, have methods for finding and correcting style errors.
-There are two types of code analysis: static and dynamic. The first is the process of identifying errors in the source code of the program, the second is the method
- of analyzing the code directly during its execution.
+Static code analysis is useful not only for optimization and increasing effectiveness but also for automatic error detection.
-Static analysis can be thought of as an automated code review process. Of the tasks solved by static code analysis programs, two main ones can be
-distinguished: identifying errors in programs and recommending code formatting. That is, the analyzer allows you to check whether the source code complies with the
-accepted coding standard. Also, a static analyzer can be used to determine the maintainability of a code, which is how easy it is to analyze, modify and adapt a given
-software. Static analysis tools allow you to identify a large number of errors in the design phase, which significantly reduces the development cost of the entire project.
-Static analysis covers the entire code - it checks even those code fragments that are difficult to test. It does not depend on the compiler used and the environment
-in which the compiled program will be executed.There are both open source\footnote{KtLint: \url{https://github.com/pinterest/ktlint},
-Detekt: \url{https://github.com/detekt/detekt}}, and commercial \footnote{IBM Security AppScan: \url{https://www.hcltechsw.com/wps/portal/products/appscan},
-PVS-Studio: \url{https://www.viva64.com/en/pvs-studio/}}.
+There are many methods and techniques used by existing analyzers to find bugs (path-sensitive data flow analysis \cite{ref:kremenek}, alias analysis \cite{ref:effective}, type analysis \cite{ref:simple}, symbolic execution \cite{ref:dis}, abstract interpretation \cite{ref:dis}.
-DiKTat - is a formal strict code style (\url{https://github.com/cqfn/diKTat}) and a linter with a set of rules that implement this code style. Basically, it is a collection
-of Kotlin code style rules implemented as AST visitors on top of KTlint framework (\url{https://github.com/pinterest/ktlint}). Diktat warns and fixes code style errors and
-code smells based on configuration file. DiKTat is a highly configurable framework, that can be extended further by adding custom rules. It can be run as command line
-application or with maven or gradle plugins. In this paper, we will explain how DiKTat works, describes advantages and disadvantages and how it differs from other static
-analyzers.
-
-So why did we decide to create diKTat? We looked at similar projects and realized that they have defects. That’s why we came to a conclusion that we need to create
-convenient and easy-to-use tool for developers. Why is it easy-to-use? First of all, diKTat has its own highly configurable ruleset. You just need to fill your own options
-on rules in ruleset or either use default one. Basically, ruleset is an yml file with a description of each rule. Secondly, there are a lot of developers that use different
-tools for building projects. Most popular are Maven and Gradle. DiKTat supports these ones and it also has cli. Finally, each developer has their own codestyle and sometimes
-they don’t want static analyzers to trigger on some lines of code. In diKTat you can easily disable a rule.
+Static analysis can be thought of as an automated code review process. Of the tasks solved by static code analysis programs, two main ones can be distinguished: identifying errors in programs and recommending code formatting. That is, the analyzer allows you to check whether the source code complies with the accepted coding standard. Also, a static analyzer can be used to determine the maintainability of a code, which is how easy it is to analyze, modify and adapt a given software. Static analysis tools allow you to identify a large number of errors in the design phase, which significantly reduces the development cost of the entire project. Static analysis covers the entire code - it checks even those code fragments that are difficult to test. It does not depend on the compiler used and the environment in which the compiled program will be executed.
\ No newline at end of file
diff --git a/wp/sections/kotlin.tex b/wp/sections/kotlin.tex
new file mode 100644
index 0000000000..c79347c6e0
--- /dev/null
+++ b/wp/sections/kotlin.tex
@@ -0,0 +1,34 @@
+\par Kotlin is a cross-platform, statically typed, general-purpose programming language with type inference. Kotlin is designed to interoperate fully with Java, and the JVM version of Kotlin's standard library depends on the Java Class Library, but type inference allows its syntax to be more concise. Kotlin mainly targets the JVM, but also compiles to JavaScript (e.g. for frontend web applications using React) or native code (via LLVM), e.g. for native iOS apps sharing business logic with Android apps. % wikipedia
+
+\par Kotlin has quickly skyrocketed in popularity. It's used by companies like Google, Square, Pinterest, Pivotal, Netflix and Atlassian. It's the fastest-growing programming language, according to GitHub, growing over 2,5 times in the past year. It was voted one of the five most loved languages, according to Stack Overflow. There are even meetups focused on Kotlin. \footnote{\url{https://www.businessinsider.com/kotlin-programming-language-explained-popularity-2019-5\#:\~:text=Kotlin\%20has\%20quickly\%20skyrocketed\%20in,times\%20in\%20the\%20past\%20year}}
+% https://www.businessinsider.com/kotlin-programming-language-explained-popularity-2019-5#:~:text=Kotlin%20has%20quickly%20skyrocketed%20in,times%20in%20the%20past%20year.
+\par Kotlin is used in a lot of ways. For example it can be used for backend development using ktor framework (developed by JetBrains), and spring framework also has first-party support for kotlin (Spring is one of the most popular framework on Java for Web development). Kotlin/JS provides the ability to transpile your Kotlin code to JavaScript, as well as providing JS variant of kotlin standard library and interopability with existing JS dependencies, both for Node.js and browser. There are numerous ways that Kotlin/JS can be used. For instance, you can write frontend web applications using Kotlin/JS,
+write server-side and serverless applications using Kotlin/JS, create libraries for use with JavaScript and TypeScript. Support for multiplatform programming is one of Kotlin’s key benefits. It reduces time spent writing and maintaining the same code for different platforms while retaining the flexibility and benefits of native programming.
+
+\par Asynchronous or non-blocking programming is the new reality. Whether we're creating server-side, desktop or mobile applications, it's important that we provide an experience that is not only fluid from the user's perspective, but scalable when needed.
+There are many approaches to this problem, and Kotlin takes a very flexible one by providing Coroutine support as a first-party library kotlinx.coroutines with a kotlin compiler plugin and delegating most of the functionality to libraries, much in line with Kotlin's philosophy.
+As a bonus, coroutines not only open the doors to asynchronous programming, but also provide a wealth of other possibilities such as concurrency, actors, etc.
+
+A coroutine is a concurrency design pattern that you can use on Android to simplify code that executes asynchronously. Coroutines(in a form of kotlinx.coroutines library and kotlin compiler plugin) were added to Kotlin in version 1.3 and are based on established concepts from other languages.
+
+On Android, coroutines help to manage long-running tasks that might otherwise block the main thread and cause your app to become unresponsive. Over 50\% of professional developers who use coroutines have reported seeing increased productivity. Coroutines enable you to write cleaner and more concise app code.
+
+The state of Kotlin in 2020 (according to the latest Kotlin Census and statistical data)
+\begin{itemize}
+ \item 4,7 million users
+ \item 65\% of users use Kotlin in production
+ \item For 56\% of users, Kotlin is their primary language, which means the main or only
+ one they use at work
+ \item 100+ people are on the Kotlin development team at JetBrains
+ \item 350+ independent contributors develop the language and its ecosystem outside
+ of JetBrains
+\end{itemize}
+
+% https://techcrunch.com/2019/05/07/kotlin-is-now-googles-preferred-language-for-android-app-development/
+Kotlin is widely used among Android developers, including open source OS, like HarmonyOS, that are compatible with Android. In 2019 Google announced that the Kotlin programming language is now its preferred language for Android app developers. In the same year Stack Overflow stated that Kotlin is fourth most loved language in community. Nowadays there are over 60\% of android developers who use Kotlin as their main language. \footnote{\url{https://techcrunch.com/2019/05/07/kotlin-is-now-googles-preferred-language-for-android-app-development/}}
+\par Kotlin's popularity can be explained by the rising number of Android users (last year, 124.4m in the USA) and, thus, Android-based devices. 80\% of Kotlin programmers use the language to build Android apps, 31\% for back-end applications, 30\% for SDK/libraries.
+Kotlin is also interoperable with Java, which allows developers to use all existing Android libraries in a Kotlin app. Kotlin is in the top of PYPL rating.
+\newline
+\includegraphics[scale = 0.5]{pictures/kotlinRating.png}
+\newline
+\par Overall, Kotlin is a modern language that gain it's popularity incredibly fast. It is mostly used by Android developers, but other "branches of programming" are gaining popularity as well, for example spring framework(the most popular Java framework) is supporting Kotlin. It supports both OO (object-oriented) and FP (function-oriented) programming paradigms. Since release 1.4 Kotlin claims to bring major updated every 6 month.
\ No newline at end of file
diff --git a/wp/sections/work.tex b/wp/sections/work.tex
new file mode 100644
index 0000000000..e6c49eb72a
--- /dev/null
+++ b/wp/sections/work.tex
@@ -0,0 +1,194 @@
+Diktat does AST-analysis. This means that for internal representation (IR) it uses Abstract Syntax Tree that was created from the parsed code by the kotlin-compiler. This chapter describes how diktat works
+
+\subsection{ktlint}
+\par
+To quickly and efficiently analyze the program code, you first need to transform it into a convenient data structure. This is exactly what ktlint does - it parses plain text code into an abstract syntax tree. In ktlint, this happens in the \textsl{prepareCodeForLinting}\footnote{\url{https://github.com/pinterest/ktlint/blob/master/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/KtLint.kt}} method. This method uses kotlin-compiler-embeddable library to create a root node of type FILE.
+For example, this simple code:
+\begin{lstlisting}[caption={Simple function.}, label={lst:example1}, language=Kotlin]
+ fun main() {
+ println("Hello World")
+ }
+\end{lstlisting}
+will be converted into this AST:\\
+
+\tikzstyle{every node}=[draw=black,thick,anchor=west, scale = 0.5]
+
+\begin{tikzpicture}[%
+ grow via three points={one child at (0.3,-0.8) and
+ two children at (0.3,-0.8) and (0.3,-1.5)},
+ scale=0.5,
+ edge from parent path={(\tikzparentnode.south) |- (\tikzchildnode.west)}]
+
+ \node {FILE}
+ child { node {PACKAGE\underline{ }DIRECTIVE}}
+ child { node {IMPORT\underline{ }LIST}}
+ child { node {FUN}
+ child {node {fun}}
+ child {node {WHITE\underline{ }SPACE}}
+ child {node {IDENTIFIER}}
+ child {node {VALUE\underline{ }PARAMETER\underline{ }LIST}
+ child {node {LPAR}}
+ child {node {RPAR}}
+ }
+ child [missing] {}
+ child [missing] {}
+ child {node {WHITE\underline{ }SPACE}}
+ child {node {BLOCK}
+ child {node {LBRACE}}
+ child {node {WHITE\underline{ }SPACE}}
+ child {node {CALL\underline{ }EXPRESSION}
+ child {node {REFERENCE\underline{ }EXPRESSION}
+ child {node {IDENTIFIER}}
+ }
+ child [missing] {}
+ child {node {VALUE\underline{ }ARGUMENT\underline{}LIST}
+ child {node {LPAR}}
+ child {node {VALUE\underline{ }ARGUMENT}
+ child {node {STRING\underline{ }TEMPLATE}
+ child {node {OPEN\underline{ }QUOTE}}
+ child {node {LITERAL\underline{ }STRING\underline{ }TEMPLATE\underline{ }ENTRY}
+ child {node {REGULAR\underline{ }STRING\underline{ }PART}}
+ }
+ child [missing] {}
+ child {node {CLOSING\underline{ }QUOTE}}
+ }
+ }
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child {node {RPAR}}
+ }
+ }
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child [missing] {}
+ child {node {WHITE\underline{ }SPACE}}
+ child {node {RBRACE}}
+ }
+ };
+\end{tikzpicture}
+
+If there are error elements inside the constructed tree, then the corresponding error is displayed. If the code is valid and parsed without errors, for each rule in the ruleset, the \textsl{visit} method is called to which the root node itself and its “children” are sequentially passed.
+When you run program, you can pass flags to ktlint - one of them is "-F". This flag means that the rule will not only report an error, but try to fix it.
+
+\subsection{diKTat}
+\par
+Another feature of ktlint is that at startup you can provide a JAR file with additional ruleset(s), which will be discovered by the ServiceLoader and then all nodes will be passed to these rules. This is diKTat! DiKTat is a set of easily configurable rules for static code analysis. The set of all rules is described in the \textsl{DiktatRuleSetProvider}\footnote{\url{https://github.com/cqfn/diKTat/blob/v0.1.3/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt}} class. This class overrides the \textsl{get()} method of the \textsl{RuleSetProvider}\footnote{\url{https://github.com/pinterest/ktlint/blob/master/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/RuleSetProvider.kt}} interface, which returns a set of rules to be "traversed". But before returning this set, the configuration file, in which the user has independently configured all the rules, is read. If there is no configuration file, then a warning will be displayed and the rules will be triggered in according with the default configuration file.
+Each rule must implement the \textsl{visit} method of the abstract Rule class, which describes the logic of the rule.
+
+//TODO: add comments
+\begin{lstlisting}[caption={Example of rule.}, label={lst:example1}, language=Kotlin]
+class SingleLineStatementsRule(private val configRules: List) : Rule("statement") {
+
+ companion object {
+ private val semicolonToken = TokenSet.create(SEMICOLON)
+ }
+
+ private lateinit var emitWarn: ((offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit)
+ private var isFixMode: Boolean = false
+
+ override fun visit(node: ASTNode,
+ autoCorrect: Boolean,
+ emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) {
+ emitWarn = emit
+ isFixMode = autoCorrect
+
+ checkSemicolon(node)
+ }
+
+ private fun checkSemicolon(node: ASTNode) {
+ node.getChildren(semicolonToken).forEach {
+ if (!it.isFollowedByNewline()) {
+ MORE_THAN_ONE_STATEMENT_PER_LINE.warnAndFix(configRules, emitWarn, isFixMode, it.extractLineOfText(),
+ it.startOffset, it) {
+ if (it.treeParent.elementType == ENUM_ENTRY) {
+ node.treeParent.addChild(PsiWhiteSpaceImpl("\n"), node.treeNext)
+ } else {
+ if (!it.isBeginByNewline()) {
+ val nextNode = it.parent({ parent -> parent.treeNext != null }, strict = false)?.treeNext
+ node.appendNewlineMergingWhiteSpace(nextNode, it)
+ }
+ node.removeChild(it)
+ }
+ }
+ }
+ }
+ }
+}
+\end{lstlisting}
+
+The example above describes the rule in which you cannot write more than two statements on one line. The list of configurations is passed to the parameter of this rule so that the error is displayed only when the rule is enabled (further it will be described how to enable and disable the rule). The class fields and the \textsl{visit} method are described below. The first parameter in method is ASTNode - the node that we got in the parsing in ktlint. Then a check occurs: if the code contains a line in which more than one statement per line and this rule is enabled, then the rule will be executed and, depending on the mode in which the user started ktlint, the rule will either simply report an error or fix it. In our case, when an error is found, the method is called to report and fix the error - \textsl{warnAndFix()}. Warnings that contain similar logic (e.g. regarding formatting of function KDocs) are checked in the same Rule. This way we can parse similar parts of AST only once. Whether the warning is enabled or disabled is checked at the very last moment, inside \textsl{warn()} or \textsl{warnAndFix()} methods. Same is true for suppressions: right before emitting the warning we check whether any of current node's parents has a Suppress annotation.
+
+\subsection{Examples of unique inspections}
+\par
+As already described above, diKTat has more rules than existing analogues, therefore, it will find and fix more errors and shortcomings and, thereby, make the code cleaner and better. To better understand how much more detailed the diKTat finds errors, consider a few examples:
+
+\begin{enumerate}
+ \item \textbf{Package}
+In diKTat, there are about 6 rules only for package (examples). For comparison: detekt has only one rule, where the package name is simply checked by a pattern, in ktlint there is no.
+ \item \textbf{KDoc}
+KDoc is an important part of good code to make it easier to understand and navigate the program. In diKTat there are 15 rules on KDoc, in detekt there are only 7. Therefore, diKTat will make and correct KDoc in more detail and correctly. Examples of rules that have no analogues: examples
+ \item \textbf{Header}
+Like KDoc, header is an essential part of quality code. DiKTat has as many as 6 rules for this, while detekt and ktlint do not. (Examples)
+\end{enumerate}
+
+There are also many unique rules that no analogues have, here are some of them:
+
+\begin{enumerate}
+ \item \textbf{COMMENTED\underline{ }OUT\underline{ }CODE} – This rule performs checks if there is any commented code.
+ \item \textbf{FILE\underline{ }CONTAINS\underline{ }ONLY\underline{ }COMMENTS} – This rule checks file contains not only comments.
+ \item \textbf{LOCAL\underline{ }VARIABLE\underline{ }EARLY\underline{ }DECLARATION} – This rule checks that local variables are declared close to the point where they are first used.
+ \item \textbf{AVOID\underline{ }NESTED\underline{ }FUNCTIONS} - This rule checks for nested functions and warns and fixes if it finds any. An example of changing the tree when this rule is triggered and diKTat is run with fix mode:\\
+ \begin{tikzpicture}[%
+ grow via three points={one child at (0.3,-0.8) and
+ two children at (0.3,-0.8) and (0.3,-1.5)},
+ scale=0.5,
+ edge from parent path={(\tikzparentnode.south) |- (\tikzchildnode.west)}]
+
+ \node(a) {...}
+ child { node {FUN}
+ child {node {...}}
+ child {node {BLOCK}
+ child {node {FUN}
+ child{node{...}}
+ child{node{BLOCK}
+ child{node{...}}
+ }
+ }
+ }
+ };
+
+ \node(b) [right of=a, xshift=17cm]{...}
+ child { node {FUN}
+ child {node {...}}
+ child {node {BLOCK}
+ child{node{...}}
+ }
+ }
+ child [missing] {}
+ child [missing] {}
+ child { node {FUN}
+ child {node {...}}
+ child {node {BLOCK}
+ child{node{...}}
+ }
+ };
+
+ \draw[-latex,very thick,shorten <=5mm,shorten >=5mm,] ([xshift=5cm,yshift=-3cm]a.north) to ([xshift=-2cm, yshift=-3cm]b.north);
+
+\end{tikzpicture}
+ \item \textbf{FLOAT\underline{ }IN\underline{ }ACCURATE\underline{ }CALCULATIONS} - Rule that checks that floating-point numbers are not used for accurate calculations.
+\end{enumerate}
diff --git a/wp/wp.tex b/wp/wp.tex
index 8c8d301661..6dda8c00c6 100644
--- a/wp/wp.tex
+++ b/wp/wp.tex
@@ -1,16 +1,33 @@
-\documentclass[12pt]{article}
+\documentclass[acmlarge, screen, nonacm]{acmart}
+\usepackage[utf8]{inputenc}
+\usepackage{graphicx}
\usepackage{pgf}
+\usepackage{multicol}
\usepackage{setspace}
- \setstretch{1.1}
-\usepackage[top=1.3in, left=1.4in, includefoot]{geometry}
\usepackage{charter}
\usepackage{listings}
-\usepackage{authblk}
+\usepackage{hyperref}
+\usepackage{float}
+\usepackage{placeins}
+\usepackage{graphicx}
+\graphicspath{ {./images/} }
+\usepackage{tikz}
+\usepackage{verbatim}
+\usepackage{cleveref}
+\usepackage{datetime}
+
+\crefname{figure}{Figure}{Figures}
+\usetikzlibrary{trees}
+\usetikzlibrary{arrows}
\definecolor{codegreen}{rgb}{0,0.6,0}
\definecolor{codegray}{rgb}{0.5,0.5,0.5}
\definecolor{codepurple}{rgb}{0.58,0,0.82}
\definecolor{backcolour}{rgb}{0.95,0.95,0.92}
+\definecolor{OrangeRed}{rgb}{1,0.27,0}
+\definecolor{ForestGreen}{rgb}{0.1334,0.545,0.1334}
+\definecolor{NavyBlue}{rgb}{0,0.502,0}
+\definecolor{BurntOrange}{rgb}{0.8,0.3334,0.1334}
\lstdefinestyle{mystyle}{
backgroundcolor=\color{backcolour},
@@ -31,81 +48,121 @@
tabsize=2
}
-\lstset{style=mystyle}
-
-\title{
- \includegraphics[height=250pt]{logo.png}\\
- \vspace{10pt}
- \textsc{DiKTat:}\\
- Static Code Analysis}
-\author{Yegor Bugayenko, Andrey Kuleshov, Peter Trifanov, Kumar Denis, Tsay Alexander}
-\affil{Huawei Technologies Co., Ltd. \\ System Programming Lab \\ Russian Research Institute (RRI) \\ Moscow, Russia}
-
-\begin{document}
+\lstdefinelanguage{Kotlin}{
+ comment=[l]{//},
+ commentstyle={\color{gray}\ttfamily},
+ emph={delegate, filter, first, firstOrNull, forEach, lazy, map, mapNotNull, println, return@},
+ emphstyle={\color{OrangeRed}},
+ identifierstyle=\color{black},
+ keywords={abstract, actual, as, as?, break, by, class, companion, continue, data, do, dynamic, else, enum, expect, false, final, for, fun, get, if, import, in, interface, internal, is, null, object, override, package, private, public, return, set, super, suspend, this, throw, true, try, typealias, val, var, vararg, when, where, while},
+ keywordstyle={\color{NavyBlue}\bfseries},
+ morecomment=[s]{/*}{*/},
+ morestring=[b]",
+ morestring=[s]{"""*}{*"""},
+ ndkeywords={@Deprecated, @JvmField, @JvmName, @JvmOverloads, @JvmStatic, @JvmSynthetic, Array, Byte, Double, Float, Int, Integer, Iterable, Long, Runnable, Short, String},
+ ndkeywordstyle={\color{BurntOrange}\bfseries},
+ sensitive=true,
+ stringstyle={\color{ForestGreen}\ttfamily},
+}
-\maketitle
+\lstset{style=mystyle}
+\settopmatter{printacmref=false}
+\setcopyright{none}
+\makeatletter
+\let\@authorsaddresses\@empty
-\pagebreak
+\makeatletter
+\let\newdate\@date
-\begin{abstract}
+\settopmatter{printacmref=false}
+\setcopyright{none}
+\renewcommand\footnotetextcopyrightpermission[1]{}
+\pagestyle{plain}
-DiKTat is a collection of Kotlin code style rules implemented as AST visitors on top of KTlint. Diktat warns and fixes code style errors based on configuration file. DiKTat can be extended further by adding custom rules. In this paper, we explain how DiKTat works, describe advantages and disadvantages and how it differs from other static analyzers.
+\begin{document}
-\end{abstract}
+\title[]{
+ \includegraphics[width = 230pt, height = 200pt]{wp/pictures/logo.png}\\
+ DiKTat - Kotlin linter
+}
-\newpage
+\author{Andrey Kuleshov}
+\email{andrewkuleshov7@gmail.com}
+\affiliation{
+\institution{Lomonosov Moscow State University}
+\country{Russia}
+}
+\author{Petr Trifanov}
+\email{peter.trifanov@mail.ru}
+\affiliation{
+\institution{Lomonosov Moscow State University}
+\country{Russia}
+}
+\author{Denis Kumar}
+\email{qbextted0@gmail.com}
+\affiliation{
+\institution{Higher School of Economics}
+\country{Russia}
+}
+\author{Alexander Tsay}
+\email{aktsay6@gmail.com}
+\affiliation{
+\institution{Higher School of Economics}
+\country{Russia}
+}
-\tableofcontents
+\renewcommand{\shortauthors}{}
-\newpage
+\maketitle
\section{Introduction}
\label{sec:intro}
\input{sections/introduction}
-\newpage
+\section{Definition}
+\label{sec:definition}
+\input{sections/definition}
-\section{How does diKTat work}
-\subsection{The idea}
-\subsection{Rules description}
-\subsection{How diKTat detects issues}
-\subsection{DiKTat implementation}
-\subsection{Examples}
+\section{Kotlin}
+\label{sec:kotlin}
+\input{sections/kotlin}
-\newpage
+\section{diKTat}
+\label{sec:diKTat}
+\input{sections/diKTat}
-\section{Analysis of similar projects}
-\subsection{Ktlint}
-\subsection{Detekt}
-\newpage
+\section{Comparative analysis}
+\label{sec:compare}
+\input{sections/compare}
-\section{How to use diKTat}
-\subsection{Maven}
-\input{sections/chapter 4/maven}
-\subsection{Gradle}
-\input{sections/chapter 4/gradle}
-\subsection{CLI-application}
-\input{sections/chapter 4/cli}
-\subsection{How to configure ruleset}
-\input{sections/chapter 4/rulesetConfigure}
-\newpage
+\section{How does it work}
+\label{sec:work}
+\input{sections/work}
-\section{DiKTat on big projects}
+\section{Killer-Feature}
+\label{sec:feature}
+\input{sections/feature}
-\newpage
-\section{Appendix}
-\subsection{Main components}
-\subsubsection{Data diagram}
-\subsubsection{Class diagram}
-\subsubsection{Component view}
+\section{How to use diKTat}
+\label{sec:download}
+\input{sections/download}
-\subsection{Diagrams of system usage}
-\subsubsection{Use-case diagram}
-\subsubsection{Activity diagram}
-\subsubsection{Data Flow Diagram}
+\section{Examples}
+\label{sec:examples}
+\input{sections/examples}
+
+\section{Conclusion \& Future Work}
+\label{sec:conclusion}
+\input{sections/conclusion}
\newpage
-\section{References}
+\nocite{*}
+\bibliographystyle{ieeetr}
+\bibliography{references.bib}
+\newpage
+\section{Appendix}
+\label{sec:appendix}
+\input{sections/appendix}
\end{document}