Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check if copyright year is valid #270

Merged
merged 11 commits into from
Sep 22, 2020
2 changes: 1 addition & 1 deletion diktat-rules/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@
</execution>
</executions>
<configuration>
<mainClass>org.cqfn.diktat.ruleset.generation.WarningsGenerationKt</mainClass>
<mainClass>org.cqfn.diktat.ruleset.generation.GenerationKt</mainClass>
</configuration>
</plugin>
<plugin>
Expand Down
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 @@ -83,6 +83,8 @@ object WarningNames {

const val HEADER_MISSING_OR_WRONG_COPYRIGHT: String = "HEADER_MISSING_OR_WRONG_COPYRIGHT"

const val WRONG_COPYRIGHT_YEAR: String = "WRONG_COPYRIGHT_YEAR"

const val HEADER_CONTAINS_DATE_OR_AUTHOR: String = "HEADER_CONTAINS_DATE_OR_AUTHOR"

const val HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE: String =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ enum class Warnings(private val canBeAutoCorrected: Boolean, private val warn: S
KDOC_NO_DEPRECATED_TAG(true, "KDoc doesn't support @deprecated tag, use @Deprecated annotation instead"),
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"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.cqfn.diktat.ruleset.generation

import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.PropertySpec
import com.squareup.kotlinpoet.TypeSpec
import java.io.File
import org.cqfn.diktat.ruleset.constants.Warnings
import org.cqfn.diktat.ruleset.rules.comments.HeaderCommentRule.Companion.afterCopyrightRegex
import org.cqfn.diktat.ruleset.rules.comments.HeaderCommentRule.Companion.curYear
import org.cqfn.diktat.ruleset.rules.comments.HeaderCommentRule.Companion.hyphenRegex

private val AUTO_GENERATION_COMMENT =
"""
| This document was auto generated, please don't modify it.
| This document contains all enum properties from Warnings.kt as Strings.
""".trimMargin()

fun main() {
generateWarningNames()
validateYear()
}

private fun generateWarningNames() {
val enumValNames = Warnings.values().map { it.name }

val propertyList = enumValNames.map {
PropertySpec.builder(it, String::class)
.addModifiers(KModifier.CONST)
.initializer("\"$it\"")
.build()
}

val fileBody = TypeSpec
.objectBuilder("WarningNames")
.addProperties(propertyList)
.build()

val kotlinFile = FileSpec
.builder("generated", "WarningNames")
.addType(fileBody)
.indent(" ")
.addComment(AUTO_GENERATION_COMMENT)
.build()

kotlinFile.writeTo(File("diktat-rules/src/main/kotlin")) // fixme: need to add it to pom
}

private fun validateYear() {
val file = File("diktat-rules/src/test/resources/test/paragraph2/header/CopyrightDifferentYearExpected.kt")
val tempFile = createTempFile()
tempFile.printWriter().use { writer ->
file.forEachLine { line ->
writer.println(when {
hyphenRegex.matches(line) -> hyphenRegex.replace(line) {
val years = it.value.split("-")
val validYears = "${years[0]}-${curYear}"
line.replace(hyphenRegex, validYears)
}
afterCopyrightRegex.matches(line) -> afterCopyrightRegex.replace(line) {
val copyrightYears = it.value.split("(c)", "(C)", "©")
val validYears = "${copyrightYears[0]}-${curYear}"
line.replace(afterCopyrightRegex, validYears)
}
else -> line
})
}
}
file.delete()
tempFile.renameTo(file)
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,24 @@ import org.cqfn.diktat.common.config.rules.RuleConfiguration
import org.cqfn.diktat.common.config.rules.RulesConfig
import org.cqfn.diktat.common.config.rules.getRuleConfig
import org.cqfn.diktat.common.config.rules.isRuleEnabled
import org.cqfn.diktat.ruleset.constants.Warnings
import org.cqfn.diktat.ruleset.constants.Warnings.HEADER_CONTAINS_DATE_OR_AUTHOR
import org.cqfn.diktat.ruleset.constants.Warnings.HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE
import org.cqfn.diktat.ruleset.constants.Warnings.HEADER_MISSING_OR_WRONG_COPYRIGHT
import org.cqfn.diktat.ruleset.constants.Warnings.HEADER_NOT_BEFORE_PACKAGE
import org.cqfn.diktat.ruleset.constants.Warnings.HEADER_WRONG_FORMAT
import org.cqfn.diktat.ruleset.constants.Warnings.WRONG_COPYRIGHT_YEAR
import org.cqfn.diktat.ruleset.utils.findChildAfter
import org.cqfn.diktat.ruleset.utils.findChildBefore
import org.cqfn.diktat.ruleset.utils.getAllChildrenWithType
import org.cqfn.diktat.ruleset.utils.getFileName
import org.cqfn.diktat.ruleset.utils.getFirstChildWithType
import org.cqfn.diktat.ruleset.utils.moveChildBefore
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafElement
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl
import java.time.LocalDate

/**
* Visitor for header comment in .kt file:
Expand Down Expand Up @@ -57,6 +61,12 @@ class HeaderCommentRule(private val configRules: List<RulesConfig>) : Rule("head
}
}

companion object {
val hyphenRegex = Regex("""\b(\d+-\d+)\b""")
val afterCopyrightRegex = Regex("""((©|\([cC]\))+ *\d+)""")
val curYear = LocalDate.now().year
}

private fun checkCopyright(node: ASTNode) {
val configuration = CopyrightConfiguration(configRules.getRuleConfig(HEADER_MISSING_OR_WRONG_COPYRIGHT)?.configuration
?: mapOf())
Expand All @@ -71,7 +81,6 @@ class HeaderCommentRule(private val configRules: List<RulesConfig>) : Rule("head
.any { commentNode ->
copyrightWords.any { commentNode.text.contains(it, ignoreCase = true) }
}

if (isWrongCopyright || isMissingCopyright || isCopyrightInsideKdoc) {
HEADER_MISSING_OR_WRONG_COPYRIGHT.warnAndFix(configRules, emitWarn, isFixMode, fileName, node.startOffset, node) {
if (headerComment != null) {
Expand All @@ -90,6 +99,39 @@ class HeaderCommentRule(private val configRules: List<RulesConfig>) : Rule("head
)
}
}

val copyrightWithCorrectYear = makeCopyrightCorrectYear(copyrightText)

if (copyrightWithCorrectYear.isNotEmpty()){
WRONG_COPYRIGHT_YEAR.warnAndFix(configRules, emitWarn, isFixMode, fileName, node.startOffset, node) {
(headerComment as LeafElement).replaceWithText(headerComment.text.replace(copyrightText, copyrightWithCorrectYear))
}
}
}

private fun makeCopyrightCorrectYear(copyrightText: String) : String {
val hyphenYear = hyphenRegex.find(copyrightText)

if (hyphenYear != null) {
val copyrightYears = hyphenYear.value.split("-")
if (copyrightYears[1].toInt() != curYear) {
val validYears = "${copyrightYears[0]}-${curYear}"
return copyrightText.replace(hyphenRegex, validYears)
}
}

val afterCopyrightYear = afterCopyrightRegex.find(copyrightText)

if (afterCopyrightYear != null) {
val copyrightYears = afterCopyrightYear.value.split("(c)", "(C)", "©")

if (copyrightYears[1].trim().toInt() != curYear) {
val validYears = "${copyrightYears[0]}-${curYear}"
return copyrightText.replace(afterCopyrightRegex, validYears)
}
}

return ""
}

/**
Expand Down
3 changes: 3 additions & 0 deletions diktat-rules/src/main/resources/diktat-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,9 @@
- name: CONFUSING_IDENTIFIER_NAMING
enabled: true
configuration: {}
- name: WRONG_COPYRIGHT_YEAR
enabled: true
configuration: {}
# Inspection that checks if local variables are declared close to the first usage site
- name: LOCAL_VARIABLE_EARLY_DECLARATION
enabled: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.cqfn.diktat.ruleset.rules.comments.HeaderCommentRule
import org.cqfn.diktat.util.FixTestBase
import org.cqfn.diktat.common.config.rules.RulesConfig
import generated.WarningNames
import generated.WarningNames.WRONG_COPYRIGHT_YEAR
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Tags
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -53,4 +54,15 @@ class HeaderCommentRuleFixTest : FixTestBase(
fun `header KDoc should be moved before package - appended copyright`() {
fixAndCompare("MisplacedHeaderKdocAppendedCopyrightExpected.kt", "MisplacedHeaderKdocAppendedCopyrightTest.kt")
}

@Test
@Tag(WRONG_COPYRIGHT_YEAR)
fun `copyright invalid year should be auto-corrected`() {
fixAndCompare("CopyrightDifferentYearExpected.kt", "CopyrightDifferentYearTest.kt",
listOf(RulesConfig(HEADER_MISSING_OR_WRONG_COPYRIGHT.name, true, mapOf(
"isCopyrightMandatory" to "true",
"copyrightText" to "Copyright (c) My Company., Ltd. 2012-2019. All rights reserved."
)))
)
}
}
Loading