Check local function declarations for overload conflicts.

In PSI unifier tests, disable errors for tests on local functions (as irrelevant).
This commit is contained in:
Dmitry Petrov
2016-02-11 16:01:58 +03:00
parent 17a95384e1
commit edf6a2142b
11 changed files with 307 additions and 14 deletions
@@ -296,7 +296,7 @@ public interface Errors {
// Members
DiagnosticFactory2<KtDeclaration, CallableMemberDescriptor, DeclarationDescriptor> CONFLICTING_OVERLOADS =
DiagnosticFactory2<PsiElement, CallableMemberDescriptor, DeclarationDescriptor> CONFLICTING_OVERLOADS =
DiagnosticFactory2.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
DiagnosticFactory0<KtNamedDeclaration> NON_FINAL_MEMBER_IN_FINAL_CLASS = DiagnosticFactory0.create(WARNING, modifierSetPosition(
@@ -18,9 +18,11 @@ package org.jetbrains.kotlin.resolve;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.resolve.scopes.RedeclarationHandler;
import static org.jetbrains.kotlin.diagnostics.Errors.CONFLICTING_OVERLOADS;
import static org.jetbrains.kotlin.diagnostics.Errors.REDECLARATION;
public class TraceBasedRedeclarationHandler implements RedeclarationHandler {
@@ -32,11 +34,27 @@ public class TraceBasedRedeclarationHandler implements RedeclarationHandler {
@Override
public void handleRedeclaration(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) {
report(first);
report(second);
reportRedeclaration(first);
reportRedeclaration(second);
}
private void report(DeclarationDescriptor descriptor) {
@Override
public void handleConflictingOverloads(@NotNull CallableMemberDescriptor first, @NotNull CallableMemberDescriptor second) {
reportConflictingOverloads(first, second.getContainingDeclaration());
reportConflictingOverloads(second, first.getContainingDeclaration());
}
private void reportConflictingOverloads(CallableMemberDescriptor conflicting, DeclarationDescriptor withContainedIn) {
PsiElement reportElement = DescriptorToSourceUtils.descriptorToDeclaration(conflicting);
if (reportElement != null) {
trace.report(CONFLICTING_OVERLOADS.on(reportElement, conflicting, withContainedIn));
}
else {
throw new IllegalStateException("No declaration found for " + conflicting);
}
}
private void reportRedeclaration(DeclarationDescriptor descriptor) {
PsiElement firstElement = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
if (firstElement != null) {
trace.report(REDECLARATION.on(firstElement, descriptor.getName().asString()));
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.resolve.scopes;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
@@ -25,6 +26,10 @@ public interface RedeclarationHandler {
@Override
public void handleRedeclaration(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) {
}
@Override
public void handleConflictingOverloads(@NotNull CallableMemberDescriptor first, @NotNull CallableMemberDescriptor second) {
}
};
RedeclarationHandler THROW_EXCEPTION = new RedeclarationHandler() {
@Override
@@ -34,7 +39,17 @@ public interface RedeclarationHandler {
DescriptorUtils.getFqName(second), second)
);
}
@Override
public void handleConflictingOverloads(@NotNull CallableMemberDescriptor first, @NotNull CallableMemberDescriptor second) {
throw new IllegalStateException(
String.format("Conflicting overloads: %s (%s) and %s (%s) (no line info available)",
DescriptorUtils.getFqName(first), first,
DescriptorUtils.getFqName(second), second)
);
}
};
void handleRedeclaration(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second);
void handleConflictingOverloads(@NotNull CallableMemberDescriptor first, @NotNull CallableMemberDescriptor second);
}
@@ -17,11 +17,9 @@
package org.jetbrains.kotlin.resolve.scopes
import com.intellij.util.SmartList
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverloadUtil
import java.util.*
abstract class WritableScopeStorage(val redeclarationHandler: RedeclarationHandler) {
@@ -50,16 +48,34 @@ abstract class WritableScopeStorage(val redeclarationHandler: RedeclarationHandl
}
protected fun addFunctionDescriptorInternal(functionDescriptor: FunctionDescriptor) {
val descriptorIndex = addDescriptor(functionDescriptor)
checkOverloadConflicts(functionDescriptor)
val name = functionDescriptor.name
val descriptorIndex = addDescriptor(functionDescriptor)
if (functionsByName == null) {
functionsByName = HashMap(1)
}
val name = functionDescriptor.name
//TODO: could not use += because of KT-8050
functionsByName!![name] = functionsByName!![name] + descriptorIndex
}
private fun checkOverloadConflicts(functionDescriptor: FunctionDescriptor) {
val name = functionDescriptor.name
val originalFunctions = functionsByName(name).orEmpty()
val originalVariableOrClass = variableOrClassDescriptorByName(name)
val potentiallyConflictingOverloads =
if (originalVariableOrClass is ClassDescriptor)
originalFunctions + originalVariableOrClass.constructors
else
originalFunctions
for (overloadedDescriptor in potentiallyConflictingOverloads) {
if (!OverloadUtil.isOverloadable(overloadedDescriptor, functionDescriptor)) {
redeclarationHandler.handleConflictingOverloads(functionDescriptor, overloadedDescriptor)
break
}
}
}
protected fun variableOrClassDescriptorByName(name: Name, descriptorLimit: Int = addedDescriptors.size): DeclarationDescriptor? {
if (descriptorLimit == 0) return null