Checks for default parameter value consistency
Inheriting default values from multiple superclasses is prohibited
This commit is contained in:
+1
-1
@@ -36,7 +36,7 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
|
||||
private final boolean isVar;
|
||||
private final int index;
|
||||
private final ValueParameterDescriptor original;
|
||||
private final Set<ValueParameterDescriptor> overriddenDescriptors = Sets.newHashSet();
|
||||
private final Set<ValueParameterDescriptor> overriddenDescriptors = Sets.newLinkedHashSet(); // Linked is essential
|
||||
|
||||
public ValueParameterDescriptorImpl(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
|
||||
@@ -381,6 +381,8 @@ public interface Errors {
|
||||
DiagnosticFactory2.create(ERROR);
|
||||
|
||||
SimpleDiagnosticFactory<JetParameter> DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE = SimpleDiagnosticFactory.create(ERROR, PositioningStrategies.PARAMETER_DEFAULT_VALUE);
|
||||
DiagnosticFactory1<JetParameter, ValueParameterDescriptor> MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES = DiagnosticFactory1.create(ERROR, PositioningStrategies.POSITION_NAME_IDENTIFIER);
|
||||
DiagnosticFactory1<JetClassOrObject, ValueParameterDescriptor> MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE = DiagnosticFactory1.create(ERROR, PositioningStrategies.POSITION_NAME_IDENTIFIER);
|
||||
|
||||
DiagnosticFactory2<JetDeclaration, CallableMemberDescriptor, String> CONFLICTING_OVERLOADS =
|
||||
DiagnosticFactory2.create(ERROR, new PositioningStrategy<JetDeclaration>() {
|
||||
|
||||
+5
@@ -386,6 +386,11 @@ public class DefaultErrorMessages {
|
||||
MAP.put(NOT_AN_ANNOTATION_CLASS, "''{0}'' is not an annotation class", TO_STRING);
|
||||
|
||||
MAP.put(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE, "An overriding function is not allowed to specify default values for its parameters");
|
||||
MAP.put(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES, "More than one overridden descriptor declares a default value for ''{0}''. " +
|
||||
"As the compiler can not make sure these values agree, this is not allowed.", TO_STRING);
|
||||
|
||||
MAP.put(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE, "More than one overridden descriptor declares a default value for ''{0}''. " +
|
||||
"As the compiler can not make sure these values agree, this is not allowed.", TO_STRING);
|
||||
|
||||
MAP.setImmutable();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.jet.lang.psi;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -25,7 +26,7 @@ import java.util.List;
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public interface JetClassOrObject extends PsiElement {
|
||||
public interface JetClassOrObject extends PsiElement, PsiNameIdentifierOwner {
|
||||
List<JetDeclaration> getDeclarations();
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
package org.jetbrains.jet.lang.resolve;
|
||||
|
||||
import com.google.common.collect.*;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.containers.LinkedMultiMap;
|
||||
@@ -80,6 +83,20 @@ public class OverrideResolver {
|
||||
|
||||
checkVisibility();
|
||||
checkOverrides(invisibleOverriddenDescriptors);
|
||||
checkParameterOverrides();
|
||||
}
|
||||
|
||||
private void checkParameterOverrides() {
|
||||
List<MutableClassDescriptor> allClasses = Lists.newArrayList(context.getClasses().values());
|
||||
allClasses.addAll(context.getObjects().values());
|
||||
for (MutableClassDescriptor classDescriptor : allClasses) {
|
||||
Collection<CallableMemberDescriptor> members = classDescriptor.getCallableMembers();
|
||||
for (CallableMemberDescriptor member : members) {
|
||||
//if (member.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||
checkOverridesForParameters(member);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -394,10 +411,6 @@ public class OverrideResolver {
|
||||
}
|
||||
}
|
||||
|
||||
if (hasOverrideModifier) {
|
||||
checkOverridesForParameters(declared);
|
||||
}
|
||||
|
||||
if (hasOverrideModifier && declared.getOverriddenDescriptors().size() == 0) {
|
||||
if (!invisibleOverriddenDescriptors.get(declared).isEmpty()) {
|
||||
CallableDescriptor descriptor = invisibleOverriddenDescriptors.values().iterator().next();
|
||||
@@ -415,6 +428,16 @@ public class OverrideResolver {
|
||||
}
|
||||
|
||||
private void checkOverridesForParameters(CallableMemberDescriptor declared) {
|
||||
boolean fakeOverride = declared.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
|
||||
if (!fakeOverride) {
|
||||
// No check if the function is not marked as 'override'
|
||||
JetModifierListOwner declaration =
|
||||
(JetModifierListOwner) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), declared);
|
||||
if (!declaration.hasModifier(JetTokens.OVERRIDE_KEYWORD)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Let p1 be a parameter of the overriding function
|
||||
// Let p2 be a parameter of the function being overridden
|
||||
// Then
|
||||
@@ -422,10 +445,42 @@ public class OverrideResolver {
|
||||
// b) p1 must have the same name as p2
|
||||
for (ValueParameterDescriptor parameterFromSubclass : declared.getValueParameters()) {
|
||||
JetParameter parameter =
|
||||
(JetParameter) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), parameterFromSubclass);
|
||||
if (parameterFromSubclass.hasDefaultValue()) {
|
||||
fakeOverride ? null :
|
||||
(JetParameter) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), parameterFromSubclass);
|
||||
|
||||
if (parameterFromSubclass.hasDefaultValue() && !fakeOverride) {
|
||||
trace.report(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE.on(parameter));
|
||||
}
|
||||
|
||||
// If p1 overrides p2 and p3 and p2 overrides p3, we remove p2 from p1's overridden list
|
||||
Set<ValueParameterDescriptor> uniqueOverridden = Sets.newHashSet(parameterFromSubclass.getOverriddenDescriptors());
|
||||
for (ValueParameterDescriptor p2 : parameterFromSubclass.getOverriddenDescriptors()) {
|
||||
for (ValueParameterDescriptor p3 : p2.getOverriddenDescriptors()) {
|
||||
if (uniqueOverridden.contains(p3)) {
|
||||
uniqueOverridden.remove(p2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean superWithDefault = false;
|
||||
for (ValueParameterDescriptor parameterFromSuperclass : uniqueOverridden) {
|
||||
if (parameterFromSuperclass.hasDefaultValue()) {
|
||||
if (!superWithDefault) {
|
||||
superWithDefault = true;
|
||||
}
|
||||
else {
|
||||
if (fakeOverride) {
|
||||
JetClassOrObject classElement = (JetClassOrObject) BindingContextUtils
|
||||
.descriptorToDeclaration(trace.getBindingContext(), declared.getContainingDeclaration());
|
||||
trace.report(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE.on(classElement, parameterFromSubclass));
|
||||
}
|
||||
else {
|
||||
trace.report(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES.on(parameter, parameterFromSubclass));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
trait Y {
|
||||
fun foo(a : Int = 1)
|
||||
}
|
||||
|
||||
trait YSub : Y {
|
||||
|
||||
}
|
||||
|
||||
class Z2 : Y, YSub {
|
||||
override fun foo(a : Int) {}
|
||||
}
|
||||
|
||||
class Z2O : Y, YSub {
|
||||
override fun foo(a : Int) {}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
trait X {
|
||||
fun foo(a : Int = 1)
|
||||
}
|
||||
|
||||
trait Y {
|
||||
fun foo(a : Int = 1)
|
||||
}
|
||||
|
||||
class Z : X, Y {
|
||||
override fun foo(<!MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES!>a<!> : Int) {}
|
||||
}
|
||||
|
||||
object ZO : X, Y {
|
||||
override fun foo(<!MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES!>a<!> : Int) {}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
trait X {
|
||||
fun foo(a : Int = 1)
|
||||
}
|
||||
|
||||
trait Y {
|
||||
fun foo(a : Int = 1)
|
||||
}
|
||||
|
||||
class Z : X, Y {
|
||||
fun <!VIRTUAL_MEMBER_HIDDEN!>foo<!>(a : Int) {}
|
||||
}
|
||||
|
||||
object ZO : X, Y {
|
||||
fun <!VIRTUAL_MEMBER_HIDDEN!>foo<!>(a : Int) {}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
trait X {
|
||||
fun foo(a : Int = 1)
|
||||
}
|
||||
|
||||
trait Y {
|
||||
fun foo(a : Int = 1)
|
||||
}
|
||||
|
||||
class <!MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE!>Z1<!> : X, Y {} // BUG
|
||||
object <!MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE!>Z1O<!> : X, Y {} // BUG
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
trait X {
|
||||
fun foo(a : Int = 1)
|
||||
}
|
||||
|
||||
trait Y {
|
||||
fun foo(a : Int)
|
||||
}
|
||||
|
||||
class Z : X, Y {
|
||||
override fun foo(a : Int) {}
|
||||
}
|
||||
Reference in New Issue
Block a user