JS: prohibit declaration names that clash with JS builtin functions
See KT-18095, KT-17475, KT-18105, KT-5259
This commit is contained in:
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.js.resolve
|
||||
import org.jetbrains.kotlin.container.StorageComponentContainer
|
||||
import org.jetbrains.kotlin.container.useImpl
|
||||
import org.jetbrains.kotlin.container.useInstance
|
||||
import org.jetbrains.kotlin.js.naming.NameSuggestion
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.*
|
||||
import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.OverloadFilter
|
||||
@@ -56,11 +57,13 @@ object JsPlatformConfigurator : PlatformConfigurator(
|
||||
overridesBackwardCompatibilityHelper = OverridesBackwardCompatibilityHelper.DEFAULT
|
||||
) {
|
||||
override fun configureModuleComponents(container: StorageComponentContainer) {
|
||||
container.useInstance(NameSuggestion())
|
||||
container.useImpl<JsCallChecker>()
|
||||
container.useInstance(SyntheticScopes.Empty)
|
||||
container.useInstance(JsTypeSpecificityComparator)
|
||||
container.useInstance(JsNameClashChecker())
|
||||
container.useInstance(JsNameCharsChecker())
|
||||
container.useImpl<JsNameClashChecker>()
|
||||
container.useImpl<JsNameCharsChecker>()
|
||||
container.useImpl<JsBuiltinNameClashChecker>()
|
||||
container.useInstance(JsModuleClassLiteralChecker)
|
||||
container.useImpl<JsReflectionAPICallChecker>()
|
||||
container.useImpl<JsNativeRttiChecker>()
|
||||
|
||||
+2
@@ -44,6 +44,8 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
|
||||
Renderers.STRING, Renderers.COMPACT)
|
||||
put(ErrorsJs.JS_FAKE_NAME_CLASH, "JavaScript name {0} is generated for different inherited members: {1} and {2}",
|
||||
Renderers.STRING, Renderers.COMPACT, Renderers.COMPACT)
|
||||
put(ErrorsJs.JS_BUILTIN_NAME_CLASH, "JavaScript name generated for this declaration clashes with built-in declaration {1}",
|
||||
Renderers.STRING)
|
||||
put(ErrorsJs.JS_NAME_ON_PRIMARY_CONSTRUCTOR_PROHIBITED, "@JsName annotation is prohibited for primary constructors")
|
||||
put(ErrorsJs.JS_NAME_ON_ACCESSOR_AND_PROPERTY, "@JsName can be either on a property or its accessors, not both of them")
|
||||
put(ErrorsJs.JS_NAME_IS_NOT_ON_ALL_ACCESSORS, "@JsName should be on all of the property accessors")
|
||||
|
||||
@@ -48,6 +48,8 @@ public interface ErrorsJs {
|
||||
ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
DiagnosticFactory3<KtElement, String, DeclarationDescriptor, DeclarationDescriptor> JS_FAKE_NAME_CLASH =
|
||||
DiagnosticFactory3.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
DiagnosticFactory1<KtElement, String> JS_BUILTIN_NAME_CLASH = DiagnosticFactory1.create(
|
||||
ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
DiagnosticFactory0<PsiElement> JS_NAME_ON_PRIMARY_CONSTRUCTOR_PROHIBITED = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> JS_NAME_ON_ACCESSOR_AND_PROPERTY = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> JS_NAME_IS_NOT_ON_ALL_ACCESSORS = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.js.resolve.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
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.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker
|
||||
|
||||
class JsBuiltinNameClashChecker(private val nameSuggestion: NameSuggestion) : SimpleDeclarationChecker {
|
||||
override fun check(
|
||||
declaration: KtDeclaration, descriptor: DeclarationDescriptor,
|
||||
diagnosticHolder: DiagnosticSink, bindingContext: BindingContext
|
||||
) {
|
||||
if (AnnotationsUtils.isNativeObject(descriptor)) return
|
||||
if (descriptor.containingDeclaration !is ClassDescriptor) return
|
||||
|
||||
val suggestedName = nameSuggestion.suggest(descriptor)!!
|
||||
if (!suggestedName.stable) return
|
||||
val simpleName = suggestedName.names.single()
|
||||
|
||||
if (descriptor is ClassDescriptor) {
|
||||
if (simpleName in PROHIBITED_STATIC_NAMES) {
|
||||
diagnosticHolder.report(ErrorsJs.JS_BUILTIN_NAME_CLASH.on(declaration, "Function.$simpleName"))
|
||||
}
|
||||
}
|
||||
else if (descriptor is CallableMemberDescriptor) {
|
||||
if (simpleName in PROHIBITED_MEMBER_NAMES) {
|
||||
diagnosticHolder.report(ErrorsJs.JS_BUILTIN_NAME_CLASH.on(declaration, "Object.prototype.$simpleName"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val PROHIBITED_STATIC_NAMES = setOf("prototype", "length", "\$metadata\$")
|
||||
|
||||
@JvmField
|
||||
val PROHIBITED_MEMBER_NAMES = setOf("constructor")
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -41,9 +41,7 @@ import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker
|
||||
|
||||
class JsNameCharsChecker() : SimpleDeclarationChecker {
|
||||
val suggestion = NameSuggestion()
|
||||
|
||||
class JsNameCharsChecker(private val suggestion: NameSuggestion) : SimpleDeclarationChecker {
|
||||
override fun check(
|
||||
declaration: KtDeclaration, descriptor: DeclarationDescriptor,
|
||||
diagnosticHolder: DiagnosticSink, bindingContext: BindingContext
|
||||
|
||||
+1
-2
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
|
||||
class JsNameClashChecker : SimpleDeclarationChecker {
|
||||
class JsNameClashChecker(private val nameSuggestion: NameSuggestion) : SimpleDeclarationChecker {
|
||||
companion object {
|
||||
private val COMMON_DIAGNOSTICS = setOf(
|
||||
Errors.REDECLARATION,
|
||||
@@ -38,7 +38,6 @@ class JsNameClashChecker : SimpleDeclarationChecker {
|
||||
Errors.PACKAGE_OR_CLASSIFIER_REDECLARATION)
|
||||
}
|
||||
|
||||
private val 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>>()
|
||||
|
||||
Reference in New Issue
Block a user