Fix false-positive @Throws error diagnostics in Native

Don't report
THROWS_LIST_EMPTY and MISSING_EXCEPTION_IN_THROWS_ON_SUSPEND
caused by unresolved arguments.
This commit is contained in:
Svyatoslav Scherbina
2020-05-25 16:30:22 +03:00
parent 242d0aa26e
commit fa152593ef
3 changed files with 106 additions and 1 deletions
+68
View File
@@ -37,6 +37,41 @@ fun foo() {}
<!THROWS_LIST_EMPTY!>@Throws()<!>
fun throwsEmptyParens() {}
@Throws(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>UnresolvedException<!>::class<!>)
fun throwsUnresolved() {}
@Throws(exceptionClasses = <!ANNOTATION_ARGUMENT_MUST_BE_CONST, ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION_ERROR!><!UNRESOLVED_REFERENCE!>UnresolvedException<!>::class<!>)
fun throwsNamedUnresolved() {}
<!THROWS_LIST_EMPTY!>@Throws(exceptionClasses = [])<!>
fun throwsNamedEmptyLiteral() {}
<!THROWS_LIST_EMPTY!>@Throws(exceptionClasses = arrayOf())<!>
fun throwsNamedEmptyArrayOf() {}
<!THROWS_LIST_EMPTY!>@Throws(*[])<!>
fun throwsSpreadEmptyLiteral() {}
<!THROWS_LIST_EMPTY!>@Throws(*arrayOf())<!>
fun throwsSpreadEmptyArrayOf() {}
@Throws(exceptionClasses = <!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>[<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>UE<!>::class<!>]<!>)
fun throwsNamedLiteralWithUnresolved() {}
@Throws(exceptionClasses = <!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>arrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>UE<!>::class<!>)<!>)
fun throwsNamedArrayOfUnresolved() {}
@Throws(*<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>[<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>UE<!>::class<!>]<!>)
fun throwsSpreadLiteralWithUnresolved() {}
@Throws(*<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>arrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>UE<!>::class<!>)<!>)
fun throwsSpreadArrayOfUnresolved() {}
typealias UEAlias = <!UNRESOLVED_REFERENCE!>UE<!>
@Throws(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>UEAlias::class<!>)
fun throwsTypealiasToUnresolved() {}
interface Base0 {
fun foo()
}
@@ -244,6 +279,39 @@ suspend fun suspendDoesNotThrowCancellationException1() {}
<!MISSING_EXCEPTION_IN_THROWS_ON_SUSPEND!>@Throws(Exception1::class, Exception2::class)<!>
suspend fun suspendDoesNotThrowCancellationException2() {}
@Throws(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>UE<!>::class<!>)
suspend fun suspendThrowsUnresolved() {}
@Throws(exceptionClasses = <!ANNOTATION_ARGUMENT_MUST_BE_CONST, ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION_ERROR!><!UNRESOLVED_REFERENCE!>UE<!>::class<!>)
suspend fun suspendThrowsNamedUnresolved() {}
<!THROWS_LIST_EMPTY!>@Throws(exceptionClasses = [])<!>
suspend fun suspendThrowsNamedEmptyLiteral() {}
<!THROWS_LIST_EMPTY!>@Throws(exceptionClasses = arrayOf())<!>
suspend fun suspendThrowsNamedEmptyArrayOf() {}
<!THROWS_LIST_EMPTY!>@Throws(*[])<!>
suspend fun suspendThrowsSpreadEmptyLiteral() {}
<!THROWS_LIST_EMPTY!>@Throws(*arrayOf())<!>
suspend fun suspendThrowsSpreadEmptyArrayOf() {}
@Throws(exceptionClasses = <!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>[<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>UE<!>::class<!>]<!>)
suspend fun suspendThrowsNamedLiteralWithUnresolved() {}
@Throws(exceptionClasses = <!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>arrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>UE<!>::class<!>)<!>)
suspend fun suspendThrowsNamedArrayOfUnresolved() {}
@Throws(*<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>[<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>UE<!>::class<!>]<!>)
suspend fun suspendThrowsSpreadLiteralWithUnresolved() {}
@Throws(*<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>arrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!><!UNRESOLVED_REFERENCE!>UE<!>::class<!>)<!>)
suspend fun suspendThrowsSpreadArrayOfUnresolved() {}
@Throws(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>UEAlias::class<!>)
suspend fun suspendThrowsTypealiasToUnresolved() {}
@Throws(Exception1::class, CancellationException::class)
suspend fun suspendThrowsCancellationException1() {}
+23
View File
@@ -12,15 +12,37 @@ package
@kotlin.Throws(exceptionClasses = {kotlin.IllegalStateException::class}) public suspend fun suspendThrowsIllegalStateException1(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {Exception2::class, kotlin.IllegalStateException::class}) public suspend fun suspendThrowsIllegalStateException2(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {kotlin.IllegalStateException::class}) public suspend fun suspendThrowsIllegalStateExceptionTypealias(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public suspend fun suspendThrowsNamedArrayOfUnresolved(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public suspend fun suspendThrowsNamedEmptyArrayOf(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public suspend fun suspendThrowsNamedEmptyLiteral(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public suspend fun suspendThrowsNamedLiteralWithUnresolved(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public suspend fun suspendThrowsNamedUnresolved(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public suspend fun suspendThrowsNothing(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {kotlin.RuntimeException::class}) public suspend fun suspendThrowsRuntimeException1(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {kotlin.RuntimeException::class, Exception3::class}) public suspend fun suspendThrowsRuntimeException2(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {kotlin.RuntimeException::class}) public suspend fun suspendThrowsRuntimeExceptionTypealias(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public suspend fun suspendThrowsSpreadArrayOfUnresolved(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public suspend fun suspendThrowsSpreadEmptyArrayOf(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public suspend fun suspendThrowsSpreadEmptyLiteral(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public suspend fun suspendThrowsSpreadLiteralWithUnresolved(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {kotlin.Throwable::class}) public suspend fun suspendThrowsThrowable1(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {kotlin.Throwable::class, Exception2::class}) public suspend fun suspendThrowsThrowable2(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {kotlin.Throwable::class, kotlin.coroutines.cancellation.CancellationException::class}) public suspend fun suspendThrowsThrowable3(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {kotlin.Throwable::class}) public suspend fun suspendThrowsThrowableTypealias(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public suspend fun suspendThrowsTypealiasToUnresolved(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public suspend fun suspendThrowsUnresolved(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public fun throwsEmptyParens(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public fun throwsNamedArrayOfUnresolved(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public fun throwsNamedEmptyArrayOf(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public fun throwsNamedEmptyLiteral(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public fun throwsNamedLiteralWithUnresolved(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public fun throwsNamedUnresolved(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public fun throwsSpreadArrayOfUnresolved(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public fun throwsSpreadEmptyArrayOf(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public fun throwsSpreadEmptyLiteral(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public fun throwsSpreadLiteralWithUnresolved(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public fun throwsTypealiasToUnresolved(): kotlin.Unit
@kotlin.Throws(exceptionClasses = {}) public fun throwsUnresolved(): kotlin.Unit
public fun withLocalClass(): kotlin.Unit
public interface Base0 {
@@ -411,6 +433,7 @@ public typealias ExceptionAlias = kotlin.Exception
public typealias IllegalStateExceptionAlias = kotlin.IllegalStateException
public typealias RuntimeExceptionAlias = kotlin.RuntimeException
public typealias ThrowableAlias = kotlin.Throwable
public typealias UEAlias = [ERROR : UE]
package kotlin {
@@ -13,10 +13,15 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.lexer.KtTokens.SUSPEND_KEYWORD
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.StatementFilter
import org.jetbrains.kotlin.resolve.annotations.KOTLIN_THROWS_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.callUtil.hasUnresolvedArguments
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.constants.ArrayValue
@@ -41,12 +46,16 @@ object NativeThrowsChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val throwsAnnotation = descriptor.annotations.findAnnotation(throwsFqName)
val reportLocation = throwsAnnotation?.let { DescriptorToSourceUtils.getSourceFromAnnotation(it) } ?: declaration
val throwsAnnotationEntry = throwsAnnotation?.let { DescriptorToSourceUtils.getSourceFromAnnotation(it) }
val reportLocation = throwsAnnotationEntry ?: declaration
if (!checkInheritance(declaration, descriptor, context, throwsAnnotation, reportLocation)) return
if (throwsAnnotation == null) return
val bindingContext = context.trace.bindingContext
if (throwsAnnotationEntry?.getCall(bindingContext)?.hasUnresolvedArgumentsRecursive(bindingContext) == true) return
val classes = throwsAnnotation.getVariadicArguments()
if (classes.isEmpty()) {
context.trace.report(ErrorsNative.THROWS_LIST_EMPTY.on(reportLocation))
@@ -134,3 +143,8 @@ object NativeThrowsChecker : DeclarationChecker {
}
}
private fun Call.hasUnresolvedArgumentsRecursive(context: BindingContext): Boolean {
return this.hasUnresolvedArguments(context, StatementFilter.NONE) ||
valueArguments.any { it.getArgumentExpression()?.getCall(context)?.hasUnresolvedArgumentsRecursive(context) == true }
}