mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 06:50:54 +07:00
IJPL-162560: IncorrectProcessCanceledExceptionHandlingInspection: Add support for CancellationException in coroutine context
GitOrigin-RevId: aeaa49f2a8e27af62a3ec826b3cece3a4e0c447b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
132168dac4
commit
cb6b9a9a0c
@@ -1,18 +1,24 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports <code>ProcessCanceledException</code>s handled in an incorrect way.
|
||||
Reports <code>ProcessCanceledException</code> and <code>CancellationException</code> handled incorrectly.
|
||||
|
||||
<p>
|
||||
<code>ProcessCanceledException</code> and its inheritors must not be caught, swallowed, logged, or handled in any way.
|
||||
Instead, it must be rethrown so that the infrastructure can handle it correctly.
|
||||
Instead, it must be rethrown so that the IntelliJ Platform infrastructure can handle it correctly.
|
||||
</p>
|
||||
<p>
|
||||
<code>CancellationException</code> must not be caught, swallowed, logged, or handled in any way in coroutine context.
|
||||
Instead, it must be rethrown so that the coroutines infrastructure can handle it correctly.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Inspection reports both explicit <code>ProcessCanceledException</code> or its inheritors catching,
|
||||
as well as catching <code>RuntimeException</code>, <code>Exception</code> and <code>Throwable</code> covering <code>ProcessCanceledException</code>.
|
||||
Inspection reports both explicit <code>ProcessCanceledException</code> (including inheritors) and <code>CancellationException</code>catching,
|
||||
as well as catching <code>RuntimeException</code>, <code>Exception</code> and <code>Throwable</code> covering cancellation exceptions.
|
||||
</p>
|
||||
|
||||
<p>Example:</p>
|
||||
<h3>Examples:</h3>
|
||||
|
||||
<h4><code>ProcessCanceledException</code>:</h4>
|
||||
|
||||
<pre><code lang="java">
|
||||
// bad:
|
||||
@@ -39,6 +45,38 @@ try {
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<h4><code>CancellationException</code>:</h4>
|
||||
<pre><code lang="kotlin">
|
||||
// bad:
|
||||
cs.launch {
|
||||
try {
|
||||
// ...
|
||||
} catch (e: CancellationException) { // exception should not be swallowed
|
||||
}
|
||||
}
|
||||
|
||||
// bad:
|
||||
suspend fun suspendingFunction() {
|
||||
try {
|
||||
// ...
|
||||
} catch (ProcessCanceledException e) {
|
||||
LOG.error("Error occurred", e); // exception should not be logged
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// good:
|
||||
cs.launch {
|
||||
try {
|
||||
// ...
|
||||
} catch (ProcessCanceledException e) {
|
||||
// additional actions
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<!-- tooltip end -->
|
||||
<p><small>New in 2023.2</small></p>
|
||||
</body>
|
||||
|
||||
@@ -444,7 +444,7 @@
|
||||
groupPathKey="inspections.group.path" groupKey="inspections.group.code"
|
||||
enabledByDefault="false" level="ERROR"
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.IncorrectProcessCanceledExceptionHandlingInspection"
|
||||
key="inspections.incorrect.process.canceled.exception.handling.display.name"/>
|
||||
key="inspections.incorrect.cancellation.exception.handling.display.name"/>
|
||||
|
||||
<localInspection language="UAST" shortName="StaticInitializationInExtensions" groupPathKey="inspections.group.path"
|
||||
projectType="INTELLIJ_PLUGIN"
|
||||
@@ -730,6 +730,11 @@
|
||||
dynamic="true">
|
||||
<with attribute="implementationClass" implements="org.jetbrains.idea.devkit.inspections.quickfix.AddServiceAnnotationProvider"/>
|
||||
</extensionPoint>
|
||||
<extensionPoint qualifiedName="DevKit.lang.cancellationExceptionHandlingChecker"
|
||||
beanClass="com.intellij.lang.LanguageExtensionPoint"
|
||||
dynamic="true">
|
||||
<with attribute="implementationClass" implements="org.jetbrains.idea.devkit.inspections.CancellationExceptionHandlingChecker"/>
|
||||
</extensionPoint>
|
||||
</extensionPoints>
|
||||
|
||||
<actions>
|
||||
|
||||
@@ -658,17 +658,17 @@ inspections.calling.method.should.be.rbc.annotated=Calling method should be anno
|
||||
inspections.calling.method.should.be.rbc.annotated.message=Calling method should be annotated with '@RequiresBlockingContext'
|
||||
inspections.calling.method.should.be.rbc.annotated.annotate.fix=Annotate calling method with '@RequiresBlockingContext'
|
||||
|
||||
inspections.incorrect.process.canceled.exception.handling.display.name='ProcessCanceledException' handled incorrectly
|
||||
inspections.incorrect.process.canceled.exception.handling.name.not.rethrown='ProcessCanceledException' must be rethrown
|
||||
inspections.incorrect.process.canceled.exception.handling.name.logged='ProcessCanceledException' must not be logged
|
||||
inspections.incorrect.process.canceled.exception.inheritor.handling.name.not.rethrown='ProcessCanceledException' inheritor must be rethrown
|
||||
inspections.incorrect.process.canceled.exception.inheritor.handling.name.logged='ProcessCanceledException' inheritor must not be logged
|
||||
inspections.incorrect.cancellation.exception.handling.display.name=Cancellation exception handled incorrectly
|
||||
inspections.incorrect.cancellation.exception.handling.name.not.rethrown=''{0}'' must be rethrown
|
||||
inspections.incorrect.cancellation.exception.handling.name.logged=''{0}'' must not be logged
|
||||
inspections.incorrect.cancellation.exception.inheritor.handling.name.not.rethrown=''{0}'' inheritor must be rethrown
|
||||
inspections.incorrect.cancellation.exception.inheritor.handling.name.logged=''{0}'' inheritor must not be logged
|
||||
|
||||
inspections.incorrect.implicit.process.canceled.exception.handling.name.not.rethrown=''ProcessCanceledException'' must be rethrown. ''ProcessCanceledException'' is thrown by ''{0}()''.
|
||||
inspections.incorrect.implicit.process.canceled.exception.handling.name.logged=''ProcessCanceledException'' must not be logged. ''ProcessCanceledException'' is thrown by ''{0}()''.
|
||||
inspections.incorrect.implicit.cancellation.exception.handling.name.not.rethrown=''{0}'' must be rethrown. It is thrown by ''{1}()''.
|
||||
inspections.incorrect.implicit.cancellation.exception.handling.name.logged=''{0}'' must not be logged. It is thrown by ''{1}()''.
|
||||
|
||||
inspections.incorrect.implicit.process.canceled.exception.inheritor.handling.name.not.rethrown=''ProcessCanceledException'' inheritor must be rethrown. ''ProcessCanceledException'' is thrown by ''{0}()''.
|
||||
inspections.incorrect.implicit.process.canceled.exception.inheritor.handling.name.logged=''ProcessCanceledException'' inheritor must not be logged. ''ProcessCanceledException'' is thrown by ''{0}()''.
|
||||
inspections.incorrect.implicit.cancellation.exception.inheritor.handling.name.not.rethrown=''{0}'' inheritor must be rethrown. It is thrown by ''{1}()''.
|
||||
inspections.incorrect.implicit.cancellation.exception.inheritor.handling.name.logged=''{0}'' inheritor must not be logged. It is thrown by ''{1}()''.
|
||||
update.ide.from.sources=Update &IDE from sources
|
||||
update.ide.from.sources.option=from sources
|
||||
inspections.meta.information.unknown.inspection.id=Unknown inspection id ''{0}''
|
||||
|
||||
@@ -3,14 +3,19 @@ package org.jetbrains.idea.devkit.inspections
|
||||
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.codeInspection.registerUProblem
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.lang.LanguageExtension
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.util.IntellijInternalApi
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.util.InheritanceUtil
|
||||
import com.intellij.psi.util.PsiTypesUtil
|
||||
import com.intellij.uast.UastHintedVisitorAdapter.Companion.create
|
||||
import org.jetbrains.idea.devkit.DevKitBundle
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.idea.devkit.DevKitBundle.message
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.visitor.AbstractUastNonRecursiveVisitor
|
||||
import org.jetbrains.uast.visitor.AbstractUastVisitor
|
||||
@@ -38,13 +43,22 @@ internal class IncorrectProcessCanceledExceptionHandlingInspection : DevKitUastI
|
||||
private fun findSuspiciousCeCaughtParam(catchParameters: List<UParameter>): CaughtCeInfo? {
|
||||
val ceClasses = findCeClasses(holder.file.resolveScope) ?: return null
|
||||
for (catchParameter in catchParameters) {
|
||||
// language-specific check:
|
||||
val checker = cancellationExceptionHandlingChecker(catchParameter.lang)
|
||||
val sourcePsi = catchParameter.sourcePsi
|
||||
if (sourcePsi != null && checker?.isSuspicious(sourcePsi) == true) {
|
||||
return CaughtCeInfo(checker.getCeName(), false, catchParameter)
|
||||
}
|
||||
// general UAST check:
|
||||
val type = catchParameter.type
|
||||
val caughtExceptionTypes = if (type is PsiDisjunctionType) type.disjunctions else listOf(type)
|
||||
val caughtExceptionTypes = (if (type is PsiDisjunctionType) type.disjunctions else listOf(type)).filterIsInstance<PsiClassType>()
|
||||
for (caughtExceptionType in caughtExceptionTypes) {
|
||||
if (ceClasses.any { caughtExceptionType.isInheritorOrSelf(it) }) {
|
||||
val baseCeClass = ceClasses.firstOrNull { caughtExceptionType.isInheritorOrSelf(it) }
|
||||
if (baseCeClass != null) {
|
||||
return CaughtCeInfo(
|
||||
catchParameter,
|
||||
caughtExceptionType.isCancellationExceptionClass()
|
||||
baseCeClass.qualifiedName!!,
|
||||
!caughtExceptionType.isCancellationExceptionClass(),
|
||||
catchParameter
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -59,7 +73,7 @@ internal class IncorrectProcessCanceledExceptionHandlingInspection : DevKitUastI
|
||||
}
|
||||
|
||||
private fun PsiType.isCancellationExceptionClass(): Boolean {
|
||||
return ceClassNames.any { it != (this as? PsiClassType)?.resolve()?.qualifiedName }
|
||||
return ceClassNames.any { it == (this as? PsiClassType)?.resolve()?.qualifiedName }
|
||||
}
|
||||
|
||||
private fun PsiType.isInheritorOrSelf(ceClass: PsiClass): Boolean {
|
||||
@@ -72,15 +86,15 @@ internal class IncorrectProcessCanceledExceptionHandlingInspection : DevKitUastI
|
||||
val catchBody = node.body
|
||||
if (!ceIsRethrown(catchBody, caughtCeInfo.parameter)) {
|
||||
val message = if (caughtCeInfo.isInheritor)
|
||||
DevKitBundle.message("inspections.incorrect.process.canceled.exception.inheritor.handling.name.not.rethrown")
|
||||
else DevKitBundle.message("inspections.incorrect.process.canceled.exception.handling.name.not.rethrown")
|
||||
message("inspections.incorrect.cancellation.exception.inheritor.handling.name.not.rethrown", caughtCeInfo.baseCeClassName)
|
||||
else message("inspections.incorrect.cancellation.exception.handling.name.not.rethrown", caughtCeInfo.baseCeClassName)
|
||||
holder.registerUProblem(caughtCeInfo.parameter, message)
|
||||
}
|
||||
val loggingExpression = findCeLoggingExpression(catchBody, caughtCeInfo.parameter)
|
||||
if (loggingExpression != null) {
|
||||
val message = if (caughtCeInfo.isInheritor)
|
||||
DevKitBundle.message("inspections.incorrect.process.canceled.exception.inheritor.handling.name.logged")
|
||||
else DevKitBundle.message("inspections.incorrect.process.canceled.exception.handling.name.logged")
|
||||
message("inspections.incorrect.cancellation.exception.inheritor.handling.name.logged", caughtCeInfo.baseCeClassName)
|
||||
else message("inspections.incorrect.cancellation.exception.handling.name.logged", caughtCeInfo.baseCeClassName)
|
||||
holder.registerUProblem(loggingExpression, message)
|
||||
}
|
||||
}
|
||||
@@ -90,7 +104,7 @@ internal class IncorrectProcessCanceledExceptionHandlingInspection : DevKitUastI
|
||||
catchParameters: List<UParameter>,
|
||||
): Boolean {
|
||||
val tryExpression = catchClause.getParentOfType<UTryExpression>() ?: return super.visitCatchClause(catchClause)
|
||||
if (tryExpression.containsCatchClauseForType<ProcessCanceledException>()) {
|
||||
if (tryExpression.containsCatchClauseForType<ProcessCanceledException>() || tryExpression.checkContainsSuspiciousCeCatchClause()) {
|
||||
// Cancellation exception will be caught by the explicit catch clause
|
||||
return super.visitCatchClause(catchClause)
|
||||
}
|
||||
@@ -102,35 +116,99 @@ internal class IncorrectProcessCanceledExceptionHandlingInspection : DevKitUastI
|
||||
// Cancellation exception will be caught by catch clause with a more specific type, so do not report
|
||||
return super.visitCatchClause(catchClause)
|
||||
}
|
||||
val (ceThrowingExpression, isCeInheritorThrown) = findCeThrowingExpression(tryExpression)
|
||||
if (ceThrowingExpression != null) {
|
||||
inspectIncorrectImplicitCeHandling(catchClause, caughtGenericThrowableParam, isCeInheritorThrown, ceThrowingExpression)
|
||||
|
||||
// lang-specific check:
|
||||
val langSpecificCaughtCeInfo = findLangSpecificCeThrowingExpressionInfo(tryExpression, caughtGenericThrowableParam)
|
||||
if (langSpecificCaughtCeInfo != null) {
|
||||
inspectIncorrectImplicitCeHandling(catchClause, langSpecificCaughtCeInfo)
|
||||
}
|
||||
// UAST check:
|
||||
val caughtCeInfo = findCeThrowingExpressionInfo(tryExpression, caughtGenericThrowableParam)
|
||||
if (caughtCeInfo != null) {
|
||||
inspectIncorrectImplicitCeHandling(catchClause, caughtCeInfo)
|
||||
}
|
||||
}
|
||||
return super.visitCatchClause(catchClause)
|
||||
}
|
||||
|
||||
private fun inspectIncorrectImplicitCeHandling(
|
||||
node: UCatchClause,
|
||||
caughtParam: UParameter,
|
||||
isCeInheritor: Boolean,
|
||||
ceThrowingExpression: UCallExpression,
|
||||
) {
|
||||
val catchBody = node.body
|
||||
if (!ceIsRethrown(catchBody, caughtParam)) {
|
||||
val methodName = ceThrowingExpression.methodName ?: return
|
||||
val message = if (isCeInheritor)
|
||||
DevKitBundle.message("inspections.incorrect.implicit.process.canceled.exception.inheritor.handling.name.not.rethrown",
|
||||
methodName)
|
||||
else DevKitBundle.message("inspections.incorrect.implicit.process.canceled.exception.handling.name.not.rethrown", methodName)
|
||||
holder.registerUProblem(caughtParam, message)
|
||||
private fun UTryExpression.checkContainsSuspiciousCeCatchClause(): Boolean {
|
||||
val sourcePsi = this.sourcePsi ?: return false
|
||||
return cancellationExceptionHandlingChecker(this.lang)?.containsSuspiciousCeCatchClause(sourcePsi) == true
|
||||
}
|
||||
|
||||
private fun findLangSpecificCeThrowingExpressionInfo(tryExpression: UTryExpression, caughtGenericThrowableParam: UParameter): CaughtCeInfo? {
|
||||
val ceHandlingChecker = cancellationExceptionHandlingChecker(tryExpression.lang)
|
||||
val ceThrowingExpressionName = ceHandlingChecker?.findCeThrowingExpressionName(tryExpression.sourcePsi!!) ?: return null
|
||||
return CaughtCeInfo(ceHandlingChecker.getCeName(), false, caughtGenericThrowableParam, ceThrowingExpressionName)
|
||||
}
|
||||
|
||||
// it searches only for explicit `throws` declarations in directly called methods.
|
||||
private fun findCeThrowingExpressionInfo(tryExpression: UTryExpression, caughtGenericThrowableParam: UParameter): CaughtCeInfo? {
|
||||
var caughtCeInfo: CaughtCeInfo? = null
|
||||
val tryClause = tryExpression.tryClause
|
||||
val resolveScope = tryClause.sourcePsi?.resolveScope ?: return null
|
||||
val ceClasses = findCeClasses(resolveScope) ?: return null
|
||||
tryClause.accept(object : AbstractUastVisitor() {
|
||||
override fun visitCallExpression(node: UCallExpression): Boolean {
|
||||
if (caughtCeInfo == null) {
|
||||
val calledMethod = node.resolveToUElementOfType<UMethod>() ?: return super.visitCallExpression(node)
|
||||
for (throwsType in calledMethod.javaPsi.throwsTypes) {
|
||||
val throwsClassType = throwsType as? PsiClassType ?: continue
|
||||
val baseThrowsCeClass = ceClasses.firstOrNull { throwsClassType.isInheritorOrSelf(it) }
|
||||
if (baseThrowsCeClass != null) {
|
||||
if (!isInNestedTryCatchBlock(node, tryExpression, throwsClassType)) {
|
||||
caughtCeInfo = CaughtCeInfo(
|
||||
baseThrowsCeClass.qualifiedName!!,
|
||||
!throwsClassType.isCancellationExceptionClass(),
|
||||
caughtGenericThrowableParam,
|
||||
node.methodName
|
||||
)
|
||||
return super.visitCallExpression(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.visitCallExpression(node)
|
||||
}
|
||||
})
|
||||
return caughtCeInfo
|
||||
}
|
||||
|
||||
private fun isInNestedTryCatchBlock(
|
||||
expression: UCallExpression,
|
||||
checkedTryExpression: UTryExpression,
|
||||
thrownExceptionType: PsiClassType,
|
||||
): Boolean {
|
||||
val thrownExceptionClass = thrownExceptionType.resolve() ?: return false
|
||||
val parentTryExpression = expression.getParentOfType<UTryExpression>() ?: return false
|
||||
if (parentTryExpression == checkedTryExpression) return false
|
||||
return parentTryExpression.catchClauses.any { catchClause ->
|
||||
catchClause.types.any anyType@{ type ->
|
||||
return@anyType (if (type is PsiDisjunctionType) type.disjunctions else listOf(type))
|
||||
.any { it.isInheritorOrSelf(thrownExceptionClass) }
|
||||
}
|
||||
}
|
||||
val loggingExpression = findCeLoggingExpression(catchBody, caughtParam)
|
||||
}
|
||||
|
||||
private fun inspectIncorrectImplicitCeHandling(catchClause: UCatchClause, caughtCeInfo: CaughtCeInfo) {
|
||||
val catchBody = catchClause.body
|
||||
if (!ceIsRethrown(catchBody, caughtCeInfo.parameter)) {
|
||||
val methodName = caughtCeInfo.ceThrowingMethodName ?: return
|
||||
val message = if (caughtCeInfo.isInheritor)
|
||||
message("inspections.incorrect.implicit.cancellation.exception.inheritor.handling.name.not.rethrown",
|
||||
caughtCeInfo.baseCeClassName, methodName)
|
||||
else message("inspections.incorrect.implicit.cancellation.exception.handling.name.not.rethrown",
|
||||
caughtCeInfo.baseCeClassName, methodName)
|
||||
holder.registerUProblem(caughtCeInfo.parameter, message)
|
||||
}
|
||||
val loggingExpression = findCeLoggingExpression(catchBody, caughtCeInfo.parameter)
|
||||
if (loggingExpression != null) {
|
||||
val methodName = ceThrowingExpression.methodName ?: return
|
||||
val message = if (isCeInheritor)
|
||||
DevKitBundle.message("inspections.incorrect.implicit.process.canceled.exception.inheritor.handling.name.logged", methodName)
|
||||
else DevKitBundle.message("inspections.incorrect.implicit.process.canceled.exception.handling.name.logged", methodName)
|
||||
val methodName = caughtCeInfo.ceThrowingMethodName ?: return
|
||||
val message = if (caughtCeInfo.isInheritor)
|
||||
message("inspections.incorrect.implicit.cancellation.exception.inheritor.handling.name.logged",
|
||||
caughtCeInfo.baseCeClassName, methodName)
|
||||
else message("inspections.incorrect.implicit.cancellation.exception.handling.name.logged",
|
||||
caughtCeInfo.baseCeClassName, methodName)
|
||||
holder.registerUProblem(loggingExpression, message)
|
||||
}
|
||||
}
|
||||
@@ -166,34 +244,6 @@ internal class IncorrectProcessCanceledExceptionHandlingInspection : DevKitUastI
|
||||
return loggingExpression
|
||||
}
|
||||
|
||||
// it searches only for explicit `throws` declarations in directly called methods.
|
||||
private fun findCeThrowingExpression(tryExpression: UTryExpression): Pair<UCallExpression?, Boolean> {
|
||||
val tryClause = tryExpression.tryClause
|
||||
var ceThrowingExpression: UCallExpression? = null
|
||||
var isCeInheritorCaught = false
|
||||
val resolveScope = tryClause.sourcePsi?.resolveScope ?: return Pair(null, false)
|
||||
val ceClasses = findCeClasses(resolveScope) ?: return Pair(null, false)
|
||||
tryClause.accept(object : AbstractUastVisitor() {
|
||||
override fun visitCallExpression(node: UCallExpression): Boolean {
|
||||
if (ceThrowingExpression == null) {
|
||||
val calledMethod = node.resolveToUElementOfType<UMethod>() ?: return super.visitCallExpression(node)
|
||||
for (throwsType in calledMethod.javaPsi.throwsTypes) {
|
||||
val psiClassType = throwsType as? PsiClassType ?: continue
|
||||
if (ceClasses.any { psiClassType.isInheritorOrSelf(it) }) {
|
||||
if (!isInNestedTryCatchBlock(node, tryExpression, psiClassType)) {
|
||||
ceThrowingExpression = node
|
||||
isCeInheritorCaught = psiClassType.isCancellationExceptionClass()
|
||||
return super.visitCallExpression(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.visitCallExpression(node)
|
||||
}
|
||||
})
|
||||
return Pair(ceThrowingExpression, isCeInheritorCaught)
|
||||
}
|
||||
|
||||
private inline fun <reified T> PsiType.isClassType(): Boolean {
|
||||
if (this is PsiDisjunctionType) {
|
||||
return this.disjunctions.any { PsiTypesUtil.classNameEquals(it, T::class.java.name) }
|
||||
@@ -214,29 +264,35 @@ internal class IncorrectProcessCanceledExceptionHandlingInspection : DevKitUastI
|
||||
}
|
||||
}
|
||||
|
||||
private fun isInNestedTryCatchBlock(
|
||||
expression: UCallExpression,
|
||||
checkedTryExpression: UTryExpression,
|
||||
thrownExceptionType: PsiClassType,
|
||||
): Boolean {
|
||||
val thrownExceptionClass = thrownExceptionType.resolve() ?: return false
|
||||
val parentTryExpression = expression.getParentOfType<UTryExpression>() ?: return false
|
||||
if (parentTryExpression == checkedTryExpression) return false
|
||||
return parentTryExpression.catchClauses.any { catchClause ->
|
||||
catchClause.types.any anyType@{ type ->
|
||||
if (type is PsiDisjunctionType) {
|
||||
return@anyType type.disjunctions.any { it.isInheritorOrSelf(thrownExceptionClass) }
|
||||
}
|
||||
return@anyType type.isInheritorOrSelf(thrownExceptionClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}, arrayOf(UCatchClause::class.java))
|
||||
}
|
||||
|
||||
private class CaughtCeInfo(
|
||||
val parameter: UParameter,
|
||||
val baseCeClassName: String,
|
||||
val isInheritor: Boolean,
|
||||
val parameter: UParameter,
|
||||
val ceThrowingMethodName: String? = null,
|
||||
)
|
||||
}
|
||||
|
||||
// allow additional languages to contribute language-specific checks
|
||||
// (used by Kotlin at least for suspending context cancellation handling):
|
||||
|
||||
private val EP_NAME: ExtensionPointName<CancellationCheckProvider> =
|
||||
ExtensionPointName.Companion.create("DevKit.lang.cancellationExceptionHandlingChecker")
|
||||
|
||||
private object CancellationExceptionHandlingCheckers :
|
||||
LanguageExtension<CancellationExceptionHandlingChecker>(EP_NAME.name)
|
||||
|
||||
private fun cancellationExceptionHandlingChecker(language: Language): CancellationExceptionHandlingChecker? {
|
||||
return CancellationExceptionHandlingCheckers.forLanguage(language)
|
||||
}
|
||||
|
||||
@IntellijInternalApi
|
||||
@ApiStatus.Internal
|
||||
interface CancellationExceptionHandlingChecker {
|
||||
fun isSuspicious(catchParameter: PsiElement): Boolean
|
||||
fun getCeName(): String
|
||||
fun containsSuspiciousCeCatchClause(tryExpression: PsiElement): Boolean
|
||||
fun findCeThrowingExpressionName(tryExpression: PsiElement): String?
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ class IncorrectPceHandlingTests {
|
||||
void testPceSwallowed() {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
} catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ class IncorrectPceHandlingTests {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException e) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -25,64 +25,64 @@ class IncorrectPceHandlingTests {
|
||||
void testSwallowedAndLoggedWithMessageOnInfoLevel() {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.info("Error occured", e)</error>;
|
||||
} catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.info("Error occured", e)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testSwallowedAndLoggedOnInfoLevel() {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.info(e)</error>;
|
||||
} catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.info(e)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testSwallowedAndLoggedOnErrorLevel() {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
} catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testSwallowedAndOnlyExceptionMessageLogged() {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
} catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testDisjunctionTypesWhenPceIsFirst() {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException | IllegalStateException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
} catch (ProcessCanceledException | IllegalStateException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testDisjunctionTypesWhenPceIsSecond() {
|
||||
try {
|
||||
// anything
|
||||
} catch (IllegalStateException | ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
} catch (IllegalStateException | ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testPceInheritorSwallowedAndLogger() {
|
||||
try {
|
||||
// anything
|
||||
} catch (SubclassOfProcessCanceledException <error descr="'ProcessCanceledException' inheritor must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' inheritor must not be logged">LOG.error(e)</error>;
|
||||
} catch (SubclassOfProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged">LOG.error(e)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testPceInheritorSwallowedAndLoggerWhenDisjunctionTypeDefined() {
|
||||
try {
|
||||
// anything
|
||||
} catch (IllegalStateException | SubclassOfProcessCanceledException <error descr="'ProcessCanceledException' inheritor must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' inheritor must not be logged">LOG.error(e)</error>;
|
||||
} catch (IllegalStateException | SubclassOfProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged">LOG.error(e)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
void testPceSwallowed() {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
} catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
// exception swallowed
|
||||
} catch (Exception e) {
|
||||
// exception swallowed
|
||||
@@ -19,7 +19,7 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException e) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// exception swallowed
|
||||
@@ -29,8 +29,8 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
void testSwallowedAndLoggedWithMessageOnInfoLevel() {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.info("Error occured", e)</error>;
|
||||
} catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.info("Error occured", e)</error>;
|
||||
} catch (Exception e) {
|
||||
LOG.info("Error occured", e);
|
||||
}
|
||||
@@ -39,8 +39,8 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
void testSwallowedAndLoggedOnInfoLevel() {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.info(e)</error>;
|
||||
} catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.info(e)</error>;
|
||||
} catch (Exception e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
@@ -49,8 +49,8 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
void testSwallowedAndLoggedOnErrorLevel() {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
} catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
} catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
@@ -59,8 +59,8 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
void testSwallowedAndOnlyExceptionMessageLogged() {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
} catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error occurred: " + e.getMessage());
|
||||
}
|
||||
@@ -69,7 +69,7 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
void testPceSwallowedAndMultipleGenericCatchClauses() {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
} catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
// exception swallowed
|
||||
} catch (RuntimeException e) {
|
||||
// exception swallowed
|
||||
@@ -84,7 +84,7 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
try {
|
||||
// anything
|
||||
} catch (ProcessCanceledException e) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
throw e;
|
||||
} catch (RuntimeException e) {
|
||||
LOG.error(e);
|
||||
@@ -98,9 +98,9 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
void testPceInheritorSwallowedAndMultipleGenericCatchClauses() {
|
||||
try {
|
||||
// anything
|
||||
} catch (SubclassOfProcessCanceledException <error descr="'ProcessCanceledException' inheritor must be rethrown">e</error>) {
|
||||
} catch (SubclassOfProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown">e</error>) {
|
||||
// exception swallowed
|
||||
} catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
} catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
// exception swallowed
|
||||
} catch (RuntimeException e) {
|
||||
// exception swallowed
|
||||
@@ -115,10 +115,10 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
try {
|
||||
// anything
|
||||
} catch (SubclassOfProcessCanceledException e) {
|
||||
<error descr="'ProcessCanceledException' inheritor must not be logged">LOG.error(e)</error>;
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged">LOG.error(e)</error>;
|
||||
throw e;
|
||||
} catch (ProcessCanceledException e) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
throw e;
|
||||
} catch (RuntimeException e) {
|
||||
LOG.error(e);
|
||||
@@ -135,8 +135,8 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
|
||||
@@ -14,7 +14,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
void testPceSwallowed() {
|
||||
try {
|
||||
throwPce();
|
||||
} catch (Exception <error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>) {
|
||||
} catch (Exception <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPce();
|
||||
} catch (Exception e) {
|
||||
<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">LOG.error(e)</error>;
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">LOG.error(e)</error>;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -31,55 +31,55 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
void testSwallowedAndLoggedWithMessageOnInfoLevel() {
|
||||
try {
|
||||
throwPce();
|
||||
} catch (Exception <error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">LOG.info("Error occured", e)</error>;
|
||||
} catch (Exception <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">LOG.info("Error occured", e)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testSwallowedAndLoggedOnInfoLevel() {
|
||||
try {
|
||||
throwPce();
|
||||
} catch (Exception <error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">LOG.info(e)</error>;
|
||||
} catch (Exception <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">LOG.info(e)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testSwallowedAndLoggedOnErrorLevel() {
|
||||
try {
|
||||
throwPce();
|
||||
} catch (Exception <error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">LOG.error(e)</error>;
|
||||
} catch (Exception <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">LOG.error(e)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testSwallowedAndOnlyExceptionMessageLogged() {
|
||||
try {
|
||||
throwPce();
|
||||
} catch (Exception <error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
} catch (Exception <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testDisjunctionTypesWhenPceIsFirst() {
|
||||
try {
|
||||
throwPce();
|
||||
} catch (RuntimeException | Error <error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
} catch (RuntimeException | Error <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testDisjunctionTypesWhenPceIsSecond() {
|
||||
try {
|
||||
throwPce();
|
||||
} catch (Error | RuntimeException <error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
} catch (Error | RuntimeException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testPceSwallowedAndMultipleGenericCatchClauses() {
|
||||
try {
|
||||
throwPce();
|
||||
} catch (RuntimeException <error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>) {
|
||||
} catch (RuntimeException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>) {
|
||||
// exception swallowed
|
||||
} catch (Exception e) {
|
||||
// exception swallowed
|
||||
@@ -92,7 +92,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPce();
|
||||
} catch (RuntimeException e) {
|
||||
<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">LOG.error(e)</error>;
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">LOG.error(e)</error>;
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
LOG.error(e);
|
||||
@@ -109,8 +109,8 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPce();
|
||||
}
|
||||
catch (ProcessCanceledException <error descr="'ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
catch (ProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">LOG.error(e)</error>;
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
@@ -129,7 +129,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
void testPceInheritorSwallowed() {
|
||||
try {
|
||||
throwPceInheritor();
|
||||
} catch (Exception <error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
} catch (Exception <error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
@@ -138,7 +138,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPceInheritor();
|
||||
} catch (Exception e) {
|
||||
<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">LOG.error(e)</error>;
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">LOG.error(e)</error>;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -146,55 +146,55 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
void testPceInheritorSwallowedAndLoggedWithMessageOnInfoLevel() {
|
||||
try {
|
||||
throwPceInheritor();
|
||||
} catch (Exception <error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">LOG.info("Error occured", e)</error>;
|
||||
} catch (Exception <error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">LOG.info("Error occured", e)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testPceInheritorSwallowedAndLoggedOnInfoLevel() {
|
||||
try {
|
||||
throwPceInheritor();
|
||||
} catch (Exception <error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">LOG.info(e)</error>;
|
||||
} catch (Exception <error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">LOG.info(e)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testPceInheritorSwallowedAndLoggedOnErrorLevel() {
|
||||
try {
|
||||
throwPceInheritor();
|
||||
} catch (Exception <error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">LOG.error(e)</error>;
|
||||
} catch (Exception <error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">LOG.error(e)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testPceInheritorSwallowedAndOnlyExceptionMessageLogged() {
|
||||
try {
|
||||
throwPceInheritor();
|
||||
} catch (Exception <error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
} catch (Exception <error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testDisjunctionTypesWhenPceInheritorIsFirst() {
|
||||
try {
|
||||
throwPceInheritor();
|
||||
} catch (RuntimeException | Error <error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
} catch (RuntimeException | Error <error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testDisjunctionTypesWhenPceInheritorIsSecond() {
|
||||
try {
|
||||
throwPceInheritor();
|
||||
} catch (Error | RuntimeException <error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
} catch (Error | RuntimeException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">LOG.error("Error occurred: " + e.getMessage())</error>;
|
||||
}
|
||||
}
|
||||
|
||||
void testPceInheritorSwallowedAndMultipleGenericCatchClauses() {
|
||||
try {
|
||||
throwPceInheritor();
|
||||
} catch (RuntimeException <error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
} catch (RuntimeException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>) {
|
||||
// exception swallowed
|
||||
} catch (Exception e) {
|
||||
// exception swallowed
|
||||
@@ -207,7 +207,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPceInheritor();
|
||||
} catch (RuntimeException e) {
|
||||
<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">LOG.error(e)</error>;
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">LOG.error(e)</error>;
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
LOG.error(e);
|
||||
@@ -224,8 +224,8 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPceInheritor();
|
||||
}
|
||||
catch (SubclassOfProcessCanceledException <error descr="'ProcessCanceledException' inheritor must be rethrown">e</error>) {
|
||||
<error descr="'ProcessCanceledException' inheritor must not be logged">LOG.error(e)</error>;
|
||||
catch (SubclassOfProcessCanceledException <error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown">e</error>) {
|
||||
<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged">LOG.error(e)</error>;
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import com.example.SubclassOfCancellationException
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import kotlinx.coroutines.CancellationException
|
||||
|
||||
private val LOG = Logger.getInstance("any")
|
||||
|
||||
fun launch(block: suspend () -> Unit) {
|
||||
// ...
|
||||
}
|
||||
|
||||
class IncorrectCeHandlingInSuspendingLambdasTests {
|
||||
fun testCeSwallowed() {
|
||||
launch {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun testCeLogged() {
|
||||
launch {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (e: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun testSwallowedAndLoggedWithMessageOnInfoLevel() {
|
||||
launch {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">info("Error occured", e)</error>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun testSwallowedAndLoggedOnInfoLevel() {
|
||||
launch {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">info(e)</error>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun testSwallowedAndLoggedOnErrorLevel() {
|
||||
launch {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">error(e)</error>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun testSwallowedAndOnlyExceptionMessageLogged() {
|
||||
launch {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">error("Error occurred: " + e.message)</error>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// should not report subclasses
|
||||
fun testCeInheritorSwallowedAndLogger() {
|
||||
launch {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (e: SubclassOfCancellationException) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import com.example.SubclassOfCancellationException
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import kotlinx.coroutines.CancellationException
|
||||
|
||||
private val LOG = Logger.getInstance("any")
|
||||
|
||||
class IncorrectCeHandlingTests {
|
||||
suspend fun testCeSwallowed() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testCeLogged() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (e: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testSwallowedAndLoggedWithMessageOnInfoLevel() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">info("Error occured", e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testSwallowedAndLoggedOnInfoLevel() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">info(e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testSwallowedAndLoggedOnErrorLevel() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">error(e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testSwallowedAndOnlyExceptionMessageLogged() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">error("Error occurred: " + e.message)</error>
|
||||
}
|
||||
}
|
||||
|
||||
// should not report subclasses
|
||||
suspend fun testCeInheritorSwallowedAndLogger() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (e: SubclassOfCancellationException) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
import com.example.SubclassOfCancellationException
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import kotlinx.coroutines.CancellationException
|
||||
|
||||
private val LOG = Logger.getInstance("any")
|
||||
|
||||
class IncorrectCeHandlingWhenMultipleCatchClausesTests {
|
||||
suspend fun testCeSwallowed() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: Exception) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testCeLogged() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (e: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
catch (e: Exception) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testSwallowedAndLoggedWithMessageOnInfoLevel() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">info("Error occured", e)</error>
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.info("Error occured", e)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testSwallowedAndLoggedOnInfoLevel() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">info(e)</error>
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.info(e)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testSwallowedAndLoggedOnErrorLevel() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">error(e)</error>
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testSwallowedAndOnlyExceptionMessageLogged() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">error("Error occurred: " + e.message)</error>
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error("Error occurred: " + e.message)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testCeSwallowedAndMultipleGenericCatchClauses() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: Exception) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testCeLoggedAndMultipleGenericCatchClauses() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (e: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
LOG.error(e)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testCeInheritorSwallowedAndMultipleGenericCatchClauses() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
// should not report subclasses of CancellationException:
|
||||
catch (e: SubclassOfCancellationException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: Exception) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testCeInheritorLoggedAndMultipleGenericCatchClauses() {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
// subclasses should not be reported:
|
||||
catch (e: SubclassOfCancellationException) {
|
||||
LOG.error(e)
|
||||
throw e
|
||||
}
|
||||
catch (e: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
LOG.error(e)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testNotHandlingOuterTryIfNestedCatchesCe() {
|
||||
try {
|
||||
// anything
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">error(e)</error>
|
||||
}
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
import com.example.SubclassOfCancellationException
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import kotlinx.coroutines.CancellationException
|
||||
|
||||
private val LOG = Logger.getInstance("any")
|
||||
|
||||
class IncorrectCeHandlingWhenCeCaughtImplicitlyTests {
|
||||
|
||||
// tests for CancellationException
|
||||
@Throws(CancellationException::class)
|
||||
fun throwCe() {
|
||||
// anything
|
||||
}
|
||||
|
||||
fun testCeSwallowed() {
|
||||
try {
|
||||
throwCe()
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown. It is thrown by 'throwCe()'.">e</error>: Exception) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
|
||||
fun testCeLogged() {
|
||||
try {
|
||||
throwCe()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged. It is thrown by 'throwCe()'.">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
fun testSwallowedAndLoggedWithMessageOnInfoLevel() {
|
||||
try {
|
||||
throwCe()
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown. It is thrown by 'throwCe()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged. It is thrown by 'throwCe()'.">info("Error occured", e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
fun testSwallowedAndLoggedOnInfoLevel() {
|
||||
try {
|
||||
throwCe()
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown. It is thrown by 'throwCe()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged. It is thrown by 'throwCe()'.">info(e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
fun testSwallowedAndLoggedOnErrorLevel() {
|
||||
try {
|
||||
throwCe()
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown. It is thrown by 'throwCe()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged. It is thrown by 'throwCe()'.">error(e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
fun testSwallowedAndOnlyExceptionMessageLogged() {
|
||||
try {
|
||||
throwCe()
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown. It is thrown by 'throwCe()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged. It is thrown by 'throwCe()'.">error("Error occurred: " + e.message)</error>
|
||||
}
|
||||
}
|
||||
|
||||
fun testCeSwallowedAndMultipleGenericCatchClauses() {
|
||||
try {
|
||||
throwCe()
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown. It is thrown by 'throwCe()'.">e</error>: RuntimeException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: Exception) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
|
||||
fun testCeLoggedAndMultipleGenericCatchClauses() {
|
||||
try {
|
||||
throwCe()
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged. It is thrown by 'throwCe()'.">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
throw e
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
LOG.error(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
fun testNotHandlingOuterTryIfNestedCatchesCe() {
|
||||
try {
|
||||
// anything
|
||||
try {
|
||||
throwCe()
|
||||
}
|
||||
catch (<error descr="'kotlinx.coroutines.CancellationException' must be rethrown">e</error>: CancellationException) {
|
||||
LOG.<error descr="'kotlinx.coroutines.CancellationException' must not be logged">error(e)</error>
|
||||
}
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
// tests for CancellationException inheritor; they should not be reported
|
||||
@Throws(SubclassOfCancellationException::class)
|
||||
fun throwCeInheritor() {
|
||||
// anything
|
||||
}
|
||||
|
||||
fun testCeInheritorSwallowed() {
|
||||
try {
|
||||
throwCeInheritor()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
|
||||
fun testCeInheritorLogged() {
|
||||
try {
|
||||
throwCeInheritor()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
fun testCeInheritorSwallowedAndLoggedWithMessageOnInfoLevel() {
|
||||
try {
|
||||
throwCeInheritor()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.info("Error occured", e)
|
||||
}
|
||||
}
|
||||
|
||||
fun testCeInheritorSwallowedAndLoggedOnInfoLevel() {
|
||||
try {
|
||||
throwCeInheritor()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.info(e)
|
||||
}
|
||||
}
|
||||
|
||||
fun testCeInheritorSwallowedAndLoggedOnErrorLevel() {
|
||||
try {
|
||||
throwCeInheritor()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
fun testCeInheritorSwallowedAndOnlyExceptionMessageLogged() {
|
||||
try {
|
||||
throwCeInheritor()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error("Error occurred: " + e.message)
|
||||
}
|
||||
}
|
||||
|
||||
fun testCeInheritorSwallowedAndMultipleGenericCatchClauses() {
|
||||
try {
|
||||
throwCeInheritor()
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: Exception) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
|
||||
fun testCeInheritorLoggedAndMultipleGenericCatchClauses() {
|
||||
try {
|
||||
throwCeInheritor()
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
LOG.error(e)
|
||||
throw e
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
throw e
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
LOG.error(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
fun testNotHandlingOuterTryIfNestedCatchesCeInheritor() {
|
||||
try {
|
||||
// anything
|
||||
try {
|
||||
throwCeInheritor()
|
||||
}
|
||||
catch (e: SubclassOfCancellationException) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,7 @@ class IncorrectPceHandlingTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ class IncorrectPceHandlingTests {
|
||||
// anything
|
||||
}
|
||||
catch (e: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">error(e)</error>
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,8 @@ class IncorrectPceHandlingTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">info("Error occured", e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">info("Error occured", e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ class IncorrectPceHandlingTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">info(e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">info(e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ class IncorrectPceHandlingTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">error(e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">error(e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +55,8 @@ class IncorrectPceHandlingTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">error("Error occurred: " + e.message)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">error("Error occurred: " + e.message)</error>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,8 +64,8 @@ class IncorrectPceHandlingTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' inheritor must be rethrown">e</error>: SubclassOfProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' inheritor must not be logged">error(e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown">e</error>: SubclassOfProcessCanceledException) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged">error(e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: Exception) {
|
||||
@@ -22,7 +22,7 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
// anything
|
||||
}
|
||||
catch (e: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">error(e)</error>
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
catch (e: Exception) {
|
||||
@@ -34,8 +34,8 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">info("Error occured", e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">info("Error occured", e)</error>
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.info("Error occured", e)
|
||||
@@ -46,8 +46,8 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">info(e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">info(e)</error>
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.info(e)
|
||||
@@ -58,8 +58,8 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">error(e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">error(e)</error>
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
@@ -70,8 +70,8 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">error("Error occurred: " + e.message)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">error("Error occurred: " + e.message)</error>
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error("Error occurred: " + e.message)
|
||||
@@ -82,7 +82,7 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
@@ -101,7 +101,7 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
// anything
|
||||
}
|
||||
catch (e: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">error(e)</error>
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
@@ -119,10 +119,10 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' inheritor must be rethrown">e</error>: SubclassOfProcessCanceledException) {
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown">e</error>: SubclassOfProcessCanceledException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
@@ -141,11 +141,11 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
// anything
|
||||
}
|
||||
catch (e: SubclassOfProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' inheritor must not be logged">error(e)</error>
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
catch (e: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">error(e)</error>
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
@@ -165,8 +165,8 @@ class IncorrectPceHandlingWhenMultipleCatchClausesTests {
|
||||
try {
|
||||
// anything
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">error(e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">error(e)</error>
|
||||
}
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
|
||||
@@ -16,7 +16,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPce()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>: Exception) {
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>: Exception) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
throwPce()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">error(e)</error>
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -35,8 +35,8 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPce()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">info("Error occured", e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">info("Error occured", e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPce()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">info(e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">info(e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +53,8 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPce()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">error(e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">error(e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,8 +62,8 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPce()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">error("Error occurred: " + e.message)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">error("Error occurred: " + e.message)</error>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPce()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown. 'ProcessCanceledException' is thrown by 'throwPce()'.">e</error>: RuntimeException) {
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown. It is thrown by 'throwPce()'.">e</error>: RuntimeException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: Exception) {
|
||||
@@ -87,7 +87,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
throwPce()
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged. 'ProcessCanceledException' is thrown by 'throwPce()'.">error(e)</error>
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged. It is thrown by 'throwPce()'.">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
catch (e: Exception) {
|
||||
@@ -106,8 +106,8 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPce()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' must not be logged">error(e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must be rethrown">e</error>: ProcessCanceledException) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' must not be logged">error(e)</error>
|
||||
}
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
@@ -125,7 +125,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPceInheritor()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>: Exception) {
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>: Exception) {
|
||||
// exception swallowed
|
||||
}
|
||||
}
|
||||
@@ -135,7 +135,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
throwPceInheritor()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">error(e)</error>
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -144,8 +144,8 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPceInheritor()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">info("Error occured", e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">info("Error occured", e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,8 +153,8 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPceInheritor()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">info(e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">info(e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,8 +162,8 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPceInheritor()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">error(e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">error(e)</error>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,8 +171,8 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPceInheritor()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">error("Error occurred: " + e.message)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>: Exception) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">error("Error occurred: " + e.message)</error>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPceInheritor()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' inheritor must be rethrown. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">e</error>: RuntimeException) {
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown. It is thrown by 'throwPceInheritor()'.">e</error>: RuntimeException) {
|
||||
// exception swallowed
|
||||
}
|
||||
catch (e: Exception) {
|
||||
@@ -196,7 +196,7 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
throwPceInheritor()
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
LOG.<error descr="'ProcessCanceledException' inheritor must not be logged. 'ProcessCanceledException' is thrown by 'throwPceInheritor()'.">error(e)</error>
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged. It is thrown by 'throwPceInheritor()'.">error(e)</error>
|
||||
throw e
|
||||
}
|
||||
catch (e: Exception) {
|
||||
@@ -215,8 +215,8 @@ class IncorrectPceHandlingWhenPceCaughtImplicitlyTests {
|
||||
try {
|
||||
throwPceInheritor()
|
||||
}
|
||||
catch (<error descr="'ProcessCanceledException' inheritor must be rethrown">e</error>: SubclassOfProcessCanceledException) {
|
||||
LOG.<error descr="'ProcessCanceledException' inheritor must not be logged">error(e)</error>
|
||||
catch (<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must be rethrown">e</error>: SubclassOfProcessCanceledException) {
|
||||
LOG.<error descr="'com.intellij.openapi.progress.ProcessCanceledException' inheritor must not be logged">error(e)</error>
|
||||
}
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.kotlin.inspections
|
||||
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
@@ -6,12 +6,11 @@ import org.intellij.lang.annotations.Language
|
||||
import org.jetbrains.idea.devkit.inspections.IncorrectProcessCanceledExceptionHandlingInspectionTestBase
|
||||
import org.jetbrains.idea.devkit.kotlin.DevkitKtTestsUtil
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData/inspections/incorrectPceHandling")
|
||||
class KtIncorrectProcessCanceledExceptionHandlingInspectionTest : IncorrectProcessCanceledExceptionHandlingInspectionTestBase() {
|
||||
abstract class KtIncorrectProcessCanceledExceptionHandlingInspectionTestBase : IncorrectProcessCanceledExceptionHandlingInspectionTestBase() {
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
addKotlinFile("JvmPlatformAnnotations.kt", """
|
||||
addKotlinFile("JvmPlatformAnnotations.kt", """
|
||||
package kotlin.jvm
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@@ -19,7 +18,7 @@ class KtIncorrectProcessCanceledExceptionHandlingInspectionTest : IncorrectProce
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class Throws(vararg val exceptionClasses: KClass<out Throwable>)
|
||||
""")
|
||||
addKotlinFile("Throws.kt", """
|
||||
addKotlinFile("Throws.kt", """
|
||||
package kotlin
|
||||
|
||||
@SinceKotlin("1.4")
|
||||
@@ -32,10 +31,19 @@ class KtIncorrectProcessCanceledExceptionHandlingInspectionTest : IncorrectProce
|
||||
""")
|
||||
}
|
||||
|
||||
private fun addKotlinFile(relativePath: String, @Language("kotlin") fileText: String) {
|
||||
protected fun addKotlinFile(relativePath: String, @Language("kotlin") fileText: String) {
|
||||
myFixture.addFileToProject(relativePath, fileText)
|
||||
}
|
||||
|
||||
override fun getBasePath() = DevkitKtTestsUtil.TESTDATA_PATH + "inspections/incorrectPceHandling"
|
||||
|
||||
override fun getFileExtension() = "kt"
|
||||
|
||||
}
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData/inspections/incorrectPceHandling")
|
||||
class KtIncorrectProcessCanceledExceptionHandlingInspectionTest : KtIncorrectProcessCanceledExceptionHandlingInspectionTestBase() {
|
||||
|
||||
fun testIncorrectPceHandlingTests() {
|
||||
doTest()
|
||||
}
|
||||
@@ -47,9 +55,73 @@ class KtIncorrectProcessCanceledExceptionHandlingInspectionTest : IncorrectProce
|
||||
fun testIncorrectPceHandlingWhenPceCaughtImplicitlyTests() {
|
||||
doTest()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getBasePath() = DevkitKtTestsUtil.TESTDATA_PATH + "inspections/incorrectPceHandling"
|
||||
|
||||
override fun getFileExtension() = "kt"
|
||||
@TestDataPath("\$CONTENT_ROOT/testData/inspections/incorrectPceHandling")
|
||||
class KtIncorrectCancellationExceptionHandlingInspectionTest : KtIncorrectProcessCanceledExceptionHandlingInspectionTestBase() {
|
||||
|
||||
private val USE_K2_KEY = "idea.kotlin.plugin.use.k2"
|
||||
private var previousK2Property: String? = null
|
||||
|
||||
override fun setUp() {
|
||||
previousK2Property = System.getProperty(USE_K2_KEY)
|
||||
System.setProperty(USE_K2_KEY, "true")
|
||||
super.setUp()
|
||||
myFixture.addClass("""
|
||||
package java.util.concurrent;
|
||||
public class CancellationException extends IllegalStateException {
|
||||
public CancellationException() {}
|
||||
public CancellationException(String message) { super(message); }
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
addKotlinFile("CancellationException.kt", """
|
||||
package kotlinx.coroutines
|
||||
|
||||
@SinceKotlin("1.4")
|
||||
typealias CancellationException = java.util.concurrent.CancellationException
|
||||
""")
|
||||
addKotlinFile("SubclassOfCancellationException.kt", """
|
||||
package com.example
|
||||
import kotlinx.coroutines.CancellationException
|
||||
class SubclassOfCancellationException : CancellationException()
|
||||
""")
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
try {
|
||||
val prevK2Property = previousK2Property
|
||||
if (prevK2Property != null) {
|
||||
System.setProperty(USE_K2_KEY, prevK2Property)
|
||||
}
|
||||
else {
|
||||
System.clearProperty(USE_K2_KEY)
|
||||
}
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
addSuppressedException(e)
|
||||
}
|
||||
finally {
|
||||
super.tearDown()
|
||||
}
|
||||
}
|
||||
|
||||
fun testIncorrectCeHandlingTests() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testIncorrectCeHandlingInSuspendingLambdasTests() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testIncorrectCeHandlingWhenMultipleCatchClausesTests() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
// TODO: disabled - for some reason @Throws cannot be resolved in test data
|
||||
/*fun testIncorrectCeHandlingWhenPceCaughtImplicitlyTests() {
|
||||
doTest()
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
@@ -86,5 +86,8 @@
|
||||
<addServiceAnnotationProvider
|
||||
language="kotlin"
|
||||
implementationClass="org.jetbrains.idea.devkit.kotlin.inspections.KotlinAddServiceAnnotationProvider"/>
|
||||
<cancellationExceptionHandlingChecker
|
||||
language="kotlin"
|
||||
implementationClass="org.jetbrains.idea.devkit.kotlin.inspections.KtCancellationExceptionHandlingChecker"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.kotlin.inspections
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.idea.devkit.inspections.CancellationExceptionHandlingChecker
|
||||
import org.jetbrains.idea.devkit.kotlin.util.getContext
|
||||
import org.jetbrains.kotlin.analysis.api.KaSession
|
||||
import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KaAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaCallableSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.name
|
||||
import org.jetbrains.kotlin.analysis.api.types.KaType
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.psi.KtTryExpression
|
||||
|
||||
private val cancellationExceptionClassId = ClassId.fromString("kotlinx/coroutines/CancellationException")
|
||||
private val throwsClassId = ClassId.fromString("kotlin/jvm/Throws")
|
||||
|
||||
internal class KtCancellationExceptionHandlingChecker : CancellationExceptionHandlingChecker {
|
||||
|
||||
override fun isSuspicious(catchParameter: PsiElement): Boolean {
|
||||
val parameter = catchParameter as? KtParameter ?: return false
|
||||
if (getContext(parameter).isSuspending()) {
|
||||
analyze(parameter) {
|
||||
val catchParameterType = parameter.typeReference?.type ?: return false
|
||||
val cancellationException = buildClassType(cancellationExceptionClassId)
|
||||
return catchParameterType.semanticallyEquals(cancellationException)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getCeName(): String {
|
||||
return "kotlinx.coroutines.CancellationException"
|
||||
}
|
||||
|
||||
override fun containsSuspiciousCeCatchClause(tryExpression: PsiElement): Boolean {
|
||||
val parameter = tryExpression as? KtTryExpression ?: return false
|
||||
if (getContext(parameter).isSuspending()) {
|
||||
return analyze(parameter) {
|
||||
parameter.catchClauses
|
||||
.any { it.catchParameter?.expressionType?.semanticallyEquals(buildCancellationExceptionType()) == true }
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun findCeThrowingExpressionName(tryExpression: PsiElement): String? {
|
||||
val ktTryExpression = tryExpression as? KtTryExpression ?: return null
|
||||
for (expression in ktTryExpression.tryBlock.statements.filterIsInstance<KtCallExpression>()) {
|
||||
analyze(expression) {
|
||||
// workaround with calleeExpression as expression.mainReference?.resolveToSymbol() doesn't work
|
||||
val symbol = expression.calleeExpression?.mainReference?.resolveToSymbol() as? KaCallableSymbol ?: return@analyze
|
||||
if (throwsCe(symbol)) {
|
||||
return symbol.name?.asString()
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun KaSession.throwsCe(symbol: KaCallableSymbol): Boolean {
|
||||
val exceptionClasses = symbol.annotations.firstOrNull { it.classId == throwsClassId }
|
||||
?.arguments?.firstOrNull { it.name.asString() == "exceptionClasses" }
|
||||
?.expression as? KaAnnotationValue.ArrayValue ?: return false
|
||||
return exceptionClasses.values
|
||||
.filterIsInstance<KaAnnotationValue.ClassLiteralValue>()
|
||||
.any { it.type.semanticallyEquals(buildCancellationExceptionType()) }
|
||||
}
|
||||
|
||||
private fun KaSession.buildCancellationExceptionType(): KaType =
|
||||
buildClassType(cancellationExceptionClassId)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user