From f4f1dd8f8b6b3dddbd09ceac0259e2d735a01f76 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 22 May 2014 13:27:58 +0400 Subject: [PATCH] Basic version of CONFLICTING_PLATFORM_DECLARATIONS diagnostic #KT-1 In Progress --- .../SignatureCollectingClassBuilderFactory.kt | 95 +++++++++++++++++++ .../jet/codegen/state/GenerationState.java | 39 +++++++- .../jet/lang/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/SignatureCollectingClassBuilderFactory.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/SignatureCollectingClassBuilderFactory.kt b/compiler/backend/src/org/jetbrains/jet/codegen/SignatureCollectingClassBuilderFactory.kt new file mode 100644 index 00000000000..676a78fe429 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/SignatureCollectingClassBuilderFactory.kt @@ -0,0 +1,95 @@ +/* + * Copyright 2010-2014 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.jet.codegen + +import com.intellij.psi.PsiElement +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor +import org.jetbrains.org.objectweb.asm.FieldVisitor +import org.jetbrains.org.objectweb.asm.MethodVisitor +import com.intellij.util.containers.MultiMap + +public enum class MemberKind { FIELD; METHOD } +public data class RawSignature(val name: String, val desc: String, val field: MemberKind) + +public class JvmDeclarationOrigin( + val element: PsiElement?, + val descriptor: DeclarationDescriptor? +) + +public val NO_ORIGIN: JvmDeclarationOrigin = JvmDeclarationOrigin(null, null) + +public abstract class SignatureCollectingClassBuilderFactory( + private val delegate: ClassBuilderFactory + +) : ClassBuilderFactory by delegate { + + protected abstract fun handleClashingSignatures( + classInternalName: String?, + classOrigin: JvmDeclarationOrigin, + signature: RawSignature, + origins: Collection + ) + + override fun newClassBuilder(forElement: PsiElement?, forDescriptor: DeclarationDescriptor?): SignatureCollectingClassBuilder { + return SignatureCollectingClassBuilder(JvmDeclarationOrigin(forElement, forDescriptor), delegate.newClassBuilder(forElement, forDescriptor)) + } + + public override fun asBytes(builder: ClassBuilder?): ByteArray? { + return delegate.asBytes((builder as SignatureCollectingClassBuilder)._delegate) + } + + private inner class SignatureCollectingClassBuilder( + private val classCreatedFor: JvmDeclarationOrigin, + internal val _delegate: ClassBuilder + ) : DelegatingClassBuilder() { + + override fun getDelegate() = _delegate + + private var classInternalName: String? = null + + private val signatures = MultiMap() + + override fun defineClass(origin: PsiElement?, version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array) { + classInternalName = name + super.defineClass(origin, version, access, name, signature, superName, interfaces) + } + + override fun newField(origin: PsiElement?, descriptor: DeclarationDescriptor?, access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor { + signatures.putValue(RawSignature(name, desc, MemberKind.FIELD), JvmDeclarationOrigin(origin, descriptor)) + return super.newField(origin, descriptor, access, name, desc, signature, value) + } + + override fun newMethod(origin: PsiElement?, descriptor: DeclarationDescriptor?, access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor { + signatures.putValue(RawSignature(name, desc, MemberKind.METHOD), JvmDeclarationOrigin(origin, descriptor)) + return super.newMethod(origin, descriptor, access, name, desc, signature, exceptions) + } + + override fun done() { + for ((signature, elementsAndDescriptors) in signatures.entrySet()!!) { + if (elementsAndDescriptors.size == 1) continue // no clash + handleClashingSignatures( + classInternalName, + classCreatedFor, + signature, + elementsAndDescriptors + ) + } + super.done() + } + + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/state/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/state/GenerationState.java index 5f50f3bf541..eba09832331 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/state/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/state/GenerationState.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.codegen.state; import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.codegen.*; @@ -26,6 +27,7 @@ import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; import org.jetbrains.jet.lang.descriptors.ScriptDescriptor; import org.jetbrains.jet.lang.diagnostics.DiagnosticHolder; +import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.JetClassOrObject; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.reflect.ReflectionTypes; @@ -36,6 +38,7 @@ import org.jetbrains.jet.lang.resolve.name.FqName; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; public class GenerationState { @@ -152,7 +155,7 @@ public class GenerationState { this.typeMapper = new JetTypeMapper(this.bindingContext, classBuilderMode); this.intrinsics = new IntrinsicMethods(); - this.classFileFactory = new ClassFileFactory(this, builderFactory); + this.classFileFactory = new ClassFileFactory(this, new BuilderfactoryForDuplicateSignatureDiagnostics(builderFactory, diagnostics)); this.generateNotNullAssertions = generateNotNullAssertions; this.generateNotNullParamAssertions = generateNotNullParamAssertions; @@ -273,4 +276,38 @@ public class GenerationState { public String getModuleId() { return moduleId; } + + private static class BuilderfactoryForDuplicateSignatureDiagnostics extends SignatureCollectingClassBuilderFactory { + + private final DiagnosticHolder diagnostics; + + public BuilderfactoryForDuplicateSignatureDiagnostics(@NotNull ClassBuilderFactory builderFactory, DiagnosticHolder diagnostics) { + super(builderFactory); + this.diagnostics = diagnostics; + } + + @Override + protected void handleClashingSignatures( + @Nullable String classInternalName, + @NotNull JvmDeclarationOrigin classOrigin, + @NotNull RawSignature signature, + @NotNull Collection origins + ) { + Collection elements = new LinkedHashSet(); + + for (JvmDeclarationOrigin origin : origins) { + PsiElement element = origin.getElement(); + if (element == null) { + element = classOrigin.getElement(); + } + if (element != null) { + elements.add(element); + } + } + + for (PsiElement element : elements) { + diagnostics.report(Errors.CONFLICTING_PLATFORM_DECLARATIONS.on(element, signature.getName() + signature.getDesc())); + } + } + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index e307cc599d8..fb182581833 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -203,6 +203,7 @@ public interface Errors { DiagnosticFactory0 PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE = DiagnosticFactory0.create(ERROR, NAMED_ELEMENT); DiagnosticFactory2 CONFLICTING_OVERLOADS = DiagnosticFactory2.create(ERROR, DECLARATION); + DiagnosticFactory1 CONFLICTING_PLATFORM_DECLARATIONS = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 NON_FINAL_MEMBER_IN_FINAL_CLASS = DiagnosticFactory0.create(WARNING, modifierSetPosition( JetTokens.OPEN_KEYWORD)); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index e9906b350e8..b57e024328e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -392,6 +392,7 @@ public class DefaultErrorMessages { RENDER_CLASS_OR_OBJECT, FQ_NAMES_IN_TYPES); MAP.put(CONFLICTING_OVERLOADS, "''{0}'' is already defined in {1}", COMPACT_WITH_MODIFIERS, STRING); + MAP.put(CONFLICTING_PLATFORM_DECLARATIONS, "Platform declaration clash: ''{0}''", STRING); MAP.put(FUNCTION_EXPECTED, "Expression ''{0}''{1} cannot be invoked as a function. The function 'invoke()' is not found", ELEMENT_TEXT, new Renderer() { @NotNull