KT-13961 REDECLARATION not reported on private-in-file 'foo' vs public 'foo' in different file
Private-in-file declarations conflict with public overload-equivalent declarations in other files in the same package. Move functions for grouping possible redeclarations to OverloadResolver (since they are used only there). Refactor redeclarations / conflicting overloads reporting.
This commit is contained in:
@@ -65,7 +65,10 @@ public interface Errors {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DiagnosticFactory1<PsiElement, String> REDECLARATION = DiagnosticFactory1.create(ERROR, FOR_REDECLARATION);
|
||||
DiagnosticFactory1<PsiElement, Collection<DeclarationDescriptor>> REDECLARATION =
|
||||
DiagnosticFactory1.create(ERROR, FOR_REDECLARATION);
|
||||
DiagnosticFactory1<PsiElement, String> PACKAGE_OR_CLASSIFIER_REDECLARATION =
|
||||
DiagnosticFactory1.create(ERROR, FOR_REDECLARATION);
|
||||
|
||||
DiagnosticFactory1<KtReferenceExpression, KtReferenceExpression> UNRESOLVED_REFERENCE =
|
||||
DiagnosticFactory1.create(ERROR, FOR_UNRESOLVED_REFERENCE);
|
||||
@@ -315,8 +318,8 @@ public interface Errors {
|
||||
|
||||
// Members
|
||||
|
||||
DiagnosticFactory2<PsiElement, CallableMemberDescriptor, DeclarationDescriptor> CONFLICTING_OVERLOADS =
|
||||
DiagnosticFactory2.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
DiagnosticFactory1<PsiElement, Collection<DeclarationDescriptor>> CONFLICTING_OVERLOADS =
|
||||
DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
|
||||
DiagnosticFactory0<KtNamedDeclaration> NON_FINAL_MEMBER_IN_FINAL_CLASS = DiagnosticFactory0.create(WARNING, modifierSetPosition(
|
||||
KtTokens.OPEN_KEYWORD));
|
||||
|
||||
@@ -17,14 +17,16 @@
|
||||
package org.jetbrains.kotlin.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getEffectiveExpectedType
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CallPosition
|
||||
@@ -139,3 +141,22 @@ fun ResolutionContext<*>.reportTypeMismatchDueToScalaLikeNamedFunctionSyntax(
|
||||
private fun isScalaLikeEqualsBlock(expression: KtElement): Boolean =
|
||||
expression is KtLambdaExpression &&
|
||||
expression.parent.let { it is KtNamedFunction && it.equalsToken != null }
|
||||
|
||||
inline fun reportOnDeclaration(trace: BindingTrace, descriptor: DeclarationDescriptor, what: (PsiElement) -> Diagnostic) {
|
||||
DescriptorToSourceUtils.descriptorToDeclaration(descriptor)?.let { psiElement ->
|
||||
trace.report(what(psiElement))
|
||||
}
|
||||
}
|
||||
inline fun reportOnDeclarationOrFail(trace: BindingTrace, descriptor: DeclarationDescriptor, what: (PsiElement) -> Diagnostic) {
|
||||
DescriptorToSourceUtils.descriptorToDeclaration(descriptor)?.let { psiElement ->
|
||||
trace.report(what(psiElement))
|
||||
} ?: throw AssertionError("No declaration for $descriptor")
|
||||
}
|
||||
|
||||
inline fun <reified T : KtDeclaration> reportOnDeclarationAs(trace: BindingTrace, descriptor: DeclarationDescriptor, what: (T) -> Diagnostic) {
|
||||
DescriptorToSourceUtils.descriptorToDeclaration(descriptor)?.let { psiElement ->
|
||||
(psiElement as? T)?.let {
|
||||
trace.report(what(it))
|
||||
} ?: throw AssertionError("Declaration for $descriptor is expected to be ${T::class.simpleName}, actual declaration: $psiElement")
|
||||
} ?: throw AssertionError("No declaration for $descriptor")
|
||||
}
|
||||
+4
-3
@@ -110,7 +110,9 @@ public class DefaultErrorMessages {
|
||||
|
||||
MAP.put(INACCESSIBLE_TYPE, "Type {0} is inaccessible in this context due to: {1}", RENDER_TYPE, RENDER_COLLECTION_OF_TYPES);
|
||||
|
||||
MAP.put(REDECLARATION, "Redeclaration: {0}", STRING);
|
||||
MAP.put(REDECLARATION, "Conflicting declarations: {0}", commaSeparated(COMPACT_WITH_MODIFIERS));
|
||||
MAP.put(PACKAGE_OR_CLASSIFIER_REDECLARATION, "Redeclaration: {0}", STRING);
|
||||
|
||||
MAP.put(NAME_SHADOWING, "Name shadowed: {0}", STRING);
|
||||
MAP.put(ACCESSOR_PARAMETER_NAME_SHADOWING, "Accessor parameter name 'field' is shadowed by backing field variable");
|
||||
|
||||
@@ -631,8 +633,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED, "{0} must override {1} because it inherits multiple interface methods of it",
|
||||
RENDER_CLASS_OR_OBJECT, FQ_NAMES_IN_TYPES);
|
||||
|
||||
MAP.put(CONFLICTING_OVERLOADS, "''{0}'' conflicts with another declaration in {1}", COMPACT_WITH_MODIFIERS,
|
||||
DECLARATION_NAME_WITH_KIND);
|
||||
MAP.put(CONFLICTING_OVERLOADS, "Conflicting overloads: {0}", commaSeparated(FQ_NAMES_IN_TYPES));
|
||||
|
||||
MAP.put(FUNCTION_EXPECTED, "Expression ''{0}''{1} cannot be invoked as a function. " +
|
||||
"The function ''" + OperatorNameConventions.INVOKE.asString() + "()'' is not found",
|
||||
|
||||
@@ -18,14 +18,13 @@ package org.jetbrains.kotlin.resolve
|
||||
|
||||
import com.google.common.collect.HashMultimap
|
||||
import com.google.common.collect.Multimap
|
||||
import com.google.common.collect.Sets
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.REDECLARATION
|
||||
import org.jetbrains.kotlin.diagnostics.reportOnDeclaration
|
||||
import org.jetbrains.kotlin.diagnostics.reportOnDeclarationOrFail
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -60,40 +59,19 @@ class DeclarationResolver(
|
||||
}
|
||||
}
|
||||
|
||||
reportRedeclarations(descriptorMap)
|
||||
reportRedeclarationsWithClassifiers(descriptorMap)
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportRedeclarations(descriptorMap: Multimap<Name, DeclarationDescriptor>) {
|
||||
val redeclarations = Sets.newHashSet<Pair<PsiElement, Name>>()
|
||||
private fun reportRedeclarationsWithClassifiers(descriptorMap: Multimap<Name, DeclarationDescriptor>) {
|
||||
for (name in descriptorMap.keySet()) {
|
||||
val descriptors = descriptorMap[name]
|
||||
if (descriptors.size <= 1) {
|
||||
continue
|
||||
}
|
||||
// We mustn't compare PropertyDescriptor with PropertyDescriptor because we do this at OverloadResolver
|
||||
for (descriptor in descriptors) {
|
||||
if (descriptor is ClassifierDescriptor) {
|
||||
for (descriptor2 in descriptors) {
|
||||
if (descriptor === descriptor2) {
|
||||
continue
|
||||
}
|
||||
|
||||
DescriptorToSourceUtils.getSourceFromDescriptor(descriptor)?.let {
|
||||
redeclarations.add(Pair(it, descriptor.getName()))
|
||||
}
|
||||
if (descriptor2 is PropertyDescriptor) {
|
||||
DescriptorToSourceUtils.descriptorToDeclaration(descriptor2)?.let {
|
||||
redeclarations.add(Pair(it, descriptor2.getName()))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (descriptors.size > 1 && descriptors.any { it is ClassifierDescriptor }) {
|
||||
for (descriptor in descriptors) {
|
||||
reportOnDeclaration(trace, descriptor) { REDECLARATION.on(it, descriptors) }
|
||||
}
|
||||
}
|
||||
}
|
||||
for ((first, second) in redeclarations) {
|
||||
trace.report(REDECLARATION.on(first, second.asString()))
|
||||
}
|
||||
}
|
||||
|
||||
fun checkRedeclarationsInPackages(topLevelDescriptorProvider: TopLevelDescriptorProvider, topLevelFqNames: Multimap<FqName, KtElement>) {
|
||||
@@ -107,7 +85,7 @@ class DeclarationResolver(
|
||||
val reportAt =
|
||||
if (declarationOrPackageDirective is KtPackageDirective) declarationOrPackageDirective.getNameIdentifier()
|
||||
else declarationOrPackageDirective
|
||||
trace.report(Errors.REDECLARATION.on(reportAt!!, fqName.shortName().asString()))
|
||||
trace.report(Errors.PACKAGE_OR_CLASSIFIER_REDECLARATION.on(reportAt!!, fqName.shortName().asString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import java.util.*
|
||||
|
||||
class OverloadChecker(val specificityComparator: TypeSpecificityComparator) {
|
||||
/**
|
||||
@@ -98,118 +99,4 @@ class OverloadChecker(val specificityComparator: TypeSpecificityComparator) {
|
||||
error("Unexpected declaration kind: $a")
|
||||
}
|
||||
|
||||
fun groupModulePackageMembersByFqName(
|
||||
c: BodiesResolveContext,
|
||||
overloadFilter: OverloadFilter
|
||||
): MultiMap<FqNameUnsafe, DeclarationDescriptorNonRoot> {
|
||||
val packageMembersByName = MultiMap<FqNameUnsafe, DeclarationDescriptorNonRoot>()
|
||||
|
||||
collectModulePackageMembersWithSameName(
|
||||
packageMembersByName,
|
||||
c.functions.values + c.declaredClasses.values + c.typeAliases.values,
|
||||
overloadFilter
|
||||
) {
|
||||
scope, name ->
|
||||
val functions = scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS)
|
||||
val classifier = scope.getContributedClassifier(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS)
|
||||
when (classifier) {
|
||||
is ClassDescriptor ->
|
||||
if (!classifier.kind.isSingleton)
|
||||
functions + classifier.constructors
|
||||
else
|
||||
functions
|
||||
is TypeAliasDescriptor ->
|
||||
functions + classifier.getTypeAliasConstructors()
|
||||
else ->
|
||||
functions
|
||||
}
|
||||
}
|
||||
|
||||
collectModulePackageMembersWithSameName(packageMembersByName, c.properties.values, overloadFilter) {
|
||||
scope, name ->
|
||||
val variables = scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS)
|
||||
val classifier = scope.getContributedClassifier(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS)
|
||||
variables + classifier.singletonOrEmptyList()
|
||||
}
|
||||
|
||||
return packageMembersByName
|
||||
}
|
||||
|
||||
private inline fun collectModulePackageMembersWithSameName(
|
||||
packageMembersByName: MultiMap<FqNameUnsafe, DeclarationDescriptorNonRoot>,
|
||||
interestingDescriptors: Collection<DeclarationDescriptor>,
|
||||
overloadFilter: OverloadFilter,
|
||||
getMembersByName: (MemberScope, Name) -> Collection<DeclarationDescriptorNonRoot>
|
||||
) {
|
||||
val observedFQNs = hashSetOf<FqNameUnsafe>()
|
||||
for (descriptor in interestingDescriptors) {
|
||||
if (descriptor.containingDeclaration !is PackageFragmentDescriptor) continue
|
||||
|
||||
val descriptorFQN = DescriptorUtils.getFqName(descriptor)
|
||||
if (observedFQNs.contains(descriptorFQN)) continue
|
||||
observedFQNs.add(descriptorFQN)
|
||||
|
||||
val packageMembersWithSameName = getModulePackageMembersWithSameName(descriptor, overloadFilter, getMembersByName)
|
||||
packageMembersByName.putValues(descriptorFQN, packageMembersWithSameName)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun getModulePackageMembersWithSameName(
|
||||
descriptor: DeclarationDescriptor,
|
||||
overloadFilter: OverloadFilter,
|
||||
getMembersByName: (MemberScope, Name) -> Collection<DeclarationDescriptorNonRoot>
|
||||
): Collection<DeclarationDescriptorNonRoot> {
|
||||
val containingPackage = descriptor.containingDeclaration
|
||||
if (containingPackage !is PackageFragmentDescriptor) {
|
||||
throw AssertionError("$descriptor is not a top-level package member")
|
||||
}
|
||||
|
||||
val containingModule = DescriptorUtils.getContainingModuleOrNull(descriptor) ?:
|
||||
return when (descriptor) {
|
||||
is CallableMemberDescriptor -> listOf(descriptor)
|
||||
is ClassDescriptor -> descriptor.constructors
|
||||
else -> throw AssertionError("Unexpected descriptor kind: $descriptor")
|
||||
}
|
||||
|
||||
val containingPackageScope = containingModule.getPackage(containingPackage.fqName).memberScope
|
||||
val possibleOverloads =
|
||||
getMembersByName(containingPackageScope, descriptor.name).filter {
|
||||
// NB memberScope for PackageViewDescriptor includes module dependencies
|
||||
DescriptorUtils.getContainingModule(it) == containingModule
|
||||
}
|
||||
|
||||
return overloadFilter.filterPackageMemberOverloads(possibleOverloads)
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.isPrivate() =
|
||||
this is DeclarationDescriptorWithVisibility &&
|
||||
Visibilities.isPrivate(this.visibility)
|
||||
|
||||
fun getPossibleRedeclarationGroups(
|
||||
members: Collection<DeclarationDescriptorNonRoot>
|
||||
): Collection<Collection<DeclarationDescriptorNonRoot>> {
|
||||
val result = arrayListOf<Collection<DeclarationDescriptorNonRoot>>()
|
||||
|
||||
val nonPrivates = members.filter { !it.isPrivate() }
|
||||
if (nonPrivates.size > 1) {
|
||||
result.add(nonPrivates)
|
||||
}
|
||||
|
||||
val bySourceFile = MultiMap.createSmart<SourceFile, DeclarationDescriptorNonRoot>()
|
||||
for (member in members) {
|
||||
val sourceFile = DescriptorUtils.getContainingSourceFile(member)
|
||||
if (sourceFile != SourceFile.NO_SOURCE_FILE) {
|
||||
bySourceFile.putValue(sourceFile, member)
|
||||
}
|
||||
}
|
||||
|
||||
for ((sourceFile, membersInFile) in bySourceFile.entrySet()) {
|
||||
// File member groups are interesting in redeclaration check if at least one file member is private.
|
||||
if (membersInFile.size > 1 && membersInFile.any { it.isPrivate() }) {
|
||||
result.add(membersInFile)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,15 @@ package org.jetbrains.kotlin.resolve
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.reportOnDeclaration
|
||||
import org.jetbrains.kotlin.idea.MainFunctionDetector
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.getTypeAliasConstructors
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import java.util.*
|
||||
|
||||
class OverloadResolver(
|
||||
private val trace: BindingTrace,
|
||||
@@ -73,13 +77,96 @@ class OverloadResolver(
|
||||
}
|
||||
|
||||
private fun checkOverloadsInPackages(c: BodiesResolveContext) {
|
||||
val membersByName = overloadChecker.groupModulePackageMembersByFqName(c, overloadFilter)
|
||||
val membersByName = groupModulePackageMembersByFqName(c, overloadFilter)
|
||||
|
||||
for (e in membersByName.entrySet()) {
|
||||
checkOverloadsInPackage(e.value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun groupModulePackageMembersByFqName(
|
||||
c: BodiesResolveContext,
|
||||
overloadFilter: OverloadFilter
|
||||
): MultiMap<FqNameUnsafe, DeclarationDescriptorNonRoot> {
|
||||
val packageMembersByName = MultiMap<FqNameUnsafe, DeclarationDescriptorNonRoot>()
|
||||
|
||||
collectModulePackageMembersWithSameName(
|
||||
packageMembersByName,
|
||||
c.functions.values + c.declaredClasses.values + c.typeAliases.values,
|
||||
overloadFilter
|
||||
) {
|
||||
scope, name ->
|
||||
val functions = scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS)
|
||||
val classifier = scope.getContributedClassifier(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS)
|
||||
when (classifier) {
|
||||
is ClassDescriptor ->
|
||||
if (!classifier.kind.isSingleton)
|
||||
functions + classifier.constructors
|
||||
else
|
||||
functions
|
||||
is TypeAliasDescriptor ->
|
||||
functions + classifier.getTypeAliasConstructors()
|
||||
else ->
|
||||
functions
|
||||
}
|
||||
}
|
||||
|
||||
collectModulePackageMembersWithSameName(packageMembersByName, c.properties.values, overloadFilter) {
|
||||
scope, name ->
|
||||
val variables = scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS)
|
||||
val classifier = scope.getContributedClassifier(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS)
|
||||
variables + classifier.singletonOrEmptyList()
|
||||
}
|
||||
|
||||
return packageMembersByName
|
||||
}
|
||||
|
||||
private inline fun collectModulePackageMembersWithSameName(
|
||||
packageMembersByName: MultiMap<FqNameUnsafe, DeclarationDescriptorNonRoot>,
|
||||
interestingDescriptors: Collection<DeclarationDescriptor>,
|
||||
overloadFilter: OverloadFilter,
|
||||
getMembersByName: (MemberScope, Name) -> Collection<DeclarationDescriptorNonRoot>
|
||||
) {
|
||||
val observedFQNs = hashSetOf<FqNameUnsafe>()
|
||||
for (descriptor in interestingDescriptors) {
|
||||
if (descriptor.containingDeclaration !is PackageFragmentDescriptor) continue
|
||||
|
||||
val descriptorFQN = DescriptorUtils.getFqName(descriptor)
|
||||
if (observedFQNs.contains(descriptorFQN)) continue
|
||||
observedFQNs.add(descriptorFQN)
|
||||
|
||||
val packageMembersWithSameName = getModulePackageMembersWithSameName(descriptor, overloadFilter, getMembersByName)
|
||||
packageMembersByName.putValues(descriptorFQN, packageMembersWithSameName)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun getModulePackageMembersWithSameName(
|
||||
descriptor: DeclarationDescriptor,
|
||||
overloadFilter: OverloadFilter,
|
||||
getMembersByName: (MemberScope, Name) -> Collection<DeclarationDescriptorNonRoot>
|
||||
): Collection<DeclarationDescriptorNonRoot> {
|
||||
val containingPackage = descriptor.containingDeclaration
|
||||
if (containingPackage !is PackageFragmentDescriptor) {
|
||||
throw AssertionError("$descriptor is not a top-level package member")
|
||||
}
|
||||
|
||||
val containingModule = DescriptorUtils.getContainingModuleOrNull(descriptor) ?:
|
||||
return when (descriptor) {
|
||||
is CallableMemberDescriptor -> listOf(descriptor)
|
||||
is ClassDescriptor -> descriptor.constructors
|
||||
else -> throw AssertionError("Unexpected descriptor kind: $descriptor")
|
||||
}
|
||||
|
||||
val containingPackageScope = containingModule.getPackage(containingPackage.fqName).memberScope
|
||||
val possibleOverloads =
|
||||
getMembersByName(containingPackageScope, descriptor.name).filter {
|
||||
// NB memberScope for PackageViewDescriptor includes module dependencies
|
||||
DescriptorUtils.getContainingModule(it) == containingModule
|
||||
}
|
||||
|
||||
return overloadFilter.filterPackageMemberOverloads(possibleOverloads)
|
||||
}
|
||||
|
||||
private fun checkOverloadsInClass(
|
||||
classDescriptor: ClassDescriptorWithResolutionScopes,
|
||||
nestedClassConstructors: Collection<FunctionDescriptor>
|
||||
@@ -102,11 +189,52 @@ class OverloadResolver(
|
||||
|
||||
private fun checkOverloadsInPackage(members: Collection<DeclarationDescriptorNonRoot>) {
|
||||
if (members.size == 1) return
|
||||
for (redeclarationGroup in overloadChecker.getPossibleRedeclarationGroups(members)) {
|
||||
reportRedeclarations(findRedeclarations(redeclarationGroup))
|
||||
|
||||
val redeclarationsMap = LinkedHashMap<DeclarationDescriptorNonRoot, MutableSet<DeclarationDescriptorNonRoot>>()
|
||||
for (redeclarationGroup in getPossibleRedeclarationGroups(members)) {
|
||||
val redeclarations = findRedeclarations(redeclarationGroup)
|
||||
redeclarations.forEach {
|
||||
redeclarationsMap.getOrPut(it) { LinkedHashSet() }.addAll(redeclarations)
|
||||
}
|
||||
}
|
||||
|
||||
val reported = HashSet<DeclarationDescriptorNonRoot>()
|
||||
for ((member, conflicting) in redeclarationsMap) {
|
||||
if (!reported.contains(member)) {
|
||||
reported.addAll(conflicting)
|
||||
reportRedeclarations(conflicting)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPossibleRedeclarationGroups(members: Collection<DeclarationDescriptorNonRoot>): Collection<Collection<DeclarationDescriptorNonRoot>> {
|
||||
val result = arrayListOf<Collection<DeclarationDescriptorNonRoot>>()
|
||||
|
||||
val nonPrivates = members.filter { !it.isPrivate() }
|
||||
|
||||
val bySourceFile = members.groupBy { DescriptorUtils.getContainingSourceFile(it) }
|
||||
|
||||
var hasGroupIncludingNonPrivateMembers = false
|
||||
for ((sourceFile, membersInFile) in bySourceFile) {
|
||||
// File member groups are interesting in redeclaration check if at least one file member is private.
|
||||
if (membersInFile.any { it.isPrivate() }) {
|
||||
hasGroupIncludingNonPrivateMembers = true
|
||||
val group = LinkedHashSet<DeclarationDescriptorNonRoot>(nonPrivates) + membersInFile
|
||||
result.add(group)
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasGroupIncludingNonPrivateMembers && nonPrivates.size > 1) {
|
||||
result.add(nonPrivates)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.isPrivate() =
|
||||
this is DeclarationDescriptorWithVisibility &&
|
||||
Visibilities.isPrivate(this.visibility)
|
||||
|
||||
private fun checkOverloadsInClass(members: Collection<CallableMemberDescriptor>) {
|
||||
if (members.size == 1) return
|
||||
reportRedeclarations(findRedeclarations(members))
|
||||
@@ -115,8 +243,8 @@ class OverloadResolver(
|
||||
private fun DeclarationDescriptor.isSynthesized() =
|
||||
this is CallableMemberDescriptor && kind == CallableMemberDescriptor.Kind.SYNTHESIZED
|
||||
|
||||
private fun findRedeclarations(members: Collection<DeclarationDescriptorNonRoot>): Set<Pair<KtDeclaration?, DeclarationDescriptorNonRoot>> {
|
||||
val redeclarations = linkedSetOf<Pair<KtDeclaration?, DeclarationDescriptorNonRoot>>()
|
||||
private fun findRedeclarations(members: Collection<DeclarationDescriptorNonRoot>): Collection<DeclarationDescriptorNonRoot> {
|
||||
val redeclarations = linkedSetOf<DeclarationDescriptorNonRoot>()
|
||||
for (member1 in members) {
|
||||
if (member1.isSynthesized()) continue
|
||||
|
||||
@@ -126,8 +254,7 @@ class OverloadResolver(
|
||||
if (isTopLevelMainInDifferentFiles(member1, member2)) continue
|
||||
|
||||
if (!overloadChecker.isOverloadable(member1, member2)) {
|
||||
val ktDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(member1) as KtDeclaration?
|
||||
redeclarations.add(ktDeclaration to member1)
|
||||
redeclarations.add(member1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,33 +281,16 @@ class OverloadResolver(
|
||||
return file1 == null || file2 == null || file1 !== file2
|
||||
}
|
||||
|
||||
private fun reportRedeclarations(redeclarations: Set<Pair<KtDeclaration?, DeclarationDescriptorNonRoot>>) {
|
||||
private fun reportRedeclarations(redeclarations: Collection<DeclarationDescriptorNonRoot>) {
|
||||
if (redeclarations.isEmpty()) return
|
||||
|
||||
val redeclarationsIterator = redeclarations.iterator()
|
||||
val firstRedeclarationDescriptor = redeclarationsIterator.next().second
|
||||
val otherRedeclarationDescriptor = redeclarationsIterator.check { it.hasNext() }?.next()?.second
|
||||
|
||||
for ((ktDeclaration, memberDescriptor) in redeclarations) {
|
||||
if (ktDeclaration == null) continue
|
||||
|
||||
for (memberDescriptor in redeclarations) {
|
||||
when (memberDescriptor) {
|
||||
is PropertyDescriptor,
|
||||
is ClassifierDescriptor -> {
|
||||
trace.report(Errors.REDECLARATION.on(ktDeclaration, memberDescriptor.name.asString()))
|
||||
}
|
||||
is FunctionDescriptor -> {
|
||||
val redeclarationDescriptor =
|
||||
if (otherRedeclarationDescriptor == null)
|
||||
firstRedeclarationDescriptor
|
||||
else if (memberDescriptor == firstRedeclarationDescriptor)
|
||||
otherRedeclarationDescriptor
|
||||
else
|
||||
firstRedeclarationDescriptor
|
||||
|
||||
trace.report(Errors.CONFLICTING_OVERLOADS.on(ktDeclaration, memberDescriptor,
|
||||
redeclarationDescriptor.containingDeclaration))
|
||||
}
|
||||
is ClassifierDescriptor ->
|
||||
reportOnDeclaration(trace, memberDescriptor) { Errors.REDECLARATION.on(it, redeclarations) }
|
||||
is FunctionDescriptor ->
|
||||
reportOnDeclaration(trace, memberDescriptor) { Errors.CONFLICTING_OVERLOADS.on(it, redeclarations) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-8
@@ -23,14 +23,13 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.FAKE_OVERR
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.reportOnDeclarationAs
|
||||
import org.jetbrains.kotlin.diagnostics.reportOnDeclarationOrFail
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.incremental.record
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
|
||||
@@ -107,13 +106,13 @@ open class LazyClassMemberScope(
|
||||
}
|
||||
|
||||
override fun overrideConflict(fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor) {
|
||||
val declaration = DescriptorToSourceUtils.descriptorToDeclaration(fromCurrent) as? KtDeclaration ?: error("fromCurrent can not be a fake override")
|
||||
trace.report(Errors.CONFLICTING_OVERLOADS.on(declaration, fromCurrent, fromSuper.containingDeclaration))
|
||||
reportOnDeclarationOrFail(trace, fromCurrent) { Errors.CONFLICTING_OVERLOADS.on(it, listOf(fromCurrent, fromSuper)) }
|
||||
}
|
||||
|
||||
override fun inheritanceConflict(first: CallableMemberDescriptor, second: CallableMemberDescriptor) {
|
||||
val thisClassDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(thisDescriptor) as? KtClassOrObject ?: error("No class declaration")
|
||||
trace.report(Errors.CONFLICTING_INHERITED_MEMBERS.on(thisClassDeclaration, thisDescriptor, listOf(first, second)))
|
||||
reportOnDeclarationAs<KtClassOrObject>(trace, thisDescriptor) { ktClassOrObject ->
|
||||
Errors.CONFLICTING_INHERITED_MEMBERS.on(ktClassOrObject, thisDescriptor, listOf(first, second))
|
||||
}
|
||||
}
|
||||
})
|
||||
OverrideResolver.resolveUnknownVisibilities(result, trace)
|
||||
|
||||
+8
-24
@@ -16,8 +16,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.scopes
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.reportOnDeclarationOrFail
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
@@ -77,32 +81,12 @@ class ThrowingLocalRedeclarationChecker(overloadChecker: OverloadChecker) : Abst
|
||||
|
||||
class TraceBasedLocalRedeclarationChecker(val trace: BindingTrace, overloadChecker: OverloadChecker): AbstractLocalRedeclarationChecker(overloadChecker) {
|
||||
override fun handleRedeclaration(first: DeclarationDescriptor, second: DeclarationDescriptor) {
|
||||
reportRedeclaration(first)
|
||||
reportRedeclaration(second)
|
||||
reportOnDeclarationOrFail(trace, first) { Errors.REDECLARATION.on(it, listOf(first, second))}
|
||||
reportOnDeclarationOrFail(trace, second) { Errors.REDECLARATION.on(it, listOf(first, second))}
|
||||
}
|
||||
|
||||
override fun handleConflictingOverloads(first: CallableMemberDescriptor, second: CallableMemberDescriptor) {
|
||||
reportConflictingOverloads(first, second.containingDeclaration)
|
||||
reportConflictingOverloads(second, first.containingDeclaration)
|
||||
}
|
||||
|
||||
private fun reportConflictingOverloads(conflicting: CallableMemberDescriptor, withContainedIn: DeclarationDescriptor) {
|
||||
val reportElement = DescriptorToSourceUtils.descriptorToDeclaration(conflicting)
|
||||
if (reportElement != null) {
|
||||
trace.report(Errors.CONFLICTING_OVERLOADS.on(reportElement, conflicting, withContainedIn))
|
||||
}
|
||||
else {
|
||||
throw IllegalStateException("No declaration found for " + conflicting)
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportRedeclaration(descriptor: DeclarationDescriptor) {
|
||||
val firstElement = DescriptorToSourceUtils.descriptorToDeclaration(descriptor)
|
||||
if (firstElement != null) {
|
||||
trace.report(Errors.REDECLARATION.on(firstElement, descriptor.name.asString()))
|
||||
}
|
||||
else {
|
||||
throw IllegalStateException("No declaration found for " + descriptor)
|
||||
}
|
||||
reportOnDeclarationOrFail(trace, first) { Errors.CONFLICTING_OVERLOADS.on(it, listOf(first, second)) }
|
||||
reportOnDeclarationOrFail(trace, second) { Errors.CONFLICTING_OVERLOADS.on(it, listOf(first, second)) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user