diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index d7311cbb4d..55d0f42fe5 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -52,6 +52,7 @@ jobs: strategy: matrix: os: [ ubuntu-latest, windows-latest, macos-latest ] + java-version: [8, 11] steps: - uses: actions/checkout@v2.4.0 diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/HeaderCommentRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/HeaderCommentRule.kt index 42699002b2..3f6e403cd2 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/HeaderCommentRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/HeaderCommentRule.kt @@ -25,6 +25,7 @@ import com.pinterest.ktlint.core.ast.ElementType.IMPORT_LIST import com.pinterest.ktlint.core.ast.ElementType.KDOC import com.pinterest.ktlint.core.ast.ElementType.PACKAGE_DIRECTIVE import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE +import com.pinterest.ktlint.core.ast.isWhiteSpace 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 @@ -137,16 +138,22 @@ class HeaderCommentRule(configRules: List) : DiktatRule( // need to make sure that copyright year is consistent with current year val copyrightText = configuration.getCopyrightText() + val copyrightWithCorrectYear = makeCopyrightCorrectYear(copyrightText) - if (makeCopyrightCorrectYear(copyrightText).isNotEmpty()) { - log.warn("Copyright year is not up do date.") + if (copyrightWithCorrectYear.isNotEmpty()) { + log.warn("Copyright year in your configuration file is not up to date.") } val headerComment = node.findChildBefore(PACKAGE_DIRECTIVE, BLOCK_COMMENT) // Depends only on content and doesn't consider years + val isCopyrightMatchesPatternExceptFirstYear = isCopyRightTextMatchesPattern(headerComment, copyrightText) || + isCopyRightTextMatchesPattern(headerComment, copyrightWithCorrectYear) + val isWrongCopyright = headerComment != null && - !headerComment.text.flatten().contains(copyrightText.flatten()) && - !headerComment.text.flatten().contains(makeCopyrightCorrectYear(copyrightText).flatten()) + !isCopyrightMatchesPatternExceptFirstYear && + !isHeaderCommentContainText(headerComment, copyrightText) && + !isHeaderCommentContainText(headerComment, copyrightWithCorrectYear) + val isMissingCopyright = headerComment == null && configuration.isCopyrightMandatory() val isCopyrightInsideKdoc = (node.getAllChildrenWithType(KDOC) + node.getAllChildrenWithType(ElementType.EOL_COMMENT)) .any { commentNode -> @@ -162,14 +169,20 @@ class HeaderCommentRule(configRules: List) : DiktatRule( else -> error("Should never get to this point") } HEADER_MISSING_OR_WRONG_COPYRIGHT.warnAndFix(configRules, emitWarn, isFixMode, freeText, node.startOffset, node) { - headerComment?.let { node.removeChild(it) } + headerComment?.let { copyrightNode -> + // remove node clearly, with trailing whitespace + if (copyrightNode.treeNext.isWhiteSpace()) { + node.removeChild(copyrightNode.treeNext) + } + node.removeChild(copyrightNode) + } // do not insert empty line before header kdoc val newLines = node.findChildBefore(PACKAGE_DIRECTIVE, KDOC)?.let { "\n" } ?: "\n\n" node.addChild(PsiWhiteSpaceImpl(newLines), node.firstChildNode) node.addChild(LeafPsiElement(BLOCK_COMMENT, """ |/* - |${handleMultilineCopyright(copyrightText)} + |${handleMultilineCopyright(copyrightWithCorrectYear.ifEmpty { copyrightText })} |*/ """.trimMargin()), node.firstChildNode @@ -177,16 +190,34 @@ class HeaderCommentRule(configRules: List) : DiktatRule( } } - val copyrightWithCorrectYear = makeCopyrightCorrectYear(copyrightText) - // Triggers when there is a copyright, but its year is not updated. - if (!isMissingCopyright && copyrightWithCorrectYear.isNotEmpty()) { + if (!isMissingCopyright && !isWrongCopyright && copyrightWithCorrectYear.isNotEmpty()) { WRONG_COPYRIGHT_YEAR.warnAndFix(configRules, emitWarn, isFixMode, "year should be $curYear", node.startOffset, node) { (headerComment as LeafElement).rawReplaceWithText(headerComment.text.replace(copyrightText, copyrightWithCorrectYear)) } } } + private fun isHeaderCommentContainText(headerComment: ASTNode, text: String): Boolean = if (text.isNotEmpty()) headerComment.text.flatten().contains(text.flatten()) else false + + // Check if provided copyright node differs only in the first date from pattern + private fun isCopyRightTextMatchesPattern(copyrightNode: ASTNode?, copyrightPattern: String): Boolean { + val copyrightText = copyrightNode?.text?.replace("/*", "")?.replace("*/", "")?.replace("*", "") + + val datesInPattern = hyphenRegex.find(copyrightPattern)?.value + val datesInCode = copyrightText?.let { hyphenRegex.find(it)?.value } + + if (datesInPattern == null || datesInCode == null) { + return false + } + + val patternWithoutDates = copyrightPattern.replace(datesInPattern, "").flatten() + val textWithoutDates = copyrightText.replace(datesInCode, "").flatten() + + // Text should be equal, first date could be different, second date should be equal to current year + return (patternWithoutDates == textWithoutDates) && (datesInCode.substringAfter("-") == curYear.toString()) + } + /** * Deletes all spaces and newlines * Used to compare copyrights in yaml and file diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleFixTest.kt index e02c7a386b..c695aaf32a 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleFixTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleFixTest.kt @@ -83,6 +83,39 @@ class HeaderCommentRuleFixTest : FixTestBase( ) } + @Test + @Tag(WRONG_COPYRIGHT_YEAR) + fun `copyright invalid year should be auto-corrected 2`() { + fixAndCompare("CopyrightDifferentYearExpected2.kt", "CopyrightDifferentYearTest2.kt", + listOf(RulesConfig(HEADER_MISSING_OR_WRONG_COPYRIGHT.name, true, mapOf( + "isCopyrightMandatory" to "true", + "copyrightText" to "Copyright (c) My Company., Ltd. 2021. All rights reserved." + ))) + ) + } + + @Test + @Tag(WRONG_COPYRIGHT_YEAR) + fun `copyright invalid pattern, but valid in code`() { + fixAndCompare("CopyrightInvalidPatternValidCodeExpected.kt", "CopyrightInvalidPatternValidCodeTest.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." + ))) + ) + } + + @Test + @Tag(WRONG_COPYRIGHT_YEAR) + fun `copyright invalid pattern, update actual year in it and auto-correct`() { + fixAndCompare("CopyrightAbsentInvalidPatternExpected.kt", "CopyrightAbsentInvalidPatternTest.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." + ))) + ) + } + @Test @Tag(WRONG_COPYRIGHT_YEAR) fun `should not raise npe`() { diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleTest.kt index 6f35d6fa1c..3693eb93e3 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleTest.kt @@ -261,6 +261,52 @@ class HeaderCommentRuleTest : LintTestBase(::HeaderCommentRule) { ) } + @Test + @Tag(WarningNames.WRONG_COPYRIGHT_YEAR) + fun `copyright year good 5`() { + lintMethod( + """ + /* + Copyright (c) My Company, Ltd. 2021-2021. All rights reserved. + */ + /** + * Very useful description, why this file has two classes + * foo bar baz + */ + + package org.cqfn.diktat.example + + class Example1 { } + + class Example2 { } + """.trimIndent(), + rulesConfigList = rulesConfigList + ) + } + + @Test + @Tag(WarningNames.WRONG_COPYRIGHT_YEAR) + fun `copyright year good 6`() { + lintMethod( + """ + /* + * Copyright (c) My Company, Ltd. 2002-2021. All rights reserved. + */ + /** + * Very useful description, why this file has two classes + * foo bar baz + */ + + package org.cqfn.diktat.example + + class Example1 { } + + class Example2 { } + """.trimIndent(), + rulesConfigList = rulesConfigList + ) + } + @Test @Tag(WarningNames.WRONG_COPYRIGHT_YEAR) fun `copyright year bad`() { diff --git a/diktat-rules/src/test/resources/test/paragraph2/header/AutoCopyrightApplyPatternTest.kt b/diktat-rules/src/test/resources/test/paragraph2/header/AutoCopyrightApplyPatternTest.kt index 993117dd44..edc24ea458 100644 --- a/diktat-rules/src/test/resources/test/paragraph2/header/AutoCopyrightApplyPatternTest.kt +++ b/diktat-rules/src/test/resources/test/paragraph2/header/AutoCopyrightApplyPatternTest.kt @@ -1,3 +1,3 @@ package test.paragraph2.header -class Example \ No newline at end of file +class Example diff --git a/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightAbsentInvalidPatternExpected.kt b/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightAbsentInvalidPatternExpected.kt new file mode 100644 index 0000000000..fe33eb4e52 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightAbsentInvalidPatternExpected.kt @@ -0,0 +1,19 @@ +/* + Copyright (c) My Company., Ltd. 2012-2021. All rights reserved. +*/ +/** + * Lorem ipsum + * dolor sit amet + */ + +package test.paragraph2.header + +import org.cqfn.diktat.example.A +import org.cqfn.diktat.example.B + +/** + * Example class + */ +class Example { + lateinit var map: Map +} diff --git a/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightAbsentInvalidPatternTest.kt b/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightAbsentInvalidPatternTest.kt new file mode 100644 index 0000000000..a0e91a476b --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightAbsentInvalidPatternTest.kt @@ -0,0 +1,16 @@ +/** + * Lorem ipsum + * dolor sit amet + */ + +package test.paragraph2.header + +import org.cqfn.diktat.example.A +import org.cqfn.diktat.example.B + +/** + * Example class + */ +class Example { + lateinit var map: Map +} diff --git a/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightDifferentYearExpected2.kt b/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightDifferentYearExpected2.kt new file mode 100644 index 0000000000..691eef9c9f --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightDifferentYearExpected2.kt @@ -0,0 +1,19 @@ +/* + Copyright (c) My Company., Ltd. 2021. All rights reserved. +*/ +/** + * Lorem ipsum + * dolor sit amet + */ + +package test.paragraph2.header + +import org.cqfn.diktat.example.A +import org.cqfn.diktat.example.B + +/** + * Example class + */ +class Example { + lateinit var map: Map +} diff --git a/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightDifferentYearTest2.kt b/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightDifferentYearTest2.kt new file mode 100644 index 0000000000..5a8264ca59 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightDifferentYearTest2.kt @@ -0,0 +1,19 @@ +/* + Copyright (c) My Company., Ltd. 2003. All rights reserved. +*/ +/** + * Lorem ipsum + * dolor sit amet + */ + +package test.paragraph2.header + +import org.cqfn.diktat.example.A +import org.cqfn.diktat.example.B + +/** + * Example class + */ +class Example { + lateinit var map: Map +} diff --git a/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightInvalidPatternValidCodeExpected.kt b/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightInvalidPatternValidCodeExpected.kt new file mode 100644 index 0000000000..b11cc5702f --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightInvalidPatternValidCodeExpected.kt @@ -0,0 +1,19 @@ +/* + Copyright (c) My Company., Ltd. 2021-2021. All rights reserved. +*/ +/** + * Lorem ipsum + * dolor sit amet + */ + +package test.paragraph2.header + +import org.cqfn.diktat.example.A +import org.cqfn.diktat.example.B + +/** + * Example class + */ +class Example { + lateinit var map: Map +} diff --git a/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightInvalidPatternValidCodeTest.kt b/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightInvalidPatternValidCodeTest.kt new file mode 100644 index 0000000000..b11cc5702f --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph2/header/CopyrightInvalidPatternValidCodeTest.kt @@ -0,0 +1,19 @@ +/* + Copyright (c) My Company., Ltd. 2021-2021. All rights reserved. +*/ +/** + * Lorem ipsum + * dolor sit amet + */ + +package test.paragraph2.header + +import org.cqfn.diktat.example.A +import org.cqfn.diktat.example.B + +/** + * Example class + */ +class Example { + lateinit var map: Map +} diff --git a/diktat-ruleset/pom.xml b/diktat-ruleset/pom.xml index 6946cf15d1..5cbaba0ffb 100644 --- a/diktat-ruleset/pom.xml +++ b/diktat-ruleset/pom.xml @@ -60,6 +60,11 @@ diktat-${project.version} false + + + true + + diff --git a/pom.xml b/pom.xml index f64f264c32..f653ac95d0 100644 --- a/pom.xml +++ b/pom.xml @@ -201,6 +201,13 @@ org.apache.maven.plugins maven-assembly-plugin 3.3.0 + + + + true + + + org.apache.maven.plugins