KT-9547: private package member can conflict only with the members
declared in the same file. Cleanup OverloadUtil stuff. Update testData.
This commit is contained in:
@@ -109,18 +109,8 @@ public class DeclarationResolver(
|
||||
}
|
||||
|
||||
private fun getTopLevelDescriptorsByFqName(topLevelDescriptorProvider: TopLevelDescriptorProvider, fqName: FqName, location: LookupLocation): Set<DeclarationDescriptor> {
|
||||
val parentFqName = fqName.parent()
|
||||
|
||||
val descriptors = HashSet<DeclarationDescriptor>()
|
||||
|
||||
val parentFragment = topLevelDescriptorProvider.getPackageFragment(parentFqName)
|
||||
if (parentFragment != null) {
|
||||
// Filter out extension properties
|
||||
descriptors.addAll(parentFragment.getMemberScope().getProperties(fqName.shortName(), location).filter {
|
||||
it.getExtensionReceiverParameter() == null
|
||||
})
|
||||
}
|
||||
|
||||
descriptors.addIfNotNull(topLevelDescriptorProvider.getPackageFragment(fqName))
|
||||
descriptors.addAll(topLevelDescriptorProvider.getTopLevelClassDescriptors(fqName, location))
|
||||
return descriptors
|
||||
|
||||
@@ -91,12 +91,11 @@ public class OverloadResolver {
|
||||
@NotNull BodiesResolveContext c,
|
||||
@NotNull MultiMap<FqNameUnsafe, ConstructorDescriptor> inPackages
|
||||
) {
|
||||
MultiMap<FqNameUnsafe, CallableMemberDescriptor> functionsByName = OverloadUtil.groupModulePackageMembersByFqName(c, inPackages);
|
||||
MultiMap<FqNameUnsafe, CallableMemberDescriptor> membersByName = OverloadUtil.groupModulePackageMembersByFqName(c, inPackages);
|
||||
|
||||
for (Map.Entry<FqNameUnsafe, Collection<CallableMemberDescriptor>> e : functionsByName.entrySet()) {
|
||||
// TODO: don't render FQ name here, extract this logic to somewhere
|
||||
for (Map.Entry<FqNameUnsafe, Collection<CallableMemberDescriptor>> e : membersByName.entrySet()) {
|
||||
FqNameUnsafe fqName = e.getKey().parent();
|
||||
checkOverloadsWithSameName(e.getValue(), fqName.isRoot() ? "root package" : fqName.asString());
|
||||
checkOverloadsInPackage(e.getValue(), fqName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,32 +128,43 @@ public class OverloadResolver {
|
||||
}
|
||||
|
||||
for (Map.Entry<Name, Collection<CallableMemberDescriptor>> e : functionsByName.entrySet()) {
|
||||
checkOverloadsWithSameName(e.getValue(), nameForErrorMessage(classDescriptor, klass));
|
||||
checkOverloadsInClass(e.getValue(), classDescriptor, klass);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkOverloadsWithSameName(
|
||||
Collection<CallableMemberDescriptor> functions,
|
||||
@NotNull String functionContainer
|
||||
private void checkOverloadsInPackage(
|
||||
@NotNull Collection<CallableMemberDescriptor> members,
|
||||
@NotNull FqNameUnsafe packageFQN
|
||||
) {
|
||||
if (functions.size() == 1) {
|
||||
// micro-optimization
|
||||
return;
|
||||
if (members.size() == 1) return;
|
||||
|
||||
for (Collection<? extends CallableMemberDescriptor> redeclarationGroup : OverloadUtil.getPossibleRedeclarationGroups(members)) {
|
||||
Set<Pair<KtDeclaration, CallableMemberDescriptor>> redeclarations = findRedeclarations(redeclarationGroup);
|
||||
// TODO: don't render FQ name here, extract this logic to somewhere
|
||||
reportRedeclarations(packageFQN.isRoot() ? "root package" : packageFQN.asString(), redeclarations);
|
||||
}
|
||||
reportRedeclarations(functionContainer, findRedeclarations(functions));
|
||||
}
|
||||
|
||||
private void checkOverloadsInClass(
|
||||
@NotNull Collection<CallableMemberDescriptor> members,
|
||||
@NotNull ClassDescriptor classDescriptor,
|
||||
@NotNull KtClassOrObject ktClass
|
||||
) {
|
||||
if (members.size() == 1) return;
|
||||
|
||||
reportRedeclarations(nameForErrorMessage(classDescriptor, ktClass), findRedeclarations(members));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Set<Pair<KtDeclaration, CallableMemberDescriptor>> findRedeclarations(@NotNull Collection<CallableMemberDescriptor> functions) {
|
||||
private static Set<Pair<KtDeclaration, CallableMemberDescriptor>> findRedeclarations(@NotNull Collection<? extends CallableMemberDescriptor> members) {
|
||||
Set<Pair<KtDeclaration, CallableMemberDescriptor>> redeclarations = Sets.newLinkedHashSet();
|
||||
for (CallableMemberDescriptor member : functions) {
|
||||
for (CallableMemberDescriptor member2 : functions) {
|
||||
for (CallableMemberDescriptor member : members) {
|
||||
for (CallableMemberDescriptor member2 : members) {
|
||||
if (member == member2 || isConstructorsOfDifferentRedeclaredClasses(member, member2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
OverloadUtil.OverloadCompatibilityInfo overloadable = OverloadUtil.isOverloadable(member, member2);
|
||||
if (!overloadable.isSuccess() && member.getKind() != CallableMemberDescriptor.Kind.SYNTHESIZED) {
|
||||
if (!OverloadUtil.isOverloadable(member, member2) && member.getKind() != CallableMemberDescriptor.Kind.SYNTHESIZED) {
|
||||
KtDeclaration ktDeclaration = (KtDeclaration) DescriptorToSourceUtils.descriptorToDeclaration(member);
|
||||
if (ktDeclaration != null) {
|
||||
redeclarations.add(Pair.create(ktDeclaration, member));
|
||||
|
||||
@@ -31,42 +31,32 @@ object OverloadUtil {
|
||||
/**
|
||||
* Does not check names.
|
||||
*/
|
||||
public @JvmStatic fun isOverloadable(a: CallableDescriptor, b: CallableDescriptor): OverloadCompatibilityInfo {
|
||||
public @JvmStatic fun isOverloadable(a: CallableDescriptor, b: CallableDescriptor): Boolean {
|
||||
val abc = braceCount(a)
|
||||
val bbc = braceCount(b)
|
||||
|
||||
if (abc != bbc) {
|
||||
return OverloadCompatibilityInfo.success()
|
||||
return true
|
||||
}
|
||||
|
||||
val overrideCompatibilityInfo = isOverloadableBy(a, b)
|
||||
when (overrideCompatibilityInfo.result) {
|
||||
OVERRIDABLE, CONFLICT -> return OverloadCompatibilityInfo.someError()
|
||||
INCOMPATIBLE -> return OverloadCompatibilityInfo.success()
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isOverloadableBy(
|
||||
superDescriptor: CallableDescriptor,
|
||||
subDescriptor: CallableDescriptor): OverridingUtil.OverrideCompatibilityInfo {
|
||||
val receiverAndParameterResult = OverridingUtil.checkReceiverAndParameterCount(superDescriptor, subDescriptor)
|
||||
val receiverAndParameterResult = OverridingUtil.checkReceiverAndParameterCount(a, b)
|
||||
if (receiverAndParameterResult != null) {
|
||||
return receiverAndParameterResult
|
||||
return receiverAndParameterResult.result == INCOMPATIBLE
|
||||
}
|
||||
|
||||
val superValueParameters = OverridingUtil.compiledValueParameters(superDescriptor)
|
||||
val subValueParameters = OverridingUtil.compiledValueParameters(subDescriptor)
|
||||
val aValueParameters = OverridingUtil.compiledValueParameters(a)
|
||||
val bValueParameters = OverridingUtil.compiledValueParameters(b)
|
||||
|
||||
for (i in superValueParameters.indices) {
|
||||
val superValueParameterType = OverridingUtil.getUpperBound(superValueParameters[i])
|
||||
val subValueParameterType = OverridingUtil.getUpperBound(subValueParameters[i])
|
||||
if (!KotlinTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType) || oneMoreSpecificThanAnother(subValueParameterType, superValueParameterType)) {
|
||||
return OverridingUtil.OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameterType, subValueParameterType, INCOMPATIBLE)
|
||||
for (i in aValueParameters.indices) {
|
||||
val superValueParameterType = OverridingUtil.getUpperBound(aValueParameters[i])
|
||||
val subValueParameterType = OverridingUtil.getUpperBound(bValueParameters[i])
|
||||
if (!KotlinTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType) ||
|
||||
oneMoreSpecificThanAnother(subValueParameterType, superValueParameterType)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return OverridingUtil.OverrideCompatibilityInfo.success()
|
||||
return false
|
||||
}
|
||||
|
||||
private fun braceCount(a: CallableDescriptor): Int =
|
||||
@@ -77,17 +67,6 @@ object OverloadUtil {
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
|
||||
class OverloadCompatibilityInfo(val isSuccess: Boolean, val message: String) {
|
||||
companion object {
|
||||
|
||||
private val SUCCESS = OverloadCompatibilityInfo(true, "SUCCESS")
|
||||
|
||||
fun success() = SUCCESS
|
||||
|
||||
fun someError() = OverloadCompatibilityInfo(false, "XXX")
|
||||
}
|
||||
}
|
||||
|
||||
public @JvmStatic fun groupModulePackageMembersByFqName(
|
||||
c: BodiesResolveContext,
|
||||
constructorsInPackages: MultiMap<FqNameUnsafe, ConstructorDescriptor>
|
||||
@@ -104,7 +83,7 @@ object OverloadUtil {
|
||||
scope.getProperties(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS).filterIsInstance<CallableMemberDescriptor>()
|
||||
}
|
||||
|
||||
// TODO handle constructor redeclarations in modules. See also https://youtrack.jetbrains.com/issue/KT-3632
|
||||
// TODO handle constructor redeclarations in modules. See also: https://youtrack.jetbrains.com/issue/KT-3632
|
||||
packageMembersByName.putAllValues(constructorsInPackages)
|
||||
|
||||
return packageMembersByName
|
||||
@@ -146,4 +125,31 @@ object OverloadUtil {
|
||||
return possibleOverloads.filter { DescriptorUtils.getContainingModule(it) == containingModule }
|
||||
}
|
||||
|
||||
private fun MemberDescriptor.isPrivate() = Visibilities.isPrivate(this.visibility)
|
||||
|
||||
public @JvmStatic fun getPossibleRedeclarationGroups(members: Collection<CallableMemberDescriptor>): Collection<Collection<CallableMemberDescriptor>> {
|
||||
val result = arrayListOf<Collection<CallableMemberDescriptor>>()
|
||||
|
||||
val nonPrivates = members.filter { !it.isPrivate() }
|
||||
if (nonPrivates.size > 1) {
|
||||
result.add(nonPrivates)
|
||||
}
|
||||
|
||||
val bySourceFile = MultiMap.createSmart<SourceFile, CallableMemberDescriptor>()
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user