report overload conflict of constructor and function
like this: === fun a() = 1 class a() ===
This commit is contained in:
+33
-9
@@ -1,10 +1,10 @@
|
|||||||
package org.jetbrains.jet.lang.diagnostics;
|
package org.jetbrains.jet.lang.diagnostics;
|
||||||
|
|
||||||
import com.intellij.openapi.util.TextRange;
|
import com.intellij.openapi.util.TextRange;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetClassOrObject;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.psi.JetNamedFunction;
|
|
||||||
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,19 +15,43 @@ public class FunctionSignatureDiagnosticFactory extends DiagnosticFactoryWithMes
|
|||||||
public FunctionSignatureDiagnosticFactory(Severity severity, String messageTemplate) {
|
public FunctionSignatureDiagnosticFactory(Severity severity, String messageTemplate) {
|
||||||
super(severity, 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
|
@NotNull
|
||||||
public Diagnostic on(@NotNull JetNamedFunction functionElement, @NotNull FunctionDescriptor functionDescriptor,
|
public Diagnostic on(@NotNull JetDeclaration declaration, @NotNull FunctionDescriptor functionDescriptor,
|
||||||
@NotNull String functionContainer)
|
@NotNull String functionContainer)
|
||||||
{
|
{
|
||||||
TextRange rangeToMark = new TextRange(
|
TextRange rangeToMark = rangeToMark(declaration);
|
||||||
functionElement.getStartOfSignatureElement().getTextRange().getStartOffset(),
|
|
||||||
functionElement.getEndOfSignatureElement().getTextRange().getEndOffset()
|
|
||||||
);
|
|
||||||
String message = messageFormat.format(new Object[]{
|
String message = messageFormat.format(new Object[]{
|
||||||
functionContainer,
|
functionContainer,
|
||||||
DescriptorRenderer.TEXT.render(functionDescriptor)});
|
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.openapi.util.Pair;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.util.containers.MultiMap;
|
import com.intellij.util.containers.MultiMap;
|
||||||
|
import org.apache.commons.lang.NotImplementedException;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
@@ -32,29 +33,62 @@ public class OverloadResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkOverloads() {
|
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()) {
|
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()) {
|
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() {
|
private static class Key extends Pair<String, String> {
|
||||||
class Key extends Pair<String, String> {
|
Key(String namespace, String name) {
|
||||||
Key(String namespace, String name) {
|
super(namespace, name);
|
||||||
super(namespace, name);
|
}
|
||||||
}
|
|
||||||
|
Key(NamespaceDescriptor namespaceDescriptor, String name) {
|
||||||
public String getNamespace() {
|
this(DescriptorRenderer.getFQName(namespaceDescriptor), name);
|
||||||
return first;
|
}
|
||||||
}
|
|
||||||
|
public String getNamespace() {
|
||||||
public String getFunctionName() {
|
return first;
|
||||||
return second;
|
}
|
||||||
|
|
||||||
|
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();
|
MultiMap<Key, FunctionDescriptor> functionsByName = MultiMap.create();
|
||||||
|
|
||||||
@@ -62,24 +96,49 @@ public class OverloadResolver {
|
|||||||
DeclarationDescriptor containingDeclaration = function.getContainingDeclaration();
|
DeclarationDescriptor containingDeclaration = function.getContainingDeclaration();
|
||||||
if (containingDeclaration instanceof NamespaceDescriptor) {
|
if (containingDeclaration instanceof NamespaceDescriptor) {
|
||||||
NamespaceDescriptor namespaceDescriptor = (NamespaceDescriptor) containingDeclaration;
|
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()) {
|
for (Map.Entry<Key, Collection<FunctionDescriptor>> e : functionsByName.entrySet()) {
|
||||||
checkOverloadsWithSameName(e.getKey().getFunctionName(), e.getValue(), e.getKey().getNamespace());
|
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();
|
MultiMap<String, FunctionDescriptor> functionsByName = MultiMap.create();
|
||||||
|
|
||||||
for (FunctionDescriptor function : classDescriptor.getFunctions()) {
|
for (FunctionDescriptor function : classDescriptor.getFunctions()) {
|
||||||
functionsByName.putValue(function.getName(), function);
|
functionsByName.putValue(function.getName(), function);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (ConstructorDescriptor nestedClassConstructor : nestedClassConstructors) {
|
||||||
|
functionsByName.putValue(nestedClassConstructor.getContainingDeclaration().getName(), nestedClassConstructor);
|
||||||
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, Collection<FunctionDescriptor>> e : functionsByName.entrySet()) {
|
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
|
// 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) {
|
if (functions.size() == 1) {
|
||||||
// microoptimization
|
// microoptimization
|
||||||
return;
|
return;
|
||||||
@@ -102,7 +161,7 @@ public class OverloadResolver {
|
|||||||
|
|
||||||
OverloadUtil.OverloadCompatibilityInfo overloadble = OverloadUtil.isOverloadble(function, function2);
|
OverloadUtil.OverloadCompatibilityInfo overloadble = OverloadUtil.isOverloadble(function, function2);
|
||||||
if (!overloadble.isSuccess()) {
|
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) {
|
if (member == null) {
|
||||||
assert context.getTrace().get(DELEGATED, function);
|
assert context.getTrace().get(DELEGATED, function);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -91,6 +91,16 @@ public class OverridingUtil {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static OverrideCompatibilityInfo isOverridableBy(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
|
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);
|
return isOverridableByImpl(superDescriptor, subDescriptor, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,15 +128,6 @@ public class OverridingUtil {
|
|||||||
* @param forOverride true for override, false for overload
|
* @param forOverride true for override, false for overload
|
||||||
*/
|
*/
|
||||||
static OverrideCompatibilityInfo isOverridableByImpl(CallableDescriptor superDescriptor, CallableDescriptor subDescriptor, boolean forOverride) {
|
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
|
// TODO : Visibility
|
||||||
|
|
||||||
|
|||||||
@@ -65,3 +65,34 @@ namespace extensionAndRegular {
|
|||||||
|
|
||||||
fun Int.who() = 1
|
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() { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user