[JS] JsExport diagnostics and legacy support
Account for JsExport in legacy backend namer. It means we catch overloaded exported function conflicts for free! Add error diagnostics: * NESTED_JS_EXPORT (Fixes KT-36798) * WRONG_EXPORTED_DECLARATION (Part of the fix for KT-37752) * NON_EXPORTABLE_TYPE (Fixes KT-37771)
This commit is contained in:
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.getNameForAnnotatedObject
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
||||
@@ -40,7 +41,7 @@ import kotlin.math.abs
|
||||
* A new instance of this class can be created for each request, however, it's recommended to use stable instance, since
|
||||
* [NameSuggestion] supports caching.
|
||||
*/
|
||||
class NameSuggestion {
|
||||
class NameSuggestion(val bindingContext: BindingContext) {
|
||||
private val cache: MutableMap<DeclarationDescriptor, SuggestedName?> = Collections.synchronizedMap(WeakHashMap())
|
||||
|
||||
/**
|
||||
@@ -112,7 +113,7 @@ class NameSuggestion {
|
||||
// Local functions and variables are always private with their own names as suggested names
|
||||
is CallableDescriptor ->
|
||||
if (DescriptorUtils.isDescriptorWithLocalVisibility(descriptor)) {
|
||||
val ownName = getNameForAnnotatedObject(descriptor) ?: getSuggestedName(descriptor)
|
||||
val ownName = getNameForAnnotatedObject(descriptor, bindingContext) ?: getSuggestedName(descriptor)
|
||||
var name = ownName
|
||||
var scope = descriptor.containingDeclaration
|
||||
|
||||
@@ -195,7 +196,7 @@ class NameSuggestion {
|
||||
|
||||
parts.reverse()
|
||||
val unmangledName = parts.joinToString("$")
|
||||
val (id, stable) = mangleNameIfNecessary(unmangledName, fixedDescriptor)
|
||||
val (id, stable) = mangleNameIfNecessary(unmangledName, fixedDescriptor, bindingContext)
|
||||
return SuggestedName(listOf(id), stable, fixedDescriptor, current)
|
||||
}
|
||||
|
||||
@@ -217,7 +218,7 @@ class NameSuggestion {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun mangleNameIfNecessary(baseName: String, descriptor: DeclarationDescriptor): NameAndStability {
|
||||
private fun mangleNameIfNecessary(baseName: String, descriptor: DeclarationDescriptor, bindingContext: BindingContext): NameAndStability {
|
||||
// If we have a callable descriptor (property or method) it can override method in a parent class.
|
||||
// Traverse to the topmost overridden method.
|
||||
// It does not matter which path to choose during traversal, since front-end must ensure
|
||||
@@ -230,7 +231,7 @@ class NameSuggestion {
|
||||
}
|
||||
|
||||
// If declaration is marked with either external, @native, @library or @JsName, return its stable name as is.
|
||||
val nativeName = getNameForAnnotatedObject(overriddenDescriptor)
|
||||
val nativeName = getNameForAnnotatedObject(overriddenDescriptor, bindingContext)
|
||||
if (nativeName != null) return NameAndStability(nativeName, true)
|
||||
|
||||
if (overriddenDescriptor is FunctionDescriptor) {
|
||||
|
||||
@@ -31,11 +31,13 @@ import org.jetbrains.kotlin.types.DynamicTypesAllowed
|
||||
object JsPlatformConfigurator : PlatformConfiguratorBase(
|
||||
DynamicTypesAllowed(),
|
||||
additionalDeclarationCheckers = listOf(
|
||||
NativeInvokeChecker(), NativeGetterChecker(), NativeSetterChecker(),
|
||||
JsNameChecker, JsModuleChecker, JsExternalFileChecker,
|
||||
JsExternalChecker, JsInheritanceChecker, JsMultipleInheritanceChecker,
|
||||
JsRuntimeAnnotationChecker,
|
||||
JsDynamicDeclarationChecker
|
||||
NativeInvokeChecker(), NativeGetterChecker(), NativeSetterChecker(),
|
||||
JsNameChecker, JsModuleChecker, JsExternalFileChecker,
|
||||
JsExternalChecker, JsInheritanceChecker, JsMultipleInheritanceChecker,
|
||||
JsRuntimeAnnotationChecker,
|
||||
JsDynamicDeclarationChecker,
|
||||
JsExportAnnotationChecker,
|
||||
JsExportDeclarationChecker
|
||||
),
|
||||
additionalCallCheckers = listOf(
|
||||
JsModuleCallChecker,
|
||||
@@ -46,7 +48,6 @@ object JsPlatformConfigurator : PlatformConfiguratorBase(
|
||||
identifierChecker = JsIdentifierChecker
|
||||
) {
|
||||
override fun configureModuleComponents(container: StorageComponentContainer) {
|
||||
container.useInstance(NameSuggestion())
|
||||
container.useImpl<JsCallChecker>()
|
||||
container.useImpl<JsTypeSpecificityComparator>()
|
||||
container.useImpl<JsNameClashChecker>()
|
||||
|
||||
+4
@@ -100,6 +100,10 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
|
||||
"Can't apply multiple inheritance here, since it's impossible to generate bridge for system function {0}",
|
||||
Renderers.DECLARATION_NAME_WITH_KIND)
|
||||
|
||||
put(ErrorsJs.NESTED_JS_EXPORT, "@JsExport is only allowed on files and top-level declarations")
|
||||
put(ErrorsJs.WRONG_EXPORTED_DECLARATION, "Declaration of such kind ({0}) can't be exported to JS", Renderers.STRING)
|
||||
put(ErrorsJs.NON_EXPORTABLE_TYPE, "Exported declaration uses non-exportable {0} type: {1}", Renderers.STRING, RENDER_TYPE)
|
||||
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +105,10 @@ public interface ErrorsJs {
|
||||
DiagnosticFactory1<PsiElement, CallableMemberDescriptor> WRONG_MULTIPLE_INHERITANCE =
|
||||
DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
|
||||
DiagnosticFactory0<PsiElement> NESTED_JS_EXPORT = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<KtExpression, String> WRONG_EXPORTED_DECLARATION = DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
DiagnosticFactory2<PsiElement, String, KotlinType> NON_EXPORTABLE_TYPE = DiagnosticFactory2.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
Object _initializer = new Object() {
|
||||
{
|
||||
|
||||
+2
-1
@@ -25,8 +25,9 @@ import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
|
||||
class JsBuiltinNameClashChecker(private val nameSuggestion: NameSuggestion) : DeclarationChecker {
|
||||
class JsBuiltinNameClashChecker : DeclarationChecker {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
val nameSuggestion = NameSuggestion(context.trace.bindingContext)
|
||||
if (AnnotationsUtils.isNativeObject(descriptor)) return
|
||||
if (descriptor.containingDeclaration !is ClassDescriptor) return
|
||||
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.js.resolve.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
|
||||
object JsExportAnnotationChecker : DeclarationChecker {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
val trace = context.trace
|
||||
|
||||
val jsExport = AnnotationsUtils.getJsExportAnnotation(descriptor) ?: return
|
||||
val jsExportPsi = jsExport.source.getPsi() ?: declaration
|
||||
|
||||
if (descriptor !is PackageFragmentDescriptor && !DescriptorUtils.isTopLevelDeclaration(descriptor)) {
|
||||
trace.report(ErrorsJs.NESTED_JS_EXPORT.on(jsExportPsi))
|
||||
}
|
||||
}
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.js.resolve.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind.*
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
|
||||
import org.jetbrains.kotlin.resolve.inline.isInlineWithReified
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeProjection
|
||||
import org.jetbrains.kotlin.types.isDynamic
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
|
||||
object JsExportDeclarationChecker : DeclarationChecker {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
val trace = context.trace
|
||||
val bindingContext = trace.bindingContext
|
||||
|
||||
fun checkTypeParameter(descriptor: TypeParameterDescriptor) {
|
||||
for (upperBound in descriptor.upperBounds) {
|
||||
if (!isTypeExportable(upperBound, bindingContext)) {
|
||||
val typeParameterDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor)!!
|
||||
trace.report(ErrorsJs.NON_EXPORTABLE_TYPE.on(typeParameterDeclaration, "upper bound", upperBound))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun checkValueParameter(descriptor: ValueParameterDescriptor) {
|
||||
if (!isTypeExportable(descriptor.type, bindingContext)) {
|
||||
val valueParameterDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor)!!
|
||||
trace.report(ErrorsJs.NON_EXPORTABLE_TYPE.on(valueParameterDeclaration, "parameter", descriptor.type))
|
||||
}
|
||||
}
|
||||
|
||||
if (!AnnotationsUtils.isExportedObject(descriptor, bindingContext)) return
|
||||
if (descriptor !is MemberDescriptor)
|
||||
return
|
||||
|
||||
val hasJsName = AnnotationsUtils.getJsNameAnnotation(descriptor) != null
|
||||
|
||||
fun reportWrongExportedDeclaration(kind: String) {
|
||||
trace.report(ErrorsJs.WRONG_EXPORTED_DECLARATION.on(declaration, kind))
|
||||
}
|
||||
|
||||
if (descriptor.isExpect) {
|
||||
reportWrongExportedDeclaration("expect")
|
||||
}
|
||||
|
||||
when (descriptor) {
|
||||
is FunctionDescriptor -> {
|
||||
for (typeParameter in descriptor.typeParameters) {
|
||||
checkTypeParameter(typeParameter)
|
||||
}
|
||||
|
||||
if (descriptor.isInlineWithReified()) {
|
||||
reportWrongExportedDeclaration("inline function with reified type parameters")
|
||||
return
|
||||
}
|
||||
|
||||
if (descriptor.isSuspend) {
|
||||
reportWrongExportedDeclaration("suspend function")
|
||||
return
|
||||
}
|
||||
|
||||
if (descriptor is ConstructorDescriptor) {
|
||||
if (!descriptor.isPrimary && !hasJsName)
|
||||
reportWrongExportedDeclaration("secondary constructor without @JsName")
|
||||
}
|
||||
|
||||
// Properties are checked instead of property accessors
|
||||
if (descriptor !is PropertyAccessorDescriptor) {
|
||||
for (parameter in descriptor.valueParameters) {
|
||||
checkValueParameter(parameter)
|
||||
}
|
||||
|
||||
descriptor.returnType?.let { returnType ->
|
||||
if (!isTypeExportable(returnType, bindingContext, true)) {
|
||||
trace.report(ErrorsJs.NON_EXPORTABLE_TYPE.on(declaration, "return", returnType))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is PropertyDescriptor -> {
|
||||
if (descriptor.isExtensionProperty) {
|
||||
reportWrongExportedDeclaration("extension property")
|
||||
return
|
||||
}
|
||||
if (!isTypeExportable(descriptor.type, bindingContext)) {
|
||||
trace.report(ErrorsJs.NON_EXPORTABLE_TYPE.on(declaration, "property", descriptor.type))
|
||||
}
|
||||
}
|
||||
|
||||
is ClassDescriptor -> {
|
||||
for (typeParameter in descriptor.declaredTypeParameters) {
|
||||
checkTypeParameter(typeParameter)
|
||||
}
|
||||
|
||||
if (descriptor.kind == ENUM_CLASS) {
|
||||
reportWrongExportedDeclaration("enum class")
|
||||
return
|
||||
}
|
||||
if (descriptor.kind == ANNOTATION_CLASS) {
|
||||
reportWrongExportedDeclaration("annotation class")
|
||||
return
|
||||
}
|
||||
if (descriptor.kind == ENUM_ENTRY) {
|
||||
// Covered by ENUM_CLASS
|
||||
return
|
||||
}
|
||||
|
||||
for (superType in descriptor.defaultType.supertypes()) {
|
||||
if (!isTypeExportable(superType, bindingContext)) {
|
||||
trace.report(ErrorsJs.NON_EXPORTABLE_TYPE.on(declaration, "super", superType))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun isTypeExportable(type: KotlinType, bindingContext: BindingContext, isReturnType: Boolean = false): Boolean {
|
||||
if (isReturnType && type.isUnit())
|
||||
return true
|
||||
|
||||
if (type.isFunctionType) {
|
||||
val arguments = type.arguments
|
||||
val argumentsSize = type.arguments.size - 1
|
||||
for (i in 0 until argumentsSize) {
|
||||
if (!isTypeExportable(arguments[i].type, bindingContext))
|
||||
return false
|
||||
}
|
||||
if (!isTypeExportable(arguments.last().type, bindingContext, isReturnType = true))
|
||||
return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
for (argument: TypeProjection in type.arguments) {
|
||||
if (!isTypeExportable(argument.type, bindingContext))
|
||||
return false
|
||||
}
|
||||
|
||||
val nonNullable = type.makeNotNullable()
|
||||
|
||||
// Is primitive exportable type
|
||||
if (nonNullable.isAnyOrNullableAny() ||
|
||||
nonNullable.isDynamic() ||
|
||||
nonNullable.isBoolean() ||
|
||||
KotlinBuiltIns.isThrowableOrNullableThrowable(nonNullable) ||
|
||||
KotlinBuiltIns.isString(nonNullable) ||
|
||||
(nonNullable.isPrimitiveNumberOrNullableType() && !nonNullable.isLong()) ||
|
||||
nonNullable.isNothingOrNullableNothing() ||
|
||||
(KotlinBuiltIns.isArray(type)) ||
|
||||
KotlinBuiltIns.isPrimitiveArray(type)
|
||||
) return true
|
||||
|
||||
val descriptor: ClassifierDescriptor = type.constructor.declarationDescriptor ?: return false
|
||||
return descriptor.isEffectivelyExternal() || AnnotationsUtils.isExportedObject(descriptor, bindingContext)
|
||||
}
|
||||
}
|
||||
+13
-2
@@ -5,18 +5,29 @@
|
||||
|
||||
package org.jetbrains.kotlin.js.resolve.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
|
||||
import org.jetbrains.kotlin.js.naming.NameSuggestion
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
|
||||
class JsNameCharsChecker(private val suggestion: NameSuggestion) : DeclarationChecker {
|
||||
class JsNameCharsChecker : DeclarationChecker {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
val bindingContext = context.trace.bindingContext
|
||||
|
||||
if (descriptor is PropertyAccessorDescriptor && AnnotationsUtils.getJsName(descriptor) == null) return
|
||||
|
||||
// This case will be reported as WRONG_EXPORTED_DECLARATION for
|
||||
// secondary constructor with missing JsName. Skipping it here to simplify further logic.
|
||||
if (descriptor is ConstructorDescriptor &&
|
||||
AnnotationsUtils.getJsName(descriptor) == null &&
|
||||
AnnotationsUtils.isExportedObject(descriptor, bindingContext)
|
||||
) return
|
||||
|
||||
val suggestion = NameSuggestion(bindingContext)
|
||||
val suggestedName = suggestion.suggest(descriptor) ?: return
|
||||
if (suggestedName.stable && suggestedName.names.any { NameSuggestion.sanitizeName(it) != it }) {
|
||||
context.trace.report(ErrorsJs.NAME_CONTAINS_ILLEGAL_CHARS.on(declaration))
|
||||
|
||||
+3
-1
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
|
||||
class JsNameClashChecker(
|
||||
private val nameSuggestion: NameSuggestion,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) : DeclarationChecker {
|
||||
companion object {
|
||||
@@ -45,6 +44,7 @@ class JsNameClashChecker(
|
||||
Errors.PACKAGE_OR_CLASSIFIER_REDECLARATION)
|
||||
}
|
||||
|
||||
lateinit var nameSuggestion: NameSuggestion
|
||||
private val scopes = mutableMapOf<DeclarationDescriptor, MutableMap<String, DeclarationDescriptor>>()
|
||||
private val clashedFakeOverrides = mutableMapOf<DeclarationDescriptor, Pair<DeclarationDescriptor, DeclarationDescriptor>>()
|
||||
private val clashedDescriptors = mutableSetOf<Pair<DeclarationDescriptor, String>>()
|
||||
@@ -62,6 +62,8 @@ class JsNameClashChecker(
|
||||
diagnosticHolder: DiagnosticSink, bindingContext: BindingContext
|
||||
) {
|
||||
if (descriptor is ConstructorDescriptor && descriptor.isPrimary) return
|
||||
if (!this::nameSuggestion.isInitialized || nameSuggestion.bindingContext !== bindingContext)
|
||||
nameSuggestion = NameSuggestion(bindingContext)
|
||||
|
||||
for (suggested in nameSuggestion.suggestAllPossibleNames(descriptor)) {
|
||||
if (suggested.stable && suggested.scope is ClassOrPackageFragmentDescriptor && presentsInGeneratedCode(suggested.descriptor)) {
|
||||
|
||||
@@ -40,6 +40,7 @@ import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.isEf
|
||||
|
||||
public final class AnnotationsUtils {
|
||||
private static final String JS_NAME = "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");
|
||||
public static final FqName JS_QUALIFIER_ANNOTATION = new FqName("kotlin.js.JsQualifier");
|
||||
@@ -83,7 +84,10 @@ public final class AnnotationsUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getNameForAnnotatedObject(@NotNull DeclarationDescriptor descriptor) {
|
||||
public static String getNameForAnnotatedObject(
|
||||
@NotNull DeclarationDescriptor descriptor,
|
||||
@NotNull BindingContext bindingContext
|
||||
) {
|
||||
String defaultJsName = getJsName(descriptor);
|
||||
|
||||
for (PredefinedAnnotation annotation : PredefinedAnnotation.Companion.getWITH_CUSTOM_NAME()) {
|
||||
@@ -97,7 +101,7 @@ public final class AnnotationsUtils {
|
||||
return name != null ? name : descriptor.getName().asString();
|
||||
}
|
||||
|
||||
if (defaultJsName == null && isEffectivelyExternalMember(descriptor)) {
|
||||
if (defaultJsName == null && (isEffectivelyExternalMember(descriptor) || isExportedObject(descriptor, bindingContext))) {
|
||||
return descriptor.getName().asString();
|
||||
}
|
||||
|
||||
@@ -112,6 +116,23 @@ public final class AnnotationsUtils {
|
||||
return descriptor.getAnnotations().findAnnotation(annotation.getFqName());
|
||||
}
|
||||
|
||||
public static boolean isExportedObject(@NotNull DeclarationDescriptor descriptor, @NotNull BindingContext bindingContext) {
|
||||
if (descriptor instanceof MemberDescriptor) {
|
||||
MemberDescriptor memberDescriptor = (MemberDescriptor) descriptor;
|
||||
if (memberDescriptor.getVisibility() != Visibilities.PUBLIC) return false;
|
||||
}
|
||||
|
||||
if (hasAnnotationOrInsideAnnotatedClass(descriptor, JS_EXPORT)) return true;
|
||||
|
||||
if (CollectionsKt.any(getContainingFileAnnotations(bindingContext, descriptor), annotation ->
|
||||
JS_EXPORT.equals(annotation.getFqName())
|
||||
)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isNativeObject(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (hasAnnotationOrInsideAnnotatedClass(descriptor, PredefinedAnnotation.NATIVE) || isEffectivelyExternalMember(descriptor)) return true;
|
||||
|
||||
@@ -154,6 +175,11 @@ public final class AnnotationsUtils {
|
||||
return descriptor.getAnnotations().findAnnotation(new FqName(JS_NAME));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static AnnotationDescriptor getJsExportAnnotation(@NotNull DeclarationDescriptor descriptor) {
|
||||
return descriptor.getAnnotations().findAnnotation(JS_EXPORT);
|
||||
}
|
||||
|
||||
public static boolean isPredefinedObject(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof MemberDescriptor && ((MemberDescriptor) descriptor).isExpect()) return true;
|
||||
if (isEffectivelyExternalMember(descriptor)) return true;
|
||||
|
||||
Reference in New Issue
Block a user