JS: when checking calls to JsModule declarations, check arguments passed to reified type parameters. See KT-15253
This commit is contained in:
+9
-1
@@ -41,6 +41,14 @@ fun box() {
|
||||
<!CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM!>baz<!>()
|
||||
|
||||
B.<!CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM!>Nested<!>()
|
||||
|
||||
boo<<!CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM!>B?<!>>(null)
|
||||
<!CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM!>boo<!>(null as B?)
|
||||
boo<<!CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM!>B.Nested?<!>>(null)
|
||||
}
|
||||
|
||||
external class DerivedB : <!CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM!>B<!>
|
||||
external class DerivedB : <!CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM!>B<!>
|
||||
|
||||
inline fun <reified T> boo(x: T) {
|
||||
println("${T::class.simpleName}: $x")
|
||||
}
|
||||
@@ -34,6 +34,7 @@ package foo {
|
||||
package
|
||||
|
||||
package bar {
|
||||
public inline fun </*0*/ reified T> boo(/*0*/ x: T): kotlin.Unit
|
||||
public fun box(): kotlin.Unit
|
||||
|
||||
public external final class DerivedB : foo.B {
|
||||
|
||||
+9
-1
@@ -34,6 +34,14 @@ fun box() {
|
||||
<!CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM!>B<!>()
|
||||
<!CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM!>bar<!>()
|
||||
B.<!CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM!>Nested<!>()
|
||||
|
||||
boo<<!CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM!>B?<!>>(null)
|
||||
<!CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM!>boo<!>(null as B?)
|
||||
boo<<!CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM!>B.Nested?<!>>(null)
|
||||
}
|
||||
|
||||
external class DerivedB : <!CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM!>B<!>
|
||||
external class DerivedB : <!CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM!>B<!>
|
||||
|
||||
inline fun <reified T> boo(x: T) {
|
||||
println("${T::class.simpleName}: $x")
|
||||
}
|
||||
+1
@@ -1,6 +1,7 @@
|
||||
package
|
||||
|
||||
package bar {
|
||||
public inline fun </*0*/ reified T> boo(/*0*/ x: T): kotlin.Unit
|
||||
public fun box(): kotlin.Unit
|
||||
|
||||
public external final class DerivedB : foo.B {
|
||||
|
||||
+4
-4
@@ -58,10 +58,10 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
|
||||
put(ErrorsJs.JS_MODULE_PROHIBITED_ON_NON_NATIVE, "@JsModule and @JsNonModule annotations prohibited for non-external declarations.")
|
||||
put(ErrorsJs.NESTED_JS_MODULE_PROHIBITED, "@JsModule and @JsNonModule can't appear on here since the file is already " +
|
||||
"marked by either @JsModule or @JsNonModule")
|
||||
put(ErrorsJs.CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM, "Can't access declaration marked with @JsModule annotation " +
|
||||
"from non-modular project")
|
||||
put(ErrorsJs.CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM, "Can't access declaration marked with @JsNonModule annotation " +
|
||||
"from modular project")
|
||||
put(ErrorsJs.CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM,
|
||||
"Can't access {0} marked with @JsModule annotation from non-modular project", Renderers.DECLARATION_NAME_WITH_KIND)
|
||||
put(ErrorsJs.CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM,
|
||||
"Can't access {0} marked with @JsNonModule annotation from modular project", Renderers.DECLARATION_NAME_WITH_KIND)
|
||||
put(ErrorsJs.CALL_FROM_UMD_MUST_BE_JS_MODULE_AND_JS_NON_MODULE, "When accessing module declarations from UMD, " +
|
||||
"they must be marked by both @JsModule and @JsNonModule")
|
||||
|
||||
|
||||
@@ -60,8 +60,10 @@ public interface ErrorsJs {
|
||||
DiagnosticFactory0<KtElement> JS_MODULE_PROHIBITED_ON_VAR = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
DiagnosticFactory0<KtElement> JS_MODULE_PROHIBITED_ON_NON_NATIVE = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
DiagnosticFactory0<KtElement> NESTED_JS_MODULE_PROHIBITED = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
DiagnosticFactory0<PsiElement> CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM = DiagnosticFactory0.create(ERROR, DEFAULT);
|
||||
DiagnosticFactory0<PsiElement> CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM = DiagnosticFactory0.create(ERROR, DEFAULT);
|
||||
DiagnosticFactory1<PsiElement, DeclarationDescriptor> CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM =
|
||||
DiagnosticFactory1.create(ERROR, DEFAULT);
|
||||
DiagnosticFactory1<PsiElement, DeclarationDescriptor> CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM =
|
||||
DiagnosticFactory1.create(ERROR, DEFAULT);
|
||||
DiagnosticFactory0<PsiElement> CALL_FROM_UMD_MUST_BE_JS_MODULE_AND_JS_NON_MODULE = DiagnosticFactory0.create(ERROR, DEFAULT);
|
||||
|
||||
DiagnosticFactory1<KtElement, KotlinType> NON_EXTERNAL_DECLARATION_IN_INAPPROPRIATE_FILE =
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.js.resolve.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
@@ -26,6 +27,8 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ClassValueReceiver
|
||||
|
||||
object JsModuleCallChecker : CallChecker {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
checkReifieidTypeParameters(resolvedCall, reportOn, context)
|
||||
|
||||
val callee = extractModuleCallee(resolvedCall) ?: return
|
||||
val bindingContext = context.trace.bindingContext
|
||||
val containingDescriptor = context.scope.ownerDescriptor
|
||||
@@ -41,4 +44,18 @@ object JsModuleCallChecker : CallChecker {
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun checkReifieidTypeParameters(call: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
val containingDescriptor = context.scope.ownerDescriptor
|
||||
val typeParams = call.candidateDescriptor.typeParameters.map { it.original }.withIndex().filter { (_, param) -> param.isReified }
|
||||
val typeArguments = call.call.typeArgumentList
|
||||
?.let { args -> typeParams.associate { (index, param) -> param.original to args.arguments[index].typeReference }}
|
||||
.orEmpty()
|
||||
for (typeParam in typeParams.map { (_, param) -> param.original }) {
|
||||
val argPsi = typeArguments[typeParam] ?: reportOn
|
||||
val typeArgument = call.typeArguments[typeParam] ?: continue
|
||||
val typeArgumentClass = typeArgument.constructor.declarationDescriptor as? ClassDescriptor ?: continue
|
||||
checkJsModuleUsage(context.trace.bindingContext, context.trace, containingDescriptor, typeArgumentClass, argPsi)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,12 +50,12 @@ fun checkJsModuleUsage(
|
||||
else {
|
||||
if (moduleKind == ModuleKind.PLAIN) {
|
||||
if (!callToNonModule && callToModule) {
|
||||
diagnosticSink.report(ErrorsJs.CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM.on(reportOn))
|
||||
diagnosticSink.report(ErrorsJs.CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM.on(reportOn, callee))
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!callToModule && callToNonModule) {
|
||||
diagnosticSink.report(ErrorsJs.CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM.on(reportOn))
|
||||
diagnosticSink.report(ErrorsJs.CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM.on(reportOn, callee))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user