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 4f5e64a5288..64d650393a5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/FunctionSignatureDiagnosticFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/FunctionSignatureDiagnosticFactory.java @@ -1,10 +1,10 @@ package org.jetbrains.jet.lang.diagnostics; import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; 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.lang.psi.*; import org.jetbrains.jet.resolve.DescriptorRenderer; /** @@ -15,19 +15,43 @@ public class FunctionSignatureDiagnosticFactory extends DiagnosticFactoryWithMes public FunctionSignatureDiagnosticFactory(Severity severity, String messageTemplate) { super(severity, messageTemplate); } + + private TextRange rangeToMark(JetDeclaration jetDeclaration) { + if (jetDeclaration instanceof JetNamedFunction) { + JetNamedFunction functionElement = (JetNamedFunction) jetDeclaration; + return new TextRange( + functionElement.getStartOfSignatureElement().getTextRange().getStartOffset(), + functionElement.getEndOfSignatureElement().getTextRange().getEndOffset() + ); + } else if (jetDeclaration instanceof JetClass) { + // primary constructor + JetClass klass = (JetClass) jetDeclaration; + PsiElement nameAsDeclaration = klass.getNameIdentifier(); + PsiElement primaryConstructorParameterList = klass.getPrimaryConstructorParameterList(); + if (nameAsDeclaration == null || primaryConstructorParameterList == null) { + return klass.getTextRange(); + } else { + return new TextRange( + nameAsDeclaration.getTextRange().getStartOffset(), + primaryConstructorParameterList.getTextRange().getEndOffset() + ); + } + } else { + // safe way + return jetDeclaration.getTextRange(); + } + } @NotNull - public Diagnostic on(@NotNull JetNamedFunction functionElement, @NotNull FunctionDescriptor functionDescriptor, - @NotNull String functionContainer) + public Diagnostic on(@NotNull JetDeclaration declaration, @NotNull FunctionDescriptor functionDescriptor, + @NotNull String functionContainer) { - TextRange rangeToMark = new TextRange( - functionElement.getStartOfSignatureElement().getTextRange().getStartOffset(), - functionElement.getEndOfSignatureElement().getTextRange().getEndOffset() - ); + TextRange rangeToMark = rangeToMark(declaration); + String message = messageFormat.format(new Object[]{ functionContainer, DescriptorRenderer.TEXT.render(functionDescriptor)}); - return new GenericDiagnostic(this, severity, message, functionElement.getContainingFile(), rangeToMark); + return new GenericDiagnostic(this, severity, message, declaration.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 69a1881ee95..71efb22c412 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java @@ -3,6 +3,7 @@ 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.apache.commons.lang.NotImplementedException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -32,29 +33,62 @@ public class OverloadResolver { } private void checkOverloads() { + Pair, MultiMap> pair = constructorsGrouped(); + MultiMap inClasses = pair.first; + MultiMap inNamespaces = pair.second; + for (Map.Entry entry : context.getClasses().entrySet()) { - checkOverloadsInAClass(entry.getValue(), entry.getKey()); + checkOverloadsInAClass(entry.getValue(), entry.getKey(), inClasses.get(entry.getValue())); } for (Map.Entry entry : context.getObjects().entrySet()) { - checkOverloadsInAClass(entry.getValue(), entry.getKey()); + checkOverloadsInAClass(entry.getValue(), entry.getKey(), inClasses.get(entry.getValue())); } - checkOverloadsInANamespace(); + checkOverloadsInANamespace(inNamespaces); } - 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; + private static class Key extends Pair { + Key(String namespace, String name) { + super(namespace, name); + } + + Key(NamespaceDescriptor namespaceDescriptor, String name) { + this(DescriptorRenderer.getFQName(namespaceDescriptor), name); + } + + public String getNamespace() { + return first; + } + + public String getFunctionName() { + return second; + } + } + + + private Pair, MultiMap> + constructorsGrouped() + { + MultiMap inClasses = MultiMap.create(); + MultiMap inNamespaces = MultiMap.create(); + + for (Map.Entry entry : context.getClasses().entrySet()) { + MutableClassDescriptor klass = entry.getValue(); + DeclarationDescriptor containingDeclaration = klass.getContainingDeclaration(); + if (containingDeclaration instanceof NamespaceDescriptor) { + NamespaceDescriptor namespaceDescriptor = (NamespaceDescriptor) containingDeclaration; + inNamespaces.put(new Key(namespaceDescriptor, klass.getName()), klass.getConstructors()); + } else if (containingDeclaration instanceof ClassDescriptor) { + ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; + inClasses.put(classDescriptor, klass.getConstructors()); + } else { + throw new NotImplementedException(); } } + + return Pair.create(inClasses, inNamespaces); + } + + private void checkOverloadsInANamespace(MultiMap inNamespaces) { MultiMap functionsByName = MultiMap.create(); @@ -62,24 +96,49 @@ public class OverloadResolver { DeclarationDescriptor containingDeclaration = function.getContainingDeclaration(); if (containingDeclaration instanceof NamespaceDescriptor) { NamespaceDescriptor namespaceDescriptor = (NamespaceDescriptor) containingDeclaration; - functionsByName.putValue(new Key(DescriptorRenderer.getFQName(namespaceDescriptor), function.getName()), function); + functionsByName.putValue(new Key(namespaceDescriptor, function.getName()), function); } } + + for (Map.Entry> entry : inNamespaces.entrySet()) { + functionsByName.putValues(entry.getKey(), entry.getValue()); + } for (Map.Entry> e : functionsByName.entrySet()) { checkOverloadsWithSameName(e.getKey().getFunctionName(), e.getValue(), e.getKey().getNamespace()); } } + + private String nameForErrorMessage(ClassDescriptor classDescriptor, JetClassOrObject jetClass) { + String name = jetClass.getName(); + if (name != null) { + return name; + } + if (jetClass instanceof JetObjectDeclaration) { + // must be class object + name = classDescriptor.getContainingDeclaration().getName(); + return "class object " + name; + } + // safe + return ""; + } - private void checkOverloadsInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) { + private void checkOverloadsInAClass( + MutableClassDescriptor classDescriptor, JetClassOrObject klass, + Collection nestedClassConstructors) + { MultiMap functionsByName = MultiMap.create(); for (FunctionDescriptor function : classDescriptor.getFunctions()) { functionsByName.putValue(function.getName(), function); } + for (ConstructorDescriptor nestedClassConstructor : nestedClassConstructors) { + functionsByName.putValue(nestedClassConstructor.getContainingDeclaration().getName(), nestedClassConstructor); + } + for (Map.Entry> e : functionsByName.entrySet()) { - checkOverloadsWithSameName(e.getKey(), e.getValue(), klass.getName()); + checkOverloadsWithSameName(e.getKey(), e.getValue(), nameForErrorMessage(classDescriptor, klass)); } // properties are checked elsewhere @@ -88,7 +147,7 @@ public class OverloadResolver { } - private void checkOverloadsWithSameName(String name, Collection functions, String functionContainer) { + private void checkOverloadsWithSameName(String name, Collection functions, @NotNull String functionContainer) { if (functions.size() == 1) { // microoptimization return; @@ -102,7 +161,7 @@ public class OverloadResolver { OverloadUtil.OverloadCompatibilityInfo overloadble = OverloadUtil.isOverloadble(function, function2); if (!overloadble.isSuccess()) { - JetNamedFunction member = (JetNamedFunction) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, function); + JetDeclaration member = (JetDeclaration) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, function); if (member == null) { assert context.getTrace().get(DELEGATED, function); return; 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 2465e60292e..1b50ad703bc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java @@ -91,6 +91,16 @@ public class OverridingUtil { @NotNull public static OverrideCompatibilityInfo isOverridableBy(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) { + if (superDescriptor instanceof FunctionDescriptor) { + if (subDescriptor instanceof PropertyDescriptor) return OverrideCompatibilityInfo.memberKindMismatch(); + } + if (superDescriptor instanceof PropertyDescriptor) { + if (subDescriptor instanceof FunctionDescriptor) return OverrideCompatibilityInfo.memberKindMismatch(); + } + if (!superDescriptor.getName().equals(subDescriptor.getName())) { + return OverrideCompatibilityInfo.nameMismatch(); + } + return isOverridableByImpl(superDescriptor, subDescriptor, true); } @@ -118,15 +128,6 @@ public class OverridingUtil { * @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(); - } - if (superDescriptor instanceof PropertyDescriptor) { - if (subDescriptor instanceof FunctionDescriptor) return OverrideCompatibilityInfo.memberKindMismatch(); - } - if (!superDescriptor.getName().equals(subDescriptor.getName())) { - return OverrideCompatibilityInfo.nameMismatch(); - } // TODO : Visibility diff --git a/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet b/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet index 9871e2803cb..b1055124354 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/ConflictingOverloads.jet @@ -65,3 +65,34 @@ namespace extensionAndRegular { fun Int.who() = 1 } + +// constructor vs. fun overload + +namespace constructorVsFun { + class a() { } + + fun a() = 1 + + class Tram { + fun f() { } + + class f() { } + } + + class Yvayva { + class object { + fun fghj() { } + + class fghj() { } + } + } + + class Rtyu { + fun ololo() { } + + class object { + class ololo() { } + } + } +} +