diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/IndentationRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/IndentationRule.kt index 68dcde3a4f..024dfceebb 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/IndentationRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/IndentationRule.kt @@ -33,6 +33,7 @@ import com.pinterest.ktlint.core.ast.ElementType.FILE import com.pinterest.ktlint.core.ast.ElementType.LBRACE import com.pinterest.ktlint.core.ast.ElementType.LBRACKET import com.pinterest.ktlint.core.ast.ElementType.LITERAL_STRING_TEMPLATE_ENTRY +import com.pinterest.ktlint.core.ast.ElementType.LONG_STRING_TEMPLATE_ENTRY import com.pinterest.ktlint.core.ast.ElementType.LONG_TEMPLATE_ENTRY_END import com.pinterest.ktlint.core.ast.ElementType.LONG_TEMPLATE_ENTRY_START import com.pinterest.ktlint.core.ast.ElementType.LPAR @@ -44,6 +45,7 @@ import com.pinterest.ktlint.core.ast.ElementType.STRING_TEMPLATE import com.pinterest.ktlint.core.ast.ElementType.THEN import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE import com.pinterest.ktlint.core.ast.visit +import org.cqfn.diktat.ruleset.utils.hasParent import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement @@ -58,6 +60,7 @@ import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult +import kotlin.math.abs /** * Rule that checks indentation. The following general rules are checked: @@ -179,10 +182,15 @@ class IndentationRule(configRules: List) : DiktatRule("indentation" } val expectedIndent = checkResult?.expectedIndent ?: indentError.expected - if (checkResult?.adjustNext == true) { + if (checkResult?.adjustNext == true && !astNode.hasParent(LONG_STRING_TEMPLATE_ENTRY)) { val exceptionInitiatorNode = astNode.getExceptionalIndentInitiator() context.addException(exceptionInitiatorNode, expectedIndent - indentError.expected, checkResult.includeLastChild) } + + if (astNode.treeParent.elementType == LONG_STRING_TEMPLATE_ENTRY && indentError.expected != indentError.actual) { + context.addException(astNode.treeParent, abs(indentError.expected - indentError.actual), false) + } + if (checkResult?.isCorrect != true && expectedIndent != indentError.actual) { WRONG_INDENTATION.warnAndFix(configRules, emitWarn, isFixMode, "expected $expectedIndent but was ${indentError.actual}", whiteSpace.startOffset + whiteSpace.text.lastIndexOf('\n') + 1, whiteSpace.node) { diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/indentation/Checkers.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/indentation/Checkers.kt index a578f34962..b97d5f0088 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/indentation/Checkers.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/indentation/Checkers.kt @@ -29,6 +29,7 @@ import com.pinterest.ktlint.core.ast.ElementType.LPAR import com.pinterest.ktlint.core.ast.ElementType.OPERATION_REFERENCE import com.pinterest.ktlint.core.ast.ElementType.REFERENCE_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.SAFE_ACCESS +import com.pinterest.ktlint.core.ast.ElementType.STRING_TEMPLATE import com.pinterest.ktlint.core.ast.ElementType.SUPER_TYPE_LIST import com.pinterest.ktlint.core.ast.ElementType.THEN import com.pinterest.ktlint.core.ast.ElementType.VALUE_ARGUMENT @@ -38,6 +39,8 @@ import com.pinterest.ktlint.core.ast.ElementType.VALUE_PARAMETER_LIST import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE import com.pinterest.ktlint.core.ast.nextCodeSibling import com.pinterest.ktlint.core.ast.prevSibling +import org.cqfn.diktat.ruleset.utils.hasParameters +import org.cqfn.diktat.ruleset.utils.hasParent import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.PsiElement import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace @@ -195,6 +198,9 @@ internal class DotCallChecker(config: IndentationConfig) : CustomIndentationChec return false } + private fun ASTNode.isFromStringTemplate(): Boolean = + hasParent(LONG_STRING_TEMPLATE_ENTRY) + @Suppress("ComplexMethod") override fun checkNode(whiteSpace: PsiWhiteSpace, indentError: IndentationError): CheckResult? { whiteSpace.nextSibling.node @@ -205,6 +211,12 @@ internal class DotCallChecker(config: IndentationConfig) : CustomIndentationChec } || nextNode.isCommentBeforeDot() } ?.let { + if (it.isFromStringTemplate()) { + val template = it.parents().takeWhile { it.elementType != STRING_TEMPLATE }.last() + return CheckResult.from(indentError.actual, indentError.expected + + (if (configuration.extendedIndentBeforeDot) 2 else 1) * configuration.indentationSize, true) + } + // we need to get indent before the first expression in calls chain return CheckResult.from(indentError.actual, (whiteSpace.run { parents.takeWhile { it is KtDotQualifiedExpression || it is KtSafeQualifiedExpression }.lastOrNull() ?: this diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleWarnTest.kt index 7a873c92a4..b7b21c4e32 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/spaces/IndentationRuleWarnTest.kt @@ -610,7 +610,7 @@ class IndentationRuleWarnTest : LintTestBase(::IndentationRule) { @Tag(WarningNames.WRONG_INDENTATION) fun `should trigger on string templates starting with new line`() { lintMethod( - """ + """ |fun foo(some: String) { | fun bar() { | val a = "${'$'}{ @@ -624,9 +624,9 @@ class IndentationRuleWarnTest : LintTestBase(::IndentationRule) { |} | """.trimMargin(), - LintError(4, 1, ruleId, warnText(12, 8), true), - LintError(5, 1, ruleId, warnText(16, 12), true), - LintError(6, 1, ruleId, warnText(16, 12), true) + LintError(4, 1, ruleId, warnText(12, 8), true), + LintError(5, 1, ruleId, warnText(16, 12), true), + LintError(6, 1, ruleId, warnText(16, 12), true) ) } diff --git a/diktat-rules/src/test/resources/test/paragraph3/indentation/IndentationFull1Expected.kt b/diktat-rules/src/test/resources/test/paragraph3/indentation/IndentationFull1Expected.kt index 73b6bfd51d..d1bca4541b 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/indentation/IndentationFull1Expected.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/indentation/IndentationFull1Expected.kt @@ -39,6 +39,12 @@ data class Example(val field1: Type1, }" val b = "${baz().foo()}" + + val c = "${ + expression + .foo() + .bar() + }" } } diff --git a/diktat-rules/src/test/resources/test/paragraph3/indentation/IndentationFull1Test.kt b/diktat-rules/src/test/resources/test/paragraph3/indentation/IndentationFull1Test.kt index e21fcca323..2eb1ab279e 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/indentation/IndentationFull1Test.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/indentation/IndentationFull1Test.kt @@ -39,5 +39,11 @@ fun foo( }" val b = "${baz().foo()}" + + val c = "${ + expression + .foo() + .bar() + }" } }