From 5218246d80855fbc2ebd96cfa333e3ce003be1ef Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Thu, 10 Nov 2011 20:00:15 +0400 Subject: [PATCH 1/4] KT-424: Check declarations for overload-compatibility === fun a() {} fun a() {} === must be an error. --- .../jet/lang/diagnostics/Errors.java | 13 ++ .../jet/lang/resolve/OverloadResolver.java | 86 ++++++++++ .../jet/lang/resolve/OverloadUtil.java | 52 ++++++ .../jet/lang/resolve/OverridingUtil.java | 7 + .../jet/lang/resolve/TopDownAnalyzer.java | 1 + .../quick/ConflictingOverloads.jet | 12 ++ .../jetbrains/jet/types/JetOverloadTest.java | 158 ++++++++++++++++++ .../jet/types/JetOverridingTest.java | 7 + 8 files changed, 336 insertions(+) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadUtil.java create mode 100644 compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet create mode 100644 compiler/tests/org/jetbrains/jet/types/JetOverloadTest.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 52b22dbcb3c..d18d4ca5db8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -375,6 +375,19 @@ public interface Errors { } }; + ParameterizedDiagnosticFactory2 CONFLICTING_OVERLOADS = new ParameterizedDiagnosticFactory2(ERROR, "{1} is already defined in ''{0}''") { + @Override + protected String makeMessageForA(@NotNull JetClassOrObject jetClassOrObject) { + return jetClassOrObject.getName(); + } + + @Override + protected String makeMessageForB(@NotNull CallableMemberDescriptor memberDescriptor) { + return DescriptorRenderer.TEXT.render(memberDescriptor); + } + }; + + ParameterizedDiagnosticFactory3 RESULT_TYPE_MISMATCH = ParameterizedDiagnosticFactory3.create(ERROR, "{0} must return {1} but returns {2}"); ParameterizedDiagnosticFactory3 UNSAFE_INFIX_CALL = ParameterizedDiagnosticFactory3.create(ERROR, "Infix call corresponds to a dot-qualified call ''{0}.{1}({2})'' which is not allowed on a nullable receiver ''{0}''. Use '?.'-qualified call instead"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java new file mode 100644 index 00000000000..be18d1938de --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java @@ -0,0 +1,86 @@ +package org.jetbrains.jet.lang.resolve; + +import com.intellij.psi.PsiElement; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.MutableClassDescriptor; +import org.jetbrains.jet.lang.diagnostics.Errors; +import org.jetbrains.jet.lang.psi.*; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static org.jetbrains.jet.lang.resolve.BindingContext.DELEGATED; + +/** + * @author Stepan Koltsov + */ +public class OverloadResolver { + private final TopDownAnalysisContext context; + + public OverloadResolver(@NotNull TopDownAnalysisContext context) { + this.context = context; + } + + public void process() { + checkOverloads(); + } + + private void checkOverloads() { + for (Map.Entry entry : context.getClasses().entrySet()) { + checkOverloadsInAClass(entry.getValue(), entry.getKey()); + } + for (Map.Entry entry : context.getObjects().entrySet()) { + checkOverloadsInAClass(entry.getValue(), entry.getKey()); + } + } + + private void checkOverloadsInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) { + MultiMap functionsByName = MultiMap.create(); + + for (FunctionDescriptor function : classDescriptor.getFunctions()) { + functionsByName.putValue(function.getName(), function); + } + + for (Map.Entry> e : functionsByName.entrySet()) { + checkOverloadsWithSameName(e.getKey(), e.getValue(), klass); + } + + // properties are checked elsewhere + + // Kotlin has no secondary constructors at this time + + } + + private void checkOverloadsWithSameName(String name, Collection functions, JetClassOrObject klass) { + if (functions.size() == 1) { + // microoptimization + return; + } + + for (FunctionDescriptor function : functions) { + for (FunctionDescriptor function2 : functions) { + if (function == function2) { + continue; + } + + OverloadUtil.OverloadCompatibilityInfo overloadble = OverloadUtil.isOverloadble(function, function2); + if (!overloadble.isSuccess()) { + JetNamedFunction member = (JetNamedFunction) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, function); + if (member == null) { + assert context.getTrace().get(DELEGATED, function); + return; + } + + // XXX: mark "fun" keyword and parameters as in Java IDE // stepan.koltsov@ + PsiElement mark = member.getNameIdentifier(); + context.getTrace().report(Errors.CONFLICTING_OVERLOADS.on(mark, klass, function)); + } + } + } + } + +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadUtil.java new file mode 100644 index 00000000000..c33d452ada0 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadUtil.java @@ -0,0 +1,52 @@ +package org.jetbrains.jet.lang.resolve; + +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; + +/** + * @author Stepan Koltsov + */ +public class OverloadUtil { + + public static OverloadCompatibilityInfo isOverloadble(FunctionDescriptor a, FunctionDescriptor b) { + OverridingUtil.OverrideCompatibilityInfo overrideCompatibilityInfo = OverridingUtil.isOverridableByImpl(a, b, false); + if (overrideCompatibilityInfo.isSuccess()) { + return OverloadCompatibilityInfo.someError(); + } else { + return OverloadCompatibilityInfo.success(); + } + } + + public static class OverloadCompatibilityInfo { + + private static final OverloadCompatibilityInfo SUCCESS = new OverloadCompatibilityInfo(true, "SUCCESS"); + + public static OverloadCompatibilityInfo success() { + return SUCCESS; + } + + public static OverloadCompatibilityInfo someError() { + return new OverloadCompatibilityInfo(false, "XXX"); + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + private final boolean isSuccess; + private final String message; + + public OverloadCompatibilityInfo(boolean success, String message) { + isSuccess = success; + this.message = message; + } + + public boolean isSuccess() { + return isSuccess; + } + + public String getMessage() { + return message; + } + + } + +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java index 53b95a441f4..6b26f59f733 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java @@ -93,6 +93,13 @@ public class OverridingUtil { @NotNull public static OverrideCompatibilityInfo isOverridableBy(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) { + return isOverridableByImpl(superDescriptor, subDescriptor, true); + } + + /** + * @param forOverride true for override, false for overload + */ + static OverrideCompatibilityInfo isOverridableByImpl(CallableDescriptor superDescriptor, CallableDescriptor subDescriptor, boolean forOverride) { if (superDescriptor instanceof FunctionDescriptor) { if (subDescriptor instanceof PropertyDescriptor) return OverrideCompatibilityInfo.memberKindMismatch(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 48a8733ee82..eefbe5a7e4b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -52,6 +52,7 @@ public class TopDownAnalyzer { new DeclarationResolver(context).process(); new DelegationResolver(context).process(); new OverrideResolver(context).process(); + new OverloadResolver(context).process(); new BodyResolver(context).resolveBehaviorDeclarationBodies(); new ControlFlowAnalyzer(context, flowDataTraceFactory, declaredLocally).process(); new DeclarationsChecker(context).process(); diff --git a/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet b/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet new file mode 100644 index 00000000000..e1d47e33868 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet @@ -0,0 +1,12 @@ +// http://youtrack.jetbrains.net/issue/KT-424 + +class A { + // XXX: error should be reported on the whole method signature + // not only on method name + fun a() { + } + + fun a() { + } +} + diff --git a/compiler/tests/org/jetbrains/jet/types/JetOverloadTest.java b/compiler/tests/org/jetbrains/jet/types/JetOverloadTest.java new file mode 100644 index 00000000000..30916fa528a --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/types/JetOverloadTest.java @@ -0,0 +1,158 @@ +package org.jetbrains.jet.types; + +import org.jetbrains.jet.JetLiteFixture; +import org.jetbrains.jet.JetTestCaseBuilder; +import org.jetbrains.jet.JetTestUtils; +import org.jetbrains.jet.lang.JetSemanticServices; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; +import org.jetbrains.jet.lang.psi.JetNamedFunction; +import org.jetbrains.jet.lang.psi.JetPsiFactory; +import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver; +import org.jetbrains.jet.lang.resolve.OverloadUtil; +import org.jetbrains.jet.lang.types.JetStandardLibrary; + +/** + * @author Stepan Koltsov + */ +public class JetOverloadTest extends JetLiteFixture { + + private ModuleDescriptor root = new ModuleDescriptor("test_root"); + private JetStandardLibrary library; + private JetSemanticServices semanticServices; + private ClassDescriptorResolver classDescriptorResolver; + + @Override + public void setUp() throws Exception { + super.setUp(); + library = JetStandardLibrary.getJetStandardLibrary(getProject()); + semanticServices = JetSemanticServices.createSemanticServices(library); + classDescriptorResolver = semanticServices.getClassDescriptorResolver(JetTestUtils.DUMMY_TRACE); + } + + @Override + protected String getTestDataPath() { + return JetTestCaseBuilder.getTestDataPathBase(); + } + + public void testBasic() throws Exception { + + assertNotOverloadable( + "fun a() : Int", + "fun a() : Int"); + + assertNotOverloadable( + "fun a() : Int", + "fun a() : Any"); + + assertNotOverloadable( + "fun a() : T1", + "fun a() : T"); + + assertNotOverloadable( + "fun a(a : T1) : T1", + "fun a(a : T) : T"); + + assertNotOverloadable( + "fun a(a : T1) : T1", + "fun a(a : T) : T"); + + assertNotOverloadable( + "fun a(a : T1) : T1", + "fun a(a : T) : Y"); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + assertOverloadable( + "fun ab() : Int", + "fun a() : Int"); + + assertNotOverloadable( + "fun a() : Int", + "fun a() : Any"); + + assertOverloadable( + "fun a(a : Int) : Int", + "fun a() : Int"); + + assertOverloadable( + "fun a() : Int", + "fun a(a : Int) : Int"); + + assertOverloadable( + "fun a(a : Int?) : Int", + "fun a(a : Int) : Int"); + + // XXX: different from overridable + /* + assertNotOverloadable( + "fun a(a : Int) : Int", + "fun a(a : Int) : Int"); + */ + + assertOverloadable( + "fun a(a : T1) : T1", + "fun a(a : T) : T"); + + assertOverloadable( + "fun a(a : T1) : T1", + "fun a(a : Y) : T"); + + assertNotOverloadable( + "fun a(a : T1) : X", + "fun a(a : T) : T"); + + assertNotOverloadable( + "fun a>(a : Array) : T1", + "fun a>(a : Array) : T"); + + assertOverloadable( + "fun a>(a : Array) : T1", + "fun a>(a : Array) : T"); + + assertOverloadable( + "fun a>(a : Array) : T1", + "fun a>(a : Array) : T"); + + assertOverloadable( + "fun a>(a : Array) : T1", + "fun a>(a : Array) : T"); + + assertOverloadable( + "fun a>(a : Array) : T1", + "fun a>(a : Array) : T"); + + assertOverloadable( + "fun a>(a : Array<*>) : T1", + "fun a>(a : Array) : T"); + + } + + private void assertNotOverloadable(String funA, String funB) { + assertOverloadabilityRelation(funA, funB, true); + } + + private void assertOverloadable(String funA, String funB) { + assertOverloadabilityRelation(funA, funB, false); + } + + private void assertOverloadabilityRelation(String funA, String funB, boolean expectedIsError) { + FunctionDescriptor a = makeFunction(funA); + FunctionDescriptor b = makeFunction(funB); + { + OverloadUtil.OverloadCompatibilityInfo overloadableWith = OverloadUtil.isOverloadble(a, b); + assertEquals(overloadableWith.getMessage(), expectedIsError, !overloadableWith.isSuccess()); + } + { + OverloadUtil.OverloadCompatibilityInfo overloadableWith = OverloadUtil.isOverloadble(b, a); + assertEquals(overloadableWith.getMessage(), expectedIsError, !overloadableWith.isSuccess()); + } + } + + private FunctionDescriptor makeFunction(String funDecl) { + JetNamedFunction function = JetPsiFactory.createFunction(getProject(), funDecl); + return classDescriptorResolver.resolveFunctionDescriptor(root, library.getLibraryScope(), function); + } + +} diff --git a/compiler/tests/org/jetbrains/jet/types/JetOverridingTest.java b/compiler/tests/org/jetbrains/jet/types/JetOverridingTest.java index 4de8bd9a285..18b27921f61 100644 --- a/compiler/tests/org/jetbrains/jet/types/JetOverridingTest.java +++ b/compiler/tests/org/jetbrains/jet/types/JetOverridingTest.java @@ -67,6 +67,13 @@ public class JetOverridingTest extends JetLiteFixture { "fun a() : Int", "fun a() : Any"); + // return types are not cheked in the utility + /* + assertNotOverridable( + "fun a() : Any", + "fun a() : Int"); + */ + assertNotOverridable( "fun a(a : Int) : Int", "fun a() : Int"); From d155de2bdcbc8adbb6c557cb73fc0528626a3158 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Thu, 10 Nov 2011 20:00:19 +0400 Subject: [PATCH 2/4] better diagnostics for KT-424 highlight full function definition, not only function name --- .../jet/lang/diagnostics/Errors.java | 12 +------ .../FunctionSignatureDiagnosticFactory.java | 33 +++++++++++++++++++ .../jet/lang/psi/JetNamedFunction.java | 22 +++++++++++++ .../jet/lang/resolve/OverloadResolver.java | 4 +-- .../quick/ConflictingOverloads.jet | 12 ++++--- 5 files changed, 64 insertions(+), 19 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/FunctionSignatureDiagnosticFactory.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index d18d4ca5db8..fc73f338479 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -375,17 +375,7 @@ public interface Errors { } }; - ParameterizedDiagnosticFactory2 CONFLICTING_OVERLOADS = new ParameterizedDiagnosticFactory2(ERROR, "{1} is already defined in ''{0}''") { - @Override - protected String makeMessageForA(@NotNull JetClassOrObject jetClassOrObject) { - return jetClassOrObject.getName(); - } - - @Override - protected String makeMessageForB(@NotNull CallableMemberDescriptor memberDescriptor) { - return DescriptorRenderer.TEXT.render(memberDescriptor); - } - }; + FunctionSignatureDiagnosticFactory CONFLICTING_OVERLOADS = new FunctionSignatureDiagnosticFactory(ERROR, "{1} is already defined in ''{0}''"); ParameterizedDiagnosticFactory3 RESULT_TYPE_MISMATCH = ParameterizedDiagnosticFactory3.create(ERROR, "{0} must return {1} but returns {2}"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/FunctionSignatureDiagnosticFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/FunctionSignatureDiagnosticFactory.java new file mode 100644 index 00000000000..cea7b7f3f4c --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/FunctionSignatureDiagnosticFactory.java @@ -0,0 +1,33 @@ +package org.jetbrains.jet.lang.diagnostics; + +import com.intellij.openapi.util.TextRange; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.psi.JetClassOrObject; +import org.jetbrains.jet.lang.psi.JetNamedFunction; +import org.jetbrains.jet.resolve.DescriptorRenderer; + +/** + * @author Stepan Koltsov + */ +public class FunctionSignatureDiagnosticFactory extends DiagnosticFactoryWithMessageFormat { + + public FunctionSignatureDiagnosticFactory(Severity severity, String messageTemplate) { + super(severity, messageTemplate); + } + + @NotNull + public Diagnostic on(@NotNull JetNamedFunction functionElement, @NotNull FunctionDescriptor functionDescriptor, + @NotNull JetClassOrObject jetClassOrObject) + { + TextRange rangeToMark = new TextRange( + functionElement.getStartOfSignatureElement().getTextRange().getStartOffset(), + functionElement.getEndOfSignatureElement().getTextRange().getEndOffset() + ); + String message = messageFormat.format(new Object[]{ + jetClassOrObject.getName(), + DescriptorRenderer.TEXT.render(functionDescriptor)}); + return new GenericDiagnostic(this, severity, message, functionElement.getContainingFile(), rangeToMark); + } + +} //~ diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedFunction.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedFunction.java index 34e96ce83b9..30ffa3b5248 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedFunction.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedFunction.java @@ -40,4 +40,26 @@ public class JetNamedFunction extends JetFunction { return findChildByType(JetTokens.EQ) == null; } + @NotNull + public JetElement getStartOfSignatureElement() { + return this; + } + + @NotNull + public JetElement getEndOfSignatureElement() { + JetElement r = getReturnTypeRef(); + if (r != null) { + return r; + } + + r = getValueParameterList(); + if (r != null) { + return r; + } + + // otherwise it is an error + + return this; + } + } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java index be18d1938de..08a4e044179 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java @@ -75,9 +75,7 @@ public class OverloadResolver { return; } - // XXX: mark "fun" keyword and parameters as in Java IDE // stepan.koltsov@ - PsiElement mark = member.getNameIdentifier(); - context.getTrace().report(Errors.CONFLICTING_OVERLOADS.on(mark, klass, function)); + context.getTrace().report(Errors.CONFLICTING_OVERLOADS.on(member, function, klass)); } } } diff --git a/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet b/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet index e1d47e33868..84260a7cbd0 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet @@ -1,12 +1,14 @@ // http://youtrack.jetbrains.net/issue/KT-424 class A { - // XXX: error should be reported on the whole method signature - // not only on method name - fun a() { + fun a(a: Int): Int = 0 + + fun a(a: Int) { } - fun a() { + fun b() { + } + + fun b() { } } - From 31b049893f9819cc12eca835147cd7996cd2f63d Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Thu, 10 Nov 2011 20:00:26 +0400 Subject: [PATCH 3/4] fix wrong test (unnecessary overload) --- .../quick/nullabilityAndAutoCasts/ReceiverNullability.jet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/ReceiverNullability.jet b/compiler/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/ReceiverNullability.jet index 0995252deff..3bea190f1d3 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/ReceiverNullability.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/nullabilityAndAutoCasts/ReceiverNullability.jet @@ -15,7 +15,7 @@ fun test(a : A?) { a?.buzz() // warning } -fun A.test() { +fun A.test2() { foo() bar() buzz() From a4b62868fa579780c7cfa997ca05661ccf92a2d7 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Thu, 10 Nov 2011 20:00:34 +0400 Subject: [PATCH 4/4] KT-424 also check overloads in namespaces --- .../FunctionSignatureDiagnosticFactory.java | 4 +- .../jet/lang/resolve/OverloadResolver.java | 42 ++++++++++++++++--- .../quick/ConflictingOverloads.jet | 28 +++++++++++++ 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/FunctionSignatureDiagnosticFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/FunctionSignatureDiagnosticFactory.java index cea7b7f3f4c..4f5e64a5288 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/FunctionSignatureDiagnosticFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/FunctionSignatureDiagnosticFactory.java @@ -18,14 +18,14 @@ public class FunctionSignatureDiagnosticFactory extends DiagnosticFactoryWithMes @NotNull public Diagnostic on(@NotNull JetNamedFunction functionElement, @NotNull FunctionDescriptor functionDescriptor, - @NotNull JetClassOrObject jetClassOrObject) + @NotNull String functionContainer) { TextRange rangeToMark = new TextRange( functionElement.getStartOfSignatureElement().getTextRange().getStartOffset(), functionElement.getEndOfSignatureElement().getTextRange().getEndOffset() ); String message = messageFormat.format(new Object[]{ - jetClassOrObject.getName(), + functionContainer, DescriptorRenderer.TEXT.render(functionDescriptor)}); return new GenericDiagnostic(this, severity, message, functionElement.getContainingFile(), rangeToMark); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java index 08a4e044179..de621ebf5d0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java @@ -1,10 +1,11 @@ package org.jetbrains.jet.lang.resolve; +import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.MutableClassDescriptor; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; @@ -36,6 +37,37 @@ public class OverloadResolver { for (Map.Entry entry : context.getObjects().entrySet()) { checkOverloadsInAClass(entry.getValue(), entry.getKey()); } + checkOverloadsInANamespace(); + } + + private void checkOverloadsInANamespace() { + class Key extends Pair { + Key(String namespace, String name) { + super(namespace, name); + } + + public String getNamespace() { + return first; + } + + public String getFunctionName() { + return second; + } + } + + MultiMap functionsByName = MultiMap.create(); + + for (FunctionDescriptorImpl function : context.getFunctions().values()) { + DeclarationDescriptor containingDeclaration = function.getContainingDeclaration(); + if (containingDeclaration instanceof NamespaceDescriptor) { + NamespaceDescriptor namespaceDescriptor = (NamespaceDescriptor) containingDeclaration; + functionsByName.putValue(new Key(namespaceDescriptor.getName(), function.getName()), function); + } + } + + for (Map.Entry> e : functionsByName.entrySet()) { + checkOverloadsWithSameName(e.getKey().getFunctionName(), e.getValue(), e.getKey().getNamespace()); + } } private void checkOverloadsInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) { @@ -46,7 +78,7 @@ public class OverloadResolver { } for (Map.Entry> e : functionsByName.entrySet()) { - checkOverloadsWithSameName(e.getKey(), e.getValue(), klass); + checkOverloadsWithSameName(e.getKey(), e.getValue(), klass.getName()); } // properties are checked elsewhere @@ -55,7 +87,7 @@ public class OverloadResolver { } - private void checkOverloadsWithSameName(String name, Collection functions, JetClassOrObject klass) { + private void checkOverloadsWithSameName(String name, Collection functions, String functionContainer) { if (functions.size() == 1) { // microoptimization return; @@ -75,7 +107,7 @@ public class OverloadResolver { return; } - context.getTrace().report(Errors.CONFLICTING_OVERLOADS.on(member, function, klass)); + context.getTrace().report(Errors.CONFLICTING_OVERLOADS.on(member, function, functionContainer)); } } } diff --git a/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet b/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet index 84260a7cbd0..ab9380427fb 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet @@ -12,3 +12,31 @@ class A { fun b() { } } + +namespace deepSpace { + fun c(s: String) { + } + + fun c(s: String) { + } + + class B { + fun d(s: String) { + } + + fun d(s: String) { + } + } +} + + +// check no error in overload in different namespaces + +namespace ns1 { + fun e() = 1 +} + +namespace ns2 { + fun e() = 1 +} +