Basic version of CONFLICTING_PLATFORM_DECLARATIONS diagnostic

#KT-1 In Progress
This commit is contained in:
Andrey Breslav
2014-05-22 13:27:58 +04:00
parent eb31be2871
commit f4f1dd8f8b
4 changed files with 135 additions and 1 deletions
@@ -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<JvmDeclarationOrigin>
)
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<RawSignature, JvmDeclarationOrigin>()
override fun defineClass(origin: PsiElement?, version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<out String>) {
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<out String>?): 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()
}
}
}
@@ -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<? extends JvmDeclarationOrigin> origins
) {
Collection<PsiElement> elements = new LinkedHashSet<PsiElement>();
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()));
}
}
}
}
@@ -203,6 +203,7 @@ public interface Errors {
DiagnosticFactory0<JetNamedDeclaration> PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE = DiagnosticFactory0.create(ERROR, NAMED_ELEMENT);
DiagnosticFactory2<JetDeclaration, CallableMemberDescriptor, String> CONFLICTING_OVERLOADS = DiagnosticFactory2.create(ERROR, DECLARATION);
DiagnosticFactory1<PsiElement, String> CONFLICTING_PLATFORM_DECLARATIONS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<JetNamedDeclaration> NON_FINAL_MEMBER_IN_FINAL_CLASS = DiagnosticFactory0.create(WARNING, modifierSetPosition(
JetTokens.OPEN_KEYWORD));
@@ -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<JetType>() {
@NotNull