Skip to content

Commit

Permalink
### What's done:
Browse files Browse the repository at this point in the history
- Fixed `KDOC_WITHOUT_THROWS_TAG` rule when it adds a @throws annotation to the function, which has `throw` inside try-catch block

Closes #1718
  • Loading branch information
diphtongue committed Dec 13, 2023
1 parent 74af4c1 commit ab404b2
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.saveourtool.diktat.ruleset.utils.KotlinParser
import com.saveourtool.diktat.ruleset.utils.appendNewlineMergingWhiteSpace
import com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType
import com.saveourtool.diktat.ruleset.utils.findChildAfter
import com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType
import com.saveourtool.diktat.ruleset.utils.getBodyLines
import com.saveourtool.diktat.ruleset.utils.getFilePath
import com.saveourtool.diktat.ruleset.utils.getFirstChildWithType
Expand Down Expand Up @@ -40,6 +41,7 @@ import org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST
import org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION
import org.jetbrains.kotlin.KtNodeTypes.THIS_EXPRESSION
import org.jetbrains.kotlin.KtNodeTypes.THROW
import org.jetbrains.kotlin.KtNodeTypes.TRY
import org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE
import org.jetbrains.kotlin.com.intellij.lang.ASTFactory
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
Expand All @@ -54,6 +56,7 @@ import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.COLON
import org.jetbrains.kotlin.lexer.KtTokens.EQ
import org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER
import org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtCatchClause
Expand Down Expand Up @@ -197,11 +200,38 @@ class KdocMethods(configRules: List<RulesConfig>) : DiktatRule(
&& !hasReturnKdoc && !isReferenceExpressionWithSameName
}

private fun isThrowInTryCatchBlock(node: ASTNode?): Boolean {
node ?: return false
var parent = node.treeParent
while (parent != null && parent.elementType != TRY) {
parent = parent.treeParent
}
val nodeNameList = node.findAllDescendantsWithSpecificType(IDENTIFIER)
val nodeName = if (nodeNameList.isNotEmpty()) {
nodeNameList[0]
} else {
null

Check warning on line 213 in diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt

View check run for this annotation

Codecov / codecov/patch

diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt#L213

Added line #L213 was not covered by tests
}

if (parent?.elementType == TRY) {
val catchNodes = parent.getAllChildrenWithType(CATCH)
val findName = catchNodes.find { catchNode ->
val catchNodeNames = catchNode.findAllDescendantsWithSpecificType(IDENTIFIER)
val matchingName = catchNodeNames.find { catchNodeName -> catchNodeName.text == nodeName?.text }
matchingName != null
}
return findName != null
}
return false
}

private fun getExplicitlyThrownExceptions(node: ASTNode): Set<String> {
val codeBlock = node.getFirstChildWithType(BLOCK)
val throwKeywords = codeBlock?.findAllDescendantsWithSpecificType(THROW)

return throwKeywords
?.asSequence()
?.filter { !isThrowInTryCatchBlock(it) }
?.map { it.psi as KtThrowExpression }
?.filter {
// we only take freshly created exceptions here: `throw IAE("stuff")` vs `throw e`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,10 @@ class KdocMethodsFixTest : FixTestBase("test/paragraph2/kdoc/package/src/main/ko
fun `KdocMethods rule should reformat code (full example)`() {
fixAndCompare("KdocMethodsFullExpected.kt", "KdocMethodsFullTested.kt")
}

@Test
@Tag(WarningNames.KDOC_WITHOUT_THROWS_TAG)
fun `@throws tag shouldn't be added`() {
fixAndCompare("KdocWithoutThrowsTagExpected.kt", "KdocWithoutThrowsTagTested.kt")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -272,26 +272,6 @@ class KdocMethodsTest : LintTestBase(::KdocMethods) {
)
}

@Test
@Tag(WarningNames.KDOC_WITHOUT_THROWS_TAG)
fun `shouldn't add @throw if exception is in catch-block`() {
lintMethod(
"""
|fun parseInputNumber(onSuccess: (number: Int) -> Unit, onFailure: () -> Unit) {
| try {
| val input: Int = binding.inputEditText.text.toString().toInt()
| if (input < 0)
| throw NumberFormatException()
|
| onSuccess(input)
| } catch (e: NumberFormatException) {
| onFailure()
| }
|}
""".trimMargin()
)
}

@Test
@Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)
fun `do not force documentation on standard methods`() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package test.paragraph2.kdoc.`package`.src.main.kotlin.com.saveourtool.diktat.kdoc.methods

/**
* @param onSuccess
* @param onFailure
*/
fun parseInputNumber(onSuccess: (number: Int) -> Unit, onFailure: () -> Unit) {
try {
val input: Int = binding.inputEditText.text.toString().toInt()
if (input < 0)
throw NumberFormatException()

onSuccess(input)
} catch (e: NumberFormatException) {
onFailure()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package test.paragraph2.kdoc.`package`.src.main.kotlin.com.saveourtool.diktat.kdoc.methods

fun parseInputNumber(onSuccess: (number: Int) -> Unit, onFailure: () -> Unit) {
try {
val input: Int = binding.inputEditText.text.toString().toInt()
if (input < 0)
throw NumberFormatException()

onSuccess(input)
} catch (e: NumberFormatException) {
onFailure()
}
}

0 comments on commit ab404b2

Please sign in to comment.