feat: add WARNING on usage top-level exportable declarations with non-consumable identifiers.
This commit is contained in:
+2
@@ -106,6 +106,8 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
|
||||
put(ErrorsJs.WRONG_EXPORTED_DECLARATION, "Declaration of such kind ({0}) can''t be exported to JS", STRING)
|
||||
put(ErrorsJs.NON_EXPORTABLE_TYPE, "Exported declaration uses non-exportable {0} type: {1}", STRING, RENDER_TYPE)
|
||||
|
||||
put(ErrorsJs.NON_CONSUMABLE_EXPORTED_IDENTIFIER, "Exported declaration contains non-consumable identifier '${0}', that can't be represented inside TS definitions and ESM", STRING)
|
||||
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +110,8 @@ public interface ErrorsJs {
|
||||
DiagnosticFactory1<KtExpression, String> WRONG_EXPORTED_DECLARATION = DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
DiagnosticFactory2<PsiElement, String, KotlinType> NON_EXPORTABLE_TYPE = DiagnosticFactory2.create(WARNING, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
|
||||
DiagnosticFactory1<PsiElement, String> NON_CONSUMABLE_EXPORTED_IDENTIFIER = DiagnosticFactory1.create(WARNING, DEFAULT);
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
Object _initializer = new Object() {
|
||||
{
|
||||
|
||||
+38
-2
@@ -5,15 +5,19 @@
|
||||
|
||||
package org.jetbrains.kotlin.js.resolve.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind.*
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.JsExportDeclarationChecker.isExportable
|
||||
import org.jetbrains.kotlin.js.common.RESERVED_KEYWORDS
|
||||
import org.jetbrains.kotlin.js.naming.NameSuggestion
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
@@ -22,6 +26,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isInsideInterface
|
||||
import org.jetbrains.kotlin.resolve.inline.isInlineWithReified
|
||||
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.isDynamic
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
@@ -61,6 +66,8 @@ object JsExportDeclarationChecker : DeclarationChecker {
|
||||
reportWrongExportedDeclaration("expect")
|
||||
}
|
||||
|
||||
validateDeclarationOnConsumableName(declaration, descriptor, trace)
|
||||
|
||||
when (descriptor) {
|
||||
is FunctionDescriptor -> {
|
||||
for (typeParameter in descriptor.typeParameters) {
|
||||
@@ -201,4 +208,33 @@ object JsExportDeclarationChecker : DeclarationChecker {
|
||||
|
||||
return descriptor.isEffectivelyExternal() || AnnotationsUtils.isExportedObject(descriptor, bindingContext)
|
||||
}
|
||||
|
||||
private fun validateDeclarationOnConsumableName(
|
||||
declaration: KtDeclaration,
|
||||
declarationDescriptor: DeclarationDescriptor,
|
||||
trace: BindingTrace
|
||||
) {
|
||||
if (!declarationDescriptor.isTopLevelInPackage() || declarationDescriptor.name.isSpecial) return
|
||||
|
||||
val name = declarationDescriptor.getKotlinOrJsName()
|
||||
|
||||
if (name !in RESERVED_KEYWORDS && NameSuggestion.sanitizeName(name) == name) return
|
||||
|
||||
val reportTarget = declarationDescriptor.getJsNameArgument() ?: declaration.getIdentifier()
|
||||
|
||||
trace.report(ErrorsJs.NON_CONSUMABLE_EXPORTED_IDENTIFIER.on(reportTarget, name))
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.getKotlinOrJsName(): String {
|
||||
return AnnotationsUtils.getJsName(this) ?: name.identifier
|
||||
}
|
||||
|
||||
private fun KtDeclaration.getIdentifier(): PsiElement {
|
||||
return (this as KtNamedDeclaration).nameIdentifier!!
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.getJsNameArgument(): PsiElement? {
|
||||
val jsNameAnnotation = AnnotationsUtils.getJsNameAnnotation(this) ?: return null
|
||||
return (jsNameAnnotation.source.getPsi() as KtAnnotationEntry).valueArgumentList?.arguments?.first()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ import java.util.List;
|
||||
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.isEffectivelyExternal;
|
||||
|
||||
public final class AnnotationsUtils {
|
||||
private static final String JS_NAME = "kotlin.js.JsName";
|
||||
public static final FqName JS_NAME = new FqName("kotlin.js.JsName");
|
||||
private static final FqName JS_EXPORT = new FqName("kotlin.js.JsExport");
|
||||
public static final FqName JS_MODULE_ANNOTATION = new FqName("kotlin.js.JsModule");
|
||||
private static final FqName JS_NON_MODULE_ANNOTATION = new FqName("kotlin.js.JsNonModule");
|
||||
@@ -172,7 +172,7 @@ public final class AnnotationsUtils {
|
||||
|
||||
@Nullable
|
||||
public static AnnotationDescriptor getJsNameAnnotation(@NotNull DeclarationDescriptor descriptor) {
|
||||
return descriptor.getAnnotations().findAnnotation(new FqName(JS_NAME));
|
||||
return descriptor.getAnnotations().findAnnotation(JS_NAME);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
Reference in New Issue
Block a user