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:
Dmitry Petrov
2015-10-21 15:04:10 +03:00
parent 5170341624
commit 829fc6938a
12 changed files with 167 additions and 84 deletions
@@ -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
}
}