JS: prohibit declaration names that clash with JS builtin functions

See KT-18095, KT-17475, KT-18105, KT-5259
This commit is contained in:
Alexey Andreev
2017-10-16 18:51:14 +03:00
parent e0eea15a4c
commit 6adb62f3a2
12 changed files with 288 additions and 8 deletions
@@ -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>()
@@ -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);
@@ -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")
}
}
@@ -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
@@ -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>>()