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
@@ -18,9 +18,9 @@ class Outer {
}
fun outerFun() {
<!FUNCTION_DECLARATION_WITH_NO_NAME!>fun ()<!> {}
<!FUNCTION_DECLARATION_WITH_NO_NAME, CONFLICTING_OVERLOADS!>fun ()<!> {}
<!FUNCTION_DECLARATION_WITH_NO_NAME!>fun B.()<!> {}
<!FUNCTION_DECLARATION_WITH_NO_NAME!>@a fun ()<!> {}
<!FUNCTION_DECLARATION_WITH_NO_NAME, CONFLICTING_OVERLOADS!>@a fun ()<!> {}
<!FUNCTION_DECLARATION_WITH_NO_NAME!>fun @a A.()<!> {}
}
@@ -58,10 +58,10 @@ class Outer {
}
fun outerFun() {
<!FUNCTION_DECLARATION_WITH_NO_NAME!>fun ()<!> {
<!FUNCTION_DECLARATION_WITH_NO_NAME, CONFLICTING_OVERLOADS!>fun ()<!> {
}
<!FUNCTION_DECLARATION_WITH_NO_NAME!>fun ()<!> {
<!FUNCTION_DECLARATION_WITH_NO_NAME, CONFLICTING_OVERLOADS!>fun ()<!> {
}
}
@@ -0,0 +1,213 @@
fun test() {
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
fun Any.test2() {}
fun test2(x: Any) = x
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun test4(): Int<!> = 0
<!CONFLICTING_OVERLOADS!>fun test4(): String<!> = ""
class Test5<!CONFLICTING_OVERLOADS!>(val x: Int)<!> {
<!CONFLICTING_OVERLOADS!>constructor()<!>: this(0)
}
<!CONFLICTING_OVERLOADS!>fun Test5()<!> {}
<!CONFLICTING_OVERLOADS!>fun Test5(x: Int)<!> = x
fun local() {
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
fun Any.test2() {}
fun test2(x: Any) = x
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun test4(): Int<!> = 0
<!CONFLICTING_OVERLOADS!>fun test4(): String<!> = ""
class Test5<!CONFLICTING_OVERLOADS!>(val x: Int)<!> {
<!CONFLICTING_OVERLOADS!>constructor()<!>: this(0)
}
<!CONFLICTING_OVERLOADS!>fun Test5()<!> {}
<!CONFLICTING_OVERLOADS!>fun Test5(x: Int)<!> = x
}
}
class Test {
init {
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
fun Any.test2() {}
fun test2(x: Any) = x
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun test4(): Int<!> = 0
<!CONFLICTING_OVERLOADS!>fun test4(): String<!> = ""
class Test5<!CONFLICTING_OVERLOADS!>(val x: Int)<!> {
<!CONFLICTING_OVERLOADS!>constructor()<!>: this(0)
}
<!CONFLICTING_OVERLOADS!>fun Test5()<!> {}
<!CONFLICTING_OVERLOADS!>fun Test5(x: Int)<!> = x
}
fun test() {
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
fun Any.test2() {}
fun test2(x: Any) = x
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun test4(): Int<!> = 0
<!CONFLICTING_OVERLOADS!>fun test4(): String<!> = ""
class Test5<!CONFLICTING_OVERLOADS!>(val x: Int)<!> {
<!CONFLICTING_OVERLOADS!>constructor()<!>: this(0)
}
<!CONFLICTING_OVERLOADS!>fun Test5()<!> {}
<!CONFLICTING_OVERLOADS!>fun Test5(x: Int)<!> = x
}
val property: Any get() {
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
fun Any.test2() {}
fun test2(x: Any) = x
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun test4(): Int<!> = 0
<!CONFLICTING_OVERLOADS!>fun test4(): String<!> = ""
class Test5<!CONFLICTING_OVERLOADS!>(val x: Int)<!> {
<!CONFLICTING_OVERLOADS!>constructor()<!>: this(0)
}
<!CONFLICTING_OVERLOADS!>fun Test5()<!> {}
<!CONFLICTING_OVERLOADS!>fun Test5(x: Int)<!> = x
return 0
}
}
val property: Any get() {
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
fun Any.test2() {}
fun test2(x: Any) = x
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun test4(): Int<!> = 0
<!CONFLICTING_OVERLOADS!>fun test4(): String<!> = ""
class Test5<!CONFLICTING_OVERLOADS!>(val x: Int)<!> {
<!CONFLICTING_OVERLOADS!>constructor()<!>: this(0)
}
<!CONFLICTING_OVERLOADS!>fun Test5()<!> {}
<!CONFLICTING_OVERLOADS!>fun Test5(x: Int)<!> = x
return 0
}
object Object {
fun test() {
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
fun Any.test2() {}
fun test2(x: Any) = x
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun test4(): Int<!> = 0
<!CONFLICTING_OVERLOADS!>fun test4(): String<!> = ""
class Test5<!CONFLICTING_OVERLOADS!>(val x: Int)<!> {
<!CONFLICTING_OVERLOADS!>constructor()<!>: this(0)
}
<!CONFLICTING_OVERLOADS!>fun Test5()<!> {}
<!CONFLICTING_OVERLOADS!>fun Test5(x: Int)<!> = x
}
val property: Any get() {
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
fun Any.test2() {}
fun test2(x: Any) = x
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun test4(): Int<!> = 0
<!CONFLICTING_OVERLOADS!>fun test4(): String<!> = ""
class Test5<!CONFLICTING_OVERLOADS!>(val x: Int)<!> {
<!CONFLICTING_OVERLOADS!>constructor()<!>: this(0)
}
<!CONFLICTING_OVERLOADS!>fun Test5()<!> {}
<!CONFLICTING_OVERLOADS!>fun Test5(x: Int)<!> = x
return 0
}
}
val obj = object {
fun test() {
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
fun Any.test2() {}
fun test2(x: Any) = x
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun test4(): Int<!> = 0
<!CONFLICTING_OVERLOADS!>fun test4(): String<!> = ""
class Test5<!CONFLICTING_OVERLOADS!>(val x: Int)<!> {
<!CONFLICTING_OVERLOADS!>constructor()<!>: this(0)
}
<!CONFLICTING_OVERLOADS!>fun Test5()<!> {}
<!CONFLICTING_OVERLOADS!>fun Test5(x: Int)<!> = x
}
val property: Any get() {
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
<!CONFLICTING_OVERLOADS!>fun test1()<!> {}
fun Any.test2() {}
fun test2(x: Any) = x
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun Any.test3()<!> {}
<!CONFLICTING_OVERLOADS!>fun test4(): Int<!> = 0
<!CONFLICTING_OVERLOADS!>fun test4(): String<!> = ""
class Test5<!CONFLICTING_OVERLOADS!>(val x: Int)<!> {
<!CONFLICTING_OVERLOADS!>constructor()<!>: this(0)
}
<!CONFLICTING_OVERLOADS!>fun Test5()<!> {}
<!CONFLICTING_OVERLOADS!>fun Test5(x: Int)<!> = x
return 0
}
}
@@ -0,0 +1,23 @@
package
public val obj: kotlin.Any
public val property: kotlin.Any
public fun test(): kotlin.Unit
public object Object {
private constructor Object()
public final val property: kotlin.Any
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun test(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Test {
public constructor Test()
public final val property: kotlin.Any
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun test(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -11781,6 +11781,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("LocalFunctions.kt")
public void testLocalFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/overload/LocalFunctions.kt");
doTest(fileName);
}
@TestMetadata("OverloadFunRegularAndExt.kt")
public void testOverloadFunRegularAndExt() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/overload/OverloadFunRegularAndExt.kt");
@@ -1,3 +1,4 @@
// DISABLE-ERRORS
class A(val n: Int)
fun test() {
@@ -1,3 +1,4 @@
// DISABLE-ERRORS
class A(val n: Int)
fun test() {