All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.jet.codegen.state.BuilderFactoryForDuplicateSignatureDiagnostics.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * 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.state

import com.intellij.psi.PsiElement
import com.intellij.util.containers.MultiMap
import org.jetbrains.jet.codegen.ClassBuilderFactory
import org.jetbrains.jet.codegen.SignatureCollectingClassBuilderFactory
import org.jetbrains.jet.lang.descriptors.*
import org.jetbrains.jet.lang.diagnostics.DiagnosticHolder
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.resolve.BindingContextUtils
import org.jetbrains.jet.lang.resolve.java.diagnostics.*
import java.util.*
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.DELEGATION
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.FAKE_OVERRIDE
import org.jetbrains.jet.utils.addIfNotNull
import org.jetbrains.jet.codegen.ClassBuilderMode
import org.jetbrains.jet.lang.resolve.java.descriptor.SamAdapterDescriptor
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils

class BuilderFactoryForDuplicateSignatureDiagnostics(
        builderFactory: ClassBuilderFactory,
        bindingContext: BindingContext,
        private val diagnostics: DiagnosticHolder
) : SignatureCollectingClassBuilderFactory(builderFactory) {

    // Avoid errors when some classes are not loaded for some reason
    private val typeMapper = JetTypeMapper(bindingContext, ClassBuilderMode.LIGHT_CLASSES)

    override fun handleClashingSignatures(data: ConflictingJvmDeclarationsData) {
        val allDelegatedToTraitImpls = data.signatureOrigins.all { it.originKind == JvmDeclarationOriginKind.DELEGATION_TO_TRAIT_IMPL }

        val elements = LinkedHashSet()
        for (origin in data.signatureOrigins) {
            var element = origin.element
            if (element == null || allDelegatedToTraitImpls) {
                element = data.classOrigin.element
            }
            elements.addIfNotNull(element)
        }

        for (element in elements) {
            diagnostics.report(ErrorsJvm.CONFLICTING_JVM_DECLARATIONS.on(element, data))
        }
    }

    override fun onClassDone(classOrigin: JvmDeclarationOrigin, classInternalName: String?, hasDuplicateSignatures: Boolean) {
        val descriptor = classOrigin.descriptor
        if (descriptor !is ClassDescriptor) return

        val groupedBySignature = groupDescriptorsBySignature(descriptor)

        @signatures
        for ((rawSignature, members) in groupedBySignature.entrySet()!!) {
            if (members.size() <= 1) continue

            var memberElement: PsiElement? = null
            var nonFakeCount = 0
            for (member in members) {
                if (member.getKind() != FAKE_OVERRIDE) {
                    nonFakeCount++
                    // If there's more than one real element, the clashing signature is already reported.
                    // Only clashes between fake overrides are interesting here
                    if (nonFakeCount > 1) continue@signatures

                    if (member.getKind() != DELEGATION) {
                        // Delegates don't have declarations in the code
                        memberElement = DescriptorToSourceUtils.callableDescriptorToDeclaration(member)
                        if (memberElement == null && member is PropertyAccessorDescriptor) {
                            memberElement = DescriptorToSourceUtils.callableDescriptorToDeclaration(member.getCorrespondingProperty())
                        }
                    }
                }
            }

            val elementToReportOn = memberElement ?: classOrigin.element
            if (elementToReportOn == null) return // TODO: it'd be better to report this error without any element at all

            val data = ConflictingJvmDeclarationsData(classInternalName, classOrigin, rawSignature, members.map { OtherOrigin(it) })
            diagnostics.report(ErrorsJvm.ACCIDENTAL_OVERRIDE.on(elementToReportOn, data))
        }
    }

    private fun groupDescriptorsBySignature(descriptor: ClassDescriptor): MultiMap {
        val groupedBySignature = MultiMap.create()

        fun processMember(member: DeclarationDescriptor?) {
            // a member of super is not visible: no override
            if (member is DeclarationDescriptorWithVisibility && member.getVisibility() == Visibilities.INVISIBLE_FAKE) return
            // if a signature clashes with a SAM-adapter or something like that, there's no harm
            if (member is CallableMemberDescriptor && isOrOverridesSamAdapter(member)) return

            if (member is PropertyDescriptor) {
                processMember(member.getGetter())
                processMember(member.getSetter())
            }
            else if (member is FunctionDescriptor) {
                val methodSignature = typeMapper.mapSignature(member)
                val rawSignature = RawSignature(
                        methodSignature.getAsmMethod().getName()!!, methodSignature.getAsmMethod().getDescriptor()!!, MemberKind.METHOD)
                groupedBySignature.putValue(rawSignature, member)
            }
        }

        for (member in descriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
            processMember(member)
        }

        return groupedBySignature
    }

    public fun isOrOverridesSamAdapter(descriptor: CallableMemberDescriptor): Boolean {
        if (descriptor is SamAdapterDescriptor<*>) return true

        return descriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE
                && descriptor.getOverriddenDescriptors().all { isOrOverridesSamAdapter(it) }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy