diff --git a/compiler/java/com/google/dart/compiler/resolver/Elements.java b/compiler/java/com/google/dart/compiler/resolver/Elements.java index 13ecfe35328..b6dc0343c94 100644 --- a/compiler/java/com/google/dart/compiler/resolver/Elements.java +++ b/compiler/java/com/google/dart/compiler/resolver/Elements.java @@ -198,8 +198,13 @@ public class Elements { ((AbstractNodeElement) element).setType(type); } - public static void setOverridden(MethodElement methodElement, Set overridden) { - ((MethodElementImplementation) methodElement).setOverridden(overridden); + public static void setOverridden(Element element, Set overridden) { + if (element instanceof MethodElementImplementation) { + ((MethodElementImplementation) element).setOverridden(overridden); + } + if (element instanceof FieldElementImplementation) { + ((FieldElementImplementation) element).setOverridden(overridden); + } } static FieldElementImplementation fieldFromNode(DartField node, diff --git a/compiler/java/com/google/dart/compiler/resolver/FieldElement.java b/compiler/java/com/google/dart/compiler/resolver/FieldElement.java index c6f99d68a13..a2fb975cfb3 100644 --- a/compiler/java/com/google/dart/compiler/resolver/FieldElement.java +++ b/compiler/java/com/google/dart/compiler/resolver/FieldElement.java @@ -6,6 +6,8 @@ package com.google.dart.compiler.resolver; import com.google.dart.compiler.type.Type; +import java.util.Set; + public interface FieldElement extends Element { boolean isStatic(); @@ -19,4 +21,9 @@ public interface FieldElement extends Element { * @return the inferred {@link Type} of this constant, may be null if not set yet. */ Type getConstantType(); + + /** + * @return {@link Element}s overridden by this {@link MethodElement}. + */ + Set getOverridden(); } diff --git a/compiler/java/com/google/dart/compiler/resolver/FieldElementImplementation.java b/compiler/java/com/google/dart/compiler/resolver/FieldElementImplementation.java index 4ec338c3d40..d60a1442504 100644 --- a/compiler/java/com/google/dart/compiler/resolver/FieldElementImplementation.java +++ b/compiler/java/com/google/dart/compiler/resolver/FieldElementImplementation.java @@ -4,6 +4,7 @@ package com.google.dart.compiler.resolver; +import com.google.common.collect.ImmutableSet; import com.google.dart.compiler.ast.DartField; import com.google.dart.compiler.ast.DartNode; import com.google.dart.compiler.ast.DartObsoleteMetadata; @@ -11,6 +12,8 @@ import com.google.dart.compiler.ast.Modifiers; import com.google.dart.compiler.common.SourceInfo; import com.google.dart.compiler.type.Type; +import java.util.Set; + class FieldElementImplementation extends AbstractNodeElement implements FieldElement, FieldNodeElement { private final EnclosingElement holder; private final SourceInfo nameLocation; @@ -20,6 +23,7 @@ class FieldElementImplementation extends AbstractNodeElement implements FieldEle private MethodNodeElement getter; private MethodNodeElement setter; private Type constantType; + private Set overridden = ImmutableSet.of(); FieldElementImplementation(DartNode node, SourceInfo nameLocation, @@ -113,4 +117,12 @@ class FieldElementImplementation extends AbstractNodeElement implements FieldEle public void setConstantType(Type type) { constantType = type; } + + public void setOverridden(Set overridden) { + this.overridden = overridden; + } + + public Set getOverridden() { + return overridden; + } } diff --git a/compiler/java/com/google/dart/compiler/resolver/MethodElement.java b/compiler/java/com/google/dart/compiler/resolver/MethodElement.java index c5ab5416297..43e88cece03 100644 --- a/compiler/java/com/google/dart/compiler/resolver/MethodElement.java +++ b/compiler/java/com/google/dart/compiler/resolver/MethodElement.java @@ -22,7 +22,7 @@ public interface MethodElement extends Element, EnclosingElement { Type getReturnType(); FunctionType getFunctionType(); - + /** * @return {@link Element}s overridden by this {@link MethodElement}. */ diff --git a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java index 01d50c69e55..2d00ca55ac3 100644 --- a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java +++ b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java @@ -3036,6 +3036,7 @@ public class TypeAnalyzer implements DartCompilationPhase { for (InterfaceType supertype : supertypes) { supertypeElements.add(supertype.getElement()); } + Set artificialNames = Sets.newHashSet(); for (ClassElement interfaceElement : supertypeElements) { for (Element member : interfaceElement.getMembers()) { String name = member.getName(); @@ -3045,6 +3046,11 @@ public class TypeAnalyzer implements DartCompilationPhase { } } superMembers.put(name, member); + if (member instanceof FieldElement + && !((FieldElement) member).getModifiers().isAbstractField()) { + artificialNames.add("setter " + name); + superMembers.put("setter " + name, member); + } } } @@ -3072,6 +3078,11 @@ public class TypeAnalyzer implements DartCompilationPhase { } supertype = supertype.getElement().getSupertype(); } + + // Remove artificial "setter " members. + for (String name : artificialNames) { + superMembers.removeAll(name); + } // All remaining methods are unimplemented. for (String name : superMembers.keys()) { @@ -3096,8 +3107,19 @@ public class TypeAnalyzer implements DartCompilationPhase { public Void visitField(DartField node) { if (superMembers != null) { FieldElement field = node.getElement(); + // prepare overridden elements String name = field.getName(); - Collection overridden = superMembers.removeAll(name); + Set overridden = Sets.newHashSet(); + if (node.getAccessor() != null) { + if (node.getAccessor().getModifiers().isSetter()) { + overridden.addAll(superMembers.removeAll("setter " + name)); + } else { + overridden.addAll(superMembers.removeAll(name)); + } + } else { + overridden.addAll(superMembers.removeAll(name)); + } + // check override for (Element superElement : overridden) { if (!(field.isStatic() && superElement.getModifiers().isStatic())) { if (canOverride(node.getName(), field.getModifiers(), superElement) @@ -3156,6 +3178,32 @@ public class TypeAnalyzer implements DartCompilationPhase { } } } + // set super-elements for FieldElement + Elements.setOverridden(field, ImmutableSet.copyOf(overridden)); + // set super-elements for getter/setter + if (node.getAccessor() != null) { + Set superGetters = Sets.newHashSet(); + Set superSetters = Sets.newHashSet(); + for (Element superElement : overridden) { + if (superElement instanceof FieldElement) { + FieldElement superField = (FieldElement) superElement; + if (superField.getGetter() != null) { + superGetters.add(superField.getGetter()); + } else if (superField.getSetter() != null) { + superSetters.add(superField.getSetter()); + } else { + superGetters.add(superField); + superSetters.add(superField); + } + } + } + if (node.getAccessor().getModifiers().isGetter()) { + Elements.setOverridden(node.getAccessor().getElement(), superGetters); + } + if (node.getAccessor().getModifiers().isSetter()) { + Elements.setOverridden(node.getAccessor().getElement(), superSetters); + } + } } return null; } diff --git a/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java b/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java index 184fa9dffaa..98ae0054ae7 100644 --- a/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java +++ b/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java @@ -7,6 +7,7 @@ import com.google.common.base.Joiner; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.google.dart.compiler.CommandLineOptions.CompilerOptions; import com.google.dart.compiler.CompilerTestCase; import com.google.dart.compiler.DartArtifactProvider; @@ -60,6 +61,7 @@ import java.io.Reader; import java.io.StringReader; import java.net.URI; import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -4992,6 +4994,79 @@ public class TypeAnalyzerCompilerTest extends CompilerTestCase { errEx(ResolverErrorCode.DUPLICATE_INITIALIZATION, 4, 9, 5)); } + public void test_getOverridden_method() throws Exception { + analyzeLibrary( + "// filler filler filler filler filler filler filler filler filler filler", + "class A {", + " foo() => 1;", + "}", + "class B extends A {", + " foo() => 2;", + "}", + ""); + DartMethodDefinition node = findNode(DartMethodDefinition.class, "foo() => 2"); + Set superElements = node.getElement().getOverridden(); + assertClassMembers(superElements, "method A.foo"); + } + + public void test_getOverridden_field_withGetterSetter() throws Exception { + analyzeLibrary( + "// filler filler filler filler filler filler filler filler filler filler", + "class A {", + " var foo;", + "}", + "class B extends A {", + " get foo => 0;", + " set foo(x) {}", + "}", + ""); + // getter + { + DartMethodDefinition node = findNode(DartMethodDefinition.class, "get foo"); + Set superElements = node.getElement().getOverridden(); + assertClassMembers(superElements, "field A.foo"); + } + // setter + { + DartMethodDefinition node = findNode(DartMethodDefinition.class, "set foo"); + Set superElements = node.getElement().getOverridden(); + assertClassMembers(superElements, "field A.foo"); + } + } + + public void test_getOverridden_getterSetter_withField() throws Exception { + analyzeLibrary( + "// filler filler filler filler filler filler filler filler filler filler", + "class A {", + " get foo => 0;", + " set foo(x) {}", + "}", + "class B extends A {", + " var foo = 42;", + "}", + ""); + DartField node = findNode(DartField.class, "foo = 42"); + Set superElements = node.getElement().getOverridden(); + assertClassMembers(superElements, "field A.foo"); + } + + private static void assertClassMembers(Set superElements, String... expectedNames) { + Set superNames = Sets.newHashSet(); + for (Element element : superElements) { + String name = element.getEnclosingElement().getName() + "." + element.getName(); + if (element instanceof FieldElement) { + superNames.add("field " + name); + } + if (element instanceof MethodElement) { + superNames.add("method " + name); + } + } + for (String name : expectedNames) { + assertTrue(name, superNames.remove(name)); + } + assertTrue(superNames.toString(), superNames.isEmpty()); + } + private T findNode(final Class clazz, String pattern) { final int index = testSource.indexOf(pattern); assertTrue(index != -1);