JS: when checking calls to JsModule declarations, check arguments passed to reified type parameters. See KT-15253

This commit is contained in:
Alexey Andreev
2017-01-23 19:19:11 +03:00
parent 4c7a07bed6
commit 9000d54d8a
8 changed files with 47 additions and 10 deletions
@@ -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 {
@@ -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,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 {
@@ -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))
}
}
}