IJPL-162560: IncorrectProcessCanceledExceptionHandlingInspection: Add support for CancellationException in coroutine context

GitOrigin-RevId: aeaa49f2a8e27af62a3ec826b3cece3a4e0c447b
This commit is contained in:
Karol Lewandowski
2024-09-20 08:24:56 +02:00
committed by intellij-monorepo-bot
parent 132168dac4
commit cb6b9a9a0c
17 changed files with 1054 additions and 233 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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}''

View File

@@ -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?
}

View File

@@ -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>;
}
}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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)
}
}
}
}

View File

@@ -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)
}
}
}

View File

@@ -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)
}
}
}

View File

@@ -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)
}
}
}

View File

@@ -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>
}
}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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()
}*/
}

View File

@@ -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>

View File

@@ -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)
}