Skip to content

Commit

Permalink
Merge branch 'master' into feature/rule-6.1.7-implicit-backing-property(
Browse files Browse the repository at this point in the history
#443)

# Conflicts:
#	diktat-analysis.yml
#	diktat-rules/src/main/kotlin/generated/WarningNames.kt
#	diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt
#	diktat-rules/src/main/resources/diktat-analysis-huawei.yml
#	diktat-rules/src/main/resources/diktat-analysis.yml
  • Loading branch information
aktsay6 committed Nov 23, 2020
2 parents 3b65bf5 + d8651d2 commit ed96214
Show file tree
Hide file tree
Showing 43 changed files with 481 additions and 29 deletions.
3 changes: 3 additions & 0 deletions diktat-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,9 @@
# 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
Expand Down
36 changes: 30 additions & 6 deletions diktat-gradle-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -14,20 +15,24 @@ repositories {
jcenter()
}

val ktlintVersion: String by project
val diktatVersion = project.version
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"))

implementation("com.pinterest.ktlint:ktlint-core:$ktlintVersion") {
exclude("com.pinterest.ktlint", "ktlint-ruleset-standard")
}
implementation("com.pinterest.ktlint:ktlint-reporter-plain:$ktlintVersion")
implementation("org.cqfn.diktat:diktat-rules:$version")
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 {
val versionsFile = File("$buildDir/generated/src/main/generated/Versions.kt")
val versionsFile = File("$buildDir/generated/src/generated/Versions.kt")

outputs.file(versionsFile)

Expand All @@ -43,14 +48,16 @@ val generateVersionsFile by tasks.registering {
)
}
}
sourceSets.main.get().java.srcDir("$buildDir/generated/src/main")
sourceSets.main.get().java.srcDir("$buildDir/generated/src")

tasks.withType<KotlinCompile> {
kotlinOptions {
// fixme: kotlin 1.3 is required for gradle <6.8
languageVersion = "1.3"
apiVersion = "1.3"
jvmTarget = "1.8"
}

dependsOn.add(generateVersionsFile)
}

Expand All @@ -66,3 +73,20 @@ gradlePlugin {
java {
withSourcesJar()
}

// === testing & code coverage, consistent with maven
tasks.withType<Test> {
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")
}
}
23 changes: 22 additions & 1 deletion diktat-gradle-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,39 @@
<artifactId>exec-maven-plugin</artifactId>
<inherited>false</inherited>
<executions>
<execution>
<id>gradle-test</id>
<phase>test</phase>
<configuration>
<executable>${gradle.executable}</executable>
<arguments>
<argument>clean</argument>
<argument>jacocoTestReport</argument>
<argument>-Pgroup=${project.groupId}</argument>
<argument>-Pversion=${project.version}</argument>
<argument>-Pdescription=${project.description}</argument>
<argument>-PktlintVersion=${ktlint.version}</argument>
<argument>-PjunitVersion=${junit.version}</argument>
<argument>-S</argument>
</arguments>
<skip>${skip.gradle.build}</skip>
</configuration>
<goals>
<goal>exec</goal>
</goals>
</execution>
<execution>
<id>gradle</id>
<phase>prepare-package</phase>
<configuration>
<executable>${gradle.executable}</executable>
<arguments>
<argument>clean</argument>
<argument>${gradle.task}</argument>
<argument>-Pgroup=${project.groupId}</argument>
<argument>-Pversion=${project.version}</argument>
<argument>-Pdescription=${project.description}</argument>
<argument>-PktlintVersion=${ktlint.version}</argument>
<argument>-PjunitVersion=${junit.version}</argument>
<argument>-S</argument>
</arguments>
<skip>${skip.gradle.build}</skip>
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
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, "$pwd" + listOf("src", "**", "*.kt").joinToString(File.separator, prefix = 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", "$pwd${listOf("src", "**", "*.kt").joinToString(File.separator, prefix = File.separator)}"),
DiktatExtension().apply {
inputs = project.files("src/**/*.kt")
debug = true
}
)
}

private fun registerDiktatTask(extension: DiktatExtension) = project.tasks.register(
"test", DiktatJavaExecTaskBase::class.java,
"6.7", extension, project.configurations.create("diktat")
)

private fun assertCommandLineEquals(expected: List<String?>, extension: DiktatExtension) {
val task = registerDiktatTask(extension).get()
Assertions.assertIterableEquals(expected, task.commandLine)
}
}
Original file line number Diff line number Diff line change
@@ -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")
)
}
}
2 changes: 2 additions & 0 deletions diktat-rules/src/main/kotlin/generated/WarningNames.kt
Original file line number Diff line number Diff line change
Expand Up @@ -220,5 +220,7 @@ public object WarningNames {

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"
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ enum class Warnings(val canBeAutoCorrected: Boolean, val ruleId: String, private
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")
;

Expand Down
Original file line number Diff line number Diff line change
@@ -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<RulesConfig>) : 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)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class DiktatRuleSetProvider(private val diktatConfigFile: String = "diktat-analy
::BracesInConditionalsAndLoopsRule,
::BlockStructureBraces,
::EmptyBlock,
::AvoidEmptyPrimaryConstructor,
::EnumsSeparated,
::SingleLineStatementsRule,
::MultipleModifiersSequence,
Expand Down Expand Up @@ -108,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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -44,8 +43,10 @@ class PackageNaming(private val configRules: List<RulesConfig>) : 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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -44,7 +43,8 @@ class SingleInitRule(private val configRule: List<RulesConfig>) : 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) {
Expand Down Expand Up @@ -97,7 +97,8 @@ class SingleInitRule(private val configRule: List<RulesConfig>) : 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
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -39,7 +44,7 @@ class BlankLinesRule(private val configRules: List<RulesConfig>) : 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
Expand All @@ -53,7 +58,10 @@ class BlankLinesRule(private val configRules: List<RulesConfig>) : 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)
}
}
}
Loading

0 comments on commit ed96214

Please sign in to comment.