/* * Copyright (c) 2013, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.engine.internal.element.handle; import com.google.dart.engine.ast.AstNode; import com.google.dart.engine.ast.CompilationUnit; import com.google.dart.engine.context.AnalysisContext; import com.google.dart.engine.context.AnalysisException; import com.google.dart.engine.element.ClassElement; import com.google.dart.engine.element.CompilationUnitElement; import com.google.dart.engine.element.ConstructorElement; import com.google.dart.engine.element.Element; import com.google.dart.engine.element.ElementAnnotation; import com.google.dart.engine.element.ElementLocation; import com.google.dart.engine.element.ElementVisitor; import com.google.dart.engine.element.ExportElement; import com.google.dart.engine.element.FieldElement; import com.google.dart.engine.element.FunctionElement; import com.google.dart.engine.element.FunctionTypeAliasElement; import com.google.dart.engine.element.ImportElement; import com.google.dart.engine.element.LabelElement; import com.google.dart.engine.element.LibraryElement; import com.google.dart.engine.element.LocalVariableElement; import com.google.dart.engine.element.MethodElement; import com.google.dart.engine.element.ParameterElement; import com.google.dart.engine.element.PrefixElement; import com.google.dart.engine.element.PropertyAccessorElement; import com.google.dart.engine.element.TopLevelVariableElement; import com.google.dart.engine.element.TypeParameterElement; import com.google.dart.engine.source.Source; import java.lang.ref.WeakReference; /** * The abstract class {@code ElementHandle} implements the behavior common to objects that implement * a handle to an {@link Element}. * * @coverage dart.engine.element */ public abstract class ElementHandle implements Element { /** * Return a handle on the given element. If the element is already a handle, then it will be * returned directly, otherwise a handle of the appropriate class will be constructed. * * @param element the element for which a handle is to be constructed * @return a handle on the given element */ @SuppressWarnings("unchecked") public static <E extends Element> E forElement(E element) { if (element instanceof ElementHandle) { return element; } switch (element.getKind()) { case CLASS: return (E) new ClassElementHandle((ClassElement) element); case COMPILATION_UNIT: return (E) new CompilationUnitElementHandle((CompilationUnitElement) element); case CONSTRUCTOR: return (E) new ConstructorElementHandle((ConstructorElement) element); case EXPORT: return (E) new ExportElementHandle((ExportElement) element); case FIELD: return (E) new FieldElementHandle((FieldElement) element); case FUNCTION: return (E) new FunctionElementHandle((FunctionElement) element); case GETTER: return (E) new PropertyAccessorElementHandle((PropertyAccessorElement) element); //case HTML: case IMPORT: return (E) new ImportElementHandle((ImportElement) element); case LABEL: return (E) new LabelElementHandle((LabelElement) element); case LIBRARY: return (E) new LibraryElementHandle((LibraryElement) element); case LOCAL_VARIABLE: return (E) new LocalVariableElementHandle((LocalVariableElement) element); case METHOD: return (E) new MethodElementHandle((MethodElement) element); case PARAMETER: return (E) new ParameterElementHandle((ParameterElement) element); case PREFIX: return (E) new PrefixElementHandle((PrefixElement) element); case SETTER: return (E) new PropertyAccessorElementHandle((PropertyAccessorElement) element); case TOP_LEVEL_VARIABLE: return (E) new TopLevelVariableElementHandle((TopLevelVariableElement) element); case FUNCTION_TYPE_ALIAS: return (E) new FunctionTypeAliasElementHandle((FunctionTypeAliasElement) element); case TYPE_PARAMETER: return (E) new TypeParameterElementHandle((TypeParameterElement) element); default: throw new UnsupportedOperationException(); } } /** * Return an array of the same size as the given array where each element of the returned array is * a handle for the corresponding element of the given array. * * @param elements the elements for which handles are to be created * @return an array of handles to the given elements */ public static <E extends Element> E[] forElements(E[] elements) { int length = elements.length; E[] handles = elements.clone(); for (int i = 0; i < length; i++) { handles[i] = forElement(elements[i]); } return handles; } /** * The context in which the element is defined. */ private AnalysisContext context; /** * The location of this element, used to reconstitute the element if it has been garbage * collected. */ private ElementLocation location; /** * A reference to the element being referenced by this handle, or {@code null} if the element has * been garbage collected. */ private WeakReference<Element> elementReference; /** * Initialize a newly created element handle to represent the given element. * * @param element the element being represented */ public ElementHandle(Element element) { context = element.getContext(); location = element.getLocation(); elementReference = new WeakReference<Element>(element); } @Override public <R> R accept(ElementVisitor<R> visitor) { return getActualElement().accept(visitor); } @Override public String computeDocumentationComment() throws AnalysisException { return getActualElement().computeDocumentationComment(); } @Override public boolean equals(Object object) { return object instanceof Element && ((Element) object).getLocation().equals(location); } @Override public <E extends Element> E getAncestor(Class<E> elementClass) { return getActualElement().getAncestor(elementClass); } @Override public AnalysisContext getContext() { return context; } @Override public String getDisplayName() { return getActualElement().getDisplayName(); } @Override public Element getEnclosingElement() { return getActualElement().getEnclosingElement(); } @Override public String getExtendedDisplayName(String shortName) { return getActualElement().getExtendedDisplayName(shortName); } @Override public LibraryElement getLibrary() { return getAncestor(LibraryElement.class); } @Override public ElementLocation getLocation() { return location; } @Override public ElementAnnotation[] getMetadata() { return getActualElement().getMetadata(); } @Override public String getName() { return getActualElement().getName(); } @Override public int getNameOffset() { return getActualElement().getNameOffset(); } @Override public AstNode getNode() throws AnalysisException { return getActualElement().getNode(); } @Override public Source getSource() { return getActualElement().getSource(); } @Override public CompilationUnit getUnit() throws AnalysisException { return getActualElement().getUnit(); } @Override public int hashCode() { return location.hashCode(); } @Override public boolean isAccessibleIn(LibraryElement library) { return getActualElement().isAccessibleIn(library); } @Override public boolean isDeprecated() { return getActualElement().isDeprecated(); } @Override public boolean isOverride() { return getActualElement().isOverride(); } @Override public boolean isPrivate() { return getActualElement().isPrivate(); } @Override public boolean isPublic() { return getActualElement().isPublic(); } @Override public boolean isSynthetic() { return getActualElement().isSynthetic(); } @Override public void visitChildren(ElementVisitor<?> visitor) { getActualElement().visitChildren(visitor); } /** * Return the element being represented by this handle, reconstituting the element if the * reference has been set to {@code null}. * * @return the element being represented by this handle */ protected Element getActualElement() { Element element = elementReference.get(); if (element == null) { element = context.getElement(location); elementReference = new WeakReference<Element>(element); } return element; } }