KT-2752: add diagnostic that checks whether Kotlin declarations produce conflicting names in generated JS
This commit is contained in:
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
class A {
|
||||||
|
<!JS_NAME_CLASH!>fun bar() = 23<!>
|
||||||
|
|
||||||
|
<!JS_NAME_CLASH!>val bar = 23<!>
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package foo {
|
||||||
|
|
||||||
|
public final class A {
|
||||||
|
public constructor A()
|
||||||
|
public final val bar: kotlin.Int = 23
|
||||||
|
public final fun bar(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
class A
|
||||||
|
|
||||||
|
class B
|
||||||
|
|
||||||
|
val A.foo: Int
|
||||||
|
get() = 32
|
||||||
|
|
||||||
|
val B.foo: Int
|
||||||
|
get() = 42
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package foo {
|
||||||
|
public val foo.A.foo: kotlin.Int
|
||||||
|
public val foo.B.foo: kotlin.Int
|
||||||
|
|
||||||
|
public final class A {
|
||||||
|
public constructor A()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class B {
|
||||||
|
public constructor B()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
fun bar() = 23
|
||||||
|
|
||||||
|
private val bar = 32
|
||||||
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package foo {
|
||||||
|
private val bar: kotlin.Int = 32
|
||||||
|
public fun bar(): kotlin.Int
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// FILE: foo.kt
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
fun bar(x: Int) = x
|
||||||
|
|
||||||
|
// FILE: foobar.kt
|
||||||
|
|
||||||
|
package foo.bar
|
||||||
|
|
||||||
|
val x = 42
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package foo {
|
||||||
|
public fun bar(/*0*/ x: kotlin.Int): kotlin.Int
|
||||||
|
|
||||||
|
package foo.bar {
|
||||||
|
public val x: kotlin.Int = 42
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// FILE: foo.kt
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
<!JS_NAME_CLASH!>fun bar() = 23<!>
|
||||||
|
|
||||||
|
// FILE: foobar.kt
|
||||||
|
|
||||||
|
package foo.bar
|
||||||
|
|
||||||
|
val x = 42
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package foo {
|
||||||
|
public fun bar(): kotlin.Int
|
||||||
|
|
||||||
|
package foo.bar {
|
||||||
|
public val x: kotlin.Int = 42
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
// FILE: foo.kt
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
private fun bar() = 23
|
||||||
|
|
||||||
|
private val bar = 42
|
||||||
|
|
||||||
|
// FILE: foobar.kt
|
||||||
|
|
||||||
|
package foo.bar
|
||||||
|
|
||||||
|
val x = 42
|
||||||
Vendored
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package foo {
|
||||||
|
private val bar: kotlin.Int = 42
|
||||||
|
private fun bar(): kotlin.Int
|
||||||
|
|
||||||
|
package foo.bar {
|
||||||
|
public val x: kotlin.Int = 42
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// FILE: foo.kt
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
<!JS_NAME_CLASH!>val bar = 23<!>
|
||||||
|
|
||||||
|
// FILE: foobar.kt
|
||||||
|
|
||||||
|
package foo.bar
|
||||||
|
|
||||||
|
val x = 42
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package foo {
|
||||||
|
public val bar: kotlin.Int = 23
|
||||||
|
|
||||||
|
package foo.bar {
|
||||||
|
public val x: kotlin.Int = 42
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
open class Super {
|
||||||
|
<!JS_NAME_CLASH!>val foo = 23<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
class Sub : Super() {
|
||||||
|
<!JS_NAME_CLASH!>fun foo() = 42<!>
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package foo {
|
||||||
|
|
||||||
|
public final class Sub : foo.Super {
|
||||||
|
public constructor Sub()
|
||||||
|
public final override /*1*/ /*fake_override*/ val foo: kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public final fun foo(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public open class Super {
|
||||||
|
public constructor Super()
|
||||||
|
public final val foo: kotlin.Int = 23
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
@native fun bar() = 23
|
||||||
|
|
||||||
|
val bar = 32
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package foo {
|
||||||
|
public val bar: kotlin.Int = 32
|
||||||
|
@kotlin.js.native() public fun bar(): kotlin.Int
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
<!JS_NAME_CLASH!>fun bar() = 23<!>
|
||||||
|
|
||||||
|
<!JS_NAME_CLASH!>val bar = 32<!>
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package foo {
|
||||||
|
public val bar: kotlin.Int = 32
|
||||||
|
public fun bar(): kotlin.Int
|
||||||
|
}
|
||||||
+69
@@ -287,6 +287,75 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Name extends AbstractDiagnosticsTestWithJsStdLib {
|
||||||
|
public void testAllFilesPresentInName() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithJsStdLib/name"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classLevelMethodAndProperty.kt")
|
||||||
|
public void testClassLevelMethodAndProperty() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/classLevelMethodAndProperty.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("extensionPropertiesWithDifferentReceiversDoNotClash.kt")
|
||||||
|
public void testExtensionPropertiesWithDifferentReceiversDoNotClash() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/extensionPropertiesWithDifferentReceiversDoNotClash.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("methodAndPrivatePropertyDoNotClash.kt")
|
||||||
|
public void testMethodAndPrivatePropertyDoNotClash() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/methodAndPrivatePropertyDoNotClash.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("packageAndMangledMethodDoNotClash.kt")
|
||||||
|
public void testPackageAndMangledMethodDoNotClash() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/packageAndMangledMethodDoNotClash.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("packageAndMethod.kt")
|
||||||
|
public void testPackageAndMethod() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/packageAndMethod.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("packageAndPrivateDeclarationsDoNotClash.kt")
|
||||||
|
public void testPackageAndPrivateDeclarationsDoNotClash() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/packageAndPrivateDeclarationsDoNotClash.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("packageAndProperty.kt")
|
||||||
|
public void testPackageAndProperty() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/packageAndProperty.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertyAndMethodInSubclass.kt")
|
||||||
|
public void testPropertyAndMethodInSubclass() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/propertyAndMethodInSubclass.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertyAndNativeMethodDoNotClash.kt")
|
||||||
|
public void testPropertyAndNativeMethodDoNotClash() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/propertyAndNativeMethodDoNotClash.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("topLevelMethodAndProperty.kt")
|
||||||
|
public void testTopLevelMethodAndProperty() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/topLevelMethodAndProperty.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native")
|
@TestMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -24,9 +24,10 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject
|
import org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class FQNGenerator {
|
class FQNGenerator {
|
||||||
private val cache = mutableMapOf<DeclarationDescriptor, FQNPart>()
|
private val cache: MutableMap<DeclarationDescriptor, FQNPart> = WeakHashMap()
|
||||||
|
|
||||||
fun generate(descriptor: DeclarationDescriptor) = cache.getOrPut(descriptor) { generateCacheMiss(descriptor.original) }
|
fun generate(descriptor: DeclarationDescriptor) = cache.getOrPut(descriptor) { generateCacheMiss(descriptor.original) }
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ package org.jetbrains.kotlin.js.resolve
|
|||||||
import org.jetbrains.kotlin.container.StorageComponentContainer
|
import org.jetbrains.kotlin.container.StorageComponentContainer
|
||||||
import org.jetbrains.kotlin.container.useImpl
|
import org.jetbrains.kotlin.container.useImpl
|
||||||
import org.jetbrains.kotlin.container.useInstance
|
import org.jetbrains.kotlin.container.useInstance
|
||||||
|
import org.jetbrains.kotlin.js.naming.FQNGenerator
|
||||||
import org.jetbrains.kotlin.js.resolve.diagnostics.JsCallChecker
|
import org.jetbrains.kotlin.js.resolve.diagnostics.JsCallChecker
|
||||||
|
import org.jetbrains.kotlin.js.resolve.diagnostics.JsNameChecker
|
||||||
import org.jetbrains.kotlin.js.resolve.diagnostics.NativeInnerClassChecker
|
import org.jetbrains.kotlin.js.resolve.diagnostics.NativeInnerClassChecker
|
||||||
import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap
|
import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap
|
||||||
import org.jetbrains.kotlin.resolve.IdentifierChecker
|
import org.jetbrains.kotlin.resolve.IdentifierChecker
|
||||||
@@ -46,5 +48,6 @@ object JsPlatformConfigurator : PlatformConfigurator(
|
|||||||
container.useInstance(SyntheticScopes.Empty)
|
container.useInstance(SyntheticScopes.Empty)
|
||||||
container.useInstance(SyntheticConstructorsProvider.Empty)
|
container.useInstance(SyntheticConstructorsProvider.Empty)
|
||||||
container.useInstance(JsTypeSpecificityComparator)
|
container.useInstance(JsTypeSpecificityComparator)
|
||||||
|
container.useInstance(JsNameChecker())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -37,6 +37,8 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
|
|||||||
put(ErrorsJs.REFERENCE_TO_BUILTIN_MEMBERS_NOT_SUPPORTED, "Callable references for builtin members are not supported yet: ''{0}''", RenderFirstLineOfElementText)
|
put(ErrorsJs.REFERENCE_TO_BUILTIN_MEMBERS_NOT_SUPPORTED, "Callable references for builtin members are not supported yet: ''{0}''", RenderFirstLineOfElementText)
|
||||||
put(ErrorsJs.JSCODE_NO_JAVASCRIPT_PRODUCED, "Argument must be non-empty JavaScript code")
|
put(ErrorsJs.JSCODE_NO_JAVASCRIPT_PRODUCED, "Argument must be non-empty JavaScript code")
|
||||||
put(ErrorsJs.NATIVE_INNER_CLASS_PROHIBITED, "Native inner classes are prohibited")
|
put(ErrorsJs.NATIVE_INNER_CLASS_PROHIBITED, "Native inner classes are prohibited")
|
||||||
|
put(ErrorsJs.JS_NAME_CLASH, "JavaScript name ({0}) generated for this declaration clashes with another declaration: {1}",
|
||||||
|
Renderers.STRING, Renderers.COMPACT)
|
||||||
|
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.resolve.diagnostics;
|
package org.jetbrains.kotlin.js.resolve.diagnostics;
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1;
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1;
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2;
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2;
|
||||||
@@ -43,6 +44,7 @@ public interface ErrorsJs {
|
|||||||
DiagnosticFactory1<KtElement, KtElement> REFERENCE_TO_BUILTIN_MEMBERS_NOT_SUPPORTED = DiagnosticFactory1.create(ERROR, DEFAULT);
|
DiagnosticFactory1<KtElement, KtElement> REFERENCE_TO_BUILTIN_MEMBERS_NOT_SUPPORTED = DiagnosticFactory1.create(ERROR, DEFAULT);
|
||||||
DiagnosticFactory0<KtExpression> JSCODE_NO_JAVASCRIPT_PRODUCED = DiagnosticFactory0.create(ERROR, DEFAULT);
|
DiagnosticFactory0<KtExpression> JSCODE_NO_JAVASCRIPT_PRODUCED = DiagnosticFactory0.create(ERROR, DEFAULT);
|
||||||
DiagnosticFactory0<KtExpression> NATIVE_INNER_CLASS_PROHIBITED = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtExpression> NATIVE_INNER_CLASS_PROHIBITED = DiagnosticFactory0.create(ERROR);
|
||||||
|
DiagnosticFactory2<KtElement, String, DeclarationDescriptor> JS_NAME_CLASH = DiagnosticFactory2.create(ERROR);
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
Object _initializer = new Object() {
|
Object _initializer = new Object() {
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 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 com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||||
|
import org.jetbrains.kotlin.js.naming.FQNGenerator
|
||||||
|
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.DeclarationChecker
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
|
|
||||||
|
class JsNameChecker : DeclarationChecker {
|
||||||
|
private val fqnGenerator = FQNGenerator()
|
||||||
|
private val scopes = mutableMapOf<DeclarationDescriptor, MutableMap<String, DeclarationDescriptor>>()
|
||||||
|
private val clashedDescriptors = mutableSetOf<DeclarationDescriptor>()
|
||||||
|
|
||||||
|
override fun check(
|
||||||
|
declaration: KtDeclaration,
|
||||||
|
descriptor: DeclarationDescriptor,
|
||||||
|
diagnosticHolder: DiagnosticSink,
|
||||||
|
bindingContext: BindingContext
|
||||||
|
) {
|
||||||
|
checkDescriptor(descriptor, declaration, diagnosticHolder)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkDescriptor(descriptor: DeclarationDescriptor, declaration: KtDeclaration, diagnosticHolder: DiagnosticSink) {
|
||||||
|
val fqn = fqnGenerator.generate(descriptor)
|
||||||
|
if (fqn.shared && fqn.scope is ClassOrPackageFragmentDescriptor && isOpaque(fqn.descriptor)) {
|
||||||
|
val scope = getScope(fqn.scope)
|
||||||
|
val name = fqn.names.last()
|
||||||
|
val existing = scope[name]
|
||||||
|
if (existing != null && existing != fqn.descriptor) {
|
||||||
|
diagnosticHolder.report(ErrorsJs.JS_NAME_CLASH.on(declaration, name, existing))
|
||||||
|
val existingDeclaration = findPsi(existing) ?: declaration
|
||||||
|
if (clashedDescriptors.add(existing) && existingDeclaration is KtDeclaration && existingDeclaration != declaration) {
|
||||||
|
diagnosticHolder.report(ErrorsJs.JS_NAME_CLASH.on(existingDeclaration, name, descriptor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findPsi(descriptor: DeclarationDescriptor): PsiElement? {
|
||||||
|
val psi = (descriptor as? DeclarationDescriptorWithSource)?.source?.getPsi()
|
||||||
|
return if (psi == null && descriptor is CallableMemberDescriptor &&
|
||||||
|
descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE
|
||||||
|
) {
|
||||||
|
descriptor.overriddenDescriptors.mapNotNull { findPsi(it) }.firstOrNull()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
psi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getScope(descriptor: DeclarationDescriptor) = scopes.getOrPut(descriptor) {
|
||||||
|
val scope = mutableMapOf<String, DeclarationDescriptor>()
|
||||||
|
when (descriptor) {
|
||||||
|
is PackageFragmentDescriptor -> {
|
||||||
|
collect(descriptor.getMemberScope(), scope)
|
||||||
|
val module = DescriptorUtils.getContainingModule(descriptor)
|
||||||
|
module.getSubPackagesOf(descriptor.fqName) { true }
|
||||||
|
.flatMap { module.getPackage(it).fragments }
|
||||||
|
.forEach { collect(it, scope) }
|
||||||
|
}
|
||||||
|
is ClassDescriptor -> collect(descriptor.defaultType.memberScope, scope)
|
||||||
|
}
|
||||||
|
scope
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun collect(scope: MemberScope, target: MutableMap<String, DeclarationDescriptor>) {
|
||||||
|
for (descriptor in scope.getContributedDescriptors()) {
|
||||||
|
val fqn = fqnGenerator.generate(descriptor)
|
||||||
|
if (fqn.shared && isOpaque(fqn.descriptor)) {
|
||||||
|
target[fqn.names.last()] = fqn.descriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun collect(descriptor: DeclarationDescriptor, target: MutableMap<String, DeclarationDescriptor>) {
|
||||||
|
val fqn = fqnGenerator.generate(descriptor)
|
||||||
|
if (fqn.shared && isOpaque(fqn.descriptor)) {
|
||||||
|
target[fqn.names.last()] = fqn.descriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isOpaque(descriptor: DeclarationDescriptor) =
|
||||||
|
!AnnotationsUtils.isNativeObject(descriptor) && !AnnotationsUtils.isLibraryObject(descriptor)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user