OverloadResolver.kt: convert to Kotlin & cleanup

This commit is contained in:
Dmitry Petrov
2016-02-09 12:28:59 +03:00
parent 6278459cc4
commit b2eb4200af
@@ -14,196 +14,160 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.resolve; package org.jetbrains.kotlin.resolve
import com.google.common.collect.Sets; import com.intellij.util.containers.MultiMap
import com.intellij.openapi.util.Pair; import org.jetbrains.kotlin.descriptors.*
import com.intellij.util.containers.MultiMap; import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.idea.MainFunctionDetector
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.idea.MainFunctionDetector; import org.jetbrains.kotlin.utils.addToStdlib.check
import org.jetbrains.kotlin.name.FqNameUnsafe;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import java.util.Collection; class OverloadResolver(
import java.util.Iterator; private val trace: BindingTrace,
import java.util.Map; private val overloadFilter: OverloadFilter) {
import java.util.Set;
public class OverloadResolver { fun process(c: BodiesResolveContext) {
@NotNull private final BindingTrace trace; checkOverloads(c)
@NotNull private final OverloadFilter overloadFilter;
public OverloadResolver(
@NotNull BindingTrace trace,
@NotNull OverloadFilter overloadFilter
) {
this.trace = trace;
this.overloadFilter = overloadFilter;
} }
public void process(@NotNull BodiesResolveContext c) { private fun checkOverloads(c: BodiesResolveContext) {
checkOverloads(c); val inClasses = findConstructorsInNestedClasses(c)
}
private void checkOverloads(@NotNull BodiesResolveContext c) { for (entry in c.declaredClasses.entries) {
MultiMap<ClassDescriptor, ConstructorDescriptor> inClasses = findConstructorsInNestedClasses(c); checkOverloadsInClass(entry.value, inClasses.get(entry.value))
for (Map.Entry<KtClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) {
checkOverloadsInAClass(entry.getValue(), inClasses.get(entry.getValue()));
} }
checkOverloadsInPackages(c); checkOverloadsInPackages(c)
} }
private static MultiMap<ClassDescriptor, ConstructorDescriptor> findConstructorsInNestedClasses(@NotNull BodiesResolveContext c) { private fun findConstructorsInNestedClasses(c: BodiesResolveContext): MultiMap<ClassDescriptor, ConstructorDescriptor> {
MultiMap<ClassDescriptor, ConstructorDescriptor> inClasses = MultiMap.create(); val constructorsInNestedClasses = MultiMap.create<ClassDescriptor, ConstructorDescriptor>()
for (ClassDescriptorWithResolutionScopes klass : c.getDeclaredClasses().values()) { for (klass in c.declaredClasses.values) {
if (klass.getKind().isSingleton() || klass.getName().isSpecial()) { if (klass.kind.isSingleton || klass.name.isSpecial) {
// Constructors of singletons or anonymous object aren't callable from the code, so they shouldn't participate in overload name checking // Constructors of singletons or anonymous object aren't callable from the code, so they shouldn't participate in overload name checking
continue; continue
} }
DeclarationDescriptor containingDeclaration = klass.getContainingDeclaration(); val containingDeclaration = klass.containingDeclaration
if (containingDeclaration instanceof ScriptDescriptor) { if (containingDeclaration is ScriptDescriptor) {
// TODO: check overload conflicts of functions with constructors in scripts // TODO: check overload conflicts of functions with constructors in scripts
} }
else if (containingDeclaration instanceof ClassDescriptor) { else if (containingDeclaration is ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; constructorsInNestedClasses.putValues(containingDeclaration, klass.constructors)
inClasses.putValues(classDescriptor, klass.getConstructors());
} }
else if (!(containingDeclaration instanceof FunctionDescriptor || else if (!(containingDeclaration is FunctionDescriptor ||
containingDeclaration instanceof PropertyDescriptor || containingDeclaration is PropertyDescriptor ||
containingDeclaration instanceof PackageFragmentDescriptor)) { containingDeclaration is PackageFragmentDescriptor)) {
throw new IllegalStateException("Illegal class container: " + containingDeclaration); throw IllegalStateException("Illegal class container: " + containingDeclaration)
} }
} }
return inClasses; return constructorsInNestedClasses
} }
private void checkOverloadsInPackages(@NotNull BodiesResolveContext c) { private fun checkOverloadsInPackages(c: BodiesResolveContext) {
MultiMap<FqNameUnsafe, CallableMemberDescriptor> membersByName = val membersByName = OverloadUtil.groupModulePackageMembersByFqName(c, overloadFilter)
OverloadUtil.groupModulePackageMembersByFqName(c, overloadFilter);
for (Map.Entry<FqNameUnsafe, Collection<CallableMemberDescriptor>> e : membersByName.entrySet()) { for (e in membersByName.entrySet()) {
checkOverloadsInPackage(e.getValue()); checkOverloadsInPackage(e.value)
} }
} }
private void checkOverloadsInAClass( private fun checkOverloadsInClass(
ClassDescriptorWithResolutionScopes classDescriptor, classDescriptor: ClassDescriptorWithResolutionScopes,
Collection<ConstructorDescriptor> nestedClassConstructors nestedClassConstructors: Collection<ConstructorDescriptor>
) { ) {
MultiMap<Name, CallableMemberDescriptor> functionsByName = MultiMap.create(); val functionsByName = MultiMap.create<Name, CallableMemberDescriptor>()
for (CallableMemberDescriptor function : classDescriptor.getDeclaredCallableMembers()) { for (function in classDescriptor.declaredCallableMembers) {
functionsByName.putValue(function.getName(), function); functionsByName.putValue(function.name, function)
} }
for (ConstructorDescriptor nestedClassConstructor : nestedClassConstructors) { for (nestedClassConstructor in nestedClassConstructors) {
functionsByName.putValue(nestedClassConstructor.getContainingDeclaration().getName(), nestedClassConstructor); functionsByName.putValue(nestedClassConstructor.containingDeclaration.name, nestedClassConstructor)
} }
for (Map.Entry<Name, Collection<CallableMemberDescriptor>> e : functionsByName.entrySet()) { for (e in functionsByName.entrySet()) {
checkOverloadsInClass(e.getValue()); checkOverloadsInClass(e.value)
} }
} }
private void checkOverloadsInPackage(@NotNull Collection<CallableMemberDescriptor> members) { private fun checkOverloadsInPackage(members: Collection<CallableMemberDescriptor>) {
if (members.size() == 1) return; if (members.size == 1) return
for (redeclarationGroup in OverloadUtil.getPossibleRedeclarationGroups(members)) {
for (Collection<? extends CallableMemberDescriptor> redeclarationGroup : OverloadUtil.getPossibleRedeclarationGroups(members)) { reportRedeclarations(findRedeclarations(redeclarationGroup))
Set<Pair<KtDeclaration, CallableMemberDescriptor>> redeclarations = findRedeclarations(redeclarationGroup);
// TODO: don't render FQ name here, extract this logic to somewhere
reportRedeclarations(redeclarations);
} }
} }
private void checkOverloadsInClass(@NotNull Collection<CallableMemberDescriptor> members) { private fun checkOverloadsInClass(members: Collection<CallableMemberDescriptor>) {
if (members.size() == 1) return; if (members.size == 1) return
reportRedeclarations(findRedeclarations(members))
reportRedeclarations(findRedeclarations(members));
} }
@NotNull private fun findRedeclarations(members: Collection<CallableMemberDescriptor>): Set<Pair<KtDeclaration?, CallableMemberDescriptor>> {
private static Set<Pair<KtDeclaration, CallableMemberDescriptor>> findRedeclarations(@NotNull Collection<? extends CallableMemberDescriptor> members) { val redeclarations = linkedSetOf<Pair<KtDeclaration?, CallableMemberDescriptor>>()
Set<Pair<KtDeclaration, CallableMemberDescriptor>> redeclarations = Sets.newLinkedHashSet(); for (member1 in members) {
for (CallableMemberDescriptor member : members) { if (member1.kind == CallableMemberDescriptor.Kind.SYNTHESIZED) continue
for (CallableMemberDescriptor member2 : members) {
if (member == member2 || isConstructorsOfDifferentRedeclaredClasses(member, member2)) {
continue;
}
if (!OverloadUtil.isOverloadable(member, member2) && member.getKind() != CallableMemberDescriptor.Kind.SYNTHESIZED) { for (member2 in members) {
if (isTopLevelMainInDifferentFiles(member, member2)) { if (member1 == member2) continue
continue; if (isConstructorsOfDifferentRedeclaredClasses(member1, member2)) continue
} if (isTopLevelMainInDifferentFiles(member1, member2)) continue
KtDeclaration ktDeclaration = (KtDeclaration) DescriptorToSourceUtils.descriptorToDeclaration(member); if (!OverloadUtil.isOverloadable(member1, member2)) {
redeclarations.add(Pair.create(ktDeclaration, member)); val ktDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(member1) as KtDeclaration?
redeclarations.add(ktDeclaration to member1)
} }
} }
} }
return redeclarations; return redeclarations
} }
private static boolean isConstructorsOfDifferentRedeclaredClasses( private fun isConstructorsOfDifferentRedeclaredClasses(member1: CallableMemberDescriptor, member2: CallableMemberDescriptor): Boolean {
@NotNull CallableMemberDescriptor member, @NotNull CallableMemberDescriptor member2 if (member1 !is ConstructorDescriptor || member2 !is ConstructorDescriptor) return false
) {
if (!(member instanceof ConstructorDescriptor) || !(member2 instanceof ConstructorDescriptor)) return false;
// ignore conflicting overloads for constructors of different classes because their redeclarations will be reported // ignore conflicting overloads for constructors of different classes because their redeclarations will be reported
// but don't ignore if there's possibility that classes redeclarations will not be reported // but don't ignore if there's possibility that classes redeclarations will not be reported
// (e.g. they're declared in different packages) // (e.g. they're declared in different packages)
assert member.getContainingDeclaration().getContainingDeclaration() != null : "Grandparent of constructor should not be null"; val parent1 = member1.containingDeclaration
return member.getContainingDeclaration() != member2.getContainingDeclaration() && val parent2 = member2.containingDeclaration
member.getContainingDeclaration().getContainingDeclaration().equals(member2.getContainingDeclaration().getContainingDeclaration()); return parent1 !== parent2 && parent1.containingDeclaration == parent2.containingDeclaration
} }
private static boolean isTopLevelMainInDifferentFiles(@NotNull CallableMemberDescriptor member, @NotNull CallableMemberDescriptor member2) { private fun isTopLevelMainInDifferentFiles(member1: CallableMemberDescriptor, member2: CallableMemberDescriptor): Boolean {
if (!MainFunctionDetector.isMain(member) || if (!MainFunctionDetector.isMain(member1) || !MainFunctionDetector.isMain(member2)) {
!MainFunctionDetector.isMain(member2)) { return false
return false;
} }
KtFile file = DescriptorToSourceUtils.getContainingFile(member); val file1 = DescriptorToSourceUtils.getContainingFile(member1)
KtFile file2 = DescriptorToSourceUtils.getContainingFile(member2); val file2 = DescriptorToSourceUtils.getContainingFile(member2)
return file == null || file2 == null || file != file2; return file1 == null || file2 == null || file1 !== file2
} }
private void reportRedeclarations(@NotNull Set<Pair<KtDeclaration, CallableMemberDescriptor>> redeclarations) { private fun reportRedeclarations(redeclarations: Set<Pair<KtDeclaration?, CallableMemberDescriptor>>) {
if (redeclarations.isEmpty()) return; if (redeclarations.isEmpty()) return
Iterator<Pair<KtDeclaration, CallableMemberDescriptor>> redeclarationsIterator = redeclarations.iterator(); val redeclarationsIterator = redeclarations.iterator()
CallableMemberDescriptor firstRedeclarationDescriptor = redeclarationsIterator.next().getSecond(); val firstRedeclarationDescriptor = redeclarationsIterator.next().second
CallableMemberDescriptor otherRedeclarationDescriptor = redeclarationsIterator.hasNext() val otherRedeclarationDescriptor = redeclarationsIterator.check { it.hasNext() }?.next()?.second
? redeclarationsIterator.next().getSecond()
: null;
for (Pair<KtDeclaration, CallableMemberDescriptor> redeclaration : redeclarations) { for ((ktDeclaration, memberDescriptor) in redeclarations) {
KtDeclaration ktDeclaration = redeclaration.getFirst(); if (ktDeclaration == null) continue
if (ktDeclaration == null) continue;
CallableMemberDescriptor memberDescriptor = redeclaration.getSecond(); if (memberDescriptor is PropertyDescriptor) {
trace.report(Errors.REDECLARATION.on(ktDeclaration, memberDescriptor.getName().asString()))
CallableMemberDescriptor redeclarationDescriptor;
if (otherRedeclarationDescriptor == null) {
redeclarationDescriptor = firstRedeclarationDescriptor;
}
else if (firstRedeclarationDescriptor == memberDescriptor) {
redeclarationDescriptor = otherRedeclarationDescriptor;
} }
else { else {
redeclarationDescriptor = firstRedeclarationDescriptor; val redeclarationDescriptor =
} if (otherRedeclarationDescriptor == null)
firstRedeclarationDescriptor
else if (memberDescriptor == firstRedeclarationDescriptor)
otherRedeclarationDescriptor
else
firstRedeclarationDescriptor
if (memberDescriptor instanceof PropertyDescriptor) {
trace.report(Errors.REDECLARATION.on(ktDeclaration, memberDescriptor.getName().asString()));
}
else {
trace.report(Errors.CONFLICTING_OVERLOADS.on(ktDeclaration, memberDescriptor, trace.report(Errors.CONFLICTING_OVERLOADS.on(ktDeclaration, memberDescriptor,
redeclarationDescriptor.getContainingDeclaration())); redeclarationDescriptor.containingDeclaration))
} }
} }
} }