Files
sdk/compiler/java/com/google/dart/compiler/resolver/ClassElementImplementation.java
T
scheglov@google.com 075b34c834 Use NodeElement to access Node in Resolver
Note, that such access it type safe, because we return NodeElement from corresponding Node subclasses, return other NodeElements from NodeElement accessors, etc.

R=zundel@google.com
BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com//9700019

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@5471 260f80e4-7a28-3924-810f-c04153c831b5
2012-03-14 15:22:39 +00:00

372 lines
11 KiB
Java

// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.resolver;
import com.google.common.collect.Lists;
import com.google.dart.compiler.ast.DartClass;
import com.google.dart.compiler.ast.DartDeclaration;
import com.google.dart.compiler.ast.DartParameterizedTypeNode;
import com.google.dart.compiler.ast.DartStringLiteral;
import com.google.dart.compiler.ast.Modifiers;
import com.google.dart.compiler.common.SourceInfo;
import com.google.dart.compiler.type.InterfaceType;
import com.google.dart.compiler.type.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
class ClassElementImplementation extends AbstractNodeElement implements ClassNodeElement {
private InterfaceType type;
private InterfaceType supertype;
private InterfaceType defaultClass;
private final List<InterfaceType> interfaces = Lists.newArrayList();
private final boolean isInterface;
private final String nativeName;
private final Modifiers modifiers;
private final AtomicReference<List<InterfaceType>> allSupertypes =
new AtomicReference<List<InterfaceType>>();
private final SourceInfo nameLocation;
private final String declarationNameWithTypeParameter;
private List<Element> unimplementedMembers;
// declared volatile for thread-safety
@SuppressWarnings("unused")
private volatile Set<InterfaceType> subtypes;
private final List<ConstructorNodeElement> constructors = Lists.newArrayList();
private final ElementMap members = new ElementMap();
private final LibraryElement library;
private static ThreadLocal<Set<Element>> seenSupertypes = new ThreadLocal<Set<Element>>() {
@Override
protected Set<Element> initialValue() {
return new HashSet<Element>();
}
};
ClassElementImplementation(DartClass node, String name, String nativeName,
LibraryElement library) {
super(node, name);
this.nativeName = nativeName;
this.library = library;
if (node != null) {
isInterface = node.isInterface();
modifiers = node.getModifiers();
nameLocation = node.getName().getSourceInfo();
declarationNameWithTypeParameter = new DartParameterizedTypeNode(node.getName(), node.getTypeParameters()).toSource();
} else {
isInterface = false;
modifiers = Modifiers.NONE;
nameLocation = SourceInfo.UNKNOWN;
declarationNameWithTypeParameter = "";
}
}
@Override
public DartDeclaration<?> getNode() {
return (DartClass) super.getNode();
}
@Override
public SourceInfo getNameLocation() {
return nameLocation;
}
@Override
public void setType(InterfaceType type) {
this.type = type;
}
@Override
public InterfaceType getType() {
return type;
}
@Override
public List<Type> getTypeParameters() {
return getType().getArguments();
}
@Override
public InterfaceType getSupertype() {
return supertype;
}
@Override
public InterfaceType getDefaultClass() {
return defaultClass;
}
@Override
public void setSupertype(InterfaceType supertype) {
this.supertype = supertype;
}
void setDefaultClass(InterfaceType element) {
defaultClass = element;
}
@Override
public Iterable<NodeElement> getMembers() {
return new Iterable<NodeElement>() {
// The only use case for calling getMembers() is for iterating through the
// members. You should not be able to add or remove members through the
// object returned by this method. Returning members or members.value()
// would allow such direct manipulation which might be problematic for
// keeping the element model consistent.
//
// On the other hand, we don't want to make a defensive copy of the list
// because that makes this method expensive. This method should not be
// expensive because the IDE may be using it in interactive scenarios.
// Strictly speaking, we should also wrap the iterator as we don't want
// the method Iterator.remove to be used either.
@Override
public Iterator<NodeElement> iterator() {
return members.values().iterator();
}
};
}
@Override
public List<ConstructorNodeElement> getConstructors() {
return constructors;
}
@Override
public List<InterfaceType> getInterfaces() {
return interfaces;
}
@Override
public ElementKind getKind() {
return ElementKind.CLASS;
}
@Override
public boolean isInterface() {
return isInterface;
}
@Override
public Modifiers getModifiers() {
return modifiers;
}
@Override
public LibraryElement getLibrary() {
return library;
}
@Override
public String getNativeName() {
return nativeName;
}
@Override
public String getDeclarationNameWithTypeParameters() {
return declarationNameWithTypeParameter;
}
void addMethod(MethodNodeElement member) {
String name = member.getName();
if (member.getModifiers().isOperator()) {
name = "operator " + name;
}
members.add(name, member);
}
void addConstructor(ConstructorNodeElement member) {
constructors.add(member);
}
void addField(FieldNodeElement member) {
members.add(member.getName(), member);
}
void addInterface(InterfaceType type) {
interfaces.add(type);
}
Element findElement(String name) {
// Temporary find all strategy to get things working.
// Match resolve order in Resolver.visitMethodInvocation
Element element = lookupLocalMethod(name);
if (element != null) {
return element;
}
element = lookupLocalField(name);
if (element != null) {
return element;
}
if (type != null) {
for (Type arg : type.getArguments()) {
if (arg.getElement().getName().equals(name)) {
return arg.getElement();
}
}
}
// Don't look for constructors, they are in a different namespace.
return null;
}
/**
* Lookup a constructor declared in this class. Note that a class may define
* constructors for interfaces in case the class is a default implementation.
*
* @param type The type of the object this constructor is creating.
* @param name The constructor name ("" if unnamed).
*
* @return The constructor found in the class, or null if not found.
*/
ConstructorElement lookupConstructor(ClassElement type, String name) {
for (ConstructorElement element : constructors) {
if (element.getConstructorType().equals(type) && element.getName().equals(name)) {
return element;
}
}
return null;
}
@Override
public ConstructorElement lookupConstructor(String name) {
// Lookup a constructor that creates instances of this class.
return lookupConstructor(this, name);
}
@Override
public Element lookupLocalElement(String name) {
return members.get(name);
}
FieldElement lookupLocalField(String name) {
return (FieldElement) members.get(name, ElementKind.FIELD);
}
MethodElement lookupLocalMethod(String name) {
return (MethodElement) members.get(name, ElementKind.METHOD);
}
public static ClassElementImplementation fromNode(DartClass node, LibraryElement library) {
DartStringLiteral nativeName = node.getNativeName();
String nativeNameString = (nativeName == null ? null : nativeName.getValue());
return new ClassElementImplementation(node, node.getClassName(), nativeNameString, library);
}
public static ClassElementImplementation named(String name) {
return new ClassElementImplementation(null, name, null, null);
}
@Override
public boolean isObject() {
return supertype == null;
}
@Override
public boolean isObjectChild() {
return supertype != null && supertype.getElement().isObject();
}
@Override
public boolean isAbstract() {
if (modifiers.isAbstract()) {
return true;
}
for (Element element : getMembers()) {
if (element.getModifiers().isAbstract()) {
return true;
}
}
return false;
}
@Override
public EnclosingElement getEnclosingElement() {
return library;
}
@Override
public List<InterfaceType> getAllSupertypes()
throws CyclicDeclarationException, DuplicatedInterfaceException {
List<InterfaceType> list = allSupertypes.get();
if (list == null) {
allSupertypes.compareAndSet(null, computeAllSupertypes());
list = allSupertypes.get();
}
return list;
}
private List<InterfaceType> computeAllSupertypes()
throws CyclicDeclarationException, DuplicatedInterfaceException {
Map<ClassElement, InterfaceType> interfaces = new HashMap<ClassElement, InterfaceType>();
if (!seenSupertypes.get().add(this)) {
throw new CyclicDeclarationException(this);
}
ArrayList<InterfaceType> supertypes = new ArrayList<InterfaceType>();
try {
for (InterfaceType intf : getInterfaces()) {
addCheckDuplicated(interfaces, supertypes, intf);
}
for (InterfaceType intf : getInterfaces()) {
for (InterfaceType t : intf.getElement().getAllSupertypes()) {
if (!t.getElement().isObject()) {
addCheckDuplicated(interfaces, supertypes,
t.subst(intf.getArguments(),
intf.getElement().getTypeParameters()));
}
}
}
if (supertype != null) {
for (InterfaceType t : supertype.getElement().getAllSupertypes()) {
if (t.getElement().isInterface()) {
addCheckDuplicated(interfaces, supertypes,
t.subst(supertype.getArguments(),
supertype.getElement().getTypeParameters()));
}
}
supertypes.add(supertype);
for (InterfaceType t : supertype.getElement().getAllSupertypes()) {
if (!t.getElement().isInterface()) {
supertypes.add(t.subst(supertype.getArguments(),
supertype.getElement().getTypeParameters()));
}
}
}
} finally {
seenSupertypes.get().remove(this);
}
return supertypes;
}
private void addCheckDuplicated(Map<ClassElement, InterfaceType> interfaces,
ArrayList<InterfaceType> supertypes,
InterfaceType intf) throws DuplicatedInterfaceException {
InterfaceType existing = interfaces.put(intf.getElement(), intf);
if (existing == null) {
supertypes.add(intf);
} else {
if (!existing.equals(intf)) {
throw new DuplicatedInterfaceException(existing, intf);
}
}
}
@Override
public List<Element> getUnimplementedMembers() {
return unimplementedMembers;
}
@Override
public void setUnimplementedMembers(List<Element> members) {
this.unimplementedMembers = members;
}
}