report overload conflict of constructor and function

like this:

===
fun a() = 1

class a()
===
This commit is contained in:
Stepan Koltsov
2011-11-12 21:24:11 +04:00
parent ffa2e8f87c
commit e97b91c6e4
4 changed files with 153 additions and 38 deletions
@@ -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);
}
} //~
@@ -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<ClassDescriptor, ConstructorDescriptor>, MultiMap<Key, ConstructorDescriptor>> pair = constructorsGrouped();
MultiMap<ClassDescriptor, ConstructorDescriptor> inClasses = pair.first;
MultiMap<Key, ConstructorDescriptor> inNamespaces = pair.second;
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
checkOverloadsInAClass(entry.getValue(), entry.getKey());
checkOverloadsInAClass(entry.getValue(), entry.getKey(), inClasses.get(entry.getValue()));
}
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> 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<String, String> {
Key(String namespace, String name) {
super(namespace, name);
}
public String getNamespace() {
return first;
}
public String getFunctionName() {
return second;
private static class Key extends Pair<String, String> {
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<ClassDescriptor, ConstructorDescriptor>, MultiMap<Key, ConstructorDescriptor>>
constructorsGrouped()
{
MultiMap<ClassDescriptor, ConstructorDescriptor> inClasses = MultiMap.create();
MultiMap<Key, ConstructorDescriptor> inNamespaces = MultiMap.create();
for (Map.Entry<JetClass, MutableClassDescriptor> 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<Key, ConstructorDescriptor> inNamespaces) {
MultiMap<Key, FunctionDescriptor> 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<Key, Collection<ConstructorDescriptor>> entry : inNamespaces.entrySet()) {
functionsByName.putValues(entry.getKey(), entry.getValue());
}
for (Map.Entry<Key, Collection<FunctionDescriptor>> 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 "<unknown>";
}
private void checkOverloadsInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) {
private void checkOverloadsInAClass(
MutableClassDescriptor classDescriptor, JetClassOrObject klass,
Collection<ConstructorDescriptor> nestedClassConstructors)
{
MultiMap<String, FunctionDescriptor> 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<String, Collection<FunctionDescriptor>> 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<FunctionDescriptor> functions, String functionContainer) {
private void checkOverloadsWithSameName(String name, Collection<FunctionDescriptor> 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;
@@ -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
@@ -65,3 +65,34 @@ namespace extensionAndRegular {
fun Int.who() = 1
}
// constructor vs. fun overload
namespace constructorVsFun {
class <!CONFLICTING_OVERLOADS!>a()<!> { }
<!CONFLICTING_OVERLOADS!>fun a()<!> = 1
class Tram {
<!CONFLICTING_OVERLOADS!>fun f()<!> { }
class <!CONFLICTING_OVERLOADS!>f()<!> { }
}
class Yvayva {
class object {
<!CONFLICTING_OVERLOADS!>fun fghj()<!> { }
class <!CONFLICTING_OVERLOADS!>fghj()<!> { }
}
}
class Rtyu {
fun ololo() { }
class object {
class ololo() { }
}
}
}